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_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 CodeGeneratorARM64;
17 class OutOfLineBailout;
18 class OutOfLineTableSwitch;
19 
20 using OutOfLineWasmTruncateCheck =
21     OutOfLineWasmTruncateCheckBase<CodeGeneratorARM64>;
22 
23 class CodeGeneratorARM64 : public CodeGeneratorShared {
24   friend class MoveResolverARM64;
25 
26  protected:
27   CodeGeneratorARM64(MIRGenerator* gen, LIRGraph* graph, MacroAssembler* masm);
28 
29   NonAssertingLabel deoptLabel_;
30 
31   MoveOperand toMoveOperand(const LAllocation a) const;
32 
33   void bailoutIf(Assembler::Condition condition, LSnapshot* snapshot);
34   void bailoutFrom(Label* label, LSnapshot* snapshot);
35   void bailout(LSnapshot* snapshot);
36 
37   template <typename T1, typename T2>
bailoutCmpPtr(Assembler::Condition c,T1 lhs,T2 rhs,LSnapshot * snapshot)38   void bailoutCmpPtr(Assembler::Condition c, T1 lhs, T2 rhs,
39                      LSnapshot* snapshot) {
40     masm.cmpPtr(lhs, rhs);
41     return bailoutIf(c, snapshot);
42   }
bailoutTestPtr(Assembler::Condition c,Register lhs,Register rhs,LSnapshot * snapshot)43   void bailoutTestPtr(Assembler::Condition c, Register lhs, Register rhs,
44                       LSnapshot* snapshot) {
45     masm.testPtr(lhs, rhs);
46     return bailoutIf(c, snapshot);
47   }
48   template <typename T1, typename T2>
bailoutCmp32(Assembler::Condition c,T1 lhs,T2 rhs,LSnapshot * snapshot)49   void bailoutCmp32(Assembler::Condition c, T1 lhs, T2 rhs,
50                     LSnapshot* snapshot) {
51     masm.cmp32(lhs, rhs);
52     return bailoutIf(c, snapshot);
53   }
54   template <typename T1, typename T2>
bailoutTest32(Assembler::Condition c,T1 lhs,T2 rhs,LSnapshot * snapshot)55   void bailoutTest32(Assembler::Condition c, T1 lhs, T2 rhs,
56                      LSnapshot* snapshot) {
57     masm.test32(lhs, rhs);
58     return bailoutIf(c, snapshot);
59   }
bailoutIfFalseBool(Register reg,LSnapshot * snapshot)60   void bailoutIfFalseBool(Register reg, LSnapshot* snapshot) {
61     masm.test32(reg, Imm32(0xFF));
62     return bailoutIf(Assembler::Zero, snapshot);
63   }
64 
65   bool generateOutOfLineCode();
66 
67   // Emits a branch that directs control flow to the true block if |cond| is
68   // true, and the false block if |cond| is false.
69   void emitBranch(Assembler::Condition cond, MBasicBlock* ifTrue,
70                   MBasicBlock* ifFalse);
71 
testNullEmitBranch(Assembler::Condition cond,const ValueOperand & value,MBasicBlock * ifTrue,MBasicBlock * ifFalse)72   void testNullEmitBranch(Assembler::Condition cond, const ValueOperand& value,
73                           MBasicBlock* ifTrue, MBasicBlock* ifFalse) {
74     cond = masm.testNull(cond, value);
75     emitBranch(cond, ifTrue, ifFalse);
76   }
testUndefinedEmitBranch(Assembler::Condition cond,const ValueOperand & value,MBasicBlock * ifTrue,MBasicBlock * ifFalse)77   void testUndefinedEmitBranch(Assembler::Condition cond,
78                                const ValueOperand& value, MBasicBlock* ifTrue,
79                                MBasicBlock* ifFalse) {
80     cond = masm.testUndefined(cond, value);
81     emitBranch(cond, ifTrue, ifFalse);
82   }
testObjectEmitBranch(Assembler::Condition cond,const ValueOperand & value,MBasicBlock * ifTrue,MBasicBlock * ifFalse)83   void testObjectEmitBranch(Assembler::Condition cond,
84                             const ValueOperand& value, MBasicBlock* ifTrue,
85                             MBasicBlock* ifFalse) {
86     cond = masm.testObject(cond, value);
87     emitBranch(cond, ifTrue, ifFalse);
88   }
testZeroEmitBranch(Assembler::Condition cond,Register reg,MBasicBlock * ifTrue,MBasicBlock * ifFalse)89   void testZeroEmitBranch(Assembler::Condition cond, Register reg,
90                           MBasicBlock* ifTrue, MBasicBlock* ifFalse) {
91     MOZ_ASSERT(cond == Assembler::Equal || cond == Assembler::NotEqual);
92     masm.cmpPtr(reg, ImmWord(0));
93     emitBranch(cond, ifTrue, ifFalse);
94   }
95 
96   void emitTableSwitchDispatch(MTableSwitch* mir, Register index,
97                                Register base);
98 
99   void emitBigIntDiv(LBigIntDiv* ins, Register dividend, Register divisor,
100                      Register output, Label* fail);
101   void emitBigIntMod(LBigIntMod* ins, Register dividend, Register divisor,
102                      Register output, Label* fail);
103   void emitSimpleBinaryI64(
104       LInstructionHelper<INT64_PIECES, 2 * INT64_PIECES, 0>* lir, JSOp op);
105 
106   ValueOperand ToValue(LInstruction* ins, size_t pos);
107   ValueOperand ToTempValue(LInstruction* ins, size_t pos);
108 
109   void generateInvalidateEpilogue();
110 
111  public:
112   void visitOutOfLineBailout(OutOfLineBailout* ool);
113   void visitOutOfLineTableSwitch(OutOfLineTableSwitch* ool);
114   void visitOutOfLineWasmTruncateCheck(OutOfLineWasmTruncateCheck* ool);
115 };
116 
117 typedef CodeGeneratorARM64 CodeGeneratorSpecific;
118 
119 // An out-of-line bailout thunk.
120 class OutOfLineBailout : public OutOfLineCodeBase<CodeGeneratorARM64> {
121  protected:  // Silence Clang warning.
122   LSnapshot* snapshot_;
123 
124  public:
OutOfLineBailout(LSnapshot * snapshot)125   explicit OutOfLineBailout(LSnapshot* snapshot) : snapshot_(snapshot) {}
126 
127   void accept(CodeGeneratorARM64* codegen) override;
128 
snapshot()129   LSnapshot* snapshot() const { return snapshot_; }
130 };
131 
132 }  // namespace jit
133 }  // namespace js
134 
135 #endif /* jit_arm64_CodeGenerator_arm64_h */
136