195 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8//9// This file implements the StokeInfo class.10//11//===----------------------------------------------------------------------===//12 13#include "bolt/Passes/StokeInfo.h"14#include "bolt/Core/BinaryFunctionCallGraph.h"15#include "bolt/Passes/DataflowInfoManager.h"16#include "llvm/Support/CommandLine.h"17 18#define DEBUG_TYPE "stoke"19 20using namespace llvm;21using namespace bolt;22 23namespace opts {24static cl::OptionCategory StokeOptCategory("STOKE pass options");25 26static cl::opt<std::string>27StokeOutputDataFilename("stoke-out",28 cl::desc("output data (.csv) for Stoke's use"),29 cl::Optional,30 cl::cat(StokeOptCategory));31}32 33namespace llvm {34namespace bolt {35 36void 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 46void 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()) {50 if (BB->empty())51 continue;52 53 // Skip function with exception handling.54 if (BB->throw_size() || BB->lp_size()) {55 FuncInfo.Omitted = true;56 return;57 }58 59 for (const MCInst &It : *BB) {60 if (MIB->isPseudo(It))61 continue;62 // skip function with exception handling yet63 if (MIB->isInvoke(It)) {64 FuncInfo.Omitted = true;65 return;66 }67 // check if this function contains call instruction68 if (MIB->isCall(It)) {69 FuncInfo.HasCall = true;70 const MCSymbol *TargetSymbol = MIB->getTargetSymbol(It);71 // if it is an indirect call, skip72 if (TargetSymbol == nullptr) {73 FuncInfo.Omitted = true;74 return;75 }76 }77 // check if this function modify stack or heap78 // TODO: more accurate analysis79 bool IsPush = MIB->isPush(It);80 bool IsRipAddr = MIB->hasPCRelOperand(It);81 if (IsPush)82 FuncInfo.StackOut = true;83 84 if (MIB->mayStore(It) && !IsPush && !IsRipAddr)85 FuncInfo.HeapOut = true;86 87 if (IsRipAddr)88 FuncInfo.HasRipAddr = true;89 } // end of for (auto &It : ...)90 } // end of for (auto *BB : ...)91}92 93bool StokeInfo::checkFunction(BinaryFunction &BF, DataflowInfoManager &DInfo,94 RegAnalysis &RA, StokeFuncInfo &FuncInfo) {95 96 std::string Name = BF.getSymbol()->getName().str();97 98 if (!BF.isSimple() || BF.isMultiEntry() || BF.empty())99 return false;100 BF.getBinaryContext().outs()101 << " STOKE-INFO: analyzing function " << Name << "\n";102 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 functions109 if (FuncInfo.NumInstrs > 500)110 return false;111 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;117 }118 119 FuncInfo.HotSize = BF.estimateHotSize();120 FuncInfo.TotalSize = BF.estimateSize();121 FuncInfo.Score = BF.getFunctionScore();122 123 checkInstr(BF, FuncInfo);124 125 // register analysis126 BinaryBasicBlock &EntryBB = BF.front();127 assert(EntryBB.isEntryPoint() && "Weird, this should be the entry block!");128 129 MCInst *FirstNonPseudo = EntryBB.getFirstNonPseudoInstr();130 if (!FirstNonPseudo)131 return false;132 133 LLVM_DEBUG(dbgs() << "\t [DefIn]\n\t ");134 BitVector LiveInBV =135 *(DInfo.getLivenessAnalysis().getStateAt(FirstNonPseudo));136 LiveInBV &= DefaultDefInMask;137 getRegNameFromBitVec(BF.getBinaryContext(), LiveInBV, &FuncInfo.DefIn);138 139 LLVM_DEBUG(dbgs() << "\t [LiveOut]\n\t ");140 BitVector LiveOutBV = RA.getFunctionClobberList(&BF);141 LiveOutBV &= DefaultLiveOutMask;142 getRegNameFromBitVec(BF.getBinaryContext(), LiveOutBV, &FuncInfo.LiveOut);143 144 BF.getBinaryContext().outs() << " STOKE-INFO: end function \n";145 return true;146}147 148Error StokeInfo::runOnFunctions(BinaryContext &BC) {149 BC.outs() << "STOKE-INFO: begin of stoke pass\n";150 151 std::ofstream Outfile;152 if (!opts::StokeOutputDataFilename.empty()) {153 Outfile.open(opts::StokeOutputDataFilename);154 } else {155 BC.errs() << "STOKE-INFO: output file is required\n";156 return Error::success();157 }158 159 // check some context meta data160 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");163 164 BinaryFunctionCallGraph CG = buildCallGraph(BC);165 RegAnalysis RA(BC, &BC.getBinaryFunctions(), &CG);166 167 NumRegs = BC.MRI->getNumRegs();168 assert(NumRegs > 0 && "STOKE-INFO: the target register number is incorrect!");169 170 DefaultDefInMask.resize(NumRegs, false);171 DefaultLiveOutMask.resize(NumRegs, false);172 173 BC.MIB->getDefaultDefIn(DefaultDefInMask);174 BC.MIB->getDefaultLiveOut(DefaultLiveOutMask);175 176 getRegNameFromBitVec(BC, DefaultDefInMask);177 getRegNameFromBitVec(BC, DefaultLiveOutMask);178 179 StokeFuncInfo FuncInfo;180 // analyze all functions181 FuncInfo.printCsvHeader(Outfile);182 for (auto &BF : BC.getBinaryFunctions()) {183 DataflowInfoManager DInfo(BF.second, &RA, nullptr);184 FuncInfo.reset();185 if (checkFunction(BF.second, DInfo, RA, FuncInfo))186 FuncInfo.printData(Outfile);187 }188 189 BC.outs() << "STOKE-INFO: end of stoke pass\n";190 return Error::success();191}192 193} // namespace bolt194} // namespace llvm195