X-Git-Url: https://git.saurik.com/apple/javascriptcore.git/blobdiff_plain/f9bf01c6616d5ddcf65b13b33cedf9e387ff7a63..14957cd040308e3eeec43d26bae5d76da13fcd85:/assembler/MacroAssemblerARM.h diff --git a/assembler/MacroAssemblerARM.h b/assembler/MacroAssemblerARM.h index 21b8de8..b365dce 100644 --- a/assembler/MacroAssemblerARM.h +++ b/assembler/MacroAssemblerARM.h @@ -1,6 +1,6 @@ /* * Copyright (C) 2008 Apple Inc. - * Copyright (C) 2009 University of Szeged + * Copyright (C) 2009, 2010 University of Szeged * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -28,8 +28,6 @@ #ifndef MacroAssemblerARM_h #define MacroAssemblerARM_h -#include - #if ENABLE(ASSEMBLER) && CPU(ARM_TRADITIONAL) #include "ARMAssembler.h" @@ -42,7 +40,10 @@ class MacroAssemblerARM : public AbstractMacroAssembler { static const int DoubleConditionBitSpecial = 0x10; COMPILE_ASSERT(!(DoubleConditionBitSpecial & DoubleConditionMask), DoubleConditionBitSpecial_should_not_interfere_with_ARMAssembler_Condition_codes); public: - enum Condition { + typedef ARMRegisters::FPRegisterID FPRegisterID; + static const int MaximumCompactPtrAlignedAddressOffset = 0x7FFFFFFF; + + enum RelationalCondition { Equal = ARMAssembler::EQ, NotEqual = ARMAssembler::NE, Above = ARMAssembler::HI, @@ -52,7 +53,10 @@ public: GreaterThan = ARMAssembler::GT, GreaterThanOrEqual = ARMAssembler::GE, LessThan = ARMAssembler::LT, - LessThanOrEqual = ARMAssembler::LE, + LessThanOrEqual = ARMAssembler::LE + }; + + enum ResultCondition { Overflow = ARMAssembler::VS, Signed = ARMAssembler::MI, Zero = ARMAssembler::EQ, @@ -86,14 +90,14 @@ public: m_assembler.adds_r(dest, dest, src); } - void add32(Imm32 imm, Address address) + void add32(TrustedImm32 imm, Address address) { load32(address, ARMRegisters::S1); add32(imm, ARMRegisters::S1); store32(ARMRegisters::S1, address); } - void add32(Imm32 imm, RegisterID dest) + void add32(TrustedImm32 imm, RegisterID dest) { m_assembler.adds_r(dest, dest, m_assembler.getImm(imm.m_value, ARMRegisters::S0)); } @@ -109,7 +113,7 @@ public: m_assembler.ands_r(dest, dest, src); } - void and32(Imm32 imm, RegisterID dest) + void and32(TrustedImm32 imm, RegisterID dest) { ARMWord w = m_assembler.getImm(imm.m_value, ARMRegisters::S0, true); if (w & ARMAssembler::OP2_INV_IMM) @@ -127,7 +131,7 @@ public: m_assembler.movs_r(dest, m_assembler.lsl_r(dest, ARMRegisters::S0)); } - void lshift32(Imm32 imm, RegisterID dest) + void lshift32(TrustedImm32 imm, RegisterID dest) { m_assembler.movs_r(dest, m_assembler.lsl(dest, imm.m_value & 0x1f)); } @@ -141,7 +145,7 @@ public: m_assembler.muls_r(dest, dest, src); } - void mul32(Imm32 imm, RegisterID src, RegisterID dest) + void mul32(TrustedImm32 imm, RegisterID src, RegisterID dest) { move(imm, ARMRegisters::S0); m_assembler.muls_r(dest, src, ARMRegisters::S0); @@ -162,7 +166,7 @@ public: m_assembler.orrs_r(dest, dest, src); } - void or32(Imm32 imm, RegisterID dest) + void or32(TrustedImm32 imm, RegisterID dest) { m_assembler.orrs_r(dest, dest, m_assembler.getImm(imm.m_value, ARMRegisters::S0)); } @@ -176,22 +180,36 @@ public: m_assembler.movs_r(dest, m_assembler.asr_r(dest, ARMRegisters::S0)); } - void rshift32(Imm32 imm, RegisterID dest) + void rshift32(TrustedImm32 imm, RegisterID dest) { m_assembler.movs_r(dest, m_assembler.asr(dest, imm.m_value & 0x1f)); } + + void urshift32(RegisterID shift_amount, RegisterID dest) + { + ARMWord w = ARMAssembler::getOp2(0x1f); + ASSERT(w != ARMAssembler::INVALID_IMM); + m_assembler.and_r(ARMRegisters::S0, shift_amount, w); + + m_assembler.movs_r(dest, m_assembler.lsr_r(dest, ARMRegisters::S0)); + } + + void urshift32(TrustedImm32 imm, RegisterID dest) + { + m_assembler.movs_r(dest, m_assembler.lsr(dest, imm.m_value & 0x1f)); + } void sub32(RegisterID src, RegisterID dest) { m_assembler.subs_r(dest, dest, src); } - void sub32(Imm32 imm, RegisterID dest) + void sub32(TrustedImm32 imm, RegisterID dest) { m_assembler.subs_r(dest, dest, m_assembler.getImm(imm.m_value, ARMRegisters::S0)); } - void sub32(Imm32 imm, Address address) + void sub32(TrustedImm32 imm, Address address) { load32(address, ARMRegisters::S1); sub32(imm, ARMRegisters::S1); @@ -209,11 +227,27 @@ public: m_assembler.eors_r(dest, dest, src); } - void xor32(Imm32 imm, RegisterID dest) + void xor32(TrustedImm32 imm, RegisterID dest) { m_assembler.eors_r(dest, dest, m_assembler.getImm(imm.m_value, ARMRegisters::S0)); } + void countLeadingZeros32(RegisterID src, RegisterID dest) + { +#if WTF_ARM_ARCH_AT_LEAST(5) + m_assembler.clz_r(dest, src); +#else + UNUSED_PARAM(src); + UNUSED_PARAM(dest); + ASSERT_NOT_REACHED(); +#endif + } + + void load8(ImplicitAddress address, RegisterID dest) + { + m_assembler.dataTransfer32(true, dest, address.base, address.offset, true); + } + void load32(ImplicitAddress address, RegisterID dest) { m_assembler.dataTransfer32(true, dest, address.base, address.offset); @@ -240,21 +274,26 @@ public: m_assembler.dtr_ur(true, dest, address.base, ARMRegisters::S0); return dataLabel; } - - Label loadPtrWithPatchToLEA(Address address, RegisterID dest) + + DataLabelCompact load32WithCompactAddressOffsetPatch(Address address, RegisterID dest) { - Label label(this); - load32(address, dest); - return label; + DataLabelCompact dataLabel(this); + load32WithAddressOffsetPatch(address, dest); + return dataLabel; } void load16(BaseIndex address, RegisterID dest) { - m_assembler.add_r(ARMRegisters::S0, address.base, m_assembler.lsl(address.index, address.scale)); - if (address.offset>=0) - m_assembler.ldrh_u(dest, ARMRegisters::S0, ARMAssembler::getOp2Byte(address.offset)); + m_assembler.add_r(ARMRegisters::S1, address.base, m_assembler.lsl(address.index, address.scale)); + load16(Address(ARMRegisters::S1, address.offset), dest); + } + + void load16(ImplicitAddress address, RegisterID dest) + { + if (address.offset >= 0) + m_assembler.ldrh_u(dest, address.base, m_assembler.getOffsetForHalfwordDataTransfer(address.offset, ARMRegisters::S0)); else - m_assembler.ldrh_d(dest, ARMRegisters::S0, ARMAssembler::getOp2Byte(-address.offset)); + m_assembler.ldrh_d(dest, address.base, m_assembler.getOffsetForHalfwordDataTransfer(-address.offset, ARMRegisters::S0)); } DataLabel32 store32WithAddressOffsetPatch(RegisterID src, Address address) @@ -275,7 +314,7 @@ public: m_assembler.baseIndexTransfer32(false, src, address.base, address.index, static_cast(address.scale), address.offset); } - void store32(Imm32 imm, ImplicitAddress address) + void store32(TrustedImm32 imm, ImplicitAddress address) { if (imm.m_isPointer) m_assembler.ldr_un_imm(ARMRegisters::S1, imm.m_value); @@ -290,7 +329,7 @@ public: m_assembler.dtr_u(false, src, ARMRegisters::S0, 0); } - void store32(Imm32 imm, void* address) + void store32(TrustedImm32 imm, void* address) { m_assembler.ldr_un_imm(ARMRegisters::S0, reinterpret_cast(address)); if (imm.m_isPointer) @@ -316,13 +355,13 @@ public: push(ARMRegisters::S1); } - void push(Imm32 imm) + void push(TrustedImm32 imm) { move(imm, ARMRegisters::S0); push(ARMRegisters::S0); } - void move(Imm32 imm, RegisterID dest) + void move(TrustedImm32 imm, RegisterID dest) { if (imm.m_isPointer) m_assembler.ldr_un_imm(dest, imm.m_value); @@ -335,9 +374,9 @@ public: m_assembler.mov_r(dest, src); } - void move(ImmPtr imm, RegisterID dest) + void move(TrustedImmPtr imm, RegisterID dest) { - move(Imm32(imm), dest); + move(TrustedImm32(imm), dest); } void swap(RegisterID reg1, RegisterID reg2) @@ -359,53 +398,64 @@ public: move(src, dest); } - Jump branch32(Condition cond, RegisterID left, RegisterID right, int useConstantPool = 0) + Jump branch8(RelationalCondition cond, Address left, TrustedImm32 right) + { + load8(left, ARMRegisters::S1); + return branch32(cond, ARMRegisters::S1, right); + } + + Jump branch32(RelationalCondition cond, RegisterID left, RegisterID right, int useConstantPool = 0) { m_assembler.cmp_r(left, right); return Jump(m_assembler.jmp(ARMCondition(cond), useConstantPool)); } - Jump branch32(Condition cond, RegisterID left, Imm32 right, int useConstantPool = 0) + Jump branch32(RelationalCondition cond, RegisterID left, TrustedImm32 right, int useConstantPool = 0) { if (right.m_isPointer) { m_assembler.ldr_un_imm(ARMRegisters::S0, right.m_value); m_assembler.cmp_r(left, ARMRegisters::S0); - } else - m_assembler.cmp_r(left, m_assembler.getImm(right.m_value, ARMRegisters::S0)); + } else { + ARMWord tmp = m_assembler.getOp2(-right.m_value); + if (tmp != ARMAssembler::INVALID_IMM) + m_assembler.cmn_r(left, tmp); + else + m_assembler.cmp_r(left, m_assembler.getImm(right.m_value, ARMRegisters::S0)); + } return Jump(m_assembler.jmp(ARMCondition(cond), useConstantPool)); } - Jump branch32(Condition cond, RegisterID left, Address right) + Jump branch32(RelationalCondition cond, RegisterID left, Address right) { load32(right, ARMRegisters::S1); return branch32(cond, left, ARMRegisters::S1); } - Jump branch32(Condition cond, Address left, RegisterID right) + Jump branch32(RelationalCondition cond, Address left, RegisterID right) { load32(left, ARMRegisters::S1); return branch32(cond, ARMRegisters::S1, right); } - Jump branch32(Condition cond, Address left, Imm32 right) + Jump branch32(RelationalCondition cond, Address left, TrustedImm32 right) { load32(left, ARMRegisters::S1); return branch32(cond, ARMRegisters::S1, right); } - Jump branch32(Condition cond, BaseIndex left, Imm32 right) + Jump branch32(RelationalCondition cond, BaseIndex left, TrustedImm32 right) { load32(left, ARMRegisters::S1); return branch32(cond, ARMRegisters::S1, right); } - Jump branch32WithUnalignedHalfWords(Condition cond, BaseIndex left, Imm32 right) + Jump branch32WithUnalignedHalfWords(RelationalCondition cond, BaseIndex left, TrustedImm32 right) { load32WithUnalignedHalfWords(left, ARMRegisters::S1); return branch32(cond, ARMRegisters::S1, right); } - Jump branch16(Condition cond, BaseIndex left, RegisterID right) + Jump branch16(RelationalCondition cond, BaseIndex left, RegisterID right) { UNUSED_PARAM(cond); UNUSED_PARAM(left); @@ -414,7 +464,7 @@ public: return jump(); } - Jump branch16(Condition cond, BaseIndex left, Imm32 right) + Jump branch16(RelationalCondition cond, BaseIndex left, TrustedImm32 right) { load16(left, ARMRegisters::S0); move(right, ARMRegisters::S1); @@ -422,14 +472,20 @@ public: return m_assembler.jmp(ARMCondition(cond)); } - Jump branchTest32(Condition cond, RegisterID reg, RegisterID mask) + Jump branchTest8(ResultCondition cond, Address address, TrustedImm32 mask = TrustedImm32(-1)) + { + load8(address, ARMRegisters::S1); + return branchTest32(cond, ARMRegisters::S1, mask); + } + + Jump branchTest32(ResultCondition cond, RegisterID reg, RegisterID mask) { ASSERT((cond == Zero) || (cond == NonZero)); m_assembler.tst_r(reg, mask); return Jump(m_assembler.jmp(ARMCondition(cond))); } - Jump branchTest32(Condition cond, RegisterID reg, Imm32 mask = Imm32(-1)) + Jump branchTest32(ResultCondition cond, RegisterID reg, TrustedImm32 mask = TrustedImm32(-1)) { ASSERT((cond == Zero) || (cond == NonZero)); ARMWord w = m_assembler.getImm(mask.m_value, ARMRegisters::S0, true); @@ -440,13 +496,13 @@ public: return Jump(m_assembler.jmp(ARMCondition(cond))); } - Jump branchTest32(Condition cond, Address address, Imm32 mask = Imm32(-1)) + Jump branchTest32(ResultCondition cond, Address address, TrustedImm32 mask = TrustedImm32(-1)) { load32(address, ARMRegisters::S1); return branchTest32(cond, ARMRegisters::S1, mask); } - Jump branchTest32(Condition cond, BaseIndex address, Imm32 mask = Imm32(-1)) + Jump branchTest32(ResultCondition cond, BaseIndex address, TrustedImm32 mask = TrustedImm32(-1)) { load32(address, ARMRegisters::S1); return branchTest32(cond, ARMRegisters::S1, mask); @@ -459,7 +515,7 @@ public: void jump(RegisterID target) { - move(target, ARMRegisters::pc); + m_assembler.bx(target); } void jump(Address address) @@ -467,14 +523,14 @@ public: load32(address, ARMRegisters::pc); } - Jump branchAdd32(Condition cond, RegisterID src, RegisterID dest) + Jump branchAdd32(ResultCondition cond, RegisterID src, RegisterID dest) { ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero)); add32(src, dest); return Jump(m_assembler.jmp(ARMCondition(cond))); } - Jump branchAdd32(Condition cond, Imm32 imm, RegisterID dest) + Jump branchAdd32(ResultCondition cond, TrustedImm32 imm, RegisterID dest) { ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero)); add32(imm, dest); @@ -491,7 +547,7 @@ public: m_assembler.cmp_r(ARMRegisters::S1, m_assembler.asr(dest, 31)); } - Jump branchMul32(Condition cond, RegisterID src, RegisterID dest) + Jump branchMul32(ResultCondition cond, RegisterID src, RegisterID dest) { ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero)); if (cond == Overflow) { @@ -503,7 +559,7 @@ public: return Jump(m_assembler.jmp(ARMCondition(cond))); } - Jump branchMul32(Condition cond, Imm32 imm, RegisterID src, RegisterID dest) + Jump branchMul32(ResultCondition cond, TrustedImm32 imm, RegisterID src, RegisterID dest) { ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero)); if (cond == Overflow) { @@ -516,21 +572,28 @@ public: return Jump(m_assembler.jmp(ARMCondition(cond))); } - Jump branchSub32(Condition cond, RegisterID src, RegisterID dest) + Jump branchSub32(ResultCondition cond, RegisterID src, RegisterID dest) { ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero)); sub32(src, dest); return Jump(m_assembler.jmp(ARMCondition(cond))); } - Jump branchSub32(Condition cond, Imm32 imm, RegisterID dest) + Jump branchSub32(ResultCondition cond, TrustedImm32 imm, RegisterID dest) { ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero)); sub32(imm, dest); return Jump(m_assembler.jmp(ARMCondition(cond))); } - Jump branchOr32(Condition cond, RegisterID src, RegisterID dest) + Jump branchNeg32(ResultCondition cond, RegisterID srcDest) + { + ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero)); + neg32(srcDest); + return Jump(m_assembler.jmp(ARMCondition(cond))); + } + + Jump branchOr32(ResultCondition cond, RegisterID src, RegisterID dest) { ASSERT((cond == Signed) || (cond == Zero) || (cond == NonZero)); or32(src, dest); @@ -544,16 +607,19 @@ public: Call nearCall() { +#if WTF_ARM_ARCH_AT_LEAST(5) + ensureSpace(2 * sizeof(ARMWord), sizeof(ARMWord)); + m_assembler.loadBranchTarget(ARMRegisters::S1, ARMAssembler::AL, true); + return Call(m_assembler.blx(ARMRegisters::S1), Call::LinkableNear); +#else prepareCall(); return Call(m_assembler.jmp(ARMAssembler::AL, true), Call::LinkableNear); +#endif } Call call(RegisterID target) { - prepareCall(); - move(ARMRegisters::pc, target); - JmpSrc jmpSrc; - return Call(jmpSrc, Call::None); + return Call(m_assembler.blx(target), Call::None); } void call(Address address) @@ -563,65 +629,51 @@ public: void ret() { - m_assembler.mov_r(ARMRegisters::pc, linkRegister); + m_assembler.bx(linkRegister); } - void set32(Condition cond, RegisterID left, RegisterID right, RegisterID dest) + void compare32(RelationalCondition cond, RegisterID left, RegisterID right, RegisterID dest) { m_assembler.cmp_r(left, right); m_assembler.mov_r(dest, ARMAssembler::getOp2(0)); m_assembler.mov_r(dest, ARMAssembler::getOp2(1), ARMCondition(cond)); } - void set32(Condition cond, RegisterID left, Imm32 right, RegisterID dest) + void compare32(RelationalCondition cond, RegisterID left, TrustedImm32 right, RegisterID dest) { m_assembler.cmp_r(left, m_assembler.getImm(right.m_value, ARMRegisters::S0)); m_assembler.mov_r(dest, ARMAssembler::getOp2(0)); m_assembler.mov_r(dest, ARMAssembler::getOp2(1), ARMCondition(cond)); } - void set8(Condition cond, RegisterID left, RegisterID right, RegisterID dest) - { - // ARM doesn't have byte registers - set32(cond, left, right, dest); - } - - void set8(Condition cond, Address left, RegisterID right, RegisterID dest) + void test32(ResultCondition cond, RegisterID reg, TrustedImm32 mask, RegisterID dest) { - // ARM doesn't have byte registers - load32(left, ARMRegisters::S1); - set32(cond, ARMRegisters::S1, right, dest); - } - - void set8(Condition cond, RegisterID left, Imm32 right, RegisterID dest) - { - // ARM doesn't have byte registers - set32(cond, left, right, dest); - } - - void setTest32(Condition cond, Address address, Imm32 mask, RegisterID dest) - { - load32(address, ARMRegisters::S1); if (mask.m_value == -1) - m_assembler.cmp_r(0, ARMRegisters::S1); + m_assembler.cmp_r(0, reg); else - m_assembler.tst_r(ARMRegisters::S1, m_assembler.getImm(mask.m_value, ARMRegisters::S0)); + m_assembler.tst_r(reg, m_assembler.getImm(mask.m_value, ARMRegisters::S0)); m_assembler.mov_r(dest, ARMAssembler::getOp2(0)); m_assembler.mov_r(dest, ARMAssembler::getOp2(1), ARMCondition(cond)); } - void setTest8(Condition cond, Address address, Imm32 mask, RegisterID dest) + void test32(ResultCondition cond, Address address, TrustedImm32 mask, RegisterID dest) + { + load32(address, ARMRegisters::S1); + test32(cond, ARMRegisters::S1, mask, dest); + } + + void test8(ResultCondition cond, Address address, TrustedImm32 mask, RegisterID dest) { - // ARM doesn't have byte registers - setTest32(cond, address, mask, dest); + load8(address, ARMRegisters::S1); + test32(cond, ARMRegisters::S1, mask, dest); } - void add32(Imm32 imm, RegisterID src, RegisterID dest) + void add32(TrustedImm32 imm, RegisterID src, RegisterID dest) { m_assembler.add_r(dest, src, m_assembler.getImm(imm.m_value, ARMRegisters::S0)); } - void add32(Imm32 imm, AbsoluteAddress address) + void add32(TrustedImm32 imm, AbsoluteAddress address) { m_assembler.ldr_un_imm(ARMRegisters::S1, reinterpret_cast(address.m_ptr)); m_assembler.dtr_u(true, ARMRegisters::S1, ARMRegisters::S1, 0); @@ -630,7 +682,7 @@ public: m_assembler.dtr_u(false, ARMRegisters::S1, ARMRegisters::S0, 0); } - void sub32(Imm32 imm, AbsoluteAddress address) + void sub32(TrustedImm32 imm, AbsoluteAddress address) { m_assembler.ldr_un_imm(ARMRegisters::S1, reinterpret_cast(address.m_ptr)); m_assembler.dtr_u(true, ARMRegisters::S1, ARMRegisters::S1, 0); @@ -639,28 +691,43 @@ public: m_assembler.dtr_u(false, ARMRegisters::S1, ARMRegisters::S0, 0); } - void load32(void* address, RegisterID dest) + void load32(const void* address, RegisterID dest) { m_assembler.ldr_un_imm(ARMRegisters::S0, reinterpret_cast(address)); m_assembler.dtr_u(true, dest, ARMRegisters::S0, 0); } - Jump branch32(Condition cond, AbsoluteAddress left, RegisterID right) + Jump branch32(RelationalCondition cond, AbsoluteAddress left, RegisterID right) { load32(left.m_ptr, ARMRegisters::S1); return branch32(cond, ARMRegisters::S1, right); } - Jump branch32(Condition cond, AbsoluteAddress left, Imm32 right) + Jump branch32(RelationalCondition cond, AbsoluteAddress left, TrustedImm32 right) { load32(left.m_ptr, ARMRegisters::S1); return branch32(cond, ARMRegisters::S1, right); } + void relativeTableJump(RegisterID index, int scale) + { + ASSERT(scale >= 0 && scale <= 31); + m_assembler.add_r(ARMRegisters::pc, ARMRegisters::pc, m_assembler.lsl(index, scale)); + + // NOP the default prefetching + m_assembler.mov_r(ARMRegisters::r0, ARMRegisters::r0); + } + Call call() { +#if WTF_ARM_ARCH_AT_LEAST(5) + ensureSpace(2 * sizeof(ARMWord), sizeof(ARMWord)); + m_assembler.loadBranchTarget(ARMRegisters::S1, ARMAssembler::AL, true); + return Call(m_assembler.blx(ARMRegisters::S1), Call::Linkable); +#else prepareCall(); return Call(m_assembler.jmp(ARMAssembler::AL, true), Call::Linkable); +#endif } Call tailRecursiveCall() @@ -673,21 +740,21 @@ public: return Call::fromTailJump(oldJump); } - DataLabelPtr moveWithPatch(ImmPtr initialValue, RegisterID dest) + DataLabelPtr moveWithPatch(TrustedImmPtr initialValue, RegisterID dest) { DataLabelPtr dataLabel(this); m_assembler.ldr_un_imm(dest, reinterpret_cast(initialValue.m_value)); return dataLabel; } - Jump branchPtrWithPatch(Condition cond, RegisterID left, DataLabelPtr& dataLabel, ImmPtr initialRightValue = ImmPtr(0)) + Jump branchPtrWithPatch(RelationalCondition cond, RegisterID left, DataLabelPtr& dataLabel, TrustedImmPtr initialRightValue = TrustedImmPtr(0)) { dataLabel = moveWithPatch(initialRightValue, ARMRegisters::S1); Jump jump = branch32(cond, left, ARMRegisters::S1, true); return jump; } - Jump branchPtrWithPatch(Condition cond, Address left, DataLabelPtr& dataLabel, ImmPtr initialRightValue = ImmPtr(0)) + Jump branchPtrWithPatch(RelationalCondition cond, Address left, DataLabelPtr& dataLabel, TrustedImmPtr initialRightValue = TrustedImmPtr(0)) { load32(left, ARMRegisters::S1); dataLabel = moveWithPatch(initialRightValue, ARMRegisters::S0); @@ -695,7 +762,7 @@ public: return jump; } - DataLabelPtr storePtrWithPatch(ImmPtr initialValue, ImplicitAddress address) + DataLabelPtr storePtrWithPatch(TrustedImmPtr initialValue, ImplicitAddress address) { DataLabelPtr dataLabel = moveWithPatch(initialValue, ARMRegisters::S1); store32(ARMRegisters::S1, address); @@ -704,7 +771,7 @@ public: DataLabelPtr storePtrWithPatch(ImplicitAddress address) { - return storePtrWithPatch(ImmPtr(0), address); + return storePtrWithPatch(TrustedImmPtr(0), address); } // Floating point operators @@ -715,7 +782,12 @@ public: bool supportsFloatingPointTruncate() const { - return false; + return s_isVFPPresent; + } + + bool supportsFloatingPointSqrt() const + { + return s_isVFPPresent; } void loadDouble(ImplicitAddress address, FPRegisterID dest) @@ -723,7 +795,7 @@ public: m_assembler.doubleTransfer(true, dest, address.base, address.offset); } - void loadDouble(void* address, FPRegisterID dest) + void loadDouble(const void* address, FPRegisterID dest) { m_assembler.ldr_un_imm(ARMRegisters::S0, (ARMWord)address); m_assembler.fdtr_u(true, dest, ARMRegisters::S0, 0); @@ -736,7 +808,7 @@ public: void addDouble(FPRegisterID src, FPRegisterID dest) { - m_assembler.faddd_r(dest, dest, src); + m_assembler.vadd_f64_r(dest, dest, src); } void addDouble(Address src, FPRegisterID dest) @@ -747,7 +819,7 @@ public: void divDouble(FPRegisterID src, FPRegisterID dest) { - m_assembler.fdivd_r(dest, dest, src); + m_assembler.vdiv_f64_r(dest, dest, src); } void divDouble(Address src, FPRegisterID dest) @@ -759,7 +831,7 @@ public: void subDouble(FPRegisterID src, FPRegisterID dest) { - m_assembler.fsubd_r(dest, dest, src); + m_assembler.vsub_f64_r(dest, dest, src); } void subDouble(Address src, FPRegisterID dest) @@ -770,7 +842,7 @@ public: void mulDouble(FPRegisterID src, FPRegisterID dest) { - m_assembler.fmuld_r(dest, dest, src); + m_assembler.vmul_f64_r(dest, dest, src); } void mulDouble(Address src, FPRegisterID dest) @@ -779,10 +851,15 @@ public: mulDouble(ARMRegisters::SD0, dest); } + void sqrtDouble(FPRegisterID src, FPRegisterID dest) + { + m_assembler.vsqrt_f64_r(dest, src); + } + void convertInt32ToDouble(RegisterID src, FPRegisterID dest) { - m_assembler.fmsr_r(dest, src); - m_assembler.fsitod_r(dest, dest); + m_assembler.vmov_vfp_r(dest << 1, src); + m_assembler.vcvt_f64_s32_r(dest, dest << 1); } void convertInt32ToDouble(Address src, FPRegisterID dest) @@ -804,8 +881,8 @@ public: Jump branchDouble(DoubleCondition cond, FPRegisterID left, FPRegisterID right) { - m_assembler.fcmpd_r(left, right); - m_assembler.fmstat(); + m_assembler.vcmp_f64_r(left, right); + m_assembler.vmrs_apsr(); if (cond & DoubleConditionBitSpecial) m_assembler.cmp_r(ARMRegisters::S0, ARMRegisters::S0, ARMAssembler::VS); return Jump(m_assembler.jmp(static_cast(cond & ~DoubleConditionMask))); @@ -814,13 +891,17 @@ public: // Truncates 'src' to an integer, and places the resulting 'dest'. // If the result is not representable as a 32 bit value, branch. // May also branch for some values that are representable in 32 bits - // (specifically, in this case, INT_MIN). + // (specifically, in this case, INT_MIN and INT_MAX). Jump branchTruncateDoubleToInt32(FPRegisterID src, RegisterID dest) { - UNUSED_PARAM(src); - UNUSED_PARAM(dest); - ASSERT_NOT_REACHED(); - return jump(); + m_assembler.vcvtr_s32_f64_r(ARMRegisters::SD0 << 1, src); + // If VCVTR.S32.F64 can't fit the result into a 32-bit + // integer, it saturates at INT_MAX or INT_MIN. Testing this is + // probably quicker than testing FPSCR for exception. + m_assembler.vmov_arm_r(dest, ARMRegisters::SD0 << 1); + m_assembler.sub_r(ARMRegisters::S0, dest, ARMAssembler::getOp2(0x80000000)); + m_assembler.cmn_r(ARMRegisters::S0, ARMAssembler::getOp2(1), ARMCondition(NotEqual)); + return Jump(m_assembler.jmp(ARMCondition(Equal))); } // Convert 'src' to an integer, and places the resulting 'dest'. @@ -829,25 +910,43 @@ public: // (specifically, in this case, 0). void branchConvertDoubleToInt32(FPRegisterID src, RegisterID dest, JumpList& failureCases, FPRegisterID fpTemp) { - m_assembler.ftosid_r(ARMRegisters::SD0, src); - m_assembler.fmrs_r(dest, ARMRegisters::SD0); + m_assembler.vcvt_s32_f64_r(ARMRegisters::SD0 << 1, src); + m_assembler.vmov_arm_r(dest, ARMRegisters::SD0 << 1); // Convert the integer result back to float & compare to the original value - if not equal or unordered (NaN) then jump. - m_assembler.fsitod_r(ARMRegisters::SD0, ARMRegisters::SD0); + m_assembler.vcvt_f64_s32_r(ARMRegisters::SD0, ARMRegisters::SD0 << 1); failureCases.append(branchDouble(DoubleNotEqualOrUnordered, src, ARMRegisters::SD0)); // If the result is zero, it might have been -0.0, and 0.0 equals to -0.0 failureCases.append(branchTest32(Zero, dest)); } - void zeroDouble(FPRegisterID srcDest) + Jump branchDoubleNonZero(FPRegisterID reg, FPRegisterID scratch) + { + m_assembler.mov_r(ARMRegisters::S0, ARMAssembler::getOp2(0)); + convertInt32ToDouble(ARMRegisters::S0, scratch); + return branchDouble(DoubleNotEqual, reg, scratch); + } + + Jump branchDoubleZeroOrNaN(FPRegisterID reg, FPRegisterID scratch) { m_assembler.mov_r(ARMRegisters::S0, ARMAssembler::getOp2(0)); - convertInt32ToDouble(ARMRegisters::S0, srcDest); + convertInt32ToDouble(ARMRegisters::S0, scratch); + return branchDouble(DoubleEqualOrUnordered, reg, scratch); + } + + void nop() + { + m_assembler.nop(); } protected: - ARMAssembler::Condition ARMCondition(Condition cond) + ARMAssembler::Condition ARMCondition(RelationalCondition cond) + { + return static_cast(cond); + } + + ARMAssembler::Condition ARMCondition(ResultCondition cond) { return static_cast(cond); } @@ -864,44 +963,56 @@ protected: void prepareCall() { +#if WTF_ARM_ARCH_VERSION < 5 ensureSpace(2 * sizeof(ARMWord), sizeof(ARMWord)); m_assembler.mov_r(linkRegister, ARMRegisters::pc); +#endif } void call32(RegisterID base, int32_t offset) { +#if WTF_ARM_ARCH_AT_LEAST(5) + int targetReg = ARMRegisters::S1; +#else + int targetReg = ARMRegisters::pc; +#endif + int tmpReg = ARMRegisters::S1; + if (base == ARMRegisters::sp) offset += 4; if (offset >= 0) { if (offset <= 0xfff) { prepareCall(); - m_assembler.dtr_u(true, ARMRegisters::pc, base, offset); + m_assembler.dtr_u(true, targetReg, base, offset); } else if (offset <= 0xfffff) { - m_assembler.add_r(ARMRegisters::S0, base, ARMAssembler::OP2_IMM | (offset >> 12) | (10 << 8)); + m_assembler.add_r(tmpReg, base, ARMAssembler::OP2_IMM | (offset >> 12) | (10 << 8)); prepareCall(); - m_assembler.dtr_u(true, ARMRegisters::pc, ARMRegisters::S0, offset & 0xfff); + m_assembler.dtr_u(true, targetReg, tmpReg, offset & 0xfff); } else { - ARMWord reg = m_assembler.getImm(offset, ARMRegisters::S0); + m_assembler.moveImm(offset, tmpReg); prepareCall(); - m_assembler.dtr_ur(true, ARMRegisters::pc, base, reg); + m_assembler.dtr_ur(true, targetReg, base, tmpReg); } } else { offset = -offset; if (offset <= 0xfff) { prepareCall(); - m_assembler.dtr_d(true, ARMRegisters::pc, base, offset); + m_assembler.dtr_d(true, targetReg, base, offset); } else if (offset <= 0xfffff) { - m_assembler.sub_r(ARMRegisters::S0, base, ARMAssembler::OP2_IMM | (offset >> 12) | (10 << 8)); + m_assembler.sub_r(tmpReg, base, ARMAssembler::OP2_IMM | (offset >> 12) | (10 << 8)); prepareCall(); - m_assembler.dtr_d(true, ARMRegisters::pc, ARMRegisters::S0, offset & 0xfff); + m_assembler.dtr_d(true, targetReg, tmpReg, offset & 0xfff); } else { - ARMWord reg = m_assembler.getImm(offset, ARMRegisters::S0); + m_assembler.moveImm(offset, tmpReg); prepareCall(); - m_assembler.dtr_dr(true, ARMRegisters::pc, base, reg); + m_assembler.dtr_dr(true, targetReg, base, tmpReg); } } +#if WTF_ARM_ARCH_AT_LEAST(5) + m_assembler.blx(targetReg); +#endif } private: