我想使用Intel内在函数(16位无符号整数向量)进行一些操作,操作如下:
来自unsigned short int数组的加载或设置。
使用unsigned short intDiv 和 Mod 操作。
使用unsigned short int乘法操作。
将unsigned short int的操作操作到数组中。
我查看了内在函数指南,但看起来只有短整数的内在函数而不是未签名的整数。有人可以帮我解决这个问题吗?
实际上,我正在尝试将特定栅格格式的图像存储在具有特定排序的数组中。所以我必须计算每个像素值将被存储的索引:
unsigned int Index(unsigned int interleaving_depth, unsigned int x_size, unsigned int y_size, unsigned int z_size, unsigned int Pixel_number)
{
unsigned int x = 0, y = 0, z = 0, reminder = 0, i = 0;
y = Pixel_number/(x_size*z_size);
reminder = Pixel_number % (x_size*z_size);
i = reminder/(x_size*interleaving_depth);
reminder = reminder % (x_size*interleaving_depth);
if(i == z_size/interleaving_depth){
x = reminder/(z_size - i*interleaving_depth);
reminder = reminder % (z_size - i*interleaving_depth);
}
else
{
x = reminder/interleaving_depth;
reminder = reminder % interleaving_depth;
}
z = interleaving_depth*i + reminder;
if(z >= z_size)
z = z_size - 1;
return x + y*x_size + *x_size*y_size;
}
答案 0 :(得分:3)
如果您只想要结果的低半部分,则乘法与有符号或无符号的二进制运算相同。因此,您可以使用pmullw
。但是,对于签名和无符号短片,有单独的高半乘法指令:_mm_mulhi_epu16
(pmulhuw
)与_mm_mulhi_epi16
(pmuluw
)
同样,您不需要_mm_set_epu16
,因为它的操作相同:在x86上转换为签名并不会改变位模式,因此英特尔只打算提供_mm_set_epi16
,但您可以使用0xFFFFu
之类的args代替-1
而没有任何问题。 (自动使用Intel内在函数意味着您的代码只能移植到x86 32和64位。)
加载/存储内在函数根本不会更改数据。
SSE / AVX没有整数除法或mod指令。如果你有编译时常数除数,可以用乘法/移位自己做。您可以查看编译器输出以获得魔术常量和移位计数(Why does GCC use multiplication by a strange number in implementing integer division?),甚至让gcc为您自动矢量化。甚至可以使用GNU C本机向量语法来划分:
#include <immintrin.h>
__m128i div13_epu16(__m128i a)
{
typedef unsigned short __attribute__((vector_size(16))) v8uw;
v8uw tmp = (v8uw)a;
v8uw divisor = (v8uw)_mm_set1_epi16(13);
v8uw result = tmp/divisor;
return (__m128i)result;
// clang allows "lax" vector type conversions without casts
// gcc allows vector / scalar, e.g. tmp / 13. Clang requires set1
// to work with both, we need to jump through all the syntax hoops
}
使用gcc和clang(Godbolt compiler explorer)编译此asm:
div13_epu16:
pmulhuw xmm0, XMMWORD PTR .LC0[rip] # tmp93,
psrlw xmm0, 2 # tmp95,
ret
.section .rodata
.LC0:
.value 20165
# repeats 8 times
如果你有运行时变量除数,它会变慢,但你可以使用http://libdivide.com/。如果重复使用相同的除数,那也不算太糟糕,所以你只需要为它计算一次定点逆,但是使用任意逆的代码需要一个变量移位计数,这对于SSE效率较低(也适用于整数),以及可能更多的指令,因为有些除数需要比其他除数更复杂的序列。