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