Index: docs/CodeGenerator.rst =================================================================== --- docs/CodeGenerator.rst +++ docs/CodeGenerator.rst @@ -1578,6 +1578,17 @@ important if you want to support direct .o file emission, or would like to implement an assembler for your target. +Emitting function stack size information +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +A section containing metadata on function stack sizes will be emitted when +``TargetLoweringObjectFile::StackSizesSection`` is not null, and +``TargetOptions::EmitStackSizeSection`` is set (-stack-size-section). The +section will contain an array of pairs of function symbol references (8 byte) +and stack sizes (unsigned LEB128). The stack size values only include the space +allocated in the function prologue. Functions with dynamic stack allocations are +not included. + VLIW Packetizer --------------- Index: docs/CommandGuide/llc.rst =================================================================== --- docs/CommandGuide/llc.rst +++ docs/CommandGuide/llc.rst @@ -132,6 +132,14 @@ Specify which EABI version should conform to. Valid EABI versions are *gnu*, *4* and *5*. Default value (*default*) depends on the triple. +.. option:: -stack-size-section + + Emit the .stack_sizes section which contains stack size metadata. The section + contains an array of pairs of function symbol references (8 byte) and stack + sizes (unsigned LEB128). The stack size values only include the space allocated + in the function prologue. Functions with dynamic stack allocations are not + included. + Tuning/Configuration Options ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Index: include/llvm/CodeGen/AsmPrinter.h =================================================================== --- include/llvm/CodeGen/AsmPrinter.h +++ include/llvm/CodeGen/AsmPrinter.h @@ -295,6 +295,8 @@ void emitFrameAlloc(const MachineInstr &MI); + void emitStackSizeSection(const MachineFunction &MF); + enum CFIMoveType { CFI_M_None, CFI_M_EH, CFI_M_Debug }; CFIMoveType needsCFIMoves() const; Index: include/llvm/CodeGen/CommandFlags.def =================================================================== --- include/llvm/CodeGen/CommandFlags.def +++ include/llvm/CodeGen/CommandFlags.def @@ -255,6 +255,10 @@ clEnumValN(DebuggerKind::LLDB, "lldb", "lldb"), clEnumValN(DebuggerKind::SCE, "sce", "SCE targets (e.g. PS4)"))); +static cl::opt EnableStackSizeSection( + "stack-size-section", + cl::desc("Emit a section containing stack size metadata"), cl::init(false)); + // Common utility function tightly tied to the options listed here. Initializes // a TargetOptions object with CodeGen flags and returns it. static TargetOptions InitTargetOptionsFromCodeGenFlags() { @@ -281,6 +285,7 @@ Options.UniqueSectionNames = UniqueSectionNames; Options.EmulatedTLS = EmulatedTLS; Options.ExceptionModel = ExceptionModel; + Options.EmitStackSizeSection = EnableStackSizeSection; Options.MCOptions = InitMCTargetOptionsFromFlags(); Index: include/llvm/MC/MCObjectFileInfo.h =================================================================== --- include/llvm/MC/MCObjectFileInfo.h +++ include/llvm/MC/MCObjectFileInfo.h @@ -154,6 +154,9 @@ /// It is initialized on demand so it can be overwritten (with uniquing). MCSection *EHFrameSection; + /// Section containing metadata on function stack sizes. + MCSection *StackSizesSection; + // ELF specific sections. MCSection *DataRelROSection; MCSection *MergeableConst4Section; @@ -287,6 +290,8 @@ MCSection *getStackMapSection() const { return StackMapSection; } MCSection *getFaultMapSection() const { return FaultMapSection; } + MCSection *getStackSizesSection() const { return StackSizesSection; } + // ELF specific sections. MCSection *getDataRelROSection() const { return DataRelROSection; } const MCSection *getMergeableConst4Section() const { Index: include/llvm/Target/TargetOptions.h =================================================================== --- include/llvm/Target/TargetOptions.h +++ include/llvm/Target/TargetOptions.h @@ -108,7 +108,7 @@ DisableIntegratedAS(false), RelaxELFRelocations(false), FunctionSections(false), DataSections(false), UniqueSectionNames(true), TrapUnreachable(false), EmulatedTLS(false), - EnableIPRA(false) {} + EnableIPRA(false), EmitStackSizeSection(false) {} /// PrintMachineCode - This flag is enabled when the -print-machineinstrs /// option is specified on the command line, and should enable debugging @@ -216,6 +216,9 @@ /// This flag enables InterProcedural Register Allocation (IPRA). unsigned EnableIPRA : 1; + /// Emit section containing metadata on function stack sizes. + unsigned EmitStackSizeSection : 1; + /// 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: lib/CodeGen/AsmPrinter/AsmPrinter.cpp =================================================================== --- lib/CodeGen/AsmPrinter/AsmPrinter.cpp +++ lib/CodeGen/AsmPrinter/AsmPrinter.cpp @@ -964,6 +964,31 @@ MCConstantExpr::create(FrameOffset, OutContext)); } +void AsmPrinter::emitStackSizeSection(const MachineFunction &MF) { + if (!MF.getTarget().Options.EmitStackSizeSection) + return; + + MCSection *StackSizeSection = getObjFileLowering().getStackSizesSection(); + if (!StackSizeSection) + return; + + const MachineFrameInfo &FrameInfo = MF.getFrameInfo(); + // Don't emit functions with dynamic stack allocations. + if (FrameInfo.hasVarSizedObjects()) + return; + + OutStreamer->PushSection(); + OutStreamer->SwitchSection(StackSizeSection); + + const MCSymbol *FunctionSymbol = getSymbol(MF.getFunction()); + uint64_t StackSize = FrameInfo.getStackSize(); + OutStreamer->EmitValue(MCSymbolRefExpr::create(FunctionSymbol, OutContext), + /* size = */ 8); + OutStreamer->EmitULEB128IntValue(StackSize); + + OutStreamer->PopSection(); +} + static bool needFuncLabelsForEHOrDebugInfo(const MachineFunction &MF, MachineModuleInfo *MMI) { if (!MF.getLandingPads().empty() || MF.hasEHFunclets() || MMI->hasDebugInfo()) @@ -1135,6 +1160,9 @@ HI.Handler->endFunction(MF); } + // Emit section containing stack size metadata. + emitStackSizeSection(*MF); + if (isVerbose()) OutStreamer->GetCommentOS() << "-- End function\n"; Index: lib/MC/MCObjectFileInfo.cpp =================================================================== --- lib/MC/MCObjectFileInfo.cpp +++ lib/MC/MCObjectFileInfo.cpp @@ -594,6 +594,8 @@ EHFrameSection = Ctx->getELFSection(".eh_frame", EHSectionType, EHSectionFlags); + + StackSizesSection = Ctx->getELFSection(".stack_sizes", ELF::SHT_PROGBITS, 0); } void MCObjectFileInfo::initCOFFMCObjectFileInfo(const Triple &T) { Index: test/CodeGen/X86/stack-size-section.ll =================================================================== --- test/CodeGen/X86/stack-size-section.ll +++ test/CodeGen/X86/stack-size-section.ll @@ -0,0 +1,30 @@ +; RUN: llc < %s -mtriple=x86_64-linux -stack-size-section | FileCheck %s + +; CHECK-LABEL: func1: +; CHECK: .section .stack_sizes,"",@progbits +; CHECK-NEXT: .quad func1 +; CHECK-NEXT: .byte 8 +define void @func1(i32, i32) #0 { + alloca i32, align 4 + alloca i32, align 4 + ret void +} + +; CHECK-LABEL: func2: +; CHECK: .section .stack_sizes,"",@progbits +; CHECK-NEXT: .quad func2 +; CHECK-NEXT: .byte 24 +define void @func2() #0 { + alloca i32, align 4 + call void @func1(i32 1, i32 2) + ret void +} + +; CHECK-LABEL: dynalloc: +; CHECK-NOT: .section .stack_sizes +define void @dynalloc(i32 %N) #0 { + alloca i32, i32 %N + ret void +} + +attributes #0 = { "no-frame-pointer-elim"="true" }