pzheng created this revision.
pzheng added reviewers: apazos, efriedma, seaneveson, bruno, MatzeB, hfinkel.
Herald added subscribers: jansvoboda11, dexonsmith, dang, hiraditya.
pzheng requested review of this revision.
Herald added projects: clang, LLVM.
Herald added subscribers: llvm-commits, cfe-commits.

This patch adds support for GCC's -fstack-usage flag. With this flag, a stack
usage file (i.e., .su file) is generated for each input source file. The format
of the stack usage file is also similar to what is used by GCC. For each
function defined in the source file, a line with the following information is
produced in the .su file.

<source_file>:<line_number>:<function_name> <size_in_byte> <static/dynamic>

"Static" means that the function's frame size is static and the size info is an
accurate reflection of the frame size. While "dynamic" means the function's
frame size can only be determined at run-time because the function manipulates
the stack dynamically (e.g., due to variable size objects). The size info only
reflects the size of the fixed size frame objects in this case and therefore is
not a reliable measure of the total frame size.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D100509

Files:
  clang/include/clang/Basic/CodeGenOptions.def
  clang/include/clang/Basic/CodeGenOptions.h
  clang/include/clang/Driver/Options.td
  clang/lib/CodeGen/BackendUtil.cpp
  clang/lib/Driver/ToolChains/Clang.cpp
  clang/lib/Frontend/CompilerInvocation.cpp
  clang/test/CodeGen/stack-usage.c
  clang/test/Driver/stack-usage.c
  llvm/include/llvm/CodeGen/AsmPrinter.h
  llvm/include/llvm/Target/TargetOptions.h
  llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp

Index: llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
===================================================================
--- llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
+++ llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
@@ -1163,6 +1163,42 @@
   OutStreamer->PopSection();
 }
 
