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/Passes/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 (BinaryBasicBlock
*BB
: BF
.layout()) {
53 for (MCInst
&It
: *BB
) {
54 if (MIB
->isPseudo(It
))
56 // skip function with exception handling yet
57 if (MIB
->isEHLabel(It
) || MIB
->isInvoke(It
)) {
58 FuncInfo
.Omitted
= true;
61 // check if this function contains call instruction
62 if (MIB
->isCall(It
)) {
63 FuncInfo
.HasCall
= true;
64 const MCSymbol
*TargetSymbol
= MIB
->getTargetSymbol(It
);
65 // if it is an indirect call, skip
66 if (TargetSymbol
== nullptr) {
67 FuncInfo
.Omitted
= true;
71 // check if this function modify stack or heap
72 // TODO: more accurate analysis
73 bool IsPush
= MIB
->isPush(It
);
74 bool IsRipAddr
= MIB
->hasPCRelOperand(It
);
76 FuncInfo
.StackOut
= true;
78 if (MIB
->isStore(It
) && !IsPush
&& !IsRipAddr
)
79 FuncInfo
.HeapOut
= true;
82 FuncInfo
.HasRipAddr
= true;
83 } // end of for (auto &It : ...)
84 } // end of for (auto *BB : ...)
87 bool StokeInfo::checkFunction(BinaryFunction
&BF
, DataflowInfoManager
&DInfo
,
88 RegAnalysis
&RA
, StokeFuncInfo
&FuncInfo
) {
90 std::string Name
= BF
.getSymbol()->getName().str();
92 if (!BF
.isSimple() || BF
.isMultiEntry() || BF
.empty())
94 outs() << " STOKE-INFO: analyzing function " << Name
<< "\n";
96 FuncInfo
.FuncName
= Name
;
97 FuncInfo
.Offset
= BF
.getFileOffset();
98 FuncInfo
.Size
= BF
.getMaxSize();
99 FuncInfo
.NumInstrs
= BF
.getNumNonPseudos();
100 FuncInfo
.NumBlocks
= BF
.size();
101 // early stop for large functions
102 if (FuncInfo
.NumInstrs
> 500)
105 FuncInfo
.IsLoopFree
= BF
.isLoopFree();
106 if (!FuncInfo
.IsLoopFree
) {
107 const BinaryLoopInfo
&BLI
= BF
.getLoopInfo();
108 FuncInfo
.NumLoops
= BLI
.OuterLoops
;
109 FuncInfo
.MaxLoopDepth
= BLI
.MaximumDepth
;
112 FuncInfo
.HotSize
= BF
.estimateHotSize();
113 FuncInfo
.TotalSize
= BF
.estimateSize();
114 FuncInfo
.Score
= BF
.getFunctionScore();
116 checkInstr(BF
, FuncInfo
);
119 BinaryBasicBlock
&EntryBB
= BF
.front();
120 assert(EntryBB
.isEntryPoint() && "Weird, this should be the entry block!");
122 MCInst
*FirstNonPseudo
= EntryBB
.getFirstNonPseudoInstr();
126 LLVM_DEBUG(dbgs() << "\t [DefIn]\n\t ");
128 *(DInfo
.getLivenessAnalysis().getStateAt(FirstNonPseudo
));
129 LiveInBV
&= DefaultDefInMask
;
130 getRegNameFromBitVec(BF
.getBinaryContext(), LiveInBV
, &FuncInfo
.DefIn
);
132 LLVM_DEBUG(dbgs() << "\t [LiveOut]\n\t ");
133 BitVector LiveOutBV
= RA
.getFunctionClobberList(&BF
);
134 LiveOutBV
&= DefaultLiveOutMask
;
135 getRegNameFromBitVec(BF
.getBinaryContext(), LiveOutBV
, &FuncInfo
.LiveOut
);
137 outs() << " STOKE-INFO: end function \n";
141 void StokeInfo::runOnFunctions(BinaryContext
&BC
) {
142 outs() << "STOKE-INFO: begin of stoke pass\n";
144 std::ofstream Outfile
;
145 if (!opts::StokeOutputDataFilename
.empty()) {
146 Outfile
.open(opts::StokeOutputDataFilename
);
148 errs() << "STOKE-INFO: output file is required\n";
152 // check some context meta data
153 LLVM_DEBUG(dbgs() << "\tTarget: " << BC
.TheTarget
->getName() << "\n");
154 LLVM_DEBUG(dbgs() << "\tTripleName " << BC
.TripleName
<< "\n");
155 LLVM_DEBUG(dbgs() << "\tgetNumRegs " << BC
.MRI
->getNumRegs() << "\n");
157 BinaryFunctionCallGraph CG
= buildCallGraph(BC
);
158 RegAnalysis
RA(BC
, &BC
.getBinaryFunctions(), &CG
);
160 NumRegs
= BC
.MRI
->getNumRegs();
161 assert(NumRegs
> 0 && "STOKE-INFO: the target register number is incorrect!");
163 DefaultDefInMask
.resize(NumRegs
, false);
164 DefaultLiveOutMask
.resize(NumRegs
, false);
166 BC
.MIB
->getDefaultDefIn(DefaultDefInMask
);
167 BC
.MIB
->getDefaultLiveOut(DefaultLiveOutMask
);
169 getRegNameFromBitVec(BC
, DefaultDefInMask
);
170 getRegNameFromBitVec(BC
, DefaultLiveOutMask
);
172 StokeFuncInfo FuncInfo
;
173 // analyze all functions
174 FuncInfo
.printCsvHeader(Outfile
);
175 for (auto &BF
: BC
.getBinaryFunctions()) {
176 DataflowInfoManager
DInfo(BF
.second
, &RA
, nullptr);
178 if (checkFunction(BF
.second
, DInfo
, RA
, FuncInfo
))
179 FuncInfo
.printData(Outfile
);
182 outs() << "STOKE-INFO: end of stoke pass\n";