[llvm] [X86][WinEH] Avoid stale RSP after Win64 dynalloca invokes (PR #191616)
via llvm-commits
llvm-commits at lists.llvm.org
Mon Jun 29 02:12:30 PDT 2026
https://github.com/taigacon updated https://github.com/llvm/llvm-project/pull/191616
>From 92565222ef8206f34b0bcb4f0d9f73b9bb36d524 Mon Sep 17 00:00:00 2001
From: taigacon <taigacon at gmail.com>
Date: Fri, 17 Apr 2026 11:23:04 +0800
Subject: [PATCH 1/4] [X86][WinEH] Avoid stale RSP after Win64 dynalloca
invokes (#191616)
Thread the raw dynalloca size through DYNAMIC_STACKALLOC and lower
x86_64-windows-msvc dynamic allocas to a dedicated WIN_ALLOCA pseudo.
Track a stable outgoing call-frame size for Win64/MSVC dynalloca
functions, keep the reserved-call-frame model, and make each WIN_ALLOCA
subtract only the allocation size plus alignment slack while still
returning rsp + CallFrameSize.
Update the affected Win64 codegen tests to match the resulting MSVC
code shape.
---
llvm/include/llvm/CodeGen/ISDOpcodes.h | 9 +-
.../SelectionDAG/SelectionDAGBuilder.cpp | 4 +-
.../Target/AArch64/AArch64ISelLowering.cpp | 2 +-
llvm/lib/Target/X86/X86DynAllocaExpander.cpp | 242 ++++++++++++++----
llvm/lib/Target/X86/X86FrameLowering.cpp | 26 +-
llvm/lib/Target/X86/X86ISelLowering.cpp | 8 +
llvm/lib/Target/X86/X86InstrCompiler.td | 8 +
llvm/lib/Target/X86/X86InstrFragments.td | 7 +
llvm/lib/Target/X86/X86MachineFunctionInfo.h | 13 +
.../test/CodeGen/X86/alloca-align-rounding.ll | 10 +
.../CodeGen/X86/catchpad-dynamic-alloca.ll | 37 ++-
llvm/test/CodeGen/X86/localescape.ll | 19 +-
llvm/test/CodeGen/X86/stack-protector-msvc.ll | 77 +++---
.../CodeGen/X86/win64_alloca_dynalloca.ll | 111 ++++++--
llvm/test/CodeGen/X86/win64_frame.ll | 108 +++++---
.../DebugInfo/X86/instr-ref-dyn-alloca.ll | 13 +-
16 files changed, 523 insertions(+), 171 deletions(-)
diff --git a/llvm/include/llvm/CodeGen/ISDOpcodes.h b/llvm/include/llvm/CodeGen/ISDOpcodes.h
index 224855e02f21d..650756f0f5de1 100644
--- a/llvm/include/llvm/CodeGen/ISDOpcodes.h
+++ b/llvm/include/llvm/CodeGen/ISDOpcodes.h
@@ -1185,10 +1185,11 @@ enum NodeType {
/// DYNAMIC_STACKALLOC - Allocate some number of bytes on the stack aligned
/// to a specified boundary. This node always has two return values: a new
/// stack pointer value and a chain. The first operand is the token chain,
- /// the second is the number of bytes to allocate, and the third is the
- /// alignment boundary. The size is guaranteed to be a multiple of the
- /// stack alignment, and the alignment is guaranteed to be bigger than the
- /// stack alignment (if required) or 0 to get standard stack alignment.
+ /// the second is the number of bytes to allocate, the third is the
+ /// alignment boundary, and the fourth is the unrounded allocation size.
+ /// The size is guaranteed to be a multiple of the stack alignment, and the
+ /// alignment is guaranteed to be bigger than the stack alignment (if
+ /// required) or 0 to get standard stack alignment.
DYNAMIC_STACKALLOC,
/// Control flow instructions. These all have token chains.
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
index 8aa184423c60c..9437ce2971a7d 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
@@ -4649,6 +4649,7 @@ void SelectionDAGBuilder::visitAlloca(const AllocaInst &I) {
AllocSize = DAG.getNode(
ISD::MUL, dl, IntPtr, AllocSize,
DAG.getZExtOrTrunc(DAG.getTypeSize(dl, MVT::i64, TySize), dl, IntPtr));
+ SDValue RawAllocSize = AllocSize;
// Handle alignment. If the requested alignment is less than or equal to
// the stack alignment, ignore it. If the size is greater than or equal to
@@ -4671,7 +4672,8 @@ void SelectionDAGBuilder::visitAlloca(const AllocaInst &I) {
SDValue Ops[] = {
getRoot(), AllocSize,
- DAG.getConstant(Alignment ? Alignment->value() : 0, dl, IntPtr)};
+ DAG.getConstant(Alignment ? Alignment->value() : 0, dl, IntPtr),
+ RawAllocSize};
SDVTList VTs = DAG.getVTList(AllocSize.getValueType(), MVT::Other);
SDValue DSA = DAG.getNode(ISD::DYNAMIC_STACKALLOC, dl, VTs, Ops);
setValue(&I, DSA);
diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
index e883c8bb5e96e..06c9219980238 100644
--- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
+++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
@@ -9466,7 +9466,7 @@ SDValue AArch64TargetLowering::LowerFormalArguments(
if (Size) {
SDValue Buffer = DAG.getNode(
ISD::DYNAMIC_STACKALLOC, DL, DAG.getVTList(MVT::i64, MVT::Other),
- {Chain, Size, DAG.getConstant(1, DL, MVT::i64)});
+ {Chain, Size, DAG.getConstant(1, DL, MVT::i64), Size});
Chain = Buffer.getValue(1);
Register BufferPtr =
diff --git a/llvm/lib/Target/X86/X86DynAllocaExpander.cpp b/llvm/lib/Target/X86/X86DynAllocaExpander.cpp
index bb4301c11c270..6693271d0f834 100644
--- a/llvm/lib/Target/X86/X86DynAllocaExpander.cpp
+++ b/llvm/lib/Target/X86/X86DynAllocaExpander.cpp
@@ -15,6 +15,7 @@
//===----------------------------------------------------------------------===//
#include "X86.h"
+#include "X86InstrBuilder.h"
#include "X86InstrInfo.h"
#include "X86MachineFunctionInfo.h"
#include "X86Subtarget.h"
@@ -50,6 +51,10 @@ class X86DynAllocaExpander {
/// Get the appropriate lowering based on current offset and amount.
Lowering getLowering(int64_t CurrentOffset, int64_t AllocaAmount);
+ Register materializeWinAllocaAmount(MachineInstr *MI,
+ MachineBasicBlock::iterator I,
+ const DebugLoc &DL);
+
/// Lower a DynAlloca instruction.
void lower(MachineInstr* MI, Lowering L);
@@ -88,13 +93,17 @@ FunctionPass *llvm::createX86DynAllocaExpanderLegacyPass() {
}
/// Return the allocation amount for a DynAlloca instruction, or -1 if unknown.
-static int64_t getDynAllocaAmount(MachineInstr *MI, MachineRegisterInfo *MRI) {
- assert(MI->getOpcode() == X86::DYN_ALLOCA_32 ||
- MI->getOpcode() == X86::DYN_ALLOCA_64);
- assert(MI->getOperand(0).isReg());
+static bool isDynAllocaOpcode(unsigned Opc) {
+ return Opc == X86::DYN_ALLOCA_32 || Opc == X86::DYN_ALLOCA_64 ||
+ Opc == X86::WIN_ALLOCA_64;
+}
+
+static unsigned getDynAllocaAmountOperandIndex(const MachineInstr *MI) {
+ return MI->getOpcode() == X86::WIN_ALLOCA_64 ? 1 : 0;
+}
- Register AmountReg = MI->getOperand(0).getReg();
- MachineInstr *Def = MRI->getUniqueVRegDef(AmountReg);
+static int64_t getConstantRegValue(Register Reg, MachineRegisterInfo *MRI) {
+ MachineInstr *Def = MRI->getUniqueVRegDef(Reg);
if (!Def ||
(Def->getOpcode() != X86::MOV32ri && Def->getOpcode() != X86::MOV64ri) ||
@@ -104,6 +113,36 @@ static int64_t getDynAllocaAmount(MachineInstr *MI, MachineRegisterInfo *MRI) {
return Def->getOperand(1).getImm();
}
+static int64_t getWinAllocaAmount(MachineInstr *MI, MachineRegisterInfo *MRI,
+ unsigned StackAlign) {
+ assert(MI->getOpcode() == X86::WIN_ALLOCA_64);
+ assert(MI->getOperand(1).isReg());
+
+ int64_t RawAmount = getConstantRegValue(MI->getOperand(1).getReg(), MRI);
+ if (RawAmount < 0)
+ return -1;
+
+ uint64_t Amount = static_cast<uint64_t>(RawAmount);
+ unsigned Alignment = MI->getOperand(2).getImm();
+ if (Alignment > StackAlign)
+ Amount += Alignment - 1;
+ Amount = alignTo(Amount, StackAlign);
+ if (Amount > static_cast<uint64_t>(INT64_MAX))
+ return -1;
+ return static_cast<int64_t>(Amount);
+}
+
+static int64_t getDynAllocaAmount(MachineInstr *MI, MachineRegisterInfo *MRI,
+ unsigned StackAlign = 0) {
+ assert(isDynAllocaOpcode(MI->getOpcode()));
+ if (MI->getOpcode() == X86::WIN_ALLOCA_64)
+ return getWinAllocaAmount(MI, MRI, StackAlign);
+
+ unsigned AmountOperandIndex = getDynAllocaAmountOperandIndex(MI);
+ assert(MI->getOperand(AmountOperandIndex).isReg());
+ return getConstantRegValue(MI->getOperand(AmountOperandIndex).getReg(), MRI);
+}
+
X86DynAllocaExpander::Lowering
X86DynAllocaExpander::getLowering(int64_t CurrentOffset,
int64_t AllocaAmount) {
@@ -154,6 +193,8 @@ void X86DynAllocaExpander::computeLowerings(MachineFunction &MF,
// Compute the reverse post-order.
ReversePostOrderTraversal<MachineFunction*> RPO(&MF);
+ bool HasStableWin64MSVCCallFrame =
+ MF.getInfo<X86MachineFunctionInfo>()->hasWin64MSVCDynAllocaCallFrame();
for (MachineBasicBlock *MBB : RPO) {
int64_t Offset = -1;
@@ -162,10 +203,10 @@ void X86DynAllocaExpander::computeLowerings(MachineFunction &MF,
if (Offset == -1) Offset = INT32_MAX;
for (MachineInstr &MI : *MBB) {
- if (MI.getOpcode() == X86::DYN_ALLOCA_32 ||
- MI.getOpcode() == X86::DYN_ALLOCA_64) {
+ if (isDynAllocaOpcode(MI.getOpcode())) {
// A DynAlloca moves StackPtr, and potentially touches it.
- int64_t Amount = getDynAllocaAmount(&MI, MRI);
+ int64_t Amount = getDynAllocaAmount(
+ &MI, MRI, STI->getFrameLowering()->getStackAlign().value());
Lowering L = getLowering(Offset, Amount);
Lowerings[&MI] = L;
switch (L) {
@@ -184,10 +225,14 @@ void X86DynAllocaExpander::computeLowerings(MachineFunction &MF,
Offset = 0;
} else if (MI.getOpcode() == X86::ADJCALLSTACKUP32 ||
MI.getOpcode() == X86::ADJCALLSTACKUP64) {
- Offset -= MI.getOperand(0).getImm();
+ if (!HasStableWin64MSVCCallFrame ||
+ MI.getOpcode() != X86::ADJCALLSTACKUP64)
+ Offset -= MI.getOperand(0).getImm();
} else if (MI.getOpcode() == X86::ADJCALLSTACKDOWN32 ||
MI.getOpcode() == X86::ADJCALLSTACKDOWN64) {
- Offset += MI.getOperand(0).getImm();
+ if (!HasStableWin64MSVCCallFrame ||
+ MI.getOpcode() != X86::ADJCALLSTACKDOWN64)
+ Offset += MI.getOperand(0).getImm();
} else if (MI.modifiesRegister(StackPtr, TRI)) {
// Any other modification of SP means we've lost track of it.
Offset = INT32_MAX;
@@ -204,13 +249,47 @@ static unsigned getSubOpcode(bool Is64Bit) {
return X86::SUB32ri;
}
+Register X86DynAllocaExpander::materializeWinAllocaAmount(
+ MachineInstr *MI, MachineBasicBlock::iterator I, const DebugLoc &DL) {
+ assert(MI->getOpcode() == X86::WIN_ALLOCA_64);
+
+ MachineBasicBlock *MBB = MI->getParent();
+ unsigned StackAlign = STI->getFrameLowering()->getStackAlign().value();
+ unsigned Alignment = MI->getOperand(2).getImm();
+ Register RawAmountReg = MI->getOperand(1).getReg();
+
+ uint64_t AlignmentSlack = Alignment > StackAlign ? Alignment - 1 : 0;
+ uint64_t RoundUpBias = StackAlign - 1;
+ uint64_t Addend = AlignmentSlack + RoundUpBias;
+
+ Register AddendReg = MRI->createVirtualRegister(&X86::GR64RegClass);
+ BuildMI(*MBB, I, DL, TII->get(X86::MOV64ri), AddendReg).addImm(Addend);
+
+ Register UnalignedAmountReg = MRI->createVirtualRegister(&X86::GR64RegClass);
+ BuildMI(*MBB, I, DL, TII->get(X86::ADD64rr), UnalignedAmountReg)
+ .addReg(RawAmountReg)
+ .addReg(AddendReg);
+
+ Register AmountReg = MRI->createVirtualRegister(&X86::GR64RegClass);
+ BuildMI(*MBB, I, DL, TII->get(X86::AND64ri32), AmountReg)
+ .addReg(UnalignedAmountReg)
+ .addImm(-int64_t(StackAlign));
+ return AmountReg;
+}
+
void X86DynAllocaExpander::lower(MachineInstr *MI, Lowering L) {
const DebugLoc &DL = MI->getDebugLoc();
MachineBasicBlock *MBB = MI->getParent();
+ unsigned Win64MSVCDynAllocaCallFrameSize =
+ MBB->getParent()
+ ->getInfo<X86MachineFunctionInfo>()
+ ->getWin64MSVCDynAllocaCallFrameSize();
MachineBasicBlock::iterator I = *MI;
- int64_t Amount = getDynAllocaAmount(MI, MRI);
- if (Amount == 0) {
+ bool IsWinAlloca = MI->getOpcode() == X86::WIN_ALLOCA_64;
+ int64_t Amount = getDynAllocaAmount(
+ MI, MRI, STI->getFrameLowering()->getStackAlign().value());
+ if (Amount == 0 && !IsWinAlloca) {
MI->eraseFromParent();
return;
}
@@ -218,65 +297,102 @@ void X86DynAllocaExpander::lower(MachineInstr *MI, Lowering L) {
// These two variables differ on x32, which is a 64-bit target with a
// 32-bit alloca.
bool Is64Bit = STI->is64Bit();
- bool Is64BitAlloca = MI->getOpcode() == X86::DYN_ALLOCA_64;
+ bool Is64BitAlloca = MI->getOpcode() == X86::DYN_ALLOCA_64 ||
+ MI->getOpcode() == X86::WIN_ALLOCA_64;
assert(SlotSize == 4 || SlotSize == 8);
std::optional<MachineFunction::DebugInstrOperandPair> InstrNum;
- if (unsigned Num = MI->peekDebugInstrNum()) {
+ if (unsigned Num = MI->peekDebugInstrNum(); !IsWinAlloca && Num) {
// Operand 2 of DYN_ALLOCAs contains the stack def.
InstrNum = {Num, 2};
}
- switch (L) {
- case TouchAndSub: {
- assert(Amount >= SlotSize);
+ unsigned AmountOperandIndex = getDynAllocaAmountOperandIndex(MI);
+ Register AmountReg = MI->getOperand(AmountOperandIndex).getReg();
- // Use a push to touch the top of the stack.
- unsigned RegA = Is64Bit ? X86::RAX : X86::EAX;
- BuildMI(*MBB, I, DL, TII->get(Is64Bit ? X86::PUSH64r : X86::PUSH32r))
- .addReg(RegA, RegState::Undef);
- Amount -= SlotSize;
- if (!Amount)
- break;
+ if (Amount != 0) {
+ switch (L) {
+ case TouchAndSub: {
+ assert(Amount >= SlotSize);
- // Fall through to make any remaining adjustment.
- [[fallthrough]];
- }
- case Sub:
- assert(Amount > 0);
- if (Amount == SlotSize) {
- // Use push to save size.
+ // Use a push to touch the top of the stack.
unsigned RegA = Is64Bit ? X86::RAX : X86::EAX;
BuildMI(*MBB, I, DL, TII->get(Is64Bit ? X86::PUSH64r : X86::PUSH32r))
.addReg(RegA, RegState::Undef);
- } else {
- // Sub.
- BuildMI(*MBB, I, DL, TII->get(getSubOpcode(Is64BitAlloca)), StackPtr)
- .addReg(StackPtr)
- .addImm(Amount);
+ Amount -= SlotSize;
+ if (!Amount)
+ break;
+
+ // Fall through to make any remaining adjustment.
+ [[fallthrough]];
+ }
+ case Sub:
+ assert(Amount > 0);
+ if (Amount == SlotSize) {
+ // Use push to save size.
+ unsigned RegA = Is64Bit ? X86::RAX : X86::EAX;
+ BuildMI(*MBB, I, DL, TII->get(Is64Bit ? X86::PUSH64r : X86::PUSH32r))
+ .addReg(RegA, RegState::Undef);
+ } else {
+ // Sub.
+ BuildMI(*MBB, I, DL, TII->get(getSubOpcode(Is64BitAlloca)), StackPtr)
+ .addReg(StackPtr)
+ .addImm(Amount);
+ }
+ break;
+ case Probe:
+ Register ProbeAmountReg = AmountReg;
+ if (IsWinAlloca) {
+ if (Amount >= 0) {
+ ProbeAmountReg = MRI->createVirtualRegister(&X86::GR64RegClass);
+ BuildMI(*MBB, I, DL, TII->get(X86::MOV64ri), ProbeAmountReg)
+ .addImm(Amount);
+ } else {
+ ProbeAmountReg = materializeWinAllocaAmount(MI, I, DL);
+ }
+ }
+ if (!NoStackArgProbe) {
+ // The probe lowering expects the amount in RAX/EAX.
+ unsigned RegA = Is64BitAlloca ? X86::RAX : X86::EAX;
+ BuildMI(*MBB, MI, DL, TII->get(TargetOpcode::COPY), RegA)
+ .addReg(ProbeAmountReg);
+
+ // Do the probe.
+ STI->getFrameLowering()->emitStackProbe(*MBB->getParent(), *MBB, MI, DL,
+ /*InProlog=*/false, InstrNum);
+ } else {
+ // Sub
+ BuildMI(*MBB, I, DL,
+ TII->get(Is64BitAlloca ? X86::SUB64rr : X86::SUB32rr), StackPtr)
+ .addReg(StackPtr)
+ .addReg(ProbeAmountReg);
+ }
+ break;
}
- break;
- case Probe:
- if (!NoStackArgProbe) {
- // The probe lowering expects the amount in RAX/EAX.
- unsigned RegA = Is64BitAlloca ? X86::RAX : X86::EAX;
- BuildMI(*MBB, MI, DL, TII->get(TargetOpcode::COPY), RegA)
- .addReg(MI->getOperand(0).getReg());
-
- // Do the probe.
- STI->getFrameLowering()->emitStackProbe(*MBB->getParent(), *MBB, MI, DL,
- /*InProlog=*/false, InstrNum);
+ }
+
+ if (IsWinAlloca) {
+ Register DstReg = MI->getOperand(0).getReg();
+ unsigned Alignment = MI->getOperand(2).getImm();
+ unsigned StackAlign = STI->getFrameLowering()->getStackAlign().value();
+
+ if (Alignment > StackAlign) {
+ Register TmpReg = MRI->createVirtualRegister(&X86::GR64RegClass);
+ addRegOffset(BuildMI(*MBB, I, DL, TII->get(X86::LEA64r), TmpReg),
+ StackPtr, false,
+ Win64MSVCDynAllocaCallFrameSize + Alignment - 1);
+ BuildMI(*MBB, I, DL, TII->get(X86::AND64ri32), DstReg)
+ .addReg(TmpReg)
+ .addImm(-int64_t(Alignment));
+ } else if (Win64MSVCDynAllocaCallFrameSize != 0) {
+ addRegOffset(BuildMI(*MBB, I, DL, TII->get(X86::LEA64r), DstReg),
+ StackPtr, false, Win64MSVCDynAllocaCallFrameSize);
} else {
- // Sub
- BuildMI(*MBB, I, DL,
- TII->get(Is64BitAlloca ? X86::SUB64rr : X86::SUB32rr), StackPtr)
- .addReg(StackPtr)
- .addReg(MI->getOperand(0).getReg());
+ BuildMI(*MBB, I, DL, TII->get(TargetOpcode::COPY), DstReg)
+ .addReg(StackPtr);
}
- break;
}
- Register AmountReg = MI->getOperand(0).getReg();
MI->eraseFromParent();
// Delete the definition of AmountReg.
@@ -297,6 +413,22 @@ bool X86DynAllocaExpander::run(MachineFunction &MF) {
SlotSize = TRI->getSlotSize();
StackProbeSize = STI->getTargetLowering()->getStackProbeSize(MF);
NoStackArgProbe = MF.getFunction().hasFnAttribute("no-stack-arg-probe");
+ auto *X86FI = MF.getInfo<X86MachineFunctionInfo>();
+ auto &MFI = MF.getFrameInfo();
+
+ unsigned Win64MSVCDynAllocaCallFrameSize = 0;
+ if (STI->isTargetWin64() && STI->isTargetWindowsMSVC()) {
+ MFI.computeMaxCallFrameSize(MF);
+ Align StackAlign = STI->getFrameLowering()->getStackAlign();
+ Win64MSVCDynAllocaCallFrameSize =
+ static_cast<unsigned>(alignTo(MFI.getMaxCallFrameSize(), StackAlign));
+ assert(Win64MSVCDynAllocaCallFrameSize == 0 ||
+ !X86FI->getHasPushSequences());
+ assert(Win64MSVCDynAllocaCallFrameSize == 0 ||
+ !X86FI->hasPreallocatedCall());
+ }
+ X86FI->setWin64MSVCDynAllocaCallFrameSize(Win64MSVCDynAllocaCallFrameSize);
+
if (NoStackArgProbe)
StackProbeSize = INT64_MAX;
diff --git a/llvm/lib/Target/X86/X86FrameLowering.cpp b/llvm/lib/Target/X86/X86FrameLowering.cpp
index a6e1d998c051a..0beef2def09f1 100644
--- a/llvm/lib/Target/X86/X86FrameLowering.cpp
+++ b/llvm/lib/Target/X86/X86FrameLowering.cpp
@@ -54,6 +54,26 @@ getCalleeSavedSpillRC(MCRegister Reg, const X86Subtarget &STI,
return TRI.getMinimalPhysRegClass(Reg);
}
+static bool hasConstantSP(const MachineFunction &MF) {
+ const auto *X86FI = MF.getInfo<X86MachineFunctionInfo>();
+ return !MF.getFrameInfo().hasVarSizedObjects() &&
+ !X86FI->getHasPushSequences() && !X86FI->hasPreallocatedCall();
+}
+
+static bool hasWin64MSVCDynAllocaCallFrame(const MachineFunction &MF) {
+ const auto &STI = MF.getSubtarget<X86Subtarget>();
+ if (!STI.isTargetWin64() || !STI.isTargetWindowsMSVC())
+ return false;
+
+ const auto *X86FI = MF.getInfo<X86MachineFunctionInfo>();
+ if (!X86FI->hasWin64MSVCDynAllocaCallFrame())
+ return false;
+
+ assert(!X86FI->getHasPushSequences());
+ assert(!X86FI->hasPreallocatedCall());
+ return true;
+}
+
X86FrameLowering::X86FrameLowering(const X86Subtarget &STI,
MaybeAlign StackAlignOverride)
: TargetFrameLowering(StackGrowsDown, StackAlignOverride.valueOrOne(),
@@ -70,9 +90,7 @@ X86FrameLowering::X86FrameLowering(const X86Subtarget &STI,
}
bool X86FrameLowering::hasReservedCallFrame(const MachineFunction &MF) const {
- return !MF.getFrameInfo().hasVarSizedObjects() &&
- !MF.getInfo<X86MachineFunctionInfo>()->getHasPushSequences() &&
- !MF.getInfo<X86MachineFunctionInfo>()->hasPreallocatedCall();
+ return hasConstantSP(MF) || hasWin64MSVCDynAllocaCallFrame(MF);
}
/// canSimplifyCallFramePseudos - If there is a reserved call frame, the
@@ -2966,7 +2984,7 @@ X86FrameLowering::getFrameIndexReferencePreferSP(const MachineFunction &MF,
// If !hasReservedCallFrame the function might have SP adjustement in the
// body. So, even though the offset is statically known, it depends on where
// we are in the function.
- if (!IgnoreSPUpdates && !hasReservedCallFrame(MF))
+ if (!IgnoreSPUpdates && !hasConstantSP(MF))
return getFrameIndexReference(MF, FI, FrameReg);
// We don't handle tail calls, and shouldn't be seeing them either.
diff --git a/llvm/lib/Target/X86/X86ISelLowering.cpp b/llvm/lib/Target/X86/X86ISelLowering.cpp
index b95ac78f50049..257286e74fb53 100644
--- a/llvm/lib/Target/X86/X86ISelLowering.cpp
+++ b/llvm/lib/Target/X86/X86ISelLowering.cpp
@@ -26706,6 +26706,7 @@ X86TargetLowering::LowerDYNAMIC_STACKALLOC(SDValue Op,
SDValue Chain = Op.getOperand(0);
SDValue Size = Op.getOperand(1);
MaybeAlign Alignment(Op.getConstantOperandVal(2));
+ SDValue RawSize = Op.getOperand(3);
EVT VT = Node->getValueType(0);
// Chain the dynamic stack allocation so that it doesn't modify the stack
@@ -26753,6 +26754,13 @@ X86TargetLowering::LowerDYNAMIC_STACKALLOC(SDValue Op,
Result =
DAG.getNode(X86ISD::SEG_ALLOCA, dl, {SPTy, MVT::Other}, {Chain, Size});
Chain = Result.getValue(1);
+ } else if (Subtarget.isTargetWin64() && Subtarget.isTargetWindowsMSVC()) {
+ SDVTList NodeTys = DAG.getVTList(SPTy, MVT::Other);
+ Result = DAG.getNode(X86ISD::WIN_ALLOCA, dl, NodeTys, Chain, RawSize,
+ DAG.getTargetConstant(
+ Alignment ? Alignment->value() : 0, dl, MVT::i32));
+ Chain = Result.getValue(1);
+ MF.getInfo<X86MachineFunctionInfo>()->setHasDynAlloca(true);
} else {
SDVTList NodeTys = DAG.getVTList(MVT::Other, MVT::Glue);
Chain = DAG.getNode(X86ISD::DYN_ALLOCA, dl, NodeTys, Chain, Size);
diff --git a/llvm/lib/Target/X86/X86InstrCompiler.td b/llvm/lib/Target/X86/X86InstrCompiler.td
index 35dfdf2d0067c..bd7e848399316 100644
--- a/llvm/lib/Target/X86/X86InstrCompiler.td
+++ b/llvm/lib/Target/X86/X86InstrCompiler.td
@@ -158,6 +158,14 @@ def DYN_ALLOCA_64 : I<0, Pseudo, (outs), (ins GR64:$size),
"# dynamic stack allocation",
[(X86DynAlloca GR64:$size)]>,
Requires<[In64BitMode]>;
+
+let Defs = [RAX, RSP, EFLAGS], Uses = [RSP] in
+def WIN_ALLOCA_64 : I<0, Pseudo, (outs GR64:$dst),
+ (ins GR64:$raw_size, i32imm:$align),
+ "# dynamic stack allocation with a stable call frame",
+ [(set GR64:$dst,
+ (X86WinAlloca GR64:$raw_size, timm:$align))]>,
+ Requires<[In64BitMode]>;
} // SchedRW
// These instructions XOR the frame pointer into a GPR. They are used in some
diff --git a/llvm/lib/Target/X86/X86InstrFragments.td b/llvm/lib/Target/X86/X86InstrFragments.td
index c183849d4f575..70ed0499218d7 100644
--- a/llvm/lib/Target/X86/X86InstrFragments.td
+++ b/llvm/lib/Target/X86/X86InstrFragments.td
@@ -114,6 +114,10 @@ def SDT_X86TLSCALL : SDTypeProfile<0, 1, [SDTCisInt<0>]>;
def SDT_X86DYN_ALLOCA : SDTypeProfile<0, 1, [SDTCisVT<0, iPTR>]>;
+def SDT_X86WIN_ALLOCA : SDTypeProfile<1, 2, [SDTCisVT<0, iPTR>,
+ SDTCisVT<1, iPTR>,
+ SDTCisVT<2, i32>]>;
+
def SDT_X86SEG_ALLOCA : SDTypeProfile<1, 1, [SDTCisVT<0, iPTR>, SDTCisVT<1, iPTR>]>;
def SDT_X86PROBED_ALLOCA : SDTypeProfile<1, 1, [SDTCisVT<0, iPTR>, SDTCisVT<1, iPTR>]>;
@@ -431,6 +435,9 @@ def X86mul_imm : SDNode<"X86ISD::MUL_IMM", SDTIntBinOp>;
def X86DynAlloca : SDNode<"X86ISD::DYN_ALLOCA", SDT_X86DYN_ALLOCA,
[SDNPHasChain, SDNPOutGlue]>;
+def X86WinAlloca : SDNode<"X86ISD::WIN_ALLOCA", SDT_X86WIN_ALLOCA,
+ [SDNPHasChain]>;
+
// For allocating variable amounts of stack space when using
// segmented stacks. Check if the current stacklet has enough space, and
// falls back to heap allocation if not.
diff --git a/llvm/lib/Target/X86/X86MachineFunctionInfo.h b/llvm/lib/Target/X86/X86MachineFunctionInfo.h
index 1cfe86d57071f..5d0be0b436555 100644
--- a/llvm/lib/Target/X86/X86MachineFunctionInfo.h
+++ b/llvm/lib/Target/X86/X86MachineFunctionInfo.h
@@ -116,6 +116,9 @@ class X86MachineFunctionInfo : public MachineFunctionInfo {
unsigned ArgumentStackSize = 0;
/// NumLocalDynamics - Number of local-dynamic TLS accesses.
unsigned NumLocalDynamics = 0;
+ /// On x86_64-windows-msvc dynalloca functions, stores the rounded stable
+ /// outgoing call-frame size inferred from ADJCALLSTACKDOWN64/UP64 pseudos.
+ unsigned Win64MSVCDynAllocaCallFrameSize = 0;
/// HasPushSequences - Keeps track of whether this function uses sequences
/// of pushes to pass function parameters.
bool HasPushSequences = false;
@@ -276,6 +279,16 @@ class X86MachineFunctionInfo : public MachineFunctionInfo {
bool hasPreallocatedCall() const { return HasPreallocatedCall; }
void setHasPreallocatedCall(bool v) { HasPreallocatedCall = v; }
+ bool hasWin64MSVCDynAllocaCallFrame() const {
+ return Win64MSVCDynAllocaCallFrameSize != 0;
+ }
+ unsigned getWin64MSVCDynAllocaCallFrameSize() const {
+ return Win64MSVCDynAllocaCallFrameSize;
+ }
+ void setWin64MSVCDynAllocaCallFrameSize(unsigned Size) {
+ Win64MSVCDynAllocaCallFrameSize = Size;
+ }
+
bool hasSwiftAsyncContext() const { return HasSwiftAsyncContext; }
void setHasSwiftAsyncContext(bool v) { HasSwiftAsyncContext = v; }
diff --git a/llvm/test/CodeGen/X86/alloca-align-rounding.ll b/llvm/test/CodeGen/X86/alloca-align-rounding.ll
index 38866ceaca32c..49efa47227de7 100644
--- a/llvm/test/CodeGen/X86/alloca-align-rounding.ll
+++ b/llvm/test/CodeGen/X86/alloca-align-rounding.ll
@@ -1,5 +1,6 @@
; RUN: llc < %s -mtriple=x86_64-pc-linux -enable-misched=false | FileCheck %s
; RUN: llc < %s -mtriple=x86_64-pc-linux-gnux32 -enable-misched=false | FileCheck %s -check-prefix=X32ABI
+; RUN: llc < %s -mtriple=x86_64-pc-win32 -enable-misched=false | FileCheck %s -check-prefix=WIN64
declare void @bar(ptr %n)
@@ -20,6 +21,15 @@ define void @foo2(i64 %h) {
; CHECK-LABEL: foo2
; CHECK: andq $-32, %rsp
; CHECK: andq $-32, %rax
+; WIN64-LABEL: foo2
+; WIN64: andq $-32, %rsp
+; WIN64: movabsq $46, %rax
+; WIN64: addq %rcx, %rax
+; WIN64: andq $-16, %rax
+; WIN64: callq __chkstk
+; WIN64: subq %rax, %rsp
+; WIN64: leaq 63(%rsp), %rcx
+; WIN64: andq $-32, %rcx
; X32ABI-LABEL: foo2
; X32ABI: andl $-32, %esp
; X32ABI: andl $-32, %eax
diff --git a/llvm/test/CodeGen/X86/catchpad-dynamic-alloca.ll b/llvm/test/CodeGen/X86/catchpad-dynamic-alloca.ll
index 6b63162717e7f..46323555a2f32 100644
--- a/llvm/test/CodeGen/X86/catchpad-dynamic-alloca.ll
+++ b/llvm/test/CodeGen/X86/catchpad-dynamic-alloca.ll
@@ -31,10 +31,27 @@ catch.switch:
%cs = catchswitch within none [label %catch.pad] unwind to caller
}
+; CHECK-LABEL: test1:
+; CHECK: movabsq $15, %rax
+; CHECK-NEXT: addq %rdx, %rax
+; CHECK-NEXT: andq $-16, %rax
+; CHECK-NEXT: callq __chkstk
+; CHECK-NEXT: subq %rax, %rsp
+; CHECK-NEXT: leaq 32(%rsp), %rax
+; CHECK-NEXT: movb $0, -9(%rbp)
+; CHECK-NEXT: movb $0, (%rax)
+; CHECK: callq rt_init
+; CHECK-NOT: subq
+; CHECK-NOT: addq
+; CHECK: callq *%rsi
+; CHECK-LABEL: "?catch$3@?0?test1 at 4HA":
+; CHECK: leaq 48(%rdx), %rbp
; CHECK-LABEL: $handlerMap$0$test1:
; CHECK: .long 0
; CHECK-NEXT: .long 0
-; CHECK-NEXT: .long 16
+; CHECK-NEXT: .long 48
+; CHECK-NEXT: .long "?catch$3@?0?test1 at 4HA"@IMGREL
+; CHECK-NEXT: .long 72
define void @test2(ptr %fp, i64 %n) personality ptr @__CxxFrameHandler3 {
entry:
@@ -59,7 +76,23 @@ catch.switch:
%cs = catchswitch within none [label %catch.pad] unwind to caller
}
+; CHECK-LABEL: test2:
+; CHECK: movabsq $15, %rax
+; CHECK-NEXT: addq %rdx, %rax
+; CHECK-NEXT: andq $-16, %rax
+; CHECK-NEXT: callq __chkstk
+; CHECK-NEXT: subq %rax, %rsp
+; CHECK-NEXT: leaq 32(%rsp), %rax
+; CHECK-NEXT: movb $0, (%rax)
+; CHECK: callq rt_init
+; CHECK-NOT: subq
+; CHECK-NOT: addq
+; CHECK: callq *%rsi
+; CHECK-LABEL: "?catch$3@?0?test2 at 4HA":
+; CHECK: leaq 64(%rdx), %rbp
; CHECK-LABEL: $handlerMap$0$test2:
; CHECK: .long 0
; CHECK-NEXT: .long 0
-; CHECK-NEXT: .long 16
+; CHECK-NEXT: .long 48
+; CHECK-NEXT: .long "?catch$3@?0?test2 at 4HA"@IMGREL
+; CHECK-NEXT: .long 72
diff --git a/llvm/test/CodeGen/X86/localescape.ll b/llvm/test/CodeGen/X86/localescape.ll
index 57369be489af3..951b2fe09da34 100644
--- a/llvm/test/CodeGen/X86/localescape.ll
+++ b/llvm/test/CodeGen/X86/localescape.ll
@@ -72,16 +72,25 @@ define void @alloc_func(i32 %n) {
; X64-LABEL: alloc_func:
; X64: pushq %rbp
-; X64: subq $16, %rsp
-; X64: .seh_stackalloc 16
-; X64: leaq 16(%rsp), %rbp
-; X64: .seh_setframe %rbp, 16
+; X64: subq $48, %rsp
+; X64: .seh_stackalloc 48
+; X64: leaq 48(%rsp), %rbp
+; X64: .seh_setframe %rbp, 48
+; X64: .seh_endprologue
; X64: .Lalloc_func$frame_escape_0 = -4
; X64: .Lalloc_func$frame_escape_1 = -12
; X64: movl $42, -4(%rbp)
; X64: movl $13, -12(%rbp)
-; X64: movq %rbp, %rcx
+; X64: movl %ecx, %ecx
+; X64: movabsq $15, %rax
+; X64: addq %rcx, %rax
+; X64: andq $-16, %rax
+; X64: callq __chkstk
+; X64: subq %rax, %rsp
+; X64: leaq 32(%rsp), %rax
+; X64: movq %rbp, %rcx
; X64: callq print_framealloc_from_fp
+; X64: movq %rbp, %rsp
; X64: retq
; X86-LABEL: alloc_func:
diff --git a/llvm/test/CodeGen/X86/stack-protector-msvc.ll b/llvm/test/CodeGen/X86/stack-protector-msvc.ll
index 3109733e0b0b7..c8cfa2085077a 100644
--- a/llvm/test/CodeGen/X86/stack-protector-msvc.ll
+++ b/llvm/test/CodeGen/X86/stack-protector-msvc.ll
@@ -176,20 +176,20 @@ define void @test_vla(i32 %n) nounwind ssp {
; MSVC-X64-LABEL: test_vla:
; MSVC-X64: # %bb.0:
; MSVC-X64-NEXT: pushq %rbp
-; MSVC-X64-NEXT: subq $16, %rsp
-; MSVC-X64-NEXT: leaq {{[0-9]+}}(%rsp), %rbp
+; MSVC-X64-NEXT: subq $48, %rsp
+; MSVC-X64-NEXT: leaq 48(%rsp), %rbp
; MSVC-X64-NEXT: movq __security_cookie(%rip), %rax
; MSVC-X64-NEXT: xorq %rbp, %rax
; MSVC-X64-NEXT: movq %rax, -8(%rbp)
-; MSVC-X64-NEXT: movl %ecx, %eax
-; MSVC-X64-NEXT: leaq 15(,%rax,4), %rax
+; MSVC-X64-NEXT: movl %ecx, %ecx
+; MSVC-X64-NEXT: shlq $2, %rcx
+; MSVC-X64-NEXT: movabsq $15, %rax
+; MSVC-X64-NEXT: addq %rcx, %rax
; MSVC-X64-NEXT: andq $-16, %rax
; MSVC-X64-NEXT: callq __chkstk
; MSVC-X64-NEXT: subq %rax, %rsp
-; MSVC-X64-NEXT: movq %rsp, %rcx
-; MSVC-X64-NEXT: subq $32, %rsp
+; MSVC-X64-NEXT: leaq 32(%rsp), %rcx
; MSVC-X64-NEXT: callq escape
-; MSVC-X64-NEXT: addq $32, %rsp
; MSVC-X64-NEXT: movq -8(%rbp), %rax
; MSVC-X64-NEXT: xorq %rbp, %rax
; MSVC-X64-NEXT: movq __security_cookie(%rip), %rcx
@@ -202,7 +202,6 @@ define void @test_vla(i32 %n) nounwind ssp {
; MSVC-X64-NEXT: .LBB1_2:
; MSVC-X64-NEXT: movq -8(%rbp), %rcx
; MSVC-X64-NEXT: xorq %rbp, %rcx
-; MSVC-X64-NEXT: subq $32, %rsp
; MSVC-X64-NEXT: callq __security_check_cookie
;
; MSVC-X86-O0-LABEL: test_vla:
@@ -239,21 +238,21 @@ define void @test_vla(i32 %n) nounwind ssp {
; MSVC-X64-O0-LABEL: test_vla:
; MSVC-X64-O0: # %bb.0:
; MSVC-X64-O0-NEXT: pushq %rbp
-; MSVC-X64-O0-NEXT: subq $16, %rsp
-; MSVC-X64-O0-NEXT: leaq {{[0-9]+}}(%rsp), %rbp
+; MSVC-X64-O0-NEXT: subq $48, %rsp
+; MSVC-X64-O0-NEXT: leaq 48(%rsp), %rbp
; MSVC-X64-O0-NEXT: movq __security_cookie(%rip), %rax
; MSVC-X64-O0-NEXT: xorq %rbp, %rax
; MSVC-X64-O0-NEXT: movq %rax, -8(%rbp)
; MSVC-X64-O0-NEXT: movl %ecx, %eax
; MSVC-X64-O0-NEXT: # kill: def $rax killed $eax
-; MSVC-X64-O0-NEXT: leaq 15(,%rax,4), %rax
+; MSVC-X64-O0-NEXT: shlq $2, %rax
+; MSVC-X64-O0-NEXT: movabsq $15, %rcx
+; MSVC-X64-O0-NEXT: addq %rcx, %rax
; MSVC-X64-O0-NEXT: andq $-16, %rax
; MSVC-X64-O0-NEXT: callq __chkstk
; MSVC-X64-O0-NEXT: subq %rax, %rsp
-; MSVC-X64-O0-NEXT: movq %rsp, %rcx
-; MSVC-X64-O0-NEXT: subq $32, %rsp
+; MSVC-X64-O0-NEXT: leaq 32(%rsp), %rcx
; MSVC-X64-O0-NEXT: callq escape
-; MSVC-X64-O0-NEXT: addq $32, %rsp
; MSVC-X64-O0-NEXT: movq -8(%rbp), %rcx
; MSVC-X64-O0-NEXT: xorq %rbp, %rcx
; MSVC-X64-O0-NEXT: movq __security_cookie(%rip), %rax
@@ -263,7 +262,6 @@ define void @test_vla(i32 %n) nounwind ssp {
; MSVC-X64-O0-NEXT: .LBB1_2:
; MSVC-X64-O0-NEXT: movq -8(%rbp), %rcx
; MSVC-X64-O0-NEXT: xorq %rbp, %rcx
-; MSVC-X64-O0-NEXT: subq $32, %rsp
; MSVC-X64-O0-NEXT: callq __security_check_cookie
; MSVC-X64-O0-NEXT: .LBB1_1:
; MSVC-X64-O0-NEXT: movq %rbp, %rsp
@@ -323,26 +321,26 @@ define void @test_vla_realign(i32 %n) nounwind ssp {
; MSVC-X64-NEXT: pushq %rbp
; MSVC-X64-NEXT: pushq %rsi
; MSVC-X64-NEXT: pushq %rbx
-; MSVC-X64-NEXT: subq $32, %rsp
-; MSVC-X64-NEXT: leaq {{[0-9]+}}(%rsp), %rbp
+; MSVC-X64-NEXT: subq $64, %rsp
+; MSVC-X64-NEXT: leaq 64(%rsp), %rbp
; MSVC-X64-NEXT: andq $-32, %rsp
; MSVC-X64-NEXT: movq %rsp, %rbx
; MSVC-X64-NEXT: movq __security_cookie(%rip), %rax
; MSVC-X64-NEXT: xorq %rbp, %rax
-; MSVC-X64-NEXT: movq %rax, 24(%rbx)
-; MSVC-X64-NEXT: movl %ecx, %eax
-; MSVC-X64-NEXT: leaq 15(,%rax,4), %rax
+; MSVC-X64-NEXT: movq %rax, 56(%rbx)
+; MSVC-X64-NEXT: movl %ecx, %ecx
+; MSVC-X64-NEXT: shlq $2, %rcx
+; MSVC-X64-NEXT: movabsq $15, %rax
+; MSVC-X64-NEXT: addq %rcx, %rax
; MSVC-X64-NEXT: andq $-16, %rax
; MSVC-X64-NEXT: callq __chkstk
; MSVC-X64-NEXT: subq %rax, %rsp
-; MSVC-X64-NEXT: movq %rsp, %rsi
-; MSVC-X64-NEXT: subq $32, %rsp
-; MSVC-X64-NEXT: movq %rbx, %rcx
+; MSVC-X64-NEXT: leaq 32(%rsp), %rsi
+; MSVC-X64-NEXT: leaq 32(%rbx), %rcx
; MSVC-X64-NEXT: callq escape
; MSVC-X64-NEXT: movq %rsi, %rcx
; MSVC-X64-NEXT: callq escape
-; MSVC-X64-NEXT: addq $32, %rsp
-; MSVC-X64-NEXT: movq 24(%rbx), %rax
+; MSVC-X64-NEXT: movq 56(%rbx), %rax
; MSVC-X64-NEXT: xorq %rbp, %rax
; MSVC-X64-NEXT: movq __security_cookie(%rip), %rcx
; MSVC-X64-NEXT: cmpq %rax, %rcx
@@ -354,9 +352,8 @@ define void @test_vla_realign(i32 %n) nounwind ssp {
; MSVC-X64-NEXT: popq %rbp
; MSVC-X64-NEXT: retq
; MSVC-X64-NEXT: .LBB2_2:
-; MSVC-X64-NEXT: movq 24(%rbx), %rcx
+; MSVC-X64-NEXT: movq 56(%rbx), %rcx
; MSVC-X64-NEXT: xorq %rbp, %rcx
-; MSVC-X64-NEXT: subq $32, %rsp
; MSVC-X64-NEXT: callq __security_check_cookie
;
; MSVC-X86-O0-LABEL: test_vla_realign:
@@ -403,37 +400,36 @@ define void @test_vla_realign(i32 %n) nounwind ssp {
; MSVC-X64-O0: # %bb.0:
; MSVC-X64-O0-NEXT: pushq %rbp
; MSVC-X64-O0-NEXT: pushq %rbx
-; MSVC-X64-O0-NEXT: subq $72, %rsp
-; MSVC-X64-O0-NEXT: leaq {{[0-9]+}}(%rsp), %rbp
+; MSVC-X64-O0-NEXT: subq $104, %rsp
+; MSVC-X64-O0-NEXT: leaq 96(%rsp), %rbp
; MSVC-X64-O0-NEXT: andq $-32, %rsp
; MSVC-X64-O0-NEXT: movq %rsp, %rbx
; MSVC-X64-O0-NEXT: movq __security_cookie(%rip), %rax
; MSVC-X64-O0-NEXT: xorq %rbp, %rax
-; MSVC-X64-O0-NEXT: movq %rax, 64(%rbx)
+; MSVC-X64-O0-NEXT: movq %rax, 96(%rbx)
; MSVC-X64-O0-NEXT: movl %ecx, %eax
; MSVC-X64-O0-NEXT: # kill: def $rax killed $eax
-; MSVC-X64-O0-NEXT: leaq 15(,%rax,4), %rax
+; MSVC-X64-O0-NEXT: shlq $2, %rax
+; MSVC-X64-O0-NEXT: movabsq $15, %rcx
+; MSVC-X64-O0-NEXT: addq %rcx, %rax
; MSVC-X64-O0-NEXT: andq $-16, %rax
; MSVC-X64-O0-NEXT: callq __chkstk
; MSVC-X64-O0-NEXT: subq %rax, %rsp
-; MSVC-X64-O0-NEXT: movq %rsp, %rax
-; MSVC-X64-O0-NEXT: movq %rax, 24(%rbx) # 8-byte Spill
-; MSVC-X64-O0-NEXT: leaq 32(%rbx), %rcx
-; MSVC-X64-O0-NEXT: subq $32, %rsp
+; MSVC-X64-O0-NEXT: leaq 32(%rsp), %rax
+; MSVC-X64-O0-NEXT: movq %rax, 56(%rbx) # 8-byte Spill
+; MSVC-X64-O0-NEXT: leaq 64(%rbx), %rcx
; MSVC-X64-O0-NEXT: callq escape
-; MSVC-X64-O0-NEXT: movq 24(%rbx), %rcx # 8-byte Reload
+; MSVC-X64-O0-NEXT: movq 56(%rbx), %rcx # 8-byte Reload
; MSVC-X64-O0-NEXT: callq escape
-; MSVC-X64-O0-NEXT: addq $32, %rsp
-; MSVC-X64-O0-NEXT: movq 64(%rbx), %rcx
+; MSVC-X64-O0-NEXT: movq 96(%rbx), %rcx
; MSVC-X64-O0-NEXT: xorq %rbp, %rcx
; MSVC-X64-O0-NEXT: movq __security_cookie(%rip), %rax
; MSVC-X64-O0-NEXT: subq %rcx, %rax
; MSVC-X64-O0-NEXT: jne .LBB2_2
; MSVC-X64-O0-NEXT: jmp .LBB2_1
; MSVC-X64-O0-NEXT: .LBB2_2:
-; MSVC-X64-O0-NEXT: movq 64(%rbx), %rcx
+; MSVC-X64-O0-NEXT: movq 96(%rbx), %rcx
; MSVC-X64-O0-NEXT: xorq %rbp, %rcx
-; MSVC-X64-O0-NEXT: subq $32, %rsp
; MSVC-X64-O0-NEXT: callq __security_check_cookie
; MSVC-X64-O0-NEXT: .LBB2_1:
; MSVC-X64-O0-NEXT: leaq 8(%rbp), %rsp
@@ -450,4 +446,3 @@ define void @test_vla_realign(i32 %n) nounwind ssp {
declare ptr @strcpy(ptr, ptr) nounwind
declare i32 @printf(ptr, ...) nounwind
-
diff --git a/llvm/test/CodeGen/X86/win64_alloca_dynalloca.ll b/llvm/test/CodeGen/X86/win64_alloca_dynalloca.ll
index 241188b8cc3d5..36b58a6d2573a 100644
--- a/llvm/test/CodeGen/X86/win64_alloca_dynalloca.ll
+++ b/llvm/test/CodeGen/X86/win64_alloca_dynalloca.ll
@@ -20,13 +20,13 @@ entry:
; M64: leaq 128(%rsp), %rbp
; __chkstk does not adjust %rsp.
-; W64: $4096, %eax
+; W64: $4144, %eax
; W64: callq __chkstk
; W64: subq %rax, %rsp
; W64: leaq 128(%rsp), %rbp
; Use %r11 for the large model.
-; L64: $4096, %eax
+; L64: $4144, %eax
; L64: movabsq $__chkstk, %r11
; L64: callq *%r11
; L64: subq %rax, %rsp
@@ -43,18 +43,20 @@ entry:
; M64: subq %rax, %rsp
; M64: movq %rsp, %rax
-; W64: leaq 15(%{{.*}}), %rax
+; W64: movabsq $15, %rax
+; W64: addq %rcx, %rax
; W64: andq $-16, %rax
; W64: callq __chkstk
; W64: subq %rax, %rsp
-; W64: movq %rsp, %rax
+; W64: leaq 48(%rsp), %rax
-; L64: leaq 15(%{{.*}}), %rax
+; L64: movabsq $15, %rax
+; L64: addq %rcx, %rax
; L64: andq $-16, %rax
; L64: movabsq $__chkstk, %r11
; L64: callq *%r11
; L64: subq %rax, %rsp
-; L64: movq %rsp, %rax
+; L64: leaq 48(%rsp), %rax
; EFI: leaq 15(%{{.*}}), [[R1:%r.*]]
; EFI: andq $-16, [[R1]]
@@ -69,9 +71,8 @@ entry:
; M64: leaq -128(%rbp), %r9
; M64: callq bar
-; W64: subq $48, %rsp
; W64: movq %rax, 32(%rsp)
-; W64: leaq -128(%rbp), %r9
+; W64: leaq -80(%rbp), %r9
; W64: callq bar
; EFI: subq $48, %rsp
@@ -83,11 +84,11 @@ entry:
; M64: leaq 3968(%rbp), %rsp
-; W64: leaq 3968(%rbp), %rsp
+; W64: leaq 4016(%rbp), %rsp
}
-define i64 @aligned(i64 %n, i64 %x) nounwind {
+define i64 @aligned(i64 %n, i64 %x, ptr %dummy) nounwind {
; M64-LABEL: aligned:
; W64-LABEL: aligned:
; EFI-LABEL: aligned:
@@ -103,13 +104,13 @@ entry:
; M64: andq $-128, [[R2]]
; M64: movq [[R2]], %rsp
-; W64: leaq 15(%{{.*}}), %rax
+; W64: movabsq $142, %rax
+; W64: addq %rcx, %rax
; W64: andq $-16, %rax
; W64: callq __chkstk
; W64: subq %rax, %rsp
-; W64: movq %rsp, [[R2:%r.*]]
+; W64: leaq 175(%rsp), [[R2:%r.*]]
; W64: andq $-128, [[R2]]
-; W64: movq [[R2]], %rsp
; EFI: leaq 15(%{{.*}}), [[R1:%r.*]]
; EFI: andq $-16, [[R1]]
@@ -118,13 +119,12 @@ entry:
; EFI: andq $-128, [[R64]]
; EFI: movq [[R64]], %rsp
- %r = call i64 @bar(i64 %n, i64 %x, i64 %n, ptr undef, ptr %buf1) nounwind
+ %r = call i64 @bar(i64 %n, i64 %x, i64 %n, ptr %dummy, ptr %buf1) nounwind
; M64: subq $48, %rsp
; M64: movq [[R2]], 32(%rsp)
; M64: callq bar
-; W64: subq $48, %rsp
; W64: movq [[R2]], 32(%rsp)
; W64: callq bar
@@ -135,4 +135,85 @@ entry:
ret i64 %r
}
+define void @two_allocas(i64 %a, i64 %b) nounwind {
+; W64-LABEL: two_allocas:
+; W64: movabsq $15, %rax
+; W64-NEXT: addq %rcx, %rax
+; W64-NEXT: andq $-16, %rax
+; W64-NEXT: callq __chkstk
+; W64-NEXT: subq %rax, %rsp
+; W64-NEXT: leaq 32(%rsp), [[P:%r[a-z0-9]+]]
+; W64: movq [[P]], %rcx
+; W64-NEXT: callq use
+; W64: movabsq $15, %rax
+; W64-NEXT: addq %rsi, %rax
+; W64-NEXT: andq $-16, %rax
+; W64-NEXT: callq __chkstk
+; W64-NEXT: subq %rax, %rsp
+; W64-NEXT: leaq 32(%rsp), [[Q:%r[a-z0-9]+]]
+; W64: movq [[P]], %rcx
+; W64-NEXT: callq use
+; W64-NEXT: movq [[Q]], %rcx
+; W64-NEXT: callq use
+entry:
+ %p = alloca i8, i64 %a, align 1
+ call void @use(ptr %p)
+ %q = alloca i8, i64 %b, align 1
+ call void @use(ptr %p)
+ call void @use(ptr %q)
+ ret void
+}
+
+define void @two_allocas_aligned(i64 %a, i64 %b) nounwind {
+; W64-LABEL: two_allocas_aligned:
+; W64: movabsq $142, %rax
+; W64-NEXT: addq %rcx, %rax
+; W64-NEXT: andq $-16, %rax
+; W64-NEXT: callq __chkstk
+; W64-NEXT: subq %rax, %rsp
+; W64-NEXT: leaq 159(%rsp), [[P:%r[a-z0-9]+]]
+; W64-NEXT: andq $-128, [[P]]
+; W64: movabsq $15, %rax
+; W64-NEXT: addq %rdx, %rax
+; W64-NEXT: andq $-16, %rax
+; W64-NEXT: callq __chkstk
+; W64-NEXT: subq %rax, %rsp
+; W64-NEXT: leaq 32(%rsp), [[Q:%r[a-z0-9]+]]
+; W64: movq [[P]], %rcx
+; W64-NEXT: callq use
+; W64-NEXT: movq [[Q]], %rcx
+; W64-NEXT: callq use
+; W64-NEXT: movq [[P]], %rcx
+; W64-NEXT: callq use
+entry:
+ %p = alloca i8, i64 %a, align 128
+ %q = alloca i8, i64 %b, align 1
+ call void @use(ptr %p)
+ call void @use(ptr %q)
+ call void @use(ptr %p)
+ ret void
+}
+
+define i64 @aligned_stack_args(i64 %n, i64 %x, ptr %dummy) nounwind {
+; W64-LABEL: aligned_stack_args:
+; W64: movabsq $78, %rax
+; W64-NEXT: addq %rcx, %rax
+; W64-NEXT: andq $-16, %rax
+; W64-NEXT: callq __chkstk
+; W64-NEXT: subq %rax, %rsp
+; W64-NEXT: leaq 111(%rsp), [[P:%r[a-z0-9]+]]
+; W64-NEXT: andq $-64, [[P]]
+; W64: movq [[P]], 40(%rsp)
+; W64-NEXT: movq [[P]], 32(%rsp)
+; W64-NOT: subq
+; W64-NOT: addq
+; W64: callq baz
+entry:
+ %p = alloca i8, i64 %n, align 64
+ %r = call i64 @baz(i64 %n, i64 %x, i64 %n, ptr %dummy, ptr %p, ptr %p) nounwind
+ ret i64 %r
+}
+
declare i64 @bar(i64, i64, i64, ptr nocapture, ptr nocapture) nounwind
+declare i64 @baz(i64, i64, i64, ptr nocapture, ptr nocapture, ptr nocapture) nounwind
+declare void @use(ptr) nounwind
diff --git a/llvm/test/CodeGen/X86/win64_frame.ll b/llvm/test/CodeGen/X86/win64_frame.ll
index c4b36c5e263c8..5f8450a69ae77 100644
--- a/llvm/test/CodeGen/X86/win64_frame.ll
+++ b/llvm/test/CodeGen/X86/win64_frame.ll
@@ -1,8 +1,8 @@
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
-; RUN: llc < %s -mtriple=x86_64-pc-win32 | FileCheck %s
-; RUN: llc < %s -mtriple=x86_64-pc-win32 -mattr=+sahf | FileCheck %s
-; RUN: llc < %s -mtriple=x86_64-uefi | FileCheck %s
-; RUN: llc < %s -mtriple=x86_64-uefi -mattr=+sahf | FileCheck %s
+; RUN: llc < %s -mtriple=x86_64-pc-win32 | FileCheck %s --check-prefixes=CHECK,WIN32
+; RUN: llc < %s -mtriple=x86_64-pc-win32 -mattr=+sahf | FileCheck %s --check-prefixes=CHECK,WIN32
+; RUN: llc < %s -mtriple=x86_64-uefi | FileCheck %s --check-prefixes=CHECK,EFI
+; RUN: llc < %s -mtriple=x86_64-uefi -mattr=+sahf | FileCheck %s --check-prefixes=CHECK,EFI
define i32 @f1(i32 %p1, i32 %p2, i32 %p3, i32 %p4, i32 %p5) "frame-pointer"="all" {
; CHECK-LABEL: f1:
@@ -161,39 +161,73 @@ define i32 @f7(i32 %a, i32 %b, i32 %c, i32 %d, i32 %e) "frame-pointer"="all" {
define i32 @f8(i32 %a, i32 %b, i32 %c, i32 %d, i32 %e) "frame-pointer"="all" {
; CHECK-LABEL: f8:
-; CHECK: # %bb.0:
-; CHECK-NEXT: pushq %rbp
-; CHECK-NEXT: .seh_pushreg %rbp
-; CHECK-NEXT: pushq %rsi
-; CHECK-NEXT: .seh_pushreg %rsi
-; CHECK-NEXT: pushq %rbx
-; CHECK-NEXT: .seh_pushreg %rbx
-; CHECK-NEXT: subq $352, %rsp # imm = 0x160
-; CHECK-NEXT: .seh_stackalloc 352
-; CHECK-NEXT: leaq {{[0-9]+}}(%rsp), %rbp
-; CHECK-NEXT: .seh_setframe %rbp, 128
-; CHECK-NEXT: .seh_endprologue
-; CHECK-NEXT: andq $-64, %rsp
-; CHECK-NEXT: movq %rsp, %rbx
-; CHECK-NEXT: movl 288(%rbp), %esi
-; CHECK-NEXT: movl %ecx, %eax
-; CHECK-NEXT: leaq 15(,%rax,4), %rax
-; CHECK-NEXT: andq $-16, %rax
-; CHECK-NEXT: callq __chkstk
-; CHECK-NEXT: subq %rax, %rsp
-; CHECK-NEXT: subq $32, %rsp
-; CHECK-NEXT: movq %rbx, %rcx
-; CHECK-NEXT: callq external
-; CHECK-NEXT: addq $32, %rsp
-; CHECK-NEXT: movl %esi, %eax
-; CHECK-NEXT: .seh_startepilogue
-; CHECK-NEXT: leaq 224(%rbp), %rsp
-; CHECK-NEXT: popq %rbx
-; CHECK-NEXT: popq %rsi
-; CHECK-NEXT: popq %rbp
-; CHECK-NEXT: .seh_endepilogue
-; CHECK-NEXT: retq
-; CHECK-NEXT: .seh_endproc
+; WIN32: # %bb.0:
+; WIN32-NEXT: pushq %rbp
+; WIN32-NEXT: .seh_pushreg %rbp
+; WIN32-NEXT: pushq %rsi
+; WIN32-NEXT: .seh_pushreg %rsi
+; WIN32-NEXT: pushq %rbx
+; WIN32-NEXT: .seh_pushreg %rbx
+; WIN32-NEXT: subq $416, %rsp # imm = 0x1A0
+; WIN32-NEXT: .seh_stackalloc 416
+; WIN32-NEXT: leaq {{[0-9]+}}(%rsp), %rbp
+; WIN32-NEXT: .seh_setframe %rbp, 128
+; WIN32-NEXT: .seh_endprologue
+; WIN32-NEXT: andq $-64, %rsp
+; WIN32-NEXT: movq %rsp, %rbx
+; WIN32-NEXT: movl 352(%rbp), %esi
+; WIN32-NEXT: movl %ecx, %ecx
+; WIN32-NEXT: shlq $2, %rcx
+; WIN32-NEXT: movabsq $15, %rax
+; WIN32-NEXT: addq %rcx, %rax
+; WIN32-NEXT: andq $-16, %rax
+; WIN32-NEXT: callq __chkstk
+; WIN32-NEXT: subq %rax, %rsp
+; WIN32-NEXT: leaq 32(%rsp), %rax
+; WIN32-NEXT: leaq 64(%rbx), %rcx
+; WIN32-NEXT: callq external
+; WIN32-NEXT: movl %esi, %eax
+; WIN32-NEXT: .seh_startepilogue
+; WIN32-NEXT: leaq 288(%rbp), %rsp
+; WIN32-NEXT: popq %rbx
+; WIN32-NEXT: popq %rsi
+; WIN32-NEXT: popq %rbp
+; WIN32-NEXT: .seh_endepilogue
+; WIN32-NEXT: retq
+; WIN32-NEXT: .seh_endproc
+; EFI: # %bb.0:
+; EFI-NEXT: pushq %rbp
+; EFI-NEXT: .seh_pushreg %rbp
+; EFI-NEXT: pushq %rsi
+; EFI-NEXT: .seh_pushreg %rsi
+; EFI-NEXT: pushq %rbx
+; EFI-NEXT: .seh_pushreg %rbx
+; EFI-NEXT: subq $352, %rsp # imm = 0x160
+; EFI-NEXT: .seh_stackalloc 352
+; EFI-NEXT: leaq {{[0-9]+}}(%rsp), %rbp
+; EFI-NEXT: .seh_setframe %rbp, 128
+; EFI-NEXT: .seh_endprologue
+; EFI-NEXT: andq $-64, %rsp
+; EFI-NEXT: movq %rsp, %rbx
+; EFI-NEXT: movl 288(%rbp), %esi
+; EFI-NEXT: movl %ecx, %eax
+; EFI-NEXT: leaq 15(,%rax,4), %rax
+; EFI-NEXT: andq $-16, %rax
+; EFI-NEXT: callq __chkstk
+; EFI-NEXT: subq %rax, %rsp
+; EFI-NEXT: subq $32, %rsp
+; EFI-NEXT: movq %rbx, %rcx
+; EFI-NEXT: callq external
+; EFI-NEXT: addq $32, %rsp
+; EFI-NEXT: movl %esi, %eax
+; EFI-NEXT: .seh_startepilogue
+; EFI-NEXT: leaq 224(%rbp), %rsp
+; EFI-NEXT: popq %rbx
+; EFI-NEXT: popq %rsi
+; EFI-NEXT: popq %rbp
+; EFI-NEXT: .seh_endepilogue
+; EFI-NEXT: retq
+; EFI-NEXT: .seh_endproc
%alloca = alloca [300 x i8], align 64
alloca i32, i32 %a
call void @external(ptr %alloca)
diff --git a/llvm/test/DebugInfo/X86/instr-ref-dyn-alloca.ll b/llvm/test/DebugInfo/X86/instr-ref-dyn-alloca.ll
index 5af743caee433..2234f3349630e 100644
--- a/llvm/test/DebugInfo/X86/instr-ref-dyn-alloca.ll
+++ b/llvm/test/DebugInfo/X86/instr-ref-dyn-alloca.ll
@@ -4,13 +4,14 @@
;; Copy of instr-ref-dyn-alloca-win32.ll, targetting 64 bit Windows. Here,
;; _chkstk doesn't return with a modified stack pointer, instead we have to
-;; edit it with our own subtract operation. Check that it's labelled and the
-;; substitution is correct. This also covers the code paths for non-Windows on
-;; x86.
+;; edit it with our own subtract operation. Check that the lowered stack
+;; pointer copy is what the DBG_INSTR_REF points at. This also covers the code
+;; paths for non-Windows on x86.
-; DYN_LOWERED: debugValueSubstitutions:
-; DYN_LOWERED-NEXT: - { srcinst: 1, srcop: 2, dstinst: 2, dstop: 0, subreg: 0 }
-; DYN_LOWERED: SUB64rr $rsp, killed $rax, {{.*}} debug-instr-number 2,
+; DYN_LOWERED: debugValueSubstitutions: []
+; DYN_LOWERED: $rsp = SUB64rr $rsp, killed $rax, {{.*}}
+; DYN_LOWERED-NEXT: %{{[0-9]+}}:gr64 = COPY $rsp, debug-location !41
+; DYN_LOWERED-NEXT: DBG_INSTR_REF !42, !DIExpression(DW_OP_LLVM_arg, 0, DW_OP_deref, DW_OP_deref), dbg-instr-ref(1, 0), debug-location !46
source_filename = "test/DebugInfo/COFF/types-array-advanced.ll"
target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
>From 903c4f30440bcef67c6cb534bda14d4f0dfa941a Mon Sep 17 00:00:00 2001
From: taigacon <taigacon at gmail.com>
Date: Tue, 5 May 2026 09:17:28 +0800
Subject: [PATCH 2/4] fixup! [X86][WinEH] Avoid stale RSP after Win64 dynalloca
invokes (#191616)
---
llvm/lib/Target/X86/X86MachineFunctionInfo.cpp | 6 ++++--
llvm/lib/Target/X86/X86MachineFunctionInfo.h | 3 +++
.../X86/win64-msvc-dynalloca-call-frame-size.mir | 14 ++++++++++++++
3 files changed, 21 insertions(+), 2 deletions(-)
create mode 100644 llvm/test/CodeGen/MIR/X86/win64-msvc-dynalloca-call-frame-size.mir
diff --git a/llvm/lib/Target/X86/X86MachineFunctionInfo.cpp b/llvm/lib/Target/X86/X86MachineFunctionInfo.cpp
index 7b57f7c23bf4d..2bb752a650768 100644
--- a/llvm/lib/Target/X86/X86MachineFunctionInfo.cpp
+++ b/llvm/lib/Target/X86/X86MachineFunctionInfo.cpp
@@ -15,7 +15,9 @@ using namespace llvm;
yaml::X86MachineFunctionInfo::X86MachineFunctionInfo(
const llvm::X86MachineFunctionInfo &MFI)
- : AMXProgModel(MFI.getAMXProgModel()) {}
+ : AMXProgModel(MFI.getAMXProgModel()),
+ Win64MSVCDynAllocaCallFrameSize(
+ MFI.getWin64MSVCDynAllocaCallFrameSize()) {}
void yaml::X86MachineFunctionInfo::mappingImpl(yaml::IO &YamlIO) {
MappingTraits<X86MachineFunctionInfo>::mapping(YamlIO, *this);
@@ -31,6 +33,7 @@ MachineFunctionInfo *X86MachineFunctionInfo::clone(
void X86MachineFunctionInfo::initializeBaseYamlFields(
const yaml::X86MachineFunctionInfo &YamlMFI) {
AMXProgModel = YamlMFI.AMXProgModel;
+ setWin64MSVCDynAllocaCallFrameSize(YamlMFI.Win64MSVCDynAllocaCallFrameSize);
}
void X86MachineFunctionInfo::anchor() { }
@@ -47,4 +50,3 @@ void X86MachineFunctionInfo::setRestoreBasePointer(const MachineFunction *MF) {
}
}
}
-
diff --git a/llvm/lib/Target/X86/X86MachineFunctionInfo.h b/llvm/lib/Target/X86/X86MachineFunctionInfo.h
index 5d0be0b436555..e5964cb5bd59e 100644
--- a/llvm/lib/Target/X86/X86MachineFunctionInfo.h
+++ b/llvm/lib/Target/X86/X86MachineFunctionInfo.h
@@ -38,6 +38,7 @@ template <> struct ScalarEnumerationTraits<AMXProgModelEnum> {
struct X86MachineFunctionInfo final : public yaml::MachineFunctionInfo {
AMXProgModelEnum AMXProgModel;
+ unsigned Win64MSVCDynAllocaCallFrameSize = 0;
X86MachineFunctionInfo() = default;
X86MachineFunctionInfo(const llvm::X86MachineFunctionInfo &MFI);
@@ -49,6 +50,8 @@ struct X86MachineFunctionInfo final : public yaml::MachineFunctionInfo {
template <> struct MappingTraits<X86MachineFunctionInfo> {
static void mapping(IO &YamlIO, X86MachineFunctionInfo &MFI) {
YamlIO.mapOptional("amxProgModel", MFI.AMXProgModel);
+ YamlIO.mapOptional("win64MSVCDynAllocaCallFrameSize",
+ MFI.Win64MSVCDynAllocaCallFrameSize, 0u);
}
};
} // end namespace yaml
diff --git a/llvm/test/CodeGen/MIR/X86/win64-msvc-dynalloca-call-frame-size.mir b/llvm/test/CodeGen/MIR/X86/win64-msvc-dynalloca-call-frame-size.mir
new file mode 100644
index 0000000000000..4bfdbb3c2ed81
--- /dev/null
+++ b/llvm/test/CodeGen/MIR/X86/win64-msvc-dynalloca-call-frame-size.mir
@@ -0,0 +1,14 @@
+# RUN: llc -mtriple=x86_64-pc-windows-msvc -run-pass=none -o - %s | FileCheck %s
+
+---
+# CHECK-LABEL: name: test
+# CHECK: machineFunctionInfo:
+# CHECK-NEXT: amxProgModel: None
+# CHECK-NEXT: win64MSVCDynAllocaCallFrameSize: 32
+name: test
+machineFunctionInfo:
+ win64MSVCDynAllocaCallFrameSize: 32
+body: |
+ bb.0:
+ RET 0
+...
>From d4274864795d26ab1a7cde0321bbcba9ec6a6b0e Mon Sep 17 00:00:00 2001
From: taigacon <taigacon at gmail.com>
Date: Tue, 16 Jun 2026 16:32:24 +0800
Subject: [PATCH 3/4] fixup! [X86][WinEH] Avoid stale RSP after Win64 dynalloca
invokes (#191616)
---
llvm/lib/Target/X86/X86DynAllocaExpander.cpp | 23 ++++++++-----------
llvm/lib/Target/X86/X86FrameLowering.cpp | 21 ++++++++++-------
llvm/lib/Target/X86/X86FrameLowering.h | 2 ++
.../lib/Target/X86/X86MachineFunctionInfo.cpp | 5 +---
llvm/lib/Target/X86/X86MachineFunctionInfo.h | 16 -------------
.../win64-msvc-dynalloca-call-frame-size.mir | 14 -----------
6 files changed, 26 insertions(+), 55 deletions(-)
delete mode 100644 llvm/test/CodeGen/MIR/X86/win64-msvc-dynalloca-call-frame-size.mir
diff --git a/llvm/lib/Target/X86/X86DynAllocaExpander.cpp b/llvm/lib/Target/X86/X86DynAllocaExpander.cpp
index 6693271d0f834..012c3cce12ade 100644
--- a/llvm/lib/Target/X86/X86DynAllocaExpander.cpp
+++ b/llvm/lib/Target/X86/X86DynAllocaExpander.cpp
@@ -15,6 +15,7 @@
//===----------------------------------------------------------------------===//
#include "X86.h"
+#include "X86FrameLowering.h"
#include "X86InstrBuilder.h"
#include "X86InstrInfo.h"
#include "X86MachineFunctionInfo.h"
@@ -194,7 +195,7 @@ void X86DynAllocaExpander::computeLowerings(MachineFunction &MF,
// Compute the reverse post-order.
ReversePostOrderTraversal<MachineFunction*> RPO(&MF);
bool HasStableWin64MSVCCallFrame =
- MF.getInfo<X86MachineFunctionInfo>()->hasWin64MSVCDynAllocaCallFrame();
+ STI->getFrameLowering()->getWin64MSVCDynAllocaCallFrameSize(MF) != 0;
for (MachineBasicBlock *MBB : RPO) {
int64_t Offset = -1;
@@ -280,10 +281,9 @@ Register X86DynAllocaExpander::materializeWinAllocaAmount(
void X86DynAllocaExpander::lower(MachineInstr *MI, Lowering L) {
const DebugLoc &DL = MI->getDebugLoc();
MachineBasicBlock *MBB = MI->getParent();
+ MachineFunction &MF = *MBB->getParent();
unsigned Win64MSVCDynAllocaCallFrameSize =
- MBB->getParent()
- ->getInfo<X86MachineFunctionInfo>()
- ->getWin64MSVCDynAllocaCallFrameSize();
+ STI->getFrameLowering()->getWin64MSVCDynAllocaCallFrameSize(MF);
MachineBasicBlock::iterator I = *MI;
bool IsWinAlloca = MI->getOpcode() == X86::WIN_ALLOCA_64;
@@ -402,7 +402,8 @@ void X86DynAllocaExpander::lower(MachineInstr *MI, Lowering L) {
}
bool X86DynAllocaExpander::run(MachineFunction &MF) {
- if (!MF.getInfo<X86MachineFunctionInfo>()->hasDynAlloca())
+ auto *X86FI = MF.getInfo<X86MachineFunctionInfo>();
+ if (!X86FI->hasDynAlloca())
return false;
MRI = &MF.getRegInfo();
@@ -413,21 +414,17 @@ bool X86DynAllocaExpander::run(MachineFunction &MF) {
SlotSize = TRI->getSlotSize();
StackProbeSize = STI->getTargetLowering()->getStackProbeSize(MF);
NoStackArgProbe = MF.getFunction().hasFnAttribute("no-stack-arg-probe");
- auto *X86FI = MF.getInfo<X86MachineFunctionInfo>();
auto &MFI = MF.getFrameInfo();
- unsigned Win64MSVCDynAllocaCallFrameSize = 0;
if (STI->isTargetWin64() && STI->isTargetWindowsMSVC()) {
MFI.computeMaxCallFrameSize(MF);
- Align StackAlign = STI->getFrameLowering()->getStackAlign();
- Win64MSVCDynAllocaCallFrameSize =
- static_cast<unsigned>(alignTo(MFI.getMaxCallFrameSize(), StackAlign));
- assert(Win64MSVCDynAllocaCallFrameSize == 0 ||
+ assert(STI->getFrameLowering()->getWin64MSVCDynAllocaCallFrameSize(MF) ==
+ 0 ||
!X86FI->getHasPushSequences());
- assert(Win64MSVCDynAllocaCallFrameSize == 0 ||
+ assert(STI->getFrameLowering()->getWin64MSVCDynAllocaCallFrameSize(MF) ==
+ 0 ||
!X86FI->hasPreallocatedCall());
}
- X86FI->setWin64MSVCDynAllocaCallFrameSize(Win64MSVCDynAllocaCallFrameSize);
if (NoStackArgProbe)
StackProbeSize = INT64_MAX;
diff --git a/llvm/lib/Target/X86/X86FrameLowering.cpp b/llvm/lib/Target/X86/X86FrameLowering.cpp
index 0beef2def09f1..4821092b5a75c 100644
--- a/llvm/lib/Target/X86/X86FrameLowering.cpp
+++ b/llvm/lib/Target/X86/X86FrameLowering.cpp
@@ -62,15 +62,10 @@ static bool hasConstantSP(const MachineFunction &MF) {
static bool hasWin64MSVCDynAllocaCallFrame(const MachineFunction &MF) {
const auto &STI = MF.getSubtarget<X86Subtarget>();
- if (!STI.isTargetWin64() || !STI.isTargetWindowsMSVC())
+ if (STI.getFrameLowering()->getWin64MSVCDynAllocaCallFrameSize(MF) == 0)
return false;
-
- const auto *X86FI = MF.getInfo<X86MachineFunctionInfo>();
- if (!X86FI->hasWin64MSVCDynAllocaCallFrame())
- return false;
-
- assert(!X86FI->getHasPushSequences());
- assert(!X86FI->hasPreallocatedCall());
+ assert(!MF.getInfo<X86MachineFunctionInfo>()->getHasPushSequences());
+ assert(!MF.getInfo<X86MachineFunctionInfo>()->hasPreallocatedCall());
return true;
}
@@ -118,6 +113,16 @@ bool X86FrameLowering::needsFrameIndexResolution(
MF.getInfo<X86MachineFunctionInfo>()->getHasPushSequences();
}
+unsigned X86FrameLowering::getWin64MSVCDynAllocaCallFrameSize(
+ const MachineFunction &MF) const {
+ if (!STI.isTargetWin64() || !STI.isTargetWindowsMSVC())
+ return 0;
+ if (!MF.getInfo<X86MachineFunctionInfo>()->hasDynAlloca())
+ return 0;
+ return static_cast<unsigned>(
+ alignTo(MF.getFrameInfo().getMaxCallFrameSize(), getStackAlign()));
+}
+
/// hasFPImpl - Return true if the specified function should have a dedicated
/// frame pointer register. This is true if the function has variable sized
/// allocas or if frame pointer elimination is disabled.
diff --git a/llvm/lib/Target/X86/X86FrameLowering.h b/llvm/lib/Target/X86/X86FrameLowering.h
index f1e3796f5fddd..0798e32eedd1b 100644
--- a/llvm/lib/Target/X86/X86FrameLowering.h
+++ b/llvm/lib/Target/X86/X86FrameLowering.h
@@ -109,6 +109,8 @@ class X86FrameLowering : public TargetFrameLowering {
bool canSimplifyCallFramePseudos(const MachineFunction &MF) const override;
bool needsFrameIndexResolution(const MachineFunction &MF) const override;
+ unsigned getWin64MSVCDynAllocaCallFrameSize(const MachineFunction &MF) const;
+
StackOffset getFrameIndexReference(const MachineFunction &MF, int FI,
Register &FrameReg) const override;
diff --git a/llvm/lib/Target/X86/X86MachineFunctionInfo.cpp b/llvm/lib/Target/X86/X86MachineFunctionInfo.cpp
index 2bb752a650768..276e5ee426da8 100644
--- a/llvm/lib/Target/X86/X86MachineFunctionInfo.cpp
+++ b/llvm/lib/Target/X86/X86MachineFunctionInfo.cpp
@@ -15,9 +15,7 @@ using namespace llvm;
yaml::X86MachineFunctionInfo::X86MachineFunctionInfo(
const llvm::X86MachineFunctionInfo &MFI)
- : AMXProgModel(MFI.getAMXProgModel()),
- Win64MSVCDynAllocaCallFrameSize(
- MFI.getWin64MSVCDynAllocaCallFrameSize()) {}
+ : AMXProgModel(MFI.getAMXProgModel()) {}
void yaml::X86MachineFunctionInfo::mappingImpl(yaml::IO &YamlIO) {
MappingTraits<X86MachineFunctionInfo>::mapping(YamlIO, *this);
@@ -33,7 +31,6 @@ MachineFunctionInfo *X86MachineFunctionInfo::clone(
void X86MachineFunctionInfo::initializeBaseYamlFields(
const yaml::X86MachineFunctionInfo &YamlMFI) {
AMXProgModel = YamlMFI.AMXProgModel;
- setWin64MSVCDynAllocaCallFrameSize(YamlMFI.Win64MSVCDynAllocaCallFrameSize);
}
void X86MachineFunctionInfo::anchor() { }
diff --git a/llvm/lib/Target/X86/X86MachineFunctionInfo.h b/llvm/lib/Target/X86/X86MachineFunctionInfo.h
index e5964cb5bd59e..1cfe86d57071f 100644
--- a/llvm/lib/Target/X86/X86MachineFunctionInfo.h
+++ b/llvm/lib/Target/X86/X86MachineFunctionInfo.h
@@ -38,7 +38,6 @@ template <> struct ScalarEnumerationTraits<AMXProgModelEnum> {
struct X86MachineFunctionInfo final : public yaml::MachineFunctionInfo {
AMXProgModelEnum AMXProgModel;
- unsigned Win64MSVCDynAllocaCallFrameSize = 0;
X86MachineFunctionInfo() = default;
X86MachineFunctionInfo(const llvm::X86MachineFunctionInfo &MFI);
@@ -50,8 +49,6 @@ struct X86MachineFunctionInfo final : public yaml::MachineFunctionInfo {
template <> struct MappingTraits<X86MachineFunctionInfo> {
static void mapping(IO &YamlIO, X86MachineFunctionInfo &MFI) {
YamlIO.mapOptional("amxProgModel", MFI.AMXProgModel);
- YamlIO.mapOptional("win64MSVCDynAllocaCallFrameSize",
- MFI.Win64MSVCDynAllocaCallFrameSize, 0u);
}
};
} // end namespace yaml
@@ -119,9 +116,6 @@ class X86MachineFunctionInfo : public MachineFunctionInfo {
unsigned ArgumentStackSize = 0;
/// NumLocalDynamics - Number of local-dynamic TLS accesses.
unsigned NumLocalDynamics = 0;
- /// On x86_64-windows-msvc dynalloca functions, stores the rounded stable
- /// outgoing call-frame size inferred from ADJCALLSTACKDOWN64/UP64 pseudos.
- unsigned Win64MSVCDynAllocaCallFrameSize = 0;
/// HasPushSequences - Keeps track of whether this function uses sequences
/// of pushes to pass function parameters.
bool HasPushSequences = false;
@@ -282,16 +276,6 @@ class X86MachineFunctionInfo : public MachineFunctionInfo {
bool hasPreallocatedCall() const { return HasPreallocatedCall; }
void setHasPreallocatedCall(bool v) { HasPreallocatedCall = v; }
- bool hasWin64MSVCDynAllocaCallFrame() const {
- return Win64MSVCDynAllocaCallFrameSize != 0;
- }
- unsigned getWin64MSVCDynAllocaCallFrameSize() const {
- return Win64MSVCDynAllocaCallFrameSize;
- }
- void setWin64MSVCDynAllocaCallFrameSize(unsigned Size) {
- Win64MSVCDynAllocaCallFrameSize = Size;
- }
-
bool hasSwiftAsyncContext() const { return HasSwiftAsyncContext; }
void setHasSwiftAsyncContext(bool v) { HasSwiftAsyncContext = v; }
diff --git a/llvm/test/CodeGen/MIR/X86/win64-msvc-dynalloca-call-frame-size.mir b/llvm/test/CodeGen/MIR/X86/win64-msvc-dynalloca-call-frame-size.mir
deleted file mode 100644
index 4bfdbb3c2ed81..0000000000000
--- a/llvm/test/CodeGen/MIR/X86/win64-msvc-dynalloca-call-frame-size.mir
+++ /dev/null
@@ -1,14 +0,0 @@
-# RUN: llc -mtriple=x86_64-pc-windows-msvc -run-pass=none -o - %s | FileCheck %s
-
----
-# CHECK-LABEL: name: test
-# CHECK: machineFunctionInfo:
-# CHECK-NEXT: amxProgModel: None
-# CHECK-NEXT: win64MSVCDynAllocaCallFrameSize: 32
-name: test
-machineFunctionInfo:
- win64MSVCDynAllocaCallFrameSize: 32
-body: |
- bb.0:
- RET 0
-...
>From 3e47609d7409d884fcdd55c849371bcfcdbbcbb8 Mon Sep 17 00:00:00 2001
From: taigacon <taigacon at gmail.com>
Date: Mon, 29 Jun 2026 17:05:04 +0800
Subject: [PATCH 4/4] [X86][WinEH] Use compact immediate moves for Win64
dynalloca addends
Reuse X86::getMOVriOpcode when materializing Win64 dynamic alloca addends so small constants use shorter encodings instead of always forcing MOV64ri.
Update the affected X86 CodeGen checks to expect the compact movl form for small immediate addends.
---
llvm/lib/Target/X86/X86DynAllocaExpander.cpp | 3 ++-
llvm/test/CodeGen/X86/alloca-align-rounding.ll | 2 +-
llvm/test/CodeGen/X86/catchpad-dynamic-alloca.ll | 4 ++--
llvm/test/CodeGen/X86/localescape.ll | 2 +-
llvm/test/CodeGen/X86/stack-protector-msvc.ll | 8 ++++----
llvm/test/CodeGen/X86/win64_alloca_dynalloca.ll | 16 ++++++++--------
llvm/test/CodeGen/X86/win64_frame.ll | 2 +-
7 files changed, 19 insertions(+), 18 deletions(-)
diff --git a/llvm/lib/Target/X86/X86DynAllocaExpander.cpp b/llvm/lib/Target/X86/X86DynAllocaExpander.cpp
index 012c3cce12ade..2785b0a3fe518 100644
--- a/llvm/lib/Target/X86/X86DynAllocaExpander.cpp
+++ b/llvm/lib/Target/X86/X86DynAllocaExpander.cpp
@@ -264,7 +264,8 @@ Register X86DynAllocaExpander::materializeWinAllocaAmount(
uint64_t Addend = AlignmentSlack + RoundUpBias;
Register AddendReg = MRI->createVirtualRegister(&X86::GR64RegClass);
- BuildMI(*MBB, I, DL, TII->get(X86::MOV64ri), AddendReg).addImm(Addend);
+ BuildMI(*MBB, I, DL, TII->get(X86::getMOVriOpcode(true, Addend)), AddendReg)
+ .addImm(Addend);
Register UnalignedAmountReg = MRI->createVirtualRegister(&X86::GR64RegClass);
BuildMI(*MBB, I, DL, TII->get(X86::ADD64rr), UnalignedAmountReg)
diff --git a/llvm/test/CodeGen/X86/alloca-align-rounding.ll b/llvm/test/CodeGen/X86/alloca-align-rounding.ll
index 49efa47227de7..54b4dbe9fb3c5 100644
--- a/llvm/test/CodeGen/X86/alloca-align-rounding.ll
+++ b/llvm/test/CodeGen/X86/alloca-align-rounding.ll
@@ -23,7 +23,7 @@ define void @foo2(i64 %h) {
; CHECK: andq $-32, %rax
; WIN64-LABEL: foo2
; WIN64: andq $-32, %rsp
-; WIN64: movabsq $46, %rax
+; WIN64: movl $46, %eax
; WIN64: addq %rcx, %rax
; WIN64: andq $-16, %rax
; WIN64: callq __chkstk
diff --git a/llvm/test/CodeGen/X86/catchpad-dynamic-alloca.ll b/llvm/test/CodeGen/X86/catchpad-dynamic-alloca.ll
index 46323555a2f32..be2d881e8278d 100644
--- a/llvm/test/CodeGen/X86/catchpad-dynamic-alloca.ll
+++ b/llvm/test/CodeGen/X86/catchpad-dynamic-alloca.ll
@@ -32,7 +32,7 @@ catch.switch:
}
; CHECK-LABEL: test1:
-; CHECK: movabsq $15, %rax
+; CHECK: movl $15, %eax
; CHECK-NEXT: addq %rdx, %rax
; CHECK-NEXT: andq $-16, %rax
; CHECK-NEXT: callq __chkstk
@@ -77,7 +77,7 @@ catch.switch:
}
; CHECK-LABEL: test2:
-; CHECK: movabsq $15, %rax
+; CHECK: movl $15, %eax
; CHECK-NEXT: addq %rdx, %rax
; CHECK-NEXT: andq $-16, %rax
; CHECK-NEXT: callq __chkstk
diff --git a/llvm/test/CodeGen/X86/localescape.ll b/llvm/test/CodeGen/X86/localescape.ll
index 951b2fe09da34..a7b8b0720f67c 100644
--- a/llvm/test/CodeGen/X86/localescape.ll
+++ b/llvm/test/CodeGen/X86/localescape.ll
@@ -82,7 +82,7 @@ define void @alloc_func(i32 %n) {
; X64: movl $42, -4(%rbp)
; X64: movl $13, -12(%rbp)
; X64: movl %ecx, %ecx
-; X64: movabsq $15, %rax
+; X64: movl $15, %eax
; X64: addq %rcx, %rax
; X64: andq $-16, %rax
; X64: callq __chkstk
diff --git a/llvm/test/CodeGen/X86/stack-protector-msvc.ll b/llvm/test/CodeGen/X86/stack-protector-msvc.ll
index c8cfa2085077a..474b489e55ae2 100644
--- a/llvm/test/CodeGen/X86/stack-protector-msvc.ll
+++ b/llvm/test/CodeGen/X86/stack-protector-msvc.ll
@@ -183,7 +183,7 @@ define void @test_vla(i32 %n) nounwind ssp {
; MSVC-X64-NEXT: movq %rax, -8(%rbp)
; MSVC-X64-NEXT: movl %ecx, %ecx
; MSVC-X64-NEXT: shlq $2, %rcx
-; MSVC-X64-NEXT: movabsq $15, %rax
+; MSVC-X64-NEXT: movl $15, %eax
; MSVC-X64-NEXT: addq %rcx, %rax
; MSVC-X64-NEXT: andq $-16, %rax
; MSVC-X64-NEXT: callq __chkstk
@@ -246,7 +246,7 @@ define void @test_vla(i32 %n) nounwind ssp {
; MSVC-X64-O0-NEXT: movl %ecx, %eax
; MSVC-X64-O0-NEXT: # kill: def $rax killed $eax
; MSVC-X64-O0-NEXT: shlq $2, %rax
-; MSVC-X64-O0-NEXT: movabsq $15, %rcx
+; MSVC-X64-O0-NEXT: movl $15, %ecx
; MSVC-X64-O0-NEXT: addq %rcx, %rax
; MSVC-X64-O0-NEXT: andq $-16, %rax
; MSVC-X64-O0-NEXT: callq __chkstk
@@ -330,7 +330,7 @@ define void @test_vla_realign(i32 %n) nounwind ssp {
; MSVC-X64-NEXT: movq %rax, 56(%rbx)
; MSVC-X64-NEXT: movl %ecx, %ecx
; MSVC-X64-NEXT: shlq $2, %rcx
-; MSVC-X64-NEXT: movabsq $15, %rax
+; MSVC-X64-NEXT: movl $15, %eax
; MSVC-X64-NEXT: addq %rcx, %rax
; MSVC-X64-NEXT: andq $-16, %rax
; MSVC-X64-NEXT: callq __chkstk
@@ -410,7 +410,7 @@ define void @test_vla_realign(i32 %n) nounwind ssp {
; MSVC-X64-O0-NEXT: movl %ecx, %eax
; MSVC-X64-O0-NEXT: # kill: def $rax killed $eax
; MSVC-X64-O0-NEXT: shlq $2, %rax
-; MSVC-X64-O0-NEXT: movabsq $15, %rcx
+; MSVC-X64-O0-NEXT: movl $15, %ecx
; MSVC-X64-O0-NEXT: addq %rcx, %rax
; MSVC-X64-O0-NEXT: andq $-16, %rax
; MSVC-X64-O0-NEXT: callq __chkstk
diff --git a/llvm/test/CodeGen/X86/win64_alloca_dynalloca.ll b/llvm/test/CodeGen/X86/win64_alloca_dynalloca.ll
index 36b58a6d2573a..9b08e4760fdc6 100644
--- a/llvm/test/CodeGen/X86/win64_alloca_dynalloca.ll
+++ b/llvm/test/CodeGen/X86/win64_alloca_dynalloca.ll
@@ -43,14 +43,14 @@ entry:
; M64: subq %rax, %rsp
; M64: movq %rsp, %rax
-; W64: movabsq $15, %rax
+; W64: movl $15, %eax
; W64: addq %rcx, %rax
; W64: andq $-16, %rax
; W64: callq __chkstk
; W64: subq %rax, %rsp
; W64: leaq 48(%rsp), %rax
-; L64: movabsq $15, %rax
+; L64: movl $15, %eax
; L64: addq %rcx, %rax
; L64: andq $-16, %rax
; L64: movabsq $__chkstk, %r11
@@ -104,7 +104,7 @@ entry:
; M64: andq $-128, [[R2]]
; M64: movq [[R2]], %rsp
-; W64: movabsq $142, %rax
+; W64: movl $142, %eax
; W64: addq %rcx, %rax
; W64: andq $-16, %rax
; W64: callq __chkstk
@@ -137,7 +137,7 @@ entry:
define void @two_allocas(i64 %a, i64 %b) nounwind {
; W64-LABEL: two_allocas:
-; W64: movabsq $15, %rax
+; W64: movl $15, %eax
; W64-NEXT: addq %rcx, %rax
; W64-NEXT: andq $-16, %rax
; W64-NEXT: callq __chkstk
@@ -145,7 +145,7 @@ define void @two_allocas(i64 %a, i64 %b) nounwind {
; W64-NEXT: leaq 32(%rsp), [[P:%r[a-z0-9]+]]
; W64: movq [[P]], %rcx
; W64-NEXT: callq use
-; W64: movabsq $15, %rax
+; W64: movl $15, %eax
; W64-NEXT: addq %rsi, %rax
; W64-NEXT: andq $-16, %rax
; W64-NEXT: callq __chkstk
@@ -166,14 +166,14 @@ entry:
define void @two_allocas_aligned(i64 %a, i64 %b) nounwind {
; W64-LABEL: two_allocas_aligned:
-; W64: movabsq $142, %rax
+; W64: movl $142, %eax
; W64-NEXT: addq %rcx, %rax
; W64-NEXT: andq $-16, %rax
; W64-NEXT: callq __chkstk
; W64-NEXT: subq %rax, %rsp
; W64-NEXT: leaq 159(%rsp), [[P:%r[a-z0-9]+]]
; W64-NEXT: andq $-128, [[P]]
-; W64: movabsq $15, %rax
+; W64: movl $15, %eax
; W64-NEXT: addq %rdx, %rax
; W64-NEXT: andq $-16, %rax
; W64-NEXT: callq __chkstk
@@ -196,7 +196,7 @@ entry:
define i64 @aligned_stack_args(i64 %n, i64 %x, ptr %dummy) nounwind {
; W64-LABEL: aligned_stack_args:
-; W64: movabsq $78, %rax
+; W64: movl $78, %eax
; W64-NEXT: addq %rcx, %rax
; W64-NEXT: andq $-16, %rax
; W64-NEXT: callq __chkstk
diff --git a/llvm/test/CodeGen/X86/win64_frame.ll b/llvm/test/CodeGen/X86/win64_frame.ll
index 5f8450a69ae77..c74fe49949248 100644
--- a/llvm/test/CodeGen/X86/win64_frame.ll
+++ b/llvm/test/CodeGen/X86/win64_frame.ll
@@ -178,7 +178,7 @@ define i32 @f8(i32 %a, i32 %b, i32 %c, i32 %d, i32 %e) "frame-pointer"="all" {
; WIN32-NEXT: movl 352(%rbp), %esi
; WIN32-NEXT: movl %ecx, %ecx
; WIN32-NEXT: shlq $2, %rcx
-; WIN32-NEXT: movabsq $15, %rax
+; WIN32-NEXT: movl $15, %eax
; WIN32-NEXT: addq %rcx, %rax
; WIN32-NEXT: andq $-16, %rax
; WIN32-NEXT: callq __chkstk
More information about the llvm-commits
mailing list