Skip to content

Commit de209fa

Browse files
[CodeGen] Introduce Static Data Splitter pass (llvm#122183)
https://discourse.llvm.org/t/rfc-profile-guided-static-data-partitioning/83744 proposes to partition static data sections. This patch introduces a codegen pass. This patch produces jump table hotness in the in-memory states (machine jump table info and entries). Target-lowering and asm-printer consume the states and produce `.hot` section suffix. The follow up PR llvm#122215 implements such changes. --------- Co-authored-by: Ellis Hoag <[email protected]>
1 parent 163935a commit de209fa

11 files changed

+408
-2
lines changed

llvm/include/llvm/CodeGen/MachineFunction.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,15 @@ template <> struct ilist_callback_traits<MachineBasicBlock> {
8888
}
8989
};
9090

91+
// The hotness of static data tracked by a MachineFunction and not represented
92+
// as a global object in the module IR / MIR. Typical examples are
93+
// MachineJumpTableInfo and MachineConstantPool.
94+
enum class MachineFunctionDataHotness {
95+
Unknown,
96+
Cold,
97+
Hot,
98+
};
99+
91100
/// MachineFunctionInfo - This class can be derived from and used by targets to
92101
/// hold private target-specific information for each MachineFunction. Objects
93102
/// of type are accessed/created with MF::getInfo and destroyed when the

