当前位置: 首页 > 知识库问答 >
问题:

硬件SIMD向量指针和相应类型之间的重新解释_cast是一种未定义的行为吗?

邓高韵
2023-03-14

reinterpret_castfloat*__m256*和通过不同的指针类型访问float对象是否合法?

constexpr size_t _m256_float_step_sz = sizeof(__m256) / sizeof(float);
alignas(__m256) float stack_store[100 * _m256_float_step_sz ]{};
__m256& hwvec1 = *reinterpret_cast<__m256*>(&stack_store[0 * _m256_float_step_sz]);

using arr_t = float[_m256_float_step_sz];
arr_t& arr1 = *reinterpret_cast<float(*)[_m256_float_step_sz]>(&hwvec1);

他们是否违反了严格的别名规则?[basic.lval]/11

或者只有一种定义的内在方式:

__m256 hwvec2 = _mm256_load_ps(&stack_store[0 * _m256_float_step_sz]);
_mm256_store_ps(&stack_store[1 * _m256_float_step_sz], hwvec2);

戈德博尔特

共有1个答案

潘鸿文
2023-03-14

ISO C++没有定义__m256,所以我们需要看看在支持它们的实现上是什么定义了它们的行为。

Intel的intrinsics定义向量指针,如__m256*允许别名,就像ISO C++定义char*允许别名一样。

因此,是的,取消引用__m256*是安全的,而不是使用_mm256_load_ps()对齐-加载内部的。

/* The Intel API is flexible enough that we must allow aliasing with other
   vector types, and their scalar components.  */
typedef float __m256 __attribute__ ((__vector_size__ (32),
                                     __may_alias__));
typedef long long __m256i __attribute__ ((__vector_size__ (32),
                                          __may_alias__));
typedef double __m256d __attribute__ ((__vector_size__ (32),
                                       __may_alias__));

/* Unaligned version of the same types.  */
typedef float __m256_u __attribute__ ((__vector_size__ (32),
                                       __may_alias__,
                                       __aligned__ (1)));
typedef long long __m256i_u __attribute__ ((__vector_size__ (32),
                                            __may_alias__,
                                            __aligned__ (1)));
typedef double __m256d_u __attribute__ ((__vector_size__ (32),
                                         __may_alias__,
                                         __aligned__ (1)));

(如果您想知道,这就是为什么取消引用__m256*类似于_mm256_store_ps,而不是storeu。)

允许没有may_alias的GNU C本机向量为其标量类型别名,例如,即使没有may_alias,您也可以安全地在float*和假设的V8SF类型之间强制转换。但是may_alias可以安全地从int[]char[]或其他类型的数组加载。

我在谈论GCC如何实现Intel的intinsics,只是因为这是我所熟悉的。我从gcc开发人员那里听说,他们选择该实现是因为需要与Intel兼容。

对于_mm_storeu_si128((__m128i*)&arr[i],vec);使用Intel的API要求您创建可能不对齐的指针,如果您推迟这些指针,就会出错。和_mm_storeu_ps到不是4字节对齐的位置时,需要创建一个未对齐的float*

在ISO C++中,仅仅创建未对齐的指针或对象外的指针是UB,即使您没有取消对它们的引用。我想这允许在异国情调的硬件上实现,在创建指针时(可能不是在取消引用时)对指针进行某种检查,或者不能存储指针的低位。(我不知道是否有任何特定的硬件存在,因为这个UB可以实现更高效的代码。)

但是支持Intel内部特性的实现必须定义行为,至少对于__m*类型和float*/double*。这对于以任何普通现代CPU为目标的编译器来说是微不足道的,包括具有平面内存模型(没有分段)的x86;asm中的指针只是与数据保持在相同寄存器中的整数。(m68k有地址寄存器和数据寄存器,但只要不取消地址,它就不会在寄存器中保留不是有效地址的位模式。)

请注意,may_aliaschar*别名规则一样,只有一种方式:不能保证使用int32_t*读取__m256是安全的。使用float*读取__m256甚至可能不安全。就像执行char buf[1024]不安全一样;int*p=(int*)buf;

