[llvm] X86: Preserve the dead flag clobber when expanding dynamic allocas (PR #227702)
Matt Arsenault via llvm-commits
llvm-commits at lists.llvm.org
Wed Sep 30 06:16:22 PDT 2026
https://github.com/arsenm created https://github.com/llvm/llvm-project/pull/227702
The DYN_ALLOCA pseudos clobber EFLAGS, so propagate the pseudo's dead
flag to the stack adjustment they expand to.
Co-Authored-By: Claude Opus 5 <noreply at anthropic.com>
>From 2483d070f0a8c08532a21aa14cbcf44333079cdb Mon Sep 17 00:00:00 2001
From: Matt Arsenault <Matthew.Arsenault at amd.com>
Date: Tue, 29 Sep 2026 02:32:12 +0200
Subject: [PATCH] X86: Preserve the dead flag clobber when expanding dynamic
allocas
The DYN_ALLOCA pseudos clobber EFLAGS, so propagate the pseudo's dead
flag to the stack adjustment they expand to.
Co-Authored-By: Claude Opus 5 <noreply at anthropic.com>
---
llvm/lib/Target/X86/X86DynAllocaExpander.cpp | 22 +++++---
.../X86/dyn-alloca-expander-dead-eflags.ll | 51 +++++++++++++++++++
2 files changed, 66 insertions(+), 7 deletions(-)
create mode 100644 llvm/test/CodeGen/X86/dyn-alloca-expander-dead-eflags.ll
diff --git a/llvm/lib/Target/X86/X86DynAllocaExpander.cpp b/llvm/lib/Target/X86/X86DynAllocaExpander.cpp
index 62b70bdd14b31e..28212258fbe090 100644
--- a/llvm/lib/Target/X86/X86DynAllocaExpander.cpp
+++ b/llvm/lib/Target/X86/X86DynAllocaExpander.cpp
@@ -225,6 +225,7 @@ void X86DynAllocaExpander::lower(MachineInstr *MI, Lowering L) {
// 32-bit alloca.
bool Is64Bit = STI->is64Bit();
bool Is64BitAlloca = MI->getOpcode() == X86::DYN_ALLOCA_64;
+ bool DeadEFLAGS = MI->registerDefIsDead(X86::EFLAGS, /*TRI=*/nullptr);
assert(SlotSize == 4 || SlotSize == 8);
std::optional<MachineFunction::DebugInstrOperandPair> InstrNum;
@@ -257,9 +258,12 @@ void X86DynAllocaExpander::lower(MachineInstr *MI, Lowering L) {
.addReg(RegA, RegState::Undef);
} else {
// Sub.
- BuildMI(*MBB, I, DL, TII->get(getSubOpcode(Is64BitAlloca)), StackPtr)
- .addReg(StackPtr)
- .addImm(Amount);
+ MachineInstrBuilder Sub =
+ BuildMI(*MBB, I, DL, TII->get(getSubOpcode(Is64BitAlloca)), StackPtr)
+ .addReg(StackPtr)
+ .addImm(Amount);
+ if (DeadEFLAGS)
+ Sub.setOperandDead(3); // implicit-def $eflags
}
break;
case Probe:
@@ -274,10 +278,14 @@ void X86DynAllocaExpander::lower(MachineInstr *MI, Lowering L) {
/*InProlog=*/false, InstrNum);
} else {
// Sub
- BuildMI(*MBB, I, DL,
- TII->get(Is64BitAlloca ? X86::SUB64rr : X86::SUB32rr), StackPtr)
- .addReg(StackPtr)
- .addReg(MI->getOperand(0).getReg());
+ MachineInstrBuilder Sub =
+ BuildMI(*MBB, I, DL,
+ TII->get(Is64BitAlloca ? X86::SUB64rr : X86::SUB32rr),
+ StackPtr)
+ .addReg(StackPtr)
+ .addReg(MI->getOperand(0).getReg());
+ if (DeadEFLAGS)
+ Sub.setOperandDead(3); // implicit-def $eflags
}
break;
}
diff --git a/llvm/test/CodeGen/X86/dyn-alloca-expander-dead-eflags.ll b/llvm/test/CodeGen/X86/dyn-alloca-expander-dead-eflags.ll
new file mode 100644
index 00000000000000..bfa744a16f75cd
--- /dev/null
+++ b/llvm/test/CodeGen/X86/dyn-alloca-expander-dead-eflags.ll
@@ -0,0 +1,51 @@
+; NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 6
+; RUN: llc -mtriple=i686-pc-win32 -stop-after=x86-dyn-alloca-expander -o - %s | FileCheck %s
+
+; The expanded stack adjustment inherits the dead flag clobber of the pseudo.
+
+define void @sub() {
+ ; CHECK-LABEL: name: sub
+ ; CHECK: bb.0.entry:
+ ; CHECK-NEXT: successors: %bb.1(0x80000000)
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: bb.1.bb:
+ ; CHECK-NEXT: ADJCALLSTACKDOWN32 0, 0, 0, implicit-def dead $esp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $esp, implicit $ssp
+ ; CHECK-NEXT: PUSH32r undef $eax, implicit-def $esp, implicit $esp
+ ; CHECK-NEXT: $esp = SUB32ri $esp, 1020, implicit-def dead $eflags
+ ; CHECK-NEXT: [[COPY:%[0-9]+]]:gr32 = COPY $esp
+ ; CHECK-NEXT: ADJCALLSTACKUP32 0, 0, implicit-def dead $esp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $esp, implicit $ssp
+ ; CHECK-NEXT: ADJCALLSTACKDOWN32 4, 0, 4, implicit-def dead $esp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $esp, implicit $ssp
+ ; CHECK-NEXT: PUSH32r [[COPY]], implicit-def $esp, implicit $esp :: (store (s32) into stack)
+ ; CHECK-NEXT: CALLpcrel32 @use, csr_32, implicit $esp, implicit $ssp, implicit-def $esp, implicit-def $ssp
+ ; CHECK-NEXT: ADJCALLSTACKUP32 4, 0, implicit-def dead $esp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $esp, implicit $ssp
+ ; CHECK-NEXT: RET 0
+entry:
+ br label %bb
+
+bb:
+ %a = alloca [1024 x i8]
+ call void @use(ptr %a)
+ ret void
+}
+
+define void @sub_dynamic(i32 %n) "no-stack-arg-probe" {
+ ; CHECK-LABEL: name: sub_dynamic
+ ; CHECK: bb.0 (%ir-block.0):
+ ; CHECK-NEXT: [[MOV32rm:%[0-9]+]]:gr32 = MOV32rm %fixed-stack.0, 1, $noreg, 0, $noreg :: (load (s32) from %fixed-stack.0)
+ ; CHECK-NEXT: ADJCALLSTACKDOWN32 0, 0, 0, implicit-def dead $esp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $esp, implicit $ssp
+ ; CHECK-NEXT: [[ADD32ri:%[0-9]+]]:gr32 = nuw ADD32ri [[MOV32rm]], 3, implicit-def dead $eflags
+ ; CHECK-NEXT: [[AND32ri:%[0-9]+]]:gr32 = AND32ri [[ADD32ri]], -4, implicit-def dead $eflags
+ ; CHECK-NEXT: $esp = SUB32rr $esp, [[AND32ri]], implicit-def dead $eflags
+ ; CHECK-NEXT: [[COPY:%[0-9]+]]:gr32 = COPY $esp
+ ; CHECK-NEXT: ADJCALLSTACKUP32 0, 0, implicit-def dead $esp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $esp, implicit $ssp
+ ; CHECK-NEXT: ADJCALLSTACKDOWN32 4, 0, 4, implicit-def dead $esp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $esp, implicit $ssp
+ ; CHECK-NEXT: PUSH32r [[COPY]], implicit-def $esp, implicit $esp :: (store (s32) into stack)
+ ; CHECK-NEXT: CALLpcrel32 @use, csr_32, implicit $esp, implicit $ssp, implicit-def $esp, implicit-def $ssp
+ ; CHECK-NEXT: ADJCALLSTACKUP32 4, 0, implicit-def dead $esp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $esp, implicit $ssp
+ ; CHECK-NEXT: RET 0
+ %a = alloca i8, i32 %n
+ call void @use(ptr %a)
+ ret void
+}
+
+declare void @use(ptr)
More information about the llvm-commits
mailing list