xref: /llvm-project/bolt/include/bolt/Passes/StackPointerTracking.h (revision c09cd64e5c6dea6e97ef7d6cee5f689df2b408d7)
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