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