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 @@ -114,18 +114,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 @@ -89,6 +89,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 @@ -2566,11 +2566,15 @@ NegFlag, PosFlag>; defm function_sections : OptInFFlag<"function-sections", "Place each function in its own section">; +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 @@ -515,10 +515,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 @@ -5110,11 +5110,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 @@ -1008,6 +1008,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 @@ -570,6 +570,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/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 @@ -1091,15 +1091,33 @@ OutStreamer->PushSection(); OutStreamer->SwitchSection(BBAddrMapSection); + + OutStreamer->emitULEB128IntValue(MF.hasBBSections() ? MBBSectionRanges.size() + : 1); OutStreamer->emitSymbolValue(FunctionSymbol, getPointerSize()); - // Emit the total number of basic blocks in this function. - OutStreamer->emitULEB128IntValue(MF.size()); + if (!MF.hasBBSections()) { + OutStreamer->emitULEB128IntValue(MF.size()); + } else { + unsigned BBCount = 0; + for (const MachineBasicBlock &MBB : MF) { + BBCount++; + if (MBB.isBeginSection() && !MBB.isEntryBlock()) + OutStreamer->emitSymbolValue(MBB.getSymbol(), getPointerSize()); + // Emit the total number of basic blocks in this section. + if (MBB.isEndSection()) { + OutStreamer->emitULEB128IntValue(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(); // 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); @@ -1280,7 +1298,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()); @@ -1420,7 +1438,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. @@ -1892,7 +1910,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; @@ -3249,7 +3268,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/BasicBlockRenumbering.cpp b/llvm/lib/CodeGen/BasicBlockRenumbering.cpp new file mode 100644 --- /dev/null +++ b/llvm/lib/CodeGen/BasicBlockRenumbering.cpp @@ -0,0 +1,30 @@ +//===-- BasicBlockRenumbering ---=========---------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineFunctionPass.h" +#include "llvm/CodeGen/Passes.h" + +using namespace llvm; + +class BasicBlockRenumbering : public MachineFunctionPass { +public: + static char ID; + BasicBlockRenumbering() : MachineFunctionPass(ID) {} + + bool runOnMachineFunction(MachineFunction &MF) override { + MF.RenumberBlocks(); + return true; + } +}; + +char BasicBlockRenumbering::ID = 0; + +MachineFunctionPass *llvm::createBasicBlockRenumberingPass() { + return new BasicBlockRenumbering(); +} 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 @@ -48,11 +48,11 @@ // Basic Block Labels // ================== // -// With -fbasic-block-sections=labels, 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``. +// With -fbasic-block-labels, 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 does not run when -fbasic-block-labels is specified. // //===----------------------------------------------------------------------===// @@ -355,17 +355,6 @@ hasInstrProfHashMismatch(MF)) return true; - // 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. - MF.RenumberBlocks(); - - if (BBSectionsType == BasicBlockSection::Labels) { - MF.setBBSectionsType(BBSectionsType); - return true; - } - std::vector> FuncBBClusterInfo; if (BBSectionsType == BasicBlockSection::List && !getBBClusterInfoForFunction(MF, FuncAliasMap, ProgramBBClusterInfo, diff --git a/llvm/lib/CodeGen/CMakeLists.txt b/llvm/lib/CodeGen/CMakeLists.txt --- a/llvm/lib/CodeGen/CMakeLists.txt +++ b/llvm/lib/CodeGen/CMakeLists.txt @@ -8,6 +8,7 @@ BranchRelaxation.cpp BreakFalseDeps.cpp BuiltinGCs.cpp + BasicBlockRenumbering.cpp BasicBlockSections.cpp CalcSpillWeights.cpp CallingConvLower.cpp 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 @@ -1191,15 +1191,24 @@ // 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) { + + if (TM->getBBSectionsType() == llvm::BasicBlockSection::List) + // 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. + addPass(createBasicBlockRenumberingPass()); + addPass(llvm::createBasicBlockSectionsPass(TM->getBBSectionsFuncListBuf())); } else if (TM->Options.EnableMachineFunctionSplitter || EnableMachineFunctionSplitter) { addPass(createMachineFunctionSplitterPass()); } + if (TM->Options.BasicBlockLabels) + addPass(createBasicBlockRenumberingPass()); + // Add passes that directly emit MI after all other MI passes. addPreEmitPass2(); 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. - uint32_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. + uint32_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 @@ -1664,7 +1664,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: .quad _Z3bazb.cold +; 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: .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/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,7 @@ # Case 4: Specify Entries. # CHECK: Name: .llvm_bb_addr_map (1) # CHECK: SectionData ( -# CHECK-NEXT: 0000: 20000000 00000000 01010203 +# CHECK-NEXT: 0000: 01200000 00000000 00010102 03 # CHECK-NEXT: ) # Case 5: Specify Entries and omit the Address field. @@ -44,13 +44,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 +91,20 @@ - 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 + +## 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 +114,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/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) {