【发布时间】:2018-09-01 14:35:39
【问题描述】:
根据参考here 以下函数应在“immintrin.h”中定义
__m128i _mm_idiv_epi32 (__m128i a, __m128i b);
__m128i _mm_idivrem_epi32 (__m128i * mem_addr, __m128i a, __m128i b);
__m128i _mm_set_epi32 (int e3, int e2, int e1, int e0);
但根据我的测试程序,它们不是:
#include "immintrin.h"
int main() {
__m128i a = _mm_set_epi32(4,3,2,1);
__m128i b = _mm_set_epi32(1,2,3,4);
__m128i c = _mm_idiv_epi32(a,b);
__m128i d;
c = _mm_idivrem_epi32(&d, a, b);
}
编译失败并显示以下错误消息:
cc -g scratch.c && ./a.out
scratch.c: In function 'main':
scratch.c:11:15: warning: implicit declaration of function '_mm_idiv_epi32'; did you mean '_mm_rorv_epi32'? [-Wimplicit-function-declaration]
__m128i c = _mm_idiv_epi32(a,b);
^~~~~~~~~~~~~~
_mm_rorv_epi32
scratch.c:11:15: error: incompatible types when initializing type '__m128i {aka __vector(2) long long int}' using type 'int'
scratch.c:14:7: warning: implicit declaration of function '_mm_idivrem_epi32'; did you mean '_mm_movm_epi32'? [-Wimplicit-function-declaration]
c = _mm_idivrem_epi32(&d, a, b);
^~~~~~~~~~~~~~~~~
_mm_movm_epi32
scratch.c:14:5: error: incompatible types when assigning to type '__m128i {aka __vector(2) long long int}' from type 'int'
c = _mm_idivrem_epi32(&d, a, b);
显然这些功能根本没有定义。那么我做错了什么?我错过了什么吗?
【问题讨论】:
-
您可能需要检查编译器的内在函数,以及您要编译的硬件。
-
x86 没有 SIMD 整数除法指令,只有 SIMD 浮点除法指令。 (以及标量整数和 FP 除法)。
_mm_idivrem_epi32不是内在函数,它是 Intel 库函数。请注意,它被列为 SVML 函数,而不是指令集的一部分,并且描述中没有列出单个 asm 指令。 -
要除以编译时常数向量,请使用乘法逆技巧,手动(like I did using GNU C native vectors to get the compiler to do it for me, in
vec_store_digit_and_space,或使用libdivide.com(也适用于运行时变量)。 -
如果您的除数不是常数,并且整数小于 2^24(或舍入可以),则转换为浮点数并使用 SIMD FP 除法。对于单个常量整数,请参阅stackoverflow.com/questions/16822757/sse-integer-division(尽管使用 AVX2 变量移位指令,您可以对不同元素进行不同的移位,并且可能使整数公式适用于不同除数的常量向量)
-
对于 16 位整数,有乘法指令占用高半部分,因此您可以使用 very fast approximate division with
mulhrs_epi16,或者使用 the full multiplicative inverse trick with shifts 精确计算所有输入。另见How to let GCC compiler turn variable-division into mul(if faster)
标签: c x86 sse simd intrinsics