X-Git-Url: https://git.saurik.com/apple/javascriptcore.git/blobdiff_plain/f9bf01c6616d5ddcf65b13b33cedf9e387ff7a63..1981f5dfe8d77d97469d20652f712a09400c48ed:/assembler/MacroAssemblerARM.h diff --git a/assembler/MacroAssemblerARM.h b/assembler/MacroAssemblerARM.h index 21b8de8..829ec53 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)); } @@ -104,12 +108,17 @@ public: add32(ARMRegisters::S1, dest); } + void add32(RegisterID src, TrustedImm32 imm, RegisterID dest) + { + m_assembler.adds_r(dest, src, m_assembler.getImm(imm.m_value, ARMRegisters::S0)); + } + void and32(RegisterID src, RegisterID dest) { 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) @@ -118,6 +127,15 @@ public: m_assembler.ands_r(dest, dest, w); } + void and32(TrustedImm32 imm, RegisterID src, RegisterID dest) + { + ARMWord w = m_assembler.getImm(imm.m_value, ARMRegisters::S0, true); + if (w & ARMAssembler::OP2_INV_IMM) + m_assembler.bics_r(dest, src, w & ~ARMAssembler::OP2_INV_IMM); + else + m_assembler.ands_r(dest, src, w); + } + void lshift32(RegisterID shift_amount, RegisterID dest) { ARMWord w = ARMAssembler::getOp2(0x1f); @@ -127,11 +145,16 @@ 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)); } + void lshift32(RegisterID src, TrustedImm32 imm, RegisterID dest) + { + m_assembler.movs_r(dest, m_assembler.lsl(src, imm.m_value & 0x1f)); + } + void mul32(RegisterID src, RegisterID dest) { if (src == dest) { @@ -141,7 +164,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); @@ -152,21 +175,26 @@ public: m_assembler.rsbs_r(srcDest, srcDest, ARMAssembler::getOp2(0)); } - void not32(RegisterID dest) - { - m_assembler.mvns_r(dest, dest); - } - void or32(RegisterID src, RegisterID dest) { 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)); } + void or32(TrustedImm32 imm, RegisterID src, RegisterID dest) + { + m_assembler.orrs_r(dest, src, m_assembler.getImm(imm.m_value, ARMRegisters::S0)); + } + + void or32(RegisterID op1, RegisterID op2, RegisterID dest) + { + m_assembler.orrs_r(dest, op1, op2); + } + void rshift32(RegisterID shift_amount, RegisterID dest) { ARMWord w = ARMAssembler::getOp2(0x1f); @@ -175,10 +203,34 @@ public: m_assembler.movs_r(dest, m_assembler.asr_r(dest, ARMRegisters::S0)); } + + void rshift32(TrustedImm32 imm, RegisterID dest) + { + rshift32(dest, imm, dest); + } - void rshift32(Imm32 imm, RegisterID dest) + void rshift32(RegisterID src, TrustedImm32 imm, RegisterID dest) { - m_assembler.movs_r(dest, m_assembler.asr(dest, imm.m_value & 0x1f)); + m_assembler.movs_r(dest, m_assembler.asr(src, 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 urshift32(RegisterID src, TrustedImm32 imm, RegisterID dest) + { + m_assembler.movs_r(dest, m_assembler.lsr(src, imm.m_value & 0x1f)); } void sub32(RegisterID src, RegisterID dest) @@ -186,12 +238,12 @@ public: 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); @@ -204,14 +256,51 @@ public: sub32(ARMRegisters::S1, dest); } + void sub32(RegisterID src, TrustedImm32 imm, RegisterID dest) + { + m_assembler.subs_r(dest, src, m_assembler.getImm(imm.m_value, ARMRegisters::S0)); + } + void xor32(RegisterID src, RegisterID dest) { m_assembler.eors_r(dest, dest, src); } - void xor32(Imm32 imm, RegisterID dest) + void xor32(TrustedImm32 imm, RegisterID dest) + { + if (imm.m_value == -1) + m_assembler.mvns_r(dest, dest); + else + m_assembler.eors_r(dest, dest, m_assembler.getImm(imm.m_value, ARMRegisters::S0)); + } + + void xor32(TrustedImm32 imm, RegisterID src, RegisterID dest) + { + if (imm.m_value == -1) + m_assembler.mvns_r(dest, src); + else + m_assembler.eors_r(dest, src, 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 load8(BaseIndex address, RegisterID dest) { - m_assembler.eors_r(dest, dest, m_assembler.getImm(imm.m_value, ARMRegisters::S0)); + m_assembler.baseIndexTransfer32(true, dest, address.base, address.index, static_cast(address.scale), address.offset, true); } void load32(ImplicitAddress address, RegisterID dest) @@ -233,6 +322,11 @@ public: } #endif + void load16Unaligned(BaseIndex address, RegisterID dest) + { + load16(address, dest); + } + DataLabel32 load32WithAddressOffsetPatch(Address address, RegisterID dest) { DataLabel32 dataLabel(this); @@ -240,21 +334,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 +374,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 +389,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 +415,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 +434,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,77 +458,84 @@ 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 branch8(RelationalCondition cond, BaseIndex left, TrustedImm32 right) + { + ASSERT(!(right.m_value & 0xFFFFFF00)); + 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 = (right.m_value == 0x80000000) ? ARMAssembler::INVALID_IMM : 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) - { - UNUSED_PARAM(cond); - UNUSED_PARAM(left); - UNUSED_PARAM(right); - ASSERT_NOT_REACHED(); - return jump(); - } - - Jump branch16(Condition cond, BaseIndex left, Imm32 right) + Jump branchTest8(ResultCondition cond, Address address, TrustedImm32 mask = TrustedImm32(-1)) { - load16(left, ARMRegisters::S0); - move(right, ARMRegisters::S1); - m_assembler.cmp_r(ARMRegisters::S0, ARMRegisters::S1); - return m_assembler.jmp(ARMCondition(cond)); + load8(address, ARMRegisters::S1); + return branchTest32(cond, ARMRegisters::S1, mask); } - Jump branchTest32(Condition cond, RegisterID reg, RegisterID 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 +546,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 +565,7 @@ public: void jump(RegisterID target) { - move(target, ARMRegisters::pc); + m_assembler.bx(target); } void jump(Address address) @@ -467,20 +573,27 @@ 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); return Jump(m_assembler.jmp(ARMCondition(cond))); } + Jump branchAdd32(ResultCondition cond, RegisterID src, TrustedImm32 imm, RegisterID dest) + { + ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero)); + add32(src, imm, dest); + return Jump(m_assembler.jmp(ARMCondition(cond))); + } + void mull32(RegisterID src1, RegisterID src2, RegisterID dest) { if (src1 == dest) { @@ -491,7 +604,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 +616,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 +629,42 @@ 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 branchSub32(ResultCondition cond, RegisterID src, TrustedImm32 imm, RegisterID dest) + { + ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero)); + sub32(src, imm, dest); + return Jump(m_assembler.jmp(ARMCondition(cond))); + } + + Jump branchSub32(ResultCondition cond, RegisterID op1, RegisterID op2, RegisterID dest) + { + ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero)); + m_assembler.subs_r(dest, op1, op2); + return Jump(m_assembler.jmp(ARMCondition(cond))); + } + + 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 +678,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 +700,57 @@ 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) + void compare8(RelationalCondition cond, Address left, TrustedImm32 right, RegisterID dest) { - // ARM doesn't have byte registers - set32(cond, left, right, dest); + load8(left, ARMRegisters::S1); + compare32(cond, ARMRegisters::S1, 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 +759,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 +768,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 +817,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 +839,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,26 +848,32 @@ public: DataLabelPtr storePtrWithPatch(ImplicitAddress address) { - return storePtrWithPatch(ImmPtr(0), address); + return storePtrWithPatch(TrustedImmPtr(0), address); } // Floating point operators - bool supportsFloatingPoint() const + static bool supportsFloatingPoint() { return s_isVFPPresent; } - bool supportsFloatingPointTruncate() const + static bool supportsFloatingPointTruncate() { return false; } + static bool supportsFloatingPointSqrt() + { + return s_isVFPPresent; + } + static bool supportsFloatingPointAbs() { return false; } + void loadDouble(ImplicitAddress address, FPRegisterID dest) { 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 +886,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 +897,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 +909,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 +920,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 +929,20 @@ public: mulDouble(ARMRegisters::SD0, dest); } + void sqrtDouble(FPRegisterID src, FPRegisterID dest) + { + m_assembler.vsqrt_f64_r(dest, src); + } + + void absDouble(FPRegisterID, FPRegisterID) + { + ASSERT_NOT_REACHED(); + } + 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 +964,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))); @@ -829,25 +989,48 @@ 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, srcDest); + 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, scratch); + return branchDouble(DoubleEqualOrUnordered, reg, scratch); + } + + void nop() + { + m_assembler.nop(); + } + + static FunctionPtr readCallTarget(CodeLocationCall call) + { + return FunctionPtr(reinterpret_cast(ARMAssembler::readCallTarget(call.dataLocation()))); } 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 +1047,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: @@ -910,7 +1105,7 @@ private: static void linkCall(void* code, Call call, FunctionPtr function) { - ARMAssembler::linkCall(code, call.m_jmp, function.value()); + ARMAssembler::linkCall(code, call.m_label, function.value()); } static void repatchCall(CodeLocationCall call, CodeLocationLabel destination)