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 @@ -90,6 +90,7 @@ CODEGENOPT(ForbidGuardVariables , 1, 0) ///< Issue errors if C++ guard variables ///< are required. CODEGENOPT(FunctionSections , 1, 0) ///< Set when -ffunction-sections is enabled. +CODEGENOPT(BBAddrMap , 1, 0) ///< Set when -fbasic-block-labels is enabled. CODEGENOPT(InstrumentFunctions , 1, 0) ///< Set when -finstrument-functions is ///< enabled. CODEGENOPT(InstrumentFunctionsAfterInlining , 1, 0) ///< Set when 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 @@ -2622,6 +2622,10 @@ CodeGenOpts<"FunctionSections">, DefaultFalse, PosFlag, NegFlag>; +defm basic_block_address_map : BoolFOption<"basic-block-address-map", + CodeGenOpts<"BBAddrMap">, DefaultFalse, + PosFlag, + NegFlag>; def fbasic_block_sections_EQ : Joined<["-"], "fbasic-block-sections=">, Group, Flags<[CC1Option, CC1AsOption]>, HelpText<"Place each function's basic blocks in unique sections (ELF Only) : all | labels | none | list=">, 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 @@ -527,6 +527,7 @@ Options.UnsafeFPMath = LangOpts.UnsafeFPMath; Options.StackAlignmentOverride = CodeGenOpts.StackAlignment; + Options.BBAddrMap = CodeGenOpts.BBAddrMap; Options.BBSections = llvm::StringSwitch(CodeGenOpts.BBSections) .Case("all", llvm::BasicBlockSection::All) 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 @@ -5131,6 +5131,17 @@ CmdArgs.push_back("-ffunction-sections"); } + if (Arg *A = Args.getLastArg(options::OPT_fbasic_block_address_map, + options::OPT_fno_basic_block_address_map)) { + if (Triple.isX86() && Triple.isOSBinFormatELF()) { + if (A->getOption().matches(options::OPT_fbasic_block_address_map)) + A->render(Args, CmdArgs); + } else { + D.Diag(diag::err_drv_unsupported_opt_for_target) + << A->getAsString(Args) << TripleStr; + } + } + if (Arg *A = Args.getLastArg(options::OPT_fbasic_block_sections_EQ)) { if (Triple.isX86() && Triple.isOSBinFormatELF()) { StringRef Val = A->getValue(); diff --git a/clang/test/Driver/basic-block-address-map.c b/clang/test/Driver/basic-block-address-map.c new file mode 100644 --- /dev/null +++ b/clang/test/Driver/basic-block-address-map.c @@ -0,0 +1,8 @@ +// RUN: %clang -### -target x86_64 -fbasic-block-address-map %s -S 2>&1 | FileCheck -check-prefix=CHECK-PRESENT %s +// CHECK-PRESENT: -fbasic-block-address-map + +// RUN: %clang -### -target x86_64 -fno-basic-block-address-map %s -S 2>&1 | FileCheck %s --check-prefix=CHECK-ABSENT +// CHECK-ABSENT-NOT: -fbasic-block-address-map + +// RUN: not %clang -c -target x86_64-apple-darwin10 -fbasic-block-address-map %s -S 2>&1 | FileCheck -check-prefix=CHECK-TRIPLE %s +// CHECK-TRIPLE: error: unsupported option '-fbasic-block-address-map' for target diff --git a/lld/ELF/Config.h b/lld/ELF/Config.h --- a/lld/ELF/Config.h +++ b/lld/ELF/Config.h @@ -121,6 +121,7 @@ llvm::StringRef sysroot; llvm::StringRef thinLTOCacheDir; llvm::StringRef thinLTOIndexOnlyArg; + bool ltoBBAddrMap; llvm::StringRef ltoBasicBlockSections; std::pair thinLTOObjectSuffixReplace; std::pair thinLTOPrefixReplace; diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp --- a/lld/ELF/Driver.cpp +++ b/lld/ELF/Driver.cpp @@ -1023,6 +1023,9 @@ config->ltoPseudoProbeForProfiling = args.hasArg(OPT_lto_pseudo_probe_for_profiling); config->ltoSampleProfile = args.getLastArgValue(OPT_lto_sample_profile); + config->ltoBBAddrMap = + args.hasFlag(OPT_lto_basic_block_address_map, + OPT_no_lto_basic_block_address_map, false); config->ltoBasicBlockSections = args.getLastArgValue(OPT_lto_basic_block_sections); config->ltoUniqueBasicBlockSectionNames = diff --git a/lld/ELF/LTO.cpp b/lld/ELF/LTO.cpp --- a/lld/ELF/LTO.cpp +++ b/lld/ELF/LTO.cpp @@ -88,6 +88,8 @@ c.Options.FunctionSections = true; c.Options.DataSections = true; + c.Options.BBAddrMap = config->ltoBBAddrMap; + // Check if basic block sections must be used. // Allowed values for --lto-basic-block-sections are "all", "labels", // "", or none. This is the equivalent diff --git a/lld/ELF/Options.td b/lld/ELF/Options.td --- a/lld/ELF/Options.td +++ b/lld/ELF/Options.td @@ -581,6 +581,9 @@ def opt_remarks_format: Separate<["--"], "opt-remarks-format">, HelpText<"The format used for serializing remarks (default: YAML)">; def save_temps: F<"save-temps">, HelpText<"Save intermediate LTO compilation results">; +defm lto_basic_block_address_map: BB<"lto-basic-block-address-map", + "Enable emitting the basic block address map section for LTO", + "Disable emitting the basic block address map section for LTO (default)">; def lto_basic_block_sections: JJ<"lto-basic-block-sections=">, HelpText<"Enable basic block sections for LTO">; defm lto_unique_basic_block_section_names: BB<"lto-unique-basic-block-section-names", diff --git a/lld/test/ELF/lto/basic-block-address-map.ll b/lld/test/ELF/lto/basic-block-address-map.ll new file mode 100644 --- /dev/null +++ b/lld/test/ELF/lto/basic-block-address-map.ll @@ -0,0 +1,28 @@ +; REQUIRES: x86 +; RUN: llvm-as %s -o %t.o +; RUN: ld.lld %t.o -o %t --lto-basic-block-address-map --lto-O0 --save-temps +; RUN: llvm-readobj -s %t.lto.o | FileCheck --check-prefix=SECNAMES %s + +; SECNAMES: Type: SHT_LLVM_BB_ADDR_MAP + +target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +; Function Attrs: nounwind uwtable +define dso_local void @foo(i32 %b) local_unnamed_addr { +entry: + %tobool.not = icmp eq i32 %b, 0 + br i1 %tobool.not, label %if.end, label %if.then + +if.then: ; preds = %entry + tail call void @foo(i32 0) + br label %if.end + +if.end: ; preds = %entry, %if.then + ret void +} + +define void @_start() { + call void @foo(i32 1) + ret void +} diff --git a/llvm/include/llvm/CodeGen/CommandFlags.h b/llvm/include/llvm/CodeGen/CommandFlags.h --- a/llvm/include/llvm/CodeGen/CommandFlags.h +++ b/llvm/include/llvm/CodeGen/CommandFlags.h @@ -146,6 +146,8 @@ RegisterCodeGenFlags(); }; +bool getEnableBBAddrMap(); + llvm::BasicBlockSection getBBSectionsMode(llvm::TargetOptions &Options); llvm::StackProtectorGuards diff --git a/llvm/include/llvm/Object/ELFTypes.h b/llvm/include/llvm/Object/ELFTypes.h --- a/llvm/include/llvm/Object/ELFTypes.h +++ b/llvm/include/llvm/Object/ELFTypes.h @@ -794,10 +794,9 @@ // Struct representing the BBAddrMap for one function. template struct Elf_BBAddrMap_Impl { LLVM_ELF_IMPORT_TYPES_ELFT(ELFT) - uintX_t Addr; // Function address // Struct representing the BBAddrMap information for one basic block. struct BBEntry { - uint32_t Offset; // Offset of basic block relative to function start. + uint32_t Offset; // Offset of basic block relative to the base address. uint32_t Size; // Size of the basic block. // The following fields are decoded from the Metadata field. The encoding @@ -810,7 +809,17 @@ : Offset(Offset), Size(Size), HasReturn(Metadata & 1), HasTailCall(Metadata & (1 << 1)), IsEHPad(Metadata & (1 << 2)){}; }; - std::vector BBEntries; // Basic block entries for this function. + + // Struct representing the BBAddrMap information for a contiguous range of + // basic blocks (a function or a basic block section). + struct BBRangeEntry { + uintX_t BaseAddr; // Base address of the range. + std::vector BBEntries; // Basic block entries for this range. + }; + + // All ranges for this function. The first range always corresponds to the + // function entry. + std::vector BBRanges; }; } // end namespace object. diff --git a/llvm/include/llvm/ObjectYAML/ELFYAML.h b/llvm/include/llvm/ObjectYAML/ELFYAML.h --- a/llvm/include/llvm/ObjectYAML/ELFYAML.h +++ b/llvm/include/llvm/ObjectYAML/ELFYAML.h @@ -160,9 +160,15 @@ llvm::yaml::Hex64 Size; llvm::yaml::Hex64 Metadata; }; - llvm::yaml::Hex64 Address; - Optional NumBlocks; - Optional> BBEntries; + + struct BBRangeEntry { + llvm::yaml::Hex64 BaseAddress; + Optional NumBlocks; + Optional> BBEntries; + }; + + Optional NumBBRanges; + Optional> BBRanges; }; struct StackSizeEntry { @@ -735,6 +741,7 @@ LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::StackSizeEntry) LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::BBAddrMapEntry) LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::BBAddrMapEntry::BBEntry) +LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::BBAddrMapEntry::BBRangeEntry) LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::DynamicEntry) LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::LinkerOption) LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::CallGraphEntry) @@ -899,6 +906,10 @@ static void mapping(IO &IO, ELFYAML::BBAddrMapEntry &Rel); }; +template <> struct MappingTraits { + static void mapping(IO &IO, ELFYAML::BBAddrMapEntry::BBRangeEntry &Rel); +}; + template <> struct MappingTraits { static void mapping(IO &IO, ELFYAML::BBAddrMapEntry::BBEntry &Rel); }; 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 @@ -65,8 +65,8 @@ // basic block sections for a subset of basic blocks which can be // used to control object size bloats from creating sections. Labels, // Do not use Basic Block Sections but label basic blocks. This - // is useful when associating profile counts from virtual addresses - // to basic blocks. + // is useful when associating profile counts from virtual + // addresses to basic blocks. Preset, // Similar to list but the blocks are identified by passes which // seek to use Basic Block Sections, e.g. MachineFunctionSplitter. // This option cannot be set via the command line. @@ -136,7 +136,7 @@ EmulatedTLS(false), ExplicitEmulatedTLS(false), EnableIPRA(false), EmitStackSizeSection(false), EnableMachineOutliner(false), EnableMachineFunctionSplitter(false), SupportsDefaultOutlining(false), - EmitAddrsig(false), EmitCallSiteInfo(false), + EmitAddrsig(false), BBAddrMap(false), EmitCallSiteInfo(false), SupportsDebugEntryValues(false), EnableDebugEntryValues(false), PseudoProbeForProfiling(false), ValueTrackingVariableLocations(false), ForceDwarfFrameSection(false), XRayOmitFunctionIndex(false), @@ -294,6 +294,10 @@ /// Emit address-significance table. unsigned EmitAddrsig : 1; + // Emit section containing basic block address offsets, which Propeller uses + // to associate profile counts from virtual addresses to basic blocks. + unsigned BBAddrMap : 1; + /// Emit basic blocks into separate sections. BasicBlockSection BBSections = BasicBlockSection::None; 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 @@ -1100,15 +1100,43 @@ OutStreamer->PushSection(); OutStreamer->SwitchSection(BBAddrMapSection); - OutStreamer->emitSymbolValue(FunctionSymbol, getPointerSize()); - // Emit the total number of basic blocks in this function. - OutStreamer->emitULEB128IntValue(MF.size()); + + // Emit the number of basic block ranges. + OutStreamer->emitULEB128IntValue(MBBSectionRanges.size()); + + // We count the number of blocks in each MBB section. + MapVector MBBSectionNumBlocks; + + if (!MF.hasBBSections()) { + // Emit the function entry address as the base address of the first BB + // range. + OutStreamer->emitSymbolValue(FunctionSymbol, getPointerSize()); + OutStreamer->emitULEB128IntValue(MF.size()); + } else { + unsigned BBCount = 0; + for (const MachineBasicBlock &MBB : MF) { + BBCount++; + if (MBB.isEndSection()) { + MBBSectionNumBlocks[MBB.getSectionIDNum()] = BBCount; + BBCount = 0; + } + } + } + // Emit BB Information for each basic block in the funciton. for (const MachineBasicBlock &MBB : MF) { const MCSymbol *MBBSymbol = MBB.isEntryBlock() ? FunctionSymbol : MBB.getSymbol(); + + if (MBB.isBeginSection()) { + OutStreamer->emitSymbolValue(MBBSymbol, getPointerSize()); + OutStreamer->emitULEB128IntValue( + MBBSectionNumBlocks[MBB.getSectionIDNum()]); + } + // Emit the basic block offset. - emitLabelDifferenceAsULEB128(MBBSymbol, FunctionSymbol); + emitLabelDifferenceAsULEB128( + MBBSymbol, MBBSectionRanges[MBB.getSectionIDNum()].BeginLabel); // Emit the basic block size. When BBs have alignments, their size cannot // always be computed from their offsets. emitLabelDifferenceAsULEB128(MBB.getEndSymbol(), MBBSymbol); @@ -1290,7 +1318,7 @@ // we have BBLabels enabled or if this basic blocks marks the end of a // section (except the section containing the entry basic block as the end // symbol for that section is CurrentFnEnd). - if (MF->hasBBLabels() || + if (MF->getTarget().Options.BBAddrMap || (MAI->hasDotTypeDotSizeDirective() && MBB.isEndSection() && !MBB.sameSection(&MF->front()))) OutStreamer->emitLabel(MBB.getEndSymbol()); @@ -1429,7 +1457,7 @@ // Emit section containing BB address offsets and their metadata, when // BB labels are requested for this function. - if (MF->hasBBLabels()) + if (MF->getTarget().Options.BBAddrMap) emitBBAddrMapSection(*MF); // Emit section containing stack size metadata. @@ -1901,7 +1929,8 @@ F.hasFnAttribute("function-instrument") || F.hasFnAttribute("xray-instruction-threshold") || needFuncLabelsForEHOrDebugInfo(MF) || NeedsLocalForSize || - MF.getTarget().Options.EmitStackSizeSection || MF.hasBBLabels()) { + MF.getTarget().Options.EmitStackSizeSection || + MF.getTarget().Options.BBAddrMap) { CurrentFnBegin = createTempSymbol("func_begin"); if (NeedsLocalForSize) CurrentFnSymForSize = CurrentFnBegin; @@ -3257,7 +3286,8 @@ // With `-fbasic-block-sections=`, a label is needed for every non-entry block // in the labels mode (option `=labels`) and every section beginning in the // sections mode (`=all` and `=list=`). - if ((MF->hasBBLabels() || MBB.isBeginSection()) && !MBB.isEntryBlock()) + if ((MF->getTarget().Options.BBAddrMap || MBB.isBeginSection()) && + !MBB.isEntryBlock()) return true; // A label is needed for any block with at least one predecessor (when that // predecessor is not the fallthrough predecessor, or if it is an EH funclet diff --git a/llvm/lib/CodeGen/BasicBlockSections.cpp b/llvm/lib/CodeGen/BasicBlockSections.cpp --- a/llvm/lib/CodeGen/BasicBlockSections.cpp +++ b/llvm/lib/CodeGen/BasicBlockSections.cpp @@ -45,14 +45,14 @@ // function into potentially several disjoint pieces, and CFI needs to be // emitted per cluster. This also bloats the object file and binary sizes. // -// Basic Block Labels +// Basic Block Address Map // ================== // -// With -fbasic-block-sections=labels, we emit the offsets of BB addresses of +// With -fbasic-block-address-map, we emit the offsets of BB addresses of // every function into the .llvm_bb_addr_map section. Along with the function // symbols, this allows for mapping of virtual addresses in PMU profiles back to // the corresponding basic blocks. This logic is implemented in AsmPrinter. This -// pass only assigns the BBSectionType of every function to ``labels``. +// pass only renumbers basic blocks. // //===----------------------------------------------------------------------===// @@ -147,6 +147,10 @@ /// Identify basic blocks that need separate sections and prepare to emit them /// accordingly. + bool handleBBSections(MachineFunction &MF); + + bool handleBBAddrMap(MachineFunction &MF); + bool runOnMachineFunction(MachineFunction &MF) override; }; @@ -339,10 +343,12 @@ return false; } -bool BasicBlockSections::runOnMachineFunction(MachineFunction &MF) { +// Identify, arrange, and modify basic blocks which need separate sections +// according to the specification provided by the -fbasic-block-sections flag. +bool BasicBlockSections::handleBBSections(MachineFunction &MF) { auto BBSectionsType = MF.getTarget().getBBSectionsType(); - assert(BBSectionsType != BasicBlockSection::None && - "BB Sections not enabled!"); + if (BBSectionsType == BasicBlockSection::None) + return false; // Check for source drift. If the source has changed since the profiles // were obtained, optimizing basic blocks might be sub-optimal. @@ -352,24 +358,18 @@ // regards to performance. if (BBSectionsType == BasicBlockSection::List && hasInstrProfHashMismatch(MF)) - return true; + return false; - // Renumber blocks before sorting them for basic block sections. This is - // useful during sorting, basic blocks in the same section will retain the - // default order. This renumbering should also be done for basic block - // labels to match the profiles with the correct blocks. + // Renumber blocks before sorting them to match the profiles with the correct + // blocks. This is also useful during sorting as basic blocks in the same + // section will retain the default order. MF.RenumberBlocks(); - if (BBSectionsType == BasicBlockSection::Labels) { - MF.setBBSectionsType(BBSectionsType); - return true; - } - std::vector> FuncBBClusterInfo; if (BBSectionsType == BasicBlockSection::List && !getBBClusterInfoForFunction(MF, FuncAliasMap, ProgramBBClusterInfo, FuncBBClusterInfo)) - return true; + return false; MF.setBBSectionsType(BBSectionsType); assignSections(MF, FuncBBClusterInfo); @@ -415,6 +415,26 @@ return true; } +// When the BB address map needs to be generated, this renumbers basic blocks to +// make them appear in increasing order of their IDs in the function. This +// avoids the need to store basic block IDs in the BB address map section, since +// they can be determined implicitly. +bool BasicBlockSections::handleBBAddrMap(MachineFunction &MF) { + if (MF.getTarget().Options.BBAddrMap) { + MF.RenumberBlocks(); + return true; + } + return false; +} + +bool BasicBlockSections::runOnMachineFunction(MachineFunction &MF) { + // First handle the basic block sections. + auto R1 = handleBBSections(MF); + // Handle basic block address map after basic block sections are finalized. + auto R2 = handleBBAddrMap(MF); + return R1 || R2; +} + // Basic Block Sections can be enabled for a subset of machine basic blocks. // This is done by passing a file containing names of functions for which basic // block sections are desired. Additionally, machine basic block ids of the diff --git a/llvm/lib/CodeGen/CommandFlags.cpp b/llvm/lib/CodeGen/CommandFlags.cpp --- a/llvm/lib/CodeGen/CommandFlags.cpp +++ b/llvm/lib/CodeGen/CommandFlags.cpp @@ -77,6 +77,7 @@ CGOPT_EXP(bool, FunctionSections) CGOPT(bool, IgnoreXCOFFVisibility) CGOPT(bool, XCOFFTracebackTable) +CGOPT(bool, EnableBBAddrMap) CGOPT(std::string, BBSections) CGOPT(std::string, StackProtectorGuard) CGOPT(unsigned, StackProtectorGuardOffset) @@ -357,6 +358,11 @@ cl::init(true)); CGBINDOPT(XCOFFTracebackTable); + static cl::opt EnableBBAddrMap( + "basic-block-address-map", + cl::desc("Emit the basic block address map section"), cl::init(false)); + CGBINDOPT(EnableBBAddrMap); + static cl::opt BBSections( "basic-block-sections", cl::desc("Emit basic blocks into separate sections"), @@ -546,6 +552,7 @@ Options.FunctionSections = getFunctionSections(); Options.IgnoreXCOFFVisibility = getIgnoreXCOFFVisibility(); Options.XCOFFTracebackTable = getXCOFFTracebackTable(); + Options.BBAddrMap = getEnableBBAddrMap(); Options.BBSections = getBBSectionsMode(Options); Options.UniqueSectionNames = getUniqueSectionNames(); Options.UniqueBasicBlockSectionNames = getUniqueBasicBlockSectionNames(); diff --git a/llvm/lib/CodeGen/TargetPassConfig.cpp b/llvm/lib/CodeGen/TargetPassConfig.cpp --- a/llvm/lib/CodeGen/TargetPassConfig.cpp +++ b/llvm/lib/CodeGen/TargetPassConfig.cpp @@ -1186,16 +1186,18 @@ addPass(createMachineOutlinerPass(RunOnAllFunctions)); } + bool NeedsBBSections = + TM->getBBSectionsType() != llvm::BasicBlockSection::None; // Machine function splitter uses the basic block sections feature. Both - // cannot be enabled at the same time. Basic block sections takes precedence. - // FIXME: In principle, BasicBlockSection::Labels and splitting can used - // together. Update this check once we have addressed any issues. - if (TM->getBBSectionsType() != llvm::BasicBlockSection::None) { - addPass(llvm::createBasicBlockSectionsPass(TM->getBBSectionsFuncListBuf())); - } else if (TM->Options.EnableMachineFunctionSplitter || - EnableMachineFunctionSplitter) { + // cannot be enabled at the same time. We do not apply machine function + // splitter if -basic-block-sections is requested. + if (!NeedsBBSections && (TM->Options.EnableMachineFunctionSplitter || + EnableMachineFunctionSplitter)) addPass(createMachineFunctionSplitterPass()); - } + // We run the BasicBlockSections pass if either we need BB sections or BB + // labels (or both). + if (NeedsBBSections || TM->Options.BBAddrMap) + addPass(llvm::createBasicBlockSectionsPass(TM->getBBSectionsFuncListBuf())); // Add passes that directly emit MI after all other MI passes. addPreEmitPass2(); diff --git a/llvm/lib/Object/ELF.cpp b/llvm/lib/Object/ELF.cpp --- a/llvm/lib/Object/ELF.cpp +++ b/llvm/lib/Object/ELF.cpp @@ -645,17 +645,24 @@ }; while (!ULEBSizeErr && Cur && Cur.tell() < Content.size()) { - uintX_t Address = static_cast(Data.getAddress(Cur)); - uint32_t NumBlocks = ReadULEB128AsUInt32(); - std::vector BBEntries; - for (uint32_t BlockID = 0; !ULEBSizeErr && Cur && (BlockID < NumBlocks); - ++BlockID) { - uint32_t Offset = ReadULEB128AsUInt32(); - uint32_t Size = ReadULEB128AsUInt32(); - uint32_t Metadata = ReadULEB128AsUInt32(); - BBEntries.push_back({Offset, Size, Metadata}); - } - FunctionEntries.push_back({Address, BBEntries}); + std::vector BBRangeEntries; + uint32_t NumBBRanges = ReadULEB128AsUInt32(); + for (uint32_t BBRangeID = 0; + !ULEBSizeErr && Cur && (BBRangeID != NumBBRanges); ++BBRangeID) { + uintX_t BaseAddress = static_cast(Data.getAddress(Cur)); + uint32_t NumBlocks = ReadULEB128AsUInt32(); + std::vector BBEntries; + BBEntries.reserve(NumBlocks); + for (uint32_t BlockID = 0; !ULEBSizeErr && Cur && (BlockID != NumBlocks); + ++BlockID) { + uint32_t Offset = ReadULEB128AsUInt32(); + uint32_t Size = ReadULEB128AsUInt32(); + uint32_t Metadata = ReadULEB128AsUInt32(); + BBEntries.push_back({Offset, Size, Metadata}); + } + BBRangeEntries.push_back({BaseAddress, BBEntries}); + } + FunctionEntries.push_back({BBRangeEntries}); } // Either Cur is in the error state, or ULEBSizeError is set (not both), but // we join the two errors here to be safe. diff --git a/llvm/lib/ObjectYAML/ELFEmitter.cpp b/llvm/lib/ObjectYAML/ELFEmitter.cpp --- a/llvm/lib/ObjectYAML/ELFEmitter.cpp +++ b/llvm/lib/ObjectYAML/ELFEmitter.cpp @@ -1356,20 +1356,28 @@ return; for (const ELFYAML::BBAddrMapEntry &E : *Section.Entries) { - // Write the address of the function. - CBA.write(E.Address, ELFT::TargetEndianness); - // Write number of BBEntries (number of basic blocks in the function). This - // is overridden by the 'NumBlocks' YAML field when specified. - uint64_t NumBlocks = - E.NumBlocks.getValueOr(E.BBEntries ? E.BBEntries->size() : 0); - SHeader.sh_size += sizeof(uintX_t) + CBA.writeULEB128(NumBlocks); - // Write all BBEntries. - if (!E.BBEntries) - continue; - for (const ELFYAML::BBAddrMapEntry::BBEntry &BBE : *E.BBEntries) - SHeader.sh_size += CBA.writeULEB128(BBE.AddressOffset) + - CBA.writeULEB128(BBE.Size) + - CBA.writeULEB128(BBE.Metadata); + // Write the number of basic block ranges, which is overridden by the + // 'NumBBRanges' field when specified. + uint32_t NumBBRanges = + E.NumBBRanges.getValueOr(E.BBRanges ? E.BBRanges->size() : 0); + SHeader.sh_size += CBA.writeULEB128(NumBBRanges); + for (const ELFYAML::BBAddrMapEntry::BBRangeEntry &BBR : *E.BBRanges) { + // Write the base address of the range. + CBA.write(BBR.BaseAddress, ELFT::TargetEndianness); + // Write number of BBEntries (number of basic blocks in this basic block + // range). This is overridden by the 'NumBlocks' YAML field when + // specified. + uint64_t NumBlocks = + BBR.NumBlocks.getValueOr(BBR.BBEntries ? BBR.BBEntries->size() : 0); + SHeader.sh_size += sizeof(uintX_t) + CBA.writeULEB128(NumBlocks); + // Write all BBEntries in this BBRange. + if (!BBR.BBEntries) + continue; + for (const ELFYAML::BBAddrMapEntry::BBEntry &BBE : *BBR.BBEntries) + SHeader.sh_size += CBA.writeULEB128(BBE.AddressOffset) + + CBA.writeULEB128(BBE.Size) + + CBA.writeULEB128(BBE.Metadata); + } } } diff --git a/llvm/lib/ObjectYAML/ELFYAML.cpp b/llvm/lib/ObjectYAML/ELFYAML.cpp --- a/llvm/lib/ObjectYAML/ELFYAML.cpp +++ b/llvm/lib/ObjectYAML/ELFYAML.cpp @@ -1669,7 +1669,13 @@ void MappingTraits::mapping( IO &IO, ELFYAML::BBAddrMapEntry &E) { assert(IO.getContext() && "The IO context is not initialized"); - IO.mapOptional("Address", E.Address, Hex64(0)); + IO.mapOptional("NumBBRanges", E.NumBBRanges); + IO.mapOptional("BBRanges", E.BBRanges); +} + +void MappingTraits::mapping( + IO &IO, ELFYAML::BBAddrMapEntry::BBRangeEntry &E) { + IO.mapOptional("BaseAddress", E.BaseAddress, Hex64(0)); IO.mapOptional("NumBlocks", E.NumBlocks); IO.mapOptional("BBEntries", E.BBEntries); } diff --git a/llvm/test/CodeGen/X86/basic-block-sections-labels-functions-sections.ll b/llvm/test/CodeGen/X86/basic-block-address-map-function-sections.ll rename from llvm/test/CodeGen/X86/basic-block-sections-labels-functions-sections.ll rename to llvm/test/CodeGen/X86/basic-block-address-map-function-sections.ll --- a/llvm/test/CodeGen/X86/basic-block-sections-labels-functions-sections.ll +++ b/llvm/test/CodeGen/X86/basic-block-address-map-function-sections.ll @@ -1,4 +1,4 @@ -; RUN: llc < %s -mtriple=x86_64 -function-sections -basic-block-sections=labels | FileCheck %s +; RUN: llc < %s -mtriple=x86_64 -function-sections -basic-block-address-map | FileCheck %s $_Z4fooTIiET_v = comdat any @@ -10,6 +10,7 @@ ; CHECK-LABEL: _Z3barv: ; CHECK-NEXT: [[BAR_BEGIN:.Lfunc_begin[0-9]+]]: ; CHECK: .section .llvm_bb_addr_map,"o",@llvm_bb_addr_map,.text._Z3barv{{$}} +; CHECK-NEXT: .byte 1 ; CHECK-NEXT: .quad [[BAR_BEGIN]] @@ -21,6 +22,7 @@ ; CHECK-LABEL: _Z3foov: ; CHECK-NEXT: [[FOO_BEGIN:.Lfunc_begin[0-9]+]]: ; CHECK: .section .llvm_bb_addr_map,"o",@llvm_bb_addr_map,.text._Z3foov{{$}} +; CHECK-NEXT: .byte 1 ; CHECK-NEXT: .quad [[FOO_BEGIN]] @@ -32,4 +34,5 @@ ; CHECK-LABEL: _Z4fooTIiET_v: ; CHECK-NEXT: [[FOOCOMDAT_BEGIN:.Lfunc_begin[0-9]+]]: ; CHECK: .section .llvm_bb_addr_map,"Go",@llvm_bb_addr_map,_Z4fooTIiET_v,comdat,.text._Z4fooTIiET_v{{$}} +; CHECK-NEXT: .byte 1 ; CHECK-NEXT: .quad [[FOOCOMDAT_BEGIN]] diff --git a/llvm/test/CodeGen/X86/basic-block-address-map-with-sections.ll b/llvm/test/CodeGen/X86/basic-block-address-map-with-sections.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/X86/basic-block-address-map-with-sections.ll @@ -0,0 +1,64 @@ +;; Check that the basic-block-address-map option works when used along with -basic-block-sections. +;; Let a function with 4 basic blocks get split into 2 sections. +; RUN: echo '!_Z3bazb' > %t +; RUN: echo '!!0 2' >> %t +; RUN: llc < %s -mtriple=x86_64 -unique-section-names=false -basic-block-address-map -basic-block-sections=%t | FileCheck %s + +define void @_Z3bazb(i1 zeroext) personality i32 (...)* @__gxx_personality_v0 { + br i1 %0, label %2, label %7 + +2: + %3 = invoke i32 @_Z3barv() + to label %7 unwind label %5 + br label %9 + +5: + landingpad { i8*, i32 } + catch i8* null + br label %9 + +7: + %8 = call i32 @_Z3foov() + br label %9 + +9: + ret void +} + +declare i32 @_Z3barv() #1 + +declare i32 @_Z3foov() #1 + +declare i32 @__gxx_personality_v0(...) + +; CHECK: .section .text,"ax",@progbits,unique,1 +; CHECK-LABEL: _Z3bazb: +; CHECK-LABEL: .Lfunc_begin0: +; CHECK-LABEL: .LBB_END0_0: +; CHECK-LABEL: .LBB0_1: +; CHECK-LABEL: .LBB_END0_1: +; CHECK: .section .text.split._Z3bazb,"ax",@progbits +; CHECK-LABEL: _Z3bazb.cold: +; CHECK-LABEL: .LBB_END0_2: +; CHECK-LABEL: .LBB0_3: +; CHECK-LABEL: .LBB_END0_3: +; CHECK-LABEL: .Lfunc_end0: + +; CHECK: .section .llvm_bb_addr_map,"o",@llvm_bb_addr_map,.text,unique,1 +; CHECK-NEXT: .byte 2 +; CHECK-NEXT: .quad .Lfunc_begin0 +; CHECK-NEXT: .byte 2 +; CHECK-NEXT: .uleb128 .Lfunc_begin0-.Lfunc_begin0 +; CHECK-NEXT: .uleb128 .LBB_END0_0-.Lfunc_begin0 +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .uleb128 .LBB0_1-.Lfunc_begin0 +; CHECK-NEXT: .uleb128 .LBB_END0_1-.LBB0_1 +; CHECK-NEXT: .byte 1 +; CHECK-NEXT: .quad _Z3bazb.cold +; CHECK-NEXT: .byte 2 +; CHECK-NEXT: .uleb128 _Z3bazb.cold-_Z3bazb.cold +; CHECK-NEXT: .uleb128 .LBB_END0_2-_Z3bazb.cold +; CHECK-NEXT: .byte 0 +; CHECK-NEXT: .uleb128 .LBB0_3-_Z3bazb.cold +; CHECK-NEXT: .uleb128 .LBB_END0_3-.LBB0_3 +; CHECK-NEXT: .byte 5 diff --git a/llvm/test/CodeGen/X86/basic-block-sections-labels.ll b/llvm/test/CodeGen/X86/basic-block-address-map.ll rename from llvm/test/CodeGen/X86/basic-block-sections-labels.ll rename to llvm/test/CodeGen/X86/basic-block-address-map.ll --- a/llvm/test/CodeGen/X86/basic-block-sections-labels.ll +++ b/llvm/test/CodeGen/X86/basic-block-address-map.ll @@ -1,7 +1,8 @@ ; Check the basic block sections labels option -; RUN: llc < %s -mtriple=x86_64 -function-sections -unique-section-names=true -basic-block-sections=labels | FileCheck %s --check-prefix=UNIQ -; RUN: llc < %s -mtriple=x86_64 -function-sections -unique-section-names=false -basic-block-sections=labels | FileCheck %s --check-prefix=NOUNIQ -; RUN: llc < %s -mtriple=x86_64 -function-sections -unique-section-names=true -basic-block-sections=labels -split-machine-functions | FileCheck %s --check-prefix=UNIQ +; RUN: llc < %s -mtriple=x86_64 -function-sections -unique-section-names=true -basic-block-address-map | FileCheck %s --check-prefixes=CHECK,UNIQ +; RUN: llc < %s -mtriple=x86_64 -function-sections -unique-section-names=false -basic-block-address-map | FileCheck %s --check-prefixes=CHECK,NOUNIQ +; RUN: llc < %s -mtriple=x86_64 -function-sections -unique-section-names=true -basic-block-address-map -split-machine-functions | FileCheck %s --check-prefixes=CHECK,UNIQ +; RUN: llc < %s -mtriple=x86_64 -basic-block-address-map | FileCheck %s --check-prefixes=CHECK,NOFSEC define void @_Z3bazb(i1 zeroext) personality i32 (...)* @__gxx_personality_v0 { br i1 %0, label %2, label %7 @@ -31,13 +32,14 @@ declare i32 @__gxx_personality_v0(...) ; UNIQ: .section .text._Z3bazb,"ax",@progbits{{$}} -; NOUNIQ: .section .text,"ax",@progbits,unique,1 +; NOUNIQ: .section .text,"ax",@progbits,unique,1{{$}} +; NOFSEC: .text ; CHECK-LABEL: _Z3bazb: ; CHECK-LABEL: .Lfunc_begin0: ; CHECK-LABEL: .LBB_END0_0: ; CHECK-LABEL: .LBB0_1: ; CHECK-LABEL: .LBB_END0_1: -; CHECK-LABEL: .LBB0_2: +; CHECK-LABEL: .LBB0_2: ; CHECK-LABEL: .LBB_END0_2: ; CHECK-LABEL: .LBB0_3: ; CHECK-LABEL: .LBB_END0_3: @@ -45,7 +47,9 @@ ; UNIQ: .section .llvm_bb_addr_map,"o",@llvm_bb_addr_map,.text._Z3bazb{{$}} ;; Verify that with -unique-section-names=false, the unique id of the text section gets assigned to the llvm_bb_addr_map section. -; NOUNIQ: .section .llvm_bb_addr_map,"o",@llvm_bb_addr_map,.text,unique,1 +; NOUNIQ: .section .llvm_bb_addr_map,"o",@llvm_bb_addr_map,.text,unique,1{{$}} +; NOFSEC: .section .llvm_bb_addr_map,"o",@llvm_bb_addr_map,.text{{$}} +; CHECK-NEXT: .byte 1 ; CHECK-NEXT: .quad .Lfunc_begin0 ; CHECK-NEXT: .byte 4 ; CHECK-NEXT: .uleb128 .Lfunc_begin0-.Lfunc_begin0 diff --git a/llvm/test/tools/llvm-readobj/ELF/bb-addr-map.test b/llvm/test/tools/llvm-readobj/ELF/bb-addr-map.test --- a/llvm/test/tools/llvm-readobj/ELF/bb-addr-map.test +++ b/llvm/test/tools/llvm-readobj/ELF/bb-addr-map.test @@ -11,38 +11,53 @@ # RUN: llvm-readelf %t1.x32.o --bb-addr-map | FileCheck %s --check-prefix=GNU ## Check that a malformed section can be handled. -# RUN: yaml2obj %s -DBITS=32 -DSIZE=4 -o %t2.o -# RUN: llvm-readobj %t2.o --bb-addr-map 2>&1 | FileCheck %s -DOFFSET=0x00000004 -DFILE=%t2.o --check-prefix=TRUNCATED +# RUN: yaml2obj %s -DBITS=32 -DSIZE=5 -o %t2.o +# RUN: llvm-readobj %t2.o --bb-addr-map 2>&1 | FileCheck %s -DOFFSET=0x00000005 -DFILE=%t2.o --check-prefix=TRUNCATED # LLVM: BBAddrMap [ # LLVM-NEXT: Function { # LLVM-NEXT: At: [[ADDR]] -# LLVM-NEXT: BB entries [ +# LLVM-NEXT: BB Ranges [ # LLVM-NEXT: { -# LLVM-NEXT: Offset: 0x0 -# LLVM-NEXT: Size: 0x1 -# LLVM-NEXT: HasReturn: No -# LLVM-NEXT: HasTailCall: Yes -# LLVM-NEXT: IsEHPad: No +# LLVM-NEXT: Base Address: [[ADDR]] +# LLVM-NEXT: BB Entries [ +# LLVM-NEXT: { +# LLVM-NEXT: Offset: 0x0 +# LLVM-NEXT: Size: 0x1 +# LLVM-NEXT: HasReturn: No +# LLVM-NEXT: HasTailCall: Yes +# LLVM-NEXT: IsEHPad: No +# LLVM-NEXT: } +# LLVM-NEXT: ] # LLVM-NEXT: } # LLVM-NEXT: { -# LLVM-NEXT: Offset: 0x3 -# LLVM-NEXT: Size: 0x4 -# LLVM-NEXT: HasReturn: Yes -# LLVM-NEXT: HasTailCall: No -# LLVM-NEXT: IsEHPad: Yes +# LLVM-NEXT: Base Address: 0x44444 +# LLVM-NEXT: BB Entries [ +# LLVM-NEXT: { +# LLVM-NEXT: Offset: 0x3 +# LLVM-NEXT: Size: 0x4 +# LLVM-NEXT: HasReturn: Yes +# LLVM-NEXT: HasTailCall: No +# LLVM-NEXT: IsEHPad: Yes +# LLVM-NEXT: } +# LLVM-NEXT: ] # LLVM-NEXT: } # LLVM-NEXT: ] # LLVM-NEXT: } # LLVM-NEXT: Function { # LLVM-NEXT: At: 0x22222 -# LLVM-NEXT: BB entries [ +# LLVM-NEXT: BB Ranges [ # LLVM-NEXT: { -# LLVM-NEXT: Offset: 0x6 -# LLVM-NEXT: Size: 0x7 -# LLVM-NEXT: HasReturn: No -# LLVM-NEXT: HasTailCall: No -# LLVM-NEXT: IsEHPad: No +# LLVM-NEXT: Base Address: 0x22222 +# LLVM-NEXT: BB Entries [ +# LLVM-NEXT: { +# LLVM-NEXT: Offset: 0x6 +# LLVM-NEXT: Size: 0x7 +# LLVM-NEXT: HasReturn: No +# LLVM-NEXT: HasTailCall: No +# LLVM-NEXT: IsEHPad: No +# LLVM-NEXT: } +# LLVM-NEXT: ] # LLVM-NEXT: } # LLVM-NEXT: ] # LLVM-NEXT: } @@ -50,13 +65,18 @@ # LLVM-NEXT: BBAddrMap [ # LLVM-NEXT: Function { # LLVM-NEXT: At: 0x33333 -# LLVM-NEXT: BB entries [ +# LLVM-NEXT: BB Ranges [ # LLVM-NEXT: { -# LLVM-NEXT: Offset: 0x9 -# LLVM-NEXT: Size: 0xA -# LLVM-NEXT: HasReturn: Yes -# LLVM-NEXT: HasTailCall: Yes -# LLVM-NEXT: IsEHPad: No +# LLVM-NEXT: Base Address: 0x33333 +# LLVM-NEXT: BB Entries [ +# LLVM-NEXT: { +# LLVM-NEXT: Offset: 0x9 +# LLVM-NEXT: Size: 0xA +# LLVM-NEXT: HasReturn: Yes +# LLVM-NEXT: HasTailCall: Yes +# LLVM-NEXT: IsEHPad: No +# LLVM-NEXT: } +# LLVM-NEXT: ] # LLVM-NEXT: } # LLVM-NEXT: ] # LLVM-NEXT: } @@ -70,14 +90,19 @@ ## Check that the other valid section is properly dumped. # TRUNCATED-NEXT: BBAddrMap [ # TRUNCATED-NEXT: Function { -# TRUNCATED-NEXT: At: 0x33333 -# TRUNCATED-NEXT: BB entries [ -# TRUNCATED-NEXT: { -# TRUNCATED-NEXT: Offset: 0x9 -# TRUNCATED-NEXT: Size: 0xA -# TRUNCATED-NEXT: HasReturn: Yes -# TRUNCATED-NEXT: HasTailCall: Yes -# TRUNCATED-NEXT: IsEHPad: No +# TRUNCATED-NEXT: At: 0x33333 +# TRUNCATED-NEXT: BB Ranges [ +# TRUNCATED-NEXT: { +# TRUNCATED-NEXT: Base Address: 0x33333 +# TRUNCATED-NEXT: BB Entries [ +# TRUNCATED-NEXT: { +# TRUNCATED-NEXT: Offset: 0x9 +# TRUNCATED-NEXT: Size: 0xA +# TRUNCATED-NEXT: HasReturn: Yes +# TRUNCATED-NEXT: HasTailCall: Yes +# TRUNCATED-NEXT: IsEHPad: No +# TRUNCATED-NEXT: } +# TRUNCATED-NEXT: ] # TRUNCATED-NEXT: } # TRUNCATED-NEXT: ] # TRUNCATED-NEXT: } @@ -93,27 +118,32 @@ Type: SHT_LLVM_BB_ADDR_MAP ShSize: [[SIZE=]] Entries: - - Address: [[ADDR=0x11111]] - BBEntries: - - AddressOffset: 0x0 - Size: 0x1 - Metadata: 0xF0000002 - - AddressOffset: 0x3 - Size: 0x4 - Metadata: 0x5 - - Address: 0x22222 - BBEntries: - - AddressOffset: 0x6 - Size: 0x7 - Metadata: 0x8 + - BBRanges: + - BaseAddress: [[ADDR=0x11111]] + BBEntries: + - AddressOffset: 0x0 + Size: 0x1 + Metadata: 0xF0000002 + - BaseAddress: 0x44444 + BBEntries: + - AddressOffset: 0x3 + Size: 0x4 + Metadata: 0x5 + - BBRanges: + - BaseAddress: 0x22222 + BBEntries: + - AddressOffset: 0x6 + Size: 0x7 + Metadata: 0x8 - Name: dummy_section Type: SHT_PROGBITS Size: 16 - Name: bb_addr_map_2 Type: SHT_LLVM_BB_ADDR_MAP Entries: - - Address: 0x33333 - BBEntries: - - AddressOffset: 0x9 - Size: 0xa - Metadata: 0xb + - BBRanges: + - BaseAddress: 0x33333 + BBEntries: + - AddressOffset: 0x9 + Size: 0xa + Metadata: 0xb diff --git a/llvm/test/tools/obj2yaml/ELF/bb-addr-map.yaml b/llvm/test/tools/obj2yaml/ELF/bb-addr-map.yaml --- a/llvm/test/tools/obj2yaml/ELF/bb-addr-map.yaml +++ b/llvm/test/tools/obj2yaml/ELF/bb-addr-map.yaml @@ -14,22 +14,26 @@ # VALID-NEXT: - Name: .llvm_bb_addr_map # VALID-NEXT: Type: SHT_LLVM_BB_ADDR_MAP # VALID-NEXT: Entries: -## The 'Address' field is omitted when it's zero. -# VALID-NEXT: BBEntries: -# VALID-NEXT: - AddressOffset: 0x1 -# VALID-NEXT: Size: 0x2 -# VALID-NEXT: Metadata: 0x3 -# VALID-NEXT: - AddressOffset: 0x4 -# VALID-NEXT: Size: 0x5 -# VALID-NEXT: Metadata: 0x6 -# VALID-NEXT: - AddressOffset: 0xFFFFFFFFFFFFFFF7 -# VALID-NEXT: Size: 0xFFFFFFFFFFFFFFF8 -# VALID-NEXT: Metadata: 0xFFFFFFFFFFFFFFF9 -# VALID-NEXT: - Address: 0xFFFFFFFFFFFFFF20 -# VALID-NEXT: BBEntries: -# VALID-NEXT: - AddressOffset: 0xA -# VALID-NEXT: Size: 0xB -# VALID-NEXT: Metadata: 0xC +# VALID-NEXT: - BBRanges: +## The 'BaseAddress' field is omitted when it's zero. +# VALID-NEXT: - BBEntries: +# VALID-NEXT: - AddressOffset: 0x1 +# VALID-NEXT: Size: 0x2 +# VALID-NEXT: Metadata: 0x3 +# VALID-NEXT: - AddressOffset: 0x4 +# VALID-NEXT: Size: 0x5 +# VALID-NEXT: Metadata: 0x6 +# VALID-NEXT: - BaseAddress: 0xFFFFFFFFFFFFFFF7 +# VALID-NEXT: BBEntries: +# VALID-NEXT: - AddressOffset: 0xFFFFFFFFFFFFFFF8 +# VALID-NEXT: Size: 0xFFFFFFFFFFFFFFF9 +# VALID-NEXT: Metadata: 0xFFFFFFFFFFFFFFFA +# VALID-NEXT: BBRanges: +# VALID-NEXT: - BaseAddress: 0xB +# VALID-NEXT: BBEntries: +# VALID-NEXT: - AddressOffset: 0xC +# VALID-NEXT: Size: 0xD +# VALID-NEXT: Metadata: 0xE --- !ELF FileHeader: @@ -41,23 +45,28 @@ Type: SHT_LLVM_BB_ADDR_MAP ShSize: [[SIZE=]] Entries: - - Address: 0x0 - NumBlocks: [[NUMBLOCKS=]] - BBEntries: - - AddressOffset: 0x1 - Size: 0x2 - Metadata: 0x3 - - AddressOffset: 0x4 - Size: 0x5 - Metadata: 0x6 - - AddressOffset: 0xFFFFFFFFFFFFFFF7 - Size: 0xFFFFFFFFFFFFFFF8 - Metadata: 0xFFFFFFFFFFFFFFF9 - - Address: 0xFFFFFFFFFFFFFF20 - BBEntries: - - AddressOffset: 0xA - Size: 0xB - Metadata: 0xC + - BBRanges: + - BaseAddress: 0x0 + NumBlocks: [[NUMBLOCKS=]] + BBEntries: + - AddressOffset: 0x1 + Size: 0x2 + Metadata: 0x3 + - AddressOffset: 0x4 + Size: 0x5 + Metadata: 0x6 + - BaseAddress: 0xFFFFFFFFFFFFFFF7 + BBEntries: + - AddressOffset: 0xFFFFFFFFFFFFFFF8 + Size: 0xFFFFFFFFFFFFFFF9 + Metadata: 0xFFFFFFFFFFFFFFFA + - BBRanges: + - BaseAddress: 0xB + BBEntries: + - AddressOffset: 0xC + Size: 0xD + Metadata: 0xE + NumBBRanges: [[NUMBBRANGES=]] ## Check obj2yaml can dump empty .llvm_bb_addr_map sections. @@ -98,16 +107,18 @@ # MULTI-NEXT: - Name: .llvm_bb_addr_map # MULTI-NEXT: Type: SHT_LLVM_BB_ADDR_MAP # MULTI-NEXT: Entries: -## The 'Address' field is omitted when it's zero. -# MULTI-NEXT: - BBEntries: -# MULTI-NEXT: - AddressOffset: 0x1 -# MULTI-NEXT: Size: 0x2 -# MULTI-NEXT: Metadata: 0x3 +# MULTI-NEXT: - BBRanges: +## The 'BaseAddress' field is omitted when it's zero. +# MULTI-NEXT: - BBEntries: +# MULTI-NEXT: - AddressOffset: 0x1 +# MULTI-NEXT: Size: 0x2 +# MULTI-NEXT: Metadata: 0x3 # MULTI-NEXT: - Name: '.llvm_bb_addr_map (1)' # MULTI-NEXT: Type: SHT_LLVM_BB_ADDR_MAP # MULTI-NEXT: Entries: -# MULTI-NEXT: - Address: 0x20 -# MULTI-NEXT: BBEntries: [] +# MULTI-NEXT: - BBRanges: +# MULTI-NEXT: - BaseAddress: 0x20 +# MULTI-NEXT: BBEntries: [] --- !ELF FileHeader: @@ -118,16 +129,18 @@ - Name: .llvm_bb_addr_map Type: SHT_LLVM_BB_ADDR_MAP Entries: + - BBRanges: ## Check that obj2yaml does not emit the Address field when it's zero. - - Address: 0x0 - BBEntries: - - AddressOffset: 0x1 - Size: 0x2 - Metadata: 0x3 + - BaseAddress: 0x0 + BBEntries: + - AddressOffset: 0x1 + Size: 0x2 + Metadata: 0x3 - Name: '.llvm_bb_addr_map (1)' Type: SHT_LLVM_BB_ADDR_MAP Entries: - - Address: 0x20 + - BBRanges: + - BaseAddress: 0x20 ## Check that obj2yaml uses the "Content" tag to describe an .llvm_bb_addr_map section ## when it can't extract the entries, for example, when the section is truncated, or @@ -136,16 +149,20 @@ # RUN: yaml2obj --docnum=1 -DSIZE=0x8 %s -o %t4 # RUN: obj2yaml %t4 | FileCheck %s --check-prefixes=TRUNCATED,INVALID -# RUN: yaml2obj --docnum=1 -DNUMBLOCKS=2 %s -o %t5 +# RUN: yaml2obj --docnum=1 -DNUMBLOCKS=3 %s -o %t5 # RUN: obj2yaml %t5 | FileCheck %s --check-prefixes=BADNUMBLOCKS,INVALID -# INVALID: --- !ELF -# INVALID-NEXT: FileHeader: -# INVALID-NEXT: Class: ELFCLASS64 -# INVALID-NEXT: Data: ELFDATA2LSB -# INVALID-NEXT: Type: ET_EXEC -# INVALID-NEXT: Sections: -# INVALID-NEXT: - Name: .llvm_bb_addr_map -# INVALID-NEXT: Type: SHT_LLVM_BB_ADDR_MAP -# BADNUMBLOCKS-NEXT: Content: {{([[:xdigit:]]+)}}{{$}} -# TRUNCATED-NEXT: Content: '{{([[:xdigit:]]{16})}}'{{$}} +# RUN: yaml2obj --docnum=1 -DNUMBBRANGES=2 %s -o %t6 +# RUN: obj2yaml %t6 | FileCheck %s --check-prefixes=BADNUMBBRANGES,INVALID + +# INVALID: --- !ELF +# INVALID-NEXT: FileHeader: +# INVALID-NEXT: Class: ELFCLASS64 +# INVALID-NEXT: Data: ELFDATA2LSB +# INVALID-NEXT: Type: ET_EXEC +# INVALID-NEXT: Sections: +# INVALID-NEXT: - Name: .llvm_bb_addr_map +# INVALID-NEXT: Type: SHT_LLVM_BB_ADDR_MAP +# TRUNCATED-NEXT: Content: '{{([[:xdigit:]]{16})}}'{{$}} +# BADNUMBLOCKS-NEXT: Content: {{([[:xdigit:]]+)}}{{$}} +# BADNUMBBRANGES-NEXT: Content: {{([[:xdigit:]]+)}}{{$}} diff --git a/llvm/test/tools/yaml2obj/ELF/bb-addr-map.yaml b/llvm/test/tools/yaml2obj/ELF/bb-addr-map.yaml --- a/llvm/test/tools/yaml2obj/ELF/bb-addr-map.yaml +++ b/llvm/test/tools/yaml2obj/ELF/bb-addr-map.yaml @@ -36,7 +36,8 @@ # Case 4: Specify Entries. # CHECK: Name: .llvm_bb_addr_map (1) # CHECK: SectionData ( -# CHECK-NEXT: 0000: 20000000 00000000 01010203 +# CHECK-NEXT: 0000: 02200000 00000000 00010102 03400000 +# CHECK-NEXT: 0010: 00000000 00010506 07 # CHECK-NEXT: ) # Case 5: Specify Entries and omit the Address field. @@ -44,13 +45,19 @@ # CHECK: Address: # CHECK-SAME: {{^ 0x0$}} # CHECK: SectionData ( -# CHECK-NEXT: 0000: 00000000 00000000 01010203 +# CHECK-NEXT: 0000: 01000000 00000000 00010102 03 # CHECK-NEXT: ) # Case 6: Override the NumBlocks field. # CHECK: Name: .llvm_bb_addr_map (1) # CHECK: SectionData ( -# CHECK-NEXT: 0000: 20000000 00000000 02010203 +# CHECK-NEXT: 0000: 01200000 00000000 00020102 03 +# CHECK-NEXT: ) + +# Case 7: Override the NumBBRanges field. +# CHECK: Name: .llvm_bb_addr_map (1) +# CHECK: SectionData ( +# CHECK-NEXT: 0000: 02200000 00000000 00010102 03 # CHECK-NEXT: ) --- !ELF @@ -85,18 +92,25 @@ - Name: '.llvm_bb_addr_map (4)' Type: SHT_LLVM_BB_ADDR_MAP Entries: - - Address: 0x0000000000000020 - BBEntries: - - AddressOffset: 0x00000001 - Size: 0x00000002 - Metadata: 0x00000003 - -## 5) When specifying the description with Entries, the 'Address' field will be + - BBRanges: + - BaseAddress: 0x0000000000000020 + BBEntries: + - AddressOffset: 0x00000001 + Size: 0x00000002 + Metadata: 0x00000003 + - BaseAddress: 0x0000000000000040 + BBEntries: + - AddressOffset: 0x00000005 + Size: 0x00000006 + Metadata: 0x00000007 + +## 5) When specifying the description with Entries, the 'BaseAddress' field will be ## zero when omitted. - Name: '.llvm_bb_addr_map (5)' Type: SHT_LLVM_BB_ADDR_MAP Entries: - - BBEntries: + - BBRanges: + - BBEntries: - AddressOffset: 0x00000001 Size: 0x00000002 Metadata: 0x00000003 @@ -106,12 +120,28 @@ - Name: '.llvm_bb_addr_map (6)' Type: SHT_LLVM_BB_ADDR_MAP Entries: - - Address: 0x0000000000000020 - NumBlocks: 2 - BBEntries: - - AddressOffset: 0x00000001 - Size: 0x00000002 - Metadata: 0x00000003 + - BBRanges: + - BaseAddress: 0x0000000000000020 + NumBlocks: 2 + BBEntries: + - AddressOffset: 0x00000001 + Size: 0x00000002 + Metadata: 0x00000003 + +## 7) We can override the NumBBRanges field with a value different from the +## actual number of BB Ranges. + - Name: '.llvm_bb_addr_map (7)' + Type: SHT_LLVM_BB_ADDR_MAP + Entries: + - NumBBRanges: 2 + BBRanges: + - BaseAddress: 0x0000000000000020 + BBEntries: + - AddressOffset: 0x00000001 + Size: 0x00000002 + Metadata: 0x00000003 + + ## Check we can't use Entries at the same time as either Content or Size. # RUN: not yaml2obj --docnum=2 -DCONTENT="00" %s 2>&1 | FileCheck %s --check-prefix=INVALID diff --git a/llvm/tools/llvm-readobj/ELFDumper.cpp b/llvm/tools/llvm-readobj/ELFDumper.cpp --- a/llvm/tools/llvm-readobj/ELFDumper.cpp +++ b/llvm/tools/llvm-readobj/ELFDumper.cpp @@ -6518,16 +6518,24 @@ continue; } for (const Elf_BBAddrMap &AM : *BBAddrMapOrErr) { - DictScope D(W, "Function"); - W.printHex("At", AM.Addr); - ListScope L(W, "BB entries"); - for (const typename Elf_BBAddrMap::BBEntry &BBE : AM.BBEntries) { - DictScope L(W); - W.printHex("Offset", BBE.Offset); - W.printHex("Size", BBE.Size); - W.printBoolean("HasReturn", BBE.HasReturn); - W.printBoolean("HasTailCall", BBE.HasTailCall); - W.printBoolean("IsEHPad", BBE.IsEHPad); + DictScope FD(W, "Function"); + if (AM.BBRanges.empty()) + continue; + uintX_t FunctionAddress = AM.BBRanges.front().BaseAddr; + W.printHex("At", FunctionAddress); + ListScope BBRL(W, "BB Ranges"); + for (const typename Elf_BBAddrMap::BBRangeEntry &BBR : AM.BBRanges) { + DictScope BBRD(W); + W.printHex("Base Address", BBR.BaseAddr); + ListScope BBEL(W, "BB Entries"); + for (const typename Elf_BBAddrMap::BBEntry &BBE : BBR.BBEntries) { + DictScope BBED(W); + W.printHex("Offset", BBE.Offset); + W.printHex("Size", BBE.Size); + W.printBoolean("HasReturn", BBE.HasReturn); + W.printBoolean("HasTailCall", BBE.HasTailCall); + W.printBoolean("IsEHPad", BBE.IsEHPad); + } } } } diff --git a/llvm/tools/obj2yaml/elf2yaml.cpp b/llvm/tools/obj2yaml/elf2yaml.cpp --- a/llvm/tools/obj2yaml/elf2yaml.cpp +++ b/llvm/tools/obj2yaml/elf2yaml.cpp @@ -851,17 +851,22 @@ std::vector Entries; DataExtractor::Cursor Cur(0); while (Cur && Cur.tell() < Content.size()) { - uint64_t Address = Data.getAddress(Cur); - uint64_t NumBlocks = Data.getULEB128(Cur); - std::vector BBEntries; - // Read the specified number of BB entries, or until decoding fails. - for (uint64_t BlockID = 0; Cur && BlockID < NumBlocks; ++BlockID) { - uint64_t Offset = Data.getULEB128(Cur); - uint64_t Size = Data.getULEB128(Cur); - uint64_t Metadata = Data.getULEB128(Cur); - BBEntries.push_back({Offset, Size, Metadata}); + uint64_t NumBBRanges = Data.getULEB128(Cur); + std::vector BBRanges; + for (uint64_t BBRangeN = 0; Cur && BBRangeN != NumBBRanges; ++BBRangeN) { + uint64_t BaseAddress = Data.getAddress(Cur); + uint64_t NumBlocks = Data.getULEB128(Cur); + std::vector BBEntries; + // Read the specified number of BB entries, or until decoding fails. + for (uint64_t BlockID = 0; Cur && BlockID != NumBlocks; ++BlockID) { + uint64_t Offset = Data.getULEB128(Cur); + uint64_t Size = Data.getULEB128(Cur); + uint64_t Metadata = Data.getULEB128(Cur); + BBEntries.push_back({Offset, Size, Metadata}); + } + BBRanges.push_back({BaseAddress, /*NumBlocks=*/{}, BBEntries}); } - Entries.push_back({Address, /*NumBlocks=*/{}, BBEntries}); + Entries.push_back({/*NumBBRanges=*/{}, BBRanges}); } if (!Cur) { diff --git a/llvm/unittests/Object/ELFObjectFileTest.cpp b/llvm/unittests/Object/ELFObjectFileTest.cpp --- a/llvm/unittests/Object/ELFObjectFileTest.cpp +++ b/llvm/unittests/Object/ELFObjectFileTest.cpp @@ -495,11 +495,12 @@ - Name: .llvm_bb_addr_map Type: SHT_LLVM_BB_ADDR_MAP Entries: - - Address: 0x11111 - BBEntries: - - AddressOffset: 0x0 - Size: 0x1 - Metadata: 0x2 + - BBRanges: + - BaseAddress: 0x11111 + BBEntries: + - AddressOffset: 0x0 + Size: 0x1 + Metadata: 0x2 )"); auto DoCheck = [&](StringRef YamlString, const char *ErrMsg) { @@ -520,9 +521,9 @@ // truncated. SmallString<128> TruncatedYamlString(CommonYamlString); TruncatedYamlString += R"( - ShSize: 0x8 + ShSize: 0x9 )"; - DoCheck(TruncatedYamlString, "unable to decode LEB128 at offset 0x00000008: " + DoCheck(TruncatedYamlString, "unable to decode LEB128 at offset 0x00000009: " "malformed uleb128, extends past end"); // Check that we can detect when the encoded BB entry fields exceed the UINT32 @@ -530,29 +531,29 @@ SmallVector, 3> OverInt32LimitYamlStrings(3, CommonYamlString); OverInt32LimitYamlStrings[0] += R"( - - AddressOffset: 0x100000000 - Size: 0xFFFFFFFF - Metadata: 0xFFFFFFFF + - AddressOffset: 0x100000000 + Size: 0xFFFFFFFF + Metadata: 0xFFFFFFFF )"; OverInt32LimitYamlStrings[1] += R"( - - AddressOffset: 0xFFFFFFFF - Size: 0x100000000 - Metadata: 0xFFFFFFFF + - AddressOffset: 0xFFFFFFFF + Size: 0x100000000 + Metadata: 0xFFFFFFFF )"; OverInt32LimitYamlStrings[2] += R"( - - AddressOffset: 0xFFFFFFFF - Size: 0xFFFFFFFF - Metadata: 0x100000000 + - AddressOffset: 0xFFFFFFFF + Size: 0xFFFFFFFF + Metadata: 0x100000000 )"; DoCheck(OverInt32LimitYamlStrings[0], - "ULEB128 value at offset 0xc exceeds UINT32_MAX (0x100000000)"); + "ULEB128 value at offset 0xd exceeds UINT32_MAX (0x100000000)"); DoCheck(OverInt32LimitYamlStrings[1], - "ULEB128 value at offset 0x11 exceeds UINT32_MAX (0x100000000)"); + "ULEB128 value at offset 0x12 exceeds UINT32_MAX (0x100000000)"); DoCheck(OverInt32LimitYamlStrings[2], - "ULEB128 value at offset 0x16 exceeds UINT32_MAX (0x100000000)"); + "ULEB128 value at offset 0x17 exceeds UINT32_MAX (0x100000000)"); // Check the proper error handling when the section has fields exceeding // UINT32 and is also truncated. This is for checking that we don't generate @@ -561,32 +562,32 @@ 3, OverInt32LimitYamlStrings[1]); // Truncate before the end of the 5-byte field. OverInt32LimitAndTruncated[0] += R"( - ShSize: 0x15 + ShSize: 0x16 )"; // Truncate at the end of the 5-byte field. OverInt32LimitAndTruncated[1] += R"( - ShSize: 0x16 + ShSize: 0x17 )"; // Truncate after the end of the 5-byte field. OverInt32LimitAndTruncated[2] += R"( - ShSize: 0x17 + ShSize: 0x18 )"; DoCheck(OverInt32LimitAndTruncated[0], - "unable to decode LEB128 at offset 0x00000011: malformed uleb128, " + "unable to decode LEB128 at offset 0x00000012: malformed uleb128, " "extends past end"); DoCheck(OverInt32LimitAndTruncated[1], - "ULEB128 value at offset 0x11 exceeds UINT32_MAX (0x100000000)"); + "ULEB128 value at offset 0x12 exceeds UINT32_MAX (0x100000000)"); DoCheck(OverInt32LimitAndTruncated[2], - "ULEB128 value at offset 0x11 exceeds UINT32_MAX (0x100000000)"); + "ULEB128 value at offset 0x12 exceeds UINT32_MAX (0x100000000)"); // Check for proper error handling when the 'NumBlocks' field is overridden // with an out-of-range value. SmallString<128> OverLimitNumBlocks(CommonYamlString); OverLimitNumBlocks += R"( - NumBlocks: 0x100000000 + NumBlocks: 0x100000000 )"; DoCheck(OverLimitNumBlocks, - "ULEB128 value at offset 0x8 exceeds UINT32_MAX (0x100000000)"); + "ULEB128 value at offset 0x9 exceeds UINT32_MAX (0x100000000)"); }