2021—研一学习笔记 day13

2021-3-31 第十三天

指令集学习

Intel->指令集->SSE

网址:
https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=210,132,831,2823,2822,5999,401,5961,85,157,605,5320,5292,3671,6173,154,2177,4853,602,4853,3505,4853,3896,1941,1292&cats=Convert&techs=SSE

SSE指令集学习
(重点看 加载、导出、逻辑运算、移位运算、shuffle洗牌指令)

头文件:#include <xmmintrin.h>
__m128的定义为:

typedef union __declspec(intrin_type) _CRT_ALIGN(16) __m128 
{  
	 float               m64_f32[4];  
    unsigned __int64    m64_u64[2];  
    __int8              m64_i8[16];  
    __int16             m64_i16[8];  
    __int32             m64_i32[4];      
    __int64             m64_i64[2];  
    unsigned __int8     m64_u8[16];  
    unsigned __int16    m64_u16[8];  
    unsigned __int32    m64_u32[4];  
} __m128;  

正常指令:生成大小相同且类型通常与操作数向量相同的结果向量
宽指令:一个双字操作数和一个四字操作数执行运算,生成四字向量结果
窄指令:四字向量操作数执行运算,生成双字向量结果(减半)
饱和指令:当超过数据类型指定到范围则自动限制在该范围内
长指令:对双字向量操作数执行运算,生成四字向量结果(加倍)

对于float转int
若正常,则四舍五入
如直接截断,则只保留整数

//

//1、Application-Targeted 以应用为目标
2、Arithmetic 算术运算
1)__m128 _mm_add_ps(__m128 a, __m128 b)

FOR j := 0 to 3
	i := j*32
	dst[i+31:i] := a[i+31:i] + b[i+31:i]
ENDFOR
  1. __m128 _mm_add_ss (__m128 a, __m128 b)
dst[31:0] := a[31:0] + b[31:0]
dst[127:32] := a[127:32]

#低32bit执行相加,其他位直接赋a
3) __m128 _mm_div_ps(__m128 a, __m128 b)
4) __m128 _mm_div_ss (__m128 a, __m128 b)
#除法,ps/ss的区分与加法一致
5) __m128 _mm_mul_ps (__m128 a, __m128 b)
6) __m128 _mm_mul_ss (__m128 a, __m128 b)
7) __m128 _mm_sub_ps (__m128 a, __m128 b)
8) __m128 _mm_sub_ss (__m128 a, __m128 b)

  1. __m64 _mm_mulhi_pu16 (__m64 a, __m64 b)
FOR j := 0 to 3
	i := j*16
	tmp[31:0] := a[i+15:i] * b[i+15:i]
	dst[i+15:i] := tmp[31:16]
ENDFOR

#每16bit相乘,取高位16bit赋值

10)__m64 _mm_sad_pu8 (__m64 a, __m64 b)

FOR j := 0 to 7
	i := j*8
	tmp[i+7:i] := ABS(a[i+7:i] - b[i+7:i])
ENDFOR
dst[15:0] := tmp[7:0] + tmp[15:8] + tmp[23:16] + tmp[31:24] + tmp[39:32] + tmp[47:40] + tmp[55:48] + tmp[63:56]
dst[63:16] := 0

#每8bit计算差的绝对值,求和赋值给低16bit,其他位赋0

总结:
ps:正常运算
ss:低32位正常运算,其他均赋为a的值

//3、Bit Manipulation
//4、Cast
5、Compare 比较

__m128 _mm_cmp…

  1. __m128 _mm_cmpeq_ps (__m128 a, __m128 b)
FOR j := 0 to 3
	i := j*32
	dst[i+31:i] := ( a[i+31:i] == b[i+31:i] ) ? 0xFFFFFFFF : 0
ENDFOR

注:共十种类别:eq、ge、gt、le、lt、neq、nge、ngt、nle、nlt

  1. __m128 _mm_cmpord_ps (__m128 a, __m128 b)
FOR j := 0 to 3
	i := j*32
	dst[i+31:i] := ( a[i+31:i] != NaN AND b[i+31:i] != NaN ) ? 0xFFFFFFFF : 0
ENDFOR

ord:a和b均不是NaN,则返回0,否则返回全1
unord:a或b是NaN,则返回0,否则返回全1

#NaN:not a number

