我正试图在基于Cortex-M的microcontroller上将-127和127之间的值钳位。
我有两个竞争功能,一个使用条件,另一个使用无网格黑客我发现here。
// Using conditional statements
int clamp(int val) { return ((val > 127) ? 127 : (val < -127) ? -127 : val); }
// Using branchless hacks
int clamp(int val) {
val -= -127;
val &= (~val) >> 31;
val += -127;
val -= 127;
val &= val >> 31;
val += 127;
return val;
}
现在我知道在某些情况下,这些方法中的一种可能比另一种方法更快,反之亦然,但总的来说使用无分支技术是值得的,因为它对我来说并不重要,我使用的,在我的情况下,它们都能正常工作吗?
微控制器的一个小背景,它是一个基于ARM的微控制器,运行速度为90 MIPS,具有3级流水线,取指,解码和执行,它似乎有某种分支预测器,但我无法挖掘细节。
答案 0 :(得分:4)
ARM代码(带-O3
的GCC 4.6.3):
clamp1:
mvn r3, #126
cmp r0, r3
movlt r0, r3
cmp r0, #127
movge r0, #127
bx lr
clamp2:
add r0, r0, #127
mvn r3, r0
and r0, r0, r3, asr #31
sub r0, r0, #254
and r0, r0, r0, asr #31
add r0, r0, #127
bx lr
拇指代码:
clamp1:
mvn r3, #126
cmp r0, r3
it lt
movlt r0, r3
cmp r0, #127
it ge
movge r0, #127
bx lr
clamp2:
adds r0, r0, #127
mvns r3, r0
and r0, r0, r3, asr #31
subs r0, r0, #254
and r0, r0, r0, asr #31
adds r0, r0, #127
bx lr
由于ARM的条件执行设计,两者都是无分支的。我敢打赌,他们在性能上基本相当。
答案 1 :(得分:3)
要实现的是ARM和x86架构在分支指令方面有很大不同。跳转可以清除管道,这可以导致多个时钟周期的流失,只是为了“回到原来的位置”。
引用我前几天下载的pdf(http://simplemachines.it/doc/arm_inst.pdf的第14页),
有条件执行
答案 2 :(得分:0)
没有。 C语言没有速度;这是由C的实现引入的概念。完美的最佳编译器会将这两者转换为相同的机器代码。
C编译器更有可能优化符合常见样式且定义良好的代码。第二个功能没有明确定义。
这些加法和减法可能导致整数溢出。整数溢出是未定义的行为,因此它们可能导致程序出现故障。乐观地说,您的硬件可能会实现包装或饱和。稍微不那么乐观,您的操作系统或编译器可能会为整数溢出实现信号或陷阱表示。检测整数溢出可能会影响修改变量的性能。最糟糕的情况是你的程序失去了它的完整性。
&amp;和&gt;&gt;运算符具有已签名类型的实现定义方面。它们可能导致负零,这是陷阱表示的一个例子。使用陷阱表示是未定义的行为,因此您的程序可能会失去它的完整性。
也许您的操作系统或编译器对int对象实施奇偶校验位检查。在这种情况下,尝试想象每次变量更改时重新计算奇偶校验位,并在每次读取变量时验证奇偶校验位。如果奇偶校验失败,您的程序可能会失去它的完整性。
使用第一个功能。至少它定义得很好。如果您的程序运行缓慢,优化此代码可能不会显着加快您的程序速度;使用分析器查找更重要的优化,使用更优化的操作系统或编译器或购买更快的硬件。