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 @@ -15,6 +15,8 @@ #ifndef LLVM_CODEGEN_ASMPRINTER_H #define LLVM_CODEGEN_ASMPRINTER_H +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/DenseSet.h" #include "llvm/ADT/MapVector.h" #include "llvm/ADT/SmallVector.h" #include "llvm/BinaryFormat/Dwarf.h" @@ -189,6 +191,9 @@ /// Output stream for the stack usage file (i.e., .su file). std::unique_ptr StackUsageStream; + /// List of symbols to be inserted into PC sections. + DenseMap> PCSectionsSymbols; + static char ID; protected: @@ -405,6 +410,12 @@ void emitRemarksSection(remarks::RemarkStreamer &RS); + /// Emits a label as reference for PC sections. + void emitPCSectionsLabel(const MachineFunction &MF, const MDNode *MD); + + /// Emits the PC sections collected from instructions. + void emitPCSections(const MachineFunction &MF); + /// Get the CFISection type for a function. CFISection getFunctionCFISectionType(const Function &F) const; 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 @@ -1421,9 +1421,84 @@ *StackUsageStream << "static\n"; } -static bool needFuncLabelsForEHOrDebugInfo(const MachineFunction &MF) { +void AsmPrinter::emitPCSectionsLabel(const MachineFunction &MF, + const MDNode *MD) { + MCSymbol *S = MF.getContext().createTempSymbol("pcsection"); + OutStreamer->emitLabel(S); + PCSectionsSymbols[MD].emplace_back(S); +} + +void AsmPrinter::emitPCSections(const MachineFunction &MF) { + const Function &F = MF.getFunction(); + if (PCSectionsSymbols.empty() && !F.hasMetadata(LLVMContext::MD_pcsections)) + return; + + const CodeModel::Model CM = MF.getTarget().getCodeModel(); + const unsigned RelativeRelocSize = + (CM == CodeModel::Medium || CM == CodeModel::Large) ? getPointerSize() + : 4; + + // Switch to PCSection, short-circuiting the common case where the current + // section is still valid (assume most MD_pcsections contain just 1 section). + auto SwitchSection = [&, Prev = StringRef()](const StringRef &Sec) mutable { + if (Sec == Prev) + return; + MCSection *S = getObjFileLowering().getPCSection(Sec, MF.getSection()); + assert(S && "PC section is not initialized"); + OutStreamer->switchSection(S); + Prev = Sec; + }; + // Emit symbols into sections and data as specified in the pcsections MDNode. + auto EmitForMD = [&](const MDNode &MD, ArrayRef Syms, + bool Deltas) { + // Expect the first operand to be a section name. After that, any number of + // constants may appear, which will simply be emitted into the current + // section (the user of MD_pcsections decides the format of encoded data). + assert(isa(MD.getOperand(0)) && "first operand not a string"); + + for (const MDOperand &MDO : MD.operands()) { + if (auto *C = dyn_cast(MDO)) { + emitGlobalConstant(F.getParent()->getDataLayout(), C->getValue()); + } else { + SwitchSection(cast(MDO)->getString()); + const MCSymbol *Prev = Syms.front(); + for (const MCSymbol *Sym : Syms) { + if (Sym == Prev || !Deltas) { + // Use the entry itself as the base of the relative offset. + MCSymbol *Base = MF.getContext().createTempSymbol("pcsection_base"); + OutStreamer->emitLabel(Base); + // Emit relative relocation `addr - base`, which avoids a dynamic + // relocation in the final binary. User will get the address with + // `base + addr`. + emitLabelDifference(Sym, Base, RelativeRelocSize); + } else { + emitLabelDifference(Sym, Prev, 4); + } + Prev = Sym; + } + } + } + }; + + OutStreamer->pushSection(); + // Emit PCs for function start and function size. + if (const MDNode *MD = F.getMetadata(LLVMContext::MD_pcsections)) { + EmitForMD(*MD, {getFunctionBegin(), getFunctionEnd()}, true); + } + // Emit PCs for instructions collected. + for (const auto &MS : PCSectionsSymbols) { + EmitForMD(*MS.first, MS.second, false); + } + OutStreamer->popSection(); + PCSectionsSymbols.clear(); +} + +/// Returns true if function begin and end labels should be emitted. +static bool needFuncLabels(const MachineFunction &MF) { MachineModuleInfo &MMI = MF.getMMI(); - if (!MF.getLandingPads().empty() || MF.hasEHFunclets() || MMI.hasDebugInfo()) + if (!MF.getLandingPads().empty() || MF.hasEHFunclets() || + MMI.hasDebugInfo() || + MF.getFunction().hasMetadata(LLVMContext::MD_pcsections)) return true; // We might emit an EH table that uses function begin and end labels even if @@ -1481,6 +1556,9 @@ if (MCSymbol *S = MI.getPreInstrSymbol()) OutStreamer->emitLabel(S); + if (MDNode *MD = MI.getPCSections()) + emitPCSectionsLabel(*MF, MD); + for (const HandlerInfo &HI : Handlers) { NamedRegionTimer T(HI.TimerName, HI.TimerDescription, HI.TimerGroupName, HI.TimerGroupDescription, TimePassesIsEnabled); @@ -1666,8 +1744,7 @@ // Emit target-specific gunk after the function body. emitFunctionBodyEnd(); - if (needFuncLabelsForEHOrDebugInfo(*MF) || - MAI->hasDotTypeDotSizeDirective()) { + if (needFuncLabels(*MF) || MAI->hasDotTypeDotSizeDirective()) { // Create a symbol for the end of function. CurrentFnEnd = createTempSymbol("func_end"); OutStreamer->emitLabel(CurrentFnEnd); @@ -1708,6 +1785,9 @@ if (MF->hasBBLabels() && HasAnyRealCode) emitBBAddrMapSection(*MF); + // Emit sections containing instruction and function PCs. + emitPCSections(*MF); + // Emit section containing stack size metadata. emitStackSizeSection(*MF); @@ -2220,7 +2300,7 @@ if (F.hasFnAttribute("patchable-function-entry") || F.hasFnAttribute("function-instrument") || F.hasFnAttribute("xray-instruction-threshold") || - needFuncLabelsForEHOrDebugInfo(MF) || NeedsLocalForSize || + needFuncLabels(MF) || NeedsLocalForSize || MF.getTarget().Options.EmitStackSizeSection || MF.hasBBLabels()) { CurrentFnBegin = createTempSymbol("func_begin"); if (NeedsLocalForSize)