1 //===- bolt/Passes/StokeInfo.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 StokeInfo class.
11 //===----------------------------------------------------------------------===//
13 #include "bolt/Passes/StokeInfo.h"
14 #include "bolt/Core/BinaryFunctionCallGraph.h"
15 #include "bolt/Passes/DataflowInfoManager.h"
16 #include "llvm/Support/CommandLine.h"
18 #define DEBUG_TYPE "stoke"
24 cl::OptionCategory
StokeOptCategory("STOKE pass options");
26 static cl::opt
<std::string
>
27 StokeOutputDataFilename("stoke-out",
28 cl::desc("output data (.csv) for Stoke's use"),
30 cl::cat(StokeOptCategory
));
36 void getRegNameFromBitVec(const BinaryContext
&BC
, const BitVector
&RegV
,
37 std::set
<std::string
> *NameVec
= nullptr) {
38 for (int RegIdx
: RegV
.set_bits()) {
39 LLVM_DEBUG(dbgs() << BC
.MRI
->getName(RegIdx
) << " ");
41 NameVec
->insert(std::string(BC
.MRI
->getName(RegIdx
)));
43 LLVM_DEBUG(dbgs() << "\n");
46 void StokeInfo::checkInstr(const BinaryFunction
&BF
, StokeFuncInfo
&FuncInfo
) {
47 MCPlusBuilder
*MIB
= BF
.getBinaryContext().MIB
.get();
48 BitVector
RegV(NumRegs
, false);
49 for (const BinaryBasicBlock
*BB
: BF
.getLayout().blocks()) {
53 // Skip function with exception handling.
54 if (BB
->throw_size() || BB
->lp_size()) {
55 FuncInfo
.Omitted
= true;
59 for (const MCInst
&It
: *BB
) {
60 if (MIB
->isPseudo(It
))
62 // skip function with exception handling yet
63 if (MIB
->isInvoke(It
)) {
64 FuncInfo
.Omitted
= true;
67 // check if this function contains call instruction
68 if (MIB
->isCall(It
)) {
69 FuncInfo
.HasCall
= true;
70 const MCSymbol
*TargetSymbol
= MIB
->getTargetSymbol(It
);
71 // if it is an indirect call, skip
72 if (TargetSymbol
== nullptr) {
73 FuncInfo
.Omitted
= true;
77 // check if this function modify stack or heap
78 // TODO: more accurate analysis
79 bool IsPush
= MIB
->isPush(It
);
80 bool IsRipAddr
= MIB
->hasPCRelOperand(It
);
82 FuncInfo
.StackOut
= true;
84 if (MIB
->mayStore(It
) && !IsPush
&& !IsRipAddr
)
85 FuncInfo
.HeapOut
= true;
88 FuncInfo
.HasRipAddr
= true;
89 } // end of for (auto &It : ...)
90 } // end of for (auto *BB : ...)
93 bool StokeInfo::checkFunction(BinaryFunction
&BF
, DataflowInfoManager
&DInfo
,
94 RegAnalysis
&RA
, StokeFuncInfo
&FuncInfo
) {
96 std::string Name
= BF
.getSymbol()->getName().str();
98 if (!BF
.isSimple() || BF
.isMultiEntry() || BF
.empty())
100 BF
.getBinaryContext().outs()
101 << " STOKE-INFO: analyzing function " << Name
<< "\n";
103 FuncInfo
.FuncName
= Name
;
104 FuncInfo
.Offset
= BF
.getFileOffset();
105 FuncInfo
.Size
= BF
.getMaxSize();
106 FuncInfo
.NumInstrs
= BF
.getNumNonPseudos();
107 FuncInfo
.NumBlocks
= BF
.size();
108 // early stop for large functions
109 if (FuncInfo
.NumInstrs
> 500)
112 FuncInfo
.IsLoopFree
= BF
.isLoopFree();
113 if (!FuncInfo
.IsLoopFree
) {
114 const BinaryLoopInfo
&BLI
= BF
.getLoopInfo();
115 FuncInfo
.NumLoops
= BLI
.OuterLoops
;
116 FuncInfo
.MaxLoopDepth
= BLI
.MaximumDepth
;
119 FuncInfo
.HotSize
= BF
.estimateHotSize();
120 FuncInfo
.TotalSize
= BF
.estimateSize();
121 FuncInfo
.Score
= BF
.getFunctionScore();
123 checkInstr(BF
, FuncInfo
);
126 BinaryBasicBlock
&EntryBB
= BF
.front();
127 assert(EntryBB
.isEntryPoint() && "Weird, this should be the entry block!");
129 MCInst
*FirstNonPseudo
= EntryBB
.getFirstNonPseudoInstr();
133 LLVM_DEBUG(dbgs() << "\t [DefIn]\n\t ");
135 *(DInfo
.getLivenessAnalysis().getStateAt(FirstNonPseudo
));
136 LiveInBV
&= DefaultDefInMask
;
137 getRegNameFromBitVec(BF
.getBinaryContext(), LiveInBV
, &FuncInfo
.DefIn
);
139 LLVM_DEBUG(dbgs() << "\t [LiveOut]\n\t ");
140 BitVector LiveOutBV
= RA
.getFunctionClobberList(&BF
);
141 LiveOutBV
&= DefaultLiveOutMask
;
142 getRegNameFromBitVec(BF
.getBinaryContext(), LiveOutBV
, &FuncInfo
.LiveOut
);
144 BF
.getBinaryContext().outs() << " STOKE-INFO: end function \n";
148 Error
StokeInfo::runOnFunctions(BinaryContext
&BC
) {
149 BC
.outs() << "STOKE-INFO: begin of stoke pass\n";
151 std::ofstream Outfile
;
152 if (!opts::StokeOutputDataFilename
.empty()) {
153 Outfile
.open(opts::StokeOutputDataFilename
);
155 BC
.errs() << "STOKE-INFO: output file is required\n";
156 return Error::success();
159 // check some context meta data
160 LLVM_DEBUG(dbgs() << "\tTarget: " << BC
.TheTarget
->getName() << "\n");
161 LLVM_DEBUG(dbgs() << "\tTripleName " << BC
.TripleName
<< "\n");
162 LLVM_DEBUG(dbgs() << "\tgetNumRegs " << BC
.MRI
->getNumRegs() << "\n");
164 BinaryFunctionCallGraph CG
= buildCallGraph(BC
);
165 RegAnalysis
RA(BC
, &BC
.getBinaryFunctions(), &CG
);
167 NumRegs
= BC
.MRI
->getNumRegs();
168 assert(NumRegs
> 0 && "STOKE-INFO: the target register number is incorrect!");
170 DefaultDefInMask
.resize(NumRegs
, false);
171 DefaultLiveOutMask
.resize(NumRegs
, false);
173 BC
.MIB
->getDefaultDefIn(DefaultDefInMask
);
174 BC
.MIB
->getDefaultLiveOut(DefaultLiveOutMask
);
176 getRegNameFromBitVec(BC
, DefaultDefInMask
);
177 getRegNameFromBitVec(BC
, DefaultLiveOutMask
);
179 StokeFuncInfo FuncInfo
;
180 // analyze all functions
181 FuncInfo
.printCsvHeader(Outfile
);
182 for (auto &BF
: BC
.getBinaryFunctions()) {
183 DataflowInfoManager
DInfo(BF
.second
, &RA
, nullptr);
185 if (checkFunction(BF
.second
, DInfo
, RA
, FuncInfo
))
186 FuncInfo
.printData(Outfile
);
189 BC
.outs() << "STOKE-INFO: end of stoke pass\n";
190 return Error::success();