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 @@ -115,18 +115,13 @@ // This field stores one of the allowed values for the option // -fbasic-block-sections=. The allowed values with this option are: - // {"labels", "all", "list=", "none"}. + // {"all", "list=", "none"}. // - // "labels": Only generate basic block symbols (labels) for all basic - // blocks, do not generate unique sections for basic blocks. - // Use the machine basic block id in the symbol name to - // associate profile info from virtual address to machine - // basic block. // "all" : Generate basic block sections for all basic blocks. // "list=": Generate basic block sections for a subset of basic blocks. // The functions and the machine basic block ids are specified // in the file. - // "none": Disable sections/labels for basic blocks. + // "none": Disable sections for basic blocks. std::string BBSections; // If set, override the default value of MCAsmInfo::BinutilsVersion. If 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(BasicBlockLabels , 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 @@ -2620,11 +2620,15 @@ CodeGenOpts<"FunctionSections">, DefaultFalse, PosFlag, NegFlag>; +defm basic_block_labels : BoolFOption<"basic-block-labels", + CodeGenOpts<"BasicBlockLabels">, 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=">, - DocBrief<[{Generate labels for each basic block or place each basic block or a subset of basic blocks in its own section.}]>, - Values<"all,labels,none,list=">, + HelpText<"Place each function's basic blocks in unique sections (ELF Only) : all | none | list=">, + DocBrief<[{Place each basic block or a subset of basic blocks in its own section.}]>, + Values<"all,none,list=">, MarshallingInfoString, [{"none"}]>; defm data_sections : BoolFOption<"data-sections", CodeGenOpts<"DataSections">, 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 @@ -527,10 +527,10 @@ Options.UnsafeFPMath = LangOpts.UnsafeFPMath; Options.StackAlignmentOverride = CodeGenOpts.StackAlignment; + Options.BasicBlockLabels = CodeGenOpts.BasicBlockLabels; Options.BBSections = llvm::StringSwitch(CodeGenOpts.BBSections) .Case("all", llvm::BasicBlockSection::All) - .Case("labels", llvm::BasicBlockSection::Labels) .StartsWith("list=", llvm::BasicBlockSection::List) .Case("none", llvm::BasicBlockSection::None) .Default(llvm::BasicBlockSection::None); 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 @@ -5132,11 +5132,21 @@ CmdArgs.push_back("-ffunction-sections"); } + if (Arg *A = Args.getLastArg(options::OPT_fbasic_block_labels, + options::OPT_fno_basic_block_labels)) { + if (Triple.isX86() && Triple.isOSBinFormatELF()) { + if (A->getOption().matches(options::OPT_fbasic_block_labels)) + 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(); - if (Val != "all" && Val != "labels" && Val != "none" && - !Val.startswith("list=")) + if (Val != "all" && Val != "none" && !Val.startswith("list=")) D.Diag(diag::err_drv_invalid_value) << A->getAsString(Args) << A->getValue(); else diff --git a/clang/test/Driver/basic-block-labels.c b/clang/test/Driver/basic-block-labels.c new file mode 100644 --- /dev/null +++ b/clang/test/Driver/basic-block-labels.c @@ -0,0 +1,8 @@ +// RUN: %clang -### -target x86_64 -fbasic-block-labels %s -S 2>&1 | FileCheck -check-prefix=CHECK-PRESENT %s +// CHECK-PRESENT: -fbasic-block-labels + +// RUN: %clang -### -target x86_64 -fno-basic-block-labels %s -S 2>&1 | FileCheck %s --check-prefix=CHECK-ABSENT +// CHECK-ABSENT-NOT: -fbasic-block-labels + +// RUN: not %clang -c -target x86_64-apple-darwin10 -fbasic-block-labels %s -S 2>&1 | FileCheck -check-prefix=CHECK-TRIPLE %s +// CHECK-TRIPLE: error: unsupported option '-fbasic-block-labels' for target diff --git a/clang/test/Driver/fbasic-block-sections.c b/clang/test/Driver/fbasic-block-sections.c --- a/clang/test/Driver/fbasic-block-sections.c +++ b/clang/test/Driver/fbasic-block-sections.c @@ -1,7 +1,6 @@ // RUN: %clang -### -target x86_64 -fbasic-block-sections=none %s -S 2>&1 | FileCheck -check-prefix=CHECK-OPT-NONE %s // RUN: %clang -### -target x86_64 -fbasic-block-sections=all %s -S 2>&1 | FileCheck -check-prefix=CHECK-OPT-ALL %s // RUN: %clang -### -target x86_64 -fbasic-block-sections=list=%s %s -S 2>&1 | FileCheck -check-prefix=CHECK-OPT-LIST %s -// RUN: %clang -### -target x86_64 -fbasic-block-sections=labels %s -S 2>&1 | FileCheck -check-prefix=CHECK-OPT-LABELS %s // RUN: not %clang -c -target arm-unknown-linux -fbasic-block-sections=all %s -S 2>&1 | FileCheck -check-prefix=CHECK-TRIPLE %s // RUN: not %clang -c -target x86_64-apple-darwin10 -fbasic-block-sections=all %s -S 2>&1 | FileCheck -check-prefix=CHECK-TRIPLE %s // RUN: %clang -### -target x86_64 -fbasic-block-sections=alll %s -S 2>&1 | FileCheck -check-prefix=CHECK-INVALID-VALUE %s @@ -11,7 +10,6 @@ // CHECK-OPT-NONE: "-fbasic-block-sections=none" // CHECK-OPT-ALL: "-fbasic-block-sections=all" // CHECK-OPT-LIST: "-fbasic-block-sections={{[^ ]*}}fbasic-block-sections.c" -// CHECK-OPT-LABELS: "-fbasic-block-sections=labels" // CHECK-TRIPLE: error: unsupported option '-fbasic-block-sections=all' for target // CHECK-INVALID-VALUE: error: invalid value {{[^ ]*}} in '-fbasic-block-sections={{.*}}' // CHECK-OPT-NULL-LIST: "-fbasic-block-sections=list=" 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 ltoBasicBlockLabels; 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,8 @@ config->ltoPseudoProbeForProfiling = args.hasArg(OPT_lto_pseudo_probe_for_profiling); config->ltoSampleProfile = args.getLastArgValue(OPT_lto_sample_profile); + config->ltoBasicBlockLabels = args.hasFlag( + OPT_lto_basic_block_labels, OPT_no_lto_basic_block_labels, 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,15 +88,15 @@ c.Options.FunctionSections = true; c.Options.DataSections = true; + c.Options.BasicBlockLabels = config->ltoBasicBlockLabels; + // Check if basic block sections must be used. - // Allowed values for --lto-basic-block-sections are "all", "labels", + // Allowed values for --lto-basic-block-sections are "all", // "", or none. This is the equivalent // of -fbasic-block-sections= flag in clang. if (!config->ltoBasicBlockSections.empty()) { if (config->ltoBasicBlockSections == "all") { c.Options.BBSections = BasicBlockSection::All; - } else if (config->ltoBasicBlockSections == "labels") { - c.Options.BBSections = BasicBlockSection::Labels; } else if (config->ltoBasicBlockSections == "none") { c.Options.BBSections = BasicBlockSection::None; } else { 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_labels: BB<"lto-basic-block-labels", + "Enable basic block labels for LTO", + "Do not enable basic block labels 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-labels.ll b/lld/test/ELF/lto/basic-block-labels.ll new file mode 100644 --- /dev/null +++ b/lld/test/ELF/lto/basic-block-labels.ll @@ -0,0 +1,28 @@ +; REQUIRES: x86 +; RUN: llvm-as %s -o %t.o +; RUN: ld.lld %t.o -o %t --lto-basic-block-labels --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 getEnableBasicBlockLabels(); + llvm::BasicBlockSection getBBSectionsMode(llvm::TargetOptions &Options); llvm::StackProtectorGuards diff --git a/llvm/include/llvm/CodeGen/MachineFunction.h b/llvm/include/llvm/CodeGen/MachineFunction.h --- a/llvm/include/llvm/CodeGen/MachineFunction.h +++ b/llvm/include/llvm/CodeGen/MachineFunction.h @@ -536,11 +536,6 @@ BBSectionsType == BasicBlockSection::Preset); } - /// Returns true if basic block labels are to be generated for this function. - bool hasBBLabels() const { - return BBSectionsType == BasicBlockSection::Labels; - } - void setBBSectionsType(BasicBlockSection V) { BBSectionsType = V; } /// Assign IsBeginSection IsEndSection fields for basic blocks in this diff --git a/llvm/include/llvm/CodeGen/Passes.h b/llvm/include/llvm/CodeGen/Passes.h --- a/llvm/include/llvm/CodeGen/Passes.h +++ b/llvm/include/llvm/CodeGen/Passes.h @@ -44,6 +44,10 @@ /// the entry block. FunctionPass *createUnreachableBlockEliminationPass(); + /// createBasicBlockRenumberingPass - This pass simply renumbers machine basic + /// blocks in all functions. + MachineFunctionPass *createBasicBlockRenumberingPass(); + /// createBasicBlockSections Pass - This pass assigns sections to machine /// basic blocks and is enabled with -fbasic-block-sections. Buf is a memory /// buffer that contains the list of functions and basic block ids to 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 @@ -64,9 +64,6 @@ List, // Get list of functions & BBs from a file. Selectively enables // 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. 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 +133,7 @@ EmulatedTLS(false), ExplicitEmulatedTLS(false), EnableIPRA(false), EmitStackSizeSection(false), EnableMachineOutliner(false), EnableMachineFunctionSplitter(false), SupportsDefaultOutlining(false), - EmitAddrsig(false), EmitCallSiteInfo(false), + EmitAddrsig(false), BasicBlockLabels(false), EmitCallSiteInfo(false), SupportsDebugEntryValues(false), EnableDebugEntryValues(false), PseudoProbeForProfiling(false), ValueTrackingVariableLocations(false), ForceDwarfFrameSection(false), XRayOmitFunctionIndex(false), @@ -294,6 +291,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 BasicBlockLabels : 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.BasicBlockLabels || (MAI->hasDotTypeDotSizeDirective() && MBB.isEndSection() && !MBB.sameSection(&MF->front()))) OutStreamer->emitLabel(MBB.getEndSymbol()); @@ -1430,7 +1458,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.BasicBlockLabels) emitBBAddrMapSection(*MF); // Emit section containing stack size metadata. @@ -1902,7 +1930,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.BasicBlockLabels) { CurrentFnBegin = createTempSymbol("func_begin"); if (NeedsLocalForSize) CurrentFnSymForSize = CurrentFnBegin; @@ -3259,7 +3288,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.BasicBlockLabels || 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 @@ -52,7 +52,7 @@ // 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 handleBBLabels(MachineFunction &MF); + bool runOnMachineFunction(MachineFunction &MF) override; }; @@ -340,10 +344,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. @@ -353,24 +359,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); @@ -416,6 +416,26 @@ return true; } +// When basic block labels need 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::handleBBLabels(MachineFunction &MF) { + if (MF.getTarget().Options.BasicBlockLabels) { + MF.RenumberBlocks(); + return true; + } + return false; +} + +bool BasicBlockSections::runOnMachineFunction(MachineFunction &MF) { + // First handle the basic block sections. + auto R1 = handleBBSections(MF); + // Handle basic block labels after basic block sections are finalized. + auto R2 = handleBBLabels(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, EnableBasicBlockLabels) CGOPT(std::string, BBSections) CGOPT(std::string, StackProtectorGuard) CGOPT(unsigned, StackProtectorGuardOffset) @@ -357,11 +358,16 @@ cl::init(true)); CGBINDOPT(XCOFFTracebackTable); + static cl::opt EnableBasicBlockLabels( + "basic-block-labels", + cl::desc("Emit a section containing basic block address offsets"), + cl::init(false)); + CGBINDOPT(EnableBasicBlockLabels); + static cl::opt BBSections( "basic-block-sections", cl::desc("Emit basic blocks into separate sections"), - cl::value_desc("all | | labels | none"), - cl::init("none")); + cl::value_desc("all | | none"), cl::init("none")); CGBINDOPT(BBSections); static cl::opt StackProtectorGuard( @@ -478,8 +484,6 @@ codegen::getBBSectionsMode(llvm::TargetOptions &Options) { if (getBBSections() == "all") return BasicBlockSection::All; - else if (getBBSections() == "labels") - return BasicBlockSection::Labels; else if (getBBSections() == "none") return BasicBlockSection::None; else { @@ -546,6 +550,7 @@ Options.FunctionSections = getFunctionSections(); Options.IgnoreXCOFFVisibility = getIgnoreXCOFFVisibility(); Options.XCOFFTracebackTable = getXCOFFTracebackTable(); + Options.BasicBlockLabels = getEnableBasicBlockLabels(); Options.BBSections = getBBSectionsMode(Options); Options.UniqueSectionNames = getUniqueSectionNames(); Options.UniqueBasicBlockSectionNames = getUniqueBasicBlockSectionNames(); diff --git a/llvm/lib/CodeGen/MIRParser/MIRParser.cpp b/llvm/lib/CodeGen/MIRParser/MIRParser.cpp --- a/llvm/lib/CodeGen/MIRParser/MIRParser.cpp +++ b/llvm/lib/CodeGen/MIRParser/MIRParser.cpp @@ -471,11 +471,8 @@ return true; } // Check Basic Block Section Flags. - if (MF.getTarget().getBBSectionsType() == BasicBlockSection::Labels) { - MF.setBBSectionsType(BasicBlockSection::Labels); - } else if (MF.hasBBSections()) { + if (MF.hasBBSections()) MF.assignBeginEndSections(); - } PFS.SM = &SM; // Initialize the frame information after creating all the MBBs so that the 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.BasicBlockLabels) + 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 @@ -1667,7 +1667,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-labels-function-sections.ll rename from llvm/test/CodeGen/X86/basic-block-sections-labels-functions-sections.ll rename to llvm/test/CodeGen/X86/basic-block-labels-function-sections.ll --- a/llvm/test/CodeGen/X86/basic-block-sections-labels-functions-sections.ll +++ b/llvm/test/CodeGen/X86/basic-block-labels-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-labels | 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-labels-with-sections.ll b/llvm/test/CodeGen/X86/basic-block-labels-with-sections.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/X86/basic-block-labels-with-sections.ll @@ -0,0 +1,64 @@ +;; Check that the basic-block-labels 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-labels -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-labels.ll rename from llvm/test/CodeGen/X86/basic-block-sections-labels.ll rename to llvm/test/CodeGen/X86/basic-block-labels.ll --- a/llvm/test/CodeGen/X86/basic-block-sections-labels.ll +++ b/llvm/test/CodeGen/X86/basic-block-labels.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-labels | FileCheck %s --check-prefixes=CHECK,UNIQ +; RUN: llc < %s -mtriple=x86_64 -function-sections -unique-section-names=false -basic-block-labels | FileCheck %s --check-prefixes=CHECK,NOUNIQ +; RUN: llc < %s -mtriple=x86_64 -function-sections -unique-section-names=true -basic-block-labels -split-machine-functions | FileCheck %s --check-prefixes=CHECK,UNIQ +; RUN: llc < %s -mtriple=x86_64 -basic-block-labels | 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 @@ -6539,16 +6539,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)"); }