int mm(u)comi…_ss
#只比较低32bit,返回值为0或1(不是全1)
#有u为无符号数,没有u为有符号数
1)

int _mm_comieq_ss (__m128 a, __m128 b)
RETURN ( a[31:0] == b[31:0] ) ? 1 : 0

2)

int _mm_ucomigt_ss (__m128 a, __m128 b)
RETURN ( a[31:0] > b[31:0] ) ? 1 : 0

6、Convert 数据类型转换

  1. __m128 _mm_cvt_pi2ps (__m128 a, __m64 b)
    #低64位赋值为b转换后的值,高64位赋值为a
dst[31:0] := Convert_Int32_To_FP32(b[31:0])
dst[63:32] := Convert_Int32_To_FP32(b[63:32])
dst[95:64] := a[95:64]
dst[127:96] := a[127:96]
  1. __m64 _mm_cvt_ps2pi (__m128 a)
    #正常转换(每32位一组)
FOR j := 0 to 1
	i := 32*j
	dst[i+31:i] := Convert_FP32_To_Int32(a[i+31:i])
ENDFOR
  1. __m128 _mm_cvt_si2ss (__m128 a, int b)
    #低32位赋值为b转换后的值,其他位直接赋值为a
dst[31:0] := Convert_Int32_To_FP32(b[31:0])
dst[127:32] := a[127:32]
  1. __m128 _mm_cvtpi16_ps (__m64 a)
    #(每组)16位转32位
FOR j := 0 to 3
	i := j*16
	m := j*32
	dst[m+31:m] := Convert_Int16_To_FP32(a[i+15:i])
ENDFOR

总结:
注:__m128数据类型默认为128bit的float型(4个float寄存器)
__m64数据类型默认为6bit的int型(1个int64寄存器)

若输入为a和b:
①低位为b或b的转换,高位为a或a的转换
②正常是a、b各占一半;ss是b占32位,其他均为a
③正常是b转,a不转;x2是a、b都要转
④指令cvt后的数据类型一般指的是b的类型

若输入为a:
cvt后面为ss,表示a的输入为32位
cvt后面为t,表示直接截断(只取整数,舍弃小数)
int和float都是32位,需要转为这些类型时,用的都是ss
///
//7、Cryptography
8、Elementary Math

  1. __m128 _mm_rcp_ps (__m128 a)
    #取倒数
FOR j := 0 to 3
	i := j*32
	dst[i+31:i] := (1.0 / a[i+31:i])
ENDFOR
  1. __m128 _mm_rcp_ss (__m128 a)
dst[31:0] := (1.0 / a[31:0])
dst[127:32] := a[127:32]

  1. __m128 _mm_rsqrt_ps (__m128 a)
    #取倒数的平方根
FOR j := 0 to 3
	i := j*32
	dst[i+31:i] := (1.0 / SQRT(a[i+31:i]))
ENDFOR
  1. __m128 _mm_sqrt_ps (__m128 a)
    #取平方根
FOR j := 0 to 3
	i := j*32
	dst[i+31:i] := SQRT(a[i+31:i])
ENDFOR

分类:rcp(倒数)、rsqrt(倒数平方根)、sqrt(平方根)

///
///

函数(Functions):

1、General Support
1)void _mm_free (void * mem_addr)
#释放_mm_malloc函数分配的可用对齐内存。
2)void* _mm_malloc (size_t size, size_t align)
#分配内存的大小字节,与align中指定的对齐方式对齐,并返回指向已分配内存的指针。_mm_free应用于释放分配了_mm_malloc的内存。

3)void _mm_prefetch (char const* p, int i)
将地址p的内存中的数据,提取到由i指定的缓存中。

  1. void _MM_SET_EXCEPTION_MASK (unsigned int a)
    #宏:将MXCSR控件和状态寄存器的异常掩码位设置为无符号32位整数a中的值
    5)unsigned int _MM_GET_EXCEPTION_MASK ()
    #宏:从MXCSR控件和状态寄存器获取异常掩码位。
    dst[31:0] := MXCSR & _MM_MASK_MASK

  2. void _mm_setcsr (unsigned int a)
    将MXCSR控制和状态寄存器的值设置为无符号32位整数a。
    MXCSR := a[31:0]
    7)unsigned int _mm_getcsr (void)
    #获取MXCSR控制和状态寄存器的无符号32位值。
    dst[31:0] := MXCSR

  3. void _mm_sfence (void)
    对在此指令之前发出的所有存储到内存指令执行序列化操作。保证在程序顺序中,每个在前面的存储指令在任何在程序顺序中跟随界限的存储指令之前是全局可见的。

  4. __m128 _mm_undefined_ps (void)
    将未定义的元素用容器类型__m128返回