通过char*读/写可以对任何东西进行别名,但是当您有char对象时,严格别名确实使得通过其他类型读它变得非常困难。(我不确定x86上的主要实现是否定义了这种行为,但您不需要依赖它,因为它们将4个字节的memcpy优化为int32_t。您可以并且应该使用memcpy来表示来自char[]缓冲区的未对齐加载,因为允许使用更宽类型的自动向量化为int16_t*假设2字节对齐,如果不是,则生成失败的代码:为什么对MMAP内存的未对齐访问有时会在AMD64上分段错误?)

要插入/提取向量元素,请使用shuffle intrinsics、SSE2_mm_insert_epi16/_mm_extract_epi16或sse4.1insert/_mm_extract_epi8/32/64。对于float,没有应该与标量float一起使用的insert/extract内部变量。

或存储到数组并读取数组。(打印__m128i变量)。这实际上html" target="_blank">优化了向量提取指令。

GNU C向量语法为向量提供[]运算符,例如__m256 v=...;v[3]=1.25;。MSVC将向量类型定义为具有.m128_f32[]成员的联合,以便对每个元素进行访问。

您还可以在向量和某种类型的数组之间使用联合类型双关语,这在ISO C99和GNU C++中是安全的,但在ISO C++中不是。我认为它在MSVC中也是安全的,因为我认为他们将__m128定义为一个普通的联合。

但是,不能保证从这些元素访问方法中获得有效的代码。不要使用inside内部循环,如果性能重要,请查看生成的asm。

 类似资料:
  • 考虑以下C程序: null 访问易失性对象、修改对象、修改文件,或者调用执行那些操作中的任何操作的函数都是副作用,它们是执行环境状态的改变。表达式的计算通常包括值计算和副作用的启动。用于lvalue表达式的值计算包括确定指定对象的标识。 Sequenced before是单线程执行的计算之间的非对称、传递、成对关系,它导致这些计算之间的部分顺序。给定任意两个评价A和B,如果A排序在B之前,那么A的

  • 主要内容:定义指针变量,通过指针变量取得数据,关于 * 和 & 的谜题,对星号*的总结数据在内存中的地址也称为 指针,如果一个变量存储了一份数据的指针,我们就称它为 指针变量。 在C语言中,允许用一个变量来存放指针,这种变量称为指针变量。指针变量的值就是某份数据的地址,这样的一份数据可以是数组、字符串、函数,也可以是另外的一个普通变量或指针变量。 现在假设有一个 char 类型的变量 c,它存储了字符 'K'(ASCII码为十进制数 75),并占用了地址为 0X11A 的内存(地址

  • 我目前正致力于创建一个python线性代数模块,以获得乐趣并练习该语言。我最近尝试向模块添加类型注释,如下所示: 但是,当我尝试导入此内容时,它会抛出一个。我承认这个问题已经在这里以某种形式得到了回答,但它似乎并没有完全为我的情况提供答案。 我想知道的是: 我已经在这个文件中定义了这个类。为什么它说这个名字没有定义

  • 我不明白为什么println是给我0。有什么想法吗? 这是游乐场的链接。https://play.rust-lang.org/?version=stable

  • 我正在学习如何在C中使用并写了以下示例: 问:是否保证在所有情况下指向一个结构的指针都是指向它的第一个元素的完全相同的指针? 在这种特殊的情况下,它能像我预期的那样工作,但我不确定它是否能得到保证。编译器可以在开始时插入一些填充吗? 我唯一能找到的关于结构类型布局的是N1570的类型: 结构类型描述了一组按顺序分配的非空成员对象(在某些情况下,还包括一个不完整的数组),每个对象都有一个可选的指定名

  • 本文向大家介绍什么是指向指针的指针? 相关面试题,主要包含被问及什么是指向指针的指针? 时的应答技巧和注意事项,需要的朋友参考一下 指针指向的变量是一个指针,即具体内容为一个指针的值,是一个地址. 此时指针指向的变量长度也是4位.