Diff
Modified: trunk/Source/_javascript_Core/ChangeLog (278855 => 278856)
--- trunk/Source/_javascript_Core/ChangeLog 2021-06-15 01:02:51 UTC (rev 278855)
+++ trunk/Source/_javascript_Core/ChangeLog 2021-06-15 01:04:01 UTC (rev 278856)
@@ -1,3 +1,64 @@
+2021-06-14 Mark Lam <mark....@apple.com>
+
+ Add ldp and stp support for FP registers, plus some bug fixes.
+ https://bugs.webkit.org/show_bug.cgi?id=226998
+ rdar://79313717
+
+ Reviewed by Robin Morisset.
+
+ This patch does the following:
+ 1. Add ldp and stp support for FP registers.
+ This simply entails providing wrappers that take FPRegisterID and passing true
+ for the V bit to the underlying loadStoreRegisterPairXXX encoding function.
+ V is for vector (aka floating point). This will cause bit 26 in the instruction
+ to be set indicating that it's loading / storing floating point registers.
+
+ 2. Add ARM64 disassembler support ldp and stp for FP registers.
+ This includes fixing A64DOpcodeLoadStoreRegisterPair::mask to not exclude the
+ FP versions of the instructions.
+
+ 3. Add ARM64Assembler query methods for determining if an immediate is encodable
+ as the signed 12 bit immediate of ldp and stp instructions.
+
+ 4. Fix ldp and stp offset form to take an int instead of an unsigned. The
+ immediate it takes is a 12-bit signed int, not unsigned.
+
+ 5. In loadStoreRegisterPairXXX encoding functions used by the forms of ldp and stp,
+ RELEASE_ASSERT that the passed in immediate is encodable. Unlike ldur / stur,
+ there is no form of ldp / stp that takes the offset in a register that can be
+ used as a fail over. Hence, if the immediate is not encodable, this is a
+ non-recoverable event. The client is responsible for ensuring that the offset
+ is encodable.
+
+ 6. Added some testmasm tests for testing the offset form (as opposed to PreIndex
+ and PostIndex forms) of ldp and stp. We currently only use the offset form
+ in our JITs.
+
+ * assembler/ARM64Assembler.h:
+ (JSC::ARM64Assembler::isValidLDPImm):
+ (JSC::ARM64Assembler::isValidLDPFPImm):
+ (JSC::ARM64Assembler::ldp):
+ (JSC::ARM64Assembler::ldnp):
+ (JSC::ARM64Assembler::isValidSTPImm):
+ (JSC::ARM64Assembler::isValidSTPFPImm):
+ (JSC::ARM64Assembler::stp):
+ (JSC::ARM64Assembler::stnp):
+ (JSC::ARM64Assembler::loadStoreRegisterPairPostIndex):
+ (JSC::ARM64Assembler::loadStoreRegisterPairPreIndex):
+ (JSC::ARM64Assembler::loadStoreRegisterPairOffset):
+ (JSC::ARM64Assembler::loadStoreRegisterPairNonTemporal):
+ * assembler/AssemblerCommon.h:
+ (JSC::isValidSignedImm7):
+ * assembler/MacroAssemblerARM64.h:
+ (JSC::MacroAssemblerARM64::loadPair64):
+ (JSC::MacroAssemblerARM64::storePair64):
+ * assembler/testmasm.cpp:
+ (JSC::testLoadStorePair64Int64):
+ (JSC::testLoadStorePair64Double):
+ * disassembler/ARM64/A64DOpcode.cpp:
+ (JSC::ARM64Disassembler::A64DOpcodeLoadStoreRegisterPair::format):
+ * disassembler/ARM64/A64DOpcode.h:
+
2021-06-14 Yijia Huang <yijia_hu...@apple.com>
Add Air opcode sub32/64(Reg, Imm, Reg) form for ARM64 and select this instruction in Air
Modified: trunk/Source/_javascript_Core/assembler/ARM64Assembler.h (278855 => 278856)
--- trunk/Source/_javascript_Core/assembler/ARM64Assembler.h 2021-06-15 01:02:51 UTC (rev 278855)
+++ trunk/Source/_javascript_Core/assembler/ARM64Assembler.h 2021-06-15 01:04:01 UTC (rev 278856)
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012-2020 Apple Inc. All rights reserved.
+ * Copyright (C) 2012-2021 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -1115,6 +1115,20 @@
}
template<int datasize>
+ ALWAYS_INLINE static bool isValidLDPImm(int immediate)
+ {
+ unsigned immedShiftAmount = memPairOffsetShift(false, MEMPAIROPSIZE_INT(datasize));
+ return isValidSignedImm7(immediate, immedShiftAmount);
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE static bool isValidLDPFPImm(int immediate)
+ {
+ unsigned immedShiftAmount = memPairOffsetShift(true, MEMPAIROPSIZE_FP(datasize));
+ return isValidSignedImm7(immediate, immedShiftAmount);
+ }
+
+ template<int datasize>
ALWAYS_INLINE void ldp(RegisterID rt, RegisterID rt2, RegisterID rn, PairPostIndex simm)
{
CHECK_DATASIZE();
@@ -1129,20 +1143,48 @@
}
template<int datasize>
- ALWAYS_INLINE void ldp(RegisterID rt, RegisterID rt2, RegisterID rn, unsigned pimm = 0)
+ ALWAYS_INLINE void ldp(RegisterID rt, RegisterID rt2, RegisterID rn, int simm = 0)
{
CHECK_DATASIZE();
- insn(loadStoreRegisterPairOffset(MEMPAIROPSIZE_INT(datasize), false, MemOp_LOAD, pimm, rn, rt, rt2));
+ insn(loadStoreRegisterPairOffset(MEMPAIROPSIZE_INT(datasize), false, MemOp_LOAD, simm, rn, rt, rt2));
}
template<int datasize>
- ALWAYS_INLINE void ldnp(RegisterID rt, RegisterID rt2, RegisterID rn, unsigned pimm = 0)
+ ALWAYS_INLINE void ldnp(RegisterID rt, RegisterID rt2, RegisterID rn, int simm = 0)
{
CHECK_DATASIZE();
- insn(loadStoreRegisterPairNonTemporal(MEMPAIROPSIZE_INT(datasize), false, MemOp_LOAD, pimm, rn, rt, rt2));
+ insn(loadStoreRegisterPairNonTemporal(MEMPAIROPSIZE_INT(datasize), false, MemOp_LOAD, simm, rn, rt, rt2));
}
template<int datasize>
+ ALWAYS_INLINE void ldp(FPRegisterID rt, FPRegisterID rt2, RegisterID rn, PairPostIndex simm)
+ {
+ CHECK_DATASIZE();
+ insn(loadStoreRegisterPairPostIndex(MEMPAIROPSIZE_FP(datasize), true, MemOp_LOAD, simm, rn, rt, rt2));
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void ldp(FPRegisterID rt, FPRegisterID rt2, RegisterID rn, PairPreIndex simm)
+ {
+ CHECK_DATASIZE();
+ insn(loadStoreRegisterPairPreIndex(MEMPAIROPSIZE_FP(datasize), true, MemOp_LOAD, simm, rn, rt, rt2));
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void ldp(FPRegisterID rt, FPRegisterID rt2, RegisterID rn, int simm = 0)
+ {
+ CHECK_DATASIZE();
+ insn(loadStoreRegisterPairOffset(MEMPAIROPSIZE_FP(datasize), true, MemOp_LOAD, simm, rn, rt, rt2));
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void ldnp(FPRegisterID rt, FPRegisterID rt2, RegisterID rn, int simm = 0)
+ {
+ CHECK_DATASIZE();
+ insn(loadStoreRegisterPairNonTemporal(MEMPAIROPSIZE_FP(datasize), true, MemOp_LOAD, simm, rn, rt, rt2));
+ }
+
+ template<int datasize>
ALWAYS_INLINE void ldr(RegisterID rt, RegisterID rn, RegisterID rm)
{
ldr<datasize>(rt, rn, rm, UXTX, 0);
@@ -1744,6 +1786,18 @@
}
template<int datasize>
+ ALWAYS_INLINE static bool isValidSTPImm(int immediate)
+ {
+ return isValidLDPImm<datasize>(immediate);
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE static bool isValidSTPFPImm(int immediate)
+ {
+ return isValidLDPFPImm<datasize>(immediate);
+ }
+
+ template<int datasize>
ALWAYS_INLINE void stp(RegisterID rt, RegisterID rt2, RegisterID rn, PairPostIndex simm)
{
CHECK_DATASIZE();
@@ -1758,20 +1812,48 @@
}
template<int datasize>
- ALWAYS_INLINE void stp(RegisterID rt, RegisterID rt2, RegisterID rn, unsigned pimm = 0)
+ ALWAYS_INLINE void stp(RegisterID rt, RegisterID rt2, RegisterID rn, int simm = 0)
{
CHECK_DATASIZE();
- insn(loadStoreRegisterPairOffset(MEMPAIROPSIZE_INT(datasize), false, MemOp_STORE, pimm, rn, rt, rt2));
+ insn(loadStoreRegisterPairOffset(MEMPAIROPSIZE_INT(datasize), false, MemOp_STORE, simm, rn, rt, rt2));
}
template<int datasize>
- ALWAYS_INLINE void stnp(RegisterID rt, RegisterID rt2, RegisterID rn, unsigned pimm = 0)
+ ALWAYS_INLINE void stnp(RegisterID rt, RegisterID rt2, RegisterID rn, int simm = 0)
{
CHECK_DATASIZE();
- insn(loadStoreRegisterPairNonTemporal(MEMPAIROPSIZE_INT(datasize), false, MemOp_STORE, pimm, rn, rt, rt2));
+ insn(loadStoreRegisterPairNonTemporal(MEMPAIROPSIZE_INT(datasize), false, MemOp_STORE, simm, rn, rt, rt2));
}
template<int datasize>
+ ALWAYS_INLINE void stp(FPRegisterID rt, FPRegisterID rt2, RegisterID rn, PairPostIndex simm)
+ {
+ CHECK_DATASIZE();
+ insn(loadStoreRegisterPairPostIndex(MEMPAIROPSIZE_FP(datasize), true, MemOp_STORE, simm, rn, rt, rt2));
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void stp(FPRegisterID rt, FPRegisterID rt2, RegisterID rn, PairPreIndex simm)
+ {
+ CHECK_DATASIZE();
+ insn(loadStoreRegisterPairPreIndex(MEMPAIROPSIZE_FP(datasize), true, MemOp_STORE, simm, rn, rt, rt2));
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void stp(FPRegisterID rt, FPRegisterID rt2, RegisterID rn, int simm = 0)
+ {
+ CHECK_DATASIZE();
+ insn(loadStoreRegisterPairOffset(MEMPAIROPSIZE_FP(datasize), true, MemOp_STORE, simm, rn, rt, rt2));
+ }
+
+ template<int datasize>
+ ALWAYS_INLINE void stnp(FPRegisterID rt, FPRegisterID rt2, RegisterID rn, int simm = 0)
+ {
+ CHECK_DATASIZE();
+ insn(loadStoreRegisterPairNonTemporal(MEMPAIROPSIZE_FP(datasize), true, MemOp_STORE, simm, rn, rt, rt2));
+ }
+
+ template<int datasize>
ALWAYS_INLINE void str(RegisterID rt, RegisterID rn, RegisterID rm)
{
str<datasize>(rt, rn, rm, UXTX, 0);
@@ -3544,6 +3626,7 @@
ASSERT(opc == (opc & 1)); // Only load or store, load signed 64 is handled via size.
ASSERT(V || (size != MemPairOp_LoadSigned_32) || (opc == MemOp_LOAD)); // There isn't an integer store signed.
unsigned immedShiftAmount = memPairOffsetShift(V, size);
+ RELEASE_ASSERT(isValidSignedImm7(immediate, immedShiftAmount));
int imm7 = immediate >> immedShiftAmount;
ASSERT((imm7 << immedShiftAmount) == immediate && isInt<7>(imm7));
return (0x28800000 | size << 30 | V << 26 | opc << 22 | (imm7 & 0x7f) << 15 | rt2 << 10 | xOrSp(rn) << 5 | rt);
@@ -3575,6 +3658,7 @@
ASSERT(opc == (opc & 1)); // Only load or store, load signed 64 is handled via size.
ASSERT(V || (size != MemPairOp_LoadSigned_32) || (opc == MemOp_LOAD)); // There isn't an integer store signed.
unsigned immedShiftAmount = memPairOffsetShift(V, size);
+ RELEASE_ASSERT(isValidSignedImm7(immediate, immedShiftAmount));
int imm7 = immediate >> immedShiftAmount;
ASSERT((imm7 << immedShiftAmount) == immediate && isInt<7>(imm7));
return (0x29800000 | size << 30 | V << 26 | opc << 22 | (imm7 & 0x7f) << 15 | rt2 << 10 | xOrSp(rn) << 5 | rt);
@@ -3592,6 +3676,7 @@
ASSERT(opc == (opc & 1)); // Only load or store, load signed 64 is handled via size.
ASSERT(V || (size != MemPairOp_LoadSigned_32) || (opc == MemOp_LOAD)); // There isn't an integer store signed.
unsigned immedShiftAmount = memPairOffsetShift(V, size);
+ RELEASE_ASSERT(isValidSignedImm7(immediate, immedShiftAmount));
int imm7 = immediate >> immedShiftAmount;
ASSERT((imm7 << immedShiftAmount) == immediate && isInt<7>(imm7));
return (0x29000000 | size << 30 | V << 26 | opc << 22 | (imm7 & 0x7f) << 15 | rt2 << 10 | xOrSp(rn) << 5 | rt);
@@ -3609,6 +3694,7 @@
ASSERT(opc == (opc & 1)); // Only load or store, load signed 64 is handled via size.
ASSERT(V || (size != MemPairOp_LoadSigned_32) || (opc == MemOp_LOAD)); // There isn't an integer store signed.
unsigned immedShiftAmount = memPairOffsetShift(V, size);
+ RELEASE_ASSERT(isValidSignedImm7(immediate, immedShiftAmount));
int imm7 = immediate >> immedShiftAmount;
ASSERT((imm7 << immedShiftAmount) == immediate && isInt<7>(imm7));
return (0x28000000 | size << 30 | V << 26 | opc << 22 | (imm7 & 0x7f) << 15 | rt2 << 10 | xOrSp(rn) << 5 | rt);
Modified: trunk/Source/_javascript_Core/assembler/AssemblerCommon.h (278855 => 278856)
--- trunk/Source/_javascript_Core/assembler/AssemblerCommon.h 2021-06-15 01:02:51 UTC (rev 278855)
+++ trunk/Source/_javascript_Core/assembler/AssemblerCommon.h 2021-06-15 01:04:01 UTC (rev 278856)
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012-2019 Apple Inc. All rights reserved.
+ * Copyright (C) 2012-2021 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -74,6 +74,15 @@
return isInt9(value);
}
+ALWAYS_INLINE bool isValidSignedImm7(int32_t value, int alignmentShiftAmount)
+{
+ constexpr int32_t disallowedHighBits = 32 - 7;
+ int32_t shiftedValue = value >> alignmentShiftAmount;
+ bool fitsIn7Bits = shiftedValue == ((shiftedValue << disallowedHighBits) >> disallowedHighBits);
+ bool hasCorrectAlignment = value == (shiftedValue << alignmentShiftAmount);
+ return fitsIn7Bits && hasCorrectAlignment;
+}
+
class ARM64LogicalImmediate {
public:
static ARM64LogicalImmediate create32(uint32_t value)
Modified: trunk/Source/_javascript_Core/assembler/MacroAssemblerARM64.h (278855 => 278856)
--- trunk/Source/_javascript_Core/assembler/MacroAssemblerARM64.h 2021-06-15 01:02:51 UTC (rev 278855)
+++ trunk/Source/_javascript_Core/assembler/MacroAssemblerARM64.h 2021-06-15 01:04:01 UTC (rev 278856)
@@ -1244,6 +1244,16 @@
m_assembler.ldnp<64>(dest1, dest2, src, offset.m_value);
}
+ void loadPair64(RegisterID src, FPRegisterID dest1, FPRegisterID dest2)
+ {
+ loadPair64(src, TrustedImm32(0), dest1, dest2);
+ }
+
+ void loadPair64(RegisterID src, TrustedImm32 offset, FPRegisterID dest1, FPRegisterID dest2)
+ {
+ m_assembler.ldp<64>(dest1, dest2, src, offset.m_value);
+ }
+
void abortWithReason(AbortReason reason)
{
// It is safe to use dataTempRegister directly since this is a crashing JIT Assert.
@@ -1568,6 +1578,16 @@
m_assembler.stnp<64>(src1, src2, dest, offset.m_value);
}
+ void storePair64(FPRegisterID src1, FPRegisterID src2, RegisterID dest)
+ {
+ storePair64(src1, src2, dest, TrustedImm32(0));
+ }
+
+ void storePair64(FPRegisterID src1, FPRegisterID src2, RegisterID dest, TrustedImm32 offset)
+ {
+ m_assembler.stp<64>(src1, src2, dest, offset.m_value);
+ }
+
void store32(RegisterID src, ImplicitAddress address)
{
if (tryStoreWithOffset<32>(src, address.base, address.offset))
Modified: trunk/Source/_javascript_Core/assembler/testmasm.cpp (278855 => 278856)
--- trunk/Source/_javascript_Core/assembler/testmasm.cpp 2021-06-15 01:02:51 UTC (rev 278855)
+++ trunk/Source/_javascript_Core/assembler/testmasm.cpp 2021-06-15 01:04:01 UTC (rev 278856)
@@ -1850,6 +1850,441 @@
#endif // CPU(X86_64) || CPU(ARM64)
+#if CPU(ARM64)
+void testLoadStorePair64Int64()
+{
+ constexpr uint64_t initialValue = 0x5555aaaabbbb8800ull;
+ constexpr uint64_t value1 = 42;
+ constexpr uint64_t value2 = 0xcafebabe12345678ull;
+
+ uint64_t buffer[10];
+
+ auto initBuffer = [&] {
+ for (unsigned i = 0; i < 10; ++i)
+ buffer[i] = initialValue + i;
+ };
+
+ struct Pair {
+ uint64_t value1;
+ uint64_t value2;
+ };
+
+ Pair pair;
+ auto initPair = [&] {
+ pair = { 0, 0 };
+ };
+
+ // Test loadPair64.
+ auto testLoadPair = [] (CCallHelpers& jit, int offset) {
+ emitFunctionPrologue(jit);
+
+ constexpr GPRReg bufferGPR = GPRInfo::argumentGPR0;
+ constexpr GPRReg pairGPR = GPRInfo::argumentGPR1;
+ jit.loadPair64(bufferGPR, CCallHelpers::TrustedImm32(offset * sizeof(CPURegister)), GPRInfo::regT2, GPRInfo::regT3);
+
+ jit.store64(GPRInfo::regT2, CCallHelpers::Address(pairGPR, 0));
+ jit.store64(GPRInfo::regT3, CCallHelpers::Address(pairGPR, sizeof(uint64_t)));
+
+ emitFunctionEpilogue(jit);
+ jit.ret();
+ };
+
+ auto testLoadPair0 = compile([&] (CCallHelpers& jit) {
+ testLoadPair(jit, 0);
+ });
+
+ initBuffer();
+
+ initPair();
+ invoke<void>(testLoadPair0, &buffer[4], &pair);
+ CHECK_EQ(pair.value1, initialValue + 4);
+ CHECK_EQ(pair.value2, initialValue + 5);
+
+ initPair();
+ buffer[4] = value1;
+ buffer[5] = value2;
+ invoke<void>(testLoadPair0, &buffer[4], &pair);
+ CHECK_EQ(pair.value1, value1);
+ CHECK_EQ(pair.value2, value2);
+
+ auto testLoadPairMinus2 = compile([&] (CCallHelpers& jit) {
+ testLoadPair(jit, -2);
+ });
+
+ initPair();
+ invoke<void>(testLoadPairMinus2, &buffer[4], &pair);
+ CHECK_EQ(pair.value1, initialValue + 4 - 2);
+ CHECK_EQ(pair.value2, initialValue + 5 - 2);
+
+ initPair();
+ buffer[4 - 2] = value2;
+ buffer[5 - 2] = value1;
+ invoke<void>(testLoadPairMinus2, &buffer[4], &pair);
+ CHECK_EQ(pair.value1, value2);
+ CHECK_EQ(pair.value2, value1);
+
+ auto testLoadPairPlus3 = compile([&] (CCallHelpers& jit) {
+ testLoadPair(jit, 3);
+ });
+
+ initPair();
+ invoke<void>(testLoadPairPlus3, &buffer[4], &pair);
+ CHECK_EQ(pair.value1, initialValue + 4 + 3);
+ CHECK_EQ(pair.value2, initialValue + 5 + 3);
+
+ initPair();
+ buffer[4 + 3] = value1;
+ buffer[5 + 3] = value2;
+ invoke<void>(testLoadPairPlus3, &buffer[4], &pair);
+ CHECK_EQ(pair.value1, value1);
+ CHECK_EQ(pair.value2, value2);
+
+ // Test storePair64.
+ auto testStorePair = [] (CCallHelpers& jit, int offset) {
+ emitFunctionPrologue(jit);
+
+ constexpr GPRReg bufferGPR = GPRInfo::argumentGPR2;
+ jit.storePair64(GPRInfo::argumentGPR0, GPRInfo::argumentGPR1, bufferGPR, CCallHelpers::TrustedImm32(offset * sizeof(CPURegister)));
+
+ emitFunctionEpilogue(jit);
+ jit.ret();
+ };
+
+ auto testStorePair0 = compile([&] (CCallHelpers& jit) {
+ testStorePair(jit, 0);
+ });
+
+ initBuffer();
+ invoke<void>(testStorePair0, value1, value2, &buffer[4]);
+ CHECK_EQ(buffer[0], initialValue + 0);
+ CHECK_EQ(buffer[1], initialValue + 1);
+ CHECK_EQ(buffer[2], initialValue + 2);
+ CHECK_EQ(buffer[3], initialValue + 3);
+ CHECK_EQ(buffer[4], value1);
+ CHECK_EQ(buffer[5], value2);
+ CHECK_EQ(buffer[6], initialValue + 6);
+ CHECK_EQ(buffer[7], initialValue + 7);
+ CHECK_EQ(buffer[8], initialValue + 8);
+ CHECK_EQ(buffer[9], initialValue + 9);
+
+ auto testStorePairMinus2 = compile([&] (CCallHelpers& jit) {
+ testStorePair(jit, -2);
+ });
+
+ initBuffer();
+ invoke<void>(testStorePairMinus2, value1, value2, &buffer[4]);
+ CHECK_EQ(buffer[0], initialValue + 0);
+ CHECK_EQ(buffer[1], initialValue + 1);
+ CHECK_EQ(buffer[2], value1);
+ CHECK_EQ(buffer[3], value2);
+ CHECK_EQ(buffer[4], initialValue + 4);
+ CHECK_EQ(buffer[5], initialValue + 5);
+ CHECK_EQ(buffer[6], initialValue + 6);
+ CHECK_EQ(buffer[7], initialValue + 7);
+ CHECK_EQ(buffer[8], initialValue + 8);
+ CHECK_EQ(buffer[9], initialValue + 9);
+
+ auto testStorePairPlus3 = compile([&] (CCallHelpers& jit) {
+ testStorePair(jit, 3);
+ });
+
+ initBuffer();
+ invoke<void>(testStorePairPlus3, value1, value2, &buffer[4]);
+ CHECK_EQ(buffer[0], initialValue + 0);
+ CHECK_EQ(buffer[1], initialValue + 1);
+ CHECK_EQ(buffer[2], initialValue + 2);
+ CHECK_EQ(buffer[3], initialValue + 3);
+ CHECK_EQ(buffer[4], initialValue + 4);
+ CHECK_EQ(buffer[5], initialValue + 5);
+ CHECK_EQ(buffer[6], initialValue + 6);
+ CHECK_EQ(buffer[7], value1);
+ CHECK_EQ(buffer[8], value2);
+ CHECK_EQ(buffer[9], initialValue + 9);
+
+ // Test storePair64 from 1 register.
+ auto testStorePairFromOneReg = [] (CCallHelpers& jit, int offset) {
+ emitFunctionPrologue(jit);
+
+ constexpr GPRReg bufferGPR = GPRInfo::argumentGPR1;
+ jit.storePair64(GPRInfo::argumentGPR0, GPRInfo::argumentGPR0, bufferGPR, CCallHelpers::TrustedImm32(offset * sizeof(CPURegister)));
+
+ emitFunctionEpilogue(jit);
+ jit.ret();
+ };
+
+ auto testStorePairFromOneReg0 = compile([&] (CCallHelpers& jit) {
+ testStorePairFromOneReg(jit, 0);
+ });
+
+ initBuffer();
+ invoke<void>(testStorePairFromOneReg0, value2, &buffer[4]);
+ CHECK_EQ(buffer[0], initialValue + 0);
+ CHECK_EQ(buffer[1], initialValue + 1);
+ CHECK_EQ(buffer[2], initialValue + 2);
+ CHECK_EQ(buffer[3], initialValue + 3);
+ CHECK_EQ(buffer[4], value2);
+ CHECK_EQ(buffer[5], value2);
+ CHECK_EQ(buffer[6], initialValue + 6);
+ CHECK_EQ(buffer[7], initialValue + 7);
+ CHECK_EQ(buffer[8], initialValue + 8);
+ CHECK_EQ(buffer[9], initialValue + 9);
+
+ auto testStorePairFromOneRegMinus2 = compile([&] (CCallHelpers& jit) {
+ testStorePairFromOneReg(jit, -2);
+ });
+
+ initBuffer();
+ invoke<void>(testStorePairFromOneRegMinus2, value1, &buffer[4]);
+ CHECK_EQ(buffer[0], initialValue + 0);
+ CHECK_EQ(buffer[1], initialValue + 1);
+ CHECK_EQ(buffer[2], value1);
+ CHECK_EQ(buffer[3], value1);
+ CHECK_EQ(buffer[4], initialValue + 4);
+ CHECK_EQ(buffer[5], initialValue + 5);
+ CHECK_EQ(buffer[6], initialValue + 6);
+ CHECK_EQ(buffer[7], initialValue + 7);
+ CHECK_EQ(buffer[8], initialValue + 8);
+ CHECK_EQ(buffer[9], initialValue + 9);
+
+ auto testStorePairFromOneRegPlus3 = compile([&] (CCallHelpers& jit) {
+ testStorePairFromOneReg(jit, 3);
+ });
+
+ initBuffer();
+ invoke<void>(testStorePairFromOneRegPlus3, value2, &buffer[4]);
+ CHECK_EQ(buffer[0], initialValue + 0);
+ CHECK_EQ(buffer[1], initialValue + 1);
+ CHECK_EQ(buffer[2], initialValue + 2);
+ CHECK_EQ(buffer[3], initialValue + 3);
+ CHECK_EQ(buffer[4], initialValue + 4);
+ CHECK_EQ(buffer[5], initialValue + 5);
+ CHECK_EQ(buffer[6], initialValue + 6);
+ CHECK_EQ(buffer[7], value2);
+ CHECK_EQ(buffer[8], value2);
+ CHECK_EQ(buffer[9], initialValue + 9);
+}
+
+void testLoadStorePair64Double()
+{
+ constexpr double initialValue = 10000.275;
+ constexpr double value1 = 42.89;
+ constexpr double value2 = -555.321;
+
+ double buffer[10];
+
+ auto initBuffer = [&] {
+ for (unsigned i = 0; i < 10; ++i)
+ buffer[i] = initialValue + i;
+ };
+
+ struct Pair {
+ double value1;
+ double value2;
+ };
+
+ Pair pair;
+ auto initPair = [&] {
+ pair = { 0, 0 };
+ };
+
+ // Test loadPair64.
+ auto testLoadPair = [] (CCallHelpers& jit, int offset) {
+ emitFunctionPrologue(jit);
+
+ constexpr GPRReg bufferGPR = GPRInfo::argumentGPR0;
+ constexpr GPRReg pairGPR = GPRInfo::argumentGPR1;
+ jit.loadPair64(bufferGPR, CCallHelpers::TrustedImm32(offset * sizeof(double)), FPRInfo::fpRegT0, FPRInfo::fpRegT1);
+
+ jit.storeDouble(FPRInfo::fpRegT0, CCallHelpers::Address(pairGPR, 0));
+ jit.storeDouble(FPRInfo::fpRegT1, CCallHelpers::Address(pairGPR, sizeof(uint64_t)));
+
+ emitFunctionEpilogue(jit);
+ jit.ret();
+ };
+
+ auto testLoadPair0 = compile([&] (CCallHelpers& jit) {
+ testLoadPair(jit, 0);
+ });
+
+ initBuffer();
+
+ initPair();
+ invoke<void>(testLoadPair0, &buffer[4], &pair);
+ CHECK_EQ(pair.value1, initialValue + 4);
+ CHECK_EQ(pair.value2, initialValue + 5);
+
+ initPair();
+ buffer[4] = value1;
+ buffer[5] = value2;
+ invoke<void>(testLoadPair0, &buffer[4], &pair);
+ CHECK_EQ(pair.value1, value1);
+ CHECK_EQ(pair.value2, value2);
+
+ auto testLoadPairMinus2 = compile([&] (CCallHelpers& jit) {
+ testLoadPair(jit, -2);
+ });
+
+ initPair();
+ invoke<void>(testLoadPairMinus2, &buffer[4], &pair);
+ CHECK_EQ(pair.value1, initialValue + 4 - 2);
+ CHECK_EQ(pair.value2, initialValue + 5 - 2);
+
+ initPair();
+ buffer[4 - 2] = value2;
+ buffer[5 - 2] = value1;
+ invoke<void>(testLoadPairMinus2, &buffer[4], &pair);
+ CHECK_EQ(pair.value1, value2);
+ CHECK_EQ(pair.value2, value1);
+
+ auto testLoadPairPlus3 = compile([&] (CCallHelpers& jit) {
+ testLoadPair(jit, 3);
+ });
+
+ initPair();
+ invoke<void>(testLoadPairPlus3, &buffer[4], &pair);
+ CHECK_EQ(pair.value1, initialValue + 4 + 3);
+ CHECK_EQ(pair.value2, initialValue + 5 + 3);
+
+ initPair();
+ buffer[4 + 3] = value1;
+ buffer[5 + 3] = value2;
+ invoke<void>(testLoadPairPlus3, &buffer[4], &pair);
+ CHECK_EQ(pair.value1, value1);
+ CHECK_EQ(pair.value2, value2);
+
+ // Test storePair64.
+ auto testStorePair = [] (CCallHelpers& jit, int offset) {
+ emitFunctionPrologue(jit);
+
+ constexpr GPRReg bufferGPR = GPRInfo::argumentGPR2;
+ jit.move64ToDouble(GPRInfo::argumentGPR0, FPRInfo::fpRegT0);
+ jit.move64ToDouble(GPRInfo::argumentGPR1, FPRInfo::fpRegT1);
+ jit.storePair64(FPRInfo::fpRegT0, FPRInfo::fpRegT1, bufferGPR, CCallHelpers::TrustedImm32(offset * sizeof(double)));
+
+ emitFunctionEpilogue(jit);
+ jit.ret();
+ };
+
+ auto asInt64 = [] (double value) {
+ return bitwise_cast<int64_t>(value);
+ };
+
+ auto testStorePair0 = compile([&] (CCallHelpers& jit) {
+ testStorePair(jit, 0);
+ });
+
+ initBuffer();
+ invoke<void>(testStorePair0, asInt64(value1), asInt64(value2), &buffer[4]);
+ CHECK_EQ(buffer[0], initialValue + 0);
+ CHECK_EQ(buffer[1], initialValue + 1);
+ CHECK_EQ(buffer[2], initialValue + 2);
+ CHECK_EQ(buffer[3], initialValue + 3);
+ CHECK_EQ(buffer[4], value1);
+ CHECK_EQ(buffer[5], value2);
+ CHECK_EQ(buffer[6], initialValue + 6);
+ CHECK_EQ(buffer[7], initialValue + 7);
+ CHECK_EQ(buffer[8], initialValue + 8);
+ CHECK_EQ(buffer[9], initialValue + 9);
+
+ auto testStorePairMinus2 = compile([&] (CCallHelpers& jit) {
+ testStorePair(jit, -2);
+ });
+
+ initBuffer();
+ invoke<void>(testStorePairMinus2, asInt64(value1), asInt64(value2), &buffer[4]);
+ CHECK_EQ(buffer[0], initialValue + 0);
+ CHECK_EQ(buffer[1], initialValue + 1);
+ CHECK_EQ(buffer[2], value1);
+ CHECK_EQ(buffer[3], value2);
+ CHECK_EQ(buffer[4], initialValue + 4);
+ CHECK_EQ(buffer[5], initialValue + 5);
+ CHECK_EQ(buffer[6], initialValue + 6);
+ CHECK_EQ(buffer[7], initialValue + 7);
+ CHECK_EQ(buffer[8], initialValue + 8);
+ CHECK_EQ(buffer[9], initialValue + 9);
+
+ auto testStorePairPlus3 = compile([&] (CCallHelpers& jit) {
+ testStorePair(jit, 3);
+ });
+
+ initBuffer();
+ invoke<void>(testStorePairPlus3, asInt64(value1), asInt64(value2), &buffer[4]);
+ CHECK_EQ(buffer[0], initialValue + 0);
+ CHECK_EQ(buffer[1], initialValue + 1);
+ CHECK_EQ(buffer[2], initialValue + 2);
+ CHECK_EQ(buffer[3], initialValue + 3);
+ CHECK_EQ(buffer[4], initialValue + 4);
+ CHECK_EQ(buffer[5], initialValue + 5);
+ CHECK_EQ(buffer[6], initialValue + 6);
+ CHECK_EQ(buffer[7], value1);
+ CHECK_EQ(buffer[8], value2);
+ CHECK_EQ(buffer[9], initialValue + 9);
+
+ // Test storePair64 from 1 register.
+ auto testStorePairFromOneReg = [] (CCallHelpers& jit, int offset) {
+ emitFunctionPrologue(jit);
+
+ constexpr GPRReg bufferGPR = GPRInfo::argumentGPR1;
+ jit.move64ToDouble(GPRInfo::argumentGPR0, FPRInfo::fpRegT0);
+ jit.storePair64(FPRInfo::fpRegT0, FPRInfo::fpRegT0, bufferGPR, CCallHelpers::TrustedImm32(offset * sizeof(double)));
+
+ emitFunctionEpilogue(jit);
+ jit.ret();
+ };
+
+ auto testStorePairFromOneReg0 = compile([&] (CCallHelpers& jit) {
+ testStorePairFromOneReg(jit, 0);
+ });
+
+ initBuffer();
+ invoke<void>(testStorePairFromOneReg0, asInt64(value2), &buffer[4]);
+ CHECK_EQ(buffer[0], initialValue + 0);
+ CHECK_EQ(buffer[1], initialValue + 1);
+ CHECK_EQ(buffer[2], initialValue + 2);
+ CHECK_EQ(buffer[3], initialValue + 3);
+ CHECK_EQ(buffer[4], value2);
+ CHECK_EQ(buffer[5], value2);
+ CHECK_EQ(buffer[6], initialValue + 6);
+ CHECK_EQ(buffer[7], initialValue + 7);
+ CHECK_EQ(buffer[8], initialValue + 8);
+ CHECK_EQ(buffer[9], initialValue + 9);
+
+ auto testStorePairFromOneRegMinus2 = compile([&] (CCallHelpers& jit) {
+ testStorePairFromOneReg(jit, -2);
+ });
+
+ initBuffer();
+ invoke<void>(testStorePairFromOneRegMinus2, asInt64(value1), &buffer[4]);
+ CHECK_EQ(buffer[0], initialValue + 0);
+ CHECK_EQ(buffer[1], initialValue + 1);
+ CHECK_EQ(buffer[2], value1);
+ CHECK_EQ(buffer[3], value1);
+ CHECK_EQ(buffer[4], initialValue + 4);
+ CHECK_EQ(buffer[5], initialValue + 5);
+ CHECK_EQ(buffer[6], initialValue + 6);
+ CHECK_EQ(buffer[7], initialValue + 7);
+ CHECK_EQ(buffer[8], initialValue + 8);
+ CHECK_EQ(buffer[9], initialValue + 9);
+
+ auto testStorePairFromOneRegPlus3 = compile([&] (CCallHelpers& jit) {
+ testStorePairFromOneReg(jit, 3);
+ });
+
+ initBuffer();
+ invoke<void>(testStorePairFromOneRegPlus3, asInt64(value2), &buffer[4]);
+ CHECK_EQ(buffer[0], initialValue + 0);
+ CHECK_EQ(buffer[1], initialValue + 1);
+ CHECK_EQ(buffer[2], initialValue + 2);
+ CHECK_EQ(buffer[3], initialValue + 3);
+ CHECK_EQ(buffer[4], initialValue + 4);
+ CHECK_EQ(buffer[5], initialValue + 5);
+ CHECK_EQ(buffer[6], initialValue + 6);
+ CHECK_EQ(buffer[7], value2);
+ CHECK_EQ(buffer[8], value2);
+ CHECK_EQ(buffer[9], initialValue + 9);
+}
+#endif // CPU(ARM64)
+
void testProbeReadsArgumentRegisters()
{
bool probeWasCalled = false;
@@ -2761,6 +3196,8 @@
#endif
#if CPU(ARM64)
+ RUN(testLoadStorePair64Int64());
+ RUN(testLoadStorePair64Double());
RUN(testMul32SignExtend());
RUN(testSub32Args());
RUN(testSub32Imm());
Modified: trunk/Source/_javascript_Core/disassembler/ARM64/A64DOpcode.cpp (278855 => 278856)
--- trunk/Source/_javascript_Core/disassembler/ARM64/A64DOpcode.cpp 2021-06-15 01:02:51 UTC (rev 278855)
+++ trunk/Source/_javascript_Core/disassembler/ARM64/A64DOpcode.cpp 2021-06-15 01:04:01 UTC (rev 278856)
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012, 2016 Apple Inc. All rights reserved.
+ * Copyright (C) 2012-2021 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -72,6 +72,8 @@
OPCODE_GROUP_ENTRY(0x0a, A64DOpcodeLogicalShiftedRegister),
OPCODE_GROUP_ENTRY(0x0b, A64DOpcodeAddSubtractExtendedRegister),
OPCODE_GROUP_ENTRY(0x0b, A64DOpcodeAddSubtractShiftedRegister),
+ OPCODE_GROUP_ENTRY(0x0c, A64DOpcodeLoadStoreRegisterPair),
+ OPCODE_GROUP_ENTRY(0x0d, A64DOpcodeLoadStoreRegisterPair),
OPCODE_GROUP_ENTRY(0x11, A64DOpcodeAddSubtractImmediate),
OPCODE_GROUP_ENTRY(0x12, A64DOpcodeMoveWide),
OPCODE_GROUP_ENTRY(0x12, A64DOpcodeLogicalImmediate),
@@ -1363,9 +1365,9 @@
appendInstructionName(thisOpName);
unsigned offsetShift;
if (vBit()) {
- appendFPRegisterName(rt(), size());
+ appendFPRegisterName(rt(), size() + 2);
appendSeparator();
- appendFPRegisterName(rt2(), size());
+ appendFPRegisterName(rt2(), size() + 2);
offsetShift = size() + 2;
} else {
if (!lBit())
Modified: trunk/Source/_javascript_Core/disassembler/ARM64/A64DOpcode.h (278855 => 278856)
--- trunk/Source/_javascript_Core/disassembler/ARM64/A64DOpcode.h 2021-06-15 01:02:51 UTC (rev 278855)
+++ trunk/Source/_javascript_Core/disassembler/ARM64/A64DOpcode.h 2021-06-15 01:04:01 UTC (rev 278856)
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012-2019 Apple Inc. All rights reserved.
+ * Copyright (C) 2012-2021 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -787,7 +787,7 @@
class A64DOpcodeLoadStoreRegisterPair : public A64DOpcodeLoadStore {
public:
- static constexpr uint32_t mask = 0x3a000000;
+ static constexpr uint32_t mask = 0x38000000;
static constexpr uint32_t pattern = 0x28000000;
DEFINE_STATIC_FORMAT(A64DOpcodeLoadStoreRegisterPair, thisObj);