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_MacroAssembler_mips_h michael@0: #define jit_mips_MacroAssembler_mips_h michael@0: michael@0: #include "jsopcode.h" michael@0: michael@0: #include "jit/IonCaches.h" michael@0: #include "jit/IonFrames.h" michael@0: #include "jit/mips/Assembler-mips.h" michael@0: #include "jit/MoveResolver.h" michael@0: michael@0: namespace js { michael@0: namespace jit { michael@0: michael@0: enum LoadStoreSize michael@0: { michael@0: SizeByte = 8, michael@0: SizeHalfWord = 16, michael@0: SizeWord = 32, michael@0: SizeDouble = 64 michael@0: }; michael@0: michael@0: enum LoadStoreExtension michael@0: { michael@0: ZeroExtend = 0, michael@0: SignExtend = 1 michael@0: }; michael@0: michael@0: enum JumpKind michael@0: { michael@0: LongJump = 0, michael@0: ShortJump = 1 michael@0: }; michael@0: michael@0: struct ImmTag : public Imm32 michael@0: { michael@0: ImmTag(JSValueTag mask) michael@0: : Imm32(int32_t(mask)) michael@0: { } michael@0: }; michael@0: michael@0: struct ImmType : public ImmTag michael@0: { michael@0: ImmType(JSValueType type) michael@0: : ImmTag(JSVAL_TYPE_TO_TAG(type)) michael@0: { } michael@0: }; michael@0: michael@0: static const ValueOperand JSReturnOperand = ValueOperand(JSReturnReg_Type, JSReturnReg_Data); michael@0: static const ValueOperand softfpReturnOperand = ValueOperand(v1, v0); michael@0: michael@0: static Register CallReg = t9; michael@0: static const int defaultShift = 3; michael@0: static_assert(1 << defaultShift == sizeof(jsval), "The defaultShift is wrong"); michael@0: michael@0: class MacroAssemblerMIPS : public Assembler michael@0: { michael@0: public: michael@0: michael@0: void convertBoolToInt32(Register source, Register dest); michael@0: void convertInt32ToDouble(const Register &src, const FloatRegister &dest); michael@0: void convertInt32ToDouble(const Address &src, FloatRegister dest); michael@0: void convertUInt32ToDouble(const Register &src, const FloatRegister &dest); michael@0: void convertUInt32ToFloat32(const Register &src, const FloatRegister &dest); michael@0: void convertDoubleToFloat32(const FloatRegister &src, const FloatRegister &dest); michael@0: void branchTruncateDouble(const FloatRegister &src, const Register &dest, Label *fail); michael@0: void convertDoubleToInt32(const FloatRegister &src, const Register &dest, Label *fail, michael@0: bool negativeZeroCheck = true); michael@0: void convertFloat32ToInt32(const FloatRegister &src, const Register &dest, Label *fail, michael@0: bool negativeZeroCheck = true); michael@0: michael@0: void convertFloat32ToDouble(const FloatRegister &src, const FloatRegister &dest); michael@0: void branchTruncateFloat32(const FloatRegister &src, const Register &dest, Label *fail); michael@0: void convertInt32ToFloat32(const Register &src, const FloatRegister &dest); michael@0: void convertInt32ToFloat32(const Address &src, FloatRegister dest); michael@0: michael@0: michael@0: void addDouble(FloatRegister src, FloatRegister dest); michael@0: void subDouble(FloatRegister src, FloatRegister dest); michael@0: void mulDouble(FloatRegister src, FloatRegister dest); michael@0: void divDouble(FloatRegister src, FloatRegister dest); michael@0: michael@0: void negateDouble(FloatRegister reg); michael@0: void inc64(AbsoluteAddress dest); michael@0: michael@0: public: michael@0: michael@0: void ma_move(Register rd, Register rs); michael@0: michael@0: void ma_li(Register dest, const ImmGCPtr &ptr); michael@0: michael@0: void ma_li(const Register &dest, AbsoluteLabel *label); michael@0: michael@0: void ma_li(Register dest, Imm32 imm); michael@0: void ma_liPatchable(Register dest, Imm32 imm); michael@0: void ma_liPatchable(Register dest, ImmPtr imm); michael@0: michael@0: // Shift operations michael@0: void ma_sll(Register rd, Register rt, Imm32 shift); michael@0: void ma_srl(Register rd, Register rt, Imm32 shift); michael@0: void ma_sra(Register rd, Register rt, Imm32 shift); michael@0: void ma_ror(Register rd, Register rt, Imm32 shift); michael@0: void ma_rol(Register rd, Register rt, Imm32 shift); michael@0: michael@0: void ma_sll(Register rd, Register rt, Register shift); michael@0: void ma_srl(Register rd, Register rt, Register shift); michael@0: void ma_sra(Register rd, Register rt, Register shift); michael@0: void ma_ror(Register rd, Register rt, Register shift); michael@0: void ma_rol(Register rd, Register rt, Register shift); michael@0: michael@0: // Negate michael@0: void ma_negu(Register rd, Register rs); michael@0: michael@0: void ma_not(Register rd, Register rs); michael@0: michael@0: // and michael@0: void ma_and(Register rd, Register rs); michael@0: void ma_and(Register rd, Register rs, Register rt); michael@0: void ma_and(Register rd, Imm32 imm); michael@0: void ma_and(Register rd, Register rs, Imm32 imm); michael@0: michael@0: // or michael@0: void ma_or(Register rd, Register rs); michael@0: void ma_or(Register rd, Register rs, Register rt); michael@0: void ma_or(Register rd, Imm32 imm); michael@0: void ma_or(Register rd, Register rs, Imm32 imm); michael@0: michael@0: // xor michael@0: void ma_xor(Register rd, Register rs); michael@0: void ma_xor(Register rd, Register rs, Register rt); michael@0: void ma_xor(Register rd, Imm32 imm); michael@0: void ma_xor(Register rd, Register rs, Imm32 imm); michael@0: michael@0: // load michael@0: void ma_load(const Register &dest, Address address, LoadStoreSize size = SizeWord, michael@0: LoadStoreExtension extension = SignExtend); michael@0: void ma_load(const Register &dest, const BaseIndex &src, LoadStoreSize size = SizeWord, michael@0: LoadStoreExtension extension = SignExtend); michael@0: michael@0: // store michael@0: void ma_store(const Register &data, Address address, LoadStoreSize size = SizeWord, michael@0: LoadStoreExtension extension = SignExtend); michael@0: void ma_store(const Register &data, const BaseIndex &dest, LoadStoreSize size = SizeWord, michael@0: LoadStoreExtension extension = SignExtend); michael@0: void ma_store(const Imm32 &imm, const BaseIndex &dest, LoadStoreSize size = SizeWord, michael@0: LoadStoreExtension extension = SignExtend); michael@0: michael@0: void computeScaledAddress(const BaseIndex &address, Register dest); michael@0: michael@0: void computeEffectiveAddress(const Address &address, Register dest) { michael@0: ma_addu(dest, address.base, Imm32(address.offset)); michael@0: } michael@0: michael@0: void computeEffectiveAddress(const BaseIndex &address, Register dest) { michael@0: computeScaledAddress(address, dest); michael@0: if (address.offset) { michael@0: ma_addu(dest, dest, Imm32(address.offset)); michael@0: } michael@0: } michael@0: michael@0: // arithmetic based ops michael@0: // add michael@0: void ma_addu(Register rd, Register rs, Imm32 imm); michael@0: void ma_addu(Register rd, Register rs); michael@0: void ma_addu(Register rd, Imm32 imm); michael@0: void ma_addTestOverflow(Register rd, Register rs, Register rt, Label *overflow); michael@0: void ma_addTestOverflow(Register rd, Register rs, Imm32 imm, Label *overflow); michael@0: michael@0: // subtract michael@0: void ma_subu(Register rd, Register rs, Register rt); michael@0: void ma_subu(Register rd, Register rs, Imm32 imm); michael@0: void ma_subu(Register rd, Imm32 imm); michael@0: void ma_subTestOverflow(Register rd, Register rs, Register rt, Label *overflow); michael@0: void ma_subTestOverflow(Register rd, Register rs, Imm32 imm, Label *overflow); michael@0: michael@0: // multiplies. For now, there are only few that we care about. michael@0: void ma_mult(Register rs, Imm32 imm); michael@0: void ma_mul_branch_overflow(Register rd, Register rs, Register rt, Label *overflow); michael@0: void ma_mul_branch_overflow(Register rd, Register rs, Imm32 imm, Label *overflow); michael@0: michael@0: // divisions michael@0: void ma_div_branch_overflow(Register rd, Register rs, Register rt, Label *overflow); michael@0: void ma_div_branch_overflow(Register rd, Register rs, Imm32 imm, Label *overflow); michael@0: michael@0: // fast mod, uses scratch registers, and thus needs to be in the assembler michael@0: // implicitly assumes that we can overwrite dest at the beginning of the sequence michael@0: void ma_mod_mask(Register src, Register dest, Register hold, int32_t shift, michael@0: Label *negZero = nullptr); michael@0: michael@0: // memory michael@0: // shortcut for when we know we're transferring 32 bits of data michael@0: void ma_lw(Register data, Address address); michael@0: michael@0: void ma_sw(Register data, Address address); michael@0: void ma_sw(Imm32 imm, Address address); michael@0: michael@0: void ma_pop(Register r); michael@0: void ma_push(Register r); michael@0: michael@0: // branches when done from within mips-specific code michael@0: void ma_b(Register lhs, Register rhs, Label *l, Condition c, JumpKind jumpKind = LongJump); michael@0: void ma_b(Register lhs, Imm32 imm, Label *l, Condition c, JumpKind jumpKind = LongJump); michael@0: void ma_b(Register lhs, Address addr, Label *l, Condition c, JumpKind jumpKind = LongJump); michael@0: void ma_b(Address addr, Imm32 imm, Label *l, Condition c, JumpKind jumpKind = LongJump); michael@0: void ma_b(Label *l, JumpKind jumpKind = LongJump); michael@0: void ma_bal(Label *l, JumpKind jumpKind = LongJump); michael@0: michael@0: // fp instructions michael@0: void ma_lis(FloatRegister dest, float value); michael@0: void ma_lid(FloatRegister dest, double value); michael@0: void ma_liNegZero(FloatRegister dest); michael@0: michael@0: void ma_mv(FloatRegister src, ValueOperand dest); michael@0: void ma_mv(ValueOperand src, FloatRegister dest); michael@0: michael@0: void ma_ls(FloatRegister fd, Address address); michael@0: void ma_ld(FloatRegister fd, Address address); michael@0: void ma_sd(FloatRegister fd, Address address); michael@0: void ma_sd(FloatRegister fd, BaseIndex address); michael@0: void ma_ss(FloatRegister fd, Address address); michael@0: void ma_ss(FloatRegister fd, BaseIndex address); michael@0: michael@0: void ma_pop(FloatRegister fs); michael@0: void ma_push(FloatRegister fs); michael@0: michael@0: //FP branches michael@0: void ma_bc1s(FloatRegister lhs, FloatRegister rhs, Label *label, DoubleCondition c, michael@0: JumpKind jumpKind = LongJump, FPConditionBit fcc = FCC0); michael@0: void ma_bc1d(FloatRegister lhs, FloatRegister rhs, Label *label, DoubleCondition c, michael@0: JumpKind jumpKind = LongJump, FPConditionBit fcc = FCC0); michael@0: michael@0: michael@0: // These fuctions abstract the access to high part of the double precision michael@0: // float register. It is intended to work on both 32 bit and 64 bit michael@0: // floating point coprocessor. michael@0: // :TODO: (Bug 985881) Modify this for N32 ABI to use mthc1 and mfhc1 michael@0: void moveToDoubleHi(Register src, FloatRegister dest) { michael@0: as_mtc1(src, getOddPair(dest)); michael@0: } michael@0: void moveFromDoubleHi(FloatRegister src, Register dest) { michael@0: as_mfc1(dest, getOddPair(src)); michael@0: } michael@0: michael@0: void moveToDoubleLo(Register src, FloatRegister dest) { michael@0: as_mtc1(src, dest); michael@0: } michael@0: void moveFromDoubleLo(FloatRegister src, Register dest) { michael@0: as_mfc1(dest, src); michael@0: } michael@0: michael@0: void moveToFloat32(Register src, FloatRegister dest) { michael@0: as_mtc1(src, dest); michael@0: } michael@0: void moveFromFloat32(FloatRegister src, Register dest) { michael@0: as_mfc1(dest, src); michael@0: } michael@0: michael@0: protected: michael@0: void branchWithCode(InstImm code, Label *label, JumpKind jumpKind); michael@0: Condition ma_cmp(Register rd, Register lhs, Register rhs, Condition c); michael@0: michael@0: void compareFloatingPoint(FloatFormat fmt, FloatRegister lhs, FloatRegister rhs, michael@0: DoubleCondition c, FloatTestKind *testKind, michael@0: FPConditionBit fcc = FCC0); michael@0: michael@0: public: michael@0: // calls an Ion function, assumes that the stack is untouched (8 byte alinged) michael@0: void ma_callIon(const Register reg); michael@0: // callso an Ion function, assuming that sp has already been decremented michael@0: void ma_callIonNoPush(const Register reg); michael@0: // calls an ion function, assuming that the stack is currently not 8 byte aligned michael@0: void ma_callIonHalfPush(const Register reg); michael@0: michael@0: void ma_call(ImmPtr dest); michael@0: michael@0: void ma_jump(ImmPtr dest); michael@0: michael@0: void ma_cmp_set(Register dst, Register lhs, Register rhs, Condition c); michael@0: void ma_cmp_set(Register dst, Register lhs, Imm32 imm, Condition c); michael@0: void ma_cmp_set(Register rd, Register rs, Address addr, Condition c); michael@0: void ma_cmp_set(Register dst, Address lhs, Register imm, Condition c); michael@0: void ma_cmp_set_double(Register dst, FloatRegister lhs, FloatRegister rhs, DoubleCondition c); michael@0: void ma_cmp_set_float32(Register dst, FloatRegister lhs, FloatRegister rhs, DoubleCondition c); michael@0: }; michael@0: michael@0: class MacroAssemblerMIPSCompat : public MacroAssemblerMIPS michael@0: { michael@0: // Number of bytes the stack is adjusted inside a call to C. Calls to C may michael@0: // not be nested. michael@0: bool inCall_; michael@0: uint32_t args_; michael@0: // The actual number of arguments that were passed, used to assert that michael@0: // the initial number of arguments declared was correct. michael@0: uint32_t passedArgs_; michael@0: michael@0: uint32_t usedArgSlots_; michael@0: MoveOp::Type firstArgType; michael@0: michael@0: bool dynamicAlignment_; michael@0: michael@0: bool enoughMemory_; michael@0: // Compute space needed for the function call and set the properties of the michael@0: // callee. It returns the space which has to be allocated for calling the michael@0: // function. michael@0: // michael@0: // arg Number of arguments of the function. michael@0: void setupABICall(uint32_t arg); michael@0: michael@0: protected: michael@0: MoveResolver moveResolver_; michael@0: michael@0: // Extra bytes currently pushed onto the frame beyond frameDepth_. This is michael@0: // needed to compute offsets to stack slots while temporary space has been michael@0: // reserved for unexpected spills or C++ function calls. It is maintained michael@0: // by functions which track stack alignment, which for clear distinction michael@0: // use StudlyCaps (for example, Push, Pop). michael@0: uint32_t framePushed_; michael@0: void adjustFrame(int value) { michael@0: setFramePushed(framePushed_ + value); michael@0: } michael@0: public: michael@0: MacroAssemblerMIPSCompat() michael@0: : inCall_(false), michael@0: enoughMemory_(true), michael@0: framePushed_(0) michael@0: { } michael@0: bool oom() const { michael@0: return Assembler::oom(); michael@0: } michael@0: michael@0: public: michael@0: using MacroAssemblerMIPS::call; michael@0: michael@0: void j(Label *dest) { michael@0: ma_b(dest); michael@0: } michael@0: michael@0: void mov(Register src, Register dest) { michael@0: as_or(dest, src, zero); michael@0: } michael@0: void mov(ImmWord imm, Register dest) { michael@0: ma_li(dest, Imm32(imm.value)); michael@0: } michael@0: void mov(ImmPtr imm, Register dest) { michael@0: mov(ImmWord(uintptr_t(imm.value)), dest); michael@0: } michael@0: void mov(Register src, Address dest) { michael@0: MOZ_ASSUME_UNREACHABLE("NYI-IC"); michael@0: } michael@0: void mov(Address src, Register dest) { michael@0: MOZ_ASSUME_UNREACHABLE("NYI-IC"); michael@0: } michael@0: michael@0: void call(const Register reg) { michael@0: as_jalr(reg); michael@0: as_nop(); michael@0: } michael@0: michael@0: void call(Label *label) { michael@0: // for now, assume that it'll be nearby? michael@0: ma_bal(label); michael@0: } michael@0: michael@0: void call(ImmWord imm) { michael@0: call(ImmPtr((void*)imm.value)); michael@0: } michael@0: void call(ImmPtr imm) { michael@0: BufferOffset bo = m_buffer.nextOffset(); michael@0: addPendingJump(bo, imm, Relocation::HARDCODED); michael@0: ma_call(imm); michael@0: } michael@0: void call(AsmJSImmPtr imm) { michael@0: movePtr(imm, CallReg); michael@0: call(CallReg); michael@0: } michael@0: void call(JitCode *c) { michael@0: BufferOffset bo = m_buffer.nextOffset(); michael@0: addPendingJump(bo, ImmPtr(c->raw()), Relocation::JITCODE); michael@0: ma_liPatchable(ScratchRegister, Imm32((uint32_t)c->raw())); michael@0: ma_callIonHalfPush(ScratchRegister); michael@0: } michael@0: void branch(JitCode *c) { michael@0: BufferOffset bo = m_buffer.nextOffset(); michael@0: addPendingJump(bo, ImmPtr(c->raw()), Relocation::JITCODE); michael@0: ma_liPatchable(ScratchRegister, Imm32((uint32_t)c->raw())); michael@0: as_jr(ScratchRegister); michael@0: as_nop(); michael@0: } michael@0: void branch(const Register reg) { michael@0: as_jr(reg); michael@0: as_nop(); michael@0: } michael@0: void nop() { michael@0: as_nop(); michael@0: } michael@0: void ret() { michael@0: ma_pop(ra); michael@0: as_jr(ra); michael@0: as_nop(); michael@0: } michael@0: void retn(Imm32 n) { michael@0: // pc <- [sp]; sp += n michael@0: ma_lw(ra, Address(StackPointer, 0)); michael@0: ma_addu(StackPointer, StackPointer, n); michael@0: as_jr(ra); michael@0: as_nop(); michael@0: } michael@0: void push(Imm32 imm) { michael@0: ma_li(ScratchRegister, imm); michael@0: ma_push(ScratchRegister); michael@0: } michael@0: void push(ImmWord imm) { michael@0: ma_li(ScratchRegister, Imm32(imm.value)); michael@0: ma_push(ScratchRegister); michael@0: } michael@0: void push(ImmGCPtr imm) { michael@0: ma_li(ScratchRegister, imm); michael@0: ma_push(ScratchRegister); michael@0: } michael@0: void push(const Address &address) { michael@0: ma_lw(ScratchRegister, address); michael@0: ma_push(ScratchRegister); michael@0: } michael@0: void push(const Register ®) { michael@0: ma_push(reg); michael@0: } michael@0: void push(const FloatRegister ®) { michael@0: ma_push(reg); michael@0: } michael@0: void pop(const Register ®) { michael@0: ma_pop(reg); michael@0: } michael@0: void pop(const FloatRegister ®) { michael@0: ma_pop(reg); michael@0: } michael@0: michael@0: // Emit a branch that can be toggled to a non-operation. On MIPS we use michael@0: // "andi" instruction to toggle the branch. michael@0: // See ToggleToJmp(), ToggleToCmp(). michael@0: CodeOffsetLabel toggledJump(Label *label); michael@0: michael@0: // Emit a "jalr" or "nop" instruction. ToggleCall can be used to patch michael@0: // this instruction. michael@0: CodeOffsetLabel toggledCall(JitCode *target, bool enabled); michael@0: michael@0: static size_t ToggledCallSize() { michael@0: // Four instructions used in: MacroAssemblerMIPSCompat::toggledCall michael@0: return 4 * sizeof(uint32_t); michael@0: } michael@0: michael@0: CodeOffsetLabel pushWithPatch(ImmWord imm) { michael@0: CodeOffsetLabel label = movWithPatch(imm, ScratchRegister); michael@0: ma_push(ScratchRegister); michael@0: return label; michael@0: } michael@0: michael@0: CodeOffsetLabel movWithPatch(ImmWord imm, Register dest) { michael@0: CodeOffsetLabel label = currentOffset(); michael@0: ma_liPatchable(dest, Imm32(imm.value)); michael@0: return label; michael@0: } michael@0: CodeOffsetLabel movWithPatch(ImmPtr imm, Register dest) { michael@0: return movWithPatch(ImmWord(uintptr_t(imm.value)), dest); michael@0: } michael@0: michael@0: void jump(Label *label) { michael@0: ma_b(label); michael@0: } michael@0: void jump(Register reg) { michael@0: as_jr(reg); michael@0: as_nop(); michael@0: } michael@0: void jump(const Address &address) { michael@0: ma_lw(ScratchRegister, address); michael@0: as_jr(ScratchRegister); michael@0: as_nop(); michael@0: } michael@0: michael@0: void neg32(Register reg) { michael@0: ma_negu(reg, reg); michael@0: } michael@0: void negl(Register reg) { michael@0: ma_negu(reg, reg); michael@0: } michael@0: michael@0: // Returns the register containing the type tag. michael@0: Register splitTagForTest(const ValueOperand &value) { michael@0: return value.typeReg(); michael@0: } michael@0: michael@0: void branchTestGCThing(Condition cond, const Address &address, Label *label); michael@0: void branchTestGCThing(Condition cond, const BaseIndex &src, Label *label); michael@0: michael@0: void branchTestPrimitive(Condition cond, const ValueOperand &value, Label *label); michael@0: void branchTestPrimitive(Condition cond, const Register &tag, Label *label); michael@0: michael@0: void branchTestValue(Condition cond, const ValueOperand &value, const Value &v, Label *label); michael@0: void branchTestValue(Condition cond, const Address &valaddr, const ValueOperand &value, michael@0: Label *label); michael@0: michael@0: // unboxing code michael@0: void unboxInt32(const ValueOperand &operand, const Register &dest); michael@0: void unboxInt32(const Address &src, const Register &dest); michael@0: void unboxBoolean(const ValueOperand &operand, const Register &dest); michael@0: void unboxBoolean(const Address &src, const Register &dest); michael@0: void unboxDouble(const ValueOperand &operand, const FloatRegister &dest); michael@0: void unboxDouble(const Address &src, const FloatRegister &dest); michael@0: void unboxString(const ValueOperand &operand, const Register &dest); michael@0: void unboxString(const Address &src, const Register &dest); michael@0: void unboxObject(const ValueOperand &src, const Register &dest); michael@0: void unboxValue(const ValueOperand &src, AnyRegister dest); michael@0: void unboxPrivate(const ValueOperand &src, Register dest); michael@0: michael@0: void notBoolean(const ValueOperand &val) { michael@0: as_xori(val.payloadReg(), val.payloadReg(), 1); michael@0: } michael@0: michael@0: // boxing code michael@0: void boxDouble(const FloatRegister &src, const ValueOperand &dest); michael@0: void boxNonDouble(JSValueType type, const Register &src, const ValueOperand &dest); michael@0: michael@0: // Extended unboxing API. If the payload is already in a register, returns michael@0: // that register. Otherwise, provides a move to the given scratch register, michael@0: // and returns that. michael@0: Register extractObject(const Address &address, Register scratch); michael@0: Register extractObject(const ValueOperand &value, Register scratch) { michael@0: return value.payloadReg(); michael@0: } michael@0: Register extractInt32(const ValueOperand &value, Register scratch) { michael@0: return value.payloadReg(); michael@0: } michael@0: Register extractBoolean(const ValueOperand &value, Register scratch) { michael@0: return value.payloadReg(); michael@0: } michael@0: Register extractTag(const Address &address, Register scratch); michael@0: Register extractTag(const BaseIndex &address, Register scratch); michael@0: Register extractTag(const ValueOperand &value, Register scratch) { michael@0: return value.typeReg(); michael@0: } michael@0: michael@0: void boolValueToDouble(const ValueOperand &operand, const FloatRegister &dest); michael@0: void int32ValueToDouble(const ValueOperand &operand, const FloatRegister &dest); michael@0: void loadInt32OrDouble(const Address &address, const FloatRegister &dest); michael@0: void loadInt32OrDouble(Register base, Register index, michael@0: const FloatRegister &dest, int32_t shift = defaultShift); michael@0: void loadConstantDouble(double dp, const FloatRegister &dest); michael@0: michael@0: void boolValueToFloat32(const ValueOperand &operand, const FloatRegister &dest); michael@0: void int32ValueToFloat32(const ValueOperand &operand, const FloatRegister &dest); michael@0: void loadConstantFloat32(float f, const FloatRegister &dest); michael@0: michael@0: void branchTestInt32(Condition cond, const ValueOperand &value, Label *label); michael@0: void branchTestInt32(Condition cond, const Register &tag, Label *label); michael@0: void branchTestInt32(Condition cond, const Address &address, Label *label); michael@0: void branchTestInt32(Condition cond, const BaseIndex &src, Label *label); michael@0: michael@0: void branchTestBoolean(Condition cond, const ValueOperand &value, Label *label); michael@0: void branchTestBoolean(Condition cond, const Register &tag, Label *label); michael@0: void branchTestBoolean(Condition cond, const BaseIndex &src, Label *label); michael@0: michael@0: void branch32(Condition cond, Register lhs, Register rhs, Label *label) { michael@0: ma_b(lhs, rhs, label, cond); michael@0: } michael@0: void branch32(Condition cond, Register lhs, Imm32 imm, Label *label) { michael@0: ma_b(lhs, imm, label, cond); michael@0: } michael@0: void branch32(Condition cond, const Operand &lhs, Register rhs, Label *label) { michael@0: if (lhs.getTag() == Operand::REG) { michael@0: ma_b(lhs.toReg(), rhs, label, cond); michael@0: } else { michael@0: branch32(cond, lhs.toAddress(), rhs, label); michael@0: } michael@0: } michael@0: void branch32(Condition cond, const Operand &lhs, Imm32 rhs, Label *label) { michael@0: if (lhs.getTag() == Operand::REG) { michael@0: ma_b(lhs.toReg(), rhs, label, cond); michael@0: } else { michael@0: branch32(cond, lhs.toAddress(), rhs, label); michael@0: } michael@0: } michael@0: void branch32(Condition cond, const Address &lhs, Register rhs, Label *label) { michael@0: ma_lw(ScratchRegister, lhs); michael@0: ma_b(ScratchRegister, rhs, label, cond); michael@0: } michael@0: void branch32(Condition cond, const Address &lhs, Imm32 rhs, Label *label) { michael@0: ma_lw(SecondScratchReg, lhs); michael@0: ma_b(SecondScratchReg, rhs, label, cond); michael@0: } michael@0: void branchPtr(Condition cond, const Address &lhs, Register rhs, Label *label) { michael@0: branch32(cond, lhs, rhs, label); michael@0: } michael@0: michael@0: void branchPrivatePtr(Condition cond, const Address &lhs, ImmPtr ptr, Label *label) { michael@0: branchPtr(cond, lhs, ptr, label); michael@0: } michael@0: michael@0: void branchPrivatePtr(Condition cond, const Address &lhs, Register ptr, Label *label) { michael@0: branchPtr(cond, lhs, ptr, label); michael@0: } michael@0: michael@0: void branchPrivatePtr(Condition cond, Register lhs, ImmWord ptr, Label *label) { michael@0: branchPtr(cond, lhs, ptr, label); michael@0: } michael@0: michael@0: void branchTestDouble(Condition cond, const ValueOperand &value, Label *label); michael@0: void branchTestDouble(Condition cond, const Register &tag, Label *label); michael@0: void branchTestDouble(Condition cond, const Address &address, Label *label); michael@0: void branchTestDouble(Condition cond, const BaseIndex &src, Label *label); michael@0: michael@0: void branchTestNull(Condition cond, const ValueOperand &value, Label *label); michael@0: void branchTestNull(Condition cond, const Register &tag, Label *label); michael@0: void branchTestNull(Condition cond, const BaseIndex &src, Label *label); michael@0: michael@0: void branchTestObject(Condition cond, const ValueOperand &value, Label *label); michael@0: void branchTestObject(Condition cond, const Register &tag, Label *label); michael@0: void branchTestObject(Condition cond, const BaseIndex &src, Label *label); michael@0: michael@0: void branchTestString(Condition cond, const ValueOperand &value, Label *label); michael@0: void branchTestString(Condition cond, const Register &tag, Label *label); michael@0: void branchTestString(Condition cond, const BaseIndex &src, Label *label); michael@0: michael@0: void branchTestUndefined(Condition cond, const ValueOperand &value, Label *label); michael@0: void branchTestUndefined(Condition cond, const Register &tag, Label *label); michael@0: void branchTestUndefined(Condition cond, const BaseIndex &src, Label *label); michael@0: void branchTestUndefined(Condition cond, const Address &address, Label *label); michael@0: michael@0: void branchTestNumber(Condition cond, const ValueOperand &value, Label *label); michael@0: void branchTestNumber(Condition cond, const Register &tag, Label *label); michael@0: michael@0: void branchTestMagic(Condition cond, const ValueOperand &value, Label *label); michael@0: void branchTestMagic(Condition cond, const Register &tag, Label *label); michael@0: void branchTestMagic(Condition cond, const Address &address, Label *label); michael@0: void branchTestMagic(Condition cond, const BaseIndex &src, Label *label); michael@0: michael@0: void branchTestMagicValue(Condition cond, const ValueOperand &val, JSWhyMagic why, michael@0: Label *label) { michael@0: MOZ_ASSERT(cond == Equal || cond == NotEqual); michael@0: // Test for magic michael@0: Label notmagic; michael@0: branchTestMagic(cond, val, ¬magic); michael@0: // Test magic value michael@0: branch32(cond, val.payloadReg(), Imm32(static_cast(why)), label); michael@0: bind(¬magic); michael@0: } michael@0: michael@0: void branchTestInt32Truthy(bool b, const ValueOperand &value, Label *label); michael@0: michael@0: void branchTestStringTruthy(bool b, const ValueOperand &value, Label *label); michael@0: michael@0: void branchTestDoubleTruthy(bool b, const FloatRegister &value, Label *label); michael@0: michael@0: void branchTestBooleanTruthy(bool b, const ValueOperand &operand, Label *label); michael@0: michael@0: void branchTest32(Condition cond, const Register &lhs, const Register &rhs, Label *label) { michael@0: MOZ_ASSERT(cond == Zero || cond == NonZero || cond == Signed || cond == NotSigned); michael@0: if (lhs == rhs) { michael@0: ma_b(lhs, rhs, label, cond); michael@0: } else { michael@0: as_and(ScratchRegister, lhs, rhs); michael@0: ma_b(ScratchRegister, ScratchRegister, label, cond); michael@0: } michael@0: } michael@0: void branchTest32(Condition cond, const Register &lhs, Imm32 imm, Label *label) { michael@0: ma_li(ScratchRegister, imm); michael@0: branchTest32(cond, lhs, ScratchRegister, label); michael@0: } michael@0: void branchTest32(Condition cond, const Address &address, Imm32 imm, Label *label) { michael@0: ma_lw(SecondScratchReg, address); michael@0: branchTest32(cond, SecondScratchReg, imm, label); michael@0: } michael@0: void branchTestPtr(Condition cond, const Register &lhs, const Register &rhs, Label *label) { michael@0: branchTest32(cond, lhs, rhs, label); michael@0: } michael@0: void branchTestPtr(Condition cond, const Register &lhs, const Imm32 rhs, Label *label) { michael@0: branchTest32(cond, lhs, rhs, label); michael@0: } michael@0: void branchTestPtr(Condition cond, const Address &lhs, Imm32 imm, Label *label) { michael@0: branchTest32(cond, lhs, imm, label); michael@0: } michael@0: void branchPtr(Condition cond, Register lhs, Register rhs, Label *label) { michael@0: ma_b(lhs, rhs, label, cond); michael@0: } michael@0: void branchPtr(Condition cond, Register lhs, ImmGCPtr ptr, Label *label) { michael@0: ma_li(ScratchRegister, ptr); michael@0: ma_b(lhs, ScratchRegister, label, cond); michael@0: } michael@0: void branchPtr(Condition cond, Register lhs, ImmWord imm, Label *label) { michael@0: ma_b(lhs, Imm32(imm.value), label, cond); michael@0: } michael@0: void branchPtr(Condition cond, Register lhs, ImmPtr imm, Label *label) { michael@0: branchPtr(cond, lhs, ImmWord(uintptr_t(imm.value)), label); michael@0: } michael@0: void branchPtr(Condition cond, Register lhs, AsmJSImmPtr imm, Label *label) { michael@0: movePtr(imm, ScratchRegister); michael@0: branchPtr(cond, lhs, ScratchRegister, label); michael@0: } michael@0: void branchPtr(Condition cond, Register lhs, Imm32 imm, Label *label) { michael@0: ma_b(lhs, imm, label, cond); michael@0: } michael@0: void decBranchPtr(Condition cond, const Register &lhs, Imm32 imm, Label *label) { michael@0: subPtr(imm, lhs); michael@0: branch32(cond, lhs, Imm32(0), label); michael@0: } michael@0: michael@0: protected: michael@0: uint32_t getType(const Value &val); michael@0: void moveData(const Value &val, Register data); michael@0: public: michael@0: void moveValue(const Value &val, Register type, Register data); michael@0: michael@0: CodeOffsetJump jumpWithPatch(RepatchLabel *label); michael@0: michael@0: template michael@0: CodeOffsetJump branchPtrWithPatch(Condition cond, Register reg, T ptr, RepatchLabel *label) { michael@0: movePtr(ptr, ScratchRegister); michael@0: Label skipJump; michael@0: ma_b(reg, ScratchRegister, &skipJump, InvertCondition(cond), ShortJump); michael@0: CodeOffsetJump off = jumpWithPatch(label); michael@0: bind(&skipJump); michael@0: return off; michael@0: } michael@0: michael@0: template michael@0: CodeOffsetJump branchPtrWithPatch(Condition cond, Address addr, T ptr, RepatchLabel *label) { michael@0: loadPtr(addr, SecondScratchReg); michael@0: movePtr(ptr, ScratchRegister); michael@0: Label skipJump; michael@0: ma_b(SecondScratchReg, ScratchRegister, &skipJump, InvertCondition(cond), ShortJump); michael@0: CodeOffsetJump off = jumpWithPatch(label); michael@0: bind(&skipJump); michael@0: return off; michael@0: } michael@0: void branchPtr(Condition cond, Address addr, ImmGCPtr ptr, Label *label) { michael@0: ma_lw(SecondScratchReg, addr); michael@0: ma_li(ScratchRegister, ptr); michael@0: ma_b(SecondScratchReg, ScratchRegister, label, cond); michael@0: } michael@0: void branchPtr(Condition cond, Address addr, ImmWord ptr, Label *label) { michael@0: ma_lw(SecondScratchReg, addr); michael@0: ma_b(SecondScratchReg, Imm32(ptr.value), label, cond); michael@0: } michael@0: void branchPtr(Condition cond, Address addr, ImmPtr ptr, Label *label) { michael@0: branchPtr(cond, addr, ImmWord(uintptr_t(ptr.value)), label); michael@0: } michael@0: void branchPtr(Condition cond, const AbsoluteAddress &addr, const Register &ptr, Label *label) { michael@0: loadPtr(addr, ScratchRegister); michael@0: ma_b(ScratchRegister, ptr, label, cond); michael@0: } michael@0: void branchPtr(Condition cond, const AsmJSAbsoluteAddress &addr, const Register &ptr, michael@0: Label *label) { michael@0: loadPtr(addr, ScratchRegister); michael@0: ma_b(ScratchRegister, ptr, label, cond); michael@0: } michael@0: void branch32(Condition cond, const AbsoluteAddress &lhs, Imm32 rhs, Label *label) { michael@0: loadPtr(lhs, SecondScratchReg); // ma_b might use scratch michael@0: ma_b(SecondScratchReg, rhs, label, cond); michael@0: } michael@0: void branch32(Condition cond, const AbsoluteAddress &lhs, const Register &rhs, Label *label) { michael@0: loadPtr(lhs, ScratchRegister); michael@0: ma_b(ScratchRegister, rhs, label, cond); michael@0: } michael@0: michael@0: void loadUnboxedValue(Address address, MIRType type, AnyRegister dest) { michael@0: if (dest.isFloat()) michael@0: loadInt32OrDouble(address, dest.fpu()); michael@0: else michael@0: ma_lw(dest.gpr(), address); michael@0: } michael@0: michael@0: void loadUnboxedValue(BaseIndex address, MIRType type, AnyRegister dest) { michael@0: if (dest.isFloat()) michael@0: loadInt32OrDouble(address.base, address.index, dest.fpu(), address.scale); michael@0: else michael@0: load32(address, dest.gpr()); michael@0: } michael@0: michael@0: void moveValue(const Value &val, const ValueOperand &dest); michael@0: michael@0: void moveValue(const ValueOperand &src, const ValueOperand &dest) { michael@0: MOZ_ASSERT(src.typeReg() != dest.payloadReg()); michael@0: MOZ_ASSERT(src.payloadReg() != dest.typeReg()); michael@0: if (src.typeReg() != dest.typeReg()) michael@0: ma_move(dest.typeReg(), src.typeReg()); michael@0: if (src.payloadReg() != dest.payloadReg()) michael@0: ma_move(dest.payloadReg(), src.payloadReg()); michael@0: } michael@0: michael@0: void storeValue(ValueOperand val, Operand dst); michael@0: void storeValue(ValueOperand val, const BaseIndex &dest); michael@0: void storeValue(JSValueType type, Register reg, BaseIndex dest); michael@0: void storeValue(ValueOperand val, const Address &dest); michael@0: void storeValue(JSValueType type, Register reg, Address dest); michael@0: void storeValue(const Value &val, Address dest); michael@0: void storeValue(const Value &val, BaseIndex dest); michael@0: michael@0: void loadValue(Address src, ValueOperand val); michael@0: void loadValue(Operand dest, ValueOperand val) { michael@0: loadValue(dest.toAddress(), val); michael@0: } michael@0: void loadValue(const BaseIndex &addr, ValueOperand val); michael@0: void tagValue(JSValueType type, Register payload, ValueOperand dest); michael@0: michael@0: void pushValue(ValueOperand val); michael@0: void popValue(ValueOperand val); michael@0: void pushValue(const Value &val) { michael@0: jsval_layout jv = JSVAL_TO_IMPL(val); michael@0: push(Imm32(jv.s.tag)); michael@0: if (val.isMarkable()) michael@0: push(ImmGCPtr(reinterpret_cast(val.toGCThing()))); michael@0: else michael@0: push(Imm32(jv.s.payload.i32)); michael@0: } michael@0: void pushValue(JSValueType type, Register reg) { michael@0: push(ImmTag(JSVAL_TYPE_TO_TAG(type))); michael@0: ma_push(reg); michael@0: } michael@0: void pushValue(const Address &addr); michael@0: void Push(const ValueOperand &val) { michael@0: pushValue(val); michael@0: framePushed_ += sizeof(Value); michael@0: } michael@0: void Pop(const ValueOperand &val) { michael@0: popValue(val); michael@0: framePushed_ -= sizeof(Value); michael@0: } michael@0: void storePayload(const Value &val, Address dest); michael@0: void storePayload(Register src, Address dest); michael@0: void storePayload(const Value &val, Register base, Register index, int32_t shift = defaultShift); michael@0: void storePayload(Register src, Register base, Register index, int32_t shift = defaultShift); michael@0: void storeTypeTag(ImmTag tag, Address dest); michael@0: void storeTypeTag(ImmTag tag, Register base, Register index, int32_t shift = defaultShift); michael@0: michael@0: void makeFrameDescriptor(Register frameSizeReg, FrameType type) { michael@0: ma_sll(frameSizeReg, frameSizeReg, Imm32(FRAMESIZE_SHIFT)); michael@0: ma_or(frameSizeReg, frameSizeReg, Imm32(type)); michael@0: } michael@0: michael@0: void linkExitFrame(); michael@0: void linkParallelExitFrame(const Register &pt); michael@0: void handleFailureWithHandler(void *handler); michael@0: void handleFailureWithHandlerTail(); michael@0: michael@0: ///////////////////////////////////////////////////////////////// michael@0: // Common interface. michael@0: ///////////////////////////////////////////////////////////////// michael@0: public: michael@0: // The following functions are exposed for use in platform-shared code. michael@0: void Push(const Register ®) { michael@0: ma_push(reg); michael@0: adjustFrame(sizeof(intptr_t)); michael@0: } michael@0: void Push(const Imm32 imm) { michael@0: ma_li(ScratchRegister, imm); michael@0: ma_push(ScratchRegister); michael@0: adjustFrame(sizeof(intptr_t)); michael@0: } michael@0: void Push(const ImmWord imm) { michael@0: ma_li(ScratchRegister, Imm32(imm.value)); michael@0: ma_push(ScratchRegister); michael@0: adjustFrame(sizeof(intptr_t)); michael@0: } michael@0: void Push(const ImmPtr imm) { michael@0: Push(ImmWord(uintptr_t(imm.value))); michael@0: } michael@0: void Push(const ImmGCPtr ptr) { michael@0: ma_li(ScratchRegister, ptr); michael@0: ma_push(ScratchRegister); michael@0: adjustFrame(sizeof(intptr_t)); michael@0: } michael@0: void Push(const FloatRegister &f) { michael@0: ma_push(f); michael@0: adjustFrame(sizeof(double)); michael@0: } michael@0: michael@0: CodeOffsetLabel PushWithPatch(const ImmWord &word) { michael@0: framePushed_ += sizeof(word.value); michael@0: return pushWithPatch(word); michael@0: } michael@0: CodeOffsetLabel PushWithPatch(const ImmPtr &imm) { michael@0: return PushWithPatch(ImmWord(uintptr_t(imm.value))); michael@0: } michael@0: michael@0: void Pop(const Register ®) { michael@0: ma_pop(reg); michael@0: adjustFrame(-sizeof(intptr_t)); michael@0: } michael@0: void implicitPop(uint32_t args) { michael@0: MOZ_ASSERT(args % sizeof(intptr_t) == 0); michael@0: adjustFrame(-args); michael@0: } michael@0: uint32_t framePushed() const { michael@0: return framePushed_; michael@0: } michael@0: void setFramePushed(uint32_t framePushed) { michael@0: framePushed_ = framePushed; michael@0: } michael@0: michael@0: // Builds an exit frame on the stack, with a return address to an internal michael@0: // non-function. Returns offset to be passed to markSafepointAt(). michael@0: bool buildFakeExitFrame(const Register &scratch, uint32_t *offset); michael@0: michael@0: void callWithExitFrame(JitCode *target); michael@0: void callWithExitFrame(JitCode *target, Register dynStack); michael@0: michael@0: // Makes an Ion call using the only two methods that it is sane for michael@0: // indep code to make a call michael@0: void callIon(const Register &callee); michael@0: michael@0: void reserveStack(uint32_t amount); michael@0: void freeStack(uint32_t amount); michael@0: void freeStack(Register amount); michael@0: michael@0: void add32(Register src, Register dest); michael@0: void add32(Imm32 imm, Register dest); michael@0: void add32(Imm32 imm, const Address &dest); michael@0: void sub32(Imm32 imm, Register dest); michael@0: void sub32(Register src, Register dest); michael@0: michael@0: void and32(Imm32 imm, Register dest); michael@0: void and32(Imm32 imm, const Address &dest); michael@0: void or32(Imm32 imm, const Address &dest); michael@0: void xor32(Imm32 imm, Register dest); michael@0: void xorPtr(Imm32 imm, Register dest); michael@0: void xorPtr(Register src, Register dest); michael@0: void orPtr(Imm32 imm, Register dest); michael@0: void orPtr(Register src, Register dest); michael@0: void andPtr(Imm32 imm, Register dest); michael@0: void andPtr(Register src, Register dest); michael@0: void addPtr(Register src, Register dest); michael@0: void subPtr(Register src, Register dest); michael@0: void addPtr(const Address &src, Register dest); michael@0: void not32(Register reg); michael@0: michael@0: void move32(const Imm32 &imm, const Register &dest); michael@0: void move32(const Register &src, const Register &dest); michael@0: michael@0: void movePtr(const Register &src, const Register &dest); michael@0: void movePtr(const ImmWord &imm, const Register &dest); michael@0: void movePtr(const ImmPtr &imm, const Register &dest); michael@0: void movePtr(const AsmJSImmPtr &imm, const Register &dest); michael@0: void movePtr(const ImmGCPtr &imm, const Register &dest); michael@0: michael@0: void load8SignExtend(const Address &address, const Register &dest); michael@0: void load8SignExtend(const BaseIndex &src, const Register &dest); michael@0: michael@0: void load8ZeroExtend(const Address &address, const Register &dest); michael@0: void load8ZeroExtend(const BaseIndex &src, const Register &dest); michael@0: michael@0: void load16SignExtend(const Address &address, const Register &dest); michael@0: void load16SignExtend(const BaseIndex &src, const Register &dest); michael@0: michael@0: void load16ZeroExtend(const Address &address, const Register &dest); michael@0: void load16ZeroExtend(const BaseIndex &src, const Register &dest); michael@0: michael@0: void load32(const Address &address, const Register &dest); michael@0: void load32(const BaseIndex &address, const Register &dest); michael@0: void load32(const AbsoluteAddress &address, const Register &dest); michael@0: michael@0: void loadPtr(const Address &address, const Register &dest); michael@0: void loadPtr(const BaseIndex &src, const Register &dest); michael@0: void loadPtr(const AbsoluteAddress &address, const Register &dest); michael@0: void loadPtr(const AsmJSAbsoluteAddress &address, const Register &dest); michael@0: michael@0: void loadPrivate(const Address &address, const Register &dest); michael@0: michael@0: void loadDouble(const Address &addr, const FloatRegister &dest); michael@0: void loadDouble(const BaseIndex &src, const FloatRegister &dest); michael@0: michael@0: // Load a float value into a register, then expand it to a double. michael@0: void loadFloatAsDouble(const Address &addr, const FloatRegister &dest); michael@0: void loadFloatAsDouble(const BaseIndex &src, const FloatRegister &dest); michael@0: michael@0: void loadFloat32(const Address &addr, const FloatRegister &dest); michael@0: void loadFloat32(const BaseIndex &src, const FloatRegister &dest); michael@0: michael@0: void store8(const Register &src, const Address &address); michael@0: void store8(const Imm32 &imm, const Address &address); michael@0: void store8(const Register &src, const BaseIndex &address); michael@0: void store8(const Imm32 &imm, const BaseIndex &address); michael@0: michael@0: void store16(const Register &src, const Address &address); michael@0: void store16(const Imm32 &imm, const Address &address); michael@0: void store16(const Register &src, const BaseIndex &address); michael@0: void store16(const Imm32 &imm, const BaseIndex &address); michael@0: michael@0: void store32(const Register &src, const AbsoluteAddress &address); michael@0: void store32(const Register &src, const Address &address); michael@0: void store32(const Register &src, const BaseIndex &address); michael@0: void store32(const Imm32 &src, const Address &address); michael@0: void store32(const Imm32 &src, const BaseIndex &address); michael@0: michael@0: void storePtr(ImmWord imm, const Address &address); michael@0: void storePtr(ImmPtr imm, const Address &address); michael@0: void storePtr(ImmGCPtr imm, const Address &address); michael@0: void storePtr(Register src, const Address &address); michael@0: void storePtr(const Register &src, const AbsoluteAddress &dest); michael@0: void storeDouble(FloatRegister src, Address addr) { michael@0: ma_sd(src, addr); michael@0: } michael@0: void storeDouble(FloatRegister src, BaseIndex addr) { michael@0: MOZ_ASSERT(addr.offset == 0); michael@0: ma_sd(src, addr); michael@0: } michael@0: void moveDouble(FloatRegister src, FloatRegister dest) { michael@0: as_movd(dest, src); michael@0: } michael@0: michael@0: void storeFloat32(FloatRegister src, Address addr) { michael@0: ma_ss(src, addr); michael@0: } michael@0: void storeFloat32(FloatRegister src, BaseIndex addr) { michael@0: MOZ_ASSERT(addr.offset == 0); michael@0: ma_ss(src, addr); michael@0: } michael@0: michael@0: void zeroDouble(FloatRegister reg) { michael@0: moveToDoubleLo(zero, reg); michael@0: moveToDoubleHi(zero, reg); michael@0: } michael@0: michael@0: void clampIntToUint8(Register reg) { michael@0: // look at (reg >> 8) if it is 0, then src shouldn't be clamped michael@0: // if it is <0, then we want to clamp to 0, michael@0: // otherwise, we wish to clamp to 255 michael@0: Label done; michael@0: ma_move(ScratchRegister, reg); michael@0: as_sra(ScratchRegister, ScratchRegister, 8); michael@0: ma_b(ScratchRegister, ScratchRegister, &done, Assembler::Zero, ShortJump); michael@0: { michael@0: Label negative; michael@0: ma_b(ScratchRegister, ScratchRegister, &negative, Assembler::Signed, ShortJump); michael@0: { michael@0: ma_li(reg, Imm32(255)); michael@0: ma_b(&done, ShortJump); michael@0: } michael@0: bind(&negative); michael@0: { michael@0: ma_move(reg, zero); michael@0: } michael@0: } michael@0: bind(&done); michael@0: } michael@0: michael@0: void subPtr(Imm32 imm, const Register dest); michael@0: void addPtr(Imm32 imm, const Register dest); michael@0: void addPtr(Imm32 imm, const Address &dest); michael@0: void addPtr(ImmWord imm, const Register dest) { michael@0: addPtr(Imm32(imm.value), dest); michael@0: } michael@0: void addPtr(ImmPtr imm, const Register dest) { michael@0: addPtr(ImmWord(uintptr_t(imm.value)), dest); michael@0: } michael@0: michael@0: void breakpoint(); michael@0: michael@0: void branchDouble(DoubleCondition cond, const FloatRegister &lhs, const FloatRegister &rhs, michael@0: Label *label); michael@0: michael@0: void branchFloat(DoubleCondition cond, const FloatRegister &lhs, const FloatRegister &rhs, michael@0: Label *label); michael@0: michael@0: void checkStackAlignment(); michael@0: michael@0: void alignPointerUp(Register src, Register dest, uint32_t alignment); michael@0: michael@0: void rshiftPtr(Imm32 imm, Register dest) { michael@0: ma_srl(dest, dest, imm); michael@0: } michael@0: void lshiftPtr(Imm32 imm, Register dest) { michael@0: ma_sll(dest, dest, imm); michael@0: } michael@0: michael@0: // If source is a double, load it into dest. If source is int32, michael@0: // convert it to double. Else, branch to failure. michael@0: void ensureDouble(const ValueOperand &source, FloatRegister dest, Label *failure); michael@0: michael@0: // Setup a call to C/C++ code, given the number of general arguments it michael@0: // takes. Note that this only supports cdecl. michael@0: // michael@0: // In order for alignment to work correctly, the MacroAssembler must have a michael@0: // consistent view of the stack displacement. It is okay to call "push" michael@0: // manually, however, if the stack alignment were to change, the macro michael@0: // assembler should be notified before starting a call. michael@0: void setupAlignedABICall(uint32_t args); michael@0: michael@0: // Sets up an ABI call for when the alignment is not known. This may need a michael@0: // scratch register. michael@0: void setupUnalignedABICall(uint32_t args, const Register &scratch); michael@0: michael@0: // Arguments must be assigned in a left-to-right order. This process may michael@0: // temporarily use more stack, in which case sp-relative addresses will be michael@0: // automatically adjusted. It is extremely important that sp-relative michael@0: // addresses are computed *after* setupABICall(). Furthermore, no michael@0: // operations should be emitted while setting arguments. michael@0: void passABIArg(const MoveOperand &from, MoveOp::Type type); michael@0: void passABIArg(const Register ®); michael@0: void passABIArg(const FloatRegister ®, MoveOp::Type type); michael@0: void passABIArg(const ValueOperand ®s); michael@0: michael@0: protected: michael@0: bool buildOOLFakeExitFrame(void *fakeReturnAddr); michael@0: michael@0: private: michael@0: void callWithABIPre(uint32_t *stackAdjust); michael@0: void callWithABIPost(uint32_t stackAdjust, MoveOp::Type result); michael@0: michael@0: public: michael@0: // Emits a call to a C/C++ function, resolving all argument moves. michael@0: void callWithABI(void *fun, MoveOp::Type result = MoveOp::GENERAL); michael@0: void callWithABI(AsmJSImmPtr imm, MoveOp::Type result = MoveOp::GENERAL); michael@0: void callWithABI(const Address &fun, MoveOp::Type result = MoveOp::GENERAL); michael@0: michael@0: CodeOffsetLabel labelForPatch() { michael@0: return CodeOffsetLabel(nextOffset().getOffset()); michael@0: } michael@0: michael@0: void memIntToValue(Address Source, Address Dest) { michael@0: MOZ_ASSUME_UNREACHABLE("NYI"); michael@0: } michael@0: michael@0: void lea(Operand addr, Register dest) { michael@0: MOZ_ASSUME_UNREACHABLE("NYI"); michael@0: } michael@0: michael@0: void abiret() { michael@0: MOZ_ASSUME_UNREACHABLE("NYI"); michael@0: } michael@0: michael@0: void ma_storeImm(Imm32 imm, const Address &addr) { michael@0: ma_sw(imm, addr); michael@0: } michael@0: michael@0: BufferOffset ma_BoundsCheck(Register bounded) { michael@0: BufferOffset bo = m_buffer.nextOffset(); michael@0: ma_liPatchable(bounded, Imm32(0)); michael@0: return bo; michael@0: } michael@0: michael@0: void moveFloat32(FloatRegister src, FloatRegister dest) { michael@0: as_movs(dest, src); michael@0: } michael@0: michael@0: void branchPtrInNurseryRange(Register ptr, Register temp, Label *label); michael@0: }; michael@0: michael@0: typedef MacroAssemblerMIPSCompat MacroAssemblerSpecific; michael@0: michael@0: } // namespace jit michael@0: } // namespace js michael@0: michael@0: #endif /* jit_mips_MacroAssembler_mips_h */