3

Is there a way to conditional move a zero into a register in assembly? I'm trying to do

cmpb %r9b, %r8b #compare r9 and r8
cmovgq $0, %rcx #If r8>r9, move zero to rcx

But the compiler is complaining about "operand type mismatch for cmovg" due to the fact that the first operand is an immediate constant. I've thought about conditional jumping to a mov but I'm unsure if there are other opcodes that might be better. How can I conditionally zero this register without eating up another register?

fuz
  • 88,405
  • 25
  • 200
  • 352
Tony S
  • 35
  • 4
  • 4
    You could store a zero in memory and use a memory operand, but it's likely slower than doing the conditional jump. Otherwise, you are going to need another register. – fuz Nov 30 '20 at 18:17
  • 1
    Note that you could have a constant zero in memory near by in the text segment and use an RIP-relative address to access it. That is likely to be faster than a hard to predict branch, but slower than just using another register temporarily. – Chris Dodd Nov 30 '20 at 20:49

1 Answers1

1

Because the cmovgq instruction does not accept an immediate value operand, an approach that would not use another register could be to add the zero value to the stack, use its corresponding address instead of using an immediate value, and then restore the stack pointer.

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

Alternatively, rather than pushing zero to the stack and then restoring the stack pointer, the zero value could be stored elsewhere in memory.

  cmpb    %r9b, %r8b  # compare r9b and r8b
  cmovgq  zero, %rcx  # if r8b > r9b, move zero to rcx
  ...

  .section .rodata
zero:
  .quad 0

Rather than using cmovgq, a conditional jump is an alternative approach that would not use another register, and would result in the same behavior (i.e., rcx conditionally set to 0 if r8b > r9b).

  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:
  ...
dannyadam
  • 3,950
  • 2
  • 22
  • 19
  • 3
    People use `cmov` for performance reasons, and these suggestions are not good for performance. The normal way is to use an extra register, like `xor %eax,%eax` ahead of the cmp, and cmov from that, not load from memory. And especially not push / add rsp around it. https://godbolt.org/z/ncba87 See also ([What is the best way to set a register to zero in x86 assembly: xor, mov or and?](https://stackoverflow.com/q/33666617) - xor not mov) – Peter Cordes Dec 01 '20 at 01:27