| Issue |
176546
|
| Summary |
$gp used as global register variable is restored in epilog on MIPS
|
| Labels |
new issue
|
| Assignees |
|
| Reporter |
ziyao233
|
A simple reproducer,
```
register unsigned long globalvar asm ("$28");
void setglobal(unsigned long x)
{
globalvar = x;
}
```
Clang generates,
```
$ clang --target=mips64el-unknown-linux-musl -c test.c -O2
$ llvm-objdump -d test.o
test.o: file format elf64-mips
Disassembly of section .text:
0000000000000000 <setglobal>:
0: 08 00 e0 03 jr $ra
4: 00 00 00 00 nop <setglobal>
```
where the assignment to `$gp` is optimized away, while GCC generates,
```
$ mips64el-unknown-linux-musl-gcc test.c -c -O2
$ llvm-objdump -d test.o
test.o: file format elf64-mips
Disassembly of section .text:
0000000000000000 <setglobal>:
0: 08 00 e0 03 jr $ra
4: 25 e0 80 00 move $gp, $4
...
```
Quoting GCC manual[1]'s explanation for global register variables,
> If the register is a call-saved register, call ABI is affected: the register will not be restored in function epilogue sequences after the variable has been assigned. Therefore, functions cannot safely return to callers that assume standard ABI.
GCC's code sequence should be the expected result since `$gp` is considered callee-saved with MIPS n32/n64 ABI. The problem could be reproduced with LLVM 18-21, and recent main branch 262208728ae9 ("Fix typo in MSVCCompatibility.rst (#176057)").
Note `$gp` is non-allocatable on MIPS[2], so this is a separate bug, rather than an unimplemented GCC extension (`clang only supports global register variables when the register specified is non-allocatable`[3]).
Disable optimization shows the problem more clear,
```
$ llvm-objdump -d test.o
test.o: file format elf64-mips
Disassembly of section .text:
0000000000000000 <setglobal>:
0: e0 ff bd 67 daddiu $sp, $sp, -0x20 <setglobal+0xffffffffffffffe0>
4: 18 00 bf ff sd $ra, 0x18($sp)
8: 10 00 be ff sd $fp, 0x10($sp)
c: 08 00 bc ff sd $gp, 0x8($sp)
10: 25 f0 a0 03 move $fp, $sp
14: 00 00 c4 ff sd $4, 0x0($fp)
18: 00 00 dc df ld $gp, 0x0($fp)
1c: 25 e8 c0 03 move $sp, $fp
20: 08 00 bc df ld $gp, 0x8($sp)
24: 10 00 be df ld $fp, 0x10($sp)
28: 18 00 bf df ld $ra, 0x18($sp)
2c: 20 00 bd 67 daddiu $sp, $sp, 0x20 <setglobal+0x20>
30: 08 00 e0 03 jr $ra
34: 00 00 00 00 nop <setglobal>
```
`$gp` is assigned, however the in epilog it's restored back. By inspecting output of `llc --print-after-all`, it should be pass `prologepilog` adding the restoring code for `$gp`,
```
# *** IR Dump After Shrink Wrapping analysis (shrink-wrap) ***:
# Machine code for function setglobal: NoPHIs, TracksLiveness, NoVRegs, TiedOpsRewritten, TracksDebugUserValues
Function Live Ins: $a0_64
bb.0 (%ir-block.1):
liveins: $a0_64
$gp_64 = COPY $a0_64
RetRA
# End machine code for function setglobal.
# *** IR Dump After Prologue/Epilogue Insertion & Frame Finalization (prologepilog) ***:
# Machine code for function setglobal: NoPHIs, TracksLiveness, NoVRegs, TiedOpsRewritten, TracksDebugUserValues
Frame Objects:
fi#0: size=8, align=8, at location [SP-8]
Function Live Ins: $a0_64
bb.0 (%ir-block.1):
liveins: $a0_64, $gp_64
$sp_64 = DADDiu $sp_64, -16
CFI_INSTRUCTION def_cfa_offset 16
SD killed $gp_64, $sp_64, 8 :: (store (s64) into %stack.0)
CFI_INSTRUCTION offset $gp_64, -8
$gp_64 = COPY $a0_64
$gp_64 = LD $sp_64, 8 :: (load (s64) from %stack.0)
$sp_64 = DADDiu $sp_64, 16
RetRA
# End machine code for function setglobal.
```
which is (again) reasonable since `$gp` is listed as a callee-saved register for n32/n64 ABI[4].
[1]: https://gcc.gnu.org/onlinedocs/gcc/Global-Register-Variables.html
[2]: https://github.com/llvm/llvm-project/blob/0a9d480fadf07aaaee8ccfa26a2a2afa3f621499/llvm/lib/Target/Mips/MipsRegisterInfo.td#L496
[3]: https://github.com/llvm/llvm-project/blob/0a9d480fadf07aaaee8ccfa26a2a2afa3f621499/clang/docs/UsersManual.rst?plain=1#L4022
[4]: https://github.com/llvm/llvm-project/blob/0a9d480fadf07aaaee8ccfa26a2a2afa3f621499/llvm/lib/Target/Mips/MipsCallingConv.td#L362-L373
_______________________________________________
llvm-bugs mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-bugs