Quantcast
Viewing all articles
Browse latest Browse all 22079

Conflicting register allocation in GCC x86_64 asm. Lifetime ignored

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?

Viewing all articles
Browse latest Browse all 22079

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>