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_arm64_CodeGenerator_arm64_h
8 #define jit_arm64_CodeGenerator_arm64_h
9 
10 #include "jit/arm64/Assembler-arm64.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 CodeGeneratorARM64 : public CodeGeneratorShared
20 {
21     friend class MoveResolverARM64;
22 
thisFromCtor()23     CodeGeneratorARM64* thisFromCtor() { return this; }
24 
25   public:
26     CodeGeneratorARM64(MIRGenerator* gen, LIRGraph* graph, MacroAssembler* masm);
27 
28   protected:
29     NonAssertingLabel deoptLabel_;
30 
31     // FIXME: VIXL Operand does not match the platform-agnostic Operand,
32     // which is just a union of possible arguments.
ToOperand(const LAllocation & a)33     inline Operand ToOperand(const LAllocation& a) {
34         MOZ_CRASH("ToOperand");
35     }
ToOperand(const LAllocation * a)36     inline Operand ToOperand(const LAllocation* a) {
37         return ToOperand(*a);
38     }
ToOperand(const LDefinition * def)39     inline Operand ToOperand(const LDefinition* def) {
40         return ToOperand(def->output());
41     }
42 
43     MoveOperand toMoveOperand(const LAllocation a) const;
44 
45     void bailoutIf(Assembler::Condition condition, LSnapshot* snapshot);
46     void bailoutFrom(Label* label, LSnapshot* snapshot);
47     void bailout(LSnapshot* snapshot);
48 
49     template <typename T1, typename T2>
bailoutCmpPtr(Assembler::Condition c,T1 lhs,T2 rhs,LSnapshot * snapshot)50     void bailoutCmpPtr(Assembler::Condition c, T1 lhs, T2 rhs, LSnapshot* snapshot) {
51         masm.cmpPtr(lhs, rhs);
52         return bailoutIf(c, snapshot);
53     }
bailoutTestPtr(Assembler::Condition c,Register lhs,Register rhs,LSnapshot * snapshot)54     void bailoutTestPtr(Assembler::Condition c, Register lhs, Register rhs, LSnapshot* snapshot) {
55         masm.testPtr(lhs, rhs);
56         return bailoutIf(c, snapshot);
57     }
58     template <typename T1, typename T2>
bailoutCmp32(Assembler::Condition c,T1 lhs,T2 rhs,LSnapshot * snapshot)59     void bailoutCmp32(Assembler::Condition c, T1 lhs, T2 rhs, LSnapshot* snapshot) {
60         masm.cmp32(lhs, rhs);
61         return bailoutIf(c, snapshot);
62     }
63     template <typename T1, typename T2>
bailoutTest32(Assembler::Condition c,T1 lhs,T2 rhs,LSnapshot * snapshot)64     void bailoutTest32(Assembler::Condition c, T1 lhs, T2 rhs, LSnapshot* snapshot) {
65         masm.test32(lhs, rhs);
66         return bailoutIf(c, snapshot);
67     }
bailoutIfFalseBool(Register reg,LSnapshot * snapshot)68     void bailoutIfFalseBool(Register reg, LSnapshot* snapshot) {
69         masm.test32(reg, Imm32(0xFF));
70         return bailoutIf(Assembler::Zero, snapshot);
71     }
72 
73   protected:
74     bool generateOutOfLineCode();
75 
76     void emitRoundDouble(FloatRegister src, Register dest, Label* fail);
77 
78     // Emits a branch that directs control flow to the true block if |cond| is
79     // true, and the false block if |cond| is false.
80     void emitBranch(Assembler::Condition cond, MBasicBlock* ifTrue, MBasicBlock* ifFalse);
81 
testNullEmitBranch(Assembler::Condition cond,const ValueOperand & value,MBasicBlock * ifTrue,MBasicBlock * ifFalse)82     void testNullEmitBranch(Assembler::Condition cond, const ValueOperand& value,
83                             MBasicBlock* ifTrue, MBasicBlock* ifFalse)
84     {
85         cond = masm.testNull(cond, value);
86         emitBranch(cond, ifTrue, ifFalse);
87     }
testUndefinedEmitBranch(Assembler::Condition cond,const ValueOperand & value,MBasicBlock * ifTrue,MBasicBlock * ifFalse)88     void testUndefinedEmitBranch(Assembler::Condition cond, const ValueOperand& value,
89                                  MBasicBlock* ifTrue, MBasicBlock* ifFalse)
90     {
91         cond = masm.testUndefined(cond, value);
92         emitBranch(cond, ifTrue, ifFalse);
93     }
testObjectEmitBranch(Assembler::Condition cond,const ValueOperand & value,MBasicBlock * ifTrue,MBasicBlock * ifFalse)94     void testObjectEmitBranch(Assembler::Condition cond, const ValueOperand& value,
95                               MBasicBlock* ifTrue, MBasicBlock* ifFalse)
96     {
97         cond = masm.testObject(cond, value);
98         emitBranch(cond, ifTrue, ifFalse);
99     }
testZeroEmitBranch(Assembler::Condition cond,Register reg,MBasicBlock * ifTrue,MBasicBlock * ifFalse)100     void testZeroEmitBranch(Assembler::Condition cond, Register reg,
101                             MBasicBlock* ifTrue, MBasicBlock* ifFalse)
102     {
103         MOZ_ASSERT(cond == Assembler::Equal || cond == Assembler::NotEqual);
104         masm.cmpPtr(reg, ImmWord(0));
105         emitBranch(cond, ifTrue, ifFalse);
106     }
107 
108     void emitTableSwitchDispatch(MTableSwitch* mir, Register index, Register base);
109 
110   public:
111     // Instruction visitors.
112     virtual void visitMinMaxD(LMinMaxD* ins);
113     virtual void visitMinMaxF(LMinMaxF* math);
114     virtual void visitAbsD(LAbsD* ins);
115     virtual void visitAbsF(LAbsF* ins);
116     virtual void visitSqrtD(LSqrtD* ins);
117     virtual void visitSqrtF(LSqrtF* ins);
118     virtual void visitAddI(LAddI* ins);
119     virtual void visitSubI(LSubI* ins);
120     virtual void visitBitNotI(LBitNotI* ins);
121     virtual void visitBitOpI(LBitOpI* ins);
122 
123     virtual void visitMulI(LMulI* ins);
124 
125     virtual void visitDivI(LDivI* ins);
126     virtual void visitDivPowTwoI(LDivPowTwoI* ins);
127     virtual void visitModI(LModI* ins);
128     virtual void visitModPowTwoI(LModPowTwoI* ins);
129     virtual void visitModMaskI(LModMaskI* ins);
130     virtual void visitPowHalfD(LPowHalfD* ins);
131     virtual void visitShiftI(LShiftI* ins);
132     virtual void visitUrshD(LUrshD* ins);
133 
134     virtual void visitTestIAndBranch(LTestIAndBranch* test);
135     virtual void visitCompare(LCompare* comp);
136     virtual void visitCompareAndBranch(LCompareAndBranch* comp);
137     virtual void visitTestDAndBranch(LTestDAndBranch* test);
138     virtual void visitTestFAndBranch(LTestFAndBranch* test);
139     virtual void visitCompareD(LCompareD* comp);
140     virtual void visitCompareF(LCompareF* comp);
141     virtual void visitCompareDAndBranch(LCompareDAndBranch* comp);
142     virtual void visitCompareFAndBranch(LCompareFAndBranch* comp);
143     virtual void visitCompareB(LCompareB* lir);
144     virtual void visitCompareBAndBranch(LCompareBAndBranch* lir);
145     virtual void visitCompareBitwise(LCompareBitwise* lir);
146     virtual void visitCompareBitwiseAndBranch(LCompareBitwiseAndBranch* lir);
147     virtual void visitBitAndAndBranch(LBitAndAndBranch* baab);
148     virtual void visitAsmJSUInt32ToDouble(LAsmJSUInt32ToDouble* lir);
149     virtual void visitAsmJSUInt32ToFloat32(LAsmJSUInt32ToFloat32* lir);
150     virtual void visitNotI(LNotI* ins);
151     virtual void visitNotD(LNotD* ins);
152     virtual void visitNotF(LNotF* ins);
153 
154     virtual void visitMathD(LMathD* math);
155     virtual void visitMathF(LMathF* math);
156     virtual void visitFloor(LFloor* lir);
157     virtual void visitFloorF(LFloorF* lir);
158     virtual void visitCeil(LCeil* lir);
159     virtual void visitCeilF(LCeilF* lir);
160     virtual void visitRound(LRound* lir);
161     virtual void visitRoundF(LRoundF* lir);
162     virtual void visitTruncateDToInt32(LTruncateDToInt32* ins);
163     virtual void visitTruncateFToInt32(LTruncateFToInt32* ins);
164 
165     virtual void visitClzI(LClzI* lir);
166     // Out of line visitors.
167     void visitOutOfLineBailout(OutOfLineBailout* ool);
168     void visitOutOfLineTableSwitch(OutOfLineTableSwitch* ool);
169 
170   protected:
171     ValueOperand ToValue(LInstruction* ins, size_t pos);
172     ValueOperand ToOutValue(LInstruction* ins);
173     ValueOperand ToTempValue(LInstruction* ins, size_t pos);
174 
175     // Functions for LTestVAndBranch.
176     Register splitTagForTest(const ValueOperand& value);
177 
178     void storeElementTyped(const LAllocation* value, MIRType valueType, MIRType elementType,
179                            Register elements, const LAllocation* index);
180 
181     void divICommon(MDiv* mir, Register lhs, Register rhs, Register output, LSnapshot* snapshot,
182                     Label& done);
183     void modICommon(MMod* mir, Register lhs, Register rhs, Register output, LSnapshot* snapshot,
184                     Label& done);
185 
186   public:
187     void visitBox(LBox* box);
188     void visitUnbox(LUnbox* unbox);
189     void visitValue(LValue* value);
190     void visitDouble(LDouble* ins);
191     void visitFloat32(LFloat32* ins);
192 
193     void visitLoadSlotV(LLoadSlotV* load);
194     void visitLoadSlotT(LLoadSlotT* load);
195     void visitStoreSlotT(LStoreSlotT* load);
196 
197     void visitLoadElementT(LLoadElementT* load);
198 
199     void visitGuardShape(LGuardShape* guard);
200     void visitGuardObjectGroup(LGuardObjectGroup* guard);
201     void visitGuardClass(LGuardClass* guard);
202 
203     void visitInterruptCheck(LInterruptCheck* lir);
204 
205     void visitNegI(LNegI* lir);
206     void visitNegD(LNegD* lir);
207     void visitNegF(LNegF* lir);
208     void visitLoadTypedArrayElementStatic(LLoadTypedArrayElementStatic* ins);
209     void visitStoreTypedArrayElementStatic(LStoreTypedArrayElementStatic* ins);
210     void visitCompareExchangeTypedArrayElement(LCompareExchangeTypedArrayElement* lir);
211     void visitAtomicExchangeTypedArrayElement(LAtomicExchangeTypedArrayElement* lir);
212     void visitAsmJSCall(LAsmJSCall* ins);
213     void visitAsmJSLoadHeap(LAsmJSLoadHeap* ins);
214     void visitAsmJSStoreHeap(LAsmJSStoreHeap* ins);
215     void visitAsmJSCompareExchangeHeap(LAsmJSCompareExchangeHeap* ins);
216     void visitAsmJSAtomicBinopHeap(LAsmJSAtomicBinopHeap* ins);
217     void visitAsmJSLoadGlobalVar(LAsmJSLoadGlobalVar* ins);
218     void visitAsmJSStoreGlobalVar(LAsmJSStoreGlobalVar* ins);
219     void visitAsmJSLoadFuncPtr(LAsmJSLoadFuncPtr* ins);
220     void visitAsmJSLoadFFIFunc(LAsmJSLoadFFIFunc* ins);
221     void visitAsmJSPassStackArg(LAsmJSPassStackArg* ins);
222 
223     void generateInvalidateEpilogue();
224 
225     void setReturnDoubleRegs(LiveRegisterSet* regs);
226 
227   protected:
postAsmJSCall(LAsmJSCall * lir)228     void postAsmJSCall(LAsmJSCall* lir) {
229         MOZ_CRASH("postAsmJSCall");
230     }
231 
232     void visitEffectiveAddress(LEffectiveAddress* ins);
233     void visitUDiv(LUDiv* ins);
234     void visitUMod(LUMod* ins);
235 
236   public:
237     // Unimplemented SIMD instructions.
visitSimdSplatX4(LSimdSplatX4 * lir)238     void visitSimdSplatX4(LSimdSplatX4* lir) { MOZ_CRASH("NYI"); }
visitInt32x4(LInt32x4 * ins)239     void visitInt32x4(LInt32x4* ins) { MOZ_CRASH("NYI"); }
visitFloat32x4(LFloat32x4 * ins)240     void visitFloat32x4(LFloat32x4* ins) { MOZ_CRASH("NYI"); }
visitSimdExtractElementI(LSimdExtractElementI * ins)241     void visitSimdExtractElementI(LSimdExtractElementI* ins) { MOZ_CRASH("NYI"); }
visitSimdExtractElementF(LSimdExtractElementF * ins)242     void visitSimdExtractElementF(LSimdExtractElementF* ins) { MOZ_CRASH("NYI"); }
visitSimdSignMaskX4(LSimdSignMaskX4 * ins)243     void visitSimdSignMaskX4(LSimdSignMaskX4* ins) { MOZ_CRASH("NYI"); }
visitSimdBinaryCompIx4(LSimdBinaryCompIx4 * lir)244     void visitSimdBinaryCompIx4(LSimdBinaryCompIx4* lir) { MOZ_CRASH("NYI"); }
visitSimdBinaryCompFx4(LSimdBinaryCompFx4 * lir)245     void visitSimdBinaryCompFx4(LSimdBinaryCompFx4* lir) { MOZ_CRASH("NYI"); }
visitSimdBinaryArithIx4(LSimdBinaryArithIx4 * lir)246     void visitSimdBinaryArithIx4(LSimdBinaryArithIx4* lir) { MOZ_CRASH("NYI"); }
visitSimdBinaryArithFx4(LSimdBinaryArithFx4 * lir)247     void visitSimdBinaryArithFx4(LSimdBinaryArithFx4* lir) { MOZ_CRASH("NYI"); }
visitSimdBinaryBitwiseX4(LSimdBinaryBitwiseX4 * lir)248     void visitSimdBinaryBitwiseX4(LSimdBinaryBitwiseX4* lir) { MOZ_CRASH("NYI"); }
249 };
250 
251 typedef CodeGeneratorARM64 CodeGeneratorSpecific;
252 
253 // An out-of-line bailout thunk.
254 class OutOfLineBailout : public OutOfLineCodeBase<CodeGeneratorARM64>
255 {
256   protected: // Silence Clang warning.
257     LSnapshot* snapshot_;
258 
259   public:
OutOfLineBailout(LSnapshot * snapshot)260     OutOfLineBailout(LSnapshot* snapshot)
261       : snapshot_(snapshot)
262     { }
263 
264     void accept(CodeGeneratorARM64* codegen);
265 
snapshot()266     LSnapshot* snapshot() const {
267         return snapshot_;
268     }
269 };
270 
271 } // namespace jit
272 } // namespace js
273 
274 #endif /* jit_arm64_CodeGenerator_arm64_h */
275