1 //===- bolt/Passes/StokeInfo.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 StokeInfo class.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #include "bolt/Passes/StokeInfo.h"
14 #include "bolt/Passes/BinaryFunctionCallGraph.h"
15 #include "bolt/Passes/DataflowInfoManager.h"
16 #include "llvm/Support/CommandLine.h"
17 
18 #define DEBUG_TYPE "stoke"
19 
20 using namespace llvm;
21 using namespace bolt;
22 
23 namespace opts {
24 cl::OptionCategory StokeOptCategory("STOKE pass options");
25 
26 static cl::opt<std::string>
27 StokeOutputDataFilename("stoke-out",
28   cl::desc("output data (.csv) for Stoke's use"),
29   cl::Optional,
30   cl::cat(StokeOptCategory));
31 }
32 
33 namespace llvm {
34 namespace bolt {
35 
getRegNameFromBitVec(const BinaryContext & BC,const BitVector & RegV,std::set<std::string> * NameVec=nullptr)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) << " ");
40     if (NameVec)
41       NameVec->insert(std::string(BC.MRI->getName(RegIdx)));
42   }
43   LLVM_DEBUG(dbgs() << "\n");
44 }
45 
checkInstr(const BinaryFunction & BF,StokeFuncInfo & FuncInfo)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.getLayout().blocks()) {
50     if (BB->empty())
51       continue;
52 
53     for (MCInst &It : *BB) {
54       if (MIB->isPseudo(It))
55         continue;
56       // skip function with exception handling yet
57       if (MIB->isEHLabel(It) || MIB->isInvoke(It)) {
58         FuncInfo.Omitted = true;
59         return;
60       }
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;
68           return;
69         }
70       }
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);
75       if (IsPush)
76         FuncInfo.StackOut = true;
77 
78       if (MIB->isStore(It) && !IsPush && !IsRipAddr)
79         FuncInfo.HeapOut = true;
80 
81       if (IsRipAddr)
82         FuncInfo.HasRipAddr = true;
83     } // end of for (auto &It : ...)
84   }   // end of for (auto *BB : ...)
85 }
86 
checkFunction(BinaryFunction & BF,DataflowInfoManager & DInfo,RegAnalysis & RA,StokeFuncInfo & FuncInfo)87 bool StokeInfo::checkFunction(BinaryFunction &BF, DataflowInfoManager &DInfo,
88                               RegAnalysis &RA, StokeFuncInfo &FuncInfo) {
89 
90   std::string Name = BF.getSymbol()->getName().str();
91 
92   if (!BF.isSimple() || BF.isMultiEntry() || BF.empty())
93     return false;
94   outs() << " STOKE-INFO: analyzing function " << Name << "\n";
95 
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)
103     return false;
104 
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;
110   }
111 
112   FuncInfo.HotSize = BF.estimateHotSize();
113   FuncInfo.TotalSize = BF.estimateSize();
114   FuncInfo.Score = BF.getFunctionScore();
115 
116   checkInstr(BF, FuncInfo);
117 
118   // register analysis
119   BinaryBasicBlock &EntryBB = BF.front();
120   assert(EntryBB.isEntryPoint() && "Weird, this should be the entry block!");
121 
122   MCInst *FirstNonPseudo = EntryBB.getFirstNonPseudoInstr();
123   if (!FirstNonPseudo)
124     return false;
125 
126   LLVM_DEBUG(dbgs() << "\t [DefIn]\n\t ");
127   BitVector LiveInBV =
128       *(DInfo.getLivenessAnalysis().getStateAt(FirstNonPseudo));
129   LiveInBV &= DefaultDefInMask;
130   getRegNameFromBitVec(BF.getBinaryContext(), LiveInBV, &FuncInfo.DefIn);
131 
132   LLVM_DEBUG(dbgs() << "\t [LiveOut]\n\t ");
133   BitVector LiveOutBV = RA.getFunctionClobberList(&BF);
134   LiveOutBV &= DefaultLiveOutMask;
135   getRegNameFromBitVec(BF.getBinaryContext(), LiveOutBV, &FuncInfo.LiveOut);
136 
137   outs() << " STOKE-INFO: end function \n";
138   return true;
139 }
140 
runOnFunctions(BinaryContext & BC)141 void StokeInfo::runOnFunctions(BinaryContext &BC) {
142   outs() << "STOKE-INFO: begin of stoke pass\n";
143 
144   std::ofstream Outfile;
145   if (!opts::StokeOutputDataFilename.empty()) {
146     Outfile.open(opts::StokeOutputDataFilename);
147   } else {
148     errs() << "STOKE-INFO: output file is required\n";
149     return;
150   }
151 
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");
156 
157   BinaryFunctionCallGraph CG = buildCallGraph(BC);
158   RegAnalysis RA(BC, &BC.getBinaryFunctions(), &CG);
159 
160   NumRegs = BC.MRI->getNumRegs();
161   assert(NumRegs > 0 && "STOKE-INFO: the target register number is incorrect!");
162 
163   DefaultDefInMask.resize(NumRegs, false);
164   DefaultLiveOutMask.resize(NumRegs, false);
165 
166   BC.MIB->getDefaultDefIn(DefaultDefInMask);
167   BC.MIB->getDefaultLiveOut(DefaultLiveOutMask);
168 
169   getRegNameFromBitVec(BC, DefaultDefInMask);
170   getRegNameFromBitVec(BC, DefaultLiveOutMask);
171 
172   StokeFuncInfo FuncInfo;
173   // analyze all functions
174   FuncInfo.printCsvHeader(Outfile);
175   for (auto &BF : BC.getBinaryFunctions()) {
176     DataflowInfoManager DInfo(BF.second, &RA, nullptr);
177     FuncInfo.reset();
178     if (checkFunction(BF.second, DInfo, RA, FuncInfo))
179       FuncInfo.printData(Outfile);
180   }
181 
182   outs() << "STOKE-INFO: end of stoke pass\n";
183 }
184 
185 } // namespace bolt
186 } // namespace llvm
187