有条件地将零移入寄存器?
Posted
技术标签:
【中文标题】有条件地将零移入寄存器?【英文标题】:Conditional move zero into register? 【发布时间】:2020-11-30 18:16:05 【问题描述】:有没有办法在汇编中有条件地将零移动到寄存器中?我正在努力做
cmpb %r9b, %r8b #compare r9 and r8
cmovgq $0, %rcx #If r8>r9, move zero to rcx
但编译器抱怨“cmovg 的操作数类型不匹配”,因为第一个操作数是立即数。我考虑过有条件地跳转到 mov 但我不确定是否还有其他可能更好的操作码。如何在不占用另一个寄存器的情况下有条件地将这个寄存器归零?
【问题讨论】:
您可以在内存中存储一个零并使用内存操作数,但它可能比条件跳转慢。否则,您将需要另一个寄存器。 请注意,您可以在文本段附近的内存中使用一个常量零,并使用相对于 RIP 的地址来访问它。这可能比难以预测的分支更快,但比临时使用另一个寄存器要慢。 【参考方案1】:由于cmovgq
指令不接受立即值操作数,不使用其他寄存器的方法可能是将零值添加到堆栈中,使用其对应地址而不是立即值,然后恢复堆栈指针。
pushq $0 # push 0 onto the stack
cmpb %r9b, %r8b # compare r9b and r8b
cmovgq (%rsp), %rcx # if r8b > r9b, move zero to rcx
addq $8, %rsp # restore stack pointer
或者,与其将零压入堆栈然后恢复堆栈指针,零值可以存储在内存中的其他位置。
cmpb %r9b, %r8b # compare r9b and r8b
cmovgq zero, %rcx # if r8b > r9b, move zero to rcx
...
.section .rodata
zero:
.quad 0
条件跳转不是使用cmovgq
,而是一种替代方法,它不会使用另一个寄存器,并且会导致相同的行为(即,如果r8b > r9b
,rcx
有条件地设置为 0)。
cmpb %r9b, %r8b # compare r9 and r8
jle destination # if r8b <= r9b, skip the next line
movq $0, %rcx # if r8b > r9b, move zero to rcx
destination:
...
【讨论】:
人们出于性能原因使用cmov
,而这些建议对性能不利。正常的方法是在 cmp 之前使用一个额外的寄存器,例如 xor %eax,%eax
,然后使用 cmov,而不是从内存中加载。尤其是不要在它周围推送/添加 rsp。 godbolt.org/z/ncba87 另见 (What is the best way to set a register to zero in x86 assembly: xor, mov or and? - xor not mov)以上是关于有条件地将零移入寄存器?的主要内容,如果未能解决你的问题,请参考以下文章