X-Git-Url: https://git.saurik.com/apple/javascriptcore.git/blobdiff_plain/12899fa232562c774004a3a9d7d3149944dec712..cb9aa2694aba0ae4f946ed34b8e0f6c99c1cfe44:/assembler/MacroAssemblerARM64.h diff --git a/assembler/MacroAssemblerARM64.h b/assembler/MacroAssemblerARM64.h index 7c9e922..830b58e 100644 --- a/assembler/MacroAssemblerARM64.h +++ b/assembler/MacroAssemblerARM64.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 Apple Inc. All rights reserved. + * Copyright (C) 2012, 2014 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -54,7 +54,6 @@ public: { } - typedef ARM64Registers::FPRegisterID FPRegisterID; typedef ARM64Assembler::LinkRecord LinkRecord; typedef ARM64Assembler::JumpType JumpType; typedef ARM64Assembler::JumpLinkType JumpLinkType; @@ -65,13 +64,11 @@ public: Vector& jumpsToLink() { return m_assembler.jumpsToLink(); } void* unlinkedCode() { return m_assembler.unlinkedCode(); } - bool canCompact(JumpType jumpType) { return m_assembler.canCompact(jumpType); } - JumpLinkType computeJumpType(JumpType jumpType, const uint8_t* from, const uint8_t* to) { return m_assembler.computeJumpType(jumpType, from, to); } - 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(JumpType jumpType, JumpLinkType jumpLinkType) { return m_assembler.jumpSizeDelta(jumpType, jumpLinkType); } - void link(LinkRecord& record, uint8_t* from, uint8_t* to) { return m_assembler.link(record, from, to); } - int executableOffsetFor(int location) { return m_assembler.executableOffsetFor(location); } + static bool canCompact(JumpType jumpType) { return ARM64Assembler::canCompact(jumpType); } + static JumpLinkType computeJumpType(JumpType jumpType, const uint8_t* from, const uint8_t* to) { return ARM64Assembler::computeJumpType(jumpType, from, to); } + static JumpLinkType computeJumpType(LinkRecord& record, const uint8_t* from, const uint8_t* to) { return ARM64Assembler::computeJumpType(record, from, to); } + static int jumpSizeDelta(JumpType jumpType, JumpLinkType jumpLinkType) { return ARM64Assembler::jumpSizeDelta(jumpType, jumpLinkType); } + static void link(LinkRecord& record, uint8_t* from, uint8_t* to) { return ARM64Assembler::link(record, from, to); } static const Scale ScalePtr = TimesEight; @@ -125,8 +122,12 @@ public: }; static const RegisterID stackPointerRegister = ARM64Registers::sp; + static const RegisterID framePointerRegister = ARM64Registers::fp; static const RegisterID linkRegister = ARM64Registers::lr; + // FIXME: Get reasonable implementations for these + static bool shouldBlindForSpecificArch(uint32_t value) { return value >= 0x00ffffff; } + static bool shouldBlindForSpecificArch(uint64_t value) { return value >= 0x00ffffff; } // Integer operations: @@ -197,7 +198,10 @@ public: void add64(RegisterID src, RegisterID dest) { - m_assembler.add<64>(dest, dest, src); + if (src == ARM64Registers::sp) + m_assembler.add<64>(dest, src, dest); + else + m_assembler.add<64>(dest, dest, src); } void add64(TrustedImm32 imm, RegisterID dest) @@ -284,6 +288,11 @@ public: store64(dataTempRegister, address.m_ptr); } + void addPtrNoFlags(TrustedImm32 imm, RegisterID srcDest) + { + add64(imm, srcDest); + } + void add64(Address src, RegisterID dest) { load64(src, getCachedDataTempRegisterIDAndInvalidate()); @@ -348,6 +357,19 @@ public: m_assembler.and_<64>(dest, dest, dataTempRegister); } + void and64(TrustedImmPtr imm, RegisterID dest) + { + LogicalImmediate logicalImm = LogicalImmediate::create64(reinterpret_cast(imm.m_value)); + + if (logicalImm.isValid()) { + m_assembler.and_<64>(dest, dest, logicalImm); + return; + } + + move(imm, getCachedDataTempRegisterIDAndInvalidate()); + m_assembler.and_<64>(dest, dest, dataTempRegister); + } + void countLeadingZeros32(RegisterID src, RegisterID dest) { m_assembler.clz<32>(dest, src); @@ -373,10 +395,35 @@ public: lshift32(dest, imm, dest); } + void lshift64(RegisterID src, RegisterID shiftAmount, RegisterID dest) + { + m_assembler.lsl<64>(dest, src, shiftAmount); + } + + void lshift64(RegisterID src, TrustedImm32 imm, RegisterID dest) + { + m_assembler.lsl<64>(dest, src, imm.m_value & 0x3f); + } + + void lshift64(RegisterID shiftAmount, RegisterID dest) + { + lshift64(dest, shiftAmount, dest); + } + + void lshift64(TrustedImm32 imm, RegisterID dest) + { + lshift64(dest, imm, dest); + } + void mul32(RegisterID src, RegisterID dest) { m_assembler.mul<32>(dest, dest, src); } + + void mul64(RegisterID src, RegisterID dest) + { + m_assembler.mul<64>(dest, dest, src); + } void mul32(TrustedImm32 imm, RegisterID src, RegisterID dest) { @@ -429,6 +476,13 @@ public: store32(dataTempRegister, address.m_ptr); } + void or32(TrustedImm32 imm, Address address) + { + load32(address, getCachedDataTempRegisterIDAndInvalidate()); + or32(imm, dataTempRegister, dataTempRegister); + store32(dataTempRegister, address); + } + void or64(RegisterID src, RegisterID dest) { or64(dest, src, dest); @@ -449,7 +503,7 @@ public: LogicalImmediate logicalImm = LogicalImmediate::create64(static_cast(static_cast(imm.m_value))); if (logicalImm.isValid()) { - m_assembler.orr<64>(dest, dest, logicalImm); + m_assembler.orr<64>(dest, src, logicalImm); return; } @@ -494,6 +548,26 @@ public: { rshift32(dest, imm, dest); } + + void rshift64(RegisterID src, RegisterID shiftAmount, RegisterID dest) + { + m_assembler.asr<64>(dest, src, shiftAmount); + } + + void rshift64(RegisterID src, TrustedImm32 imm, RegisterID dest) + { + m_assembler.asr<64>(dest, src, imm.m_value & 0x3f); + } + + void rshift64(RegisterID shiftAmount, RegisterID dest) + { + rshift64(dest, shiftAmount, dest); + } + + void rshift64(TrustedImm32 imm, RegisterID dest) + { + rshift64(dest, imm, dest); + } void sub32(RegisterID src, RegisterID dest) { @@ -638,7 +712,7 @@ public: LogicalImmediate logicalImm = LogicalImmediate::create32(imm.m_value); if (logicalImm.isValid()) { - m_assembler.eor<32>(dest, dest, logicalImm); + m_assembler.eor<32>(dest, src, logicalImm); return; } @@ -677,7 +751,7 @@ public: LogicalImmediate logicalImm = LogicalImmediate::create64(static_cast(static_cast(imm.m_value))); if (logicalImm.isValid()) { - m_assembler.eor<64>(dest, dest, logicalImm); + m_assembler.eor<64>(dest, src, logicalImm); return; } @@ -731,6 +805,18 @@ public: return label; } + void abortWithReason(AbortReason reason) + { + move(TrustedImm32(reason), dataTempRegister); + breakpoint(); + } + + void abortWithReason(AbortReason reason, intptr_t misc) + { + move(TrustedImm64(misc), memoryTempRegister); + abortWithReason(reason); + } + ConvertibleLoadLabel convertibleLoadPtr(Address address, RegisterID dest) { ConvertibleLoadLabel result(this); @@ -1014,10 +1100,19 @@ public: void store8(RegisterID src, void* address) { - move(ImmPtr(address), getCachedMemoryTempRegisterIDAndInvalidate()); + move(TrustedImmPtr(address), getCachedMemoryTempRegisterIDAndInvalidate()); m_assembler.strb(src, memoryTempRegister, 0); } + void store8(RegisterID src, ImplicitAddress address) + { + if (tryStoreWithOffset<8>(src, address.base, address.offset)) + return; + + signExtend32ToPtr(TrustedImm32(address.offset), getCachedMemoryTempRegisterIDAndInvalidate()); + m_assembler.str<8>(src, address.base, memoryTempRegister); + } + void store8(TrustedImm32 imm, void* address) { if (!imm.m_value) { @@ -1029,6 +1124,16 @@ public: store8(dataTempRegister, address); } + void store8(TrustedImm32 imm, ImplicitAddress address) + { + if (!imm.m_value) { + store8(ARM64Registers::zr, address); + return; + } + + move(imm, getCachedDataTempRegisterIDAndInvalidate()); + store8(dataTempRegister, address); + } // Floating-point operations: @@ -1062,7 +1167,7 @@ public: void addDouble(AbsoluteAddress address, FPRegisterID dest) { - loadDouble(address.m_ptr, fpTempRegister); + loadDouble(TrustedImmPtr(address.m_ptr), fpTempRegister); addDouble(fpTempRegister, dest); } @@ -1147,15 +1252,6 @@ public: return Jump(makeBranch(branchType == BranchIfTruncateSuccessful ? Equal : NotEqual)); } - Jump branchTruncateDoubleToUint32(FPRegisterID src, RegisterID dest, BranchTruncateType branchType = BranchIfTruncateFailed) - { - // Truncate to a 64-bit integer in dataTempRegister, copy the low 32-bit to dest. - m_assembler.fcvtzs<64, 64>(dest, src); - // Check thlow 32-bits zero extend to be equal to the full value. - m_assembler.cmp<64>(dest, dest, ARM64Assembler::UXTW, 0); - return Jump(makeBranch(branchType == BranchIfTruncateSuccessful ? Equal : NotEqual)); - } - void convertDoubleToFloat(FPRegisterID src, FPRegisterID dest) { m_assembler.fcvt<32, 64>(dest, src); @@ -1189,6 +1285,11 @@ public: convertInt32ToDouble(dataTempRegister, dest); } + void convertInt64ToDouble(RegisterID src, FPRegisterID dest) + { + m_assembler.scvtf<64, 64>(dest, src); + } + void divDouble(FPRegisterID src, FPRegisterID dest) { divDouble(dest, src, dest); @@ -1220,9 +1321,9 @@ public: m_assembler.ldr<64>(dest, address.base, memoryTempRegister); } - void loadDouble(const void* address, FPRegisterID dest) + void loadDouble(TrustedImmPtr address, FPRegisterID dest) { - moveToCachedReg(TrustedImmPtr(address), m_cachedMemoryTempRegister); + moveToCachedReg(address, m_cachedMemoryTempRegister); m_assembler.ldr<64>(dest, memoryTempRegister, ARM64Registers::zr); } @@ -1288,9 +1389,9 @@ public: m_assembler.str<64>(src, address.base, memoryTempRegister); } - void storeDouble(FPRegisterID src, const void* address) + void storeDouble(FPRegisterID src, TrustedImmPtr address) { - moveToCachedReg(TrustedImmPtr(address), m_cachedMemoryTempRegister); + moveToCachedReg(address, m_cachedMemoryTempRegister); m_assembler.str<64>(src, memoryTempRegister, ARM64Registers::zr); } @@ -1349,14 +1450,14 @@ public: // Stack manipulation operations: // // The ABI is assumed to provide a stack abstraction to memory, - // containing machine word sized units of data. Push and pop + // containing machine word sized units of data. Push and pop // operations add and remove a single register sized unit of data - // to or from the stack. These operations are not supported on - // ARM64. Peek and poke operations read or write values on the - // stack, without moving the current stack position. Additionally, + // to or from the stack. These operations are not supported on + // ARM64. Peek and poke operations read or write values on the + // stack, without moving the current stack position. Additionally, // there are popToRestore and pushToSave operations, which are // designed just for quick-and-dirty saving and restoring of - // temporary values. These operations don't claim to have any + // temporary values. These operations don't claim to have any // ABI compatibility. void pop(RegisterID) NO_RETURN_DUE_TO_CRASH @@ -1379,6 +1480,16 @@ public: CRASH(); } + void popPair(RegisterID dest1, RegisterID dest2) + { + m_assembler.ldp<64>(dest1, dest2, ARM64Registers::sp, PairPostIndex(16)); + } + + void pushPair(RegisterID src1, RegisterID src2) + { + m_assembler.stp<64>(src1, src2, ARM64Registers::sp, PairPreIndex(-16)); + } + void popToRestore(RegisterID dest) { m_assembler.ldr<64>(dest, ARM64Registers::sp, PostIndex(16)); @@ -1388,6 +1499,15 @@ public: { m_assembler.str<64>(src, ARM64Registers::sp, PreIndex(-16)); } + + void pushToSaveImmediateWithoutTouchingRegisters(TrustedImm32 imm) + { + RegisterID reg = dataTempRegister; + pushPair(reg, reg); + move(imm, reg); + store64(reg, stackPointerRegister); + load64(Address(stackPointerRegister, 8), reg); + } void pushToSave(Address address) { @@ -1413,6 +1533,7 @@ public: storeDouble(src, stackPointerRegister); } + static ptrdiff_t pushToSaveByteOffset() { return 16; } // Register move operations: @@ -1572,6 +1693,12 @@ public: return branch64(cond, memoryTempRegister, right); } + Jump branchPtr(RelationalCondition cond, BaseIndex left, RegisterID right) + { + load64(left, getCachedMemoryTempRegisterIDAndInvalidate()); + return branch64(cond, memoryTempRegister, right); + } + Jump branch8(RelationalCondition cond, Address left, TrustedImm32 right) { ASSERT(!(0xffffff00 & right.m_value)); @@ -1586,12 +1713,45 @@ public: return branch32(cond, memoryTempRegister, right); } + Jump branch8(RelationalCondition cond, AbsoluteAddress left, TrustedImm32 right) + { + ASSERT(!(0xffffff00 & right.m_value)); + load8(left.m_ptr, getCachedMemoryTempRegisterIDAndInvalidate()); + return branch32(cond, memoryTempRegister, right); + } + Jump branchTest32(ResultCondition cond, RegisterID reg, RegisterID mask) { m_assembler.tst<32>(reg, mask); return Jump(makeBranch(cond)); } + void test32(ResultCondition cond, RegisterID reg, TrustedImm32 mask = TrustedImm32(-1)) + { + if (mask.m_value == -1) + m_assembler.tst<32>(reg, reg); + else { + bool testedWithImmediate = false; + if ((cond == Zero) || (cond == NonZero)) { + LogicalImmediate logicalImm = LogicalImmediate::create32(mask.m_value); + + if (logicalImm.isValid()) { + m_assembler.tst<32>(reg, logicalImm); + testedWithImmediate = true; + } + } + if (!testedWithImmediate) { + move(mask, getCachedDataTempRegisterIDAndInvalidate()); + m_assembler.tst<32>(reg, dataTempRegister); + } + } + } + + Jump branch(ResultCondition cond) + { + return Jump(makeBranch(cond)); + } + Jump branchTest32(ResultCondition cond, RegisterID reg, TrustedImm32 mask = TrustedImm32(-1)) { if (mask.m_value == -1) { @@ -1696,11 +1856,17 @@ public: Jump branchTest8(ResultCondition cond, ExtendedAddress address, TrustedImm32 mask = TrustedImm32(-1)) { - move(ImmPtr(reinterpret_cast(address.offset)), getCachedDataTempRegisterIDAndInvalidate()); + move(TrustedImmPtr(reinterpret_cast(address.offset)), getCachedDataTempRegisterIDAndInvalidate()); m_assembler.ldrb(dataTempRegister, address.base, dataTempRegister); return branchTest32(cond, dataTempRegister, mask); } + Jump branchTest8(ResultCondition cond, BaseIndex address, TrustedImm32 mask = TrustedImm32(-1)) + { + load8(address, getCachedDataTempRegisterIDAndInvalidate()); + return branchTest32(cond, dataTempRegister, mask); + } + Jump branch32WithUnalignedHalfWords(RelationalCondition cond, BaseIndex left, TrustedImm32 right) { return branch32(cond, left, right); @@ -1710,7 +1876,7 @@ public: // Arithmetic control flow operations: // // This set of conditional branch operations branch based - // on the result of an arithmetic operation. The operation + // on the result of an arithmetic operation. The operation // is performed as normal, storing the result. // // * jz operations branch if the result is zero. @@ -1738,6 +1904,12 @@ public: return branchAdd32(cond, op1, dataTempRegister, dest); } + Jump branchAdd32(ResultCondition cond, Address src, RegisterID dest) + { + load32(src, getCachedDataTempRegisterIDAndInvalidate()); + return branchAdd32(cond, dest, dataTempRegister, dest); + } + Jump branchAdd32(ResultCondition cond, RegisterID src, RegisterID dest) { return branchAdd32(cond, dest, src, dest); @@ -1830,12 +2002,41 @@ public: return branchMul32(cond, dataTempRegister, src, dest); } + Jump branchMul64(ResultCondition cond, RegisterID src1, RegisterID src2, RegisterID dest) + { + ASSERT(cond != Signed); + + // This is a signed multiple of two 64-bit values, producing a 64-bit result. + m_assembler.mul<64>(dest, src1, src2); + + if (cond != Overflow) + return branchTest64(cond, dest); + + // Compute bits 127..64 of the result into dataTempRegister. + m_assembler.smulh(getCachedDataTempRegisterIDAndInvalidate(), src1, src2); + // Splat bit 63 of the result to bits 63..0 of memoryTempRegister. + m_assembler.asr<64>(getCachedMemoryTempRegisterIDAndInvalidate(), dest, 63); + // Check that bits 31..63 of the original result were all equal. + return branch64(NotEqual, memoryTempRegister, dataTempRegister); + } + + Jump branchMul64(ResultCondition cond, RegisterID src, RegisterID dest) + { + return branchMul64(cond, dest, src, dest); + } + Jump branchNeg32(ResultCondition cond, RegisterID dest) { m_assembler.neg<32, S>(dest, dest); return Jump(makeBranch(cond)); } + Jump branchNeg64(ResultCondition cond, RegisterID srcDest) + { + m_assembler.neg<64, S>(srcDest, srcDest); + return Jump(makeBranch(cond)); + } + Jump branchSub32(ResultCondition cond, RegisterID dest) { m_assembler.neg<32, S>(dest, dest); @@ -2098,6 +2299,13 @@ public: return branch64(cond, left, dataTempRegister); } + ALWAYS_INLINE Jump branch32WithPatch(RelationalCondition cond, Address left, DataLabel32& dataLabel, TrustedImm32 initialRightValue = TrustedImm32(0)) + { + dataLabel = DataLabel32(this); + moveWithPatch(initialRightValue, getCachedDataTempRegisterIDAndInvalidate()); + return branch32(cond, left, dataTempRegister); + } + PatchableJump patchableBranchPtr(RelationalCondition cond, Address left, TrustedImmPtr right = TrustedImmPtr(0)) { m_makeJumpPatchable = true; @@ -2130,6 +2338,14 @@ public: return PatchableJump(result); } + PatchableJump patchableBranch32WithPatch(RelationalCondition cond, Address left, DataLabel32& dataLabel, TrustedImm32 initialRightValue = TrustedImm32(0)) + { + m_makeJumpPatchable = true; + Jump result = branch32WithPatch(cond, left, dataLabel, initialRightValue); + m_makeJumpPatchable = false; + return PatchableJump(result); + } + PatchableJump patchableJump() { m_makeJumpPatchable = true; @@ -2167,6 +2383,11 @@ public: { m_assembler.nop(); } + + void memoryFence() + { + m_assembler.dmbSY(); + } // Misc helper functions. @@ -2192,7 +2413,15 @@ public: return ARM64Assembler::maxJumpReplacementSize(); } + RegisterID scratchRegisterForBlinding() + { + // We *do not* have a scratch register for blinding. + RELEASE_ASSERT_NOT_REACHED(); + return getCachedDataTempRegisterIDAndInvalidate(); + } + static bool canJumpReplacePatchableBranchPtrWithPatch() { return false; } + static bool canJumpReplacePatchableBranch32WithPatch() { return false; } static CodeLocationLabel startOfBranchPtrWithPatchOnRegister(CodeLocationDataLabelPtr label) { @@ -2205,6 +2434,12 @@ public: return CodeLocationLabel(); } + static CodeLocationLabel startOfPatchableBranch32WithPatchOnAddress(CodeLocationDataLabel32) + { + UNREACHABLE_FOR_PLATFORM(); + return CodeLocationLabel(); + } + static void revertJumpReplacementToBranchPtrWithPatch(CodeLocationLabel instructionStart, RegisterID, void* initialValue) { reemitInitialMoveWithPatch(instructionStart.dataLocation(), initialValue); @@ -2215,6 +2450,11 @@ public: UNREACHABLE_FOR_PLATFORM(); } + static void revertJumpReplacementToPatchableBranch32WithPatch(CodeLocationLabel, Address, int32_t) + { + UNREACHABLE_FOR_PLATFORM(); + } + protected: ALWAYS_INLINE Jump makeBranch(ARM64Assembler::Condition cond) { @@ -2279,8 +2519,8 @@ private: template void moveInternal(ImmediateType imm, RegisterID dest) { - const int dataSize = sizeof(rawType)*8; - const int numberHalfWords = dataSize/16; + const int dataSize = sizeof(rawType) * 8; + const int numberHalfWords = dataSize / 16; rawType value = bitwise_cast(imm.m_value); uint16_t halfword[numberHalfWords];