2、Load(加载)
#从内存中加载数据并返回

  1. __m128 _mm_load_ps (float const* mem_addr)
    #正常加载赋值,但需要对齐
dst[127:0] := MEM[mem_addr+127:mem_addr]
  1. __m128 _mm_load_ps1 (float const* mem_addr)
    #只加载开始的32bit,并分别赋值
dst[31:0] := MEM[mem_addr+31:mem_addr]
dst[63:32] := MEM[mem_addr+31:mem_addr]
dst[95:64] := MEM[mem_addr+31:mem_addr]
dst[127:96] := MEM[mem_addr+31:mem_addr]
  1. __m128 _mm_load_ss (float const* mem_addr)
    #加载赋值开始的32bit,其他均赋值为0
dst[31:0] := MEM[mem_addr+31:mem_addr]
dst[127:32] := 0
  1. __m128 _mm_loadh_pi (__m128 a, __m64 const* mem_addr)
    #高位加载赋值,低位用a赋值
dst[31:0] := a[31:0]
dst[63:32] := a[63:32]
dst[95:64] := MEM[mem_addr+31:mem_addr]
dst[127:96] := MEM[mem_addr+63:mem_addr+32]
  1. __m128 _mm_loadl_pi (__m128 a, __m64 const* mem_addr)
    #低位加载赋值,高位用a赋值
dst[31:0] := MEM[mem_addr+31:mem_addr]
dst[63:32] := MEM[mem_addr+63:mem_addr+32]
dst[95:64] := a[95:64]
dst[127:96] := a[127:96]
  1. __m128 _mm_loadr_ps (float const* mem_addr)
    #按寄存器反向顺序赋值
dst[31:0] := MEM[mem_addr+127:mem_addr+96]
dst[63:32] := MEM[mem_addr+95:mem_addr+64]
dst[95:64] := MEM[mem_addr+63:mem_addr+32]
dst[127:96] := MEM[mem_addr+31:mem_addr]
  1. __m128 _mm_loadu_ps (float const* mem_addr)
    #正常加载赋值,不需要对齐
dst[127:0] := MEM[mem_addr+127:mem_addr]
  1. __m128i _mm_loadu_si16 (void const* mem_addr)
    #只加载赋值16bit,其他均赋值为0
dst[15:0] := MEM[mem_addr+15:mem_addr]
dst[MAX:16] := 0

3、Logical(逻辑运算)

  1. __m128 _mm_and_ps (__m128 a, __m128 b)
FOR j := 0 to 3
	i := j*32
	dst[i+31:i] := (a[i+31:i] AND b[i+31:i])
ENDFOR
  1. __m128 _mm_andnot_ps (__m128 a, __m128 b)
  2. __m128 _mm_or_ps (__m128 a, __m128 b)
  3. __m128 _mm_xor_ps (__m128 a, __m128 b)
FOR j := 0 to 3
	i := j*32
	dst[i+31:i] := a[i+31:i] XOR b[i+31:i]
ENDFOR

//4、Mask(掩码)
5、Miscellaneous

  1. int _mm_movemask_pi8 (__m64 a)
    #每8位取最高位,并存储,共8bit,其他位赋0
FOR j := 0 to 7
	i := j*8
	dst[j] := a[i+7]
ENDFOR
dst[MAX:8] := 0
  1. int _mm_movemask_ps (__m128 a)
    #每32位取最高位,并存储,共4bit,其他位赋0

  2. int _m_pmovmskb (__m64 a) 同1)

  3. __m64 _mm_sad_pu8 (__m64 a, __m64 b)
    #每8位,求差的绝对值,并累加赋值到16bit中,其他位置赋0

FOR j := 0 to 7
	i := j*8
	tmp[i+7:i] := ABS(a[i+7:i] - b[i+7:i])
ENDFOR
dst[15:0] := tmp[7:0] + tmp[15:8] + tmp[23:16] + tmp[31:24] + tmp[39:32] + tmp[47:40] + tmp[55:48] + tmp[63:56]
dst[63:16] := 0
  1. __m64 _m_psadbw (__m64 a, __m64 b) 同4)

