1 //===- bolt/Passes/RegAnalysis.cpp ----------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
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"
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
));
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
) {
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
;
50 RegsKilledMap
[Func
] = std::move(RegsKilled
);
54 CGWalker
.registerVisitor([&](BinaryFunction
*Func
) -> bool {
55 BitVector RegsGen
= getFunctionUsedRegsList(Func
);
56 bool Updated
= RegsGenMap
.find(Func
) == RegsGenMap
.end() ||
57 RegsGenMap
[Func
] != RegsGen
;
59 RegsGenMap
[Func
] = std::move(RegsGen
);
65 if (opts::Verbosity
== 0) {
67 if (!DebugFlag
|| !isCurrentDebugType(DEBUG_TYPE
))
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
;
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
);
109 void RegAnalysis::beConservative(BitVector
&Result
) const {
111 case ConservativeStrategy::CLOBBERS_ALL
:
114 case ConservativeStrategy::CLOBBERS_ABI
: {
115 BitVector
BV(BC
.MRI
->getNumRegs(), false);
116 BC
.MIB
->getCalleeSavedRegs(BV
);
121 case ConservativeStrategy::CLOBBERS_NONE
:
127 bool RegAnalysis::isConservative(BitVector
&Vec
) const {
129 case ConservativeStrategy::CLOBBERS_ALL
:
131 case ConservativeStrategy::CLOBBERS_ABI
: {
132 BitVector
BV(BC
.MRI
->getNumRegs(), false);
133 BC
.MIB
->getCalleeSavedRegs(BV
);
137 case ConservativeStrategy::CLOBBERS_NONE
:
143 void RegAnalysis::getInstUsedRegsList(const MCInst
&Inst
, BitVector
&RegSet
,
144 bool GetClobbers
) const {
145 if (!BC
.MIB
->isCall(Inst
)) {
147 BC
.MIB
->getClobberedRegs(Inst
, RegSet
);
149 BC
.MIB
->getUsedRegs(Inst
, RegSet
);
153 // If no call graph supplied...
154 if (RegsKilledMap
.size() == 0) {
155 beConservative(RegSet
);
159 const MCSymbol
*TargetSymbol
= BC
.MIB
->getTargetSymbol(Inst
);
160 // If indirect call, we know nothing
161 if (TargetSymbol
== nullptr) {
162 beConservative(RegSet
);
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
);
175 auto BV
= RegsKilledMap
.find(Function
);
176 if (BV
!= RegsKilledMap
.end()) {
177 RegSet
|= BV
->second
;
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.
184 auto BV
= RegsGenMap
.find(Function
);
185 if (BV
!= RegsGenMap
.end()) {
186 RegSet
|= BV
->second
;
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
);
204 for (const BinaryBasicBlock
&BB
: *Func
) {
205 for (const MCInst
&Inst
: BB
) {
206 getInstUsedRegsList(Inst
, UsedRegs
, /*GetClobbers*/ false);
215 BitVector
RegAnalysis::getFunctionClobberList(const BinaryFunction
*Func
) {
216 BitVector RegsKilled
= BitVector(BC
.MRI
->getNumRegs(), false);
218 if (!Func
->isSimple() || !Func
->hasCFG()) {
219 beConservative(RegsKilled
);
223 for (const BinaryBasicBlock
&BB
: *Func
) {
224 for (const MCInst
&Inst
: BB
) {
225 getInstClobberList(Inst
, RegsKilled
);
226 if (RegsKilled
.all())
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
));