|
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_mips_CodeGenerator_mips_h |
|
8 #define jit_mips_CodeGenerator_mips_h |
|
9 |
|
10 #include "jit/mips/Assembler-mips.h" |
|
11 #include "jit/shared/CodeGenerator-shared.h" |
|
12 |
|
13 namespace js { |
|
14 namespace jit { |
|
15 |
|
16 class OutOfLineBailout; |
|
17 class OutOfLineTableSwitch; |
|
18 |
|
19 class CodeGeneratorMIPS : public CodeGeneratorShared |
|
20 { |
|
21 friend class MoveResolverMIPS; |
|
22 |
|
23 CodeGeneratorMIPS *thisFromCtor() { |
|
24 return this; |
|
25 } |
|
26 |
|
27 protected: |
|
28 // Label for the common return path. |
|
29 NonAssertingLabel returnLabel_; |
|
30 NonAssertingLabel deoptLabel_; |
|
31 |
|
32 inline Address ToAddress(const LAllocation &a) { |
|
33 MOZ_ASSERT(a.isMemory()); |
|
34 int32_t offset = ToStackOffset(&a); |
|
35 |
|
36 // The way the stack slots work, we assume that everything from |
|
37 // depth == 0 downwards is writable however, since our frame is |
|
38 // included in this, ensure that the frame gets skipped. |
|
39 if (gen->compilingAsmJS()) |
|
40 offset -= AlignmentMidPrologue; |
|
41 |
|
42 return Address(StackPointer, offset); |
|
43 } |
|
44 |
|
45 inline Address ToAddress(const LAllocation *a) { |
|
46 return ToAddress(*a); |
|
47 } |
|
48 |
|
49 inline Operand ToOperand(const LAllocation &a) { |
|
50 if (a.isGeneralReg()) |
|
51 return Operand(a.toGeneralReg()->reg()); |
|
52 if (a.isFloatReg()) |
|
53 return Operand(a.toFloatReg()->reg()); |
|
54 |
|
55 MOZ_ASSERT(a.isMemory()); |
|
56 int32_t offset = ToStackOffset(&a); |
|
57 |
|
58 // The way the stack slots work, we assume that everything from |
|
59 // depth == 0 downwards is writable however, since our frame is |
|
60 // included in this, ensure that the frame gets skipped. |
|
61 if (gen->compilingAsmJS()) |
|
62 offset -= AlignmentMidPrologue; |
|
63 |
|
64 return Operand(StackPointer, offset); |
|
65 } |
|
66 inline Operand ToOperand(const LAllocation *a) { |
|
67 return ToOperand(*a); |
|
68 } |
|
69 inline Operand ToOperand(const LDefinition *def) { |
|
70 return ToOperand(def->output()); |
|
71 } |
|
72 |
|
73 MoveOperand toMoveOperand(const LAllocation *a) const; |
|
74 |
|
75 template <typename T1, typename T2> |
|
76 bool bailoutCmp32(Assembler::Condition c, T1 lhs, T2 rhs, LSnapshot *snapshot) { |
|
77 bool goodBailout; |
|
78 Label skip; |
|
79 masm.ma_b(lhs, rhs, &skip, Assembler::InvertCondition(c), ShortJump); |
|
80 goodBailout = bailout(snapshot); |
|
81 masm.bind(&skip); |
|
82 return goodBailout; |
|
83 } |
|
84 template<typename T> |
|
85 bool bailoutCmp32(Assembler::Condition c, Operand lhs, T rhs, LSnapshot *snapshot) { |
|
86 if (lhs.getTag() == Operand::REG) |
|
87 return bailoutCmp32(c, lhs.toReg(), rhs, snapshot); |
|
88 if (lhs.getTag() == Operand::MEM) |
|
89 return bailoutCmp32(c, lhs.toAddress(), rhs, snapshot); |
|
90 MOZ_ASSUME_UNREACHABLE("Invalid operand tag."); |
|
91 return false; |
|
92 } |
|
93 template<typename T> |
|
94 bool bailoutTest32(Assembler::Condition c, Register lhs, T rhs, LSnapshot *snapshot) { |
|
95 Label bail; |
|
96 masm.branchTest32(c, lhs, rhs, &bail); |
|
97 return bailoutFrom(&bail, snapshot); |
|
98 } |
|
99 template <typename T1, typename T2> |
|
100 bool bailoutCmpPtr(Assembler::Condition c, T1 lhs, T2 rhs, LSnapshot *snapshot) { |
|
101 return bailoutCmp32(c, lhs, rhs, snapshot); |
|
102 } |
|
103 bool bailoutTestPtr(Assembler::Condition c, Register lhs, Register rhs, LSnapshot *snapshot) { |
|
104 Label bail; |
|
105 masm.branchTestPtr(c, lhs, rhs, &bail); |
|
106 return bailoutFrom(&bail, snapshot); |
|
107 } |
|
108 |
|
109 bool bailoutFrom(Label *label, LSnapshot *snapshot); |
|
110 bool bailout(LSnapshot *snapshot); |
|
111 |
|
112 protected: |
|
113 bool generatePrologue(); |
|
114 bool generateEpilogue(); |
|
115 bool generateOutOfLineCode(); |
|
116 |
|
117 template <typename T> |
|
118 void branchToBlock(Register lhs, T rhs, MBasicBlock *mir, Assembler::Condition cond) |
|
119 { |
|
120 Label *label = mir->lir()->label(); |
|
121 if (Label *oolEntry = labelForBackedgeWithImplicitCheck(mir)) { |
|
122 // Note: the backedge is initially a jump to the next instruction. |
|
123 // It will be patched to the target block's label during link(). |
|
124 RepatchLabel rejoin; |
|
125 CodeOffsetJump backedge; |
|
126 Label skip; |
|
127 |
|
128 masm.ma_b(lhs, rhs, &skip, Assembler::InvertCondition(cond), ShortJump); |
|
129 backedge = masm.jumpWithPatch(&rejoin); |
|
130 masm.bind(&rejoin); |
|
131 masm.bind(&skip); |
|
132 |
|
133 if (!patchableBackedges_.append(PatchableBackedgeInfo(backedge, label, oolEntry))) |
|
134 MOZ_CRASH(); |
|
135 } else { |
|
136 masm.ma_b(lhs, rhs, label, cond); |
|
137 } |
|
138 } |
|
139 void branchToBlock(Assembler::FloatFormat fmt, FloatRegister lhs, FloatRegister rhs, |
|
140 MBasicBlock *mir, Assembler::DoubleCondition cond); |
|
141 |
|
142 // Emits a branch that directs control flow to the true block if |cond| is |
|
143 // true, and the false block if |cond| is false. |
|
144 template <typename T> |
|
145 void emitBranch(Register lhs, T rhs, Assembler::Condition cond, |
|
146 MBasicBlock *mirTrue, MBasicBlock *mirFalse) |
|
147 { |
|
148 if (isNextBlock(mirFalse->lir())) { |
|
149 branchToBlock(lhs, rhs, mirTrue, cond); |
|
150 } else { |
|
151 branchToBlock(lhs, rhs, mirFalse, Assembler::InvertCondition(cond)); |
|
152 jumpToBlock(mirTrue); |
|
153 } |
|
154 } |
|
155 void testNullEmitBranch(Assembler::Condition cond, const ValueOperand &value, |
|
156 MBasicBlock *ifTrue, MBasicBlock *ifFalse) |
|
157 { |
|
158 emitBranch(value.typeReg(), (Imm32)ImmType(JSVAL_TYPE_NULL), cond, ifTrue, ifFalse); |
|
159 } |
|
160 void testUndefinedEmitBranch(Assembler::Condition cond, const ValueOperand &value, |
|
161 MBasicBlock *ifTrue, MBasicBlock *ifFalse) |
|
162 { |
|
163 emitBranch(value.typeReg(), (Imm32)ImmType(JSVAL_TYPE_UNDEFINED), cond, ifTrue, ifFalse); |
|
164 } |
|
165 |
|
166 bool emitTableSwitchDispatch(MTableSwitch *mir, const Register &index, const Register &base); |
|
167 |
|
168 public: |
|
169 // Instruction visitors. |
|
170 virtual bool visitMinMaxD(LMinMaxD *ins); |
|
171 virtual bool visitAbsD(LAbsD *ins); |
|
172 virtual bool visitAbsF(LAbsF *ins); |
|
173 virtual bool visitSqrtD(LSqrtD *ins); |
|
174 virtual bool visitSqrtF(LSqrtF *ins); |
|
175 virtual bool visitAddI(LAddI *ins); |
|
176 virtual bool visitSubI(LSubI *ins); |
|
177 virtual bool visitBitNotI(LBitNotI *ins); |
|
178 virtual bool visitBitOpI(LBitOpI *ins); |
|
179 |
|
180 virtual bool visitMulI(LMulI *ins); |
|
181 |
|
182 virtual bool visitDivI(LDivI *ins); |
|
183 virtual bool visitDivPowTwoI(LDivPowTwoI *ins); |
|
184 virtual bool visitModI(LModI *ins); |
|
185 virtual bool visitModPowTwoI(LModPowTwoI *ins); |
|
186 virtual bool visitModMaskI(LModMaskI *ins); |
|
187 virtual bool visitPowHalfD(LPowHalfD *ins); |
|
188 virtual bool visitShiftI(LShiftI *ins); |
|
189 virtual bool visitUrshD(LUrshD *ins); |
|
190 |
|
191 virtual bool visitTestIAndBranch(LTestIAndBranch *test); |
|
192 virtual bool visitCompare(LCompare *comp); |
|
193 virtual bool visitCompareAndBranch(LCompareAndBranch *comp); |
|
194 virtual bool visitTestDAndBranch(LTestDAndBranch *test); |
|
195 virtual bool visitTestFAndBranch(LTestFAndBranch *test); |
|
196 virtual bool visitCompareD(LCompareD *comp); |
|
197 virtual bool visitCompareF(LCompareF *comp); |
|
198 virtual bool visitCompareDAndBranch(LCompareDAndBranch *comp); |
|
199 virtual bool visitCompareFAndBranch(LCompareFAndBranch *comp); |
|
200 virtual bool visitCompareB(LCompareB *lir); |
|
201 virtual bool visitCompareBAndBranch(LCompareBAndBranch *lir); |
|
202 virtual bool visitCompareV(LCompareV *lir); |
|
203 virtual bool visitCompareVAndBranch(LCompareVAndBranch *lir); |
|
204 virtual bool visitBitAndAndBranch(LBitAndAndBranch *lir); |
|
205 virtual bool visitAsmJSUInt32ToDouble(LAsmJSUInt32ToDouble *lir); |
|
206 virtual bool visitAsmJSUInt32ToFloat32(LAsmJSUInt32ToFloat32 *lir); |
|
207 virtual bool visitNotI(LNotI *ins); |
|
208 virtual bool visitNotD(LNotD *ins); |
|
209 virtual bool visitNotF(LNotF *ins); |
|
210 |
|
211 virtual bool visitMathD(LMathD *math); |
|
212 virtual bool visitMathF(LMathF *math); |
|
213 virtual bool visitFloor(LFloor *lir); |
|
214 virtual bool visitFloorF(LFloorF *lir); |
|
215 virtual bool visitRound(LRound *lir); |
|
216 virtual bool visitRoundF(LRoundF *lir); |
|
217 virtual bool visitTruncateDToInt32(LTruncateDToInt32 *ins); |
|
218 virtual bool visitTruncateFToInt32(LTruncateFToInt32 *ins); |
|
219 |
|
220 // Out of line visitors. |
|
221 bool visitOutOfLineBailout(OutOfLineBailout *ool); |
|
222 bool visitOutOfLineTableSwitch(OutOfLineTableSwitch *ool); |
|
223 |
|
224 protected: |
|
225 ValueOperand ToValue(LInstruction *ins, size_t pos); |
|
226 ValueOperand ToOutValue(LInstruction *ins); |
|
227 ValueOperand ToTempValue(LInstruction *ins, size_t pos); |
|
228 |
|
229 // Functions for LTestVAndBranch. |
|
230 Register splitTagForTest(const ValueOperand &value); |
|
231 |
|
232 void storeElementTyped(const LAllocation *value, MIRType valueType, MIRType elementType, |
|
233 const Register &elements, const LAllocation *index); |
|
234 |
|
235 public: |
|
236 CodeGeneratorMIPS(MIRGenerator *gen, LIRGraph *graph, MacroAssembler *masm); |
|
237 |
|
238 public: |
|
239 bool visitBox(LBox *box); |
|
240 bool visitBoxFloatingPoint(LBoxFloatingPoint *box); |
|
241 bool visitUnbox(LUnbox *unbox); |
|
242 bool visitValue(LValue *value); |
|
243 bool visitDouble(LDouble *ins); |
|
244 bool visitFloat32(LFloat32 *ins); |
|
245 |
|
246 bool visitLoadSlotV(LLoadSlotV *load); |
|
247 bool visitLoadSlotT(LLoadSlotT *load); |
|
248 bool visitStoreSlotT(LStoreSlotT *load); |
|
249 |
|
250 bool visitLoadElementT(LLoadElementT *load); |
|
251 |
|
252 bool visitGuardShape(LGuardShape *guard); |
|
253 bool visitGuardObjectType(LGuardObjectType *guard); |
|
254 bool visitGuardClass(LGuardClass *guard); |
|
255 bool visitImplicitThis(LImplicitThis *lir); |
|
256 |
|
257 bool visitInterruptCheck(LInterruptCheck *lir); |
|
258 |
|
259 bool visitNegI(LNegI *lir); |
|
260 bool visitNegD(LNegD *lir); |
|
261 bool visitNegF(LNegF *lir); |
|
262 bool visitLoadTypedArrayElementStatic(LLoadTypedArrayElementStatic *ins); |
|
263 bool visitStoreTypedArrayElementStatic(LStoreTypedArrayElementStatic *ins); |
|
264 bool visitAsmJSLoadHeap(LAsmJSLoadHeap *ins); |
|
265 bool visitAsmJSStoreHeap(LAsmJSStoreHeap *ins); |
|
266 bool visitAsmJSLoadGlobalVar(LAsmJSLoadGlobalVar *ins); |
|
267 bool visitAsmJSStoreGlobalVar(LAsmJSStoreGlobalVar *ins); |
|
268 bool visitAsmJSLoadFuncPtr(LAsmJSLoadFuncPtr *ins); |
|
269 bool visitAsmJSLoadFFIFunc(LAsmJSLoadFFIFunc *ins); |
|
270 |
|
271 bool visitAsmJSPassStackArg(LAsmJSPassStackArg *ins); |
|
272 |
|
273 bool visitForkJoinGetSlice(LForkJoinGetSlice *ins); |
|
274 |
|
275 bool generateInvalidateEpilogue(); |
|
276 protected: |
|
277 void postAsmJSCall(LAsmJSCall *lir) {} |
|
278 |
|
279 bool visitEffectiveAddress(LEffectiveAddress *ins); |
|
280 bool visitUDiv(LUDiv *ins); |
|
281 bool visitUMod(LUMod *ins); |
|
282 }; |
|
283 |
|
284 typedef CodeGeneratorMIPS CodeGeneratorSpecific; |
|
285 |
|
286 // An out-of-line bailout thunk. |
|
287 class OutOfLineBailout : public OutOfLineCodeBase<CodeGeneratorMIPS> |
|
288 { |
|
289 LSnapshot *snapshot_; |
|
290 uint32_t frameSize_; |
|
291 |
|
292 public: |
|
293 OutOfLineBailout(LSnapshot *snapshot, uint32_t frameSize) |
|
294 : snapshot_(snapshot), |
|
295 frameSize_(frameSize) |
|
296 { } |
|
297 |
|
298 bool accept(CodeGeneratorMIPS *codegen); |
|
299 |
|
300 LSnapshot *snapshot() const { |
|
301 return snapshot_; |
|
302 } |
|
303 }; |
|
304 |
|
305 } // namespace jit |
|
306 } // namespace js |
|
307 |
|
308 #endif /* jit_mips_CodeGenerator_mips_h */ |