6、Move (数据传送)

  1. __m128 _mm_move_ss (__m128 a, __m128 b)
dst[31:0] := b[31:0]
dst[127:32] := a[127:32]
  1. __m128 _mm_movehl_ps (__m128 a, __m128 b)
dst[31:0] := b[95:64]
dst[63:32] := b[127:96]
dst[95:64] := a[95:64]
dst[127:96] := a[127:96]
  1. __m128 _mm_movelh_ps (__m128 a, __m128 b)
dst[31:0] := a[31:0]
dst[63:32] := a[63:32]
dst[95:64] := b[31:0]
dst[127:96] := b[63:32]

//7、OS-Targeted
8、Probability/Statistics(概率/统计)

  1. __m64 _mm_avg_pu16 (__m64 a, __m64 b)
    #每16位一组,求平均
FOR j := 0 to 3
	i := j*16
	dst[i+15:i] := (a[i+15:i] + b[i+15:i] + 1) >> 1
ENDFOR
  1. __m64 _mm_avg_pu8 (__m64 a, __m64 b)
    #每8位一组,求平均
FOR j := 0 to 7
	i := j*8
	dst[i+7:i] := (a[i+7:i] + b[i+7:i] + 1) >> 1
ENDFOR
  1. __m64 _m_pavgb (__m64 a, __m64 b) 同2)
  2. __m64 _m_pavgw (__m64 a, __m64 b) 同1)

//9、Random
10、Set 设置(赋值)

  1. __m128 _mm_set_ps (float e3, float e2, float e1, float e0)
    #正常赋值
dst[31:0] := e0
dst[63:32] := e1
dst[95:64] := e2
dst[127:96] := e3
  1. __m128 _mm_set_ps1 (float a)
    #一个值赋值4次
FOR j := 0 to 3
	i := j*32
	dst[i+31:i] := a[31:0]
ENDFOR
  1. __m128 _mm_set_ss (float a)
    #只赋值32bit,其他赋0
  2. __m128 _mm_set1_ps (float a) 同2)

#反着赋值

dst[31:0] := e3
dst[63:32] := e2
dst[95:64] := e1
dst[127:96] := e0
  1. __m128 _mm_setzero_ps (void)
    #都赋为0
dst[MAX:0] := 0

//11、Shift
12、Special Math Functions (特殊数学函数)

  1. __m64 _m_pmaxsw (__m64 a, __m64 b)
  2. __m64 _m_pmaxub (__m64 a, __m64 b)
  3. __m64 _m_pminsw (__m64 a, __m64 b)
  4. __m64 _m_pminub (__m64 a, __m64 b)

13、Store (存储)

  1. void _mm_maskmove_si64 (__m64 a, __m64 mask, char* mem_addr)
    #使用掩码(当对应的元素中没有设置最高位时,不存储元素),每次8bit
FOR j := 0 to 7
	i := j*8
	IF mask[i+7]
		MEM[mem_addr+i+7:mem_addr+i] := a[i+7:i]
	FI
ENDFOR
  1. void _m_maskmovq (__m64 a, __m64 mask, char* mem_addr)
  2. void _mm_store_ps (float* mem_addr, __m128 a)
MEM[mem_addr+127:mem_addr] := a[127:0]
  1. void _mm_store_ps1 (float* mem_addr, __m128 a)
MEM[mem_addr+31:mem_addr] := a[31:0]
MEM[mem_addr+63:mem_addr+32] := a[31:0]
MEM[mem_addr+95:mem_addr+64] := a[31:0]
MEM[mem_addr+127:mem_addr+96] := a[31:0]
  1. void _mm_store_ss (float* mem_addr, __m128 a)
MEM[mem_addr+31:mem_addr] := a[31:0]
  1. void _mm_storeh_pi (__m64* mem_addr, __m128 a)
MEM[mem_addr+31:mem_addr] := a[95:64]
MEM[mem_addr+63:mem_addr+32] := a[127:96]
  1. void _mm_storel_pi (__m64* mem_addr, __m128 a)
MEM[mem_addr+31:mem_addr] := a[31:0]
MEM[mem_addr+63:mem_addr+32] := a[63:32]
  1. void _mm_storer_ps (float* mem_addr, __m128 a)
