从基本类型(例如短)填充 __m128i 参数以与 _mm256_broadcast_epi(例如 _mm_broadcastw_epi16)一起使用的正确方法是什么

What is the correct way to fill a __m128i parameter, from basic type (such as short), to use with _mm256_broadcast_epi (such as _mm_broadcastw_epi16)

所有四个 _mm256_broadcastb_epi8、_mm_broadcastw_epi16、_mm256_broadcastd_epi32 和 _mm256_broadcastq_epi64 相应地,函数是 VPBROADCASTB、VPBROADCASTW、VPBROADCASTD 和 VPBROADCASTQ 指令的内在函数。 根据英特尔的文档:"Intel® Advanced Vector Extensions Programming Reference", 这些指令可能相应地接收 8 位、16 位、32 位、64 位内存位置。
第 5-230 页:

The source operand is 8-bit, 16-bit 32-bit, 64-bit memory location or the low 8-bit, 16-bit 32-bit, 64-bit data in an XMM register

但是,这些指令的内在 API(Intel、MSVS 和 gcc)接收一个 __m128i 参数。 现在,如果我有一个基本类型的变量,据说 'short',什么是最有效和跨平台的方式(至少在 MSVS 和 gcc 之间) 将该变量传递给相应的广播内在函数(_mm_broadcastw_epi16 在短的情况下)?

例如:

void func1(uint8_t v) {
    __m256i a = _mm256_broadcastb_epi8(<convert_to__m128i>(v));
    ...
}

void func1(uint16t v) {
    __m256i a = _mm256_broadcastw_epi16(<convert_to__m128i>(v));
    ...
}

void func1(uint32_t v) {
    __m256i a = _mm256_broadcastd_epi32(<convert_to__m128i>(v));
    ...
}

void func1(uint64_t v) {
    __m256i a = _mm256_broadcastq_epi64(<convert_to__m128i>(v));
    ...
}

应该是什么才最有效和跨平台(如果可能)?

例如,对于 MSVS,可以这样做:

void func1(uint16t v) {
    __m128i vt;
    vt.m128_u16[0] = v;
    __m256i a = _mm256_broadcastw_epi16(vt);
    ...
}

但如果不进行优化,它可以先加载一个 xmm 寄存器,然后才能在 VPBROADCASTW 中使用它。 当进行优化时,它可以直接使用 v 的内存位置。 它也只对 MSVS 有效。

已经有 sequence/compound 个内在函数可以完全满足您的需求:

_mm256_set1_epi8/16/32/64

来自英特尔内在函数指南:

Broadcast 8-bit integer a to all elements of dst. This intrinsic may generate the vpbroadcastb.

使用这些,您应该能够相信编译器会生成最佳代码。

我在做这样的事情时使用英特尔内部函数指南,这很有帮助,因为您可以从助记符反向搜索(在这种情况下,您知道您最终想要 vpbroadcastb)并且它会告诉您哪些内部函数与其相关.

只要让编译器为 _mm256_set1_epi8(scalar) 内在函数发出广播指令,如果您有一个标量值作为开始,而不是 __m128i


但您通常也不希望这样,_mm_broadcastb_epi8__m128i 结果)或 __m256i _mm256_broadcastb_epi8(__m128i),除非您已经有一个 __m128i 开始并想要低元素。

在不让编译器浪费指令的情况下将标量转换为 __m128i 对于 8 位或 16 位标量来说可能是一个实际问题,如果您不关心低位双字的高 2 或 3 字节;它可能 movzx 加载到一个整数寄存器中,然后使用 vmovd 或类似的可怕东西。