+void AsmPrinter::emitStackUsage(const MachineFunction &MF) {
+  if (!MF.getTarget().Options.EmitStackUsage)
+    return;
+
+  const MachineFrameInfo &FrameInfo = MF.getFrameInfo();
+  uint64_t StackSize = FrameInfo.getStackSize();
+
+  auto OutputFilename = MF.getTarget().Options.StackUsageOutput;
+  if (OutputFilename.empty()) {
+    SmallString<128> Val = MF.getFunction().getParent()->getName();
+
+    llvm::sys::path::replace_extension(Val, "su");
+    OutputFilename = std::string(Val.str());
+  }
+
+  if (StackUsageStream == nullptr) {
+    std::error_code EC;
+    StackUsageStream =
+        std::make_unique<raw_fd_ostream>(OutputFilename, EC, sys::fs::OF_Text);
+    if (EC) {
+      errs() << "Could not open file: " << EC.message();
+      return;
+    }
+  }
+
+  *StackUsageStream << MF.getFunction().getParent()->getName();
+  if (const DISubprogram *DSP = MF.getFunction().getSubprogram())
+    *StackUsageStream << ":" << DSP->getLine();
+
+  *StackUsageStream << ":" << MF.getName() << "\t" << StackSize << "\t";
+  if (FrameInfo.hasVarSizedObjects())
+    *StackUsageStream << "dynamic\n";
+  else
+    *StackUsageStream << "static\n";
+}
+
 static bool needFuncLabelsForEHOrDebugInfo(const MachineFunction &MF) {
   MachineModuleInfo &MMI = MF.getMMI();
   if (!MF.getLandingPads().empty() || MF.hasEHFunclets() || MMI.hasDebugInfo())
@@ -1447,6 +1483,9 @@
   // Emit section containing stack size metadata.
   emitStackSizeSection(*MF);
 
+  // Emit .su file containing function stack size information.
+  emitStackUsage(*MF);
+
   emitPatchableFunctionEntries();
 
   if (isVerbose())
Index: llvm/include/llvm/Target/TargetOptions.h
===================================================================
--- llvm/include/llvm/Target/TargetOptions.h
+++ llvm/include/llvm/Target/TargetOptions.h
@@ -130,7 +130,7 @@
           GuaranteedTailCallOpt(false), StackSymbolOrdering(true),
           EnableFastISel(false), EnableGlobalISel(false), UseInitArray(false),
           DisableIntegratedAS(false), RelaxELFRelocations(false),
-          FunctionSections(false), DataSections(false),
+          FunctionSections(false), DataSections(false), EmitStackUsage(false),
           IgnoreXCOFFVisibility(false), XCOFFTracebackTable(true),
           UniqueSectionNames(true), UniqueBasicBlockSectionNames(false),
           TrapUnreachable(false), NoTrapAfterNoreturn(false), TLSSize(0),
@@ -249,6 +249,9 @@
     /// Emit data into separate sections.
     unsigned DataSections : 1;
 
+    /// Emit .su file containing information on function stack sizes.
+    unsigned EmitStackUsage : 1;
+
     /// Do not emit visibility attribute for xcoff.
     unsigned IgnoreXCOFFVisibility : 1;
 
@@ -341,6 +344,11 @@
     /// Stack protector guard reg to use, e.g. usually fs or gs in X86.
     std::string StackProtectorGuardReg = "None";
 
+    /// Name of the stack usage file (i.e., .su file). If empty, the name of the
+    /// source file should be used to name the stack usage file (e.g., foo.su
+    /// for foo.c)
+    std::string StackUsageOutput = "";
+
     /// FloatABIType - This setting is set by -float-abi=xxx option is specfied
     /// on the command line. This setting may either be Default, Soft, or Hard.
     /// Default selects the target's default behavior. Soft selects the ABI for
Index: llvm/include/llvm/CodeGen/AsmPrinter.h
===================================================================
--- llvm/include/llvm/CodeGen/AsmPrinter.h
+++ llvm/include/llvm/CodeGen/AsmPrinter.h
@@ -175,6 +175,9 @@
   /// Emit comments in assembly output if this is true.
   bool VerboseAsm;
 
+  /// Output stream for the stack usage file (i.e., .su file).
+  std::unique_ptr<raw_fd_ostream> StackUsageStream = nullptr;
+
   static char ID;
 
 protected:
@@ -351,6 +354,8 @@
 
   void emitStackSizeSection(const MachineFunction &MF);
 
+  void emitStackUsage(const MachineFunction &MF);
+
   void emitBBAddrMapSection(const MachineFunction &MF);
 
   void emitPseudoProbe(const MachineInstr &MI);
Index: clang/test/Driver/stack-usage.c
===================================================================
--- /dev/null
+++ clang/test/Driver/stack-usage.c
@@ -0,0 +1,11 @@
+// RUN: %clang -target x86_64-unknown %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-ABSENT
+// RUN: %clang -target aarch64-unknown %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-ABSENT
+// RUN: %clang -target arm-unknown %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-ABSENT
+// CHECK-ABSENT-NOT: -fstack-usage
+
+// RUN: %clang -target x86_64-unknown -fstack-usage %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-PRESENT
+// RUN: %clang -target aarch64-unknown -fstack-usage %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-PRESENT
+// RUN: %clang -target arm-unknown -fstack-usage %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-PRESENT
+// CHECK-PRESENT: -fstack-usage
+
+int foo() { return 42; }
Index: clang/test/CodeGen/stack-usage.c
===================================================================
--- /dev/null
+++ clang/test/CodeGen/stack-usage.c
@@ -0,0 +1,22 @@
+// REQUIRES: x86-registered-target,aarch64-registered-target,arm-registered-target
+
+// RUN: %clang_cc1 -triple x86_64-unknown -fstack-usage -fstack-usage=%T/a.su -emit-obj %s -o %T/a.o
+// RUN: FileCheck %s < %T/a.su
+// RUN: %clang_cc1 -triple aarch64-unknown -fstack-usage -fstack-usage=%T/b.su -emit-obj %s -o %T/b.o
+// RUN: FileCheck %s < %T/b.su
+// RUN: %clang_cc1 -triple arm-unknown -fstack-usage -fstack-usage=%T/c.su -emit-obj %s -o %T/c.o
+// RUN: FileCheck %s < %T/c.su
+
+// CHECK: stack-usage.c:11:foo	{{[0-9]+}}	static
+int foo() {
+  char a[8];
+
+  return 0;
+}
+
+// CHECK: stack-usage.c:18:bar	{{[0-9]+}}	dynamic
+int bar(int len) {
+  char a[len];
+
+  return 1;
+}
Index: clang/lib/Frontend/CompilerInvocation.cpp
===================================================================
--- clang/lib/Frontend/CompilerInvocation.cpp
+++ clang/lib/Frontend/CompilerInvocation.cpp
@@ -1923,6 +1923,12 @@
   if (UsingSampleProfile)
     NeedLocTracking = true;
 
+  if (Args.hasArg(OPT_fstack_usage))
+    NeedLocTracking = true;
+
+  if (Arg *A = Args.getLastArg(OPT_fstack_usage_EQ))
+    Opts.StackUsageOutput = std::string(A->getValue());
+
   // If the user requested a flag that requires source locations available in
   // the backend, make sure that the backend tracks source location information.
   if (NeedLocTracking && Opts.getDebugInfo() == codegenoptions::NoDebugInfo)
Index: clang/lib/Driver/ToolChains/Clang.cpp
===================================================================
--- clang/lib/Driver/ToolChains/Clang.cpp
+++ clang/lib/Driver/ToolChains/Clang.cpp
@@ -5468,6 +5468,17 @@
                    options::OPT_fno_stack_size_section, RawTriple.isPS4()))
     CmdArgs.push_back("-fstack-size-section");
 
