在thumb 2汇编中,当r 0和r1有有符号整数时,我希望r1=-1(i.即0xffffffff),否则r1=0。
我可以简单地写代码:
4288 cmp r0, r1
bfb4 ite lt
f04f 31ff movlt.w r1, #-1
2100 movge r1, #0
但我想知道是否有更优化的方式,无论是在周期或空间。
如果它是一个unsigned比较,我可以使用进位标志:
4288 cmp r0, r1
4189 sbcs r1, r1
在ARM 64中,cset r1, lt
会返回0或1,但我喜欢在thumb 2汇编中编写代码。
1条答案
按热度按时间tquggr8v1#
**如果你的输入范围有限,所以减法不会有符号溢出,**你可以使用Jester的建议,使用减法的符号位:
只要
r0-r1
不溢出2的补码有符号整数,这就可以工作。那么,当r0 < r1
时,结果的符号确实是负的。失败的情况包括
-10 < INT_MAX
,数学结果是-2147483657
,但截断为32位,我们得到0x7ffffff7
(+2147483639
)。V标志将被设置,指示有符号的overflow,并且N标志(符号位)将被清除,因为截断结果不是负的,与数学非截断结果的符号相反。这就是为什么像
lt
这样的signed compare conditions检查N != V
,而不仅仅是N
,所以例如cmp
/blt
可以正确地使用这些输入。**如果你的代码必须正确地处理任意输入(全范围),我不认为有任何改进的空间,甚至在代码大小上也是如此。**使用
lt
条件,分支或it
预测,似乎是唯一合理的选择。手动模拟2的补码比较不会比这更短。即使在IT块之外,ARM Thumb 2也没有用于将寄存器设置为
-1
的2字节指令。(至少编译器不知道或使用。)movs
不对其立即数进行符号扩展,而mvn
/mvns
-immediate是一条4字节指令。orrs r0, #-1
也是如此,并不是说您无论如何都希望这种虚假的依赖关系来提高性能。因此,即使我们可以在与任何输入不同的寄存器中产生结果,也没有节省。当前的GCC和clang(Godbolt)更喜欢无条件地设置一个寄存器,然后Assert一个
mov
-immediate来覆盖它。但这可能只是Thumb模式的启发式,如果其中一个常量允许IT块外部的更短指令,或者在填充IT块并需要另一个IT或无法合并成一个ITE的情况下,预测更少的指令。这可能发生在一个更大的函数中,或者如果其他事情是在相同的条件下预测的,但在这里不是问题。ARM模式下(
-marm
),GCC首选cmp
;movge r0, #0
;mvnlt r0, #0
对于我看过的所有-mcpu=
(cortex-a8,cortex-a53,cortex-a76和unset)。(我正在看一个函数,所以它返回r 0,但输入是r 0和r1,所以它仍然是你的情况一样。)所以这和你的拇指模式的策略完全一样。除非IT块内部的指令比外部的指令慢,否则最好还是做你正在做的事情。