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