首页 > 编程语言 >x86平台SIMD编程入门(3):浮点指令

x86平台SIMD编程入门(3):浮点指令

时间:2023-11-04 13:22:49浏览次数:32  
标签:mm256 ps x86 mm 浮点 pd SIMD sd CMP

1、算术指令

算术类型 函数示例 备注
_mm_add_sd_mm256_add_ps
_mm_sub_sd_mm256_sub_ps
_mm_mul_sd_mm256_mul_ps
_mm_div_sd_mm256_div_ps
平方根 _mm_sqrt_sd_mm256_sqrt_ps
倒数 _mm_rcp_ss_mm_rcp_ps_mm256_rcp_ps 快速计算32位浮点数的近似倒数(1/x),最大相对误差小于\(1.5\times 2^{-12}\)。
倒数平方根 _mm_rsqrt_ss_mm_rsqrt_ps_mm256_rsqrt_ps 快速计算32位浮点数的近似倒数平方根(1/sqrt(x)),最大相对误差小于\(1.5\times 2^{-12}\)。
水平加 _mm_hadd_ps_mm256_hadd_pd 输入两个寄存器[a, b, c, d]和[e, f, g, h],返回[a+b, c+d, e+f, g+h]。
水平减 _mm_hsub_ps_mm256_hsub_pd 输入两个寄存器[a, b, c, d]和[e, f, g, h],返回[a-b, c-d, e-f, g-h]。
交替加减 _mm_addsub_ps_mm256_addsub_pd 输入两个寄存器[a, b, c, d]和[e, f, g, h],返回[a-e, b+f, c-g, d+h]。对于复数乘法比较有用。
点乘 _mm_dp_ps_mm_dp_pd_mm256_dp_ps 输入两个寄存器和一个8位常量,常量高4位表示需要点乘的通道,低4位表示需要广播结果的通道。
四舍五入 _mm_round_ps_mm_floor_ss_mm256_ceil_pd
最大/最小值 _mm_min_ss_mm256_max_pd

x86 SIMD指令中没有一元减号或绝对值指令,但可以通过位操作技巧来实现对应的功能,例如_mm_xor_ps(x, _mm_set1_ps(-0.0f))可实现一元减号运算,_mm_andnot_ps(_mm_set1_ps(-0.0f), x)可实现取绝对值。(因为-0.0f浮点数值只把符号位设置为1,其余位均为0,所以_mm_xor_ps会翻转符号,_mm_andnot_ps会清除符号位。)

2、比较指令

SSE实现了各种浮点数比较运算,如下表所示:

运算符 函数示例
等于 _mm_cmpeq_ss_mm_cmpeq_ps_mm_cmpeq_sd_mm_cmpeq_pd
小于 _mm_cmplt_ss_mm_cmplt_ps_mm_cmplt_sd_mm_cmplt_pd
小于等于 _mm_cmple_ss_mm_cmple_ps_mm_cmple_sd_mm_cmple_pd
大于 _mm_cmpgt_ss_mm_cmpgt_ps_mm_cmpgt_sd_mm_cmpgt_pd
大于等于 _mm_cmpge_ss_mm_cmpge_ps_mm_cmpge_sd_mm_cmpge_pd
不等于 _mm_cmpneq_ss_mm_cmpneq_ps_mm_cmpneq_sd_mm_cmpneq_pd
不小于 _mm_cmpnlt_ss_mm_cmpnlt_ps_mm_cmpnlt_sd_mm_cmpnlt_pd
不小于等于 _mm_cmpnle_ss_mm_cmpnle_ps_mm_cmpnle_sd_mm_cmpnle_pd
不大于 _mm_cmpngt_ss_mm_cmpngt_ps_mm_cmpngt_sd_mm_cmpngt_pd
不大于等于 _mm_cmpnge_ss_mm_cmpnge_ps_mm_cmpnge_sd_mm_cmpnge_pd

AVX将浮点数比较指令统一成了_mm_cmp_xx_mm256_cmp_xx这样的形式,然后通过一个常量来表示比较谓语。比较谓语如下表所示,两个数比较时若其中一个数为NaN,则ordered模式将返回false,unordered模式将返回true,另外signalling只影响MXCSR的值。

比较运算 ordered (non-signalling) unordered (non-signalling) ordered (signalling) unordered (signalling)
a < b _CMP_LT_OQ _CMP_NGE_UQ _CMP_LT_OS _CMP_NGE_US
a <= b _CMP_LE_OQ _CMP_NGT_UQ _CMP_LE_OS _CMP_NGT_US
a == b _CMP_EQ_OQ _CMP_EQ_UQ _CMP_EQ_OS _CMP_EQ_US
a != b _CMP_NEQ_OQ _CMP_NEQ_UQ _CMP_NEQ_OS _CMP_NEQ_US
a >= b _CMP_GE_OQ _CMP_NLT_UQ _CMP_GE_OS _CMP_NLT_US
a > b _CMP_GT_OQ _CMP_NLE_UQ _CMP_GT_OS _CMP_NLE_US
true _CMP_ORD_Q _CMP_TRUE_UQ _CMP_ORD_S _CMP_TRUE_US
false _CMP_FALSE_OQ _CMP_UNORD_Q _CMP_FALSE_OS _CMP_UNORD_S

