如何用SSE2指令将无符号32位整数钳位到0x10000并简化代码?
简化SSE2实现32位无符号整数钳位到0x10000的汇编代码
需求是将XMM0中存储的4个32位无符号整数钳位到0x10000(对应C逻辑:if (c > 0x10000) c = 0x10000;),利用0x10000的特性(二进制为1<<16),可以大幅简化原有汇编代码,以下分通用场景和受限输入场景给出优化方案:
通用场景(输入范围0x00000000~0xFFFFFFFF)
利用SSE2的无符号减法指令psubusd直接判断数值是否超过阈值,生成掩码后选择保留原值或替换为0x10000:
movdqa xmm3, xmm0 ; 保存XMM0中的原始无符号双字 movdqa xmm4, xmm5 ; XMM5预存4个0x10000的32位常量 psubusd xmm3, xmm4 ; 无符号减法:c>0x10000时结果为c-0x10000,否则为0 pcmpeqd xmm3, xmm0 ; 生成掩码:c<=0x10000时对应位置为0xFFFFFFFF,否则为0 pand xmm0, xmm3 ; 保留未超过阈值的原值,超过的位置清零 pandn xmm3, xmm5 ; 生成替换掩码:超过阈值的位置设为0x10000,否则为0 por xmm0, xmm3 ; 合并结果,完成钳位
相比原有代码,减少了3条指令,逻辑更直观,无需额外处理有符号/无符号比较的转换。
受限输入场景(输入范围0x00000000~0x00FFFFFF)
若输入数值最高8位恒为0,那么c>0x10000等价于数值的高16位不为0,可直接通过右移提取高16位生成掩码:
movdqa xmm3, xmm0 ; 保存原始值 movdqa xmm4, xmm5 ; XMM5预存4个0x10000常量 psrld xmm3, 16 ; 提取每个双字的高16位 pcmpeqd xmm3, xmm0 ; 高16位为0时(c<=0xFFFF<0x10000)生成0xFFFFFFFF掩码,否则为0 pand xmm0, xmm3 ; 保留未超阈值的值 pandn xmm3, xmm5 ; 生成超阈值的替换值 por xmm0, xmm3 ; 合并结果
此方案进一步简化了判断逻辑,利用输入范围特性减少了减法操作。
受限输入场景(输入范围0x00000000~0x00FF0000)
若输入数值低16位恒为0(即格式为0xXX0000),则c>0x10000等价于高16位大于1,可通过比较高16位生成掩码:
movdqa xmm3, xmm0 ; 保存原始值 movdqa xmm4, xmm5 ; XMM5预存4个0x10000常量 psrld xmm3, 16 ; 提取高16位(即XX部分) pcmpltd xmm3, xmm1 ; XMM1预存4个1的32位常量,XX<=1时生成0xFFFFFFFF掩码 pand xmm0, xmm3 ; 保留c<=0x10000的值 pandn xmm3, xmm5 ; 生成超阈值的替换值 por xmm0, xmm3 ; 合并结果
此方案完全利用输入的格式特性,判断逻辑最简洁。
内容的提问来源于stack exchange,提问作者Sanyin
相关产品推荐
相关产品推荐

