1 //===-- CGProfile.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 #include "llvm/Transforms/Instrumentation/CGProfile.h" 10 11 #include "llvm/ADT/MapVector.h" 12 #include "llvm/Analysis/BlockFrequencyInfo.h" 13 #include "llvm/Analysis/LazyBlockFrequencyInfo.h" 14 #include "llvm/Analysis/TargetTransformInfo.h" 15 #include "llvm/IR/Constants.h" 16 #include "llvm/IR/MDBuilder.h" 17 #include "llvm/IR/Module.h" 18 #include "llvm/IR/PassManager.h" 19 #include "llvm/ProfileData/InstrProf.h" 20 #include "llvm/Transforms/Instrumentation.h" 21 #include <optional> 22 23 using namespace llvm; 24 25 static bool 26 addModuleFlags(Module &M, 27 MapVector<std::pair<Function *, Function *>, uint64_t> &Counts) { 28 if (Counts.empty()) 29 return false; 30 31 LLVMContext &Context = M.getContext(); 32 MDBuilder MDB(Context); 33 std::vector<Metadata *> Nodes; 34 35 for (auto E : Counts) { 36 Metadata *Vals[] = {ValueAsMetadata::get(E.first.first), 37 ValueAsMetadata::get(E.first.second), 38 MDB.createConstant(ConstantInt::get( 39 Type::getInt64Ty(Context), E.second))}; 40 Nodes.push_back(MDNode::get(Context, Vals)); 41 } 42 43 M.addModuleFlag(Module::Append, "CG Profile", 44 MDTuple::getDistinct(Context, Nodes)); 45 return true; 46 } 47 48 static bool runCGProfilePass(Module &M, FunctionAnalysisManager &FAM, 49 bool InLTO) { 50 MapVector<std::pair<Function *, Function *>, uint64_t> Counts; 51 InstrProfSymtab Symtab; 52 auto UpdateCounts = [&](TargetTransformInfo &TTI, Function *F, 53 Function *CalledF, uint64_t NewCount) { 54 if (NewCount == 0) 55 return; 56 if (!CalledF || !TTI.isLoweredToCall(CalledF) || 57 CalledF->hasDLLImportStorageClass()) 58 return; 59 uint64_t &Count = Counts[std::make_pair(F, CalledF)]; 60 Count = SaturatingAdd(Count, NewCount); 61 }; 62 // Ignore error here. Indirect calls are ignored if this fails. 63 (void)(bool)Symtab.create(M, InLTO); 64 for (auto &F : M) { 65 // Avoid extra cost of running passes for BFI when the function doesn't have 66 // entry count. 67 if (F.isDeclaration() || !F.getEntryCount()) 68 continue; 69 auto &BFI = FAM.getResult<BlockFrequencyAnalysis>(F); 70 if (BFI.getEntryFreq() == BlockFrequency(0)) 71 continue; 72 TargetTransformInfo &TTI = FAM.getResult<TargetIRAnalysis>(F); 73 for (auto &BB : F) { 74 std::optional<uint64_t> BBCount = BFI.getBlockProfileCount(&BB); 75 if (!BBCount) 76 continue; 77 for (auto &I : BB) { 78 CallBase *CB = dyn_cast<CallBase>(&I); 79 if (!CB) 80 continue; 81 if (CB->isIndirectCall()) { 82 uint64_t TotalC; 83 auto ValueData = 84 getValueProfDataFromInst(*CB, IPVK_IndirectCallTarget, 8, TotalC); 85 for (const auto &VD : ValueData) 86 UpdateCounts(TTI, &F, Symtab.getFunction(VD.Value), VD.Count); 87 continue; 88 } 89 UpdateCounts(TTI, &F, CB->getCalledFunction(), *BBCount); 90 } 91 } 92 } 93 94 return addModuleFlags(M, Counts); 95 } 96 97 PreservedAnalyses CGProfilePass::run(Module &M, ModuleAnalysisManager &MAM) { 98 FunctionAnalysisManager &FAM = 99 MAM.getResult<FunctionAnalysisManagerModuleProxy>(M).getManager(); 100 runCGProfilePass(M, FAM, InLTO); 101 102 return PreservedAnalyses::all(); 103 } 104