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_arm_CodeGenerator_arm_h michael@0: #define jit_arm_CodeGenerator_arm_h michael@0: michael@0: #include "jit/arm/Assembler-arm.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 CodeGeneratorARM : public CodeGeneratorShared michael@0: { michael@0: friend class MoveResolverARM; michael@0: michael@0: CodeGeneratorARM *thisFromCtor() {return this;} michael@0: michael@0: protected: michael@0: // Label for the common return path. michael@0: NonAssertingLabel returnLabel_; michael@0: NonAssertingLabel deoptLabel_; michael@0: // ugh. this is not going to be pretty to move over. michael@0: // stack slotted variables are not useful on arm. michael@0: // it looks like this will need to return one of two types. 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: return Operand(StackPointer, ToStackOffset(&a)); 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: bool bailoutIf(Assembler::Condition condition, LSnapshot *snapshot); michael@0: bool bailoutFrom(Label *label, LSnapshot *snapshot); michael@0: bool bailout(LSnapshot *snapshot); michael@0: michael@0: template michael@0: bool bailoutCmpPtr(Assembler::Condition c, T1 lhs, T2 rhs, LSnapshot *snapshot) { michael@0: masm.cmpPtr(lhs, rhs); michael@0: return bailoutIf(c, snapshot); michael@0: } michael@0: bool bailoutTestPtr(Assembler::Condition c, Register lhs, Register rhs, LSnapshot *snapshot) { michael@0: masm.testPtr(lhs, rhs); michael@0: return bailoutIf(c, snapshot); michael@0: } michael@0: template michael@0: bool bailoutCmp32(Assembler::Condition c, T1 lhs, T2 rhs, LSnapshot *snapshot) { michael@0: masm.cmp32(lhs, rhs); michael@0: return bailoutIf(c, snapshot); michael@0: } michael@0: template michael@0: bool bailoutTest32(Assembler::Condition c, T1 lhs, T2 rhs, LSnapshot *snapshot) { michael@0: masm.test32(lhs, rhs); michael@0: return bailoutIf(c, snapshot); michael@0: } michael@0: michael@0: protected: michael@0: bool generatePrologue(); michael@0: bool generateAsmJSPrologue(Label *stackOverflowLabel); michael@0: bool generateEpilogue(); michael@0: bool generateOutOfLineCode(); michael@0: michael@0: void emitRoundDouble(const FloatRegister &src, const Register &dest, Label *fail); 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: void emitBranch(Assembler::Condition cond, MBasicBlock *ifTrue, MBasicBlock *ifFalse); michael@0: michael@0: void testNullEmitBranch(Assembler::Condition cond, const ValueOperand &value, michael@0: MBasicBlock *ifTrue, MBasicBlock *ifFalse) michael@0: { michael@0: cond = masm.testNull(cond, value); michael@0: emitBranch(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: cond = masm.testUndefined(cond, value); michael@0: emitBranch(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 visitSoftDivI(LSoftDivI *ins); michael@0: virtual bool visitDivPowTwoI(LDivPowTwoI *ins); michael@0: virtual bool visitModI(LModI *ins); michael@0: virtual bool visitSoftModI(LSoftModI *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 *baab); 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: bool divICommon(MDiv *mir, Register lhs, Register rhs, Register output, LSnapshot *snapshot, michael@0: Label &done); michael@0: bool modICommon(MMod *mir, Register lhs, Register rhs, Register output, LSnapshot *snapshot, michael@0: Label &done); michael@0: michael@0: public: michael@0: CodeGeneratorARM(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: 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: if (!useHardFpABI() && lir->mir()->callee().which() == MAsmJSCall::Callee::Builtin) { michael@0: switch (lir->mir()->type()) { michael@0: case MIRType_Double: michael@0: masm.ma_vxfer(r0, r1, d0); michael@0: break; michael@0: case MIRType_Float32: michael@0: masm.as_vxfer(r0, InvalidReg, VFPRegister(d0).singleOverlay(), michael@0: Assembler::CoreToFloat); michael@0: break; michael@0: default: michael@0: break; michael@0: } michael@0: } michael@0: } michael@0: michael@0: bool visitEffectiveAddress(LEffectiveAddress *ins); michael@0: bool visitUDiv(LUDiv *ins); michael@0: bool visitUMod(LUMod *ins); michael@0: bool visitSoftUDivOrMod(LSoftUDivOrMod *ins); michael@0: }; michael@0: michael@0: typedef CodeGeneratorARM CodeGeneratorSpecific; michael@0: michael@0: // An out-of-line bailout thunk. michael@0: class OutOfLineBailout : public OutOfLineCodeBase michael@0: { michael@0: protected: // Silence Clang warning. 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(CodeGeneratorARM *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_arm_CodeGenerator_arm_h */