Index: llvm/include/llvm/CodeGen/StackMaps.h =================================================================== --- llvm/include/llvm/CodeGen/StackMaps.h +++ llvm/include/llvm/CodeGen/StackMaps.h @@ -303,7 +303,7 @@ struct FunctionInfo { uint64_t StackSize = 0; - uint64_t RecordCount = 1; + uint64_t RecordCount = 0; FunctionInfo() = default; explicit FunctionInfo(uint64_t StackSize) : StackSize(StackSize) {} @@ -325,6 +325,10 @@ using FnInfoMap = MapVector; using CallsiteInfoList = std::vector; + /// Register function. Must be called before the other record methods for the + /// current function. + void recordFunction(); + /// Generate a stackmap record for a stackmap instruction. /// /// MI must be a raw STACKMAP, not a PATCHPOINT. Index: llvm/lib/CodeGen/StackMaps.cpp =================================================================== --- llvm/lib/CodeGen/StackMaps.cpp +++ llvm/lib/CodeGen/StackMaps.cpp @@ -19,6 +19,7 @@ #include "llvm/CodeGen/TargetRegisterInfo.h" #include "llvm/CodeGen/TargetSubtargetInfo.h" #include "llvm/IR/DataLayout.h" +#include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCContext.h" #include "llvm/MC/MCExpr.h" #include "llvm/MC/MCObjectFileInfo.h" @@ -43,6 +44,10 @@ "stackmap-version", cl::init(3), cl::Hidden, cl::desc("Specify the stackmap encoding version (default = 3)")); +static cl::opt ForceSerializationIfEmpty( + "stackmap-force-serialization", cl::init(false), cl::Hidden, + cl::desc("Forcibly serializes stack map section even if empty.")); + const char *StackMaps::WSMP = "Stack Maps: "; static uint64_t getConstMetaVal(const MachineInstr &MI, unsigned Idx) { @@ -507,18 +512,26 @@ CSInfos.emplace_back(CSOffsetExpr, ID, std::move(Locations), std::move(LiveOuts)); - // Record the stack size of the current function and update callsite count. + // Update callsite count. + auto CurrentIt = FnInfos.find(AP.CurrentFnSym); + assert(CurrentIt != FnInfos.end() && + "Current function must have been recorded"); + CurrentIt->second.RecordCount++; +} + +void StackMaps::recordFunction() { + // Record the stack size of the current function. + // Safely avoid doing it twice. It is parser's responsibility to report the + // redefinition error. + if (FnInfos.find(AP.CurrentFnSym) != FnInfos.end()) + return; + const MachineFrameInfo &MFI = AP.MF->getFrameInfo(); const TargetRegisterInfo *RegInfo = AP.MF->getSubtarget().getRegisterInfo(); bool HasDynamicFrameSize = MFI.hasVarSizedObjects() || RegInfo->hasStackRealignment(*(AP.MF)); uint64_t FrameSize = HasDynamicFrameSize ? UINT64_MAX : MFI.getStackSize(); - - auto CurrentIt = FnInfos.find(AP.CurrentFnSym); - if (CurrentIt != FnInfos.end()) - CurrentIt->second.RecordCount++; - else - FnInfos.insert(std::make_pair(AP.CurrentFnSym, FunctionInfo(FrameSize))); + FnInfos.insert(std::make_pair(AP.CurrentFnSym, FunctionInfo(FrameSize))); } void StackMaps::recordStackMap(const MCSymbol &L, const MachineInstr &MI) { @@ -578,8 +591,17 @@ OS.emitInt16(0); // Reserved. // Num functions. - LLVM_DEBUG(dbgs() << WSMP << "#functions = " << FnInfos.size() << '\n'); - OS.emitInt32(FnInfos.size()); + // Count functions that will be emitted. + uint64_t NumOfFunctions = + ForceSerializationIfEmpty + ? FnInfos.size() + : std::count_if(FnInfos.begin(), FnInfos.end(), + [](const FnInfoMap::value_type &FnInfo) { + return FnInfo.second.RecordCount != 0; + }); + + LLVM_DEBUG(dbgs() << WSMP << "#functions = " << NumOfFunctions << '\n'); + OS.emitInt32(NumOfFunctions); // Num constants. LLVM_DEBUG(dbgs() << WSMP << "#constants = " << ConstPool.size() << '\n'); OS.emitInt32(ConstPool.size()); @@ -599,9 +621,13 @@ // Function Frame records. LLVM_DEBUG(dbgs() << WSMP << "functions:\n"); for (auto const &FR : FnInfos) { + if (FR.second.RecordCount == 0 && !ForceSerializationIfEmpty) + continue; LLVM_DEBUG(dbgs() << WSMP << "function addr: " << FR.first << " frame size: " << FR.second.StackSize << " callsite count: " << FR.second.RecordCount << '\n'); + assert(OS.getContext().getAsmInfo()->getCodePointerSize() == 8 && + 'StackMap supports only 64-bit platforms'); OS.emitSymbolValue(FR.first, 8); OS.emitIntValue(FR.second.StackSize, 8); OS.emitIntValue(FR.second.RecordCount, 8); @@ -710,9 +736,7 @@ // Bail out if there's no stack map data. assert((!CSInfos.empty() || ConstPool.empty()) && "Expected empty constant pool too!"); - assert((!CSInfos.empty() || FnInfos.empty()) && - "Expected empty function record too!"); - if (CSInfos.empty()) + if (CSInfos.empty() && !ForceSerializationIfEmpty) return; MCContext &OutContext = AP.OutStreamer->getContext(); Index: llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp =================================================================== --- llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp +++ llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp @@ -170,6 +170,7 @@ void PrintDebugValueComment(const MachineInstr *MI, raw_ostream &OS); + void emitFunctionBodyStart() override { SM.recordFunction(); } void emitFunctionBodyEnd() override; MCSymbol *GetCPISymbol(unsigned CPID) const override; Index: llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp =================================================================== --- llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp +++ llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp @@ -136,6 +136,7 @@ return AsmPrinter::doInitialization(M); } + void emitFunctionBodyStart() override { SM.recordFunction(); } void emitInstruction(const MachineInstr *MI) override; /// This function is for PrintAsmOperand and PrintAsmMemoryOperand, @@ -1655,6 +1656,8 @@ /// EmitFunctionBodyStart - Emit a global entry point prefix for ELFv2. void PPCLinuxAsmPrinter::emitFunctionBodyStart() { + PPCAsmPrinter::emitFunctionBodyStart(); + // In the ELFv2 ABI, in functions that use the TOC register, we need to // provide two entry points. The ABI guarantees that when calling the // local entry point, r2 is set up by the caller to contain the TOC base Index: llvm/lib/Target/SystemZ/SystemZAsmPrinter.h =================================================================== --- llvm/lib/Target/SystemZ/SystemZAsmPrinter.h +++ llvm/lib/Target/SystemZ/SystemZAsmPrinter.h @@ -31,6 +31,7 @@ : AsmPrinter(TM, std::move(Streamer)), SM(*this) {} // Override AsmPrinter. + void emitFunctionBodyStart() override { SM.recordFunction(); } StringRef getPassName() const override { return "SystemZ Assembly Printer"; } void emitInstruction(const MachineInstr *MI) override; void emitMachineConstantPoolValue(MachineConstantPoolValue *MCPV) override; Index: llvm/lib/Target/X86/X86AsmPrinter.cpp =================================================================== --- llvm/lib/Target/X86/X86AsmPrinter.cpp +++ llvm/lib/Target/X86/X86AsmPrinter.cpp @@ -91,6 +91,7 @@ } void X86AsmPrinter::emitFunctionBodyStart() { + SM.recordFunction(); if (EmitFPOData) { if (auto *XTS = static_cast(OutStreamer->getTargetStreamer())) Index: llvm/test/CodeGen/AArch64/stackmap.ll =================================================================== --- llvm/test/CodeGen/AArch64/stackmap.ll +++ llvm/test/CodeGen/AArch64/stackmap.ll @@ -1,4 +1,5 @@ -; RUN: llc < %s -mtriple=arm64-linux-gnu | FileCheck %s +; RUN: llc < %s -mtriple=arm64-linux-gnu -stackmap-force-serialization=0 | FileCheck -check-prefixes=CHECK,CHECK-FORCED0 %s +; RUN: llc < %s -mtriple=arm64-linux-gnu -stackmap-force-serialization=1 | FileCheck -check-prefixes=CHECK,CHECK-FORCED1 %s ; ; Note: Print verbose stackmaps using -debug-only=stackmaps. @@ -9,7 +10,8 @@ ; CHECK-NEXT: .byte 0 ; CHECK-NEXT: .hword 0 ; Num Functions -; CHECK-NEXT: .word 14 +; CHECK-FORCED0-NEXT: .word 14 +; CHECK-FORCED1-NEXT: .word 15 ; Num LargeConstants ; CHECK-NEXT: .word 3 ; Num Callsites @@ -58,6 +60,9 @@ ; CHECK-NEXT: .xword needsStackRealignment ; CHECK-NEXT: .xword -1 ; CHECK-NEXT: .xword 1 +; CHECK-FORCED1-NEXT: .xword noStackMapEntries +; CHECK-FORCED1-NEXT: .xword 0 +; CHECK-FORCED1-NEXT: .xword 0 ; Large Constants ; CHECK-NEXT: .xword 2147483648 @@ -485,6 +490,10 @@ tail call void (i64, i32, ...) @llvm.experimental.stackmap(i64 0, i32 0) ret void } + +define void @noStackMapEntries() { + unreachable +} declare void @escape_values(...) declare void @llvm.experimental.stackmap(i64, i32, ...) Index: llvm/test/CodeGen/SystemZ/stackmap.ll =================================================================== --- llvm/test/CodeGen/SystemZ/stackmap.ll +++ llvm/test/CodeGen/SystemZ/stackmap.ll @@ -1,4 +1,5 @@ -; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s +; RUN: llc < %s -mtriple=s390x-linux-gnu -stackmap-force-serialization=0 | FileCheck -check-prefixes=CHECK,CHECK-FORCED0 %s +; RUN: llc < %s -mtriple=s390x-linux-gnu -stackmap-force-serialization=1 | FileCheck -check-prefixes=CHECK,CHECK-FORCED1 %s ; ; Note: Print verbose stackmaps using -debug-only=stackmaps. @@ -9,7 +10,8 @@ ; CHECK-NEXT: .byte 0 ; CHECK-NEXT: .short 0 ; Num Functions -; CHECK-NEXT: .long 15 +; CHECK-FORCED0-NEXT: .long 15 +; CHECK-FORCED1-NEXT: .long 16 ; Num LargeConstants ; CHECK-NEXT: .long 3 ; Num Callsites @@ -61,6 +63,9 @@ ; CHECK-NEXT: .quad needsStackRealignment ; CHECK-NEXT: .quad -1 ; CHECK-NEXT: .quad 1 +; CHECK-FORCED1-NEXT: .quad noStackMapEntries +; CHECK-FORCED1-NEXT: .quad 0 +; CHECK-FORCED1-NEXT: .quad 0 ; Large Constants ; CHECK-NEXT: .quad 2147483648 @@ -530,6 +535,10 @@ tail call void (i64, i32, ...) @llvm.experimental.stackmap(i64 0, i32 0) ret void } + +define void @noStackMapEntries() { + unreachable +} declare void @escape_values(...) declare void @llvm.experimental.stackmap(i64, i32, ...) Index: llvm/test/CodeGen/X86/stackmap.ll =================================================================== --- llvm/test/CodeGen/X86/stackmap.ll +++ llvm/test/CodeGen/X86/stackmap.ll @@ -1,4 +1,5 @@ -; RUN: llc < %s -mtriple=x86_64-apple-darwin -mcpu=corei7 | FileCheck %s +; RUN: llc < %s -mtriple=x86_64-apple-darwin -mcpu=corei7 -stackmap-force-serialization=0 | FileCheck -check-prefixes=CHECK,CHECK-FORCED0 %s +; RUN: llc < %s -mtriple=x86_64-apple-darwin -mcpu=corei7 -stackmap-force-serialization=1 | FileCheck -check-prefixes=CHECK,CHECK-FORCED1 %s ; ; Note: Print verbose stackmaps using -debug-only=stackmaps. @@ -9,7 +10,8 @@ ; CHECK-NEXT: .byte 0 ; CHECK-NEXT: .short 0 ; Num Functions -; CHECK-NEXT: .long 16 +; CHECK-FORCED0-NEXT: .long 16 +; CHECK-FORCED1-NEXT: .long 17 ; Num LargeConstants ; CHECK-NEXT: .long 3 ; Num Callsites @@ -64,6 +66,9 @@ ; CHECK-NEXT: .quad _needsStackRealignment ; CHECK-NEXT: .quad -1 ; CHECK-NEXT: .quad 1 +; CHECK-FORCED1-NEXT: .quad _noStackMapEntries +; CHECK-FORCED1-NEXT: .quad 0 +; CHECK-FORCED1-NEXT: .quad 0 ; Large Constants ; CHECK-NEXT: .quad 2147483648 @@ -568,6 +573,10 @@ tail call void (i64, i32, ...) @llvm.experimental.stackmap(i64 0, i32 0) ret void } + +define void @noStackMapEntries() { + unreachable +} declare void @escape_values(...) declare void @llvm.experimental.stackmap(i64, i32, ...)