[llvm-dev] BUGS in code generated for target i386-win32

Stefan Kanthak via llvm-dev llvm-dev at lists.llvm.org
Mon Nov 26 04:27:22 PST 2018


Hi @ll,

LLVM/clang generates wrong code for the following program
(see <https://godbolt.org/z/UZrrkG>):

--- sample.c ---
unsigned __fastcall lfsr32(unsigned argument, unsigned polynomial)
{
    __asm
    {
        add ecx, ecx ; ecx = argument << 1
        sbb eax, eax ; eax = CF ? -1 : 0
        and eax, edx ; eax = CF ? polynomial : 0
        xor eax, ecx ; eax = (argument << 1) ^ (CF ? polynomial : 0)
    }
}

int main()
{
    unsigned lfsr = 123456789;
    unsigned period = 0;

    do
    {
        period++;
#ifdef MITIGATE
        lfsr = lfsr & 0x80000000 ? 0x04C11DB7 ^ (lfsr << 1) : lfsr << 1;
#else
        lfsr = lfsr32(lfsr, 0x04C11DB7);
#endif
    } while (lfsr != 123456789);

    return period;
}
--- EOF ---

Compiled with -O2 -target i386-win32 this yields the following code:

_main: # @main

    xor edx, edx

LBB1_1: # =>This Inner Loop Header: Depth=1

    add ecx, ecx
    sbb eax, eax
    and eax, edx
    xor eax, ecx

    inc edx
    cmp eax, 123456789
    jne LBB1_1
    mov eax, edx
    ret

BUG #1: the compiler fails to allocate (EAX for) the variable "lfsr"!
~~~~~~~
It fails to load the result of the inlined function call, held in EAX,
back into ECX, which holds the first argument with the __fastcall
calling convention, inside the loop starting with LBB1_1:

FIX #1: emit a "mov ecx, eax" immediately after LBB1_1:
~~~~~~~

BUG #2: the variable "lfsr" is NOT initialized!
~~~~~~~
The constant 123456789 is NOT loaded into whatever register holds "lfsr".

FIX #2: emit a "mov eax, 123456789" immediately before LBB1_1:
~~~~~~~

BUG #3: the compiler allocates EDX for the variable "period"!
~~~~~~~
EDX is a volatile register, it is not preserved through function calls;
additionally it holds the second argument with the __fastcall calling
convention, so the constant 0x04C11DB7 MUST be loaded into EDX before
label LBB1_1:

The compiler MUST use another register (of course except ECX, which
holds the first argument with __fastcall, and except EAX, which holds
the return value), for example EBX instead of EDX.

Stefan Kanthak

PS: for comparision with another (likewise buggy) compiler, take a look
    at <https://skanthak.homepage.t-online.de/msvc.html#example9>


More information about the llvm-dev mailing list