(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 %raxis0, %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!