Index: clang/include/clang/Basic/CodeGenOptions.h =================================================================== --- clang/include/clang/Basic/CodeGenOptions.h +++ clang/include/clang/Basic/CodeGenOptions.h @@ -118,6 +118,9 @@ enum class SignReturnAddressKeyValue { AKey, BKey }; + // Allowed values are {"all", "labels", "none", ""} + std::string BBSections; + enum class FramePointerKind { None, // Omit all frame pointers. NonLeaf, // Keep non-leaf frame pointers. Index: clang/include/clang/Basic/CodeGenOptions.def =================================================================== --- clang/include/clang/Basic/CodeGenOptions.def +++ clang/include/clang/Basic/CodeGenOptions.def @@ -48,6 +48,9 @@ ///< aliases to base ctors when possible. CODEGENOPT(DataSections , 1, 0) ///< Set when -fdata-sections is enabled. CODEGENOPT(UniqueSectionNames, 1, 1) ///< Set for -funique-section-names. +CODEGENOPT(UniqueBBSectionNames, 1, 1) ///< Set for -funique-bb-section-names, + ///< Produce unique section names with + ///< basic block sections. ENUM_CODEGENOPT(FramePointer, FramePointerKind, 2, FramePointerKind::None) /// frame-pointer: all,non-leaf,none CODEGENOPT(DisableFree , 1, 0) ///< Don't free memory. Index: clang/include/clang/Driver/Options.td =================================================================== --- clang/include/clang/Driver/Options.td +++ clang/include/clang/Driver/Options.td @@ -1937,6 +1937,8 @@ HelpText<"Place each function in its own section (ELF Only)">; def fno_function_sections : Flag<["-"], "fno-function-sections">, Group, Flags<[CC1Option]>; +def fbasicblock_sections_EQ : Joined<["-"], "fbasicblock-sections=">, Group, Flags<[CC1Option, CC1AsOption]>, + HelpText<"Place each function's basic blocks in unique sections (ELF Only) : all | labels | none | ">; def fdata_sections : Flag <["-"], "fdata-sections">, Group, Flags<[CC1Option]>, HelpText<"Place each data in its own section (ELF Only)">; def fno_data_sections : Flag <["-"], "fno-data-sections">, Group, @@ -1952,6 +1954,11 @@ def fno_unique_section_names : Flag <["-"], "fno-unique-section-names">, Group, Flags<[CC1Option]>; +def funique_bb_section_names : Flag <["-"], "funique-bb-section-names">, + Group, Flags<[CC1Option]>, + HelpText<"Use unique names for basic block sections (ELF Only)">; +def fno_unique_bb_section_names : Flag <["-"], "fno-unique-bb-section-names">, + Group, Flags<[CC1Option]>; def fstrict_return : Flag<["-"], "fstrict-return">, Group, Flags<[CC1Option]>, HelpText<"Always treat control flow paths that fall off the end of a " Index: clang/lib/CodeGen/BackendUtil.cpp =================================================================== --- clang/lib/CodeGen/BackendUtil.cpp +++ clang/lib/CodeGen/BackendUtil.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "clang/CodeGen/BackendUtil.h" +#include "fstream" #include "clang/Basic/CodeGenOptions.h" #include "clang/Basic/Diagnostic.h" #include "clang/Basic/LangOptions.h" @@ -413,6 +414,56 @@ } } +// 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 +// functions can also be specified for a finer granularity. +// A file with basic block sections for all of function main and two blocks for +// function foo looks like this: +// ---------------------------- +// list.txt: +// !main +// !foo +// !!2 +// !!4 +static bool getBBSectionsList(llvm::TargetOptions &Options, + std::string FunctionsListFile) { + assert((Options.BBSections == llvm::BasicBlockSection::List) && + "Invalid BasicBlock Section Type"); + if (FunctionsListFile.empty()) + return false; + + std::ifstream fin(FunctionsListFile); + if (!fin.good()) { + errs() << "Cannot open " + FunctionsListFile; + return false; + } + StringMap>::iterator fi = Options.BBSectionsList.end(); + std::string line; + while ((std::getline(fin, line)).good()) { + StringRef S(line); + // Lines beginning with @, # are not useful here. + if (S.empty() || S[0] == '@' || S[0] == '#') + continue; + if (!S.consume_front("!") || S.empty()) + break; + if (S.consume_front("!")) { + if (fi != Options.BBSectionsList.end()) + fi->second.insert(std::stoi(S)); + else { + errs() << "Found \"!!\" without preceding \"!\""; + return false; + } + } else { + // Start a new function. + auto R = Options.BBSectionsList.try_emplace(S.split('/').first); + fi = R.first; + assert(R.second); + } + } + return true; +} + static void initTargetOptions(llvm::TargetOptions &Options, const CodeGenOptions &CodeGenOpts, const clang::TargetOptions &TargetOpts, @@ -471,9 +522,21 @@ Options.NoZerosInBSS = CodeGenOpts.NoZeroInitializedInBSS; Options.UnsafeFPMath = CodeGenOpts.UnsafeFPMath; Options.StackAlignmentOverride = CodeGenOpts.StackAlignment; + + Options.BBSections = llvm::StringSwitch( + CodeGenOpts.BBSections) + .Case("all", llvm::BasicBlockSection::All) + .Case("labels", llvm::BasicBlockSection::Labels) + .Case("none", llvm::BasicBlockSection::None) + .Default(llvm::BasicBlockSection::List); + + if (Options.BBSections == llvm::BasicBlockSection::List) + getBBSectionsList(Options, CodeGenOpts.BBSections); + Options.FunctionSections = CodeGenOpts.FunctionSections; Options.DataSections = CodeGenOpts.DataSections; Options.UniqueSectionNames = CodeGenOpts.UniqueSectionNames; + Options.UniqueBBSectionNames = CodeGenOpts.UniqueBBSectionNames; Options.TLSSize = CodeGenOpts.TLSSize; Options.EmulatedTLS = CodeGenOpts.EmulatedTLS; Options.ExplicitEmulatedTLS = CodeGenOpts.ExplicitEmulatedTLS; Index: clang/lib/Driver/ToolChains/Clang.cpp =================================================================== --- clang/lib/Driver/ToolChains/Clang.cpp +++ clang/lib/Driver/ToolChains/Clang.cpp @@ -4153,8 +4153,11 @@ options::OPT_fno_function_sections, options::OPT_fdata_sections, options::OPT_fno_data_sections, + options::OPT_fbasicblock_sections_EQ, options::OPT_funique_section_names, options::OPT_fno_unique_section_names, + options::OPT_funique_bb_section_names, + options::OPT_fno_unique_bb_section_names, options::OPT_mrestrict_it, options::OPT_mno_restrict_it, options::OPT_mstackrealign, @@ -4686,6 +4689,11 @@ CmdArgs.push_back("-ffunction-sections"); } + if (Arg *A = Args.getLastArg(options::OPT_fbasicblock_sections_EQ)) { + CmdArgs.push_back( + Args.MakeArgString(Twine("-fbasicblock-sections=") + A->getValue())); + } + if (Args.hasFlag(options::OPT_fdata_sections, options::OPT_fno_data_sections, UseSeparateSections)) { CmdArgs.push_back("-fdata-sections"); @@ -4694,6 +4702,11 @@ if (!Args.hasFlag(options::OPT_funique_section_names, options::OPT_fno_unique_section_names, true)) CmdArgs.push_back("-fno-unique-section-names"); + + if (Args.hasFlag(options::OPT_funique_bb_section_names, + options::OPT_fno_unique_bb_section_names, false)) + CmdArgs.push_back("-funique-bb-section-names"); + Args.AddLastArg(CmdArgs, options::OPT_finstrument_functions, options::OPT_finstrument_functions_after_inlining, options::OPT_finstrument_function_entry_bare); Index: clang/lib/Frontend/CompilerInvocation.cpp =================================================================== --- clang/lib/Frontend/CompilerInvocation.cpp +++ clang/lib/Frontend/CompilerInvocation.cpp @@ -955,14 +955,27 @@ Opts.TrapFuncName = Args.getLastArgValue(OPT_ftrap_function_EQ); Opts.UseInitArray = !Args.hasArg(OPT_fno_use_init_array); - Opts.FunctionSections = Args.hasFlag(OPT_ffunction_sections, - OPT_fno_function_sections, false); + Opts.BBSections = Args.getLastArgValue(OPT_fbasicblock_sections_EQ, "none"); + if (Opts.BBSections != "all" && Opts.BBSections != "labels" && + Opts.BBSections != "none" && !llvm::sys::fs::exists(Opts.BBSections)) { + Diags.Report(diag::err_drv_invalid_value) + << Args.getLastArg(OPT_fbasicblock_sections_EQ)->getAsString(Args) + << Opts.BBSections; + } + + // Basic Block Sections implies Function Sections. + Opts.FunctionSections = + Args.hasFlag(OPT_ffunction_sections, OPT_fno_function_sections, false) || + (Opts.BBSections != "none" && Opts.BBSections != "labels"); + Opts.DataSections = Args.hasFlag(OPT_fdata_sections, OPT_fno_data_sections, false); Opts.StackSizeSection = Args.hasFlag(OPT_fstack_size_section, OPT_fno_stack_size_section, false); Opts.UniqueSectionNames = Args.hasFlag(OPT_funique_section_names, OPT_fno_unique_section_names, true); + Opts.UniqueBBSectionNames = Args.hasFlag( + OPT_funique_bb_section_names, OPT_fno_unique_bb_section_names, false); Opts.MergeFunctions = Args.hasArg(OPT_fmerge_functions); Index: clang/test/CodeGen/basicblock-sections.c =================================================================== --- /dev/null +++ clang/test/CodeGen/basicblock-sections.c @@ -0,0 +1,47 @@ +// REQUIRES: x86-registered-target + +// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -S -o - < %s | FileCheck %s --check-prefix=PLAIN +// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -S -fbasicblock-sections=all -fbasicblock-sections=none -o - < %s | FileCheck %s --check-prefix=PLAIN + +// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -S -fbasicblock-sections=labels -o - < %s | FileCheck %s --check-prefix=BB_LABELS +// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -S -fbasicblock-sections=all -o - < %s | FileCheck %s --check-prefix=BB_WORLD --check-prefix=BB_ALL +// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -S -fbasicblock-sections=%S/basicblock-sections.funcnames -o - < %s | FileCheck %s --check-prefix=BB_WORLD --check-prefix=BB_LIST +// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -S -fbasicblock-sections=all -funique-bb-section-names -o - < %s | FileCheck %s --check-prefix=UNIQUE + +int world(int a) { + if (a > 10) + return 10; + else if (a > 5) + return 5; + else + return 0; +} + +int another(int a) { + if (a > 10) + return 20; + return 0; +} + +// PLAIN-NOT: section +// PLAIN: world +// +// BB_LABELS-NOT: section +// BB_LABELS: world +// BB_LABELS-LABEL: a.BB.world +// BB_LABELS-LABEL: aa.BB.world +// BB_LABEL-LABEL: a.BB.another +// +// BB_WORLD: .section .text.world,"ax",@progbits +// BB_WORLD: world +// BB_WORLD: .section .text.world,"ax",@progbits,unique +// BB_WORLD: a.BB.world +// BB_WORLD: .section .text.another,"ax",@progbits +// BB_ALL: .section .text.another,"ax",@progbits,unique +// BB_ALL: a.BB.another +// BB_LIST-NOT: .section .text.another,"ax",@progbits,unique +// BB_LIST: another +// BB_LIST-NOT: a.BB.another +// +// UNIQUE: .section .text.world.a.BB.world +// UNIQUE: .section .text.another.a.BB.another