SIMD函数整理:01 《PC平台新技术MMX(上册):开发编程指南》第8章 MMX编码技术
2012-04-26 22:22
525 查看
一、来源
来源:《PC平台新技术MMX(上册):开发编程指南》第8章 MMX编码技术
书籍信息——
http://e.360buy.com/30027396.html
PC平台新技术MMX(上册):开发编程指南
作 者: 吴乐南 编
出 版 社: 东南大学出版社
ISBN:9787810502528
出版时间:1997-10-01
页 数:149
字 数:237000
所属分类:
电子书 > 计算机与互联网 > 编程语言与程序设计
电子书 > 计算机与互联网 > 计算机工具书
二、整理后的代码
代码——
来源:《PC平台新技术MMX(上册):开发编程指南》第8章 MMX编码技术
书籍信息——
http://e.360buy.com/30027396.html
PC平台新技术MMX(上册):开发编程指南
作 者: 吴乐南 编
出 版 社: 东南大学出版社
ISBN:9787810502528
出版时间:1997-10-01
页 数:149
字 数:237000
所属分类:
电子书 > 计算机与互联网 > 编程语言与程序设计
电子书 > 计算机与互联网 > 计算机工具书
二、整理后的代码
代码——
#include <Windows.h> #include <stdlib.h> #include <stdio.h> #include <time.h> #include <conio.h> #include <assert.h> // MMX, SSE, SSE2 #include <emmintrin.h> // 紧缩无符号字 解包为 两组紧缩无符号双字 // 章节:8.1 数据拆封/8.1.1 无符号数拆封 // // result: 两个零扩展的32位双字,来自源的两个低端字。 // mm1_dst_hi: 两个零扩展的32位双字,来自源的两个高端字。 // mm0_src: 源值(紧缩16位无符号数)。 inline __m64 md_unpack_mud4muw(__m64& mm1_dst_hi, const __m64 mm0_src) { __m64 muwZero = _mm_setzero_si64(); // [MMX]赋值为0 mm1_dst_hi = _mm_unpackhi_pi16(mm0_src, muwZero); // 把两个高端字拆封到两个32位双字中。[MMX]高位解包.字到双字 return _mm_unpacklo_pi16(mm0_src, muwZero); // 把两个低端字拆封到两个32位双字中。[MMX]低位解包.字到双字 } // 紧缩带符号字 解包为 两组紧缩带符号双字 // 章节:8.1 数据拆封/8.1.2 带符号数拆封 // // result: 两个符号扩展的32位双字,来自源的两个低端字。 // mm1_dst_hi: 两个符号扩展的32位双字,来自源的两个高端字。 // mm0_src: 源值(紧缩16位带符号数)。 inline __m64 md_unpack_mid4miw(__m64& mm1_dst_hi, const __m64 mm0_src) { // 注:其实并不需要读取mm1_dst_hi,但为了符合语法,只能这样写。 mm1_dst_hi = _mm_srai_pi32(_mm_unpackhi_pi16(mm1_dst_hi, mm0_src), 16); // 把源数据的两个高端字拆分到 第1字与第3字(即两个紧缩双字的高16位),再紧缩双字算术右移16位。使源数据的两个高端字扩展为2个32位带符号双字。 return _mm_srai_pi32(_mm_unpacklo_pi16(mm0_src, mm0_src), 16); // 把源数据的两个低端字拆分到 第1字与第3字(即两个紧缩双字的高16位),再紧缩双字算术右移16位。使源数据的两个低端字扩展为2个32位带符号双字。 } // 两组紧缩带符号双字 交叉饱和紧缩为 紧缩带符号字 // 章节:8.2 数据紧缩/8.2.1 带饱和的交叉紧缩 // 例如:将 {[B1,B0], [A1,A0]} 交叉紧缩为 {[B1',A1',B0',A0']} // 注:紧缩(_mm_packs_pi32)是将 {[B1,B0], [A1,A0]} 转为 {[B1',B0',A1',A0']} // // result: 紧缩16位带符号数。第0字和第2字来自mm0_lo的带符号饱和双字,第1字和第3字来自mm1_hi的带符号饱和双字。 // mm0_lo: 低位源值(A)。 // mm1_hi: 高位源值(B)。 inline __m64 md_pack_s_cross_miw4mid(__m64 mm0_lo, __m64 mm1_hi) { mm1_hi = _mm_packs_pi32(mm1_hi, mm1_hi); // 紧缩并且符号饱和。即变为[B1',B0',B1',B0']。[MMX]饱和打包.双字到字 mm0_lo = _mm_packs_pi32(mm0_lo, mm0_lo); // 紧缩并且符号饱和。即变为[A1',A0',A1',A0']。 return _mm_unpacklo_pi16(mm0_lo, mm1_hi); // 交叉操作数的低16位。[MMX]低位解包.字到双字 } // 两组紧缩无符号双字 交叉环绕紧缩为 紧缩无符号字 // 章节:8.2 数据紧缩/8.2.2 不带饱和的交叉紧缩 // 例如:将 {[B1,B0], [A1,A0]} 交叉紧缩为 {[B1',A1',B0',A0']} // // result: 紧缩16位无符号数。第0字和第2字来自mm0_lo的无符号双字,第1字和第3字来自mm1_hi的无符号双字。 // mm0_lo: 低位源值(A)。 // mm1_hi: 高位源值(B)。 inline __m64 md_pack_w_cross_muw4mud(__m64 mm0_lo, __m64 mm1_hi) { mm1_hi = _mm_slli_pi32(mm1_hi, 16); // 将每个双字的低16位左移至高16位 mm0_lo = _mm_and_si64(mm0_lo, _mm_set_pi16(0, (short)0xFFFF, 0, (short)0xFFFF)); // 用0屏蔽每个双字的最高16位 return _mm_or_si64(mm0_lo, mm1_hi); // 合并两个操作数 } // 2x2矩阵转置.紧缩双字 // 章节:8.3 非交叉拆分 // 例如:将2x2矩阵 [[A1,A0] [B1,B0]] 转置为 [[B0,A0] [B1,A1]]。 // // [A1 A0] [B0 A0] // [B1 B0] -> [B1 A1] // msb<-lsb // // mm0_row0: 2x2矩阵的第0行(A)。 // mm1_row1: 2x2矩阵的第1行(B)。 inline void md_matrix_transpose_2x2_mmd(__m64& mm0_row0, __m64& mm1_row1) { __m64 tmp = mm0_row0; // 备份第0行 mm0_row0 = _mm_unpacklo_pi32(mm0_row0, mm1_row1); // 高32位为mm1_row1的低32位(B0),低32位为源mm0_row0的低32位(A0)。[MMX]低位解包.双字到四字 mm1_row1 = _mm_unpackhi_pi32(tmp , mm1_row1); // 高32位为mm1_row1的高32位(B1),低32位为源mm0_row0的高32位(A1)。[MMX]高位解包.双字到四字 } // 复数与常量相乘(紧缩字->紧缩双字) // 章节:8.4 复数与常量相乘 // // result: 复数乘法的结果,高32位是实部,低32位是虚部。 // mm0_src: 被乘数([?,?,Dr,Di])。 // mm1_c: 已调整好顺序的常量乘数([Cr,-Ci,Ci,Cr])。 inline __m64 md_complex_mul_c_mid4miw(__m64 mm0_src, const __m64 mm1_c) { mm0_src = _mm_unpacklo_pi32(mm0_src, mm0_src); // 产生 [Dr,Di,Dr,Di]。[MMX]低位解包.双字到四字 return _mm_madd_pi16(mm0_src, mm1_c); // 操作结果是 [(Dr*Cr-Di*Ci), (Dr*Ci+Di*Cr)]。[MMX]乘后二加.带符号16位至带符号32位 } // 无符号紧缩字节的绝对差 // 章节:8.5 数的绝对差\8.5.1 无符号数的绝对差 // // result: 无符号紧缩字节的绝对差。伪代码——result[i]=abs(mm0[i] - mm1[i])。 // mm0: 源操作数A。 // mm1: 源操作数B。 inline __m64 md_absolute_deviation_mub(const __m64 mm0, const __m64 mm1) { return _mm_or_si64(_mm_subs_pu8(mm0, mm1), _mm_subs_pu8(mm1, mm0)); // 1. "_mm_subs_pu8(mm0, mm1)": 计算差值 // 2. "_mm_subs_pu8(mm1, mm0)": 以另一种途径计算差值 // 3. "_mm_or_si64(..., ...)": 合并结果 } // 带符号紧缩字的绝对差 // 章节:8.5 数的绝对差\8.5.2 带符号数的绝对差 // // result: 带符号紧缩字的绝对差。伪代码——result[i]=abs(mm0[i] - mm1[i])。 // mm0: 源操作数A。 // mm1: 源操作数B。 inline __m64 md_absolute_deviation_miw(const __m64 mm0, const __m64 mm1) { __m64 miwMaskGt = _mm_cmpgt_pi16(mm0, mm1); // 产生 A>B 的屏蔽值 __m64 miwXor = _mm_and_si64(_mm_xor_si64(mm0, mm1), miwMaskGt); // 产生交换屏蔽值(仅在A>B时的XOR(A,B)值)。即当A>B时,该字是XOR(A,B);而A<=B时,该字是是0。 __m64 miwMin = _mm_xor_si64(mm0, miwXor); // 当A>B时就用xor交换,产生最小值 __m64 miwMax = _mm_xor_si64(mm1, miwXor); // 当B<=A时就用xor交换,产生最大值 return _mm_sub_pi16(miwMax, miwMin); // 绝对差 = 最大值 - 最小值 } // 带符号紧缩字的绝对值 // 章节:8.6 绝对值 // // result: 带符号紧缩字的绝对值。伪代码——result[i]=abs(mm0[i])。 // mm0: 源操作数。 inline __m64 md_abs_miw(const __m64 mm0) { __m64 miwSign = _mm_srai_pi16(mm0, 15); // 将符号位转为掩码。使每个字为全0(对于非负数)或全1(对于负数)。注:补码下的“全1”代表数值“-1”,减法碰到“-1”就形成了“加一”。 return _mm_subs_pi16(_mm_xor_si64(mm0, miwSign), miwSign); // 为了获得绝对值,仅对负数求相反数。补码求相反数规则——原码取反再加一。 } // 将带符号紧缩字限制在[iLow,iHigh]区间 // 章节:8.7 数值的截取/8.7.1 对任意有符号数范围截取符号数/[0] // // result: 限制后的带符号紧缩字。伪代码——result[i]=(mm0[i]<iLow)?iLow:( (mm0[i]>iHigh)?iHigh:mm0[i] )。 // mm0: 源操作数。 inline __m64 md_clamp_miw(const __m64 mm0, short iLow, short iHigh) { const __m64 miwMinInt16 = _mm_set1_pi16((short)0x8000); // 带符号16位的最小值 __m64 tmp = _mm_add_pi16(mm0, miwMinInt16); // 利用环绕加法,将带符号数 偏移至 无符号数的空间。 tmp = _mm_adds_pu16(tmp, _mm_set1_pi16( (short)(0xFFFF-(iHigh+0x8000)) )); // 限制最高值 tmp = _mm_subs_pu16(tmp, _mm_set1_pi16( (short)(0xFFFF-(iHigh+0x8000)+(iLow+0x8000)) )); // 限制最低值 return _mm_add_pi16(tmp, _mm_set1_pi16( iLow )); // 恢复偏移 } // 将无符号紧缩字限制在[uLow,uHigh]区间 // 章节:8.7 数值的截取/8.7.2 对任意有符号数范围截取符号数 // // result: 限制后的带符号紧缩字。伪代码——result[i]=(mm0[i]<uLow)?uLow:( (mm0[i]>uHigh)?uHigh:mm0[i] )。 // mm0: 源操作数。 inline __m64 md_clamp_muw(const __m64 mm0, unsigned short uLow, unsigned short uHigh) { __m64 tmp = _mm_adds_pu16(mm0, _mm_set1_pi16( (short)(0xFFFFU-uHigh) )); // 限制最高值 tmp = _mm_subs_pu16(tmp, _mm_set1_pi16( (short)(0xFFFFU-uHigh+uLow) )); // 限制最低值 return _mm_add_pi16(tmp, _mm_set1_pi16( uLow )); // 恢复偏移 } // 返回常数:0 // 章节:8.8 生成常量/[0]在MM0产生0寄存器 inline __m64 md_setzero_mmq() { __m64 tmp=_mm_setzero_si64(); // 其实并不需要赋值,但为了符合语法,只能这样写。 return _mm_xor_si64(tmp, tmp); // 其实Intrinsics函数中有这样的函数—— // return _mm_setzero_si64(); } // 返回常数:全1 // 章节:8.8 生成常量/[1]在寄存器MM1中置全1,它在每一个紧缩数据类型的值域中都是-1 inline __m64 md_setfull_mmq() { __m64 tmp=_mm_setzero_si64(); // 其实并不需要赋值,但为了符合语法,只能这样写。 return _mm_cmpeq_pi8(tmp, tmp); } // 返回常数:每个紧缩字节为1 // 章节:8.8 生成常量/[2]在每一个紧缩字节[或紧缩字](或紧缩双字)的值域中产生常数1 inline __m64 md_set_1_mib() { __m64 mibZero = _mm_setzero_si64(); __m64 mibNegativeOne = _mm_cmpeq_pi8(mibZero, mibZero); return _mm_sub_pi8(mibZero, mibNegativeOne); } // 返回常数:每个紧缩字为pow(2,n)-1 // 章节:8.8 生成常量/[3]在每一个紧缩字(或紧缩双字)的值域中产生带符号常数pow(2,n)-1 inline __m64 md_set_pow2n_sub1_miw(int n) { assert((n>=1) && (n<=16)); __m64 mibZero = _mm_setzero_si64(); __m64 mibFull = _mm_cmpeq_pi8(mibZero, mibZero); return _mm_srli_pi16(mibFull, 16-n); } // 返回常数:每个紧缩字为-pow(2,n) // 章节:8.8 生成常量/[4]在每一个紧缩字(或紧缩双字)的值域中产生带符号常数-pow(2,n) inline __m64 md_set_neg_pow2n_miw(int n) { assert((n>=0) && (n<=15)); __m64 mibZero = _mm_setzero_si64(); __m64 mibFull = _mm_cmpeq_pi8(mibZero, mibZero); return _mm_slli_pi16(mibFull, n); } // 验证 void doTest(int cnt) { __m64 t0,t1,t2; int i; // 紧缩无符号字 解包为 两组紧缩无符号双字 printf("md_unpack_mud4muw:\n"); t0 = _mm_set_pi32(0x01234567, 0x89ABCDEF); printf("[%.8X%.8X] -> ", t0.m64_u32[1], t0.m64_u32[0]); for(i=0; i<cnt; ++i) { t2 = md_unpack_mud4muw(t1, t0); } printf("[%.8X%.8X],[%.8X%.8X]\n", t1.m64_u32[1], t1.m64_u32[0], t2.m64_u32[1], t2.m64_u32[0]); printf("\n"); // 紧缩带符号字 解包为 两组紧缩带符号双字 printf("md_unpack_mid4miw:\n"); t0 = _mm_set_pi32(0x01234567, 0x89ABCDEF); printf("[%.8X%.8X] -> ", t0.m64_u32[1], t0.m64_u32[0]); for(i=0; i<cnt; ++i) { t2 = md_unpack_mid4miw(t1, t0); } printf("[%.8X%.8X],[%.8X%.8X]\n", t1.m64_u32[1], t1.m64_u32[0], t2.m64_u32[1], t2.m64_u32[0]); printf("\n"); // 两组紧缩带符号双字 交叉饱和紧缩为 紧缩带符号字 printf("md_pack_s_cross_miw4mid:\n"); t1 = _mm_set_pi32(0x00001111, 0x000F2222); t2 = _mm_set_pi32(0xFFFFCCCC, 0xFFFFDDDD); printf("[%.8X%.8X],[%.8X%.8X] -> ", t1.m64_u32[1], t1.m64_u32[0], t2.m64_u32[1], t2.m64_u32[0]); for(i=0; i<cnt; ++i) { t0 = md_pack_s_cross_miw4mid(t2, t1); } printf("[%.8X%.8X]\n", t0.m64_u32[1], t0.m64_u32[0]); printf("\n"); // 两组紧缩无符号双字 交叉环绕紧缩为 紧缩无符号字 printf("md_pack_w_cross_muw4mud:\n"); t1 = _mm_set_pi32(0x00001111, 0x000F2222); t2 = _mm_set_pi32(0xFFFFCCCC, 0xFFFFDDDD); printf("[%.8X%.8X],[%.8X%.8X] -> ", t1.m64_u32[1], t1.m64_u32[0], t2.m64_u32[1], t2.m64_u32[0]); for(i=0; i<cnt; ++i) { t0 = md_pack_w_cross_muw4mud(t2, t1); } printf("[%.8X%.8X]\n", t0.m64_u32[1], t0.m64_u32[0]); printf("\n"); // 2x2矩阵转置.紧缩双字 printf("md_matrix_transpose_2x2_mmd:\n"); t1 = _mm_set_pi32(0x00001111, 0x000F2222); t2 = _mm_set_pi32(0xFFFFCCCC, 0xFFFFDDDD); printf("[%.8X%.8X],[%.8X%.8X] -> ", t1.m64_u32[1], t1.m64_u32[0], t2.m64_u32[1], t2.m64_u32[0]); for(i=0; i<cnt; ++i) { md_matrix_transpose_2x2_mmd(t1, t2); } printf("[%.8X%.8X],[%.8X%.8X]\n", t1.m64_u32[1], t1.m64_u32[0], t2.m64_u32[1], t2.m64_u32[0]); printf("\n"); // 复数与常量相乘(紧缩字->紧缩双字) printf("md_complex_mul_c_mid4miw:\n"); t1 = _mm_set_pi16(0,0, 1, 1); // 1+i t2 = _mm_set_pi16(3,-2, 2,3); // 3+2i. (1+i)*(3+2i) = 1+5i printf("[%.8X%.8X],[%.8X%.8X] -> ", t1.m64_u32[1], t1.m64_u32[0], t2.m64_u32[1], t2.m64_u32[0]); for(i=0; i<cnt; ++i) { t0 = md_complex_mul_c_mid4miw(t1, t2); } printf("[%.8X%.8X]\n", t0.m64_u32[1], t0.m64_u32[0]); printf("\n"); // 无符号紧缩字节的绝对差 printf("md_absolute_deviation_mub:\n"); t1 = _mm_set_pi8(1,2,3,4,5,6,7,8); t2 = _mm_set_pi8(8,7,6,5,4,3,2,1); printf("[%.8X%.8X],[%.8X%.8X] -> ", t1.m64_u32[1], t1.m64_u32[0], t2.m64_u32[1], t2.m64_u32[0]); for(i=0; i<cnt; ++i) { t0 = md_absolute_deviation_mub(t1, t2); } printf("[%.8X%.8X]\n", t0.m64_u32[1], t0.m64_u32[0]); printf("\n"); // 带符号紧缩字的绝对差 printf("md_absolute_deviation_miw:\n"); t1 = _mm_set_pi16(-1, 1, 3, 5); t2 = _mm_set_pi16( 2, 2, 2, 2); printf("[%.8X%.8X],[%.8X%.8X] -> ", t1.m64_u32[1], t1.m64_u32[0], t2.m64_u32[1], t2.m64_u32[0]); for(i=0; i<cnt; ++i) { t0 = md_absolute_deviation_miw(t1, t2); } printf("[%.8X%.8X]\n", t0.m64_u32[1], t0.m64_u32[0]); printf("\n"); // 带符号紧缩字的绝对值 printf("md_abs_miw4miw:\n"); t0 = _mm_set_pi16(-1, 1, 3, -5); printf("[%.8X%.8X] -> ", t0.m64_u32[1], t0.m64_u32[0]); for(i=0; i<cnt; ++i) { t1 = md_abs_miw(t0); } printf("[%.8X%.8X]\n", t1.m64_u32[1], t1.m64_u32[0]); printf("\n"); // 将带符号紧缩字限制在[iLow,iHigh]区间 printf("md_clamp_miw:\n"); t0 = _mm_set_pi16(-15, 1, 254, 257); printf("[%.8X%.8X] -> ", t0.m64_u32[1], t0.m64_u32[0]); for(i=0; i<cnt; ++i) { t1 = md_clamp_miw(t0, -1, 255); } printf("[%.8X%.8X]\n", t1.m64_u32[1], t1.m64_u32[0]); printf("\n"); // 将无符号紧缩字限制在[uLow,uHigh]区间 printf("md_clamp_muw:\n"); t0 = _mm_set_pi16(1, 254, 257, 32769U); printf("[%.8X%.8X] -> ", t0.m64_u32[1], t0.m64_u32[0]); for(i=0; i<cnt; ++i) { t1 = md_clamp_muw(t0, 16, 255); } printf("[%.8X%.8X]\n", t1.m64_u32[1], t1.m64_u32[0]); printf("\n"); // 返回常数:0 printf("md_setzero_mmq:\t"); t0 = md_setzero_mmq(); printf("[%.8X%.8X]\n", t0.m64_u32[1], t0.m64_u32[0]); // 返回常数:全1 printf("md_setfull_mmq:\t"); t0 = md_setfull_mmq(); printf("[%.8X%.8X]\n", t0.m64_u32[1], t0.m64_u32[0]); // 返回常数:每个紧缩字节为1 printf("md_set_1_mib:\t"); t0 = md_set_1_mib(); printf("[%.8X%.8X]\n", t0.m64_u32[1], t0.m64_u32[0]); // 返回常数:每个紧缩字为pow(2,n)-1 printf("md_set_pow2n_sub1_miw:\t"); t0 = md_set_pow2n_sub1_miw(8); printf("[%.8X%.8X]\n", t0.m64_u32[1], t0.m64_u32[0]); // 返回常数:每个紧缩字为pow(2,n)-1 printf("md_set_neg_pow2n_miw:\t"); t0 = md_set_neg_pow2n_miw(15); printf("[%.8X%.8X]\n", t0.m64_u32[1], t0.m64_u32[0]); } int main(int argc, char* argv[]) { doTest((rand()&1) + 1); // 用一个随机数作为循环次数,避免编译器优化循环 return 0; }
相关文章推荐
- SIMD函数整理:01 《PC平台新技术MMX(上册):开发编程指南》第8章 MMX编码技术
- Intel 平台编程总结----SIMD技术
- 基于DotNet构件技术的企业级敏捷软件开发平台 - AgileEAS.NET平台开发指南 - 应用部署
- 综合交易平台API技术开发指南
- Intel 平台编程总结----SIMD技术
- 基于DotNet构件技术的企业级敏捷软件开发平台 - AgileEAS.NET平台开发指南 - 开发流程
- 基于DotNet构件技术的企业级敏捷软件开发平台 - AgileEAS.NET - 文章汇总及学习指南
- 面向 Java 开发人员的 Scala 指南: 面向对象的函数编程
- Intel 平台编程总结----SIMD技术
- 高质量C++/C编程指南 - 第8章 C++函数的高级特性
- Linux平台下4412开发板开发板裸机开发指南 01
- 基于DotNet构件技术的企业级敏捷软件开发平台 - AgileEAS.NET - 文章汇总及学习指南 推荐
- 高质量C++/C编程指南 -- 第8章 C++函数的高级特性
- 基于DotNet构件技术的企业级敏捷软件开发平台 - AgileEAS.NET平台开发指南 - 实现业务
- 高质量C++/C编程指南 -- 第8章 C++函数的高级特性
- 基于DotNet构件技术的企业级敏捷软件开发平台 - AgileEAS.NET平台开发指南 - 数据层开发
- 基于DotNet构件技术的企业级敏捷软件开发平台 - AgileEAS.NET平台开发指南 - 处理报表
- Linux平台开发技术指南
- 基于DotNet构件技术的企业级敏捷软件开发平台 - AgileEAS.NET平台开发指南 - 报表系统集成说明
- 基于DotNet构件技术的企业级敏捷软件开发平台 - AgileEAS.NET平台开发指南 - 数据访问