MEM[mem_addr+31:mem_addr] := a[127:96]
MEM[mem_addr+63:mem_addr+32] := a[95:64]
MEM[mem_addr+95:mem_addr+64] := a[63:32]
MEM[mem_addr+127:mem_addr+96] := a[31:0]
  1. void _mm_stream_pi (__m64* mem_addr, __m64 a)
MEM[mem_addr+63:mem_addr] := a[63:0]
  1. void _mm_stream_ps (float* mem_addr, __m128 a)
    使用非时态内存提示将128位(由4个压缩单精度(32位)浮点元素组成)从内存存储到内存中。mem_addr必须在16字节边界上对齐,否则可能会生成一般保护异常。
MEM[mem_addr+127:mem_addr] := a[127:0]

注:r:反着赋值 1:赋相同的值
///
//14、String Compare
15、Swizzle (交替)

  1. int _mm_extract_pi16 (__m64 a, int imm8)
    #在imm8指定位置从a中提取16bit数,并存在低位
dst[15:0] := (a[63:0] >> (imm8[1:0] * 16))[15:0]
dst[31:16] := 0
  1. int _m_pextrw (__m64 a, int imm8) 同1)
  2. __m64 _mm_insert_pi16 (__m64 a, int i, int imm8)
    #在64bit的a中,在imm8指定位置插入16bit
dst[63:0] := a[63:0]
sel := imm8[1:0]*16
dst[sel+15:sel] := i[15:0]
  1. __m64 _m_pinsrw (__m64 a, int i, int imm8) 同3)
  2. __m64 _mm_shuffle_pi16 (__m64 a, int imm8)
    #shuffle 洗牌指令 根据imm8中的值(0/1/2/3)进行重新排序
    #一组16bit,共4组
DEFINE SELECT4(src, control) {
	CASE(control[1:0]) OF
	0:	tmp[15:0] := src[15:0]
	1:	tmp[15:0] := src[31:16]
	2:	tmp[15:0] := src[47:32]
	3:	tmp[15:0] := src[63:48]
	ESAC
	RETURN tmp[15:0]
}
dst[15:0] := SELECT4(a[63:0], imm8[1:0])
dst[31:16] := SELECT4(a[63:0], imm8[3:2])
dst[47:32] := SELECT4(a[63:0], imm8[5:4])
dst[63:48] := SELECT4(a[63:0], imm8[7:6])
  1. __m128 _mm_shuffle_ps (__m128 a, __m128 b, unsigned int imm8)
    #一组32bit,共4组

  2. __m128 _mm_unpackhi_ps (__m128 a, __m128 b)
    #取a和b的高半区,并交叉赋值

DEFINE INTERLEAVE_HIGH_DWORDS(src1[127:0], src2[127:0]) {
	dst[31:0] := src1[95:64] 
	dst[63:32] := src2[95:64] 
	dst[95:64] := src1[127:96] 
	dst[127:96] := src2[127:96] 
	RETURN dst[127:0]	
}
dst[127:0] := INTERLEAVE_HIGH_DWORDS(a[127:0], b[127:0])
  1. __m128 _mm_unpacklo_ps (__m128 a, __m128 b)
    #取a和b的低半区,并交叉赋值

9)void _MM_TRANSPOSE4_PS (__m128 row0, __m128 row1, __m128 row2, __m128 row3)
#row0 := row3[31:0], row2[31:0], row1[31:0], row0[31:0];
#row1 := row3[63:32], row2[63:32], row1[63:32], row0[63:32];
#row2 := row3[95:64], row2[95:64], row1[95:64], row0[95:64];
#row3 := row3[127:96], row2[127:96], row1[127:96], row0[127:96];

__m128 tmp3, tmp2, tmp1, tmp0;
tmp0 := _mm_unpacklo_ps(row0, row1);
tmp2 := _mm_unpacklo_ps(row2, row3);
tmp1 := _mm_unpackhi_ps(row0, row1);
tmp3 := _mm_unpackhi_ps(row2, row3);
row0 := _mm_movelh_ps(tmp0, tmp2);
row1 := _mm_movehl_ps(tmp2, tmp0);
row2 := _mm_movelh_ps(tmp1, tmp3);
row3 := _mm_movehl_ps(tmp3, tmp1);

//16、Trigonometry

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值