将 GCC 的 __builtin_ia32_pshufd 和 __v4si 模式转换为可移植的内在模式?

Posted

技术标签:

【中文标题】将 GCC 的 __builtin_ia32_pshufd 和 __v4si 模式转换为可移植的内在模式?【英文标题】:Convert GCC's __builtin_ia32_pshufd and __v4si mode to portable intrinsic? 【发布时间】:2016-04-18 17:21:15 【问题描述】:

我有一个充满自定义宏和 GCC 内在函数的程序,例如 __builtin_ia32_pshufd。我想将其转换为 Intel 内在函数,以便移植和最终支持 Windows。

我预处理了源文件,包括-fno-builtin 选项,但我似乎得到了一些内置函数。这是其中之一:

row = 
 ((__m128i)__builtin_ia32_pshufd ((__v4si)(__m128i)(
 row
 ), (int)((((
 1
 ) << 6) | ((
 0
 ) << 4) | ((
 3
 ) << 2) | (
 2
 )))))
 ;

我也无法弄清楚如何处理 mode 属性 (__v4si):

row = 
 ((__m128i) ((__v4si)(__m128i)(
 row
 ), (int)((((
 0
 ) << 6) | ((
 3
 ) << 4) | ((
 2
 ) << 2) | (
 1
 )))))
 ;

如何将这两个 GCC 内部函数转换为可移植的 Intel 内部函数?

【问题讨论】:

@Olaf - 无需编辑。请发展一些主题知识。 【参考方案1】:
row = 
 ((__m128i) ((__v4si)(__m128i)(
 row
 ), (int)((((
 0
 ) << 6) | ((
 3
 ) << 4) | ((
 2
 ) << 2) | (
 1
 )))))
 ;

这可以通过以下方式返回到可移植的内在函数:

row = (_mm_shuffle_epi32(row, _MM_SHUFFLE(2,1,0,3)));

如果您使用的是经过预处理的源文件,那么:

file=<preprocessed source file>
tfile=<temporary file>

cp $file $tfile

sed -i 's|(__m128i)__builtin_ia32_pshufd ((__v4si)(__m128i)|_mm_shuffle_epi32(|g' "$tfile"

perl -0777 -i -pe 's/\(\n 0\n\)/0/igs' "$tfile"
perl -0777 -i -pe 's/\(\n 1\n\)/1/igs' "$tfile"
perl -0777 -i -pe 's/\(\n 2\n\)/2/igs' "$tfile"
perl -0777 -i -pe 's/\(\n 3\n\)/3/igs' "$tfile"
perl -0777 -i -pe 's/\(\n row\n\)/ row/igs' "$tfile"

sed -i 's|(int)(((2 << 6) \| (1 << 4) \| (0 << 2) \| 3)))|_MM_SHUFFLE(2,1,0,3))|g' "$tfile"
sed -i 's|(int)(((1 << 6) \| (0 << 4) \| (3 << 2) \| 2)))|_MM_SHUFFLE(1,0,3,2))|g' "$tfile"
sed -i 's|(int)(((0 << 6) \| (3 << 4) \| (2 << 2) \| 1)))|_MM_SHUFFLE(0,3,2,1))|g' "$tfile"
...

【讨论】:

您不需要使用_MM_SHUFFLE。它肯定比那些乱七八糟的东西更容易阅读,但原来的仍然会产生一个整数,你可以将它用作_mm_shuffle_epi32 的 shuffle arg。不使用 _MM_SHUFFLE 宏的另一种半可读方式编写 1,0,3,2 是 0b01001110。我更喜欢汇编程序中的 0b 方式,但在 C 中,_MM_SHUFFLE 方式更可取。

以上是关于将 GCC 的 __builtin_ia32_pshufd 和 __v4si 模式转换为可移植的内在模式?的主要内容,如果未能解决你的问题,请参考以下文章

使用 __builtin_ ia32 shufps 将向量移动 32 位?

为啥 gcc 将 _mm256_permute2f128_ps 编译为 Vinsertf128 指令?

_MM_TRANSPOSE4_PS 导致 GCC 中的编译器错误?

如何将两个_pd 转换为一个_ps?

使用 gcc 3.3 mips32 提升 1_49_0 错误

有没有办法将 8bitX32 ymm 寄存器右/左洗牌 N 个位置(c++)