[llvm] X86: Mark the dead EFLAGS clobbers in the SjLj expansions (PR #227271)
via llvm-commits
llvm-commits at lists.llvm.org
Tue Sep 29 03:49:58 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-backend-x86
Author: Matt Arsenault (arsenm)
<details>
<summary>Changes</summary>
The zero materializations and the shadow stack delta shifts emitted by
the setjmp/longjmp custom inserters never have their EFLAGS clobber
read, so set the dead flag where the instructions are built.
Co-Authored-By: Claude Opus 5 <noreply@<!-- -->anthropic.com>
---
Full diff: https://github.com/llvm/llvm-project/pull/227271.diff
2 Files Affected:
- (modified) llvm/lib/Target/X86/X86ISelLowering.cpp (+10-5)
- (added) llvm/test/CodeGen/X86/sjlj-shadow-stack-dead-eflags.ll (+113)
``````````diff
diff --git a/llvm/lib/Target/X86/X86ISelLowering.cpp b/llvm/lib/Target/X86/X86ISelLowering.cpp
index ddf9241ef7956..20505be987b81 100644
--- a/llvm/lib/Target/X86/X86ISelLowering.cpp
+++ b/llvm/lib/Target/X86/X86ISelLowering.cpp
@@ -38228,7 +38228,8 @@ void X86TargetLowering::emitSetJmpShadowStackFix(MachineInstr &MI,
BuildMI(*MBB, MI, MIMD, TII->get(XorRROpc))
.addDef(ZReg)
.addReg(ZReg, RegState::Undef)
- .addReg(ZReg, RegState::Undef);
+ .addReg(ZReg, RegState::Undef)
+ .setOperandDead(3); // implicit-def $eflags
// Read the current SSP Register value to the zeroed register.
Register SSPCopyReg = MRI.createVirtualRegister(PtrRC);
@@ -38373,7 +38374,8 @@ X86TargetLowering::emitEHSjLjSetJmp(MachineInstr &MI,
// mainMBB:
// EAX = 0
- BuildMI(mainMBB, MIMD, TII->get(X86::MOV32r0), mainDstReg);
+ BuildMI(mainMBB, MIMD, TII->get(X86::MOV32r0), mainDstReg)
+ .setOperandDead(1); // implicit-def $eflags
mainMBB->addSuccessor(sinkMBB);
// sinkMBB:
@@ -38471,7 +38473,8 @@ X86TargetLowering::emitLongJmpShadowStackFix(MachineInstr &MI,
// Initialize a register with zero.
Register ZReg = MRI.createVirtualRegister(&X86::GR32RegClass);
- BuildMI(checkSspMBB, MIMD, TII->get(X86::MOV32r0), ZReg);
+ BuildMI(checkSspMBB, MIMD, TII->get(X86::MOV32r0), ZReg)
+ .setOperandDead(1); // implicit-def $eflags
if (PVT == MVT::i64) {
Register TmpZReg = MRI.createVirtualRegister(PtrRC);
@@ -38536,7 +38539,8 @@ X86TargetLowering::emitLongJmpShadowStackFix(MachineInstr &MI,
Register SspFirstShrReg = MRI.createVirtualRegister(PtrRC);
BuildMI(fixShadowMBB, MIMD, TII->get(ShrRIOpc), SspFirstShrReg)
.addReg(SspSubReg)
- .addImm(Offset);
+ .addImm(Offset)
+ .setOperandDead(3); // implicit-def $eflags
// Increase SSP when looking only on the lower 8 bits of the delta.
unsigned IncsspOpc = (PVT == MVT::i64) ? X86::INCSSPQ : X86::INCSSPD;
@@ -38560,7 +38564,8 @@ X86TargetLowering::emitLongJmpShadowStackFix(MachineInstr &MI,
Register SspAfterShlReg = MRI.createVirtualRegister(PtrRC);
BuildMI(fixShadowLoopPrepareMBB, MIMD, TII->get(ShlR1Opc), SspAfterShlReg)
.addReg(SspSecondShrReg)
- .addImm(1);
+ .addImm(1)
+ .setOperandDead(3); // implicit-def $eflags
// Save the value 128 to a register (will be used next with incssp).
Register Value128InReg = MRI.createVirtualRegister(PtrRC);
diff --git a/llvm/test/CodeGen/X86/sjlj-shadow-stack-dead-eflags.ll b/llvm/test/CodeGen/X86/sjlj-shadow-stack-dead-eflags.ll
new file mode 100644
index 0000000000000..db092e90779c7
--- /dev/null
+++ b/llvm/test/CodeGen/X86/sjlj-shadow-stack-dead-eflags.ll
@@ -0,0 +1,113 @@
+; NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 6
+; RUN: llc -mtriple=x86_64-- -stop-after=finalize-isel < %s | FileCheck %s
+
+ at buf = common local_unnamed_addr global ptr null, align 8
+
+define i32 @setjmp_dead_eflags() {
+ ; CHECK-LABEL: name: setjmp_dead_eflags
+ ; CHECK: bb.0.entry:
+ ; CHECK-NEXT: successors: %bb.1(0x40000000), %bb.3(0x40000000)
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[MOV64rm:%[0-9]+]]:gr64 = MOV64rm $rip, 1, $noreg, target-flags(x86-gotpcrel) @buf, $noreg :: (load (s64) from got)
+ ; CHECK-NEXT: [[MOV64rm1:%[0-9]+]]:gr64 = MOV64rm killed [[MOV64rm]], 1, $noreg, 0, $noreg :: (dereferenceable load (s64) from @buf)
+ ; CHECK-NEXT: [[COPY:%[0-9]+]]:gr64 = COPY $rbp
+ ; CHECK-NEXT: MOV64mr [[MOV64rm1]], 1, $noreg, 0, $noreg, [[COPY]] :: (store (s64) into %ir.0)
+ ; CHECK-NEXT: [[COPY1:%[0-9]+]]:gr64 = COPY $rsp
+ ; CHECK-NEXT: MOV64mr [[MOV64rm1]], 1, $noreg, 16, $noreg, [[COPY1]] :: (store (s64) into %ir.3)
+ ; CHECK-NEXT: MOV64mi32 [[MOV64rm1]], 1, $noreg, 8, $noreg, %bb.3
+ ; CHECK-NEXT: [[XOR64rr:%[0-9]+]]:gr64 = XOR64rr undef [[XOR64rr]], undef [[XOR64rr]], implicit-def dead $eflags
+ ; CHECK-NEXT: [[RDSSPQ:%[0-9]+]]:gr64 = RDSSPQ [[XOR64rr]], implicit $ssp
+ ; CHECK-NEXT: MOV64mr [[MOV64rm1]], 1, $noreg, 24, $noreg, [[RDSSPQ]]
+ ; CHECK-NEXT: EH_SjLj_Setup %bb.3, csr_noregs
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: bb.1.entry:
+ ; CHECK-NEXT: successors: %bb.2(0x80000000)
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[MOV32r0_:%[0-9]+]]:gr32 = MOV32r0 implicit-def dead $eflags
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: bb.2.entry:
+ ; CHECK-NEXT: [[PHI:%[0-9]+]]:gr32 = PHI [[MOV32r0_]], %bb.1, %6, %bb.3
+ ; CHECK-NEXT: $eax = COPY [[PHI]]
+ ; CHECK-NEXT: RET 0, $eax
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: bb.3.entry (machine-block-address-taken):
+ ; CHECK-NEXT: successors: %bb.2(0x80000000)
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[MOV32ri:%[0-9]+]]:gr32 = MOV32ri 1
+ ; CHECK-NEXT: JMP_1 %bb.2
+entry:
+ %0 = load ptr, ptr @buf, align 8
+ %1 = tail call ptr @llvm.frameaddress(i32 0)
+ store ptr %1, ptr %0, align 8
+ %2 = tail call ptr @llvm.stacksave()
+ %3 = getelementptr inbounds ptr, ptr %0, i64 2
+ store ptr %2, ptr %3, align 8
+ %4 = tail call i32 @llvm.eh.sjlj.setjmp(ptr %0)
+ ret i32 %4
+}
+
+define void @longjmp_dead_eflags() {
+ ; CHECK-LABEL: name: longjmp_dead_eflags
+ ; CHECK: bb.0.entry:
+ ; CHECK-NEXT: successors: %bb.1(0x80000000)
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[MOV64rm:%[0-9]+]]:gr64 = MOV64rm $rip, 1, $noreg, target-flags(x86-gotpcrel) @buf, $noreg :: (load (s64) from got)
+ ; CHECK-NEXT: [[MOV64rm1:%[0-9]+]]:gr64 = MOV64rm killed [[MOV64rm]], 1, $noreg, 0, $noreg :: (dereferenceable load (s64) from @buf)
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: bb.1.entry:
+ ; CHECK-NEXT: successors: %bb.6(0x40000000), %bb.2(0x40000000)
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[MOV32r0_:%[0-9]+]]:gr32 = MOV32r0 implicit-def dead $eflags
+ ; CHECK-NEXT: [[SUBREG_TO_REG:%[0-9]+]]:gr64 = SUBREG_TO_REG [[MOV32r0_]], %subreg.sub_32bit
+ ; CHECK-NEXT: [[RDSSPQ:%[0-9]+]]:gr64 = RDSSPQ [[SUBREG_TO_REG]], implicit $ssp
+ ; CHECK-NEXT: TEST64rr [[RDSSPQ]], [[RDSSPQ]], implicit-def $eflags
+ ; CHECK-NEXT: JCC_1 %bb.6, 4, implicit $eflags
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: bb.2.entry:
+ ; CHECK-NEXT: successors: %bb.6(0x40000000), %bb.3(0x40000000)
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[MOV64rm2:%[0-9]+]]:gr64 = MOV64rm [[MOV64rm1]], 1, $noreg, 24, $noreg
+ ; CHECK-NEXT: [[SUB64rr:%[0-9]+]]:gr64 = SUB64rr [[MOV64rm2]], [[RDSSPQ]], implicit-def $eflags
+ ; CHECK-NEXT: JCC_1 %bb.6, 6, implicit $eflags
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: bb.3.entry:
+ ; CHECK-NEXT: successors: %bb.6(0x40000000), %bb.4(0x40000000)
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[SHR64ri:%[0-9]+]]:gr64 = SHR64ri [[SUB64rr]], 3, implicit-def dead $eflags
+ ; CHECK-NEXT: INCSSPQ [[SHR64ri]], implicit-def $ssp, implicit $ssp
+ ; CHECK-NEXT: [[SHR64ri1:%[0-9]+]]:gr64 = SHR64ri [[SHR64ri]], 8, implicit-def $eflags
+ ; CHECK-NEXT: JCC_1 %bb.6, 4, implicit $eflags
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: bb.4.entry:
+ ; CHECK-NEXT: successors: %bb.5(0x80000000)
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[SHL64ri:%[0-9]+]]:gr64 = SHL64ri [[SHR64ri1]], 1, implicit-def dead $eflags
+ ; CHECK-NEXT: [[MOV64ri32_:%[0-9]+]]:gr64 = MOV64ri32 128
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: bb.5.entry:
+ ; CHECK-NEXT: successors: %bb.6(0x40000000), %bb.5(0x40000000)
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[PHI:%[0-9]+]]:gr64 = PHI [[SHL64ri]], %bb.4, %12, %bb.5
+ ; CHECK-NEXT: INCSSPQ [[MOV64ri32_]], implicit-def $ssp, implicit $ssp
+ ; CHECK-NEXT: [[DEC64r:%[0-9]+]]:gr64 = DEC64r [[PHI]], implicit-def $eflags
+ ; CHECK-NEXT: JCC_1 %bb.5, 5, implicit $eflags
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: bb.6.entry:
+ ; CHECK-NEXT: $rbp = frame-destroy MOV64rm [[MOV64rm1]], 1, $noreg, 0, $noreg
+ ; CHECK-NEXT: [[MOV64rm3:%[0-9]+]]:gr64 = MOV64rm [[MOV64rm1]], 1, $noreg, 8, $noreg
+ ; CHECK-NEXT: $rsp = frame-destroy MOV64rm killed [[MOV64rm1]], 1, $noreg, 16, $noreg
+ ; CHECK-NEXT: JMP64r [[MOV64rm3]]
+entry:
+ %0 = load ptr, ptr @buf, align 8
+ tail call void @llvm.eh.sjlj.longjmp(ptr %0)
+ unreachable
+}
+
+declare ptr @llvm.frameaddress(i32)
+declare ptr @llvm.stacksave()
+declare i32 @llvm.eh.sjlj.setjmp(ptr)
+declare void @llvm.eh.sjlj.longjmp(ptr)
+
+!llvm.module.flags = !{!0}
+
+!0 = !{i32 8, !"cf-protection-return", i32 1}
``````````
</details>
https://github.com/llvm/llvm-project/pull/227271
More information about the llvm-commits
mailing list