Line data Source code
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_x86_shared_CodeGenerator_x86_shared_h
8 : #define jit_x86_shared_CodeGenerator_x86_shared_h
9 :
10 : #include "jit/shared/CodeGenerator-shared.h"
11 :
12 : namespace js {
13 : namespace jit {
14 :
15 : class OutOfLineBailout;
16 : class OutOfLineUndoALUOperation;
17 : class OutOfLineLoadTypedArrayOutOfBounds;
18 : class MulNegativeZeroCheck;
19 : class ModOverflowCheck;
20 : class ReturnZero;
21 : class OutOfLineTableSwitch;
22 :
23 8 : class CodeGeneratorX86Shared : public CodeGeneratorShared
24 : {
25 : friend class MoveResolverX86;
26 :
27 : CodeGeneratorX86Shared* thisFromCtor() {
28 : return this;
29 : }
30 :
31 : template <typename T>
32 : void bailout(const T& t, LSnapshot* snapshot);
33 :
34 : protected:
35 : // Load a NaN or zero into a register for an out of bounds AsmJS or static
36 : // typed array load.
37 : class OutOfLineLoadTypedArrayOutOfBounds : public OutOfLineCodeBase<CodeGeneratorX86Shared>
38 : {
39 : AnyRegister dest_;
40 : Scalar::Type viewType_;
41 : public:
42 : OutOfLineLoadTypedArrayOutOfBounds(AnyRegister dest, Scalar::Type viewType)
43 : : dest_(dest), viewType_(viewType)
44 : {}
45 :
46 0 : AnyRegister dest() const { return dest_; }
47 0 : Scalar::Type viewType() const { return viewType_; }
48 : void accept(CodeGeneratorX86Shared* codegen) {
49 : codegen->visitOutOfLineLoadTypedArrayOutOfBounds(this);
50 : }
51 : };
52 :
53 : // Additional bounds check for vector Float to Int conversion, when the
54 : // undefined pattern is seen. Might imply a bailout.
55 : class OutOfLineSimdFloatToIntCheck : public OutOfLineCodeBase<CodeGeneratorX86Shared>
56 : {
57 : Register temp_;
58 : FloatRegister input_;
59 : LInstruction* ins_;
60 : wasm::BytecodeOffset bytecodeOffset_;
61 :
62 : public:
63 0 : OutOfLineSimdFloatToIntCheck(Register temp, FloatRegister input, LInstruction *ins,
64 : wasm::BytecodeOffset bytecodeOffset)
65 0 : : temp_(temp), input_(input), ins_(ins), bytecodeOffset_(bytecodeOffset)
66 0 : {}
67 :
68 0 : Register temp() const { return temp_; }
69 0 : FloatRegister input() const { return input_; }
70 0 : LInstruction* ins() const { return ins_; }
71 0 : wasm::BytecodeOffset bytecodeOffset() const { return bytecodeOffset_; }
72 :
73 0 : void accept(CodeGeneratorX86Shared* codegen) {
74 0 : codegen->visitOutOfLineSimdFloatToIntCheck(this);
75 0 : }
76 : };
77 :
78 : public:
79 : NonAssertingLabel deoptLabel_;
80 :
81 : Operand ToOperand(const LAllocation& a);
82 : Operand ToOperand(const LAllocation* a);
83 : Operand ToOperand(const LDefinition* def);
84 :
85 : #ifdef JS_PUNBOX64
86 : Operand ToOperandOrRegister64(const LInt64Allocation input);
87 : #else
88 : Register64 ToOperandOrRegister64(const LInt64Allocation input);
89 : #endif
90 :
91 : MoveOperand toMoveOperand(LAllocation a) const;
92 :
93 : void bailoutIf(Assembler::Condition condition, LSnapshot* snapshot);
94 : void bailoutIf(Assembler::DoubleCondition condition, LSnapshot* snapshot);
95 : void bailoutFrom(Label* label, LSnapshot* snapshot);
96 : void bailout(LSnapshot* snapshot);
97 :
98 : template <typename T1, typename T2>
99 0 : void bailoutCmpPtr(Assembler::Condition c, T1 lhs, T2 rhs, LSnapshot* snapshot) {
100 0 : masm.cmpPtr(lhs, rhs);
101 0 : bailoutIf(c, snapshot);
102 0 : }
103 : void bailoutTestPtr(Assembler::Condition c, Register lhs, Register rhs, LSnapshot* snapshot) {
104 : masm.testPtr(lhs, rhs);
105 : bailoutIf(c, snapshot);
106 : }
107 : template <typename T1, typename T2>
108 3 : void bailoutCmp32(Assembler::Condition c, T1 lhs, T2 rhs, LSnapshot* snapshot) {
109 3 : masm.cmp32(lhs, rhs);
110 3 : bailoutIf(c, snapshot);
111 3 : }
112 : template <typename T1, typename T2>
113 0 : void bailoutTest32(Assembler::Condition c, T1 lhs, T2 rhs, LSnapshot* snapshot) {
114 0 : masm.test32(lhs, rhs);
115 0 : bailoutIf(c, snapshot);
116 0 : }
117 : void bailoutIfFalseBool(Register reg, LSnapshot* snapshot) {
118 : masm.test32(reg, Imm32(0xFF));
119 : bailoutIf(Assembler::Zero, snapshot);
120 : }
121 0 : void bailoutCvttsd2si(FloatRegister src, Register dest, LSnapshot* snapshot) {
122 : // vcvttsd2si returns 0x80000000 on failure. Test for it by
123 : // subtracting 1 and testing overflow. The other possibility is to test
124 : // equality for INT_MIN after a comparison, but 1 costs fewer bytes to
125 : // materialize.
126 0 : masm.vcvttsd2si(src, dest);
127 0 : masm.cmp32(dest, Imm32(1));
128 0 : bailoutIf(Assembler::Overflow, snapshot);
129 0 : }
130 0 : void bailoutCvttss2si(FloatRegister src, Register dest, LSnapshot* snapshot) {
131 : // Same trick as explained in the above comment.
132 0 : masm.vcvttss2si(src, dest);
133 0 : masm.cmp32(dest, Imm32(1));
134 0 : bailoutIf(Assembler::Overflow, snapshot);
135 0 : }
136 :
137 : protected:
138 : bool generateOutOfLineCode();
139 :
140 : void emitCompare(MCompare::CompareType type, const LAllocation* left, const LAllocation* right);
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 : void emitBranch(Assembler::Condition cond, MBasicBlock* ifTrue, MBasicBlock* ifFalse,
145 : Assembler::NaNCond ifNaN = Assembler::NaN_HandledByCond);
146 : void emitBranch(Assembler::DoubleCondition cond, MBasicBlock* ifTrue, MBasicBlock* ifFalse);
147 :
148 0 : void testNullEmitBranch(Assembler::Condition cond, const ValueOperand& value,
149 : MBasicBlock* ifTrue, MBasicBlock* ifFalse)
150 : {
151 0 : cond = masm.testNull(cond, value);
152 0 : emitBranch(cond, ifTrue, ifFalse);
153 0 : }
154 0 : void testUndefinedEmitBranch(Assembler::Condition cond, const ValueOperand& value,
155 : MBasicBlock* ifTrue, MBasicBlock* ifFalse)
156 : {
157 0 : cond = masm.testUndefined(cond, value);
158 0 : emitBranch(cond, ifTrue, ifFalse);
159 0 : }
160 0 : void testObjectEmitBranch(Assembler::Condition cond, const ValueOperand& value,
161 : MBasicBlock* ifTrue, MBasicBlock* ifFalse)
162 : {
163 0 : cond = masm.testObject(cond, value);
164 0 : emitBranch(cond, ifTrue, ifFalse);
165 0 : }
166 :
167 0 : void testZeroEmitBranch(Assembler::Condition cond, Register reg,
168 : MBasicBlock* ifTrue, MBasicBlock* ifFalse)
169 : {
170 0 : MOZ_ASSERT(cond == Assembler::Equal || cond == Assembler::NotEqual);
171 0 : masm.cmpPtr(reg, ImmWord(0));
172 0 : emitBranch(cond, ifTrue, ifFalse);
173 0 : }
174 :
175 : void emitTableSwitchDispatch(MTableSwitch* mir, Register index, Register base);
176 :
177 : void emitSimdExtractLane8x16(FloatRegister input, Register output, unsigned lane,
178 : SimdSign signedness);
179 : void emitSimdExtractLane16x8(FloatRegister input, Register output, unsigned lane,
180 : SimdSign signedness);
181 : void emitSimdExtractLane32x4(FloatRegister input, Register output, unsigned lane);
182 :
183 : public:
184 : CodeGeneratorX86Shared(MIRGenerator* gen, LIRGraph* graph, MacroAssembler* masm);
185 :
186 : public:
187 : // Instruction visitors.
188 : virtual void visitDouble(LDouble* ins);
189 : virtual void visitFloat32(LFloat32* ins);
190 : virtual void visitMinMaxD(LMinMaxD* ins);
191 : virtual void visitMinMaxF(LMinMaxF* ins);
192 : virtual void visitAbsD(LAbsD* ins);
193 : virtual void visitAbsF(LAbsF* ins);
194 : virtual void visitClzI(LClzI* ins);
195 : virtual void visitCtzI(LCtzI* ins);
196 : virtual void visitPopcntI(LPopcntI* ins);
197 : virtual void visitPopcntI64(LPopcntI64* lir);
198 : virtual void visitSqrtD(LSqrtD* ins);
199 : virtual void visitSqrtF(LSqrtF* ins);
200 : virtual void visitPowHalfD(LPowHalfD* ins);
201 : virtual void visitAddI(LAddI* ins);
202 : virtual void visitAddI64(LAddI64* ins);
203 : virtual void visitSubI(LSubI* ins);
204 : virtual void visitSubI64(LSubI64* ins);
205 : virtual void visitMulI(LMulI* ins);
206 : virtual void visitMulI64(LMulI64* ins);
207 : virtual void visitDivI(LDivI* ins);
208 : virtual void visitDivPowTwoI(LDivPowTwoI* ins);
209 : virtual void visitDivOrModConstantI(LDivOrModConstantI* ins);
210 : virtual void visitModI(LModI* ins);
211 : virtual void visitModPowTwoI(LModPowTwoI* ins);
212 : virtual void visitBitNotI(LBitNotI* ins);
213 : virtual void visitBitOpI(LBitOpI* ins);
214 : virtual void visitBitOpI64(LBitOpI64* ins);
215 : virtual void visitShiftI(LShiftI* ins);
216 : virtual void visitShiftI64(LShiftI64* ins);
217 : virtual void visitUrshD(LUrshD* ins);
218 : virtual void visitTestIAndBranch(LTestIAndBranch* test);
219 : virtual void visitTestDAndBranch(LTestDAndBranch* test);
220 : virtual void visitTestFAndBranch(LTestFAndBranch* test);
221 : virtual void visitCompare(LCompare* comp);
222 : virtual void visitCompareAndBranch(LCompareAndBranch* comp);
223 : virtual void visitCompareD(LCompareD* comp);
224 : virtual void visitCompareDAndBranch(LCompareDAndBranch* comp);
225 : virtual void visitCompareF(LCompareF* comp);
226 : virtual void visitCompareFAndBranch(LCompareFAndBranch* comp);
227 : virtual void visitBitAndAndBranch(LBitAndAndBranch* baab);
228 : virtual void visitNotI(LNotI* comp);
229 : virtual void visitNotD(LNotD* comp);
230 : virtual void visitNotF(LNotF* comp);
231 : virtual void visitMathD(LMathD* math);
232 : virtual void visitMathF(LMathF* math);
233 : virtual void visitFloor(LFloor* lir);
234 : virtual void visitFloorF(LFloorF* lir);
235 : virtual void visitCeil(LCeil* lir);
236 : virtual void visitCeilF(LCeilF* lir);
237 : virtual void visitRound(LRound* lir);
238 : virtual void visitRoundF(LRoundF* lir);
239 : virtual void visitNearbyInt(LNearbyInt* lir);
240 : virtual void visitNearbyIntF(LNearbyIntF* lir);
241 : virtual void visitGuardShape(LGuardShape* guard);
242 : virtual void visitGuardObjectGroup(LGuardObjectGroup* guard);
243 : virtual void visitGuardClass(LGuardClass* guard);
244 : virtual void visitEffectiveAddress(LEffectiveAddress* ins);
245 : virtual void visitUDivOrMod(LUDivOrMod* ins);
246 : virtual void visitUDivOrModConstant(LUDivOrModConstant *ins);
247 : virtual void visitWasmStackArg(LWasmStackArg* ins);
248 : virtual void visitWasmStackArgI64(LWasmStackArgI64* ins);
249 : virtual void visitWasmSelect(LWasmSelect* ins);
250 : virtual void visitWasmReinterpret(LWasmReinterpret* lir);
251 : virtual void visitMemoryBarrier(LMemoryBarrier* ins);
252 : virtual void visitWasmAddOffset(LWasmAddOffset* lir);
253 : virtual void visitWasmTruncateToInt32(LWasmTruncateToInt32* lir);
254 : virtual void visitAtomicTypedArrayElementBinop(LAtomicTypedArrayElementBinop* lir);
255 : virtual void visitAtomicTypedArrayElementBinopForEffect(LAtomicTypedArrayElementBinopForEffect* lir);
256 : virtual void visitCompareExchangeTypedArrayElement(LCompareExchangeTypedArrayElement* lir);
257 : virtual void visitAtomicExchangeTypedArrayElement(LAtomicExchangeTypedArrayElement* lir);
258 : virtual void visitCopySignD(LCopySignD* lir);
259 : virtual void visitCopySignF(LCopySignF* lir);
260 : virtual void visitRotateI64(LRotateI64* lir);
261 :
262 : void visitOutOfLineLoadTypedArrayOutOfBounds(OutOfLineLoadTypedArrayOutOfBounds* ool);
263 :
264 : void visitNegI(LNegI* lir);
265 : void visitNegD(LNegD* lir);
266 : void visitNegF(LNegF* lir);
267 :
268 : void visitOutOfLineWasmTruncateCheck(OutOfLineWasmTruncateCheck* ool);
269 :
270 : // SIMD operators
271 : void visitSimdValueInt32x4(LSimdValueInt32x4* lir);
272 : void visitSimdValueFloat32x4(LSimdValueFloat32x4* lir);
273 : void visitSimdSplatX16(LSimdSplatX16* lir);
274 : void visitSimdSplatX8(LSimdSplatX8* lir);
275 : void visitSimdSplatX4(LSimdSplatX4* lir);
276 : void visitSimd128Int(LSimd128Int* ins);
277 : void visitSimd128Float(LSimd128Float* ins);
278 : void visitInt32x4ToFloat32x4(LInt32x4ToFloat32x4* ins);
279 : void visitFloat32x4ToInt32x4(LFloat32x4ToInt32x4* ins);
280 : void visitFloat32x4ToUint32x4(LFloat32x4ToUint32x4* ins);
281 : void visitSimdReinterpretCast(LSimdReinterpretCast* lir);
282 : void visitSimdExtractElementB(LSimdExtractElementB* lir);
283 : void visitSimdExtractElementI(LSimdExtractElementI* lir);
284 : void visitSimdExtractElementU2D(LSimdExtractElementU2D* lir);
285 : void visitSimdExtractElementF(LSimdExtractElementF* lir);
286 : void visitSimdInsertElementI(LSimdInsertElementI* lir);
287 : void visitSimdInsertElementF(LSimdInsertElementF* lir);
288 : void visitSimdSwizzleI(LSimdSwizzleI* lir);
289 : void visitSimdSwizzleF(LSimdSwizzleF* lir);
290 : void visitSimdShuffleX4(LSimdShuffleX4* lir);
291 : void visitSimdShuffle(LSimdShuffle* lir);
292 : void visitSimdUnaryArithIx16(LSimdUnaryArithIx16* lir);
293 : void visitSimdUnaryArithIx8(LSimdUnaryArithIx8* lir);
294 : void visitSimdUnaryArithIx4(LSimdUnaryArithIx4* lir);
295 : void visitSimdUnaryArithFx4(LSimdUnaryArithFx4* lir);
296 : void visitSimdBinaryCompIx16(LSimdBinaryCompIx16* lir);
297 : void visitSimdBinaryCompIx8(LSimdBinaryCompIx8* lir);
298 : void visitSimdBinaryCompIx4(LSimdBinaryCompIx4* lir);
299 : void visitSimdBinaryCompFx4(LSimdBinaryCompFx4* lir);
300 : void visitSimdBinaryArithIx16(LSimdBinaryArithIx16* lir);
301 : void visitSimdBinaryArithIx8(LSimdBinaryArithIx8* lir);
302 : void visitSimdBinaryArithIx4(LSimdBinaryArithIx4* lir);
303 : void visitSimdBinaryArithFx4(LSimdBinaryArithFx4* lir);
304 : void visitSimdBinarySaturating(LSimdBinarySaturating* lir);
305 : void visitSimdBinaryBitwise(LSimdBinaryBitwise* lir);
306 : void visitSimdShift(LSimdShift* lir);
307 : void visitSimdSelect(LSimdSelect* ins);
308 : void visitSimdAllTrue(LSimdAllTrue* ins);
309 : void visitSimdAnyTrue(LSimdAnyTrue* ins);
310 :
311 : template <class T, class Reg> void visitSimdGeneralShuffle(LSimdGeneralShuffleBase* lir, Reg temp);
312 : void visitSimdGeneralShuffleI(LSimdGeneralShuffleI* lir);
313 : void visitSimdGeneralShuffleF(LSimdGeneralShuffleF* lir);
314 :
315 : // Out of line visitors.
316 : void visitOutOfLineBailout(OutOfLineBailout* ool);
317 : void visitOutOfLineUndoALUOperation(OutOfLineUndoALUOperation* ool);
318 : void visitMulNegativeZeroCheck(MulNegativeZeroCheck* ool);
319 : void visitModOverflowCheck(ModOverflowCheck* ool);
320 : void visitReturnZero(ReturnZero* ool);
321 : void visitOutOfLineTableSwitch(OutOfLineTableSwitch* ool);
322 : void visitOutOfLineSimdFloatToIntCheck(OutOfLineSimdFloatToIntCheck* ool);
323 : void generateInvalidateEpilogue();
324 :
325 : // Generating a result.
326 : template<typename S, typename T>
327 : void atomicBinopToTypedIntArray(AtomicOp op, Scalar::Type arrayType, const S& value,
328 : const T& mem, Register temp1, Register temp2, AnyRegister output);
329 :
330 : // Generating no result.
331 : template<typename S, typename T>
332 : void atomicBinopToTypedIntArray(AtomicOp op, Scalar::Type arrayType, const S& value, const T& mem);
333 :
334 : void setReturnDoubleRegs(LiveRegisterSet* regs);
335 :
336 : void canonicalizeIfDeterministic(Scalar::Type type, const LAllocation* value);
337 : };
338 :
339 : // An out-of-line bailout thunk.
340 : class OutOfLineBailout : public OutOfLineCodeBase<CodeGeneratorX86Shared>
341 : {
342 : LSnapshot* snapshot_;
343 :
344 : public:
345 370 : explicit OutOfLineBailout(LSnapshot* snapshot)
346 370 : : snapshot_(snapshot)
347 370 : { }
348 :
349 : void accept(CodeGeneratorX86Shared* codegen);
350 :
351 370 : LSnapshot* snapshot() const {
352 370 : return snapshot_;
353 : }
354 : };
355 :
356 : } // namespace jit
357 : } // namespace js
358 :
359 : #endif /* jit_x86_shared_CodeGenerator_x86_shared_h */
|