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(V: E.first.first), |
37 | ValueAsMetadata::get(V: E.first.second), |
38 | MDB.createConstant(C: ConstantInt::get( |
39 | Ty: Type::getInt64Ty(C&: Context), V: E.second))}; |
40 | Nodes.push_back(x: MDNode::get(Context, MDs: Vals)); |
41 | } |
42 | |
43 | M.addModuleFlag(Behavior: Module::Append, Key: "CG Profile" , |
44 | Val: MDTuple::getDistinct(Context, MDs: 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(F: CalledF) || |
57 | CalledF->hasDLLImportStorageClass()) |
58 | return; |
59 | uint64_t &Count = Counts[std::make_pair(x&: F, y&: CalledF)]; |
60 | Count = SaturatingAdd(X: Count, Y: 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>(IR&: F); |
70 | if (BFI.getEntryFreq() == BlockFrequency(0)) |
71 | continue; |
72 | TargetTransformInfo &TTI = FAM.getResult<TargetIRAnalysis>(IR&: F); |
73 | for (auto &BB : F) { |
74 | std::optional<uint64_t> BBCount = BFI.getBlockProfileCount(BB: &BB); |
75 | if (!BBCount) |
76 | continue; |
77 | for (auto &I : BB) { |
78 | CallBase *CB = dyn_cast<CallBase>(Val: &I); |
79 | if (!CB) |
80 | continue; |
81 | if (CB->isIndirectCall()) { |
82 | uint64_t TotalC; |
83 | auto ValueData = |
84 | getValueProfDataFromInst(Inst: *CB, ValueKind: IPVK_IndirectCallTarget, MaxNumValueData: 8, TotalC); |
85 | for (const auto &VD : ValueData) |
86 | UpdateCounts(TTI, &F, Symtab.getFunction(FuncMD5Hash: 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>(IR&: M).getManager(); |
100 | runCGProfilePass(M, FAM, InLTO); |
101 | |
102 | return PreservedAnalyses::all(); |
103 | } |
104 | |