[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