Ruslan
Ruslan

Reputation: 19150

Why is such strange code generated?

Consider a piece of C++ code:

int main()
{
    volatile int a=0;
    if(!a)
        ++a;
}

I compile it on amd64 system with g++ (Ubuntu 4.8.1-2ubuntu1~12.04) with command g++ test.cpp -S -o test.S -masm=intel and get the following code:

...
    mov eax, DWORD PTR [ebp-4]
    test    eax, eax
    sete    al
    test    al, al
    je  .L2
    mov eax, DWORD PTR [ebp-4] ; don't use result of sete
    add eax, 1
    mov DWORD PTR [ebp-4], eax
.L2:
    mov eax, 0 ; also drop result of sete
...

This code really surprises me. At first I thought it has something to do with 64-bit mode. But when I tried to compile with -m32, this bit remained the same.

Why does it check eax for being zero and then recheck the result once more after setting al to ZF? Why doesn't it just do test eax,eax\n jne .L2?

Upvotes: 3

Views: 155

Answers (1)

Jonathon Reinhart
Jonathon Reinhart

Reputation: 137547

I think it has to do with how bool is handled differently in C and C++. In your code, the if(!a) first converts a to a bool (that's what the test eax, eax; sete al does), and then tests that boolean (in al) for true/false.

If you rename as .c and compile the same code with gcc, it generates the expected code

    mov DWORD PTR [rbp-4], 0
    mov eax, DWORD PTR [rbp-4]
    test    eax, eax
    jne .L3
    mov eax, DWORD PTR [rbp-4]
    add eax, 1
    mov DWORD PTR [rbp-4], eax
.L3:

In C, it seems that boolean tests of integral variables happens without the intermediate conversion to bool. Note that al is never involved, so this implies that the value is never "converted" to a one-byte bool before testing it for non-zero.

Upvotes: 6

Related Questions