Skip to content

Commit

Permalink
[AsmPrinter][ELF] Support profile-guided section prefix for jump tabl…
Browse files Browse the repository at this point in the history
…es' (read-only) data sections (#122215)

#122183 adds a codegen pass to
infer machine jump table entry's hotness from the MBB hotness. This is a
follow-up PR to produce `.hot` and or `.unlikely` section prefix for
jump table's (read-only) data sections in the relocatable `.o` files.

When this patch is enabled, linker will see {`.rodata`, `.rodata.hot`,
`.rodata.unlikely`} in input sections. It can map `.rodata.hot` and
`.rodata` in the input sections to `.rodata.hot` in the executable, and
map `.rodata.unlikely` into `.rodata` with a pending extension to
`--keep-text-section-prefix` like
059e7cb,
or with a linker script.

1. To partition hot and jump tables, the AsmPrinter pass slices a function's jump table indices into two groups, one for hot and the other for cold jump tables. It then emits hot jump tables into a `.hot`-prefixed data section and cold ones into a `.unlikely`-prefixed data section, retaining the relative order of `LJT<N>` labels within each group.

2. [ELF only] To have data sections with _dynamic_ names (e.g., `.rodata.hot[.func]`), we implement
`TargetLoweringObjectFile::getSectionForJumpTable` method that accepts a `MachineJumpTableEntry` parameter, and update `selectELFSectionForGlobal` to generate `.hot` or `.unlikely` based on
MJTE's hotness.
    - The dynamic JT section name doesn't depend on `-ffunction-section=true` or `-funique-section-names=true`, even though it leverages the similar underlying mechanism to have a MCSection with on-demand name as `-ffunction-section` does.

3. The new code path is off by default.
    - Typically, `TargetOptions` conveys clang or LLVM tools' options to code generation passes. To follow the pattern, add option `EnableStaticDataPartitioning` bit in `TargetOptions` and make it
readable through `TargetMachine`.
    - To enable the new code path in tools like `llc`, `partition-static-data-sections` option is introduced in
`CodeGen/CommandFlags.h/cpp`.
    -  A subsequent patch
([draft](8f36a13)) will add a clang option to enable the new code path.

---------

Co-authored-by: Ellis Hoag <[email protected]>
  • Loading branch information
mingmingl-llvm and ellishg authored Jan 29, 2025
1 parent 77e44e5 commit 3feb724
Show file tree
Hide file tree
Showing 12 changed files with 173 additions and 49 deletions.
2 changes: 2 additions & 0 deletions llvm/include/llvm/CodeGen/CommandFlags.h
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,8 @@ bool getEmitCallSiteInfo();

bool getEnableMachineFunctionSplitter();

bool getEnableStaticDataPartitioning();

bool getEnableDebugEntryValues();