llvm/include/llvm/CodeGen/MachineJumpTableInfo.h

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,15 +28,19 @@ namespace llvm {
2828
class MachineBasicBlock;
2929
class DataLayout;
3030
class raw_ostream;
31+
enum class MachineFunctionDataHotness;
3132

3233
/// MachineJumpTableEntry - One jump table in the jump table info.
3334
///
3435
struct MachineJumpTableEntry {
3536
/// MBBs - The vector of basic blocks from which to create the jump table.
3637
std::vector<MachineBasicBlock*> MBBs;
3738

38-
explicit MachineJumpTableEntry(const std::vector<MachineBasicBlock*> &M)
39-
: MBBs(M) {}
39+
/// The hotness of MJTE is inferred from the hotness of the source basic
40+
/// block(s) that reference it.
41+
MachineFunctionDataHotness Hotness;
42+
43+
explicit MachineJumpTableEntry(const std::vector<MachineBasicBlock *> &M);
4044
};
4145

4246
class MachineJumpTableInfo {
@@ -107,6 +111,11 @@ class MachineJumpTableInfo {
107111
return JumpTables;
108112
}
109113

114+
// Update machine jump table entry's hotness. Return true if the hotness is
115+
// updated.
116+
bool updateJumpTableEntryHotness(size_t JTI,
117+
MachineFunctionDataHotness Hotness);
118+
110119
/// RemoveJumpTable - Mark the specific index as being dead. This will
111120
/// prevent it from being emitted.
112121
void RemoveJumpTable(unsigned Idx) {

llvm/include/llvm/CodeGen/Passes.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,10 @@ namespace llvm {
7171
/// using profile information.
7272
MachineFunctionPass *createMachineFunctionSplitterPass();
7373

74+
/// createStaticDataSplitterPass - This pass partitions a static data section
75+
/// into a hot and cold section using profile information.
76+
MachineFunctionPass *createStaticDataSplitterPass();
77+
7478
/// MachineFunctionPrinter pass - This pass prints out the machine function to
7579
/// the given stream as a debugging tool.
7680
MachineFunctionPass *

llvm/include/llvm/InitializePasses.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,7 @@ void initializeSpeculativeExecutionLegacyPassPass(PassRegistry &);
293293
void initializeSpillPlacementWrapperLegacyPass(PassRegistry &);
294294
void initializeStackColoringLegacyPass(PassRegistry &);
295295
void initializeStackFrameLayoutAnalysisPassPass(PassRegistry &);
296+
void initializeStaticDataSplitterPass(PassRegistry &);
296297
void initializeStackMapLivenessPass(PassRegistry &);
297298
void initializeStackProtectorPass(PassRegistry &);
298299
void initializeStackSafetyGlobalInfoWrapperPassPass(PassRegistry &);

llvm/include/llvm/Passes/MachinePassRegistry.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,7 @@ DUMMY_MACHINE_FUNCTION_PASS("livedebugvalues", LiveDebugValuesPass)
235235
DUMMY_MACHINE_FUNCTION_PASS("lrshrink", LiveRangeShrinkPass)
236236
DUMMY_MACHINE_FUNCTION_PASS("machine-combiner", MachineCombinerPass)
237237
DUMMY_MACHINE_FUNCTION_PASS("machine-cp", MachineCopyPropagationPass)
238+
DUMMY_MACHINE_FUNCTION_PASS("static-data-splitter", StaticDataSplitter)
238239
DUMMY_MACHINE_FUNCTION_PASS("machine-function-splitter", MachineFunctionSplitterPass)
239240
DUMMY_MACHINE_FUNCTION_PASS("machine-latecleanup", MachineLateInstrsCleanupPass)
240241
DUMMY_MACHINE_FUNCTION_PASS("machine-sanmd", MachineSanitizerBinaryMetadata)

llvm/lib/CodeGen/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,7 @@ add_llvm_component_library(LLVMCodeGen
226226
StackMaps.cpp
227227
StackProtector.cpp
228228
StackSlotColoring.cpp
229+
StaticDataSplitter.cpp
229230
SwiftErrorValueTracking.cpp
230231
SwitchLoweringUtils.cpp
231232
TailDuplication.cpp

llvm/lib/CodeGen/CodeGen.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@ void llvm::initializeCodeGen(PassRegistry &Registry) {
131131
initializeStackMapLivenessPass(Registry);
132132
initializeStackProtectorPass(Registry);
133133
initializeStackSlotColoringPass(Registry);
134+
initializeStaticDataSplitterPass(Registry);
134135
initializeStripDebugMachineModulePass(Registry);
135136
initializeTailDuplicateLegacyPass(Registry);
136137
initializeTargetPassConfigPass(Registry);

llvm/lib/CodeGen/MachineFunction.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1311,6 +1311,10 @@ const unsigned MachineFunction::DebugOperandMemNumber = 1000000;
13111311
// MachineJumpTableInfo implementation
13121312
//===----------------------------------------------------------------------===//
13131313

1314+
MachineJumpTableEntry::MachineJumpTableEntry(
1315+
const std::vector<MachineBasicBlock *> &MBBs)
1316+
: MBBs(MBBs), Hotness(MachineFunctionDataHotness::Unknown) {}
1317+
13141318
/// Return the size of each entry in the jump table.
13151319
unsigned MachineJumpTableInfo::getEntrySize(const DataLayout &TD) const {
13161320
// The size of a jump table entry is 4 bytes unless the entry is just the
@@ -1360,6 +1364,17 @@ unsigned MachineJumpTableInfo::createJumpTableIndex(
13601364
return JumpTables.size()-1;
13611365
}
13621366

1367+
bool MachineJumpTableInfo::updateJumpTableEntryHotness(
1368+
size_t JTI, MachineFunctionDataHotness Hotness) {
1369+
assert(JTI < JumpTables.size() && "Invalid JTI!");
1370+
// Record the largest hotness value.
1371+
if (Hotness <= JumpTables[JTI].Hotness)
1372+
return false;
1373+
1374+
JumpTables[JTI].Hotness = Hotness;
1375+
return true;
1376+
}
1377+
13631378
/// If Old is the target of any jump tables, update the jump tables to branch
13641379
/// to New instead.
13651380
bool MachineJumpTableInfo::ReplaceMBBInJumpTables(MachineBasicBlock *Old,
Lines changed: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
1+
//===- StaticDataSplitter.cpp ---------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// The pass uses branch profile data to assign hotness based section qualifiers
10+
// for the following types of static data:
11+
// - Jump tables
12+
// - Constant pools (TODO)
13+
// - Other module-internal data (TODO)
14+
//
15+
// For the original RFC of this pass please see
16+
// https://discourse.llvm.org/t/rfc-profile-guided-static-data-partitioning/83744
17+
18+
#include "llvm/ADT/ScopeExit.h"
19+
#include "llvm/ADT/Statistic.h"
20+
#include "llvm/Analysis/ProfileSummaryInfo.h"
21+
#include "llvm/CodeGen/MBFIWrapper.h"
22+
#include "llvm/CodeGen/MachineBasicBlock.h"
23+
#include "llvm/CodeGen/MachineBlockFrequencyInfo.h"
24+
#include "llvm/CodeGen/MachineBranchProbabilityInfo.h"
25+
#include "llvm/CodeGen/MachineConstantPool.h"
26+
#include "llvm/CodeGen/MachineFunction.h"
27+
#include "llvm/CodeGen/MachineFunctionPass.h"
28+
#include "llvm/CodeGen/MachineJumpTableInfo.h"
29+
#include "llvm/CodeGen/Passes.h"
30+
#include "llvm/InitializePasses.h"
31+
#include "llvm/Pass.h"
32+
#include "llvm/Support/CommandLine.h"
33+
34+
using namespace llvm;
35+
36+
#define DEBUG_TYPE "static-data-splitter"
37+
38+
STATISTIC(NumHotJumpTables, "Number of hot jump tables seen");
39+
STATISTIC(NumColdJumpTables, "Number of cold jump tables seen");
40+
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")));
51+
52+
class StaticDataSplitter : public MachineFunctionPass {
53+
const MachineBranchProbabilityInfo *MBPI = nullptr;
54+
const MachineBlockFrequencyInfo *MBFI = nullptr;
55+
const ProfileSummaryInfo *PSI = nullptr;
56+
57+
// Returns true iff any jump table is hot-cold categorized.
58+
bool splitJumpTables(MachineFunction &MF);
59+
60+
// Same as above but works on functions with profile information.
61+
bool splitJumpTablesWithProfiles(const MachineFunction &MF,
62+
MachineJumpTableInfo &MJTI);
63+
64+
public:
65+
static char ID;
66+
67+
StaticDataSplitter() : MachineFunctionPass(ID) {
68+
initializeStaticDataSplitterPass(*PassRegistry::getPassRegistry());
69+
}
70+
71+
StringRef getPassName() const override { return "Static Data Splitter"; }
72+
73+
void getAnalysisUsage(AnalysisUsage &AU) const override {
74+
MachineFunctionPass::getAnalysisUsage(AU);
75+
AU.addRequired<MachineBranchProbabilityInfoWrapperPass>();
76+
AU.addRequired<MachineBlockFrequencyInfoWrapperPass>();
77+
AU.addRequired<ProfileSummaryInfoWrapperPass>();
78+
}
79+
80+
bool runOnMachineFunction(MachineFunction &MF) override;
81+
};
82+
83+
bool StaticDataSplitter::runOnMachineFunction(MachineFunction &MF) {
84+
MBPI = &getAnalysis<MachineBranchProbabilityInfoWrapperPass>().getMBPI();
85+
MBFI = &getAnalysis<MachineBlockFrequencyInfoWrapperPass>().getMBFI();
86+
PSI = &getAnalysis<ProfileSummaryInfoWrapperPass>().getPSI();
87+
88+
return splitJumpTables(MF);
89+
}
90+
91+
bool StaticDataSplitter::splitJumpTablesWithProfiles(
92+
const MachineFunction &MF, MachineJumpTableInfo &MJTI) {
93+
int NumChangedJumpTables = 0;
94+
95+
// Jump table could be used by either terminating instructions or
96+
// non-terminating ones, so we walk all instructions and use
97+
// `MachineOperand::isJTI()` to identify jump table operands.
98+
// Similarly, `MachineOperand::isCPI()` can identify constant pool usages
99+
// in the same loop.
100+
for (const auto &MBB : MF) {
101+
for (const MachineInstr &I : MBB) {
102+
for (const MachineOperand &Op : I.operands()) {
103+
if (!Op.isJTI())
104+
continue;
105+
const int JTI = Op.getIndex();
106+
// This is not a source block of jump table.
107+
if (JTI == -1)
108+
continue;
109+
110+
auto Hotness = MachineFunctionDataHotness::Hot;
111+
112+
// Hotness is based on source basic block hotness.
113+
// TODO: PSI APIs are about instruction hotness. Introduce API for data
114+
// access hotness.
115+
if (PSI->isColdBlock(&MBB, MBFI))
116+
Hotness = MachineFunctionDataHotness::Cold;
117+
118+
if (MJTI.updateJumpTableEntryHotness(JTI, Hotness))
119+
++NumChangedJumpTables;
120+
}
121+
}
122+
}
123+
return NumChangedJumpTables > 0;
124+
}
125+
126+
bool StaticDataSplitter::splitJumpTables(MachineFunction &MF) {
127+
MachineJumpTableInfo *MJTI = MF.getJumpTableInfo();
128+
if (!MJTI || MJTI->getJumpTables().empty())
129+
return false;
130+
131+
const bool ProfileAvailable = PSI && PSI->hasProfileSummary() && MBFI &&
132+
MF.getFunction().hasProfileData();
133+
auto statOnExit = llvm::make_scope_exit([&] {
134+
if (!AreStatisticsEnabled())
135+
return;
136+
137+
if (!ProfileAvailable) {
138+
NumUnknownJumpTables += MJTI->getJumpTables().size();
139+
return;
140+
}
141+
142+
for (size_t JTI = 0; JTI < MJTI->getJumpTables().size(); JTI++) {
143+
auto Hotness = MJTI->getJumpTables()[JTI].Hotness;
144+
if (Hotness == MachineFunctionDataHotness::Hot) {
145+
++NumHotJumpTables;
146+
} else {
147+
assert(Hotness == MachineFunctionDataHotness::Cold &&
148+
"A jump table is either hot or cold when profile information is "
149+
"available.");
150+
++NumColdJumpTables;
151+
}
152+
}
153+
});
154+
155+
// Place jump tables according to block hotness if function has profile data.
156+
if (ProfileAvailable)
157+
return splitJumpTablesWithProfiles(MF, *MJTI);
158+
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+
166+
return true;
167+
}
168+
169+
char StaticDataSplitter::ID = 0;
170+
171+
INITIALIZE_PASS_BEGIN(StaticDataSplitter, DEBUG_TYPE, "Split static data",
172+
false, false)
173+
INITIALIZE_PASS_DEPENDENCY(MachineBranchProbabilityInfoWrapperPass)
174+
INITIALIZE_PASS_DEPENDENCY(MachineBlockFrequencyInfoWrapperPass)
175+
INITIALIZE_PASS_DEPENDENCY(ProfileSummaryInfoWrapperPass)
176+
INITIALIZE_PASS_END(StaticDataSplitter, DEBUG_TYPE, "Split static data", false,
177+
false)
178+
179+
MachineFunctionPass *llvm::createStaticDataSplitterPass() {
180+
return new StaticDataSplitter();
181+
}

llvm/lib/CodeGen/TargetPassConfig.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,11 @@ static cl::opt<bool>
261261
GCEmptyBlocks("gc-empty-basic-blocks", cl::init(false), cl::Hidden,
262262
cl::desc("Enable garbage-collecting empty basic blocks"));
263263

264+
static cl::opt<bool>
265+
SplitStaticData("split-static-data", cl::Hidden, cl::init(false),
266+
cl::desc("Split static data sections into hot and cold "
267+
"sections using profile information"));
268+
264269
/// Allow standard passes to be disabled by command line options. This supports
265270
/// simple binary flags that either suppress the pass or do nothing.
266271
/// i.e. -disable-mypass=false has no effect.
@@ -1251,6 +1256,8 @@ void TargetPassConfig::addMachinePasses() {
12511256
}
12521257
}
12531258
addPass(createMachineFunctionSplitterPass());
1259+
if (SplitStaticData)
1260+
addPass(createStaticDataSplitterPass());
12541261
}
12551262
// We run the BasicBlockSections pass if either we need BB sections or BB
12561263
// address map (or both).

0 commit comments

Comments
 (0)