从基本类型(例如短)填充 __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
或类似的可怕东西。
所有四个 _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
或类似的可怕东西。