[llvm] [RISCV] Improve stack usage reporting accuracy in the cases when the call frame is not reserved at function entries. (PR #189990)

via llvm-commits llvm-commits at lists.llvm.org
Wed Apr 1 09:05:58 PDT 2026


https://github.com/zinechant created https://github.com/llvm/llvm-project/pull/189990

Refactors stack size calculation in AsmPrinter by introducing a new virtual method, calculateStackSize. This allows for target-specific overrides.

The RISC-V target overrides this method to conditionally add MaxCallFrameSize to the total stack size when a reserved call frame is not used. This ensures a more accurate stack usage report for --fstack-usage and the .stack_sizes_section.

fixes #189085

>From 30bf7ad78eeb0beda609fe42e1cab5663b89752d Mon Sep 17 00:00:00 2001
From: Chen Zou <chenzou at google.com>
Date: Wed, 1 Apr 2026 01:18:27 +0000
Subject: [PATCH] [RISCV] Refactors stack size calculation in AsmPrinter by
 introducing a new virtual method, calculateStackSize. This allows for
 target-specific overrides.

    The RISC-V target overrides this method to conditionally add MaxCallFrameSize to the total stack size when a reserved call frame is not used. This e
nsures a more accurate stack usage report for --fstack-usage and the .stack_sizes_section.
---
 llvm/include/llvm/CodeGen/AsmPrinter.h     |  6 ++++++
 llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp | 13 ++++++++-----
 llvm/lib/Target/RISCV/RISCVAsmPrinter.cpp  | 12 ++++++++++++
 llvm/test/CodeGen/RISCV/alloca.ll          |  6 ++++++
 4 files changed, 32 insertions(+), 5 deletions(-)

diff --git a/llvm/include/llvm/CodeGen/AsmPrinter.h b/llvm/include/llvm/CodeGen/AsmPrinter.h
index b160de2f060d6..73d60e7d9621b 100644
--- a/llvm/include/llvm/CodeGen/AsmPrinter.h
+++ b/llvm/include/llvm/CodeGen/AsmPrinter.h
@@ -476,6 +476,12 @@ class LLVM_ABI AsmPrinter : public MachineFunctionPass {
 
   void emitFrameAlloc(const MachineInstr &MI);
 
+  // Helper function to allow potentially post-fix the stack size of a function
+  // via target-specific override.
+  // Will be called by emitStackUsage or emitStackSizeSection, which usually
+  // wouldn't require target-specific overrides.
+  virtual uint64_t calculateStackSize(const MachineFunction &MF);
+
   void emitStackSizeSection(const MachineFunction &MF);
 
   void emitStackUsage(const MachineFunction &MF);
diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
index 5fdf88831892f..2ff2583af3f5a 100644
--- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
@@ -1702,6 +1702,11 @@ void AsmPrinter::emitPseudoProbe(const MachineInstr &MI) {
   }
 }
 
+uint64_t AsmPrinter::calculateStackSize(const MachineFunction &MF) {
+  const MachineFrameInfo &FrameInfo = MF.getFrameInfo();
+  return FrameInfo.getStackSize() + FrameInfo.getUnsafeStackSize();
+}
+
 void AsmPrinter::emitStackSizeSection(const MachineFunction &MF) {
   if (!MF.getTarget().Options.EmitStackSizeSection)
     return;
@@ -1720,8 +1725,7 @@ void AsmPrinter::emitStackSizeSection(const MachineFunction &MF) {
   OutStreamer->switchSection(StackSizeSection);
 
   const MCSymbol *FunctionSymbol = getFunctionBegin();
-  uint64_t StackSize =
-      FrameInfo.getStackSize() + FrameInfo.getUnsafeStackSize();
+  const uint64_t StackSize = calculateStackSize(MF);
   OutStreamer->emitSymbolValue(FunctionSymbol, TM.getProgramPointerSize());
   OutStreamer->emitULEB128IntValue(StackSize);
 
@@ -1737,9 +1741,6 @@ void AsmPrinter::emitStackUsage(const MachineFunction &MF) {
   if (OutputFilename.empty())
     return;
 
-  const MachineFrameInfo &FrameInfo = MF.getFrameInfo();
-  uint64_t StackSize =
-      FrameInfo.getStackSize() + FrameInfo.getUnsafeStackSize();
 
   if (StackUsageStream == nullptr) {
     std::error_code EC;
@@ -1756,6 +1757,8 @@ void AsmPrinter::emitStackUsage(const MachineFunction &MF) {
   else
     *StackUsageStream << MF.getFunction().getParent()->getName();
 
+  const uint64_t StackSize = calculateStackSize(MF);
+  const MachineFrameInfo &FrameInfo = MF.getFrameInfo();
   *StackUsageStream << ':' << MF.getName() << '\t' << StackSize << '\t';
   if (FrameInfo.hasVarSizedObjects())
     *StackUsageStream << "dynamic\n";
diff --git a/llvm/lib/Target/RISCV/RISCVAsmPrinter.cpp b/llvm/lib/Target/RISCV/RISCVAsmPrinter.cpp
index eb15227a72a83..e7af7bf01bc28 100644
--- a/llvm/lib/Target/RISCV/RISCVAsmPrinter.cpp
+++ b/llvm/lib/Target/RISCV/RISCVAsmPrinter.cpp
@@ -43,6 +43,7 @@
 #include "llvm/Support/raw_ostream.h"
 #include "llvm/TargetParser/RISCVISAInfo.h"
 #include "llvm/Transforms/Instrumentation/HWAddressSanitizer.h"
+#include <cstdint>
 
 using namespace llvm;
 
@@ -83,6 +84,8 @@ class RISCVAsmPrinter : public AsmPrinter {
 
   void emitInstruction(const MachineInstr *MI) override;
 
+  uint64_t calculateStackSize(const MachineFunction &MF) override;
+
   void emitMachineConstantPoolValue(MachineConstantPoolValue *MCPV) override;
 
   bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
@@ -358,6 +361,15 @@ void RISCVAsmPrinter::emitInstruction(const MachineInstr *MI) {
   EmitToStreamer(*OutStreamer, OutInst);
 }
 
+uint64_t RISCVAsmPrinter::calculateStackSize(const MachineFunction &MF) {
+  uint64_t StackSize = AsmPrinter::calculateStackSize(MF);
+  const TargetFrameLowering *TFI = MF.getSubtarget().getFrameLowering();
+  if (!TFI->hasReservedCallFrame(MF)) {
+    StackSize += MF.getFrameInfo().getMaxCallFrameSize();
+  }
+  return StackSize;
+}
+
 bool RISCVAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
                                       const char *ExtraCode, raw_ostream &OS) {
   // First try the generic code, which knows about modifiers like 'c' and 'n'.
diff --git a/llvm/test/CodeGen/RISCV/alloca.ll b/llvm/test/CodeGen/RISCV/alloca.ll
index 9ea5471e4c633..f8315f27038ae 100644
--- a/llvm/test/CodeGen/RISCV/alloca.ll
+++ b/llvm/test/CodeGen/RISCV/alloca.ll
@@ -1,6 +1,8 @@
 ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
 ; RUN: llc -mtriple=riscv32 -verify-machineinstrs < %s \
 ; RUN:   | FileCheck %s -check-prefix=RV32I
+; RUN: llc -mtriple=riscv32 -verify-machineinstrs -stack-usage-file=%t.su < %s
+; RUN: FileCheck --input-file=%t.su %s --check-prefix=SU
 
 declare void @notdead(ptr)
 
@@ -100,3 +102,7 @@ define void @alloca_callframe(i32 %n) nounwind {
                   i32 9, i32 10, i32 11, i32 12)
   ret void
 }
+
+; SU: simple_alloca{{.*}}16{{.*}}dynamic
+; SU: scoped_alloca{{.*}}16{{.*}}dynamic
+; SU: alloca_callframe{{.*}}32{{.*}}dynamic



More information about the llvm-commits mailing list