浮点数比较指令返回另一个寄存器来保存结果,其中比较条件成立的值赋为全1(NaN),其它赋为全0(0.0f)。可以使用_mm_movemask_ps_mm_movemask_pd或AVX中的等效指令来将结果发送到CPU通用寄存器,这些指令收集每个浮点数通道的最高有效位(恰好也是符号位)并打包成标量,然后复制到通用寄存器中。

const __m128 zero = _mm_setzero_ps();
const __m128 eq = _mm_cmpeq_ps(zero, zero);
const int mask = _mm_movemask_ps(eq);
printf("%i\n", mask);

在上面这段代码中,对于__m128的所有4个通道,0 == 0的比较结果都是正确的,eq变量的所有128位都设置为1,然后_mm_movemask_ps收集并返回所有4个浮点数通道的符号位,最终打印出的mask值是15,即二进制的0b1111。比较结果的另外一些用途,就是可以将它们作为其它指令的参数(例如blendv指令)。

除了全通道比较函数外,也有一些函数可以只比较两个寄存器的最低通道,如下表所示:

运算符 函数示例
等于 _mm_comieq_ss_mm_comieq_sd
不等于 _mm_comineq_ss_mm_comineq_sd
小于 _mm_comilt_ss_mm_comilt_sd
小于等于 _mm_comile_ss_mm_comile_sd
大于 _mm_comigt_ss_mm_comigt_sd
大于等于 _mm_comige_ss_mm_comige_sd

3、洗牌指令

3.1、固定顺序洗牌

函数示例 说明 示意图
_mm_movehl_ps 将向量a中的高2个元素复制到dst的高2个元素中,将向量b中的高2个元素复制到dst的低2个元素中。
_mm_movelh_ps 将向量a中的低2个元素复制到dst的低2个元素中,将向量b中的低2个元素复制到dst的高2个元素中。
_mm_unpacklo_ps 取向量a和向量b的低半部分元素并交错存储到dst中。
_mm_unpackhi_ps 取向量a和向量b的高半部分元素并交错存储到dst中。
_mm_movehdup_ps 复制输入向量中的奇数索引元素,并存储到dst中。
_mm_moveldup_ps 复制输入向量中的偶数索引元素,并存储到dst中。
_mm_broadcastss_ps 将输入向量的最低通道元素广播到dst的所有元素中。

3.2、编译时洗牌

这类函数都接收一个编译期确定的常量来控制洗牌顺序,如果传入的控制系数无法在编译期确定,那么将导致编译错误,例如:

const __m128 zero = _mm_setzero_ps();
_mm_shuffle_ps(zero, zero, rand()); //error C2057: expected constant expression

下表仅列举了一些参数是__m128类型的洗牌函数,__m128d__m256__m256d也都有对应的函数,可以类推。示意图中蓝色箭头表示使用控制系数选择的内容,灰色箭头表示不同控制系数可能选择的内容。

函数示例 说明 示意图
_mm_shuffle_ps 右图中,控制常数是0x98(二进制 10 01 10 00)。输出向量的前2个通道来自第一个输入向量的0b00和0b10号通道,后2个通道来自第二个输入向量的0b01和0b10号通道。如果要对单个向量进行置换,可将两个输入向量都设为同一个向量。可以使用宏_MM_SHUFFLE来生成控制常数。
_mm_blend_ps 右图中,控制常数为1(二进制 0 0 0 1),所以只从第二个输入向量中提取了对应的0号通道,其余通道都取自第一个输入向量的对应通道。
_mm_insert_ps 插入单个通道,并可选择将某些通道清零。右图中,控制常数为0x61(二进制 01 10 0001):源索引为0b01,目标索引为0b10,所以第二个输入向量中0b01号通道的F被插入了输出的0b10号通道;最低4位为0b0001,因此0号输出通道被清零。此外,我们也可以选择性地将某些通道清零而无需插入,例如控制常数0b00001001将0号和3号通道清零。(也可以使用_mm_blend_ps_mm_setzero_ps实现等价功能,但这就是两条指令,而不是一条。)
_mm_permute_ps _mm_shuffle_ps类似,区别在于仅对一个输入向量进行洗牌。右图中,控制常数是0x63(二进制 01 10 00 11)。

3.3、运行时洗牌

_mm_blendv_ps_mm_blendv_pd_mm256_blendv_ps_mm256_blendv_pd接收3个参数,通过掩码的符号位从向量a或向量b中选择通道。

_mm_permutevar_ps_mm256_permutevar8x32_ps都接收一个包含源数据的浮点数寄存器和一个包含源索引的整数寄存器,根据整数寄存器中的索引值从浮点数寄存器中选择通道。

