[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