作者:多米音乐_34281398 | 来源:互联网 | 2022-12-07 04:34
我正在优化瓶颈代码:
int sum = ........
sum = (sum >> _bitShift);
if (sum > 32000)
sum = 32000; //if we get an overflow, saturate output
else if (sum <-32000)
sum = -32000; //if we get an underflow, saturate output
short result = static_cast(sum);
我想将饱和条件写为一个"if condition",或者甚至更好,没有"if condition"来使这段代码更快.我不需要精确饱和值为32000,任何类似的值如32768都是可以接受的.
根据此页面,ARM中有一个饱和指令.在x86/x64中有类似的东西吗?
1> Jerry Coffin..:
我完全不相信试图消除这些if
陈述可能会带来任何真正的好处.快速检查表明给出此代码:
int clamp(int x) {
if (x <-32768)
x = -32768;
else if (x > 32767)
x = 32767;
return x;
}
...... gcc和Clang都会产生这样的无分支结果:
clamp(int):
cmp edi, 32767
mov eax, 32767
cmovg edi, eax
mov eax, -32768
cmp edi, -32768
cmovge eax, edi
ret
你可以做类似的事情x = std::min(std::max(x, -32768), 32767);
,但这会产生相同的序列,并且源码似乎不太可读,至少对我而言.
如果你使用英特尔的向量指令,你可以做得比这更好,但可能只有你愿意投入大量的工作 - 特别是你可能需要对整个(小)向量进行操作通过这种方式同时实现价值观.如果你这样做,你通常会想要采取一种与你现在所采取的方法不同的方法.现在,你显然依赖于int
32位类型,所以你在32位类型上进行算术运算,然后将其截断回到(饱和的)16位值.
对于像AVX这样的东西,你通常想要使用一个指令_mm256_adds_epi16
来获取16个值(每个16位)的向量,并同时对所有这些值进行饱和加法(或者同样地,_mm256_subs_epi16
做饱和度减法) ).
由于您正在编写C++,我上面给出的是x86处理器的大多数当前编译器(gcc,icc,clang,msvc)中使用的编译器内在函数的名称.如果您直接编写汇编语言,则说明分别为vpaddsw和vpsubsw.
如果您可以依靠当前的处理器(支持AVX 512指令的处理器),您可以使用它们来同时操作32个16位值的向量.