(This is my first post ever on stack overflow, please lmk if I've done something wrong)
I'm currently brushing up on assembly
code for C
and doing some sample problems to test my understanding. One multiple-choice practice problem gives a description of the code in C
and asks you to pick the corresponding assembly
code. Answers A
and C
are clearly wrong. Answers B
and D
are identical (I ran them through a text comparison thing to make sure I wasn't missing anything, that's how sure I am that they're identical) except for the following two (greatly simplified) lines:
# Answer B
...
6 testq %rax, %rax
7 jle .L3
...
# Answer D
...
6 cmpq $0, %rax
7 jle .L3
...
According to the practice problem, D
is correct and B
is wrong.
But from what I understand, shouldn't they calculate the same thing? Here's my reasoning, can anyone tell me where I went wrong?
1. Both testq
and cmpq
alter condition codes but not the registers themselves, so nothing but the condition codes should make a difference.
2. testq S1 S2
will set condition codes according to the calculation S1&S2
. If S1==S2
(both %rax
here), testq
should set condition codes according to whatever is currently in %rax
.
3. cmpq S1 S2
will set condition codes according to the calculation S2-S1
. If S1==0
, then cmpq
should set condition codes according to %rax-0 = %rax
.
So they're both setting condition codes according to the same thing, the contents of %rax
. That was enough to really confuse me. I thought maybe looking at the problem at a lower level, specifically in terms of condition codes, might clear things up, but that didn't really help either.
4. This specific jump (jle/jng if you prefer) will jump to .L3
if (SF^OF)|ZF
is true.
5. %rax
is not going to overflow on something&something or something-0, so OF=0
. Therefore it will jump if SF=1 or ZF=1.
6a. If %rax
is negative, %rax & %rax
will still yield a negative, so SF is set and jump occurs. If %rax
is negative, %rax-$0
will still yield a negative, so SF is set and jump occurs.
6b. If %rax
is 0, %rax&%rax
is 0, so ZF is set and jump occurs. If %rax
is0, %rax-0 = 0-0 = 0
, so ZF
is set and jump occurs.
6c. If %rax
is positive (and non-zero), %rax&%rax
will yield a positive (non-zero), so SF=0
and ZF=0
and the jump doesn't happen. If %rax
is positive (non-zero), %rax-0
will yield a positive (non-zero), so SF=0
and ZF=0
and the jump doesn't happen.
Where did I go wrong? From what I understand after thinking about the problem, shouldn't it always be true that
testq R,R
has the same logical outcome as
cmpq $0,R
(Note: I know almost nothing about efficiency. It's possible one instruction is shorter or more efficient than the other, but I'm primarily concerned with the logical/condition code outcomes here. For real code and not just textbook problems, the computer/gcc will decide which one it thinks is faster later, when it optimizes it to the point of being unreadable.)
Thanks!