【问题标题】:accessing __m128 fields across compilers跨编译器访问 __m128 字段
【发布时间】:2013-10-25 06:46:24
【问题描述】:

我注意到在gcc 中可以通过索引访问__m128 字段,而无需使用union 技巧。

__m128 t;

float r(t[0] + t[1] + t[2] + t[3]);

我也可以像数组一样加载__m128

__m128 t{1.f, 2.f, 3.f, 4.f};

这完全符合gcc 的向量扩展。但是,这些可能在其他地方不可用。 intel编译器和msvc是否支持加载和访问功能?

【问题讨论】:

  • 标准 C++ 不支持 SSE。您对哪些目标平台感兴趣?
  • union 访问 __m128 字段的技巧是什么?
  • @Blue 类似于:union vec { __m128 a; float b[4]; double c[2]; };。不保证有效。

标签: visual-c++ g++ sse icc


【解决方案1】:

如果您希望您的代码在其他编译器上工作,请不要使用那些 GCC 扩展。使用 set/load/store 内在函数。 _mm_setr_ps 可用于设置常量值,但不应在循环中使用。要访问元素,我通常先将值存储到数组中,然后再读取数组。

如果你有一个数组a,你应该读/存储它

__m128 t = _mm_loadu_ps(a);
_mm_storeu_ps(a, t);

如果数组是 16 字节对齐的,您可以使用对齐的加载/存储,这在新系统上稍快,但在旧系统上快得多。

__m128 t = _mm_load_ps(a);
_mm_store_ps(a, t);

要在堆栈上获得 16 字节对齐的内存,请使用

__declspec(align(16)) const float a[] = ...//MSVC
__attribute__((aligned(16))) const float a[] ...//GCC, ICC

对于 16 字节对齐的dynamic arrays use

float *a = (float*)_mm_malloc(sizeof(float)*n, 16); //MSVC, GCC, ICC, MinGW 

【讨论】:

  • 我喜欢按索引寻址,因为这样我就不用做那些讨厌的转变了。轮班呢?
  • 轮班?您存储到一个数组并像任何数组一样通过索引访问该数组。
  • 啊,现在我明白你的意思了...从反汇编中我看到编译器对 xmm 寄存器进行了一些移位以实现索引寻址。
  • 在这种情况下,你不能同时拥有它。不要指望那些 GCC 扩展会进入 MSVC。如果您不小心,这些扩展也可能导致非最佳代码。特别是如果您将 SIMD 寄存器视为数组并在循环中插入/读取寄存器的一个或两个元素。扩展使这变得如此简单,太容易了......
  • 好吧,不需要将扩展​​视为特定于gcc,这些扩展已经(也许部分地,我没有icc)成为icc。他们也不需要完全进入 MSVC。
【解决方案2】:

您也可以为此使用宏:

//Test to see if we are using MSVC as MSVC AVX types are slightly different to the GCC ones
#ifdef _MSC_VER 
#define GET_F32_AVX_MULTIPLATTFORM(vector,index) (vector).m256_f32[index]
#define GET_F64_AVX_MULTIPLATTFORM(vector,index) (vector).m256d_f64[index]
#else 
#define GET_F32_AVX_MULTIPLATTFORM(vector,index) (vector)[index]
#define GET_F64_AVX_MULTIPLATTFORM(vector,index) (vector)[index]
#endif

【讨论】:

    【解决方案3】:

    要加载__m128,可以写_mm_setr_ps(1.f, 2.f, 3.f, 4.f),GCC、ICC、MSVC和clang都支持。

    据我所知,clang 和最新版本的 GCC 支持按索引访问 __m128 字段。我不知道如何在 ICC 或 MSVC 中执行此操作。我猜_mm_extract_ps 适用于所有 4 个编译器,但它的返回类型很疯狂,使用起来很痛苦。

    【讨论】:

    • 您不需要_mm_extract_ps,因为标量浮点数只是 XMM 寄存器的低元素。你想将你想要的浮点数洗牌到一个向量的底部(例如_mm_shuffle_ps_mm_insert_ps),对于_mm_cvtps_f32(这只是一个演员,没有asm指令)。除非目标是内存,否则您不希望编译器发出 extractps 指令;它基本上只是pextrd。 (Intel SSE: Why does `_mm_extract_ps` return `int` instead of `float`?)
    • @PeterCordes 现代编译器不会将_mm_extract_ps 解释为生成准确 extractps 指令的命令,而是“使用编译器认为最好的任何指令提取元素”。 GCC 可能不会为_mm_extract_ps 生成任何内容、movshdup、movhlps、shufps、extractps 或 pextrd,具体取决于索引和上下文。
    • MSVC 不优化内在函数,并且 确实 使用您所要求的。我认为ICC是一样的。 Clang 的 shuffle 优化器很好,如果你用memcpy 或联合或std::bit_cast 将它键入回浮动,GCC 可能会也可能不会解决这个问题,但它非常不方便,并且会导致编译器朝着错误 asm 的方向发展.
    猜你喜欢
    • 1970-01-01
    • 2015-06-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-13
    • 2011-07-02
    • 2014-01-05
    • 1970-01-01
    相关资源
    最近更新 更多