对于以下功能...
uint16_t swap(const uint16_t value)
{
return value << 8 | value >> 8;
}
...为什么带 -O2 的 ARM gcc 6.3.0 会产生以下程序集?
swap(unsigned short):
lsr r3, r0, #8
orr r0, r3, r0, lsl #8
lsl r0, r0, #16 # shift left
lsr r0, r0, #16 # shift right
bx lr
编译器似乎使用两次移位来屏蔽不需要的字节,而不是使用逻辑 AND。编译器可以改为使用and r0, r0, #4294901760
?
较旧的 ARM 程序集无法轻松创建常量。相反,它们被加载到文字池中,然后通过内存加载读入。这and
你建议只能采用我相信带有移位的 8 位文字。你的0xFFFF0000
需要 16 位来执行 1 条指令。
所以,我们可以从内存中加载并执行and
(慢的),
采用 2 条指令来创建值,并采用 1 条指令来创建值(更长),
或者只是便宜地转移两次并称之为好的。
编译器选择了移位,老实说,它非常快。
现在进行现实检查:
担心一个班次,除非这确实是 100% 的瓶颈,否则就是浪费时间。即使编译器不是最优的,您也几乎永远不会感觉到。担心代码中的“热”循环,而不是像这样的微操作。出于好奇心来看这个真是太棒了。不必太担心应用程序性能的确切代码。
Edit:
这里的其他人已经指出,新版本的 ARM 规范允许更有效地完成此类事情。这表明,在这个级别进行讨论时,指定芯片或至少指定我们正在处理的确切 ARM 规范非常重要。我假设古老的 ARM 缺乏从你的输出中给出的“更新”指令。如果我们正在跟踪编译器错误,那么这个假设可能不成立,并且了解规范更为重要。对于这样的交换,在以后的版本中确实有更简单的指令来处理这个问题。
Edit 2
为了使其更快,可以做的一件事就是使其内联。在这种情况下,编译器可以将这些操作与其他工作交织在一起。根据 CPU 的不同,这可能会使吞吐量加倍,因为许多 ARM CPU 都有 2 个整数指令管道。将说明充分展开,以免出现危险,然后它就消失了。这必须与 I-Cache 使用情况进行权衡,但在重要的情况下,您可以看到更好的东西。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)