[llvm] [RegAllocFast] Give an undef tied use the register of its tied def (PR #222249)
via llvm-commits
llvm-commits at lists.llvm.org
Tue Sep 8 23:16:36 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-backend-x86
Author: Fangrui Song (MaskRay)
<details>
<summary>Changes</summary>
X86TargetLowering::emitSetJmpShadowStackFix zeroes a register by
building an XOR whose two uses are undef reads of its own def (per
MachineOperand.h "... reading the same dont-care value"). Def processing
frees a def whose tied use is undef before the uses are allocated, so
allocVirtRegUndef() no longer finds the virtual register and takes the
head of the allocation order instead. -verify-machineinstrs would fail:
```
renamable $rcx = XOR64rr undef renamable $rax(tied-def 0), undef renamable $rax, implicit-def dead $eflags
*** Bad machine code: Tied physical registers must match. ***
```
Take the register from the tie, and rewrite the instruction's other
reads of the value with it so that they keep agreeing on one register.
Aided by Opus 5
---
Full diff: https://github.com/llvm/llvm-project/pull/222249.diff
2 Files Affected:
- (modified) llvm/lib/CodeGen/RegAllocFast.cpp (+22)
- (added) llvm/test/CodeGen/X86/regallocfast-undef-tied-use.mir (+21)
``````````diff
diff --git a/llvm/lib/CodeGen/RegAllocFast.cpp b/llvm/lib/CodeGen/RegAllocFast.cpp
index 3db118c62fb09..a084faf3cc108 100644
--- a/llvm/lib/CodeGen/RegAllocFast.cpp
+++ b/llvm/lib/CodeGen/RegAllocFast.cpp
@@ -1031,6 +1031,28 @@ void RegAllocFastImpl::allocVirtRegUndef(MachineOperand &MO) {
if (!shouldAllocateRegister(VirtReg))
return;
+ // The def is freed before the uses are allocated, so a tie is the only
+ // record left of its register. Rewrite every read of VirtReg so they agree.
+ MachineInstr &MI = *MO.getParent();
+ for (const MachineOperand &Tied : MI.all_uses()) {
+ if (!Tied.isTied() || Tied.getReg() != VirtReg)
+ continue;
+ unsigned TiedIdx = MI.findTiedOperandIdx(MI.getOperandNo(&Tied));
+ MCRegister DefReg = MI.getOperand(TiedIdx).getReg().asMCReg();
+ for (MachineOperand &O : MI.all_uses()) {
+ if (O.getReg() != VirtReg)
+ continue;
+ // A tie needs the register itself, not the subregister it names.
+ MCRegister Reg = DefReg;
+ if (unsigned SubIdx = O.getSubReg(); SubIdx && !O.isTied())
+ Reg = TRI->getSubReg(DefReg, SubIdx);
+ O.setSubReg(0);
+ O.setReg(Reg);
+ O.setIsRenamable(!MRI->isReserved(Reg));
+ }
+ return;
+ }
+
LiveRegMap::iterator LRI = findLiveVirtReg(VirtReg);
MCRegister PhysReg;
bool IsRenamable = true;
diff --git a/llvm/test/CodeGen/X86/regallocfast-undef-tied-use.mir b/llvm/test/CodeGen/X86/regallocfast-undef-tied-use.mir
new file mode 100644
index 0000000000000..b9cef97eca525
--- /dev/null
+++ b/llvm/test/CodeGen/X86/regallocfast-undef-tied-use.mir
@@ -0,0 +1,21 @@
+# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 6
+# RUN: llc -mtriple=x86_64-linux -run-pass=regallocfast -verify-machineinstrs %s -o - | FileCheck %s
+
+## X86 builds this zeroing XOR for __builtin_setjmp with a shadow stack. The
+## copy hint puts the def in $rcx, which the undef reads have to follow.
+
+--- |
+ define i64 @undef_tied_use() { ret i64 0 }
+...
+---
+name: undef_tied_use
+tracksRegLiveness: true
+body: |
+ bb.0:
+ ; CHECK-LABEL: name: undef_tied_use
+ ; CHECK: renamable $rcx = XOR64rr undef renamable $rcx, undef renamable $rcx, implicit-def dead $eflags
+ ; CHECK-NEXT: RET64 implicit killed $rcx
+ %0:gr64 = XOR64rr undef %0, undef %0, implicit-def dead $eflags
+ $rcx = COPY %0
+ RET64 implicit $rcx
+...
``````````
</details>
https://github.com/llvm/llvm-project/pull/222249
More information about the llvm-commits
mailing list