js/src/jit/MoveResolver.h

changeset 0
6474c204b198
equal deleted inserted replaced
-1:000000000000 0:2f3c56db890a
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 * vim: set ts=8 sts=4 et sw=4 tw=99:
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7 #ifndef jit_MoveResolver_h
8 #define jit_MoveResolver_h
9
10 #include "jit/InlineList.h"
11 #include "jit/IonAllocPolicy.h"
12 #include "jit/Registers.h"
13
14 namespace js {
15 namespace jit {
16
17 // This is similar to Operand, but carries more information. We're also not
18 // guaranteed that Operand looks like this on all ISAs.
19 class MoveOperand
20 {
21 public:
22 enum Kind {
23 // A register in the "integer", aka "general purpose", class.
24 REG,
25 // A register in the "float" register class.
26 FLOAT_REG,
27 // A memory region.
28 MEMORY,
29 // The address of a memory region.
30 EFFECTIVE_ADDRESS
31 };
32
33 private:
34 Kind kind_;
35 uint32_t code_;
36 int32_t disp_;
37
38 public:
39 MoveOperand()
40 { }
41 explicit MoveOperand(const Register &reg) : kind_(REG), code_(reg.code())
42 { }
43 explicit MoveOperand(const FloatRegister &reg) : kind_(FLOAT_REG), code_(reg.code())
44 { }
45 MoveOperand(const Register &reg, int32_t disp, Kind kind = MEMORY)
46 : kind_(kind),
47 code_(reg.code()),
48 disp_(disp)
49 {
50 JS_ASSERT(isMemoryOrEffectiveAddress());
51
52 // With a zero offset, this is a plain reg-to-reg move.
53 if (disp == 0 && kind_ == EFFECTIVE_ADDRESS)
54 kind_ = REG;
55 }
56 MoveOperand(const MoveOperand &other)
57 : kind_(other.kind_),
58 code_(other.code_),
59 disp_(other.disp_)
60 { }
61 bool isFloatReg() const {
62 return kind_ == FLOAT_REG;
63 }
64 bool isGeneralReg() const {
65 return kind_ == REG;
66 }
67 bool isMemory() const {
68 return kind_ == MEMORY;
69 }
70 bool isEffectiveAddress() const {
71 return kind_ == EFFECTIVE_ADDRESS;
72 }
73 bool isMemoryOrEffectiveAddress() const {
74 return isMemory() || isEffectiveAddress();
75 }
76 Register reg() const {
77 JS_ASSERT(isGeneralReg());
78 return Register::FromCode(code_);
79 }
80 FloatRegister floatReg() const {
81 JS_ASSERT(isFloatReg());
82 return FloatRegister::FromCode(code_);
83 }
84 Register base() const {
85 JS_ASSERT(isMemoryOrEffectiveAddress());
86 return Register::FromCode(code_);
87 }
88 int32_t disp() const {
89 JS_ASSERT(isMemoryOrEffectiveAddress());
90 return disp_;
91 }
92
93 bool operator ==(const MoveOperand &other) const {
94 if (kind_ != other.kind_)
95 return false;
96 if (code_ != other.code_)
97 return false;
98 if (isMemoryOrEffectiveAddress())
99 return disp_ == other.disp_;
100 return true;
101 }
102 bool operator !=(const MoveOperand &other) const {
103 return !operator==(other);
104 }
105 };
106
107 // This represents a move operation.
108 class MoveOp
109 {
110 protected:
111 MoveOperand from_;
112 MoveOperand to_;
113 bool cycleBegin_;
114 bool cycleEnd_;
115
116 public:
117 enum Type {
118 GENERAL,
119 INT32,
120 FLOAT32,
121 DOUBLE
122 };
123
124 protected:
125 Type type_;
126
127 // If cycleBegin_ is true, endCycleType_ is the type of the move at the end
128 // of the cycle. For example, given these moves:
129 // INT32 move a -> b
130 // GENERAL move b -> a
131 // the move resolver starts by copying b into a temporary location, so that
132 // the last move can read it. This copy needs to use use type GENERAL.
133 Type endCycleType_;
134
135 public:
136 MoveOp()
137 { }
138 MoveOp(const MoveOperand &from, const MoveOperand &to, Type type)
139 : from_(from),
140 to_(to),
141 cycleBegin_(false),
142 cycleEnd_(false),
143 type_(type)
144 { }
145
146 bool isCycleBegin() const {
147 return cycleBegin_;
148 }
149 bool isCycleEnd() const {
150 return cycleEnd_;
151 }
152 const MoveOperand &from() const {
153 return from_;
154 }
155 const MoveOperand &to() const {
156 return to_;
157 }
158 Type type() const {
159 return type_;
160 }
161 Type endCycleType() const {
162 JS_ASSERT(isCycleBegin());
163 return endCycleType_;
164 }
165 };
166
167 class MoveResolver
168 {
169 private:
170 struct PendingMove
171 : public MoveOp,
172 public TempObject,
173 public InlineListNode<PendingMove>
174 {
175 PendingMove()
176 { }
177 PendingMove(const MoveOperand &from, const MoveOperand &to, Type type)
178 : MoveOp(from, to, type)
179 { }
180
181 void setCycleBegin(Type endCycleType) {
182 JS_ASSERT(!isCycleBegin() && !isCycleEnd());
183 cycleBegin_ = true;
184 endCycleType_ = endCycleType;
185 }
186 void setCycleEnd() {
187 JS_ASSERT(!isCycleBegin() && !isCycleEnd());
188 cycleEnd_ = true;
189 }
190 };
191
192 typedef InlineList<MoveResolver::PendingMove>::iterator PendingMoveIterator;
193
194 private:
195 // Moves that are definitely unblocked (constants to registers). These are
196 // emitted last.
197 js::Vector<MoveOp, 16, SystemAllocPolicy> orderedMoves_;
198 bool hasCycles_;
199
200 TempObjectPool<PendingMove> movePool_;
201
202 InlineList<PendingMove> pending_;
203
204 PendingMove *findBlockingMove(const PendingMove *last);
205
206 // Internal reset function. Does not clear lists.
207 void resetState();
208
209 public:
210 MoveResolver();
211
212 // Resolves a move group into two lists of ordered moves. These moves must
213 // be executed in the order provided. Some moves may indicate that they
214 // participate in a cycle. For every cycle there are two such moves, and it
215 // is guaranteed that cycles do not nest inside each other in the list.
216 //
217 // After calling addMove() for each parallel move, resolve() performs the
218 // cycle resolution algorithm. Calling addMove() again resets the resolver.
219 bool addMove(const MoveOperand &from, const MoveOperand &to, MoveOp::Type type);
220 bool resolve();
221
222 size_t numMoves() const {
223 return orderedMoves_.length();
224 }
225 const MoveOp &getMove(size_t i) const {
226 return orderedMoves_[i];
227 }
228 bool hasCycles() const {
229 return hasCycles_;
230 }
231 void clearTempObjectPool() {
232 movePool_.clear();
233 }
234 void setAllocator(TempAllocator &alloc) {
235 movePool_.setAllocator(alloc);
236 }
237 };
238
239 } // namespace jit
240 } // namespace js
241
242 #endif /* jit_MoveResolver_h */

mercurial