[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