[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