C++ AVX intrinsics vec中的填充常量浮动

C++ AVX intrinsics vec中的填充常量浮动,c++,c,simd,intrinsics,avx,C++,C,Simd,Intrinsics,Avx,我正在使用AVX intrinsic进行矢量化,我想将像1.0这样的常量浮点填充到向量\uuuu m256。所以在一个寄存器中我得到了一个向量{1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0} 有人知道怎么做吗 这与这个问题类似 但我使用的是AVX,而不是SSE,请参见此处了解更多信息。您只需声明一个浮点数组,一个AVX向量\uuuM256,然后使用适当的操作将浮点数组作为AVX向量加载 在这种情况下,指令\u mm256\u load\u ps就是您想要的 更新:如注释中所述,

我正在使用AVX intrinsic进行矢量化,我想将像
1.0
这样的常量浮点填充到向量
\uuuu m256
。所以在一个寄存器中我得到了一个向量
{1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0}
有人知道怎么做吗

这与这个问题类似

但我使用的是AVX,而不是SSE,请参见此处了解更多信息。您只需声明一个浮点数组,一个AVX向量
\uuuM256
,然后使用适当的操作将浮点数组作为AVX向量加载

在这种情况下,指令
\u mm256\u load\u ps
就是您想要的

更新:如注释中所述,数据必须是32位对齐的。有关详细说明,请参阅。根据Peter的评论,我已经使解决方案代码更清晰了。启用优化(
-O3
)后,生成的代码与Paul的答案相同(也启用了优化)。但是,如果未启用优化,则指令数是相同的,但所有8个浮点数都被存储,而不是Paul答案中的单个浮点数

以下是修改后的示例:

#include <immintrin.h> // For AVX instructions

#ifdef __GNUC__
  #define ALIGN(x) x __attribute__((aligned(32)))
#elif defined(_MSC_VER)
  #define ALIGN(x) __declspec(align(32))
#endif

static constexpr ALIGN(float a[8]) = {1.0f,1.0f,1.0f,1.0f,1.0f,1.0f,1.0f,1.0f};

int main() {
  // Load the float array into an avx vector
  __m256 vect = _mm256_load_ps(a);
}
#包含//以获取AVX指令
#ifdef__GNUC__
#定义ALIGN(x)x _uu属性_uuu((aligned(32)))
#elif已定义(\u MSC\u VER)
#定义对齐(x)uu declspec(对齐(32))
#恩迪夫
静态constexpr ALIGN(float a[8])={1.0f、1.0f、1.0f、1.0f、1.0f、1.0f、1.0f、1.0f};
int main(){
//将浮点数组加载到avx向量中
__m256矢量=_mm256_load_ps(a);
}

通过使用,您可以使用一些编译器轻松地检查程序集输出

您可以在不使用常量数组的情况下使用它

pcmpeqw xmm0, xmm0
pslld   xmm0, 25
psrld   xmm0, 2
请参阅Agner Fog的优化指南中的其他常数的生成方法

另见


    • 最简单的方法是使用:


      感谢您的回答您需要将数组与32字节边界对齐,否则程序将crash@Lbj_x当前位置Paul R的答案更好:告诉编译器你真正想要什么,而不是如何做。它将使用任何可用/适用的技巧(如广播说明)。您绝对不想强迫它生成本地数组,而不是从全局/静态常量加载。实际上,创建本地数组意味着将数据存储到堆栈中。还请注意,针对win32的gcc编译将被这段代码阻塞,因为它不是Unix与Windows,而是GNU C(
      \uuuuu attribute\uuuuu
      )与MSVC(
      \uuuu declspec
      )。@PeterCordes,我同意Paul R的答案更好,因此是向上投票,并同意您的评论,尤其是从全局/静态常量加载。Windows vs Unix的使用取自参考的“英特尔校准”文档。请将我的投票更改为upvote:)我将此代码放在godbolt:。我想出了一些其他的方法。你问题中的链接是指向godbolt上的其他代码。gcc以不同的方式编译它们,但clang甚至看穿了静态数组并使用
      vbroadcastss
      main
      对于在godbolt上测试代码来说是一个糟糕的选择:gcc将其标记为“冷”,并且优化较少。此外,编写函数获取参数和/或返回结果比担心
      main
      优化到
      return0更容易。请记住,我们只想查看asm,而不是运行它。请注意,如果需要,编译器可以使用Lu'u答案中的整数序列(您使用的是AVX2)。它还可以将
      set1
      编译为广播指令,而不是256b加载。如果你真的想,你可以通过使用另外两个答案中的一个(强制加载或动态生成)来为编译器做出决定。谢谢你@Paul R,事实上我最终选择使用你的答案,但是,盖伊·纳布拉给了我一个快速的答案,所以我给了他答案希望你能理解:D@Lbj_x:没问题-所有的答案都是有效的,可能对未来的读者有用。我认为在某些时候,一些编译器将
      \u mm256\u set1\u ps
      转换为两条指令,而所有编译器都将一条指令用于
      \u mm256\u broadcast\u ps
      。这就是我读这篇文章的地方。也许Clang现在已经解决了这个问题。“生成常量”现在是Agner Fog《装配优化指南》的第13.7节。
      pcmpeqw xmm0, xmm0 ; 1.5f
      pslld   xmm0, 24
      psrld   xmm0, 2
      
      pcmpeqw xmm0, xmm0 ; -2.0f
      pslld   xmm0, 30
      
      __m256 v = _mm256_set1_ps(1.0f);