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

Tim Northover via llvm-dev llvm-dev at lists.llvm.org
Mon Nov 26 10:24:07 PST 2018


Hi Stefan,

On Mon, 26 Nov 2018 at 18:01, Stefan Kanthak <stefan.kanthak at nexgo.de> wrote:
> > I'll try to explain a little below how that one mismatch causes the
> > issues you're seeing.
> >
> >> BUG #1: the compiler fails to allocate (EAX for) the variable "lfsr"!
> >> BUG #2: the variable "lfsr" is NOT initialized!
> >
> > Since the __asm isn't linked (as far as Clang is concerned) to
> > either input for lfsr32, they're both unused.
>
> REALLY? Or better: OUCH!
> Is Clang NOT aware of the __fastcall calling convention and its
> register usage?

It is, but it intentionally does not tie that knowledge together with
any __asm blocks, even if they are the only statement in a function
body.

> Clang does NOT create prolog/epilog here, so it CLEARLY knows that
> "argument" is held in ECX and "polynomial" in EDX ... as documented
> for __fastcall

That doesn't follow from the lack of a prologue, though it happens to
be true. There is still no link with the register usage in the __asm
however.

> JFTR: Clang (like MSVC too) knows VERY well which registers are used
>       (clobbered) in an __asm block. See <https://godbolt.org/z/blDIzK>,
>       which proves your assumption WRONG!

I don't believe so. Clobbering a register is very different from
guessing some input value to put into that register prior to the
block. For MSVC you're apparently supposed to write inline asm that
materializes values into registers from elsewhere (variables of one
kind or another) before using them.

I could see the behaviour you're expecting being a reasonable default
for a __declspec(naked) function restricted to a single __asm block,
but it interacts very poorly with C language semantics for functions
that can contain both C and assembly.

> 2. add "__declspec(noinline)" to the function definition ... and notice
>    that the compiler STILL does NOT setup ANY of EAX, ECX and EDX before
>    the function call!
>    See <https://godbolt.org/z/X9R9w7>, which again proves your assumption
>    WRONG.

The noinline prevents actual inlining, but the same inferences can be
(and are) made through inter-procedural analysis. Add "-emit-llvm -g0"
and you'll see your function being called with "undef" arguments and
the complete elimination of lfsr.

> If the function is declared only, but not defined, then the compiler
> sets the arguments up before the call: see <https://godbolt.org/z/4pmOlC>

Indeed.

> >> additionally it holds the second argument with the __fastcall calling
> >> convention, so the constant 0x04C11DB7 MUST be loaded into EDX before
> >> label LBB1_1:
> >
> > This is the same unused-as-far-as-the-compiler-knows thing as the first two.
>
> OUCH!
> <https://godbolt.org/z/X9R9w7> proves this WRONG.

I'm afraid I don't see how. It's an unused variable (as far as Clang
is concerned) so it doesn't need to be materialized anywhere.

> My expectation is that AT LEAST a warning message should be printed by
> the compiler.

For using a register before defining it, perhaps? That's within the
implementable realm I think (at least to cover some cases), though
whether anyone is interested enough to actually do it is another
question.

Cheers.

Tim.


More information about the llvm-dev mailing list