llvm / llvm-project

The LLVM Project is a collection of modular and reusable compiler and toolchain technologies.
http://llvm.org
Other
28.39k stars 11.73k forks source link

Incorrect register allocation for inline assembly with 4 outputs #42175

Open ramosian-glider opened 5 years ago

ramosian-glider commented 5 years ago
Bugzilla Link 42830
Version trunk
OS Linux
CC @topperc,@efriedma-quic,@ramosian-glider,@RKSimon,@rotateright

Extended Description

When compiling the following code:

$ cat bar.c char foo();

int bar() { char x1 = foo(); char x2 = foo(); char x3 = foo(); char y1, y2, y3, y4; asm("mov $1, %k0\nmov $2, %k1\nmov $3, %k2\nmov $4, %k3" : "=r"(y1), "=r"(y2), "=r"(y3), "=r"(y4)); return x1 + x2 + y1 + y2 + y3 + y4; }

with -m32, Clang uses EAX twice to return 1 and 4 from the inline assembly:

$ clang bar.c -c -m32 $ objdump -dr bar.o

00000000 : 0: 55 push %ebp 1: 89 e5 mov %esp,%ebp 3: 57 push %edi 4: 56 push %esi 5: 83 ec 10 sub $0x10,%esp 8: e8 fc ff ff ff call 9 <bar+0x9> 9: R_386_PC32 foo d: 88 45 f7 mov %al,-0x9(%ebp) 10: e8 fc ff ff ff call 11 <bar+0x11> 11: R_386_PC32 foo 15: 88 45 f6 mov %al,-0xa(%ebp) 18: e8 fc ff ff ff call 19 <bar+0x19> 19: R_386_PC32 foo 1d: 88 45 f5 mov %al,-0xb(%ebp) 20: b8 01 00 00 00 mov $0x1,%eax 25: b9 02 00 00 00 mov $0x2,%ecx 2a: ba 03 00 00 00 mov $0x3,%edx 2f: b8 04 00 00 00 mov $0x4,%eax

Without -m32 Clang returns 1 and 4 in EAX and ESI, respectively.

efriedma-quic commented 5 years ago

I'm not sure how this is relevant to the %eax case.

The "k" in the string is an operand modifier; it only affects how the asm string is printed, not register allocation.

ramosian-glider commented 5 years ago

FWIW here's a link to godbolt with a couple of similar examples: https://godbolt.org/resetlayout/5d0MxL

Function baz():

int baz() { char x1 = foo(); char x2 = foo(); char x3 = foo(); char y1, y2, y3, y4; asm("mov $1, %0\nmov $2, %1\nmov $3, %2\nmov $4, %3" : "=r"(y1), "=r"(y2), "=r"(y3), "=r"(y4)); return x1 + x2 + y1 + y2 + y3 + y4; }

indeed returns 1 and 4 in %al and %ah, but I'm not sure how this is relevant to the %eax case.

efriedma-quic commented 5 years ago

Looks like LLVM is treating "ah" as a valid 8-bit register, where gcc does not.

ramosian-glider commented 5 years ago

This bug has been spotted by Victor Khimenko (khim@google.com)