diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -70,6 +70,10 @@ - ``-Wreserved-identifier`` emits warning when user code uses reserved identifiers. +- ``-fstack-usage`` generates an extra .su file per input source file. The .su + file contains frame size information for each function defined in the source + file. + Deprecated Compiler Flags ------------------------- diff --git a/clang/include/clang/Basic/CodeGenOptions.h b/clang/include/clang/Basic/CodeGenOptions.h --- a/clang/include/clang/Basic/CodeGenOptions.h +++ b/clang/include/clang/Basic/CodeGenOptions.h @@ -389,6 +389,11 @@ /// coverage pass should actually not be instrumented. std::vector SanitizeCoverageIgnorelistFiles; + /// 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; + /// 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; diff --git a/clang/include/clang/Basic/CodeGenOptions.def b/clang/include/clang/Basic/CodeGenOptions.def --- a/clang/include/clang/Basic/CodeGenOptions.def +++ b/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. diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -2701,6 +2701,9 @@ CodeGenOpts<"StackSizeSection">, DefaultFalse, PosFlag, NegFlag>; +def fstack_usage : Flag<["-"], "fstack-usage">, Group, Flags<[CC1Option]>, + HelpText<"Emit .su file containing information on function stack sizes">, + MarshallingInfoFlag>; defm unique_basic_block_section_names : BoolFOption<"unique-basic-block-section-names", CodeGenOpts<"UniqueBasicBlockSectionNames">, DefaultFalse, diff --git a/clang/lib/CodeGen/BackendUtil.cpp b/clang/lib/CodeGen/BackendUtil.cpp --- a/clang/lib/CodeGen/BackendUtil.cpp +++ b/clang/lib/CodeGen/BackendUtil.cpp @@ -567,6 +567,7 @@ Options.ExplicitEmulatedTLS = CodeGenOpts.ExplicitEmulatedTLS; Options.DebuggerTuning = CodeGenOpts.getDebuggerTuning(); Options.EmitStackSizeSection = CodeGenOpts.StackSizeSection; + Options.StackUsageOutput = CodeGenOpts.StackUsageOutput; Options.EmitAddrsig = CodeGenOpts.Addrsig; Options.ForceDwarfFrameSection = CodeGenOpts.ForceDwarfFrameSection; Options.EmitCallSiteInfo = CodeGenOpts.EmitCallSiteInfo; diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -5485,6 +5485,9 @@ 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")); + CmdArgs.push_back("-ferror-limit"); if (Arg *A = Args.getLastArg(options::OPT_ferror_limit_EQ)) CmdArgs.push_back(A->getValue()); diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -1923,6 +1923,14 @@ if (UsingSampleProfile) NeedLocTracking = true; + if (Opts.StackUsage) { + SmallString<128> OutputFilename(OutputFile); + + llvm::sys::path::replace_extension(OutputFilename, "su"); + Opts.StackUsageOutput = std::string(OutputFilename.str()); + NeedLocTracking = true; + } + // 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) diff --git a/clang/test/CodeGen/stack-usage.c b/clang/test/CodeGen/stack-usage.c new file mode 100644 --- /dev/null +++ b/clang/test/CodeGen/stack-usage.c @@ -0,0 +1,19 @@ +// REQUIRES: aarch64-registered-target + +// RUN: rm -rf %t && mkdir %t +// RUN: %clang_cc1 -triple aarch64-unknown -fstack-usage -emit-obj %s -o %t/b.o +// RUN: FileCheck %s < %t/b.su + +// CHECK: stack-usage.c:8:foo {{[0-9]+}} static +int foo() { + char a[8]; + + return 0; +} + +// CHECK: stack-usage.c:15:bar {{[0-9]+}} dynamic +int bar(int len) { + char a[len]; + + return 1; +} diff --git a/clang/test/Driver/stack-usage.c b/clang/test/Driver/stack-usage.c new file mode 100644 --- /dev/null +++ b/clang/test/Driver/stack-usage.c @@ -0,0 +1,7 @@ +// RUN: %clang -target aarch64-unknown %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-ABSENT +// CHECK-ABSENT-NOT: -fstack-usage + +// RUN: %clang -target aarch64-unknown -fstack-usage %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-PRESENT +// CHECK-PRESENT: "-fstack-usage" + +int foo() { return 42; } diff --git a/llvm/include/llvm/CodeGen/AsmPrinter.h b/llvm/include/llvm/CodeGen/AsmPrinter.h --- a/llvm/include/llvm/CodeGen/AsmPrinter.h +++ b/llvm/include/llvm/CodeGen/AsmPrinter.h @@ -182,6 +182,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 StackUsageStream; + static char ID; protected: @@ -358,6 +361,8 @@ void emitStackSizeSection(const MachineFunction &MF); + void emitStackUsage(const MachineFunction &MF); + void emitBBAddrMapSection(const MachineFunction &MF); void emitPseudoProbe(const MachineInstr &MI); diff --git a/llvm/include/llvm/Target/TargetOptions.h b/llvm/include/llvm/Target/TargetOptions.h --- a/llvm/include/llvm/Target/TargetOptions.h +++ b/llvm/include/llvm/Target/TargetOptions.h @@ -337,6 +337,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 diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp --- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp @@ -1185,6 +1185,36 @@ OutStreamer->PopSection(); } +void AsmPrinter::emitStackUsage(const MachineFunction &MF) { + auto OutputFilename = MF.getTarget().Options.StackUsageOutput; + + if (OutputFilename.empty()) + return; + + const MachineFrameInfo &FrameInfo = MF.getFrameInfo(); + uint64_t StackSize = FrameInfo.getStackSize(); + + if (StackUsageStream == nullptr) { + std::error_code EC; + StackUsageStream = + std::make_unique(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()) @@ -1469,6 +1499,9 @@ // Emit section containing stack size metadata. emitStackSizeSection(*MF); + // Emit .su file containing function stack size information. + emitStackUsage(*MF); + emitPatchableFunctionEntries(); if (isVerbose())