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