ToB企服应用市场:ToB评测及商务社交产业平台

标题: x86平台SIMD编程入门(2):通用指令 [打印本页]

作者: 去皮卡多    时间: 2023-12-4 07:04
标题: x86平台SIMD编程入门(2):通用指令
1、重解释转换

虽然128位的XMM寄存器在硬件上只是256位YMM寄存器的下半部分,但在C++中它们是不同的类型。有一些intrinsic函数可以将它们重新解释为不同的类型,如下表所示,行代表源类型,列代表目标类型。
__m128__m128d__m128i__m256__m256d__m256d__m128=_mm_castps_pd_mm_castps_si128_mm256_castps128_ps256__m128d_mm_castpd_ps=_mm_castpd_si128_mm256_castpd128_pd256__m128i_mm_castsi128_ps_mm_castsi128_pd=_mm256_castsi128_si256__m256_mm256_castps256_ps128=_mm256_castps_pd_mm256_castps_si256__m256d_mm256_castpd256_pd128_mm256_castpd_ps=_mm256_castpd_si256__m256i_mm256_castsi256_si128_mm256_castsi256_ps_mm256_castsi256_pd=这些函数不会被编译成任何指令,所以性能上几乎没有损耗,因为它们不改变寄存器中的值,例如32位float浮点数1.0f转换成32位整数后会变为0x3f800000。将128位值转换成256位值时,上半部分是未定义的。
2、类型转换

类型转换只支持带符号的32位整数,例如:
函数示例说明_mm_cvtepi32_ps、_mm256_cvtepi32_ps将32位整数转换成对应的32位浮点数_mm_cvtepi32_pd、_mm256_cvtepi32_pd将32位整数转换成对应的64位浮点数_mm_cvtps_epi32、_mm256_cvtps_epi32将32位浮点数转换成对应的32位整数_mm_cvtpd_epi32、_mm256_cvtpd_epi32将64位浮点数转换成对应的32位整数当浮点数转换为整数时,函数使用MXCSR寄存器中指定的舍入模式,若要更改模式,可以使用宏_MM_SET_ROUNDING_MODE。此外,也有一些名称中带有额外t的函数会忽略MXCSR寄存器,并始终使用向零截断(_MM_ROUND_TOWARD_ZERO)的模式,例如_mm_cvttpd_epi32、_mm_cvttps_epi32。
此外还有一些函数可以在32位浮点数与64位浮点数之间进行转换,例如_mm256_cvtps_pd将32位浮点数转换成64位浮点数。
3、内存访问

3.1、加载

3.2、存储

4、向量寄存器初始化

所有向量寄存器类型都有_mm_setzero_ps或_mm256_setzero_si256这样的函数,用于将寄存器初始化为全零,它可能会被编译成xorps xmm0, xmm0, xmm0这样的指令,其执行效率很高。
虽然CPU无法使用0以外的常量来初始化寄存器,但编译器还是提供了一些函数来实现非0初始化,例如_mm_set_ps可以用不同的值初始化各个通道,_mm256_set1_epi用相同的值初始化所有通道。这些函数的实现依据具体情况而定:如果参数是编译时的常量,它们通常会被编译成二进制文件中的只读数据;如果编译时无法确定参数,编译器就会执行其它合理操作,例如寄存器大部分为0,而我们只设置了一条通道,那么编译器可能会执行插入指令,再比如参数来自变量,编译器就可能会先实行洗牌或标量存储、然后再进行向量加载。
5、向量寄存器与通用寄存器的转换

数据类型数据复制方向函数示例整数向量寄存器最低通道 ==> 通用寄存器_mm_cvtsi128_si32、_mm_cvtsi128_si64整数通用寄存器 ==> 向量寄存器最低通道_mm_cvtsi32_si128、_mm_cvtsi64x_si128浮点数向量寄存器最低通道 ==> 通用寄存器_mm_cvtss_f32、_mm_cvtsd_f64浮点数通用寄存器 ==> 向量寄存器最低通道没有对应的转换函数,但可以使用_mm_set_ps或_mm_set1_ps实现相同功能上表中列举的转换函数只操作向量寄存器的最低通道,除此之外还有一类函数可以将整数向量寄存器任意通道的值复制到通用寄存器,它们是_mm_extract_epi8、_mm_extract_epi16等。
当程序是32位时,所有通用寄存器也都是32位的,在向量寄存器和通用寄存器之间移动64位整数的指令不可用。
6、位运算

浮点数和整数有一套完整的位运算指令,它们包含AND、OR、XOR、ANDNOT指令,例如_mm_and_ps、_mm256_xor_epi32等。如果需要位运算NOT,最快的方法可能是与所有1进行XOR,例如:
  1. __m128i bitwiseNot(__m128i x)
  2. {
  3.     const __m128i zero = _mm_setzero_si128();
  4.     const __m128i one = _mm_cmpeq_epi32(zero, zero);
  5.     return _mm_xor_si128(x, one);
  6. }
复制代码
test指令将计算结果直接保存到int型的通用寄存器中,部分test函数及其功能如下表所示:
函数示例返回结果_mm_testz_si128、_mm256_testz_si256return ((a & b) == 0) ? 1 : 0_mm_testc_si128、_mm256_testc_si256return (((~a) & b) == 0) ? 1 : 0_mm_testnzc_si128、_mm256_testnzc_si256testz和testc结果都为0时返回1,否则返回0_mm_test_all_ones把输入向量取反后与全1向量按位与,如果等于0则返回1,否则返回0_mm_test_all_zeros把输入向量与掩码向量按位与,如果等于0则返回1,否则返回0
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4