Skip to content

Commit 3feb724

Browse files
[AsmPrinter][ELF] Support profile-guided section prefix for jump tables' (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]>
1 parent 77e44e5 commit 3feb724

12 files changed

+173
-49
lines changed

llvm/include/llvm/CodeGen/CommandFlags.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,8 @@ bool getEmitCallSiteInfo();
136136

137137
bool getEnableMachineFunctionSplitter();
138138

139+
bool getEnableStaticDataPartitioning();
140+
139141
bool getEnableDebugEntryValues();
140142

141143
bool getValueTrackingVariableLocations();

llvm/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,9 @@ class TargetLoweringObjectFileELF : public TargetLoweringObjectFile {
7676

7777
MCSection *getSectionForJumpTable(const Function &F,
7878
const TargetMachine &TM) const override;
79+
MCSection *
80+
getSectionForJumpTable(const Function &F, const TargetMachine &TM,
81+
const MachineJumpTableEntry *JTE) const override;
7982
MCSection *getSectionForLSDA(const Function &F, const MCSymbol &FnSym,
8083
const TargetMachine &TM) const override;
8184

llvm/include/llvm/Target/TargetLoweringObjectFile.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
namespace llvm {
2222

2323
struct Align;
24+
struct MachineJumpTableEntry;
2425
class Constant;
2526
class DataLayout;
2627
class Function;
@@ -135,6 +136,10 @@ class TargetLoweringObjectFile : public MCObjectFileInfo {
135136

136137
virtual MCSection *getSectionForJumpTable(const Function &F,
137138
const TargetMachine &TM) const;
139+
virtual MCSection *
140+
getSectionForJumpTable(const Function &F, const TargetMachine &TM,
141+
const MachineJumpTableEntry *JTE) const;
142+
138143
virtual MCSection *getSectionForLSDA(const Function &, const MCSymbol &,
139144
const TargetMachine &) const {
140145
return LSDASection;

llvm/include/llvm/Target/TargetMachine.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,10 @@ class TargetMachine {
305305
return Options.FunctionSections;
306306
}
307307

308+
bool getEnableStaticDataPartitioning() const {
309+
return Options.EnableStaticDataPartitioning;
310+
}
311+
308312
/// Return true if visibility attribute should not be emitted in XCOFF,
309313
/// corresponding to -mignore-xcoff-visibility.
310314
bool getIgnoreXCOFFVisibility() const {

llvm/include/llvm/Target/TargetOptions.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,8 @@ namespace llvm {
145145
TrapUnreachable(false), NoTrapAfterNoreturn(false), TLSSize(0),
146146
EmulatedTLS(false), EnableTLSDESC(false), EnableIPRA(false),
147147
EmitStackSizeSection(false), EnableMachineOutliner(false),
148-
EnableMachineFunctionSplitter(false), SupportsDefaultOutlining(false),
148+
EnableMachineFunctionSplitter(false),
149+
EnableStaticDataPartitioning(false), SupportsDefaultOutlining(false),
149150
EmitAddrsig(false), BBAddrMap(false), EmitCallSiteInfo(false),
150151
SupportsDebugEntryValues(false), EnableDebugEntryValues(false),
151152
ValueTrackingVariableLocations(false), ForceDwarfFrameSection(false),
@@ -312,6 +313,9 @@ namespace llvm {
312313
/// Enables the MachineFunctionSplitter pass.
313314
unsigned EnableMachineFunctionSplitter : 1;
314315

316+
/// Enables the StaticDataSplitter pass.
317+
unsigned EnableStaticDataPartitioning : 1;
318+
315319
/// Set if the target supports default outlining behaviour.
316320
unsigned SupportsDefaultOutlining : 1;
317321

llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2868,11 +2868,26 @@ void AsmPrinter::emitJumpTableInfo() {
28682868
MJTI->getEntryKind() == MachineJumpTableInfo::EK_LabelDifference64,
28692869
F);
28702870

2871-
SmallVector<unsigned> JumpTableIndices;
2871+
if (!TM.Options.EnableStaticDataPartitioning) {
2872+
emitJumpTableImpl(*MJTI, llvm::to_vector(llvm::seq<unsigned>(JT.size())),
2873+
JTInDiffSection);
2874+
return;
2875+
}
2876+
2877+
SmallVector<unsigned> HotJumpTableIndices, ColdJumpTableIndices;
2878+
// When static data partitioning is enabled, collect jump table entries that
2879+
// go into the same section together to reduce the amount of section switch
2880+
// statements.
28722881
for (unsigned JTI = 0, JTSize = JT.size(); JTI < JTSize; ++JTI) {
2873-
JumpTableIndices.push_back(JTI);
2882+
if (JT[JTI].Hotness == MachineFunctionDataHotness::Cold) {
2883+
ColdJumpTableIndices.push_back(JTI);
2884+
} else {
2885+
HotJumpTableIndices.push_back(JTI);
2886+
}
28742887
}
2875-
emitJumpTableImpl(*MJTI, JumpTableIndices, JTInDiffSection);
2888+
2889+
emitJumpTableImpl(*MJTI, HotJumpTableIndices, JTInDiffSection);
2890+
emitJumpTableImpl(*MJTI, ColdJumpTableIndices, JTInDiffSection);
28762891
}
28772892

28782893
void AsmPrinter::emitJumpTableImpl(const MachineJumpTableInfo &MJTI,
@@ -2884,7 +2899,13 @@ void AsmPrinter::emitJumpTableImpl(const MachineJumpTableInfo &MJTI,
28842899
const TargetLoweringObjectFile &TLOF = getObjFileLowering();
28852900
const Function &F = MF->getFunction();
28862901
const std::vector<MachineJumpTableEntry> &JT = MJTI.getJumpTables();
2887-
MCSection *JumpTableSection = TLOF.getSectionForJumpTable(F, TM);
2902+
MCSection *JumpTableSection = nullptr;
2903+
if (TM.Options.EnableStaticDataPartitioning) {
2904+
JumpTableSection =
2905+
TLOF.getSectionForJumpTable(F, TM, &JT[JumpTableIndices.front()]);
2906+
} else {
2907+
JumpTableSection = TLOF.getSectionForJumpTable(F, TM);
2908+
}
28882909

28892910
const DataLayout &DL = MF->getDataLayout();
28902911
if (JTInDiffSection) {

llvm/lib/CodeGen/CommandFlags.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ CGOPT(bool, EnableStackSizeSection)
103103
CGOPT(bool, EnableAddrsig)
104104
CGOPT(bool, EmitCallSiteInfo)
105105
CGOPT(bool, EnableMachineFunctionSplitter)
106+
CGOPT(bool, EnableStaticDataPartitioning)
106107
CGOPT(bool, EnableDebugEntryValues)
107108
CGOPT(bool, ForceDwarfFrameSection)
108109
CGOPT(bool, XRayFunctionIndex)
@@ -480,6 +481,12 @@ codegen::RegisterCodeGenFlags::RegisterCodeGenFlags() {
480481
cl::init(false));
481482
CGBINDOPT(EnableMachineFunctionSplitter);
482483

484+
static cl::opt<bool> EnableStaticDataPartitioning(
485+
"partition-static-data-sections",
486+
cl::desc("Partition data sections using profile information."),
487+
cl::init(false));
488+
CGBINDOPT(EnableStaticDataPartitioning);
489+
483490
static cl::opt<bool> ForceDwarfFrameSection(
484491
"force-dwarf-frame-section",
485492
cl::desc("Always emit a debug frame section."), cl::init(false));
@@ -586,6 +593,7 @@ codegen::InitTargetOptionsFromCodeGenFlags(const Triple &TheTriple) {
586593
Options.ExceptionModel = getExceptionModel();
587594
Options.EmitStackSizeSection = getEnableStackSizeSection();
588595
Options.EnableMachineFunctionSplitter = getEnableMachineFunctionSplitter();
596+
Options.EnableStaticDataPartitioning = getEnableStaticDataPartitioning();
589597
Options.EmitAddrsig = getEnableAddrsig();
590598
Options.EmitCallSiteInfo = getEmitCallSiteInfo();
591599
Options.EnableDebugEntryValues = getEnableDebugEntryValues();

llvm/lib/CodeGen/StaticDataSplitter.cpp

Lines changed: 4 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -35,19 +35,11 @@ using namespace llvm;
3535

3636
#define DEBUG_TYPE "static-data-splitter"
3737

38-
STATISTIC(NumHotJumpTables, "Number of hot jump tables seen");
39-
STATISTIC(NumColdJumpTables, "Number of cold jump tables seen");
38+
STATISTIC(NumHotJumpTables, "Number of hot jump tables seen.");
39+
STATISTIC(NumColdJumpTables, "Number of cold jump tables seen.");
4040
STATISTIC(NumUnknownJumpTables,
41-
"Number of jump tables with unknown hotness. Option "
42-
"-static-data-default-hotness specifies the hotness.");
43-
44-
static cl::opt<MachineFunctionDataHotness> StaticDataDefaultHotness(
45-
"static-data-default-hotness", cl::Hidden,
46-
cl::desc("This option specifies the hotness of static data when profile "
47-
"information is unavailable"),
48-
cl::init(MachineFunctionDataHotness::Hot),
49-
cl::values(clEnumValN(MachineFunctionDataHotness::Hot, "hot", "Hot"),
50-
clEnumValN(MachineFunctionDataHotness::Cold, "cold", "Cold")));
41+
"Number of jump tables with unknown hotness. They are from functions "
42+
"without profile information.");
5143

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

159-
// If function profile is unavailable (e.g., module not instrumented, or new
160-
// code paths lacking samples), -static-data-default-hotness specifies the
161-
// hotness.
162-
for (size_t JTI = 0; JTI < MJTI->getJumpTables().size(); JTI++)
163-
MF.getJumpTableInfo()->updateJumpTableEntryHotness(
164-
JTI, StaticDataDefaultHotness);
165-
166151
return true;
167152
}
168153

llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include "llvm/CodeGen/BasicBlockSectionUtils.h"
2525
#include "llvm/CodeGen/MachineBasicBlock.h"
2626
#include "llvm/CodeGen/MachineFunction.h"
27+
#include "llvm/CodeGen/MachineJumpTableInfo.h"
2728
#include "llvm/CodeGen/MachineModuleInfo.h"
2829
#include "llvm/CodeGen/MachineModuleInfoImpls.h"
2930
#include "llvm/IR/Comdat.h"
@@ -648,7 +649,8 @@ static StringRef getSectionPrefixForGlobal(SectionKind Kind, bool IsLarge) {
648649
static SmallString<128>
649650
getELFSectionNameForGlobal(const GlobalObject *GO, SectionKind Kind,
650651
Mangler &Mang, const TargetMachine &TM,
651-
unsigned EntrySize, bool UniqueSectionName) {
652+
unsigned EntrySize, bool UniqueSectionName,
653+
const MachineJumpTableEntry *JTE) {
652654
SmallString<128> Name =
653655
getSectionPrefixForGlobal(Kind, TM.isLargeGlobalValue(GO));
654656
if (Kind.isMergeableCString()) {
@@ -669,7 +671,19 @@ getELFSectionNameForGlobal(const GlobalObject *GO, SectionKind Kind,
669671

670672
bool HasPrefix = false;
671673
if (const auto *F = dyn_cast<Function>(GO)) {
672-
if (std::optional<StringRef> Prefix = F->getSectionPrefix()) {
674+
// Jump table hotness takes precedence over its enclosing function's hotness
675+
// if it's known. The function's section prefix is used if jump table entry
676+
// hotness is unknown.
677+
if (JTE && JTE->Hotness != MachineFunctionDataHotness::Unknown) {
678+
if (JTE->Hotness == MachineFunctionDataHotness::Hot) {
679+
raw_svector_ostream(Name) << ".hot";
680+
} else {
681+
assert(JTE->Hotness == MachineFunctionDataHotness::Cold &&
682+
"Hotness must be cold");
683+
raw_svector_ostream(Name) << ".unlikely";
684+
}
685+
HasPrefix = true;
686+
} else if (std::optional<StringRef> Prefix = F->getSectionPrefix()) {
673687
raw_svector_ostream(Name) << '.' << *Prefix;
674688
HasPrefix = true;
675689
}
@@ -767,8 +781,8 @@ calcUniqueIDUpdateFlagsAndSize(const GlobalObject *GO, StringRef SectionName,
767781
// implicitly for this symbol e.g. .rodata.str1.1, then we don't need
768782
// to unique the section as the entry size for this symbol will be
769783
// compatible with implicitly created sections.
770-
SmallString<128> ImplicitSectionNameStem =
771-
getELFSectionNameForGlobal(GO, Kind, Mang, TM, EntrySize, false);
784+
SmallString<128> ImplicitSectionNameStem = getELFSectionNameForGlobal(
785+
GO, Kind, Mang, TM, EntrySize, false, /*MJTE=*/nullptr);
772786
if (SymbolMergeable &&
773787
Ctx.isELFImplicitMergeableSectionNamePrefix(SectionName) &&
774788
SectionName.starts_with(ImplicitSectionNameStem))
@@ -874,7 +888,8 @@ MCSection *TargetLoweringObjectFileELF::getExplicitSectionGlobal(
874888
static MCSectionELF *selectELFSectionForGlobal(
875889
MCContext &Ctx, const GlobalObject *GO, SectionKind Kind, Mangler &Mang,
876890
const TargetMachine &TM, bool EmitUniqueSection, unsigned Flags,
877-
unsigned *NextUniqueID, const MCSymbolELF *AssociatedSymbol) {
891+
unsigned *NextUniqueID, const MCSymbolELF *AssociatedSymbol,
892+
const MachineJumpTableEntry *MJTE = nullptr) {
878893

879894
auto [Group, IsComdat, ExtraFlags] = getGlobalObjectInfo(GO, TM);
880895
Flags |= ExtraFlags;
@@ -893,7 +908,7 @@ static MCSectionELF *selectELFSectionForGlobal(
893908
}
894909
}
895910
SmallString<128> Name = getELFSectionNameForGlobal(
896-
GO, Kind, Mang, TM, EntrySize, UniqueSectionName);
911+
GO, Kind, Mang, TM, EntrySize, UniqueSectionName, MJTE);
897912

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

968983
MCSection *TargetLoweringObjectFileELF::getSectionForJumpTable(
969984
const Function &F, const TargetMachine &TM) const {
985+
return getSectionForJumpTable(F, TM, /*JTE=*/nullptr);
986+
}
987+
988+
MCSection *TargetLoweringObjectFileELF::getSectionForJumpTable(
989+
const Function &F, const TargetMachine &TM,
990+
const MachineJumpTableEntry *JTE) const {
970991
// If the function can be removed, produce a unique section so that
971992
// the table doesn't prevent the removal.
972993
const Comdat *C = F.getComdat();
973994
bool EmitUniqueSection = TM.getFunctionSections() || C;
974-
if (!EmitUniqueSection)
995+
if (!EmitUniqueSection && !TM.getEnableStaticDataPartitioning())
975996
return ReadOnlySection;
976997

977998
return selectELFSectionForGlobal(getContext(), &F, SectionKind::getReadOnly(),
978999
getMangler(), TM, EmitUniqueSection,
9791000
ELF::SHF_ALLOC, &NextUniqueID,
980-
/* AssociatedSymbol */ nullptr);
1001+
/* AssociatedSymbol */ nullptr, JTE);
9811002
}
9821003

9831004
MCSection *TargetLoweringObjectFileELF::getSectionForLSDA(

llvm/lib/CodeGen/TargetPassConfig.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1255,7 +1255,7 @@ void TargetPassConfig::addMachinePasses() {
12551255
}
12561256
}
12571257
addPass(createMachineFunctionSplitterPass());
1258-
if (SplitStaticData)
1258+
if (SplitStaticData || TM->Options.EnableStaticDataPartitioning)
12591259
addPass(createStaticDataSplitterPass());
12601260
}
12611261
// We run the BasicBlockSections pass if either we need BB sections or BB

llvm/lib/Target/TargetLoweringObjectFile.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -348,6 +348,12 @@ TargetLoweringObjectFile::SectionForGlobal(const GlobalObject *GO,
348348

349349
MCSection *TargetLoweringObjectFile::getSectionForJumpTable(
350350
const Function &F, const TargetMachine &TM) const {
351+
return getSectionForJumpTable(F, TM, /*JTE=*/nullptr);
352+
}
353+
354+
MCSection *TargetLoweringObjectFile::getSectionForJumpTable(
355+
const Function &F, const TargetMachine &TM,
356+
const MachineJumpTableEntry *JTE) const {
351357
Align Alignment(1);
352358
return getSectionForConstant(F.getDataLayout(),
353359
SectionKind::getReadOnly(), /*C=*/nullptr,

0 commit comments

Comments
 (0)