diff options
Diffstat (limited to 'JavaScriptCore/assembler/MacroAssemblerARMv7.h')
-rw-r--r-- | JavaScriptCore/assembler/MacroAssemblerARMv7.h | 244 |
1 files changed, 224 insertions, 20 deletions
diff --git a/JavaScriptCore/assembler/MacroAssemblerARMv7.h b/JavaScriptCore/assembler/MacroAssemblerARMv7.h index 532a9cf..a1539f2 100644 --- a/JavaScriptCore/assembler/MacroAssemblerARMv7.h +++ b/JavaScriptCore/assembler/MacroAssemblerARMv7.h @@ -1,5 +1,6 @@ /* * Copyright (C) 2009 Apple Inc. All rights reserved. + * Copyright (C) 2010 University of Szeged * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -26,8 +27,6 @@ #ifndef MacroAssemblerARMv7_h #define MacroAssemblerARMv7_h -#include <wtf/Platform.h> - #if ENABLE(ASSEMBLER) #include "ARMv7Assembler.h" @@ -39,9 +38,29 @@ class MacroAssemblerARMv7 : public AbstractMacroAssembler<ARMv7Assembler> { // FIXME: switch dataTempRegister & addressTempRegister, or possibly use r7? // - dTR is likely used more than aTR, and we'll get better instruction // encoding if it's in the low 8 registers. - static const ARMRegisters::RegisterID dataTempRegister = ARMRegisters::ip; + static const RegisterID dataTempRegister = ARMRegisters::ip; static const RegisterID addressTempRegister = ARMRegisters::r3; - static const FPRegisterID fpTempRegister = ARMRegisters::d7; + + static const ARMRegisters::FPDoubleRegisterID fpTempRegister = ARMRegisters::d7; + inline ARMRegisters::FPSingleRegisterID fpTempRegisterAsSingle() { return ARMRegisters::asSingle(fpTempRegister); } + +public: + typedef ARMv7Assembler::LinkRecord LinkRecord; + typedef ARMv7Assembler::JumpLinkType JumpLinkType; + + MacroAssemblerARMv7() + : m_inUninterruptedSequence(false) + { + } + + void beginUninterruptedSequence() { m_inUninterruptedSequence = true; } + void endUninterruptedSequence() { m_inUninterruptedSequence = false; } + Vector<LinkRecord>& jumpsToLink() { return m_assembler.jumpsToLink(); } + void* unlinkedCode() { return m_assembler.unlinkedCode(); } + JumpLinkType computeJumpType(LinkRecord& record, const uint8_t* from, const uint8_t* to) { return m_assembler.computeJumpType(record, from, to); } + void recordLinkOffsets(int32_t regionStart, int32_t regionEnd, int32_t offset) {return m_assembler.recordLinkOffsets(regionStart, regionEnd, offset); } + int jumpSizeDelta(JumpLinkType jumpLinkType) { return m_assembler.jumpSizeDelta(jumpLinkType); } + void link(LinkRecord& record, uint8_t* from, uint8_t* to) { return m_assembler.link(record, from, to); } struct ArmAddress { enum AddressType { @@ -74,6 +93,7 @@ class MacroAssemblerARMv7 : public AbstractMacroAssembler<ARMv7Assembler> { }; public: + typedef ARMRegisters::FPDoubleRegisterID FPRegisterID; static const Scale ScalePtr = TimesFour; @@ -223,6 +243,11 @@ public: m_assembler.smull(dest, dataTempRegister, src, dataTempRegister); } + void neg32(RegisterID srcDest) + { + m_assembler.neg(srcDest, srcDest); + } + void not32(RegisterID srcDest) { m_assembler.mvn(srcDest, srcDest); @@ -258,6 +283,21 @@ public: { m_assembler.asr(dest, dest, imm.m_value & 0x1f); } + + void urshift32(RegisterID shift_amount, RegisterID dest) + { + // Clamp the shift to the range 0..31 + ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(0x1f); + ASSERT(armImm.isValid()); + m_assembler.ARM_and(dataTempRegister, shift_amount, armImm); + + m_assembler.lsr(dest, dest, dataTempRegister); + } + + void urshift32(Imm32 imm, RegisterID dest) + { + m_assembler.lsr(dest, dest, imm.m_value & 0x1f); + } void sub32(RegisterID src, RegisterID dest) { @@ -368,6 +408,20 @@ private: } } + void load8(ArmAddress address, RegisterID dest) + { + if (address.type == ArmAddress::HasIndex) + m_assembler.ldrb(dest, address.base, address.u.index, address.u.scale); + else if (address.u.offset >= 0) { + ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12(address.u.offset); + ASSERT(armImm.isValid()); + m_assembler.ldrb(dest, address.base, armImm); + } else { + ASSERT(address.u.offset >= -255); + m_assembler.ldrb(dest, address.base, address.u.offset, true, false); + } + } + void store32(RegisterID src, ArmAddress address) { if (address.type == ArmAddress::HasIndex) @@ -404,6 +458,11 @@ public: m_assembler.ldr(dest, addressTempRegister, ARMThumbImmediate::makeUInt16(0)); } + void load8(ImplicitAddress address, RegisterID dest) + { + load8(setupArmAddress(address), dest); + } + DataLabel32 load32WithAddressOffsetPatch(Address address, RegisterID dest) { DataLabel32 label = moveWithPatch(Imm32(address.offset), dataTempRegister); @@ -423,6 +482,17 @@ public: { m_assembler.ldrh(dest, makeBaseIndexBase(address), address.index, address.scale); } + + void load16(ImplicitAddress address, RegisterID dest) + { + ARMThumbImmediate armImm = ARMThumbImmediate::makeUInt12(address.offset); + if (armImm.isValid()) + m_assembler.ldrh(dest, address.base, armImm); + else { + move(Imm32(address.offset), dataTempRegister); + m_assembler.ldrh(dest, address.base, dataTempRegister); + } + } DataLabel32 store32WithAddressOffsetPatch(RegisterID src, Address address) { @@ -476,6 +546,11 @@ public: // In short, FIXME:. bool supportsFloatingPointTruncate() const { return false; } + bool supportsFloatingPointSqrt() const + { + return false; + } + void loadDouble(ImplicitAddress address, FPRegisterID dest) { RegisterID base = address.base; @@ -491,6 +566,12 @@ public: m_assembler.vldr(dest, base, offset); } + void loadDouble(const void* address, FPRegisterID dest) + { + move(ImmPtr(address), addressTempRegister); + m_assembler.vldr(dest, addressTempRegister, 0); + } + void storeDouble(FPRegisterID src, ImplicitAddress address) { RegisterID base = address.base; @@ -517,6 +598,11 @@ public: addDouble(fpTempRegister, dest); } + void divDouble(FPRegisterID src, FPRegisterID dest) + { + m_assembler.vdiv_F64(dest, dest, src); + } + void subDouble(FPRegisterID src, FPRegisterID dest) { m_assembler.vsub_F64(dest, dest, src); @@ -539,16 +625,37 @@ public: mulDouble(fpTempRegister, dest); } + void sqrtDouble(FPRegisterID, FPRegisterID) + { + ASSERT_NOT_REACHED(); + } + void convertInt32ToDouble(RegisterID src, FPRegisterID dest) { - m_assembler.vmov(fpTempRegister, src); - m_assembler.vcvt_F64_S32(dest, fpTempRegister); + m_assembler.vmov(fpTempRegisterAsSingle(), src); + m_assembler.vcvt_F64_S32(dest, fpTempRegisterAsSingle()); + } + + void convertInt32ToDouble(Address address, FPRegisterID dest) + { + // Fixme: load directly into the fpr! + load32(address, dataTempRegister); + m_assembler.vmov(fpTempRegisterAsSingle(), dataTempRegister); + m_assembler.vcvt_F64_S32(dest, fpTempRegisterAsSingle()); + } + + void convertInt32ToDouble(AbsoluteAddress address, FPRegisterID dest) + { + // Fixme: load directly into the fpr! + load32(address.m_ptr, dataTempRegister); + m_assembler.vmov(fpTempRegisterAsSingle(), dataTempRegister); + m_assembler.vcvt_F64_S32(dest, fpTempRegisterAsSingle()); } Jump branchDouble(DoubleCondition cond, FPRegisterID left, FPRegisterID right) { m_assembler.vcmp_F64(left, right); - m_assembler.vmrs_APSR_nzcv_FPSCR(); + m_assembler.vmrs(); if (cond == DoubleNotEqual) { // ConditionNE jumps if NotEqual *or* unordered - force the unordered cases not to jump. @@ -575,6 +682,27 @@ public: return jump(); } + // Convert '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, 0). + void branchConvertDoubleToInt32(FPRegisterID src, RegisterID dest, JumpList& failureCases, FPRegisterID) + { + m_assembler.vcvtr_S32_F64(fpTempRegisterAsSingle(), src); + m_assembler.vmov(dest, fpTempRegisterAsSingle()); + + // Convert the integer result back to float & compare to the original value - if not equal or unordered (NaN) then jump. + m_assembler.vcvt_F64_S32(fpTempRegister, fpTempRegisterAsSingle()); + failureCases.append(branchDouble(DoubleNotEqualOrUnordered, src, fpTempRegister)); + + // If the result is zero, it might have been -0.0, and the double comparison won't catch this! + failureCases.append(branchTest32(Zero, dest)); + } + + void zeroDouble(FPRegisterID dest) + { + m_assembler.vmov_F64_0(dest); + } // Stack manipulation operations: // @@ -793,6 +921,19 @@ public: return branch32(cond, addressTempRegister, Imm32(right.m_value << 16)); } + Jump branch8(Condition cond, RegisterID left, Imm32 right) + { + compare32(left, right); + return Jump(makeBranch(cond)); + } + + Jump branch8(Condition cond, Address left, Imm32 right) + { + // use addressTempRegister incase the branch8 we call uses dataTempRegister. :-/ + load8(left, addressTempRegister); + return branch8(cond, addressTempRegister, right); + } + Jump branchTest32(Condition cond, RegisterID reg, RegisterID mask) { ASSERT((cond == Zero) || (cond == NonZero)); @@ -823,6 +964,21 @@ public: return branchTest32(cond, addressTempRegister, mask); } + Jump branchTest8(Condition cond, RegisterID reg, Imm32 mask = Imm32(-1)) + { + ASSERT((cond == Zero) || (cond == NonZero)); + test32(reg, mask); + return Jump(makeBranch(cond)); + } + + Jump branchTest8(Condition cond, Address address, Imm32 mask = Imm32(-1)) + { + ASSERT((cond == Zero) || (cond == NonZero)); + // use addressTempRegister incase the branchTest8 we call uses dataTempRegister. :-/ + load8(address, addressTempRegister); + return branchTest8(cond, addressTempRegister, mask); + } + Jump jump() { return Jump(makeJump()); @@ -830,14 +986,14 @@ public: void jump(RegisterID target) { - m_assembler.bx(target); + m_assembler.bx(target, inUninterruptedSequence() ? ARMv7Assembler::JumpFullSize : ARMv7Assembler::JumpNoCondition); } // Address is a memory location containing the address to jump to void jump(Address address) { load32(address, dataTempRegister); - m_assembler.bx(dataTempRegister); + m_assembler.bx(dataTempRegister, inUninterruptedSequence() ? ARMv7Assembler::JumpFullSize : ARMv7Assembler::JumpNoCondition); } @@ -873,7 +1029,7 @@ public: Jump branchMul32(Condition cond, RegisterID src, RegisterID dest) { - ASSERT(cond == Overflow); + ASSERT_UNUSED(cond, cond == Overflow); m_assembler.smull(dest, dataTempRegister, dest, src); m_assembler.asr(addressTempRegister, dest, 31); return branch32(NotEqual, addressTempRegister, dataTempRegister); @@ -881,13 +1037,20 @@ public: Jump branchMul32(Condition cond, Imm32 imm, RegisterID src, RegisterID dest) { - ASSERT(cond == Overflow); + ASSERT_UNUSED(cond, cond == Overflow); move(imm, dataTempRegister); m_assembler.smull(dest, dataTempRegister, src, dataTempRegister); m_assembler.asr(addressTempRegister, dest, 31); return branch32(NotEqual, addressTempRegister, dataTempRegister); } + Jump branchOr32(Condition cond, RegisterID src, RegisterID dest) + { + ASSERT((cond == Signed) || (cond == Zero) || (cond == NonZero)); + m_assembler.orr_S(dest, dest, src); + return Jump(makeBranch(cond)); + } + Jump branchSub32(Condition cond, RegisterID src, RegisterID dest) { ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero)); @@ -913,35 +1076,35 @@ public: void breakpoint() { - m_assembler.bkpt(); + m_assembler.bkpt(0); } Call nearCall() { moveFixedWidthEncoding(Imm32(0), dataTempRegister); - return Call(m_assembler.blx(dataTempRegister), Call::LinkableNear); + return Call(m_assembler.blx(dataTempRegister, ARMv7Assembler::JumpFullSize), Call::LinkableNear); } Call call() { moveFixedWidthEncoding(Imm32(0), dataTempRegister); - return Call(m_assembler.blx(dataTempRegister), Call::Linkable); + return Call(m_assembler.blx(dataTempRegister, ARMv7Assembler::JumpFullSize), Call::Linkable); } Call call(RegisterID target) { - return Call(m_assembler.blx(target), Call::None); + return Call(m_assembler.blx(target, ARMv7Assembler::JumpFullSize), Call::None); } Call call(Address address) { load32(address, dataTempRegister); - return Call(m_assembler.blx(dataTempRegister), Call::None); + return Call(m_assembler.blx(dataTempRegister, ARMv7Assembler::JumpFullSize), Call::None); } void ret() { - m_assembler.bx(linkRegister); + m_assembler.bx(linkRegister, ARMv7Assembler::JumpFullSize); } void set32(Condition cond, RegisterID left, RegisterID right, RegisterID dest) @@ -952,6 +1115,12 @@ public: m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(0)); } + void set32(Condition cond, Address left, RegisterID right, RegisterID dest) + { + load32(left, dataTempRegister); + set32(cond, dataTempRegister, right, dest); + } + void set32(Condition cond, RegisterID left, Imm32 right, RegisterID dest) { compare32(left, right); @@ -960,6 +1129,21 @@ public: m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(0)); } + void set8(Condition cond, RegisterID left, RegisterID right, RegisterID dest) + { + set32(cond, left, right, dest); + } + + void set8(Condition cond, Address left, RegisterID right, RegisterID dest) + { + set32(cond, left, right, dest); + } + + void set8(Condition cond, RegisterID left, Imm32 right, RegisterID dest) + { + set32(cond, left, right, dest); + } + // FIXME: // The mask should be optional... paerhaps the argument order should be // dest-src, operations always have a dest? ... possibly not true, considering @@ -973,6 +1157,14 @@ public: m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(0)); } + void setTest8(Condition cond, Address address, Imm32 mask, RegisterID dest) + { + load8(address, dataTempRegister); + test32(dataTempRegister, mask); + m_assembler.it(armV7Condition(cond), false); + m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(1)); + m_assembler.mov(dest, ARMThumbImmediate::makeUInt16(0)); + } DataLabel32 moveWithPatch(Imm32 imm, RegisterID dst) { @@ -1012,7 +1204,7 @@ public: { // Like a normal call, but don't link. moveFixedWidthEncoding(Imm32(0), dataTempRegister); - return Call(m_assembler.bx(dataTempRegister), Call::Linkable); + return Call(m_assembler.bx(dataTempRegister, ARMv7Assembler::JumpFullSize), Call::Linkable); } Call makeTailRecursiveCall(Jump oldJump) @@ -1021,19 +1213,29 @@ public: return tailRecursiveCall(); } + + int executableOffsetFor(int location) + { + return m_assembler.executableOffsetFor(location); + } protected: + bool inUninterruptedSequence() + { + return m_inUninterruptedSequence; + } + ARMv7Assembler::JmpSrc makeJump() { moveFixedWidthEncoding(Imm32(0), dataTempRegister); - return m_assembler.bx(dataTempRegister); + return m_assembler.bx(dataTempRegister, inUninterruptedSequence() ? ARMv7Assembler::JumpFullSize : ARMv7Assembler::JumpNoCondition); } ARMv7Assembler::JmpSrc makeBranch(ARMv7Assembler::Condition cond) { m_assembler.it(cond, true, true); moveFixedWidthEncoding(Imm32(0), dataTempRegister); - return m_assembler.bx(dataTempRegister); + return m_assembler.bx(dataTempRegister, inUninterruptedSequence() ? ARMv7Assembler::JumpFullSize : ARMv7Assembler::JumpCondition, cond); } ARMv7Assembler::JmpSrc makeBranch(Condition cond) { return makeBranch(armV7Condition(cond)); } ARMv7Assembler::JmpSrc makeBranch(DoubleCondition cond) { return makeBranch(armV7Condition(cond)); } @@ -1123,6 +1325,8 @@ private: { ARMv7Assembler::relinkCall(call.dataLocation(), destination.executableAddress()); } + + bool m_inUninterruptedSequence; }; } // namespace JSC |