[X86] Wrong code for inline assembly with memory operands with segment registers
- Dominant language
- LLVM
- Stars
- 40.5k
- Forks
- 18.7k
- PR merge metrics
- PR metrics pending
Description
```c
int foo(int __seg_gs *p) {
int v;
asm ("movl %1, %0" : "=r"(v) : "m"(*p));
return v - *p;
}
```
Compiling with GCC produces
```asm
foo:
movl %gs:(%rdi), %eax
subl %gs:(%rdi), %eax
ret
```
Compiling with Clang produces
```asm
foo:
movl (%rdi), %eax
subl %gs:(%rdi), %eax
retq
```
Note how the segment override is missing in the instruction coming from the inline assembly.
https://godbolt.org/z/e4bG3Mc5h
This is one of the issues affecting glibc for i386 getting built with Clang: see [`sysdeps/i386/nptl/tls.h`](https://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/i386/nptl/tls.h;h=87dcf5dc1f47462e63eb14b089c7b9792bd1f577;hb=HEAD#l255)'s definition of `THREAD_GSCOPE_RESET_FLAG()`.
This looks to be handled correctly in Clang, the generated LLVM IR still contains the address space (the `addrspace(256)` in `tail call i32 asm "movl $1, $0", "=r,*m,~{dirflag},~{fpsr},~{flags}"(ptr addrspace(256) elementtype(i32) %0)`), but the backend does not translate this in a way that preserves that.
Contributor guide
Research direction
Start with the provided C reproducer and compare the LLVM IR, especially the addrspace(256) inline-assembly operand, with the generated x86 assembly. Trace the backend lowering that handles the memory operand; done means the inline-assembly load preserves the segment-register override, matching the non-inline-assembly access.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- c
- Domain
- compilers
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 48/100