+  if (Args.hasArg(options::OPT_fstack_usage)) {
+    CmdArgs.push_back(Args.MakeArgString("-fstack-usage"));
+
+    if (Arg *OutputOpt = Args.getLastArg(options::OPT_o)) {
+      SmallString<128> OutputFilename(OutputOpt->getValue());
+      llvm::sys::path::replace_extension(OutputFilename, "su");
+      CmdArgs.push_back(Args.MakeArgString("-fstack-usage=" +
+                                           std::string(OutputFilename.str())));
+    }
+  }
+
   CmdArgs.push_back("-ferror-limit");
   if (Arg *A = Args.getLastArg(options::OPT_ferror_limit_EQ))
     CmdArgs.push_back(A->getValue());
Index: clang/lib/CodeGen/BackendUtil.cpp
===================================================================
--- clang/lib/CodeGen/BackendUtil.cpp
+++ clang/lib/CodeGen/BackendUtil.cpp
@@ -567,6 +567,8 @@
   Options.ExplicitEmulatedTLS = CodeGenOpts.ExplicitEmulatedTLS;
   Options.DebuggerTuning = CodeGenOpts.getDebuggerTuning();
   Options.EmitStackSizeSection = CodeGenOpts.StackSizeSection;
+  Options.EmitStackUsage = CodeGenOpts.StackUsage;
+  Options.StackUsageOutput = CodeGenOpts.StackUsageOutput;
   Options.EmitAddrsig = CodeGenOpts.Addrsig;
   Options.ForceDwarfFrameSection = CodeGenOpts.ForceDwarfFrameSection;
   Options.EmitCallSiteInfo = CodeGenOpts.EmitCallSiteInfo;
Index: clang/include/clang/Driver/Options.td
===================================================================
--- clang/include/clang/Driver/Options.td
+++ clang/include/clang/Driver/Options.td
@@ -2650,6 +2650,12 @@
   CodeGenOpts<"StackSizeSection">, DefaultFalse,
   PosFlag<SetTrue, [CC1Option], "Emit section containing metadata on function stack sizes">,
   NegFlag<SetFalse>>;
+def fstack_usage : Flag<["-"], "fstack-usage">, Group<f_Group>, Flags<[CC1Option]>,
+  HelpText<"Emit .su file containing information on function stack sizes">,
+  MarshallingInfoFlag<CodeGenOpts<"StackUsage">>;
+def fstack_usage_EQ : Joined<["-"], "fstack-usage=">, Group<f_Group>,
+  Flags<[CC1Option, NoDriverOption]>,
+  MarshallingInfoString<CodeGenOpts<"StackUsageOutput">, [{""}]>;
 
 defm unique_basic_block_section_names : BoolFOption<"unique-basic-block-section-names",
   CodeGenOpts<"UniqueBasicBlockSectionNames">, DefaultFalse,
Index: clang/include/clang/Basic/CodeGenOptions.h
===================================================================
--- clang/include/clang/Basic/CodeGenOptions.h
+++ clang/include/clang/Basic/CodeGenOptions.h
@@ -389,6 +389,8 @@
   /// coverage pass should actually not be instrumented.
   std::vector<std::string> SanitizeCoverageBlocklistFiles;
 
+  std::string StackUsageOutput;
+
   /// Executable and command-line used to create a given CompilerInvocation.
   /// Most of the time this will be the full -cc1 command.
   const char *Argv0 = nullptr;
Index: clang/include/clang/Basic/CodeGenOptions.def
===================================================================
--- clang/include/clang/Basic/CodeGenOptions.def
+++ clang/include/clang/Basic/CodeGenOptions.def
@@ -107,6 +107,7 @@
 CODEGENOPT(XRayInstrumentFunctions , 1, 0) ///< Set when -fxray-instrument is
                                            ///< enabled.
 CODEGENOPT(StackSizeSection  , 1, 0) ///< Set when -fstack-size-section is enabled.
+CODEGENOPT(StackUsage        , 1, 0) ///< Set when -fstack-usage is enabled.
 CODEGENOPT(ForceDwarfFrameSection , 1, 0) ///< Set when -fforce-dwarf-frame is
                                           ///< enabled.
 
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to