1 //===- bolt/Passes/StackPointerTracking.h -----------------------*- C++ -*-===// 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 #ifndef BOLT_PASSES_STACKPOINTERTRACKING_H 10 #define BOLT_PASSES_STACKPOINTERTRACKING_H 11 12 #include "bolt/Passes/DataflowAnalysis.h" 13 #include "llvm/Support/CommandLine.h" 14 15 namespace opts { 16 extern llvm::cl::opt<bool> TimeOpts; 17 } // namespace opts 18 19 namespace llvm { 20 namespace bolt { 21 22 /// Perform a dataflow analysis to track the value of SP as an offset relative 23 /// to the CFA. 24 template <typename Derived> 25 class StackPointerTrackingBase 26 : public DataflowAnalysis<Derived, std::pair<int, int>> { 27 friend class DataflowAnalysis<Derived, std::pair<int, int>>; 28 29 protected: preflight()30 void preflight() {} 31 getEmpty()32 int getEmpty() { return EMPTY; } 33 getStartingStateAtBB(const BinaryBasicBlock & BB)34 std::pair<int, int> getStartingStateAtBB(const BinaryBasicBlock &BB) { 35 // Entry BB start with offset 8 from CFA. 36 // All others start with EMPTY (meaning we don't know anything). 37 if (BB.isEntryPoint()) 38 return std::make_pair(-8, getEmpty()); 39 return std::make_pair(getEmpty(), getEmpty()); 40 } 41 getStartingStateAtPoint(const MCInst & Point)42 std::pair<int, int> getStartingStateAtPoint(const MCInst &Point) { 43 return std::make_pair(getEmpty(), getEmpty()); 44 } 45 doConfluenceSingleReg(int & StateOut,const int & StateIn)46 void doConfluenceSingleReg(int &StateOut, const int &StateIn) { 47 if (StateOut == EMPTY) { 48 StateOut = StateIn; 49 return; 50 } 51 if (StateIn == EMPTY || StateIn == StateOut) 52 return; 53 54 // We can't agree on a specific value from this point on 55 StateOut = SUPERPOSITION; 56 } 57 doConfluence(std::pair<int,int> & StateOut,const std::pair<int,int> & StateIn)58 void doConfluence(std::pair<int, int> &StateOut, 59 const std::pair<int, int> &StateIn) { 60 doConfluenceSingleReg(StateOut.first, StateIn.first); 61 doConfluenceSingleReg(StateOut.second, StateIn.second); 62 } 63 doConfluenceWithLP(std::pair<int,int> & StateOut,const std::pair<int,int> & StateIn,const MCInst & Invoke)64 void doConfluenceWithLP(std::pair<int, int> &StateOut, 65 const std::pair<int, int> &StateIn, 66 const MCInst &Invoke) { 67 int SPVal = StateIn.first; 68 if (SPVal != EMPTY && SPVal != SUPERPOSITION) { 69 const int64_t GnuArgsSize = this->BC.MIB->getGnuArgsSize(Invoke); 70 if (GnuArgsSize > 0) 71 SPVal += GnuArgsSize; 72 } 73 doConfluenceSingleReg(StateOut.first, SPVal); 74 doConfluenceSingleReg(StateOut.second, StateIn.second); 75 } 76 computeNextSP(const MCInst & Point,int SPVal,int FPVal)77 int computeNextSP(const MCInst &Point, int SPVal, int FPVal) { 78 const auto &MIB = this->BC.MIB; 79 80 if (int Sz = MIB->getPushSize(Point)) { 81 if (SPVal == EMPTY || SPVal == SUPERPOSITION) 82 return SPVal; 83 84 return SPVal - Sz; 85 } 86 87 if (int Sz = MIB->getPopSize(Point)) { 88 if (SPVal == EMPTY || SPVal == SUPERPOSITION) 89 return SPVal; 90 91 return SPVal + Sz; 92 } 93 94 MCPhysReg From, To; 95 if (MIB->isRegToRegMove(Point, From, To) && To == MIB->getStackPointer() && 96 From == MIB->getFramePointer()) { 97 if (FPVal == EMPTY || FPVal == SUPERPOSITION) 98 return FPVal; 99 100 if (MIB->isLeave(Point)) 101 return FPVal + 8; 102 return FPVal; 103 } 104 105 if (this->BC.MII->get(Point.getOpcode()) 106 .hasDefOfPhysReg(Point, MIB->getStackPointer(), *this->BC.MRI)) { 107 std::pair<MCPhysReg, int64_t> SP; 108 if (SPVal != EMPTY && SPVal != SUPERPOSITION) 109 SP = std::make_pair(MIB->getStackPointer(), SPVal); 110 else 111 SP = std::make_pair(0, 0); 112 std::pair<MCPhysReg, int64_t> FP; 113 if (FPVal != EMPTY && FPVal != SUPERPOSITION) 114 FP = std::make_pair(MIB->getFramePointer(), FPVal); 115 else 116 FP = std::make_pair(0, 0); 117 int64_t Output; 118 if (!MIB->evaluateStackOffsetExpr(Point, Output, SP, FP)) { 119 if (SPVal == EMPTY && FPVal == EMPTY) 120 return SPVal; 121 return SUPERPOSITION; 122 } 123 124 return static_cast<int>(Output); 125 } 126 127 return SPVal; 128 } 129 computeNextFP(const MCInst & Point,int SPVal,int FPVal)130 int computeNextFP(const MCInst &Point, int SPVal, int FPVal) { 131 const auto &MIB = this->BC.MIB; 132 133 MCPhysReg From, To; 134 if (MIB->isRegToRegMove(Point, From, To) && To == MIB->getFramePointer() && 135 From == MIB->getStackPointer()) { 136 HasFramePointer = true; 137 return SPVal; 138 } 139 140 if (this->BC.MII->get(Point.getOpcode()) 141 .hasDefOfPhysReg(Point, MIB->getFramePointer(), *this->BC.MRI)) { 142 std::pair<MCPhysReg, int64_t> FP; 143 if (FPVal != EMPTY && FPVal != SUPERPOSITION) 144 FP = std::make_pair(MIB->getFramePointer(), FPVal); 145 else 146 FP = std::make_pair(0, 0); 147 std::pair<MCPhysReg, int64_t> SP; 148 if (SPVal != EMPTY && SPVal != SUPERPOSITION) 149 SP = std::make_pair(MIB->getStackPointer(), SPVal); 150 else 151 SP = std::make_pair(0, 0); 152 int64_t Output; 153 if (!MIB->evaluateStackOffsetExpr(Point, Output, SP, FP)) { 154 if (SPVal == EMPTY && FPVal == EMPTY) 155 return FPVal; 156 return SUPERPOSITION; 157 } 158 159 if (!HasFramePointer && MIB->escapesVariable(Point, false)) 160 HasFramePointer = true; 161 return static_cast<int>(Output); 162 } 163 164 return FPVal; 165 } 166 computeNext(const MCInst & Point,const std::pair<int,int> & Cur)167 std::pair<int, int> computeNext(const MCInst &Point, 168 const std::pair<int, int> &Cur) { 169 return std::make_pair(computeNextSP(Point, Cur.first, Cur.second), 170 computeNextFP(Point, Cur.first, Cur.second)); 171 } 172 getAnnotationName()173 StringRef getAnnotationName() const { 174 return StringRef("StackPointerTracking"); 175 } 176 177 public: 178 StackPointerTrackingBase(BinaryFunction &BF, 179 MCPlusBuilder::AllocatorIdTy AllocatorId = 0) 180 : DataflowAnalysis<Derived, std::pair<int, int>>(BF, AllocatorId) {} 181 ~StackPointerTrackingBase()182 virtual ~StackPointerTrackingBase() {} 183 184 bool HasFramePointer{false}; 185 186 static constexpr int SUPERPOSITION = std::numeric_limits<int>::max(); 187 static constexpr int EMPTY = std::numeric_limits<int>::min(); 188 }; 189 190 class StackPointerTracking 191 : public StackPointerTrackingBase<StackPointerTracking> { 192 friend class DataflowAnalysis<StackPointerTracking, std::pair<int, int>>; 193 194 public: 195 StackPointerTracking(BinaryFunction &BF, 196 MCPlusBuilder::AllocatorIdTy AllocatorId = 0); ~StackPointerTracking()197 virtual ~StackPointerTracking() {} 198 run()199 void run() { StackPointerTrackingBase<StackPointerTracking>::run(); } 200 }; 201 202 } // end namespace bolt 203 204 llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, 205 const std::pair<int, int> &Val); 206 207 } // end namespace llvm 208 209 #endif 210