bool getValueTrackingVariableLocations();
Expand Down
3 changes: 3 additions & 0 deletions llvm/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,9 @@ class TargetLoweringObjectFileELF : public TargetLoweringObjectFile {

MCSection *getSectionForJumpTable(const Function &F,
const TargetMachine &TM) const override;
MCSection *
getSectionForJumpTable(const Function &F, const TargetMachine &TM,
const MachineJumpTableEntry *JTE) const override;
MCSection *getSectionForLSDA(const Function &F, const MCSymbol &FnSym,
const TargetMachine &TM) const override;

Expand Down
5 changes: 5 additions & 0 deletions llvm/include/llvm/Target/TargetLoweringObjectFile.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
namespace llvm {

struct Align;
struct MachineJumpTableEntry;
class Constant;
class DataLayout;
class Function;
Expand Down Expand Up @@ -135,6 +136,10 @@ class TargetLoweringObjectFile : public MCObjectFileInfo {

virtual MCSection *getSectionForJumpTable(const Function &F,
const TargetMachine &TM) const;
virtual MCSection *
getSectionForJumpTable(const Function &F, const TargetMachine &TM,
const MachineJumpTableEntry *JTE) const;

virtual MCSection *getSectionForLSDA(const Function &, const MCSymbol &,
const TargetMachine &) const {
return LSDASection;
Expand Down
4 changes: 4 additions & 0 deletions llvm/include/llvm/Target/TargetMachine.h
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,10 @@ class TargetMachine {
return Options.FunctionSections;
}

bool getEnableStaticDataPartitioning() const {
return Options.EnableStaticDataPartitioning;
}

/// Return true if visibility attribute should not be emitted in XCOFF,
/// corresponding to -mignore-xcoff-visibility.
bool getIgnoreXCOFFVisibility() const {
Expand Down
6 changes: 5 additions & 1 deletion llvm/include/llvm/Target/TargetOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,8 @@ namespace llvm {
TrapUnreachable(false), NoTrapAfterNoreturn(false), TLSSize(0),
EmulatedTLS(false), EnableTLSDESC(false), EnableIPRA(false),
EmitStackSizeSection(false), EnableMachineOutliner(false),
EnableMachineFunctionSplitter(false), SupportsDefaultOutlining(false),
EnableMachineFunctionSplitter(false),
EnableStaticDataPartitioning(false), SupportsDefaultOutlining(false),
EmitAddrsig(false), BBAddrMap(false), EmitCallSiteInfo(false),
SupportsDebugEntryValues(false), EnableDebugEntryValues(false),
ValueTrackingVariableLocations(false), ForceDwarfFrameSection(false),
Expand Down Expand Up @@ -312,6 +313,9 @@ namespace llvm {
/// Enables the MachineFunctionSplitter pass.
unsigned EnableMachineFunctionSplitter : 1;

/// Enables the StaticDataSplitter pass.
unsigned EnableStaticDataPartitioning : 1;

/// Set if the target supports default outlining behaviour.
unsigned SupportsDefaultOutlining : 1;

Expand Down
29 changes: 25 additions & 4 deletions llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2868,11 +2868,26 @@ void AsmPrinter::emitJumpTableInfo() {
MJTI->getEntryKind() == MachineJumpTableInfo::EK_LabelDifference64,
F);

SmallVector<unsigned> JumpTableIndices;
if (!TM.Options.EnableStaticDataPartitioning) {
emitJumpTableImpl(*MJTI, llvm::to_vector(llvm::seq<unsigned>(JT.size())),
JTInDiffSection);
return;
}

SmallVector<unsigned> HotJumpTableIndices, ColdJumpTableIndices;
// When static data partitioning is enabled, collect jump table entries that
// go into the same section together to reduce the amount of section switch
// statements.
for (unsigned JTI = 0, JTSize = JT.size(); JTI < JTSize; ++JTI) {
JumpTableIndices.push_back(JTI);
if (JT[JTI].Hotness == MachineFunctionDataHotness::Cold) {
ColdJumpTableIndices.push_back(JTI);
} else {
HotJumpTableIndices.push_back(JTI);
}
}
emitJumpTableImpl(*MJTI, JumpTableIndices, JTInDiffSection);

emitJumpTableImpl(*MJTI, HotJumpTableIndices, JTInDiffSection);
emitJumpTableImpl(*MJTI, ColdJumpTableIndices, JTInDiffSection);
}

void AsmPrinter::emitJumpTableImpl(const MachineJumpTableInfo &MJTI,
Expand All @@ -2884,7 +2899,13 @@ void AsmPrinter::emitJumpTableImpl(const MachineJumpTableInfo &MJTI,
const TargetLoweringObjectFile &TLOF = getObjFileLowering();
const Function &F = MF->getFunction();
const std::vector<MachineJumpTableEntry> &JT = MJTI.getJumpTables();
MCSection *JumpTableSection = TLOF.getSectionForJumpTable(F, TM);
MCSection *JumpTableSection = nullptr;
if (TM.Options.EnableStaticDataPartitioning) {
JumpTableSection =
TLOF.getSectionForJumpTable(F, TM, &JT[JumpTableIndices.front()]);
} else {
JumpTableSection = TLOF.getSectionForJumpTable(F, TM);
}

const DataLayout &DL = MF->getDataLayout();
if (JTInDiffSection) {
Expand Down
8 changes: 8 additions & 0 deletions llvm/lib/CodeGen/CommandFlags.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ CGOPT(bool, EnableStackSizeSection)
CGOPT(bool, EnableAddrsig)
CGOPT(bool, EmitCallSiteInfo)
CGOPT(bool, EnableMachineFunctionSplitter)
CGOPT(bool, EnableStaticDataPartitioning)
CGOPT(bool, EnableDebugEntryValues)
CGOPT(bool, ForceDwarfFrameSection)
CGOPT(bool, XRayFunctionIndex)
Expand Down Expand Up @@ -480,6 +481,12 @@ codegen::RegisterCodeGenFlags::RegisterCodeGenFlags() {
cl::init(false));
CGBINDOPT(EnableMachineFunctionSplitter);

static cl::opt<bool> EnableStaticDataPartitioning(
"partition-static-data-sections",
cl::desc("Partition data sections using profile information."),
cl::init(false));
CGBINDOPT(EnableStaticDataPartitioning);

static cl::opt<bool> ForceDwarfFrameSection(
"force-dwarf-frame-section",
cl::desc("Always emit a debug frame section."), cl::init(false));
Expand Down Expand Up @@ -586,6 +593,7 @@ codegen::InitTargetOptionsFromCodeGenFlags(const Triple &TheTriple) {
Options.ExceptionModel = getExceptionModel();
Options.EmitStackSizeSection = getEnableStackSizeSection();
Options.EnableMachineFunctionSplitter = getEnableMachineFunctionSplitter();
Options.EnableStaticDataPartitioning = getEnableStaticDataPartitioning();
Options.EmitAddrsig = getEnableAddrsig();
Options.EmitCallSiteInfo = getEmitCallSiteInfo();
Options.EnableDebugEntryValues = getEnableDebugEntryValues();
Expand Down
23 changes: 4 additions & 19 deletions llvm/lib/CodeGen/StaticDataSplitter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,19 +35,11 @@ using namespace llvm;

#define DEBUG_TYPE "static-data-splitter"

STATISTIC(NumHotJumpTables, "Number of hot jump tables seen");
STATISTIC(NumColdJumpTables, "Number of cold jump tables seen");
STATISTIC(NumHotJumpTables, "Number of hot jump tables seen.");
STATISTIC(NumColdJumpTables, "Number of cold jump tables seen.");
STATISTIC(NumUnknownJumpTables,
"Number of jump tables with unknown hotness. Option "
"-static-data-default-hotness specifies the hotness.");

static cl::opt<MachineFunctionDataHotness> StaticDataDefaultHotness(
"static-data-default-hotness", cl::Hidden,
cl::desc("This option specifies the hotness of static data when profile "
"information is unavailable"),
cl::init(MachineFunctionDataHotness::Hot),
cl::values(clEnumValN(MachineFunctionDataHotness::Hot, "hot", "Hot"),
clEnumValN(MachineFunctionDataHotness::Cold, "cold", "Cold")));
"Number of jump tables with unknown hotness. They are from functions "
"without profile information.");

class StaticDataSplitter : public MachineFunctionPass {
const MachineBranchProbabilityInfo *MBPI = nullptr;
Expand Down Expand Up @@ -156,13 +148,6 @@ bool StaticDataSplitter::splitJumpTables(MachineFunction &MF) {
if (ProfileAvailable)
return splitJumpTablesWithProfiles(MF, *MJTI);

// If function profile is unavailable (e.g., module not instrumented, or new
// code paths lacking samples), -static-data-default-hotness specifies the
// hotness.
for (size_t JTI = 0; JTI < MJTI->getJumpTables().size(); JTI++)
MF.getJumpTableInfo()->updateJumpTableEntryHotness(
JTI, StaticDataDefaultHotness);

return true;
}

Expand Down
37 changes: 29 additions & 8 deletions llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include "llvm/CodeGen/BasicBlockSectionUtils.h"
#include "llvm/CodeGen/MachineBasicBlock.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineJumpTableInfo.h"
#include "llvm/CodeGen/MachineModuleInfo.h"
#include "llvm/CodeGen/MachineModuleInfoImpls.h"
#include "llvm/IR/Comdat.h"
Expand Down Expand Up @@ -648,7 +649,8 @@ static StringRef getSectionPrefixForGlobal(SectionKind Kind, bool IsLarge) {
static SmallString<128>
getELFSectionNameForGlobal(const GlobalObject *GO, SectionKind Kind,
Mangler &Mang, const TargetMachine &TM,
unsigned EntrySize, bool UniqueSectionName) {
unsigned EntrySize, bool UniqueSectionName,
const MachineJumpTableEntry *JTE) {
SmallString<128> Name =
getSectionPrefixForGlobal(Kind, TM.isLargeGlobalValue(GO));
if (Kind.isMergeableCString()) {
Expand All @@ -669,7 +671,19 @@ getELFSectionNameForGlobal(const GlobalObject *GO, SectionKind Kind,

bool HasPrefix = false;
if (const auto *F = dyn_cast<Function>(GO)) {
if (std::optional<StringRef> Prefix = F->getSectionPrefix()) {
// Jump table hotness takes precedence over its enclosing function's hotness
// if it's known. The function's section prefix is used if jump table entry
// hotness is unknown.
if (JTE && JTE->Hotness != MachineFunctionDataHotness::Unknown) {
if (JTE->Hotness == MachineFunctionDataHotness::Hot) {
raw_svector_ostream(Name) << ".hot";
} else {
assert(JTE->Hotness == MachineFunctionDataHotness::Cold &&
"Hotness must be cold");
raw_svector_ostream(Name) << ".unlikely";
}
HasPrefix = true;
} else if (std::optional<StringRef> Prefix = F->getSectionPrefix()) {
raw_svector_ostream(Name) << '.' << *Prefix;
HasPrefix = true;
}
Expand Down Expand Up @@ -767,8 +781,8 @@ calcUniqueIDUpdateFlagsAndSize(const GlobalObject *GO, StringRef SectionName,
// implicitly for this symbol e.g. .rodata.str1.1, then we don't need
// to unique the section as the entry size for this symbol will be
// compatible with implicitly created sections.
SmallString<128> ImplicitSectionNameStem =
getELFSectionNameForGlobal(GO, Kind, Mang, TM, EntrySize, false);
SmallString<128> ImplicitSectionNameStem = getELFSectionNameForGlobal(
GO, Kind, Mang, TM, EntrySize, false, /*MJTE=*/nullptr);
if (SymbolMergeable &&
Ctx.isELFImplicitMergeableSectionNamePrefix(SectionName) &&
SectionName.starts_with(ImplicitSectionNameStem))
Expand Down Expand Up @@ -874,7 +888,8 @@ MCSection *TargetLoweringObjectFileELF::getExplicitSectionGlobal(
static MCSectionELF *selectELFSectionForGlobal(
MCContext &Ctx, const GlobalObject *GO, SectionKind Kind, Mangler &Mang,
const TargetMachine &TM, bool EmitUniqueSection, unsigned Flags,
unsigned *NextUniqueID, const MCSymbolELF *AssociatedSymbol) {
unsigned *NextUniqueID, const MCSymbolELF *AssociatedSymbol,
const MachineJumpTableEntry *MJTE = nullptr) {

auto [Group, IsComdat, ExtraFlags] = getGlobalObjectInfo(GO, TM);
Flags |= ExtraFlags;
Expand All @@ -893,7 +908,7 @@ static MCSectionELF *selectELFSectionForGlobal(
}
}
SmallString<128> Name = getELFSectionNameForGlobal(
GO, Kind, Mang, TM, EntrySize, UniqueSectionName);
GO, Kind, Mang, TM, EntrySize, UniqueSectionName, MJTE);

// Use 0 as the unique ID for execute-only text.
if (Kind.isExecuteOnly())
Expand Down Expand Up @@ -967,17 +982,23 @@ MCSection *TargetLoweringObjectFileELF::getUniqueSectionForFunction(

MCSection *TargetLoweringObjectFileELF::getSectionForJumpTable(
const Function &F, const TargetMachine &TM) const {
return getSectionForJumpTable(F, TM, /*JTE=*/nullptr);
}

MCSection *TargetLoweringObjectFileELF::getSectionForJumpTable(
const Function &F, const TargetMachine &TM,
const MachineJumpTableEntry *JTE) const {
// If the function can be removed, produce a unique section so that
// the table doesn't prevent the removal.
const Comdat *C = F.getComdat();
bool EmitUniqueSection = TM.getFunctionSections() || C;
if (!EmitUniqueSection)
if (!EmitUniqueSection && !TM.getEnableStaticDataPartitioning())
return ReadOnlySection;

return selectELFSectionForGlobal(getContext(), &F, SectionKind::getReadOnly(),
getMangler(), TM, EmitUniqueSection,
ELF::SHF_ALLOC, &NextUniqueID,
/* AssociatedSymbol */ nullptr);
/* AssociatedSymbol */ nullptr, JTE);
}

MCSection *TargetLoweringObjectFileELF::getSectionForLSDA(
Expand Down
2 changes: 1 addition & 1 deletion llvm/lib/CodeGen/TargetPassConfig.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1255,7 +1255,7 @@ void TargetPassConfig::addMachinePasses() {
}
}
addPass(createMachineFunctionSplitterPass());
if (SplitStaticData)
if (SplitStaticData || TM->Options.EnableStaticDataPartitioning)
addPass(createStaticDataSplitterPass());
}
// We run the BasicBlockSections pass if either we need BB sections or BB
Expand Down
6 changes: 6 additions & 0 deletions llvm/lib/Target/TargetLoweringObjectFile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -348,6 +348,12 @@ TargetLoweringObjectFile::SectionForGlobal(const GlobalObject *GO,

MCSection *TargetLoweringObjectFile::getSectionForJumpTable(
const Function &F, const TargetMachine &TM) const {
return getSectionForJumpTable(F, TM, /*JTE=*/nullptr);
}

MCSection *TargetLoweringObjectFile::getSectionForJumpTable(
const Function &F, const TargetMachine &TM,
const MachineJumpTableEntry *JTE) const {
Align Alignment(1);
return getSectionForConstant(F.getDataLayout(),
SectionKind::getReadOnly(), /*C=*/nullptr,
Expand Down
Loading

0 comments on commit 3feb724

Please sign in to comment.