4、乘加融合指令

乘加运算 函数示例
(a · b) + c _mm_fmadd_ps_mm256_fmadd_pd
(a · b) - c _mm_fmsub_ps_mm256_fmsub_pd
-(a · b) + c _mm_fnmadd_ps_mm256_fnmadd_pd
-(a · b) - c _mm_fnmsub_ps_mm256_fnmsub_pd

相较于分别使用乘法和加法指令,乘加融合(fused multiply-add, FMA)指令除了性能较高外,还更加精确,因为这些指令只在计算完乘法与加法后进行一次舍入。

标签:mm256,ps,x86,mm,浮点,pd,SIMD,sd,CMP
From: https://www.cnblogs.com/moonzzz/p/17808572.html

相关文章

  • x86平台SIMD编程入门(2):通用指令
    1、重解释转换虽然128位的XMM寄存器在硬件上只是256位YMM寄存器的下半部分,但在C++中它们是不同的类型。有一些intrinsic函数可以将它们重新解释为不同的类型,如下表所示,行代表源类型,列代表目标类型。__m128__m128d__m128i__m256__m256d__m256d__m128=_mm_castps_......
  • x86平台SIMD编程入门(1):SIMD基础知识
    1、简介SIMD(SingleInstruction,MultipleData)是一种并行计算技术,它通过向量寄存器存储多个数据元素,并使用单条指令同时对这些数据元素进行处理,从而提高了计算效率。SIMD已被广泛应用于需要大量数据并行计算的领域,包括图像处理、视频编码、信号处理、科学计算等。许多现代处理......
  • 浅析C++中浮点数在内存中的存储方式
    1.任何数据在内存中都是以二进制的形式进行存储。例如,short型数据1156,由于在32位机和64位机都占2B一共16位其二进制形式为:0000010010000100。在IntelCPU架构的系统中(目前用的最多的硬件架构系统),存放方式为10000100(低地址单元)00000100(高地址单元),因为IntelCPU的......
  • libpcre2-8.so.0()(64bit) is needed by zabbix-agent-6.4.0-release1.el7.x86_64
    报错:libpcre2-8.so.0()(64bit)isneededbyzabbix-agent-6.4.0-release1.el7.x86_64解决方法:[root@zabbix_server~]#yuminstallpcre2-......
  • 如何强制进行浮点数除法?除法总是向下取整为0?
    内容来自DOChttps://q.houxu6.top/?s=如何强制进行浮点数除法?除法总是向下取整为0?我有两个整数值a和b,但需要它们的浮点数比率。我知道a<b,我想计算a/b,所以如果我使用整数除法,我总是会得到一个余数为a的0。在Python2中,如何强制将c变成浮点数?c=a/b在......
  • C#中无法将文件“obj\x86\Debug\BookShoopTuto.exe”复制到“bin\Debug\BookShoo
    因为任务多开了,数据无法写入也是因为这个去任务管理区删掉运行的项目就可以了(删掉BookShoopTuto) 参考博客——https://blog.csdn.net/nxg0916/article/details/126782186......
  • 软件模拟实现IEEE-754单精度浮点数运算
    软件模拟实现IEEE-754单精度浮点数运算本文首发于吾爱破解论坛https://www.52pojie.cn/thread-1830228-1-1.html大多数CPU都有硬件的浮点单元(FPU),但是有一些MCU使用的内核(比如Cortex-M3)没有FPU,或者一些内核只支持单精度,同时大部分CPU都不支持高精度128位的浮点数,如果需要使用这......
  • 汇编-浮点单元寄存器
      浮点单元(Floating-PointUnit,FPU)执行高速浮点算术运算。之前为了实现这个目的,需要一个单独的协处理器芯片。从Intel486开始,FPU已经集成到主处理器芯片上了。FPU中有8个浮点数据寄存器,分别命名为ST(0)、ST(1)、ST(2)、ST(3)、ST(4)、ST(5)、ST(6)及ST(7)。其余的控制......
  • 钡铼技术 工控机领域的X86和ARM处理器:哪个更适合你?
    X86和ARM是两种不同的处理器架构,它们在工控机中的应用也有所不同。X86架构的处理器是英特尔公司和AMD公司生产的,它们主要应用于个人电脑和服务器等领域。X86架构的处理器具有良好的通用性和兼容性,可以运行各种操作系统和应用软件。X86架构的处理器的性能强劲,适合处理复杂的计算任务......
  • 钡铼技术 工控机选购指南:理解X86和ARM处理器的区别
    X86和ARM是两种不同的处理器架构,它们在工控机中的应用也有所不同。X86架构的处理器是英特尔公司和AMD公司生产的,它们主要应用于个人电脑和服务器等领域。X86架构的处理器具有良好的通用性和兼容性,可以运行各种操作系统和应用软件。X86架构的处理器的性能强劲,适合处理复杂的计......