[clang] [llvm] [LoongArch] Add `-fstack-clash-protection` support (PR #195595)
via cfe-commits
cfe-commits at lists.llvm.org
Sun May 3 23:48:51 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-backend-loongarch
Author: Rong "Mantle" Bao (CSharperMantle)
<details>
<summary>Changes</summary>
This PR adds stack probing and `-fstack-clash-protection` support to the LoongArch backend and Clang driver.
The implementation is largely borrowed from the RISCV backend (cf. #<!-- -->117612, #<!-- -->139731), with the same allocation-unrolling strategy for const-sized allocations.
---
Patch is 84.13 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/195595.diff
13 Files Affected:
- (modified) clang/lib/Driver/ToolChains/Clang.cpp (+1-1)
- (modified) clang/test/CodeGen/stack-clash-protection.c (+1)
- (modified) llvm/lib/Target/LoongArch/LoongArchFrameLowering.cpp (+225-21)
- (modified) llvm/lib/Target/LoongArch/LoongArchFrameLowering.h (+8)
- (modified) llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp (+123-1)
- (modified) llvm/lib/Target/LoongArch/LoongArchISelLowering.h (+9)
- (modified) llvm/lib/Target/LoongArch/LoongArchInstrInfo.td (+22)
- (modified) llvm/lib/Target/LoongArch/LoongArchMachineFunctionInfo.h (+5)
- (modified) llvm/test/CodeGen/LoongArch/inline-asm-constraint-f.ll (-2)
- (added) llvm/test/CodeGen/LoongArch/stack-clash-prologue-nounwind.ll (+351)
- (added) llvm/test/CodeGen/LoongArch/stack-clash-prologue.ll (+714)
- (added) llvm/test/CodeGen/LoongArch/stack-probing-dynamic.ll (+479)
- (added) llvm/test/CodeGen/LoongArch/stack-probing-frame-setup.mir (+147)
``````````diff
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp
index bdffa4fdd7e6b..f1ea87f5b74bc 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -3646,7 +3646,7 @@ static void RenderSCPOptions(const ToolChain &TC, const ArgList &Args,
if (!EffectiveTriple.isX86() && !EffectiveTriple.isSystemZ() &&
!EffectiveTriple.isPPC64() && !EffectiveTriple.isAArch64() &&
- !EffectiveTriple.isRISCV())
+ !EffectiveTriple.isRISCV() && !EffectiveTriple.isLoongArch())
return;
Args.addOptInFlag(CmdArgs, options::OPT_fstack_clash_protection,
diff --git a/clang/test/CodeGen/stack-clash-protection.c b/clang/test/CodeGen/stack-clash-protection.c
index b07e4c4ce9084..b00cd46f8d24b 100644
--- a/clang/test/CodeGen/stack-clash-protection.c
+++ b/clang/test/CodeGen/stack-clash-protection.c
@@ -4,6 +4,7 @@
// RUN: %clang_cc1 -triple powerpc64le-linux-gnu -O0 -emit-llvm -o- %s -fstack-clash-protection -mstack-probe-size=8192 | FileCheck %s
// RUN: %clang_cc1 -triple powerpc64-linux-gnu -O0 -emit-llvm -o- %s -fstack-clash-protection -mstack-probe-size=8192 | FileCheck %s
// RUN: %clang_cc1 -triple aarch64-linux-gnu -O0 -emit-llvm -o- %s -fstack-clash-protection -mstack-probe-size=8192 | FileCheck %s
+// RUN: %clang_cc1 -triple loongarch64-linux-gnu -O0 -emit-llvm -o- %s -fstack-clash-protection -mstack-probe-size=8192 | FileCheck %s
// CHECK: define{{.*}} void @large_stack() #[[A:.*]] {
void large_stack(void) {
diff --git a/llvm/lib/Target/LoongArch/LoongArchFrameLowering.cpp b/llvm/lib/Target/LoongArch/LoongArchFrameLowering.cpp
index 690b0639484d0..23897fe9bc787 100644
--- a/llvm/lib/Target/LoongArch/LoongArchFrameLowering.cpp
+++ b/llvm/lib/Target/LoongArch/LoongArchFrameLowering.cpp
@@ -15,6 +15,8 @@
#include "LoongArchSubtarget.h"
#include "MCTargetDesc/LoongArchBaseInfo.h"
#include "MCTargetDesc/LoongArchMCTargetDesc.h"
+#include "llvm/CodeGen/CFIInstBuilder.h"
+#include "llvm/CodeGen/LivePhysRegs.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
@@ -182,6 +184,118 @@ void LoongArchFrameLowering::processFunctionBeforeFrameFinalized(
}
}
+// Allocate stack space and probe it if necessary.
+void LoongArchFrameLowering::allocateStack(MachineBasicBlock &MBB,
+ MachineBasicBlock::iterator MBBI,
+ MachineFunction &MF, uint64_t Offset,
+ uint64_t RealStackSize, bool EmitCFI,
+ bool NeedProbe, uint64_t ProbeSize,
+ bool DynAllocation,
+ MachineInstr::MIFlag Flag) const {
+ DebugLoc DL;
+ const LoongArchInstrInfo *TII = STI.getInstrInfo();
+ const bool IsLA64 = STI.is64Bit();
+ const Register SPReg = LoongArch::R3;
+ CFIInstBuilder CFIBuilder(MBB, MBBI, MachineInstr::FrameSetup);
+
+ // Simply allocate the stack if it's not big enough to require a probe.
+ if (!NeedProbe || Offset <= ProbeSize) {
+ adjustReg(MBB, MBBI, DL, SPReg, SPReg, -Offset, Flag);
+ if (EmitCFI)
+ CFIBuilder.buildDefCFAOffset(RealStackSize);
+
+ if (NeedProbe && DynAllocation) {
+ // st.{w/d} $zero, $sp, 0
+ BuildMI(MBB, MBBI, DL,
+ TII->get(IsLA64 ? LoongArch::ST_D : LoongArch::ST_W))
+ .addReg(LoongArch::R0)
+ .addReg(SPReg)
+ .addImm(0)
+ .setMIFlag(Flag);
+ }
+
+ return;
+ }
+
+ // Unroll the probe loop depending on the number of iterations.
+ if (Offset < ProbeSize * 5) {
+ const uint64_t CFAAdjust = RealStackSize - Offset;
+
+ uint64_t CurrentOffset = 0;
+ while (CurrentOffset + ProbeSize <= Offset) {
+ adjustReg(MBB, MBBI, DL, SPReg, SPReg, -ProbeSize, Flag);
+ // st.{w/d} $zero, $sp, 0
+ BuildMI(MBB, MBBI, DL,
+ TII->get(IsLA64 ? LoongArch::ST_D : LoongArch::ST_W))
+ .addReg(LoongArch::R0)
+ .addReg(SPReg)
+ .addImm(0)
+ .setMIFlag(Flag);
+
+ CurrentOffset += ProbeSize;
+ if (EmitCFI)
+ CFIBuilder.buildDefCFAOffset(CurrentOffset + CFAAdjust);
+ }
+
+ const uint64_t Residual = Offset - CurrentOffset;
+ if (Residual) {
+ adjustReg(MBB, MBBI, DL, SPReg, SPReg, -Residual, Flag);
+ if (EmitCFI)
+ CFIBuilder.buildDefCFAOffset(RealStackSize);
+
+ if (DynAllocation) {
+ // st.{w/d} $zero, $sp, 0
+ BuildMI(MBB, MBBI, DL,
+ TII->get(IsLA64 ? LoongArch::ST_D : LoongArch::ST_W))
+ .addReg(LoongArch::R0)
+ .addReg(SPReg)
+ .addImm(0)
+ .setMIFlag(Flag);
+ }
+ }
+ return;
+ }
+
+ // Emit a variable-length allocation probing loop.
+ const uint64_t RoundedSize = alignDown(Offset, ProbeSize);
+ const uint64_t Residual = Offset - RoundedSize;
+ const uint64_t CFAAdjust = RealStackSize - Offset;
+
+ const Register TargetReg = LoongArch::R13;
+ // SUB TargetReg, $sp, RoundedSize
+ adjustReg(MBB, MBBI, DL, TargetReg, SPReg, -RoundedSize, Flag);
+
+ if (EmitCFI) {
+ // Set the CFA register to TargetReg.
+ CFIBuilder.buildDefCFA(TargetReg, RoundedSize + CFAAdjust);
+ }
+
+ // It will be expanded to a probe loop in inlineStackProbe().
+ BuildMI(MBB, MBBI, DL, TII->get(LoongArch::PROBED_STACKALLOC))
+ .addReg(TargetReg);
+
+ if (EmitCFI) {
+ // Set the CFA register back to SP.
+ CFIBuilder.buildDefCFARegister(SPReg);
+ }
+
+ if (Residual) {
+ adjustReg(MBB, MBBI, DL, SPReg, SPReg, -Residual, Flag);
+ if (DynAllocation) {
+ // st.{w/d} $zero, $sp, 0
+ BuildMI(MBB, MBBI, DL,
+ TII->get(IsLA64 ? LoongArch::ST_D : LoongArch::ST_W))
+ .addReg(LoongArch::R0)
+ .addReg(SPReg)
+ .addImm(0)
+ .setMIFlag(Flag);
+ }
+ }
+
+ if (EmitCFI)
+ CFIBuilder.buildDefCFAOffset(RealStackSize);
+}
+
void LoongArchFrameLowering::emitPrologue(MachineFunction &MF,
MachineBasicBlock &MBB) const {
MachineFrameInfo &MFI = MF.getFrameInfo();
@@ -218,13 +332,15 @@ void LoongArchFrameLowering::emitPrologue(MachineFunction &MF,
StackSize = FirstSPAdjustAmount;
// Adjust stack.
- adjustReg(MBB, MBBI, DL, SPReg, SPReg, -StackSize, MachineInstr::FrameSetup);
- // Emit ".cfi_def_cfa_offset StackSize".
- unsigned CFIIndex =
- MF.addFrameInst(MCCFIInstruction::cfiDefCfaOffset(nullptr, StackSize));
- BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION))
- .addCFIIndex(CFIIndex)
- .setMIFlag(MachineInstr::FrameSetup);
+ const LoongArchTargetLowering *TLI = STI.getTargetLowering();
+ const bool NeedProbe = TLI->hasInlineStackProbe(MF);
+ const uint64_t ProbeSize = TLI->getStackProbeSize(MF, getStackAlign());
+ const bool DynAllocation =
+ MF.getInfo<LoongArchMachineFunctionInfo>()->hasDynamicAllocation();
+ if (StackSize != 0)
+ allocateStack(MBB, MBBI, MF, StackSize, StackSize,
+ /*EmitCFI=*/true, NeedProbe, ProbeSize, DynAllocation,
+ MachineInstr::FrameSetup);
const auto &CSI = MFI.getCalleeSavedInfo();
@@ -265,19 +381,9 @@ void LoongArchFrameLowering::emitPrologue(MachineFunction &MF,
uint64_t SecondSPAdjustAmount = RealStackSize - FirstSPAdjustAmount;
assert(SecondSPAdjustAmount > 0 &&
"SecondSPAdjustAmount should be greater than zero");
- adjustReg(MBB, MBBI, DL, SPReg, SPReg, -SecondSPAdjustAmount,
- MachineInstr::FrameSetup);
-
- if (!hasFP(MF)) {
- // If we are using a frame-pointer, and thus emitted ".cfi_def_cfa fp, 0",
- // don't emit an sp-based .cfi_def_cfa_offset
- // Emit ".cfi_def_cfa_offset RealStackSize"
- unsigned CFIIndex = MF.addFrameInst(
- MCCFIInstruction::cfiDefCfaOffset(nullptr, RealStackSize));
- BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION))
- .addCFIIndex(CFIIndex)
- .setMIFlag(MachineInstr::FrameSetup);
- }
+ allocateStack(MBB, MBBI, MF, SecondSPAdjustAmount, RealStackSize,
+ !hasFP(MF), NeedProbe, ProbeSize, DynAllocation,
+ MachineInstr::FrameSetup);
}
if (hasFP(MF)) {
@@ -353,6 +459,89 @@ void LoongArchFrameLowering::emitEpilogue(MachineFunction &MF,
adjustReg(MBB, MBBI, DL, SPReg, SPReg, StackSize, MachineInstr::FrameDestroy);
}
+// Synthesize the probe loop.
+static void emitStackProbeInline(MachineBasicBlock::iterator MBBI, DebugLoc DL,
+ Register TargetReg) {
+ assert(TargetReg != LoongArch::R3 &&
+ "New top of stack cannot already be in $sp");
+
+ MachineBasicBlock &MBB = *MBBI->getParent();
+ MachineFunction &MF = *MBB.getParent();
+
+ const LoongArchSubtarget &STI = MF.getSubtarget<LoongArchSubtarget>();
+ const LoongArchInstrInfo *TII = STI.getInstrInfo();
+ const bool IsLA64 = STI.is64Bit();
+ const Align StackAlign = STI.getFrameLowering()->getStackAlign();
+ const LoongArchTargetLowering *TLI = STI.getTargetLowering();
+ const uint64_t ProbeSize = TLI->getStackProbeSize(MF, StackAlign);
+
+ MachineFunction::iterator MBBInsertPoint = std::next(MBB.getIterator());
+ MachineBasicBlock *LoopTestMBB =
+ MF.CreateMachineBasicBlock(MBB.getBasicBlock());
+ MF.insert(MBBInsertPoint, LoopTestMBB);
+ MachineBasicBlock *ExitMBB = MF.CreateMachineBasicBlock(MBB.getBasicBlock());
+ MF.insert(MBBInsertPoint, ExitMBB);
+ const Register SPReg = LoongArch::R3;
+ const Register ScratchReg = LoongArch::R14;
+ const MachineInstr::MIFlag Flags = MachineInstr::FrameSetup;
+
+ // ScratchReg = ProbeSize
+ TII->movImm(MBB, MBBI, DL, ScratchReg, ProbeSize, Flags);
+
+ // LoopTest:
+ // sub.{w/d} $sp, $sp, ScratchReg
+ BuildMI(*LoopTestMBB, LoopTestMBB->end(), DL,
+ TII->get(IsLA64 ? LoongArch::SUB_D : LoongArch::SUB_W), SPReg)
+ .addReg(SPReg)
+ .addReg(ScratchReg)
+ .setMIFlag(Flags);
+
+ // st.{w/d} $zero, $sp, 0
+ BuildMI(*LoopTestMBB, LoopTestMBB->end(), DL,
+ TII->get(IsLA64 ? LoongArch::ST_D : LoongArch::ST_W))
+ .addReg(LoongArch::R0)
+ .addReg(SPReg)
+ .addImm(0)
+ .setMIFlag(Flags);
+
+ // bne $sp, TargetReg, LoopTest
+ BuildMI(*LoopTestMBB, LoopTestMBB->end(), DL, TII->get(LoongArch::BNE))
+ .addReg(SPReg)
+ .addReg(TargetReg)
+ .addMBB(LoopTestMBB)
+ .setMIFlag(Flags);
+
+ ExitMBB->splice(ExitMBB->end(), &MBB, std::next(MBBI), MBB.end());
+ ExitMBB->transferSuccessorsAndUpdatePHIs(&MBB);
+
+ LoopTestMBB->addSuccessor(ExitMBB);
+ LoopTestMBB->addSuccessor(LoopTestMBB);
+ MBB.addSuccessor(LoopTestMBB);
+ // Update liveins.
+ fullyRecomputeLiveIns({ExitMBB, LoopTestMBB});
+}
+
+void LoongArchFrameLowering::inlineStackProbe(MachineFunction &MF,
+ MachineBasicBlock &MBB) const {
+ // Get the instructions that need to be replaced. We emit at most two of
+ // these. Remember them in order to avoid complications coming from the need
+ // to traverse the block while potentially creating more blocks.
+ SmallVector<MachineInstr *, 2> ToReplace;
+ for (MachineInstr &MI : MBB) {
+ if (MI.getOpcode() == LoongArch::PROBED_STACKALLOC) {
+ ToReplace.push_back(&MI);
+ }
+ }
+
+ for (MachineInstr *MI : ToReplace) {
+ MachineBasicBlock::iterator MBBI = MI->getIterator();
+ DebugLoc DL = MBB.findDebugLoc(MBBI);
+ Register TargetReg = MI->getOperand(0).getReg();
+ emitStackProbeInline(MBBI, DL, TargetReg);
+ MBBI->eraseFromParent();
+ }
+}
+
// We would like to split the SP adjustment to reduce prologue/epilogue
// as following instructions. In this way, the offset of the callee saved
// register could fit in a single store.
@@ -425,7 +614,22 @@ LoongArchFrameLowering::eliminateCallFramePseudoInstr(
if (MI->getOpcode() == LoongArch::ADJCALLSTACKDOWN)
Amount = -Amount;
- adjustReg(MBB, MI, DL, SPReg, SPReg, Amount, MachineInstr::NoFlags);
+ const LoongArchTargetLowering *TLI =
+ MF.getSubtarget<LoongArchSubtarget>().getTargetLowering();
+ const int64_t ProbeSize = TLI->getStackProbeSize(MF, getStackAlign());
+ if (TLI->hasInlineStackProbe(MF) && -Amount >= ProbeSize) {
+ // When stack probing is enabled, the decrement of SP may need to be
+ // probed. We can handle both the decrement and the probing in
+ // allocateStack.
+ const bool DynAllocation =
+ MF.getInfo<LoongArchMachineFunctionInfo>()->hasDynamicAllocation();
+ allocateStack(MBB, MI, MF, -Amount, -Amount,
+ MF.needsFrameMoves() && !hasFP(MF),
+ /*NeedProbe=*/true, ProbeSize, DynAllocation,
+ MachineInstr::NoFlags);
+ } else {
+ adjustReg(MBB, MI, DL, SPReg, SPReg, Amount, MachineInstr::NoFlags);
+ }
}
}
diff --git a/llvm/lib/Target/LoongArch/LoongArchFrameLowering.h b/llvm/lib/Target/LoongArch/LoongArchFrameLowering.h
index 6cbfcf665f6a9..8a540986e9d70 100644
--- a/llvm/lib/Target/LoongArch/LoongArchFrameLowering.h
+++ b/llvm/lib/Target/LoongArch/LoongArchFrameLowering.h
@@ -55,11 +55,19 @@ class LoongArchFrameLowering : public TargetFrameLowering {
bool enableShrinkWrapping(const MachineFunction &MF) const override;
+ void inlineStackProbe(MachineFunction &MF,
+ MachineBasicBlock &PrologueMBB) const override;
+
protected:
bool hasFPImpl(const MachineFunction &MF) const override;
private:
void determineFrameLayout(MachineFunction &MF) const;
+ void allocateStack(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
+ MachineFunction &MF, uint64_t Offset,
+ uint64_t RealStackSize, bool EmitCFI, bool NeedProbe,
+ uint64_t ProbeSize, bool DynAllocation,
+ MachineInstr::MIFlag Flag) const;
void adjustReg(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
const DebugLoc &DL, Register DestReg, Register SrcReg,
int64_t Val, MachineInstr::MIFlag Flag) const;
diff --git a/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp b/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp
index 789229eae1b92..6556e534cd615 100644
--- a/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp
+++ b/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp
@@ -120,7 +120,7 @@ LoongArchTargetLowering::LoongArchTargetLowering(const TargetMachine &TM,
setOperationAction(ISD::EH_DWARF_CFA, GRLenVT, Custom);
- setOperationAction(ISD::DYNAMIC_STACKALLOC, GRLenVT, Expand);
+ setOperationAction(ISD::DYNAMIC_STACKALLOC, GRLenVT, Custom);
setOperationAction({ISD::STACKSAVE, ISD::STACKRESTORE}, MVT::Other, Expand);
setOperationAction(ISD::VASTART, MVT::Other, Custom);
setOperationAction({ISD::VAARG, ISD::VACOPY, ISD::VAEND}, MVT::Other, Expand);
@@ -652,6 +652,8 @@ SDValue LoongArchTargetLowering::LowerOperation(SDValue Op,
return lowerFP_ROUND(Op, DAG);
case ISD::FP_EXTEND:
return lowerFP_EXTEND(Op, DAG);
+ case ISD::DYNAMIC_STACKALLOC:
+ return lowerDYNAMIC_STACKALLOC(Op, DAG);
}
return SDValue();
}
@@ -8688,6 +8690,8 @@ MachineBasicBlock *LoongArchTargetLowering::EmitInstrWithCustomInserter(
if (!Subtarget.is64Bit())
report_fatal_error("STATEPOINT is only supported on 64-bit targets");
return emitPatchPoint(MI, BB);
+ case LoongArch::PROBED_STACKALLOC_DYN:
+ return emitDynamicProbedAlloc(MI, BB);
}
}
@@ -10907,3 +10911,121 @@ bool LoongArchTargetLowering::isExtractVecEltCheap(EVT VT,
// Extract a scalar FP value from index 0 of a vector is free.
return (EltVT == MVT::f32 || EltVT == MVT::f64) && Index == 0;
}
+
+bool LoongArchTargetLowering::hasInlineStackProbe(
+ const MachineFunction &MF) const {
+
+ // If the function specifically requests inline stack probes, emit them.
+ if (MF.getFunction().hasFnAttribute("probe-stack"))
+ return MF.getFunction().getFnAttribute("probe-stack").getValueAsString() ==
+ "inline-asm";
+
+ return false;
+}
+
+unsigned LoongArchTargetLowering::getStackProbeSize(const MachineFunction &MF,
+ Align StackAlign) const {
+ // The default stack probe size is 4096 if the function has no
+ // stack-probe-size attribute.
+ const Function &Fn = MF.getFunction();
+ unsigned StackProbeSize =
+ Fn.getFnAttributeAsParsedInteger("stack-probe-size", 4096);
+ // Round down to the stack alignment.
+ StackProbeSize = alignDown(StackProbeSize, StackAlign.value());
+ return StackProbeSize ? StackProbeSize : StackAlign.value();
+}
+
+SDValue
+LoongArchTargetLowering::lowerDYNAMIC_STACKALLOC(SDValue Op,
+ SelectionDAG &DAG) const {
+ MachineFunction &MF = DAG.getMachineFunction();
+ if (!hasInlineStackProbe(MF))
+ return SDValue();
+
+ const MVT GRLenVT = Subtarget.getGRLenVT();
+ // Get the inputs.
+ SDValue Chain = Op.getOperand(0);
+ SDValue Size = Op.getOperand(1);
+
+ const MaybeAlign Align =
+ cast<ConstantSDNode>(Op.getOperand(2))->getMaybeAlignValue();
+ const SDLoc dl(Op);
+ const EVT VT = Op.getValueType();
+
+ // Construct the new SP value in a GPR.
+ SDValue SP = DAG.getCopyFromReg(Chain, dl, LoongArch::R3, GRLenVT);
+ Chain = SP.getValue(1);
+ SP = DAG.getNode(ISD::SUB, dl, GRLenVT, SP, Size);
+ if (Align)
+ SP = DAG.getNode(ISD::AND, dl, VT, SP.getValue(0),
+ DAG.getSignedConstant(-Align->value(), dl, VT));
+
+ // Set the real SP to the new value with a probing loop.
+ Chain = DAG.getNode(LoongArchISD::PROBED_ALLOCA, dl, MVT::Other, Chain, SP);
+ return DAG.getMergeValues({SP, Chain}, dl);
+}
+
+MachineBasicBlock *
+LoongArchTargetLowering::emitDynamicProbedAlloc(MachineInstr &MI,
+ MachineBasicBlock *MBB) const {
+ MachineFunction &MF = *MBB->getParent();
+ MachineBasicBlock::iterator MBBI = MI.getIterator();
+ DebugLoc DL = MBB->findDebugLoc(MBBI);
+ const Register TargetReg = MI.getOperand(0).getReg();
+
+ const LoongArchInstrInfo *TII = Subtarget.getInstrInfo();
+ const bool IsLA64 = Subtarget.is64Bit();
+ const Align StackAlign = Subtarget.getFrameLowering()->getStackAlign();
+ const LoongArchTargetLowering *TLI = Subtarget.getTargetLowering();
+ const uint64_t ProbeSize = TLI->getStackProbeSize(MF, StackAlign);
+
+ MachineFunction::iterator MBBInsertPoint = std::next(MBB->getIterator());
+ MachineBasicBlock *const LoopTestMBB =
+ MF.CreateMachineBasicBlock(MBB->getBasicBlock());
+ MF.insert(MBBInsertPoint, LoopTestMBB);
+ MachineBasicBlock *const ExitMBB =
+ MF.CreateMachineBasicBlock(MBB->getBasicBlock());
+ MF.insert(MBBInsertPoint, ExitMBB);
+ const Register SPReg = LoongArch::R3;
+ const Register ScratchReg =
+ MF.getRegInfo().createVirtualRegister(&LoongArch::GPRRegClass);
+
+ // ScratchReg = ProbeSize
+ TII->movImm(*MBB, MBBI, DL, ScratchReg, ProbeSize, MachineInstr::NoFlags);
+
+ // LoopTest:
+ // sub.{w/d} $sp, $sp, ScratchReg
+ BuildMI(*LoopTestMBB, LoopTestMBB->end(), DL,
+ TII->get(IsLA64 ? LoongArch::SUB_D : LoongArch::SUB_W), SPReg)
+ .addReg(SPReg)
+ .addReg(ScratchReg);
+
+ // st.{w/d} $zero, $sp, 0
+ BuildMI(*LoopTestMBB, LoopTestMBB->end(), DL,
+ TII->get(IsLA64 ? LoongArch::ST_D : LoongArch::ST_W))
+ .addReg(LoongArch::R0)
+ .addReg(SPReg)
+ .addImm(0);
+
+ // bltu TargetReg, $sp, LoopTest
+ BuildMI(*LoopTestMBB, LoopTestMBB->end(), DL, TII->get(LoongArch::BLTU))
+ .addReg(TargetReg)
+ .addReg(SPReg)
+ .addMBB(LoopTestMBB);
+
+ // move $sp, TargetReg
+ BuildMI(*ExitMBB, ExitMBB->end(), DL, TII->get(LoongArch::OR), SPReg)
+ .addReg(TargetReg)
+ .addReg(LoongArch::R0);
+
+ ExitMBB->splice(ExitMBB->end(), MBB, std::next(MBBI), MBB->end());
+ ExitMBB->transferSuccessorsAndUpdatePHIs(MBB);
+
+ LoopTestMBB->addSuccessor(ExitMBB);
+ LoopTestMBB->addSuccessor(LoopTestMBB);
+ MBB->addSuccessor(LoopTestMBB);
+
+ MI.eraseFromParent();
+ MF.getInfo<LoongArchMachineFunctionInfo>()->setDynamicAllocation();
+ return ExitMBB->begin()->getParent();
+}
diff --git a/llvm/lib/Target/LoongArch/LoongArchISelLo...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/195595
More information about the cfe-commits
mailing list