1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2  * vim: set ts=8 sts=2 et sw=2 tw=80:
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 #include "js/ScalarType.h"  // js::Scalar::Type
12 
13 namespace js {
14 namespace jit {
15 
16 class CodeGeneratorX86Shared;
17 class OutOfLineBailout;
18 class OutOfLineUndoALUOperation;
19 class OutOfLineLoadTypedArrayOutOfBounds;
20 class MulNegativeZeroCheck;
21 class ModOverflowCheck;
22 class ReturnZero;
23 class OutOfLineTableSwitch;
24 
25 using OutOfLineWasmTruncateCheck =
26     OutOfLineWasmTruncateCheckBase<CodeGeneratorX86Shared>;
27 
28 class CodeGeneratorX86Shared : public CodeGeneratorShared {
29   friend class MoveResolverX86;
30 
31   template <typename T>
32   void bailout(const T& t, LSnapshot* snapshot);
33 
34  protected:
35   CodeGeneratorX86Shared(MIRGenerator* gen, LIRGraph* graph,
36                          MacroAssembler* masm);
37 
38   // Load a NaN or zero into a register for an out of bounds AsmJS or static
39   // typed array load.
40   class OutOfLineLoadTypedArrayOutOfBounds
41       : public OutOfLineCodeBase<CodeGeneratorX86Shared> {
42     AnyRegister dest_;
43     Scalar::Type viewType_;
44 
45    public:
OutOfLineLoadTypedArrayOutOfBounds(AnyRegister dest,Scalar::Type viewType)46     OutOfLineLoadTypedArrayOutOfBounds(AnyRegister dest, Scalar::Type viewType)
47         : dest_(dest), viewType_(viewType) {}
48 
dest()49     AnyRegister dest() const { return dest_; }
viewType()50     Scalar::Type viewType() const { return viewType_; }
accept(CodeGeneratorX86Shared * codegen)51     void accept(CodeGeneratorX86Shared* codegen) override {
52       codegen->visitOutOfLineLoadTypedArrayOutOfBounds(this);
53     }
54   };
55 
56   NonAssertingLabel deoptLabel_;
57 
58   Operand ToOperand(const LAllocation& a);
59   Operand ToOperand(const LAllocation* a);
60   Operand ToOperand(const LDefinition* def);
61 
62 #ifdef JS_PUNBOX64
63   Operand ToOperandOrRegister64(const LInt64Allocation input);
64 #else
65   Register64 ToOperandOrRegister64(const LInt64Allocation input);
66 #endif
67 
68   MoveOperand toMoveOperand(LAllocation a) const;
69 
70   void bailoutIf(Assembler::Condition condition, LSnapshot* snapshot);
71   void bailoutIf(Assembler::DoubleCondition condition, LSnapshot* snapshot);
72   void bailoutFrom(Label* label, LSnapshot* snapshot);
73   void bailout(LSnapshot* snapshot);
74 
75   template <typename T1, typename T2>
bailoutCmpPtr(Assembler::Condition c,T1 lhs,T2 rhs,LSnapshot * snapshot)76   void bailoutCmpPtr(Assembler::Condition c, T1 lhs, T2 rhs,
77                      LSnapshot* snapshot) {
78     masm.cmpPtr(lhs, rhs);
79     bailoutIf(c, snapshot);
80   }
bailoutTestPtr(Assembler::Condition c,Register lhs,Register rhs,LSnapshot * snapshot)81   void bailoutTestPtr(Assembler::Condition c, Register lhs, Register rhs,
82                       LSnapshot* snapshot) {
83     masm.testPtr(lhs, rhs);
84     bailoutIf(c, snapshot);
85   }
86   template <typename T1, typename T2>
bailoutCmp32(Assembler::Condition c,T1 lhs,T2 rhs,LSnapshot * snapshot)87   void bailoutCmp32(Assembler::Condition c, T1 lhs, T2 rhs,
88                     LSnapshot* snapshot) {
89     masm.cmp32(lhs, rhs);
90     bailoutIf(c, snapshot);
91   }
92   template <typename T1, typename T2>
bailoutTest32(Assembler::Condition c,T1 lhs,T2 rhs,LSnapshot * snapshot)93   void bailoutTest32(Assembler::Condition c, T1 lhs, T2 rhs,
94                      LSnapshot* snapshot) {
95     masm.test32(lhs, rhs);
96     bailoutIf(c, snapshot);
97   }
bailoutIfFalseBool(Register reg,LSnapshot * snapshot)98   void bailoutIfFalseBool(Register reg, LSnapshot* snapshot) {
99     masm.test32(reg, Imm32(0xFF));
100     bailoutIf(Assembler::Zero, snapshot);
101   }
bailoutCvttsd2si(FloatRegister src,Register dest,LSnapshot * snapshot)102   void bailoutCvttsd2si(FloatRegister src, Register dest, LSnapshot* snapshot) {
103     Label bail;
104     masm.truncateDoubleToInt32(src, dest, &bail);
105     bailoutFrom(&bail, snapshot);
106   }
bailoutCvttss2si(FloatRegister src,Register dest,LSnapshot * snapshot)107   void bailoutCvttss2si(FloatRegister src, Register dest, LSnapshot* snapshot) {
108     Label bail;
109     masm.truncateFloat32ToInt32(src, dest, &bail);
110     bailoutFrom(&bail, snapshot);
111   }
112 
113   bool generateOutOfLineCode();
114 
115   void emitCompare(MCompare::CompareType type, const LAllocation* left,
116                    const LAllocation* right);
117 
118   // Emits a branch that directs control flow to the true block if |cond| is
119   // true, and the false block if |cond| is false.
120   void emitBranch(Assembler::Condition cond, MBasicBlock* ifTrue,
121                   MBasicBlock* ifFalse,
122                   Assembler::NaNCond ifNaN = Assembler::NaN_HandledByCond);
123   void emitBranch(Assembler::DoubleCondition cond, MBasicBlock* ifTrue,
124                   MBasicBlock* ifFalse);
125 
testNullEmitBranch(Assembler::Condition cond,const ValueOperand & value,MBasicBlock * ifTrue,MBasicBlock * ifFalse)126   void testNullEmitBranch(Assembler::Condition cond, const ValueOperand& value,
127                           MBasicBlock* ifTrue, MBasicBlock* ifFalse) {
128     cond = masm.testNull(cond, value);
129     emitBranch(cond, ifTrue, ifFalse);
130   }
testUndefinedEmitBranch(Assembler::Condition cond,const ValueOperand & value,MBasicBlock * ifTrue,MBasicBlock * ifFalse)131   void testUndefinedEmitBranch(Assembler::Condition cond,
132                                const ValueOperand& value, MBasicBlock* ifTrue,
133                                MBasicBlock* ifFalse) {
134     cond = masm.testUndefined(cond, value);
135     emitBranch(cond, ifTrue, ifFalse);
136   }
testObjectEmitBranch(Assembler::Condition cond,const ValueOperand & value,MBasicBlock * ifTrue,MBasicBlock * ifFalse)137   void testObjectEmitBranch(Assembler::Condition cond,
138                             const ValueOperand& value, MBasicBlock* ifTrue,
139                             MBasicBlock* ifFalse) {
140     cond = masm.testObject(cond, value);
141     emitBranch(cond, ifTrue, ifFalse);
142   }
143 
testZeroEmitBranch(Assembler::Condition cond,Register reg,MBasicBlock * ifTrue,MBasicBlock * ifFalse)144   void testZeroEmitBranch(Assembler::Condition cond, Register reg,
145                           MBasicBlock* ifTrue, MBasicBlock* ifFalse) {
146     MOZ_ASSERT(cond == Assembler::Equal || cond == Assembler::NotEqual);
147     masm.cmpPtr(reg, ImmWord(0));
148     emitBranch(cond, ifTrue, ifFalse);
149   }
150 
151   void emitTableSwitchDispatch(MTableSwitch* mir, Register index,
152                                Register base);
153 
154   void generateInvalidateEpilogue();
155 
156   void canonicalizeIfDeterministic(Scalar::Type type, const LAllocation* value);
157 
158   template <typename T>
159   Operand toMemoryAccessOperand(T* lir, int32_t disp);
160 
161  public:
162   // Out of line visitors.
163   void visitOutOfLineBailout(OutOfLineBailout* ool);
164   void visitOutOfLineUndoALUOperation(OutOfLineUndoALUOperation* ool);
165   void visitMulNegativeZeroCheck(MulNegativeZeroCheck* ool);
166   void visitModOverflowCheck(ModOverflowCheck* ool);
167   void visitReturnZero(ReturnZero* ool);
168   void visitOutOfLineTableSwitch(OutOfLineTableSwitch* ool);
169   void visitOutOfLineLoadTypedArrayOutOfBounds(
170       OutOfLineLoadTypedArrayOutOfBounds* ool);
171   void visitOutOfLineWasmTruncateCheck(OutOfLineWasmTruncateCheck* ool);
172 };
173 
174 // An out-of-line bailout thunk.
175 class OutOfLineBailout : public OutOfLineCodeBase<CodeGeneratorX86Shared> {
176   LSnapshot* snapshot_;
177 
178  public:
OutOfLineBailout(LSnapshot * snapshot)179   explicit OutOfLineBailout(LSnapshot* snapshot) : snapshot_(snapshot) {}
180 
181   void accept(CodeGeneratorX86Shared* codegen) override;
182 
snapshot()183   LSnapshot* snapshot() const { return snapshot_; }
184 };
185 
186 }  // namespace jit
187 }  // namespace js
188 
189 #endif /* jit_x86_shared_CodeGenerator_x86_shared_h */
190