| /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- |
| * vim: set ts=8 sts=4 et sw=4 tw=99: |
| * This Source Code Form is subject to the terms of the Mozilla Public |
| * License, v. 2.0. If a copy of the MPL was not distributed with this |
| * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
| |
| #ifndef jit_mips_CodeGenerator_mips_h |
| #define jit_mips_CodeGenerator_mips_h |
| |
| #include "jit/mips/Assembler-mips.h" |
| #include "jit/shared/CodeGenerator-shared.h" |
| |
| namespace js { |
| namespace jit { |
| |
| class OutOfLineBailout; |
| class OutOfLineTableSwitch; |
| |
| class CodeGeneratorMIPS : public CodeGeneratorShared |
| { |
| friend class MoveResolverMIPS; |
| |
| CodeGeneratorMIPS *thisFromCtor() { |
| return this; |
| } |
| |
| protected: |
| // Label for the common return path. |
| HeapLabel *returnLabel_; |
| HeapLabel *deoptLabel_; |
| |
| inline Address ToAddress(const LAllocation &a) { |
| MOZ_ASSERT(a.isMemory()); |
| int32_t offset = ToStackOffset(&a); |
| |
| // The way the stack slots work, we assume that everything from |
| // depth == 0 downwards is writable however, since our frame is |
| // included in this, ensure that the frame gets skipped. |
| if (gen->compilingAsmJS()) |
| offset -= AlignmentMidPrologue; |
| |
| return Address(StackPointer, offset); |
| } |
| |
| inline Address ToAddress(const LAllocation *a) { |
| return ToAddress(*a); |
| } |
| |
| inline Operand ToOperand(const LAllocation &a) { |
| if (a.isGeneralReg()) |
| return Operand(a.toGeneralReg()->reg()); |
| if (a.isFloatReg()) |
| return Operand(a.toFloatReg()->reg()); |
| |
| MOZ_ASSERT(a.isMemory()); |
| int32_t offset = ToStackOffset(&a); |
| |
| // The way the stack slots work, we assume that everything from |
| // depth == 0 downwards is writable however, since our frame is |
| // included in this, ensure that the frame gets skipped. |
| if (gen->compilingAsmJS()) |
| offset -= AlignmentMidPrologue; |
| |
| return Operand(StackPointer, offset); |
| } |
| inline Operand ToOperand(const LAllocation *a) { |
| return ToOperand(*a); |
| } |
| inline Operand ToOperand(const LDefinition *def) { |
| return ToOperand(def->output()); |
| } |
| |
| MoveResolver::MoveOperand toMoveOperand(const LAllocation* a) const; |
| |
| template <typename T1, typename T2> |
| bool bailoutCmp32(Assembler::Condition c, T1 lhs, T2 rhs, LSnapshot *snapshot) { |
| bool goodBailout; |
| Label skip; |
| masm.ma_b(lhs, rhs, &skip, Assembler::InvertCondition(c), ShortJump); |
| goodBailout = bailout(snapshot); |
| masm.bind(&skip); |
| return goodBailout; |
| } |
| template<typename T> |
| bool bailoutCmp32(Assembler::Condition c, Operand lhs, T rhs, LSnapshot *snapshot) { |
| if (lhs.getTag() == Operand::REG) |
| return bailoutCmp32(c, lhs.toReg(), rhs, snapshot); |
| if (lhs.getTag() == Operand::MEM) |
| return bailoutCmp32(c, lhs.toAddress(), rhs, snapshot); |
| MOZ_NOT_REACHED("Invalid operand tag."); |
| return false; |
| } |
| template<typename T> |
| bool bailoutTest32(Assembler::Condition c, Register lhs, T rhs, LSnapshot *snapshot) { |
| Label bail; |
| masm.branchTest32(c, lhs, rhs, &bail); |
| return bailoutFrom(&bail, snapshot); |
| } |
| template <typename T1, typename T2> |
| bool bailoutCmpPtr(Assembler::Condition c, T1 lhs, T2 rhs, LSnapshot *snapshot) { |
| return bailoutCmp32(c, lhs, rhs, snapshot); |
| } |
| bool bailoutTestPtr(Assembler::Condition c, Register lhs, Register rhs, LSnapshot *snapshot) { |
| Label bail; |
| masm.branchTestPtr(c, lhs, rhs, &bail); |
| return bailoutFrom(&bail, snapshot); |
| } |
| |
| bool bailoutFrom(Label *label, LSnapshot *snapshot); |
| bool bailout(LSnapshot *snapshot); |
| |
| protected: |
| bool generatePrologue(); |
| bool generateEpilogue(); |
| bool generateOutOfLineCode(); |
| |
| void branchToBlock(Assembler::FloatFormat fmt, FloatRegister lhs, FloatRegister rhs, |
| MBasicBlock *mir, Assembler::DoubleCondition cond); |
| |
| // Generate a jump to the start of the specified block, adding information |
| // if this is a loop backedge. Use this in place of jumping directly to |
| // mir->lir()->label(), or use getJumpLabelForBranch() if a label to use |
| // directly is needed. |
| void jumpToBlock(MBasicBlock *mir) { |
| // No jump necessary if we can fall through to the next block. |
| if (isNextBlock(mir->lir())) { |
| return; |
| } |
| |
| masm.jump(mir->lir()->label()); |
| } |
| |
| template <typename T> |
| void branchToBlock(Register lhs, T rhs, MBasicBlock *mir, Assembler::Condition cond) |
| { |
| Label *label = mir->lir()->label(); |
| masm.ma_b(lhs, rhs, label, cond); |
| } |
| |
| // Emits a branch that directs control flow to the true block if |cond| is |
| // true, and the false block if |cond| is false. |
| template <typename T> |
| void emitBranch(Register lhs, T rhs, Assembler::Condition cond, |
| MBasicBlock *mirTrue, MBasicBlock *mirFalse) |
| { |
| if (isNextBlock(mirFalse->lir())) { |
| branchToBlock(lhs, rhs, mirTrue, cond); |
| } else { |
| branchToBlock(lhs, rhs, mirFalse, Assembler::InvertCondition(cond)); |
| jumpToBlock(mirTrue); |
| } |
| } |
| |
| void testNullEmitBranch(Assembler::Condition cond, const ValueOperand &value, |
| MBasicBlock *ifTrue, MBasicBlock *ifFalse) |
| { |
| emitBranch(value.typeReg(), (Imm32)ImmType(JSVAL_TYPE_NULL), cond, ifTrue, ifFalse); |
| } |
| void testUndefinedEmitBranch(Assembler::Condition cond, const ValueOperand &value, |
| MBasicBlock *ifTrue, MBasicBlock *ifFalse) |
| { |
| emitBranch(value.typeReg(), (Imm32)ImmType(JSVAL_TYPE_UNDEFINED), cond, ifTrue, ifFalse); |
| } |
| |
| bool emitTableSwitchDispatch(MTableSwitch *mir, const Register &index, const Register &base); |
| |
| public: |
| // Instruction visitors. |
| virtual bool visitMinMaxD(LMinMaxD *ins); |
| virtual bool visitAbsD(LAbsD *ins); |
| virtual bool visitSqrtD(LSqrtD *ins); |
| virtual bool visitAddI(LAddI *ins); |
| virtual bool visitSubI(LSubI *ins); |
| virtual bool visitBitNotI(LBitNotI *ins); |
| virtual bool visitBitOpI(LBitOpI *ins); |
| |
| virtual bool visitMulI(LMulI *ins); |
| |
| virtual bool visitDivI(LDivI *ins); |
| virtual bool visitDivPowTwoI(LDivPowTwoI *ins); |
| virtual bool visitModI(LModI *ins); |
| virtual bool visitModPowTwoI(LModPowTwoI *ins); |
| virtual bool visitModMaskI(LModMaskI *ins); |
| virtual bool visitPowHalfD(LPowHalfD *ins); |
| virtual bool visitShiftI(LShiftI *ins); |
| virtual bool visitUrshD(LUrshD *ins); |
| |
| virtual bool visitTestIAndBranch(LTestIAndBranch *test); |
| virtual bool visitCompare(LCompare *comp); |
| virtual bool visitCompareAndBranch(LCompareAndBranch *comp); |
| virtual bool visitTestDAndBranch(LTestDAndBranch *test); |
| virtual bool visitCompareD(LCompareD *comp); |
| virtual bool visitCompareDAndBranch(LCompareDAndBranch *comp); |
| virtual bool visitCompareB(LCompareB *lir); |
| virtual bool visitCompareBAndBranch(LCompareBAndBranch *lir); |
| virtual bool visitCompareV(LCompareV *lir); |
| virtual bool visitCompareVAndBranch(LCompareVAndBranch *lir); |
| virtual bool visitUInt32ToDouble(LUInt32ToDouble *lir); |
| virtual bool visitNotI(LNotI *ins); |
| virtual bool visitNotD(LNotD *ins); |
| |
| virtual bool visitMathD(LMathD *math); |
| virtual bool visitFloor(LFloor *lir); |
| virtual bool visitRound(LRound *lir); |
| virtual bool visitTruncateDToInt32(LTruncateDToInt32 *ins); |
| |
| // Out of line visitors. |
| bool visitOutOfLineBailout(OutOfLineBailout *ool); |
| bool visitOutOfLineTableSwitch(OutOfLineTableSwitch *ool); |
| |
| protected: |
| ValueOperand ToValue(LInstruction *ins, size_t pos); |
| ValueOperand ToOutValue(LInstruction *ins); |
| ValueOperand ToTempValue(LInstruction *ins, size_t pos); |
| |
| // Functions for LTestVAndBranch. |
| Register splitTagForTest(const ValueOperand &value); |
| |
| void storeElementTyped(const LAllocation *value, MIRType valueType, MIRType elementType, |
| const Register &elements, const LAllocation *index); |
| |
| public: |
| CodeGeneratorMIPS(MIRGenerator *gen, LIRGraph *graph, MacroAssembler *masm); |
| |
| public: |
| bool visitBox(LBox *box); |
| bool visitBoxDouble(LBoxDouble *box); |
| bool visitUnbox(LUnbox *unbox); |
| bool visitValue(LValue *value); |
| bool visitOsrValue(LOsrValue *value); |
| bool visitDouble(LDouble *ins); |
| |
| bool visitLoadSlotV(LLoadSlotV *load); |
| bool visitLoadSlotT(LLoadSlotT *load); |
| bool visitStoreSlotT(LStoreSlotT *load); |
| |
| bool visitLoadElementT(LLoadElementT *load); |
| |
| bool visitGuardShape(LGuardShape *guard); |
| bool visitGuardObjectType(LGuardObjectType *guard); |
| bool visitGuardClass(LGuardClass *guard); |
| bool visitImplicitThis(LImplicitThis *lir); |
| |
| bool visitInterruptCheck(LInterruptCheck *lir); |
| |
| bool visitNegI(LNegI *lir); |
| bool visitNegD(LNegD *lir); |
| bool visitLoadTypedArrayElementStatic(LLoadTypedArrayElementStatic *ins); |
| bool visitStoreTypedArrayElementStatic(LStoreTypedArrayElementStatic *ins); |
| bool visitAsmJSLoadHeap(LAsmJSLoadHeap *ins); |
| bool visitAsmJSStoreHeap(LAsmJSStoreHeap *ins); |
| bool visitAsmJSLoadGlobalVar(LAsmJSLoadGlobalVar *ins); |
| bool visitAsmJSStoreGlobalVar(LAsmJSStoreGlobalVar *ins); |
| bool visitAsmJSLoadFuncPtr(LAsmJSLoadFuncPtr *ins); |
| bool visitAsmJSLoadFFIFunc(LAsmJSLoadFFIFunc *ins); |
| |
| bool visitAsmJSPassStackArg(LAsmJSPassStackArg *ins); |
| |
| bool generateInvalidateEpilogue(); |
| protected: |
| void postAsmJSCall(LAsmJSCall *lir) {} |
| |
| bool visitEffectiveAddress(LEffectiveAddress *ins); |
| bool visitUDiv(LUDiv *ins); |
| bool visitUMod(LUMod *ins); |
| |
| public: |
| bool bailoutIf(Assembler::Condition condition, LSnapshot *snapshot); |
| bool visitMoveGroup(LMoveGroup *group); |
| }; |
| |
| typedef CodeGeneratorMIPS CodeGeneratorSpecific; |
| |
| // An out-of-line bailout thunk. |
| class OutOfLineBailout : public OutOfLineCodeBase<CodeGeneratorMIPS> |
| { |
| LSnapshot *snapshot_; |
| uint32_t frameSize_; |
| |
| public: |
| OutOfLineBailout(LSnapshot *snapshot, uint32_t frameSize) |
| : snapshot_(snapshot), |
| frameSize_(frameSize) |
| { } |
| |
| bool accept(CodeGeneratorMIPS *codegen); |
| |
| LSnapshot *snapshot() const { |
| return snapshot_; |
| } |
| }; |
| |
| } // namespace jit |
| } // namespace js |
| |
| #endif /* jit_mips_CodeGenerator_mips_h */ |