SIMD(MMX/SSE/AVX)变量命名规范心得
http://blog.csdn.net/zyl910/article/details/7490598
当使用Intrinsics函数来操作SIMD指令集(MMX/SSE/AVX等)时,会面对不同长度的SIMD数据类型,其中又分为多种紧缩格式。为此,我设计了一套SIMD变量命名规范,可以有效的提高代码的可读性。
一、SIMD数据类型简介
SIMD数据类型有—— __m64:64位紧缩整数(MMX)。 __m128:128位紧缩单精度(SSE)。 __m128d:128位紧缩双精度(SSE2)。 __m128i:128位紧缩整数(SSE2)。 __m256:256位紧缩单精度(AVX)。 __m256d:256位紧缩双精度(AVX)。 __m256i:256位紧缩整数(AVX)。 注:紧缩整数包括了8位、16位、32位、64位的带符号和无符号整数。
这些数据类型与寄存器的对应关系为—— 64位MM寄存器(MM0~MM7):__m64。 128位SSE寄存器(XMM0~XMM15):__m128、__m128d、__m128i。 256位AVX寄存器(YMM0~YMM15):__m256、__m256d、__m256i。
二、SIMD变量命名规范
参考匈牙利命名法(Hungarian notation),在变量名前面增加类型前缀。 类型前缀为3个小写字母,首字母代表寄存器宽度,最后两个字母代表紧缩数据类型。
寄存器宽度(首字母)—— m:64位MM寄存器。对应 __m64 x:128位SSE寄存器。对应 __m128、__m128d、__m128i。 y:256位AVX寄存器。对应 __m256、__m256d、__m256i。
紧缩数据类型(两个字母)—— mb:8位数据。用于只知道长度、不知道具体紧缩格式时。(b:Byte) mw:16位数据。(w:Word) md:32位数据。(d:DoubleWord) mq:64位数据。(q:QuadWord) mo:128位数据。(o:OctaWord) mh:256位数据。(h:HexWord) ub:8位无符号整数。 uw:16位无符号整数。 ud:32位无符号整数。 uq:64位无符号整数。 ib:8位带符号整数。 iw:16位带符号整数。 id:32位带符号整数。 iq:64位带符号整数。 fh:16位浮点数,即半精度浮点数。(h:Half) fs:32位浮点数,即单精度浮点数。(s:Single) fd:64位浮点数,即双精度浮点数。(d:double)
例如—— mub:64位紧缩字节(64位MMX寄存器,其中存放了8个8位无符号整数)。 xfs:128位紧缩单精度(128位SSE寄存器,其中存放了4个单精度浮点数)。 xid:128位紧缩带符号字(128位SSE寄存器,其中存放了4个32位带符号整数)。 yfd:256位紧缩双精度(256位AVX寄存器,其中存放了4个双精度浮点数)。 yfh:256位紧缩半精度(256位AVX寄存器,其中存放了16个半精度浮点数)。
三、示例代码
例如SSE累加求和程序——
- int sum3_Intrinsics(int *a, int size)
- {
- if (NULL==a) return 0;
- if (size<0) return 0;
- int s = 0; // 返回值
- __m128i xidSum = _mm_setzero_si128(); // 累积。[SSE2] 赋初值0
- __m128i xidLoad; // 加载
- int cntBlock = size / 4; // 块数。SSE寄存器能一次处理4个DWORD
- int cntRem = size & 3; // 剩余数量
- __m128i* p = (__m128i*)a;
- for(int i = 0; i < cntBlock; ++i)
- {
- xidLoad = _mm_load_si128(p); // [SSE2] 加载
- xidSum = _mm_add_epi32(xidSum, xidLoad); // [SSE2] 带符号32位紧缩加法
- ++p;
- }
- // 处理剩下的
- int* q = (int*)p;
- for(int i = 0; i < cntRem; ++i) s += q[i];
- // 将累加值合并
- xidSum = _mm_hadd_epi32(xidSum, xidSum); // [SSSE3] 带符号32位水平加法
- xidSum = _mm_hadd_epi32(xidSum, xidSum);
- s += _mm_cvtsi128_si32(xidSum); // [SSE2] 返回低32位
- return s;
- }
int sum3_Intrinsics(int *a, int size)
{
if (NULL==a) return 0;
if (size<0) return 0;
int s = 0; // 返回值
__m128i xidSum = _mm_setzero_si128(); // 累积。[SSE2] 赋初值0
__m128i xidLoad; // 加载
int cntBlock = size / 4; // 块数。SSE寄存器能一次处理4个DWORD
int cntRem = size & 3; // 剩余数量
__m128i* p = (__m128i*)a;
for(int i = 0; i < cntBlock; ++i)
{
xidLoad = _mm_load_si128(p); // [SSE2] 加载
xidSum = _mm_add_epi32(xidSum, xidLoad); // [SSE2] 带符号32位紧缩加法
++p;
}
// 处理剩下的
int* q = (int*)p;
for(int i = 0; i < cntRem; ++i) s += q[i];
// 将累加值合并
xidSum = _mm_hadd_epi32(xidSum, xidSum); // [SSSE3] 带符号32位水平加法
xidSum = _mm_hadd_epi32(xidSum, xidSum);
s += _mm_cvtsi128_si32(xidSum); // [SSE2] 返回低32位
return s;
}
代码出自—— http://topic.csdn.net/u/20120102/01/fc8d7aa4-bffc-4d9a-a34a-5056c6d27b54.html
浙公网安备 33010602011771号