Run DCE after a LoopFlatten test to reduce spurious output [nfc]
[llvm-project.git] / bolt / lib / Passes / RegAnalysis.cpp
blobeab16cb0903289b9207daa0caddfb283a6722c71
1 //===- bolt/Passes/RegAnalysis.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 // This file implements the RegAnalysis class.
11 //===----------------------------------------------------------------------===//
13 #include "bolt/Passes/RegAnalysis.h"
14 #include "bolt/Core/BinaryFunction.h"
15 #include "bolt/Passes/CallGraphWalker.h"
16 #include "llvm/MC/MCRegisterInfo.h"
17 #include "llvm/Support/CommandLine.h"
19 #define DEBUG_TYPE "ra"
21 using namespace llvm;
23 namespace opts {
24 extern cl::opt<unsigned> Verbosity;
25 extern cl::OptionCategory BoltOptCategory;
27 cl::opt<bool> AssumeABI("assume-abi",
28 cl::desc("assume the ABI is never violated"),
29 cl::cat(BoltOptCategory));
32 namespace llvm {
33 namespace bolt {
35 RegAnalysis::RegAnalysis(BinaryContext &BC,
36 std::map<uint64_t, BinaryFunction> *BFs,
37 BinaryFunctionCallGraph *CG)
38 : BC(BC), CS(opts::AssumeABI ? ConservativeStrategy::CLOBBERS_ABI
39 : ConservativeStrategy::CLOBBERS_ALL) {
40 if (!CG)
41 return;
43 CallGraphWalker CGWalker(*CG);
45 CGWalker.registerVisitor([&](BinaryFunction *Func) -> bool {
46 BitVector RegsKilled = getFunctionClobberList(Func);
47 bool Updated = RegsKilledMap.find(Func) == RegsKilledMap.end() ||
48 RegsKilledMap[Func] != RegsKilled;
49 if (Updated)
50 RegsKilledMap[Func] = std::move(RegsKilled);
51 return Updated;
52 });
54 CGWalker.registerVisitor([&](BinaryFunction *Func) -> bool {
55 BitVector RegsGen = getFunctionUsedRegsList(Func);
56 bool Updated = RegsGenMap.find(Func) == RegsGenMap.end() ||
57 RegsGenMap[Func] != RegsGen;
58 if (Updated)
59 RegsGenMap[Func] = std::move(RegsGen);
60 return Updated;
61 });
63 CGWalker.walk();
65 if (opts::Verbosity == 0) {
66 #ifndef NDEBUG
67 if (!DebugFlag || !isCurrentDebugType(DEBUG_TYPE))
68 return;
69 #else
70 return;
71 #endif
74 if (!BFs)
75 return;
77 // This loop is for computing statistics only
78 for (auto &MapEntry : *BFs) {
79 BinaryFunction *Func = &MapEntry.second;
80 auto Iter = RegsKilledMap.find(Func);
81 assert(Iter != RegsKilledMap.end() &&
82 "Failed to compute all clobbers list");
83 if (Iter->second.all()) {
84 uint64_t Count = Func->getExecutionCount();
85 if (Count != BinaryFunction::COUNT_NO_PROFILE)
86 CountFunctionsAllClobber += Count;
87 ++NumFunctionsAllClobber;
89 DEBUG_WITH_TYPE("ra",
90 dbgs() << "Killed regs set for func: " << Func->getPrintName() << "\n";
91 const BitVector &RegsKilled = Iter->second;
92 int RegIdx = RegsKilled.find_first();
93 while (RegIdx != -1) {
94 dbgs() << "\tREG" << RegIdx;
95 RegIdx = RegsKilled.find_next(RegIdx);
97 dbgs() << "\nUsed regs set for func: " << Func->getPrintName() << "\n";
98 const BitVector &RegsUsed = RegsGenMap.find(Func)->second;
99 RegIdx = RegsUsed.find_first();
100 while (RegIdx != -1) {
101 dbgs() << "\tREG" << RegIdx;
102 RegIdx = RegsUsed.find_next(RegIdx);
104 dbgs() << "\n";
109 void RegAnalysis::beConservative(BitVector &Result) const {
110 switch (CS) {
111 case ConservativeStrategy::CLOBBERS_ALL:
112 Result.set();
113 break;
114 case ConservativeStrategy::CLOBBERS_ABI: {
115 BitVector BV(BC.MRI->getNumRegs(), false);
116 BC.MIB->getCalleeSavedRegs(BV);
117 BV.flip();
118 Result |= BV;
119 break;
121 case ConservativeStrategy::CLOBBERS_NONE:
122 Result.reset();
123 break;
127 bool RegAnalysis::isConservative(BitVector &Vec) const {
128 switch (CS) {
129 case ConservativeStrategy::CLOBBERS_ALL:
130 return Vec.all();
131 case ConservativeStrategy::CLOBBERS_ABI: {
132 BitVector BV(BC.MRI->getNumRegs(), false);
133 BC.MIB->getCalleeSavedRegs(BV);
134 BV |= Vec;
135 return BV.all();
137 case ConservativeStrategy::CLOBBERS_NONE:
138 return Vec.none();
140 return false;
143 void RegAnalysis::getInstUsedRegsList(const MCInst &Inst, BitVector &RegSet,
144 bool GetClobbers) const {
145 if (!BC.MIB->isCall(Inst)) {
146 if (GetClobbers)
147 BC.MIB->getClobberedRegs(Inst, RegSet);
148 else
149 BC.MIB->getUsedRegs(Inst, RegSet);
150 return;
153 // If no call graph supplied...
154 if (RegsKilledMap.size() == 0) {
155 beConservative(RegSet);
156 return;
159 const MCSymbol *TargetSymbol = BC.MIB->getTargetSymbol(Inst);
160 // If indirect call, we know nothing
161 if (TargetSymbol == nullptr) {
162 beConservative(RegSet);
163 return;
166 const BinaryFunction *Function = BC.getFunctionForSymbol(TargetSymbol);
167 if (Function == nullptr) {
168 // Call to a function without a BinaryFunction object.
169 // This should be a call to a PLT entry, and since it is a trampoline to
170 // a DSO, we can't really know the code in advance.
171 beConservative(RegSet);
172 return;
174 if (GetClobbers) {
175 auto BV = RegsKilledMap.find(Function);
176 if (BV != RegsKilledMap.end()) {
177 RegSet |= BV->second;
178 return;
180 // Ignore calls to function whose clobber list wasn't yet calculated. This
181 // instruction will be evaluated again once we have info for the callee.
182 return;
184 auto BV = RegsGenMap.find(Function);
185 if (BV != RegsGenMap.end()) {
186 RegSet |= BV->second;
187 return;
191 void RegAnalysis::getInstClobberList(const MCInst &Inst,
192 BitVector &KillSet) const {
193 return getInstUsedRegsList(Inst, KillSet, /*GetClobbers*/ true);
196 BitVector RegAnalysis::getFunctionUsedRegsList(const BinaryFunction *Func) {
197 BitVector UsedRegs = BitVector(BC.MRI->getNumRegs(), false);
199 if (!Func->isSimple() || !Func->hasCFG()) {
200 beConservative(UsedRegs);
201 return UsedRegs;
204 for (const BinaryBasicBlock &BB : *Func) {
205 for (const MCInst &Inst : BB) {
206 getInstUsedRegsList(Inst, UsedRegs, /*GetClobbers*/ false);
207 if (UsedRegs.all())
208 return UsedRegs;
212 return UsedRegs;
215 BitVector RegAnalysis::getFunctionClobberList(const BinaryFunction *Func) {
216 BitVector RegsKilled = BitVector(BC.MRI->getNumRegs(), false);
218 if (!Func->isSimple() || !Func->hasCFG()) {
219 beConservative(RegsKilled);
220 return RegsKilled;
223 for (const BinaryBasicBlock &BB : *Func) {
224 for (const MCInst &Inst : BB) {
225 getInstClobberList(Inst, RegsKilled);
226 if (RegsKilled.all())
227 return RegsKilled;
231 return RegsKilled;
234 void RegAnalysis::printStats() {
235 outs() << "BOLT-INFO REG ANALYSIS: Number of functions conservatively "
236 "treated as clobbering all registers: "
237 << NumFunctionsAllClobber
238 << format(" (%.1lf%% dyn cov)\n",
239 (100.0 * CountFunctionsAllClobber / CountDenominator));
242 } // namespace bolt
243 } // namespace llvm