I have a function containing a small assembly block. The assembly for this function compiled by GCC is incorrect since it assigns the same register to two different variables. This is the function source:
void *ptr;
uint64_t foo(uint64_t arg1) {
register uint64_t tmp;
asm ("lea TARGET(%%rip), %[tmp];""shl $4, %[arg1];""sub %[arg1], %[tmp];""movq %[tmp], %[ptr];"
: [ptr] "+m" (ptr), [tmp] "=r" (tmp)
: [arg1] "r" (arg1)
:);
asm ("TARGET:;");
}
I use the constraint "+m" for the global ptr
since I write to it, and it is should be in memory. The constraint for tmp
is "=r" since its only being written to. The constaint for the input arg1
is merely "r". This might be important.
The SSA pseudo-code for the assembly block is:
tmp_0 = something
arg1_1 = arg1_0 << 4
tmp_1 = tmp_0 - arg_1
*ptr_0 = tmp_1
The compiled assembly for this function at optimization O0
is
00000000000005fa <foo>:
5fa: 55 push %rbp
5fb: 48 89 e5 mov %rsp,%rbp
5fe: 48 89 7d f8 mov %rdi,-0x8(%rbp) # Storing arg1 to stack (optimization level O0)
602: 48 8b 45 f8 mov -0x8(%rbp),%rax # arg1_0 is assigned register rax
606: 48 8d 05 0e 00 00 00 lea 0xe(%rip),%rax # 61b <TARGET>, tmp_0 is ALSO assigned rax
60d: 48 c1 e0 04 shl $0x4,%rax # arg1_0 is used, its lifetime ends
611: 48 29 c0 sub %rax,%rax # subtracting two vars both assigned the same register
614: 48 89 05 fd 09 20 00 mov %rax,0x2009fd(%rip) # 201018 <ptr>, store to global
000000000000061b <TARGET>:
61b: 90 nop
61c: 5d pop %rbp
61d: c3 retq
Inspecting the assembly, we see that in address 0x602, the register rax
is assigned to the SSA register arg1_0
whose lifetime is till the instruction 0x60d. Meanwhile, the instruction at address 0x606 ALSO assigns the register rax
to the SSA register tmp_0
. It seems that a physical register was assigned to another SSA register during its lifetime.
System information:
- x86_64 CPU
- gcc version 7.4.0
- Ubuntu 18.04.3
My questions:
- Why does GCC create such an assembly output?
- Are my constraints to the assembly inputs and outputs correct? If not, why?
- Is this a GCC bug?