[llvm] [RISCV] Force a frame pointer when the max reserved call frame exceeds simm12. (PR #182124)

Craig Topper via llvm-commits llvm-commits at lists.llvm.org
Wed Feb 18 13:47:27 PST 2026


https://github.com/topperc updated https://github.com/llvm/llvm-project/pull/182124

>From ad9ed15371d012d5fcae57e3989ae7f80d8c9001 Mon Sep 17 00:00:00 2001
From: Craig Topper <craig.topper at sifive.com>
Date: Fri, 13 Feb 2026 13:49:11 -0800
Subject: [PATCH 1/3] [RISCV] Force a frame pointer when the reserved call
 frame exceeds simm12.

We need to be able to address emergency spill slots without requiring
a register scavenging. This requires the emergency spill slot to be
near the SP or the FP to keep the offset small enough. If there is
a large reserved call frame, we can't keep the emergency spill slot
near SP. But we might not have a frame pointer.

This patch forces the use of a frame pointer so we can keep the
emergency spill slot near it. This idea is borrowed from AArch64.

Fixes #180199.
---
 llvm/lib/Target/RISCV/RISCVFrameLowering.cpp  |  23 ++-
 llvm/lib/Target/RISCV/RISCVSubtarget.cpp      |  13 ++
 llvm/lib/Target/RISCV/RISCVSubtarget.h        |   2 +
 llvm/test/CodeGen/RISCV/pr153598.mir          |   2 +
 .../riscv-scavenge-crash-2nd-pass-rv32.mir    | 137 +++++++++++++++++-
 .../riscv-scavenge-crash-2nd-pass-rv64.mir    |  60 +++++++-
 .../RISCV/rvv/stack-probing-dynamic.ll        |  40 +++--
 .../rvv/wrong-stack-offset-for-rvv-object.mir |   2 +-
 llvm/test/CodeGen/RISCV/xqccmp-cm-popretz.mir |   4 +
 .../test/CodeGen/RISCV/xqccmp-cm-push-pop.mir |   2 +
 llvm/test/CodeGen/RISCV/zcmp-cm-popretz.mir   |   4 +
 llvm/test/CodeGen/RISCV/zcmp-cm-push-pop.mir  |   2 +
 12 files changed, 263 insertions(+), 28 deletions(-)

diff --git a/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp b/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp
index 6a4848b2115ed..c7b0bc3be190f 100644
--- a/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp
@@ -486,9 +486,26 @@ bool RISCVFrameLowering::hasFPImpl(const MachineFunction &MF) const {
   const TargetRegisterInfo *RegInfo = MF.getSubtarget().getRegisterInfo();
 
   const MachineFrameInfo &MFI = MF.getFrameInfo();
-  return MF.getTarget().Options.DisableFramePointerElim(MF) ||
-         RegInfo->hasStackRealignment(MF) || MFI.hasVarSizedObjects() ||
-         MFI.isFrameAddressTaken();
+  if (MF.getTarget().Options.DisableFramePointerElim(MF) ||
+      RegInfo->hasStackRealignment(MF) || MFI.hasVarSizedObjects() ||
+      MFI.isFrameAddressTaken())
+    return true;
+
+  // With large callframes around we may need to use FP to access the scavenging
+  // emergency spillslot.
+  //
+  // We calculate the MaxCallFrameSize at the end of isel so this value should
+  // be stable for the whole post-isel MIR pipeline.
+  //
+  // NOTE: The idea of forcing a frame pointer is copied from AArch64, but they
+  // conservatively return true when the call frame size hasd not been
+  // computed yet. On RISC-V that caused MachineOutliner tests to fail the
+  // MachineVerifier due to outlined functions not computing max call frame
+  // size thus the frame pointr would always be reserved.
+  if (MFI.isMaxCallFrameSizeComputed() && MFI.getMaxCallFrameSize() > 2047)
+    return true;
+
+  return false;
 }
 
 bool RISCVFrameLowering::hasBP(const MachineFunction &MF) const {
diff --git a/llvm/lib/Target/RISCV/RISCVSubtarget.cpp b/llvm/lib/Target/RISCV/RISCVSubtarget.cpp
index ee86818805530..d8994ca199218 100644
--- a/llvm/lib/Target/RISCV/RISCVSubtarget.cpp
+++ b/llvm/lib/Target/RISCV/RISCVSubtarget.cpp
@@ -17,6 +17,7 @@
 #include "RISCVFrameLowering.h"
 #include "RISCVSelectionDAGInfo.h"
 #include "RISCVTargetMachine.h"
+#include "llvm/CodeGen/MachineFrameInfo.h"
 #include "llvm/MC/TargetRegistry.h"
 #include "llvm/Support/ErrorHandling.h"
 
@@ -237,6 +238,18 @@ bool RISCVSubtarget::enableMachinePipeliner() const {
   return getSchedModel().hasInstrSchedModel();
 }
 
+void RISCVSubtarget::mirFileLoaded(MachineFunction &MF) const {
+  // We usually compute max call frame size after ISel. Do the computation now
+  // if the .mir file didn't specify it. Note that this will probably give you
+  // bogus values after PEI has eliminated the callframe setup/destroy pseudo
+  // instructions, specify explicitly if you need it to be correct.
+  MachineFrameInfo &MFI = MF.getFrameInfo();
+  if (!MFI.isMaxCallFrameSizeComputed()) {
+    MFI.computeMaxCallFrameSize(MF);
+    dbgs() << "ctopper " << MFI.getMaxCallFrameSize() << "\n";
+  }
+}
+
   /// Enable use of alias analysis during code generation (during MI
   /// scheduling, DAGCombine, etc.).
 bool RISCVSubtarget::useAA() const { return UseAA; }
diff --git a/llvm/lib/Target/RISCV/RISCVSubtarget.h b/llvm/lib/Target/RISCV/RISCVSubtarget.h
index 4503b6fc44e24..fea9aae716fb5 100644
--- a/llvm/lib/Target/RISCV/RISCVSubtarget.h
+++ b/llvm/lib/Target/RISCV/RISCVSubtarget.h
@@ -147,6 +147,8 @@ class RISCVSubtarget : public RISCVGenSubtargetInfo {
     return &TLInfo;
   }
 
+  void mirFileLoaded(MachineFunction &MF) const override;
+
   bool enableMachineScheduler() const override { return true; }
 
   bool enablePostRAScheduler() const override { return UsePostRAScheduler; }
diff --git a/llvm/test/CodeGen/RISCV/pr153598.mir b/llvm/test/CodeGen/RISCV/pr153598.mir
index a084197fe83cc..ef2890810f100 100644
--- a/llvm/test/CodeGen/RISCV/pr153598.mir
+++ b/llvm/test/CodeGen/RISCV/pr153598.mir
@@ -3,6 +3,8 @@
 ---
 name: mov-merge
 tracksRegLiveness: true
+frameInfo:
+  maxCallFrameSize: 0
 body:             |
   bb.0.entry:
     liveins: $x8, $x9
diff --git a/llvm/test/CodeGen/RISCV/riscv-scavenge-crash-2nd-pass-rv32.mir b/llvm/test/CodeGen/RISCV/riscv-scavenge-crash-2nd-pass-rv32.mir
index 8c17b77aa4641..5619099468303 100644
--- a/llvm/test/CodeGen/RISCV/riscv-scavenge-crash-2nd-pass-rv32.mir
+++ b/llvm/test/CodeGen/RISCV/riscv-scavenge-crash-2nd-pass-rv32.mir
@@ -1,7 +1,7 @@
-# RUN: not --crash llc -mtriple=riscv32 -run-pass=prologepilog -verify-machineinstrs -filetype=null %s 2>&1 | FileCheck %s
-
-# CHECK: LLVM ERROR: Incomplete scavenging after 2nd pass
+# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 6
+# RUN: llc -mtriple=riscv32 -run-pass=prologepilog -verify-machineinstrs %s -o - | FileCheck %s
 
+---
 name:            main
 alignment:       2
 tracksRegLiveness: true
@@ -9,6 +9,7 @@ frameInfo:
   maxAlignment:    4
   adjustsStack:    true
   hasCalls:        true
+  maxCallFrameSize: 2276
 stack:
   - { id: 0, name: '', type: default, offset: 0, size: 2304, alignment: 4,
       stack-id: default, callee-saved-register: '', callee-saved-restored: true,
@@ -25,6 +26,134 @@ stack:
       debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
 body:             |
   bb.0:
+    ; CHECK-LABEL: name: main
+    ; CHECK: liveins: $x1, $x9, $x18, $x19, $x20, $x21, $x22, $x23, $x24, $x25, $x26, $x27
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: $x2 = frame-setup ADDI $x2, -2032
+    ; CHECK-NEXT: frame-setup CFI_INSTRUCTION def_cfa_offset 2032
+    ; CHECK-NEXT: frame-setup SW killed $x1, $x2, 2028 :: (store (s32) into %stack.4)
+    ; CHECK-NEXT: frame-setup SW killed $x8, $x2, 2024 :: (store (s32) into %stack.5)
+    ; CHECK-NEXT: frame-setup SW killed $x9, $x2, 2020 :: (store (s32) into %stack.6)
+    ; CHECK-NEXT: frame-setup SW killed $x18, $x2, 2016 :: (store (s32) into %stack.7)
+    ; CHECK-NEXT: frame-setup SW killed $x19, $x2, 2012 :: (store (s32) into %stack.8)
+    ; CHECK-NEXT: frame-setup SW killed $x20, $x2, 2008 :: (store (s32) into %stack.9)
+    ; CHECK-NEXT: frame-setup SW killed $x21, $x2, 2004 :: (store (s32) into %stack.10)
+    ; CHECK-NEXT: frame-setup SW killed $x22, $x2, 2000 :: (store (s32) into %stack.11)
+    ; CHECK-NEXT: frame-setup SW killed $x23, $x2, 1996 :: (store (s32) into %stack.12)
+    ; CHECK-NEXT: frame-setup SW killed $x24, $x2, 1992 :: (store (s32) into %stack.13)
+    ; CHECK-NEXT: frame-setup SW killed $x25, $x2, 1988 :: (store (s32) into %stack.14)
+    ; CHECK-NEXT: frame-setup SW killed $x26, $x2, 1984 :: (store (s32) into %stack.15)
+    ; CHECK-NEXT: frame-setup SW killed $x27, $x2, 1980 :: (store (s32) into %stack.16)
+    ; CHECK-NEXT: frame-setup CFI_INSTRUCTION offset $x1, -4
+    ; CHECK-NEXT: frame-setup CFI_INSTRUCTION offset $x8, -8
+    ; CHECK-NEXT: frame-setup CFI_INSTRUCTION offset $x9, -12
+    ; CHECK-NEXT: frame-setup CFI_INSTRUCTION offset $x18, -16
+    ; CHECK-NEXT: frame-setup CFI_INSTRUCTION offset $x19, -20
+    ; CHECK-NEXT: frame-setup CFI_INSTRUCTION offset $x20, -24
+    ; CHECK-NEXT: frame-setup CFI_INSTRUCTION offset $x21, -28
+    ; CHECK-NEXT: frame-setup CFI_INSTRUCTION offset $x22, -32
+    ; CHECK-NEXT: frame-setup CFI_INSTRUCTION offset $x23, -36
+    ; CHECK-NEXT: frame-setup CFI_INSTRUCTION offset $x24, -40
+    ; CHECK-NEXT: frame-setup CFI_INSTRUCTION offset $x25, -44
+    ; CHECK-NEXT: frame-setup CFI_INSTRUCTION offset $x26, -48
+    ; CHECK-NEXT: frame-setup CFI_INSTRUCTION offset $x27, -52
+    ; CHECK-NEXT: $x8 = frame-setup ADDI $x2, 2032
+    ; CHECK-NEXT: frame-setup CFI_INSTRUCTION def_cfa $x8, 0
+    ; CHECK-NEXT: $x10 = frame-setup LUI 2
+    ; CHECK-NEXT: $x10 = frame-setup ADDI killed $x10, -1168
+    ; CHECK-NEXT: $x2 = frame-setup SUB $x2, killed $x10
+    ; CHECK-NEXT: renamable $x10 = ADDI $x8, -440
+    ; CHECK-NEXT: $x11 = LUI 2
+    ; CHECK-NEXT: $x11 = SUB $x8, killed $x11
+    ; CHECK-NEXT: $x11 = LW killed $x11, 1420
+    ; CHECK-NEXT: renamable $x12 = LW undef renamable $x10, 1
+    ; CHECK-NEXT: renamable $x13 = LW undef renamable $x10, 9
+    ; CHECK-NEXT: renamable $x14 = LW undef renamable $x10, 13
+    ; CHECK-NEXT: renamable $x15 = LW undef renamable $x10, 17
+    ; CHECK-NEXT: renamable $x16 = LW undef renamable $x10, 21
+    ; CHECK-NEXT: renamable $x17 = LW undef renamable $x10, 25
+    ; CHECK-NEXT: renamable $x5 = LW undef renamable $x10, 29
+    ; CHECK-NEXT: renamable $x6 = LW undef renamable $x10, 33
+    ; CHECK-NEXT: renamable $x7 = LW undef renamable $x10, 37
+    ; CHECK-NEXT: renamable $x28 = LW undef renamable $x10, 41
+    ; CHECK-NEXT: renamable $x29 = LW undef renamable $x10, 45
+    ; CHECK-NEXT: renamable $x30 = LW undef renamable $x10, 49
+    ; CHECK-NEXT: renamable $x31 = LW undef renamable $x10, 53
+    ; CHECK-NEXT: renamable $x9 = LW undef renamable $x10, 61
+    ; CHECK-NEXT: renamable $x18 = LW undef renamable $x10, 65
+    ; CHECK-NEXT: renamable $x19 = LW undef renamable $x10, 69
+    ; CHECK-NEXT: renamable $x20 = LW undef renamable $x10, 73
+    ; CHECK-NEXT: renamable $x21 = LW undef renamable $x10, 77
+    ; CHECK-NEXT: renamable $x22 = LW undef renamable $x10, 81
+    ; CHECK-NEXT: renamable $x23 = LW undef renamable $x10, 85
+    ; CHECK-NEXT: renamable $x24 = LW undef renamable $x10, 89
+    ; CHECK-NEXT: renamable $x25 = LW undef renamable $x10, 93
+    ; CHECK-NEXT: renamable $x26 = LW undef renamable $x10, 97
+    ; CHECK-NEXT: renamable $x27 = LW undef renamable $x10, 101
+    ; CHECK-NEXT: renamable $x1 = LW undef renamable $x10, 105
+    ; CHECK-NEXT: SW killed $x11, $x8, -56 :: (store (s32) into %stack.17)
+    ; CHECK-NEXT: $x11 = LUI 1
+    ; CHECK-NEXT: $x11 = SUB $x8, killed $x11
+    ; CHECK-NEXT: SW $x10, killed $x11, -472
+    ; CHECK-NEXT: $x11 = LW $x8, -56 :: (load (s32) from %stack.17)
+    ; CHECK-NEXT: SW killed renamable $x1, undef renamable $x11, 105
+    ; CHECK-NEXT: SW killed renamable $x27, undef renamable $x11, 101
+    ; CHECK-NEXT: SW killed renamable $x26, renamable $x11, 97
+    ; CHECK-NEXT: SW killed renamable $x25, undef renamable $x11, 93
+    ; CHECK-NEXT: SW killed renamable $x24, undef renamable $x11, 89
+    ; CHECK-NEXT: SW killed renamable $x23, undef renamable $x11, 85
+    ; CHECK-NEXT: SW killed renamable $x22, undef renamable $x11, 81
+    ; CHECK-NEXT: SW killed renamable $x21, undef renamable $x11, 77
+    ; CHECK-NEXT: SW killed renamable $x20, undef renamable $x11, 73
+    ; CHECK-NEXT: SW killed renamable $x19, undef renamable $x11, 69
+    ; CHECK-NEXT: SW killed renamable $x18, undef renamable $x11, 65
+    ; CHECK-NEXT: SW killed renamable $x9, undef renamable $x11, 61
+    ; CHECK-NEXT: SW killed renamable $x31, undef renamable $x11, 53
+    ; CHECK-NEXT: SW killed renamable $x30, undef renamable $x11, 49
+    ; CHECK-NEXT: SW killed renamable $x29, undef renamable $x11, 45
+    ; CHECK-NEXT: SW killed renamable $x28, undef renamable $x11, 41
+    ; CHECK-NEXT: SW killed renamable $x7, undef renamable $x11, 37
+    ; CHECK-NEXT: SW killed renamable $x6, undef renamable $x11, 33
+    ; CHECK-NEXT: SW killed renamable $x5, undef renamable $x11, 29
+    ; CHECK-NEXT: SW killed renamable $x17, undef renamable $x11, 25
+    ; CHECK-NEXT: SW killed renamable $x16, undef renamable $x11, 21
+    ; CHECK-NEXT: SW killed renamable $x15, undef renamable $x11, 17
+    ; CHECK-NEXT: SW killed renamable $x14, undef renamable $x11, 13
+    ; CHECK-NEXT: SW killed renamable $x13, undef renamable $x11, 9
+    ; CHECK-NEXT: SW killed renamable $x12, undef renamable $x11, 5
+    ; CHECK-NEXT: $x10 = frame-destroy LUI 2
+    ; CHECK-NEXT: $x10 = frame-destroy ADDI killed $x10, -1168
+    ; CHECK-NEXT: $x2 = frame-destroy ADD $x2, killed $x10
+    ; CHECK-NEXT: frame-destroy CFI_INSTRUCTION def_cfa $x2, 2032
+    ; CHECK-NEXT: $x1 = frame-destroy LW $x2, 2028 :: (load (s32) from %stack.4)
+    ; CHECK-NEXT: $x8 = frame-destroy LW $x2, 2024 :: (load (s32) from %stack.5)
+    ; CHECK-NEXT: $x9 = frame-destroy LW $x2, 2020 :: (load (s32) from %stack.6)
+    ; CHECK-NEXT: $x18 = frame-destroy LW $x2, 2016 :: (load (s32) from %stack.7)
+    ; CHECK-NEXT: $x19 = frame-destroy LW $x2, 2012 :: (load (s32) from %stack.8)
+    ; CHECK-NEXT: $x20 = frame-destroy LW $x2, 2008 :: (load (s32) from %stack.9)
+    ; CHECK-NEXT: $x21 = frame-destroy LW $x2, 2004 :: (load (s32) from %stack.10)
+    ; CHECK-NEXT: $x22 = frame-destroy LW $x2, 2000 :: (load (s32) from %stack.11)
+    ; CHECK-NEXT: $x23 = frame-destroy LW $x2, 1996 :: (load (s32) from %stack.12)
+    ; CHECK-NEXT: $x24 = frame-destroy LW $x2, 1992 :: (load (s32) from %stack.13)
+    ; CHECK-NEXT: $x25 = frame-destroy LW $x2, 1988 :: (load (s32) from %stack.14)
+    ; CHECK-NEXT: $x26 = frame-destroy LW $x2, 1984 :: (load (s32) from %stack.15)
+    ; CHECK-NEXT: $x27 = frame-destroy LW $x2, 1980 :: (load (s32) from %stack.16)
+    ; CHECK-NEXT: frame-destroy CFI_INSTRUCTION restore $x1
+    ; CHECK-NEXT: frame-destroy CFI_INSTRUCTION restore $x8
+    ; CHECK-NEXT: frame-destroy CFI_INSTRUCTION restore $x9
+    ; CHECK-NEXT: frame-destroy CFI_INSTRUCTION restore $x18
+    ; CHECK-NEXT: frame-destroy CFI_INSTRUCTION restore $x19
+    ; CHECK-NEXT: frame-destroy CFI_INSTRUCTION restore $x20
+    ; CHECK-NEXT: frame-destroy CFI_INSTRUCTION restore $x21
+    ; CHECK-NEXT: frame-destroy CFI_INSTRUCTION restore $x22
+    ; CHECK-NEXT: frame-destroy CFI_INSTRUCTION restore $x23
+    ; CHECK-NEXT: frame-destroy CFI_INSTRUCTION restore $x24
+    ; CHECK-NEXT: frame-destroy CFI_INSTRUCTION restore $x25
+    ; CHECK-NEXT: frame-destroy CFI_INSTRUCTION restore $x26
+    ; CHECK-NEXT: frame-destroy CFI_INSTRUCTION restore $x27
+    ; CHECK-NEXT: $x2 = frame-destroy ADDI $x2, 2032
+    ; CHECK-NEXT: frame-destroy CFI_INSTRUCTION def_cfa_offset 0
+    ; CHECK-NEXT: PseudoRET
     renamable $x10 = ADDI %stack.0, 1920
     ADJCALLSTACKDOWN 2276, 0, implicit-def dead $x2, implicit $x2
     $x11 = LW %stack.3, 0
@@ -42,7 +171,6 @@ body:             |
     renamable $x29 = LW undef renamable $x10, 45
     renamable $x30 = LW undef renamable $x10, 49
     renamable $x31 = LW undef renamable $x10, 53
-    renamable $x8 = LW undef renamable $x10, 57
     renamable $x9 = LW undef renamable $x10, 61
     renamable $x18 = LW undef renamable $x10, 65
     renamable $x19 = LW undef renamable $x10, 69
@@ -68,7 +196,6 @@ body:             |
     SW killed renamable $x19, undef renamable $x11, 69
     SW killed renamable $x18, undef renamable $x11, 65
     SW killed renamable $x9, undef renamable $x11, 61
-    SW killed renamable $x8, undef renamable $x11, 57
     SW killed renamable $x31, undef renamable $x11, 53
     SW killed renamable $x30, undef renamable $x11, 49
     SW killed renamable $x29, undef renamable $x11, 45
diff --git a/llvm/test/CodeGen/RISCV/riscv-scavenge-crash-2nd-pass-rv64.mir b/llvm/test/CodeGen/RISCV/riscv-scavenge-crash-2nd-pass-rv64.mir
index f9fbb318e9a77..7d8cf0889f664 100644
--- a/llvm/test/CodeGen/RISCV/riscv-scavenge-crash-2nd-pass-rv64.mir
+++ b/llvm/test/CodeGen/RISCV/riscv-scavenge-crash-2nd-pass-rv64.mir
@@ -1,7 +1,7 @@
-# RUN: not --crash llc -mtriple=riscv64 -run-pass=prologepilog -verify-machineinstrs -filetype=null %s 2>&1 | FileCheck %s
-
-# CHECK: LLVM ERROR: Incomplete scavenging after 2nd pass
+# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 6
+# RUN: llc -mtriple=riscv64 -run-pass=prologepilog -verify-machineinstrs %s -o - | FileCheck %s
 
+---
 name:            test
 alignment:       4
 tracksRegLiveness: true
@@ -12,11 +12,65 @@ frameInfo:
   maxAlignment:    8
   adjustsStack:    true
   hasCalls:        true
+  maxCallFrameSize: 4808
 stack:
   - { id: 0, name: '', type: spill-slot, offset: 0, size: 104, alignment: 8,
       stack-id: default, callee-saved-register: '', callee-saved-restored: true,
       debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
 body:             |
+  ; CHECK-LABEL: name: test
+  ; CHECK: bb.0:
+  ; CHECK-NEXT:   successors: %bb.1(0x40000000), %bb.5(0x40000000)
+  ; CHECK-NEXT:   liveins: $x10, $x11, $x12, $x1
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   $x2 = frame-setup ADDI $x2, -2032
+  ; CHECK-NEXT:   frame-setup CFI_INSTRUCTION def_cfa_offset 2032
+  ; CHECK-NEXT:   frame-setup SD killed $x1, $x2, 2024 :: (store (s64) into %stack.1)
+  ; CHECK-NEXT:   frame-setup SD killed $x8, $x2, 2016 :: (store (s64) into %stack.2)
+  ; CHECK-NEXT:   frame-setup CFI_INSTRUCTION offset $x1, -8
+  ; CHECK-NEXT:   frame-setup CFI_INSTRUCTION offset $x8, -16
+  ; CHECK-NEXT:   $x8 = frame-setup ADDI $x2, 2032
+  ; CHECK-NEXT:   frame-setup CFI_INSTRUCTION def_cfa $x8, 0
+  ; CHECK-NEXT:   $x2 = frame-setup ADDI $x2, -2048
+  ; CHECK-NEXT:   $x2 = frame-setup ADDI killed $x2, -864
+  ; CHECK-NEXT:   BEQ undef renamable $x10, $x0, %bb.5
+  ; CHECK-NEXT:   PseudoBR %bb.1
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.1:
+  ; CHECK-NEXT:   successors: %bb.2(0x80000000)
+  ; CHECK-NEXT:   liveins: $x10, $x11, $x12
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.2:
+  ; CHECK-NEXT:   successors: %bb.3(0x80000000)
+  ; CHECK-NEXT:   liveins: $x11, $x30
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.3:
+  ; CHECK-NEXT:   successors: %bb.4(0x04000000), %bb.3(0x7c000000)
+  ; CHECK-NEXT:   liveins: $x6, $x8, $x9, $x10, $x11, $x17, $x18, $x19, $x20, $x21, $x22, $x23, $x24, $x28, $x31, $x30
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   SD undef renamable $x23, $x8, -128
+  ; CHECK-NEXT:   BEQ undef renamable $x30, $x0, %bb.3
+  ; CHECK-NEXT:   PseudoBR %bb.4
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.4:
+  ; CHECK-NEXT:   successors: %bb.2(0x80000000)
+  ; CHECK-NEXT:   liveins: $x1, $x5, $x7, $x11, $x12, $x13, $x14, $x15, $x16, $x25, $x26, $x27, $x29, $x30
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   PseudoBR %bb.2
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.5:
+  ; CHECK-NEXT:   liveins: $x10
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   $x2 = frame-destroy ADDI $x2, 2032
+  ; CHECK-NEXT:   $x2 = frame-destroy ADDI killed $x2, 880
+  ; CHECK-NEXT:   frame-destroy CFI_INSTRUCTION def_cfa $x2, 2032
+  ; CHECK-NEXT:   $x1 = frame-destroy LD $x2, 2024 :: (load (s64) from %stack.1)
+  ; CHECK-NEXT:   $x8 = frame-destroy LD $x2, 2016 :: (load (s64) from %stack.2)
+  ; CHECK-NEXT:   frame-destroy CFI_INSTRUCTION restore $x1
+  ; CHECK-NEXT:   frame-destroy CFI_INSTRUCTION restore $x8
+  ; CHECK-NEXT:   $x2 = frame-destroy ADDI $x2, 2032
+  ; CHECK-NEXT:   frame-destroy CFI_INSTRUCTION def_cfa_offset 0
+  ; CHECK-NEXT:   PseudoRET
   bb.0:
     successors: %bb.1(0x40000000), %bb.5(0x40000000)
     liveins: $x10, $x11, $x12
diff --git a/llvm/test/CodeGen/RISCV/rvv/stack-probing-dynamic.ll b/llvm/test/CodeGen/RISCV/rvv/stack-probing-dynamic.ll
index c79fb0f91b21f..f6e257085ee84 100644
--- a/llvm/test/CodeGen/RISCV/rvv/stack-probing-dynamic.ll
+++ b/llvm/test/CodeGen/RISCV/rvv/stack-probing-dynamic.ll
@@ -456,22 +456,25 @@ define void @reserved_call_frame(i64 %n) #0 {
 ; RV64I-NEXT:    addi sp, sp, -2032
 ; RV64I-NEXT:    .cfi_def_cfa_offset 2032
 ; RV64I-NEXT:    sd ra, 2024(sp) # 8-byte Folded Spill
+; RV64I-NEXT:    sd s0, 2016(sp) # 8-byte Folded Spill
 ; RV64I-NEXT:    .cfi_offset ra, -8
+; RV64I-NEXT:    .cfi_offset s0, -16
+; RV64I-NEXT:    addi s0, sp, 2032
+; RV64I-NEXT:    .cfi_def_cfa s0, 0
+; RV64I-NEXT:    addi sp, sp, -64
 ; RV64I-NEXT:    lui a0, 1
 ; RV64I-NEXT:    sub sp, sp, a0
-; RV64I-NEXT:    sd zero, 0(sp)
-; RV64I-NEXT:    .cfi_def_cfa_offset 6128
-; RV64I-NEXT:    addi sp, sp, -48
-; RV64I-NEXT:    .cfi_def_cfa_offset 6176
-; RV64I-NEXT:    lui a0, 1
-; RV64I-NEXT:    add a0, sp, a0
+; RV64I-NEXT:    addi a0, s0, -2048
+; RV64I-NEXT:    addi a0, a0, -48
 ; RV64I-NEXT:    call callee_stack_args
 ; RV64I-NEXT:    lui a0, 1
-; RV64I-NEXT:    addi a0, a0, 48
 ; RV64I-NEXT:    add sp, sp, a0
-; RV64I-NEXT:    .cfi_def_cfa_offset 2032
+; RV64I-NEXT:    addi sp, s0, -2032
+; RV64I-NEXT:    .cfi_def_cfa sp, 2032
 ; RV64I-NEXT:    ld ra, 2024(sp) # 8-byte Folded Reload
+; RV64I-NEXT:    ld s0, 2016(sp) # 8-byte Folded Reload
 ; RV64I-NEXT:    .cfi_restore ra
+; RV64I-NEXT:    .cfi_restore s0
 ; RV64I-NEXT:    addi sp, sp, 2032
 ; RV64I-NEXT:    .cfi_def_cfa_offset 0
 ; RV64I-NEXT:    ret
@@ -481,23 +484,28 @@ define void @reserved_call_frame(i64 %n) #0 {
 ; RV32I-NEXT:    addi sp, sp, -2032
 ; RV32I-NEXT:    .cfi_def_cfa_offset 2032
 ; RV32I-NEXT:    sw ra, 2028(sp) # 4-byte Folded Spill
+; RV32I-NEXT:    sw s0, 2024(sp) # 4-byte Folded Spill
 ; RV32I-NEXT:    .cfi_offset ra, -4
+; RV32I-NEXT:    .cfi_offset s0, -8
+; RV32I-NEXT:    addi s0, sp, 2032
+; RV32I-NEXT:    .cfi_def_cfa s0, 0
+; RV32I-NEXT:    addi sp, sp, -64
 ; RV32I-NEXT:    lui a0, 1
 ; RV32I-NEXT:    sub sp, sp, a0
 ; RV32I-NEXT:    sw zero, 0(sp)
-; RV32I-NEXT:    .cfi_def_cfa_offset 6128
-; RV32I-NEXT:    addi sp, sp, -80
-; RV32I-NEXT:    .cfi_def_cfa_offset 6208
-; RV32I-NEXT:    lui a0, 1
-; RV32I-NEXT:    addi a0, a0, 36
-; RV32I-NEXT:    add a0, sp, a0
+; RV32I-NEXT:    addi sp, sp, -32
+; RV32I-NEXT:    addi a0, s0, -2048
+; RV32I-NEXT:    addi a0, a0, -36
 ; RV32I-NEXT:    call callee_stack_args
 ; RV32I-NEXT:    lui a0, 1
-; RV32I-NEXT:    addi a0, a0, 80
+; RV32I-NEXT:    addi a0, a0, 32
 ; RV32I-NEXT:    add sp, sp, a0
-; RV32I-NEXT:    .cfi_def_cfa_offset 2032
+; RV32I-NEXT:    addi sp, s0, -2032
+; RV32I-NEXT:    .cfi_def_cfa sp, 2032
 ; RV32I-NEXT:    lw ra, 2028(sp) # 4-byte Folded Reload
+; RV32I-NEXT:    lw s0, 2024(sp) # 4-byte Folded Reload
 ; RV32I-NEXT:    .cfi_restore ra
+; RV32I-NEXT:    .cfi_restore s0
 ; RV32I-NEXT:    addi sp, sp, 2032
 ; RV32I-NEXT:    .cfi_def_cfa_offset 0
 ; RV32I-NEXT:    ret
diff --git a/llvm/test/CodeGen/RISCV/rvv/wrong-stack-offset-for-rvv-object.mir b/llvm/test/CodeGen/RISCV/rvv/wrong-stack-offset-for-rvv-object.mir
index d357ec644220f..7c9574e4a806f 100644
--- a/llvm/test/CodeGen/RISCV/rvv/wrong-stack-offset-for-rvv-object.mir
+++ b/llvm/test/CodeGen/RISCV/rvv/wrong-stack-offset-for-rvv-object.mir
@@ -86,7 +86,7 @@ frameInfo:
   adjustsStack:    true
   hasCalls:        true
   stackProtector:  ''
-  maxCallFrameSize: 4294967295
+  maxCallFrameSize: 0
   cvBytesOfCalleeSavedRegisters: 0
   hasOpaqueSPAdjustment: false
   hasVAStart:      false
diff --git a/llvm/test/CodeGen/RISCV/xqccmp-cm-popretz.mir b/llvm/test/CodeGen/RISCV/xqccmp-cm-popretz.mir
index b3f4b9cfe307a..4f797433ce4aa 100644
--- a/llvm/test/CodeGen/RISCV/xqccmp-cm-popretz.mir
+++ b/llvm/test/CodeGen/RISCV/xqccmp-cm-popretz.mir
@@ -6,6 +6,8 @@
 ---
 name: popret_rvlist5
 tracksRegLiveness: true
+frameInfo:
+  maxCallFrameSize: 0
 body:                   |
   bb.0:
     ; CHECK-XQCCMP32-LABEL: name: popret_rvlist5
@@ -36,6 +38,8 @@ body:                   |
 ---
 name: popretz_rvlist5
 tracksRegLiveness: true
+frameInfo:
+  maxCallFrameSize: 0
 body:                   |
   bb.0:
     ; CHECK-XQCCMP32-LABEL: name: popretz_rvlist5
diff --git a/llvm/test/CodeGen/RISCV/xqccmp-cm-push-pop.mir b/llvm/test/CodeGen/RISCV/xqccmp-cm-push-pop.mir
index 96b49525710a3..7ed481ae5a49e 100644
--- a/llvm/test/CodeGen/RISCV/xqccmp-cm-push-pop.mir
+++ b/llvm/test/CodeGen/RISCV/xqccmp-cm-push-pop.mir
@@ -6,6 +6,8 @@
 ---
 name: push_rvlist15
 tracksRegLiveness: true
+frameInfo:
+  maxCallFrameSize: 0
 body:                   |
   bb.0:
     ; CHECK-XQCCMP32-LABEL: name: push_rvlist15
diff --git a/llvm/test/CodeGen/RISCV/zcmp-cm-popretz.mir b/llvm/test/CodeGen/RISCV/zcmp-cm-popretz.mir
index a2cba85ad543c..1cdb35256723e 100644
--- a/llvm/test/CodeGen/RISCV/zcmp-cm-popretz.mir
+++ b/llvm/test/CodeGen/RISCV/zcmp-cm-popretz.mir
@@ -14,6 +14,8 @@
 ---
 name: popret_rvlist5
 tracksRegLiveness: true
+frameInfo:
+  maxCallFrameSize: 0
 body:                   |
   bb.0:
     ; CHECK-ZCMP32-LABEL: name: popret_rvlist5
@@ -104,6 +106,8 @@ body:                   |
 ---
 name: popretz_rvlist5
 tracksRegLiveness: true
+frameInfo:
+  maxCallFrameSize: 0
 body:                   |
   bb.0:
     ; CHECK-ZCMP32-LABEL: name: popretz_rvlist5
diff --git a/llvm/test/CodeGen/RISCV/zcmp-cm-push-pop.mir b/llvm/test/CodeGen/RISCV/zcmp-cm-push-pop.mir
index f78031e62f049..9cc84216e61fc 100644
--- a/llvm/test/CodeGen/RISCV/zcmp-cm-push-pop.mir
+++ b/llvm/test/CodeGen/RISCV/zcmp-cm-push-pop.mir
@@ -14,6 +14,8 @@
 ---
 name: push_rvlist15
 tracksRegLiveness: true
+frameInfo:
+  maxCallFrameSize: 0
 body:                   |
   bb.0:
     ; CHECK-ZCMP32-LABEL: name: push_rvlist15

>From 602dc36699d60f31a320d2bb708994097aa2e415 Mon Sep 17 00:00:00 2001
From: Craig Topper <craig.topper at sifive.com>
Date: Wed, 18 Feb 2026 13:44:45 -0800
Subject: [PATCH 2/3] Update RISCVSubtarget.cpp

Co-authored-by: Sam Elliott <sam at lenary.co.uk>
---
 llvm/lib/Target/RISCV/RISCVSubtarget.cpp | 1 -
 1 file changed, 1 deletion(-)

diff --git a/llvm/lib/Target/RISCV/RISCVSubtarget.cpp b/llvm/lib/Target/RISCV/RISCVSubtarget.cpp
index d8994ca199218..e884f0fea9f2e 100644
--- a/llvm/lib/Target/RISCV/RISCVSubtarget.cpp
+++ b/llvm/lib/Target/RISCV/RISCVSubtarget.cpp
@@ -246,7 +246,6 @@ void RISCVSubtarget::mirFileLoaded(MachineFunction &MF) const {
   MachineFrameInfo &MFI = MF.getFrameInfo();
   if (!MFI.isMaxCallFrameSizeComputed()) {
     MFI.computeMaxCallFrameSize(MF);
-    dbgs() << "ctopper " << MFI.getMaxCallFrameSize() << "\n";
   }
 }
 

>From bfd9d3baee28222f6e9cf829390c5a1f2b7fa089 Mon Sep 17 00:00:00 2001
From: Craig Topper <craig.topper at sifive.com>
Date: Wed, 18 Feb 2026 13:47:18 -0800
Subject: [PATCH 3/3] Apply suggestion from @topperc

---
 llvm/lib/Target/RISCV/RISCVSubtarget.cpp | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/llvm/lib/Target/RISCV/RISCVSubtarget.cpp b/llvm/lib/Target/RISCV/RISCVSubtarget.cpp
index e884f0fea9f2e..bfc8a86cbfe36 100644
--- a/llvm/lib/Target/RISCV/RISCVSubtarget.cpp
+++ b/llvm/lib/Target/RISCV/RISCVSubtarget.cpp
@@ -244,9 +244,8 @@ void RISCVSubtarget::mirFileLoaded(MachineFunction &MF) const {
   // bogus values after PEI has eliminated the callframe setup/destroy pseudo
   // instructions, specify explicitly if you need it to be correct.
   MachineFrameInfo &MFI = MF.getFrameInfo();
-  if (!MFI.isMaxCallFrameSizeComputed()) {
+  if (!MFI.isMaxCallFrameSizeComputed())
     MFI.computeMaxCallFrameSize(MF);
-  }
 }
 
   /// Enable use of alias analysis during code generation (during MI



More information about the llvm-commits mailing list