Home | History | Annotate | Line # | Download | only in Instrumentation
      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/Instructions.h"
     17 #include "llvm/IR/MDBuilder.h"
     18 #include "llvm/IR/PassManager.h"
     19 #include "llvm/InitializePasses.h"
     20 #include "llvm/ProfileData/InstrProf.h"
     21 #include "llvm/Transforms/Instrumentation.h"
     22 
     23 #include <array>
     24 
     25 using namespace llvm;
     26 
     27 static bool
     28 addModuleFlags(Module &M,
     29                MapVector<std::pair<Function *, Function *>, uint64_t> &Counts) {
     30   if (Counts.empty())
     31     return false;
     32 
     33   LLVMContext &Context = M.getContext();
     34   MDBuilder MDB(Context);
     35   std::vector<Metadata *> Nodes;
     36 
     37   for (auto E : Counts) {
     38     Metadata *Vals[] = {ValueAsMetadata::get(E.first.first),
     39                         ValueAsMetadata::get(E.first.second),
     40                         MDB.createConstant(ConstantInt::get(
     41                             Type::getInt64Ty(Context), E.second))};
     42     Nodes.push_back(MDNode::get(Context, Vals));
     43   }
     44 
     45   M.addModuleFlag(Module::Append, "CG Profile", MDNode::get(Context, Nodes));
     46   return true;
     47 }
     48 
     49 static bool runCGProfilePass(
     50     Module &M, function_ref<BlockFrequencyInfo &(Function &)> GetBFI,
     51     function_ref<TargetTransformInfo &(Function &)> GetTTI, bool LazyBFI) {
     52   MapVector<std::pair<Function *, Function *>, uint64_t> Counts;
     53   InstrProfSymtab Symtab;
     54   auto UpdateCounts = [&](TargetTransformInfo &TTI, Function *F,
     55                           Function *CalledF, uint64_t NewCount) {
     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);
     64   for (auto &F : M) {
     65     // Avoid extra cost of running passes for BFI when the function doesn't have
     66     // entry count. Since LazyBlockFrequencyInfoPass only exists in LPM, check
     67     // if using LazyBlockFrequencyInfoPass.
     68     // TODO: Remove LazyBFI when LazyBlockFrequencyInfoPass is available in NPM.
     69     if (F.isDeclaration() || (LazyBFI && !F.getEntryCount()))
     70       continue;
     71     auto &BFI = GetBFI(F);
     72     if (BFI.getEntryFreq() == 0)
     73       continue;
     74     TargetTransformInfo &TTI = GetTTI(F);
     75     for (auto &BB : F) {
     76       Optional<uint64_t> BBCount = BFI.getBlockProfileCount(&BB);
     77       if (!BBCount)
     78         continue;
     79       for (auto &I : BB) {
     80         CallBase *CB = dyn_cast<CallBase>(&I);
     81         if (!CB)
     82           continue;
     83         if (CB->isIndirectCall()) {
     84           InstrProfValueData ValueData[8];
     85           uint32_t ActualNumValueData;
     86           uint64_t TotalC;
     87           if (!getValueProfDataFromInst(*CB, IPVK_IndirectCallTarget, 8,
     88                                         ValueData, ActualNumValueData, TotalC))
     89             continue;
     90           for (const auto &VD :
     91                ArrayRef<InstrProfValueData>(ValueData, ActualNumValueData)) {
     92             UpdateCounts(TTI, &F, Symtab.getFunction(VD.Value), VD.Count);
     93           }
     94           continue;
     95         }
     96         UpdateCounts(TTI, &F, CB->getCalledFunction(), *BBCount);
     97       }
     98     }
     99   }
    100 
    101   return addModuleFlags(M, Counts);
    102 }
    103 
    104 namespace {
    105 struct CGProfileLegacyPass final : public ModulePass {
    106   static char ID;
    107   CGProfileLegacyPass() : ModulePass(ID) {
    108     initializeCGProfileLegacyPassPass(*PassRegistry::getPassRegistry());
    109   }
    110 
    111   void getAnalysisUsage(AnalysisUsage &AU) const override {
    112     AU.setPreservesCFG();
    113     AU.addRequired<LazyBlockFrequencyInfoPass>();
    114     AU.addRequired<TargetTransformInfoWrapperPass>();
    115   }
    116 
    117   bool runOnModule(Module &M) override {
    118     auto GetBFI = [this](Function &F) -> BlockFrequencyInfo & {
    119       return this->getAnalysis<LazyBlockFrequencyInfoPass>(F).getBFI();
    120     };
    121     auto GetTTI = [this](Function &F) -> TargetTransformInfo & {
    122       return this->getAnalysis<TargetTransformInfoWrapperPass>().getTTI(F);
    123     };
    124 
    125     return runCGProfilePass(M, GetBFI, GetTTI, true);
    126   }
    127 };
    128 
    129 } // namespace
    130 
    131 char CGProfileLegacyPass::ID = 0;
    132 
    133 INITIALIZE_PASS(CGProfileLegacyPass, "cg-profile", "Call Graph Profile", false,
    134                 false)
    135 
    136 ModulePass *llvm::createCGProfileLegacyPass() {
    137   return new CGProfileLegacyPass();
    138 }
    139 
    140 PreservedAnalyses CGProfilePass::run(Module &M, ModuleAnalysisManager &MAM) {
    141   FunctionAnalysisManager &FAM =
    142       MAM.getResult<FunctionAnalysisManagerModuleProxy>(M).getManager();
    143   auto GetBFI = [&FAM](Function &F) -> BlockFrequencyInfo & {
    144     return FAM.getResult<BlockFrequencyAnalysis>(F);
    145   };
    146   auto GetTTI = [&FAM](Function &F) -> TargetTransformInfo & {
    147     return FAM.getResult<TargetIRAnalysis>(F);
    148   };
    149 
    150   runCGProfilePass(M, GetBFI, GetTTI, false);
    151 
    152   return PreservedAnalyses::all();
    153 }
    154