66//
77// ===----------------------------------------------------------------------===//
88//
9- // This pass uses profile information to partition static data sections into
10- // hot and cold ones. It begins to split jump tables based on profile, and
11- // subsequent patches will handle constant pools and other module internal data.
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)
1214//
1315// For the original RFC of this pass please see
14- // https://discourse.llvm.org/t/rfc-profile-guided-static-data-partitioning/83744.
16+ // https://discourse.llvm.org/t/rfc-profile-guided-static-data-partitioning/83744
1517
18+ #include " llvm/ADT/ScopeExit.h"
1619#include " llvm/ADT/Statistic.h"
1720#include " llvm/Analysis/ProfileSummaryInfo.h"
1821#include " llvm/CodeGen/MBFIWrapper.h"
@@ -35,8 +38,16 @@ using namespace llvm;
3538STATISTIC (NumHotJumpTables, " Number of hot jump tables seen" );
3639STATISTIC (NumColdJumpTables, " Number of cold jump tables seen" );
3740STATISTIC (NumUnknownJumpTables,
38- " Number of jump tables with unknown hotness. Such jump tables will "
39- " be placed in the hot-suffixed section by default." );
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" )));
4051
4152class StaticDataSplitter : public MachineFunctionPass {
4253 const MachineBranchProbabilityInfo *MBPI = nullptr ;
@@ -74,20 +85,13 @@ bool StaticDataSplitter::runOnMachineFunction(MachineFunction &MF) {
7485 MBFI = &getAnalysis<MachineBlockFrequencyInfoWrapperPass>().getMBFI ();
7586 PSI = &getAnalysis<ProfileSummaryInfoWrapperPass>().getPSI ();
7687
77- // Split jump tables based on profile information. Subsequent patches will
78- // handle other data types like constant pools, module-internal data, etc.
7988 return splitJumpTables (MF);
8089}
8190
8291bool StaticDataSplitter::splitJumpTablesWithProfiles (
8392 MachineFunction &MF, MachineJumpTableInfo &MJTI) {
8493 int NumChangedJumpTables = 0 ;
85- // Regard a jump table as hot by default. If the source and all of destination
86- // blocks are cold, regard the jump table as cold. While a destination block
87- // does not read a jump table (unless it's also a source block), a hot
88- // destination heuristically makes its jump table hot to accommodate for
89- // potential profile data skews (from sampled profiles, for example).
90- DataHotness Hotness = DataHotness::Hot;
94+
9195 for (const auto &MBB : MF) {
9296 // IMPORTANT, `getJumpTableIndex` is a thin wrapper around per-target
9397 // interface `TargetInstrInfo::getjumpTableIndex`, and only X86 implements
@@ -97,21 +101,14 @@ bool StaticDataSplitter::splitJumpTablesWithProfiles(
97101 if (JTI == -1 )
98102 continue ;
99103
100- bool AllBlocksCold = PSI-> isColdBlock (&MBB, MBFI) ;
104+ auto Hotness = MachineFunctionDataHotness::Hot ;
101105
102- for ( const MachineBasicBlock *MBB : MJTI. getJumpTables ()[JTI]. MBBs )
103- if (! PSI->isColdBlock (MBB, MBFI))
104- AllBlocksCold = false ;
106+ // Hotness is based on source basic block hotness.
107+ if (PSI->isColdBlock (& MBB, MBFI))
108+ Hotness = MachineFunctionDataHotness::Cold ;
105109
106- if (AllBlocksCold) {
107- Hotness = DataHotness::Cold;
108- ++NumColdJumpTables;
109- } else {
110- ++NumHotJumpTables;
111- }
112-
113- MF.getJumpTableInfo ()->updateJumpTableHotness (JTI, Hotness);
114- ++NumChangedJumpTables;
110+ if (MF.getJumpTableInfo ()->updateJumpTableEntryHotness (JTI, Hotness))
111+ ++NumChangedJumpTables;
115112 }
116113 return NumChangedJumpTables > 0 ;
117114}
@@ -121,18 +118,41 @@ bool StaticDataSplitter::splitJumpTables(MachineFunction &MF) {
121118 if (!MJTI || MJTI->getJumpTables ().empty ())
122119 return false ;
123120
121+ const bool ProfileAvailable = PSI && PSI->hasProfileSummary () && MBFI &&
122+ MF.getFunction ().hasProfileData ();
123+ auto statOnExit = llvm::make_scope_exit ([&] {
124+ if (!AreStatisticsEnabled ())
125+ return ;
126+
127+ if (!ProfileAvailable) {
128+ NumUnknownJumpTables += MJTI->getJumpTables ().size ();
129+ return ;
130+ }
131+
132+ for (size_t JTI = 0 ; JTI < MJTI->getJumpTables ().size (); JTI++) {
133+ auto Hotness = MJTI->getJumpTables ()[JTI].Hotness ;
134+ if (Hotness == MachineFunctionDataHotness::Hot)
135+ NumHotJumpTables++;
136+ else {
137+ assert (Hotness == MachineFunctionDataHotness::Cold &&
138+ " A jump table is either hot or cold when profile information is "
139+ " available." );
140+ NumColdJumpTables++;
141+ }
142+ }
143+ });
144+
124145 // Place jump tables according to block hotness if function has profile data.
125- if (PSI && PSI->hasProfileSummary () && MBFI &&
126- MF.getFunction ().hasProfileData ())
146+ if (ProfileAvailable)
127147 return splitJumpTablesWithProfiles (MF, *MJTI);
128148
129- // Conservatively place all jump tables in the hot-suffixed section if profile
130- // information for the function is not available, or the target doesn't
131- // implement `TargetInstrInfo::getJumpTableIndex` yet .
149+ // If function profile is unavailable (e.g., module not instrumented, or new
150+ // code paths lacking samples), -static-data-default-hotness specifies the
151+ // hotness .
132152 for (size_t JTI = 0 ; JTI < MJTI->getJumpTables ().size (); JTI++)
133- MF.getJumpTableInfo ()->updateJumpTableHotness (JTI, DataHotness::Hot);
153+ MF.getJumpTableInfo ()->updateJumpTableEntryHotness (
154+ JTI, StaticDataDefaultHotness);
134155
135- NumUnknownJumpTables += MJTI->getJumpTables ().size ();
136156 return true ;
137157}
138158
0 commit comments