Title: [280578] trunk/Source/_javascript_Core
Revision
280578
Author
ysuz...@apple.com
Date
2021-08-02 18:45:11 -0700 (Mon, 02 Aug 2021)

Log Message

[JSC] Use loadPair / storePair in YarrJIT
https://bugs.webkit.org/show_bug.cgi?id=228687

Reviewed by Mark Lam.

Use loadPair / storePair if possible in YarrJIT. Currently, we are not
deploying Spooler in YarrJIT, but we should do that in the future too.

In this patch, we also add appropriate fallback code in loadPair / storePair:
the offset of these functions are small enough so that we should consider
overflowing case. If it overflows, we use two loads or stores.

This patch also adds loadPair32 and storePair32 to all macro assembler so that
we can call it without CPU(ARM64). Internally, two loads or stores are combined.

* assembler/MacroAssemblerARM64.h:
(JSC::MacroAssemblerARM64::loadPair32):
(JSC::MacroAssemblerARM64::loadPair64):
(JSC::MacroAssemblerARM64::loadPair64WithNonTemporalAccess):
(JSC::MacroAssemblerARM64::storePair32):
(JSC::MacroAssemblerARM64::storePair64):
(JSC::MacroAssemblerARM64::storePair64WithNonTemporalAccess):
* assembler/MacroAssemblerARMv7.h:
(JSC::MacroAssemblerARMv7::loadPair32):
(JSC::MacroAssemblerARMv7::storePair32):
* assembler/MacroAssemblerMIPS.h:
(JSC::MacroAssemblerMIPS::loadPair32):
(JSC::MacroAssemblerMIPS::storePair32):
* assembler/MacroAssemblerX86Common.h:
(JSC::MacroAssemblerX86Common::loadPair32):
(JSC::MacroAssemblerX86Common::storePair32):
* assembler/testmasm.cpp:
(JSC::testLoadStorePair32):
(JSC::testLoadStorePair64Int64):
* yarr/YarrJIT.cpp:

Modified Paths

Diff

Modified: trunk/Source/_javascript_Core/ChangeLog (280577 => 280578)


--- trunk/Source/_javascript_Core/ChangeLog	2021-08-03 01:11:27 UTC (rev 280577)
+++ trunk/Source/_javascript_Core/ChangeLog	2021-08-03 01:45:11 UTC (rev 280578)
@@ -1,5 +1,43 @@
 2021-08-02  Yusuke Suzuki  <ysuz...@apple.com>
 
+        [JSC] Use loadPair / storePair in YarrJIT
+        https://bugs.webkit.org/show_bug.cgi?id=228687
+
+        Reviewed by Mark Lam.
+
+        Use loadPair / storePair if possible in YarrJIT. Currently, we are not
+        deploying Spooler in YarrJIT, but we should do that in the future too.
+
+        In this patch, we also add appropriate fallback code in loadPair / storePair:
+        the offset of these functions are small enough so that we should consider
+        overflowing case. If it overflows, we use two loads or stores.
+
+        This patch also adds loadPair32 and storePair32 to all macro assembler so that
+        we can call it without CPU(ARM64). Internally, two loads or stores are combined.
+
+        * assembler/MacroAssemblerARM64.h:
+        (JSC::MacroAssemblerARM64::loadPair32):
+        (JSC::MacroAssemblerARM64::loadPair64):
+        (JSC::MacroAssemblerARM64::loadPair64WithNonTemporalAccess):
+        (JSC::MacroAssemblerARM64::storePair32):
+        (JSC::MacroAssemblerARM64::storePair64):
+        (JSC::MacroAssemblerARM64::storePair64WithNonTemporalAccess):
+        * assembler/MacroAssemblerARMv7.h:
+        (JSC::MacroAssemblerARMv7::loadPair32):
+        (JSC::MacroAssemblerARMv7::storePair32):
+        * assembler/MacroAssemblerMIPS.h:
+        (JSC::MacroAssemblerMIPS::loadPair32):
+        (JSC::MacroAssemblerMIPS::storePair32):
+        * assembler/MacroAssemblerX86Common.h:
+        (JSC::MacroAssemblerX86Common::loadPair32):
+        (JSC::MacroAssemblerX86Common::storePair32):
+        * assembler/testmasm.cpp:
+        (JSC::testLoadStorePair32):
+        (JSC::testLoadStorePair64Int64):
+        * yarr/YarrJIT.cpp:
+
+2021-08-02  Yusuke Suzuki  <ysuz...@apple.com>
+
         Unreviewed, fix accidental narrowing
         https://bugs.webkit.org/show_bug.cgi?id=228613
 

Modified: trunk/Source/_javascript_Core/assembler/MacroAssemblerARM64.h (280577 => 280578)


--- trunk/Source/_javascript_Core/assembler/MacroAssemblerARM64.h	2021-08-03 01:11:27 UTC (rev 280577)
+++ trunk/Source/_javascript_Core/assembler/MacroAssemblerARM64.h	2021-08-03 01:45:11 UTC (rev 280578)
@@ -1473,6 +1473,27 @@
         return label;
     }
 
+    void loadPair32(RegisterID src, RegisterID dest1, RegisterID dest2)
+    {
+        loadPair32(src, TrustedImm32(0), dest1, dest2);
+    }
+
+    void loadPair32(RegisterID src, TrustedImm32 offset, RegisterID dest1, RegisterID dest2)
+    {
+        ASSERT(dest1 != dest2); // If it is the same, ldp becomes illegal instruction.
+        if (ARM64Assembler::isValidLDPImm<32>(offset.m_value)) {
+            m_assembler.ldp<32>(dest1, dest2, src, offset.m_value);
+            return;
+        }
+        if (src == dest1) {
+            load32(Address(src, offset.m_value + 4), dest2);
+            load32(Address(src, offset.m_value), dest1);
+        } else {
+            load32(Address(src, offset.m_value), dest1);
+            load32(Address(src, offset.m_value + 4), dest2);
+        }
+    }
+
     void loadPair64(RegisterID src, RegisterID dest1, RegisterID dest2)
     {
         loadPair64(src, TrustedImm32(0), dest1, dest2);
@@ -1480,7 +1501,18 @@
 
     void loadPair64(RegisterID src, TrustedImm32 offset, RegisterID dest1, RegisterID dest2)
     {
-        m_assembler.ldp<64>(dest1, dest2, src, offset.m_value);
+        ASSERT(dest1 != dest2); // If it is the same, ldp becomes illegal instruction.
+        if (ARM64Assembler::isValidLDPImm<64>(offset.m_value)) {
+            m_assembler.ldp<64>(dest1, dest2, src, offset.m_value);
+            return;
+        }
+        if (src == dest1) {
+            load64(Address(src, offset.m_value + 8), dest2);
+            load64(Address(src, offset.m_value), dest1);
+        } else {
+            load64(Address(src, offset.m_value), dest1);
+            load64(Address(src, offset.m_value + 8), dest2);
+        }
     }
 
     void loadPair64WithNonTemporalAccess(RegisterID src, RegisterID dest1, RegisterID dest2)
@@ -1490,7 +1522,18 @@
 
     void loadPair64WithNonTemporalAccess(RegisterID src, TrustedImm32 offset, RegisterID dest1, RegisterID dest2)
     {
-        m_assembler.ldnp<64>(dest1, dest2, src, offset.m_value);
+        ASSERT(dest1 != dest2); // If it is the same, ldp becomes illegal instruction.
+        if (ARM64Assembler::isValidLDPImm<64>(offset.m_value)) {
+            m_assembler.ldnp<64>(dest1, dest2, src, offset.m_value);
+            return;
+        }
+        if (src == dest1) {
+            load64(Address(src, offset.m_value + 8), dest2);
+            load64(Address(src, offset.m_value), dest1);
+        } else {
+            load64(Address(src, offset.m_value), dest1);
+            load64(Address(src, offset.m_value + 8), dest2);
+        }
     }
 
     void loadPair64(RegisterID src, FPRegisterID dest1, FPRegisterID dest2)
@@ -1500,7 +1543,13 @@
 
     void loadPair64(RegisterID src, TrustedImm32 offset, FPRegisterID dest1, FPRegisterID dest2)
     {
-        m_assembler.ldp<64>(dest1, dest2, src, offset.m_value);
+        ASSERT(dest1 != dest2); // If it is the same, ldp becomes illegal instruction.
+        if (ARM64Assembler::isValidLDPFPImm<64>(offset.m_value)) {
+            m_assembler.ldp<64>(dest1, dest2, src, offset.m_value);
+            return;
+        }
+        loadDouble(Address(src, offset.m_value), dest1);
+        loadDouble(Address(src, offset.m_value + 8), dest2);
     }
 
     void abortWithReason(AbortReason reason)
@@ -1824,6 +1873,21 @@
         return label;
     }
 
+    void storePair32(RegisterID src1, RegisterID src2, RegisterID dest)
+    {
+        storePair32(src1, src2, dest, TrustedImm32(0));
+    }
+
+    void storePair32(RegisterID src1, RegisterID src2, RegisterID dest, TrustedImm32 offset)
+    {
+        if (ARM64Assembler::isValidSTPImm<32>(offset.m_value)) {
+            m_assembler.stp<32>(src1, src2, dest, offset.m_value);
+            return;
+        }
+        store32(src1, Address(dest, offset.m_value));
+        store32(src2, Address(dest, offset.m_value + 4));
+    }
+
     void storePair64(RegisterID src1, RegisterID src2, RegisterID dest)
     {
         storePair64(src1, src2, dest, TrustedImm32(0));
@@ -1831,7 +1895,12 @@
 
     void storePair64(RegisterID src1, RegisterID src2, RegisterID dest, TrustedImm32 offset)
     {
-        m_assembler.stp<64>(src1, src2, dest, offset.m_value);
+        if (ARM64Assembler::isValidSTPImm<64>(offset.m_value)) {
+            m_assembler.stp<64>(src1, src2, dest, offset.m_value);
+            return;
+        }
+        store64(src1, Address(dest, offset.m_value));
+        store64(src2, Address(dest, offset.m_value + 8));
     }
 
     void storePair64WithNonTemporalAccess(RegisterID src1, RegisterID src2, RegisterID dest)
@@ -1841,7 +1910,12 @@
 
     void storePair64WithNonTemporalAccess(RegisterID src1, RegisterID src2, RegisterID dest, TrustedImm32 offset)
     {
-        m_assembler.stnp<64>(src1, src2, dest, offset.m_value);
+        if (ARM64Assembler::isValidSTPImm<64>(offset.m_value)) {
+            m_assembler.stnp<64>(src1, src2, dest, offset.m_value);
+            return;
+        }
+        store64(src1, Address(dest, offset.m_value));
+        store64(src2, Address(dest, offset.m_value + 8));
     }
 
     void storePair64(FPRegisterID src1, FPRegisterID src2, RegisterID dest)
@@ -1851,7 +1925,12 @@
 
     void storePair64(FPRegisterID src1, FPRegisterID src2, RegisterID dest, TrustedImm32 offset)
     {
-        m_assembler.stp<64>(src1, src2, dest, offset.m_value);
+        if (ARM64Assembler::isValidSTPFPImm<64>(offset.m_value)) {
+            m_assembler.stp<64>(src1, src2, dest, offset.m_value);
+            return;
+        }
+        storeDouble(src1, Address(dest, offset.m_value));
+        storeDouble(src2, Address(dest, offset.m_value + 8));
     }
 
     void store32(RegisterID src, ImplicitAddress address)

Modified: trunk/Source/_javascript_Core/assembler/MacroAssemblerARMv7.h (280577 => 280578)


--- trunk/Source/_javascript_Core/assembler/MacroAssemblerARMv7.h	2021-08-03 01:11:27 UTC (rev 280577)
+++ trunk/Source/_javascript_Core/assembler/MacroAssemblerARMv7.h	2021-08-03 01:45:11 UTC (rev 280578)
@@ -867,6 +867,24 @@
         UNREACHABLE_FOR_PLATFORM();
     }
 
+    void loadPair32(RegisterID src, RegisterID dest1, RegisterID dest2)
+    {
+        loadPair32(src, TrustedImm32(0), dest1, dest2);
+    }
+
+    void loadPair32(RegisterID src, TrustedImm32 offset, RegisterID dest1, RegisterID dest2)
+    {
+        // FIXME: ldrd/ldm can be used if dest1 and dest2 are consecutive pair of registers.
+        ASSERT(dest1 != dest2); // If it is the same, ldp becomes illegal instruction.
+        if (src == dest1) {
+            load32(Address(src, offset.m_value + 4), dest2);
+            load32(Address(src, offset.m_value), dest1);
+        } else {
+            load32(Address(src, offset.m_value), dest1);
+            load32(Address(src, offset.m_value + 4), dest2);
+        }
+    }
+
     DataLabel32 store32WithAddressOffsetPatch(RegisterID src, Address address)
     {
         DataLabel32 label = moveWithPatch(TrustedImm32(address.offset), dataTempRegister);
@@ -965,6 +983,18 @@
         store16(dataTempRegister, address);
     }
 
+    void storePair32(RegisterID src1, RegisterID src2, RegisterID dest)
+    {
+        storePair32(src1, src2, dest, TrustedImm32(0));
+    }
+
+    void storePair32(RegisterID src1, RegisterID src2, RegisterID dest, TrustedImm32 offset)
+    {
+        // FIXME: strd/stm can be used if src1 and src2 are consecutive pair of registers.
+        store32(src1, Address(dest, offset.m_value));
+        store32(src2, Address(dest, offset.m_value + 4));
+    }
+
     // Possibly clobbers src, but not on this architecture.
     void moveDoubleToInts(FPRegisterID src, RegisterID dest1, RegisterID dest2)
     {

Modified: trunk/Source/_javascript_Core/assembler/MacroAssemblerMIPS.h (280577 => 280578)


--- trunk/Source/_javascript_Core/assembler/MacroAssemblerMIPS.h	2021-08-03 01:11:27 UTC (rev 280577)
+++ trunk/Source/_javascript_Core/assembler/MacroAssemblerMIPS.h	2021-08-03 01:45:11 UTC (rev 280578)
@@ -1293,6 +1293,23 @@
         }
     }
 
+    void loadPair32(RegisterID src, RegisterID dest1, RegisterID dest2)
+    {
+        loadPair32(src, TrustedImm32(0), dest1, dest2);
+    }
+
+    void loadPair32(RegisterID src, TrustedImm32 offset, RegisterID dest1, RegisterID dest2)
+    {
+        ASSERT(dest1 != dest2); // If it is the same, ldp becomes illegal instruction.
+        if (src == dest1) {
+            load32(Address(src, offset.m_value + 4), dest2);
+            load32(Address(src, offset.m_value), dest1);
+        } else {
+            load32(Address(src, offset.m_value), dest1);
+            load32(Address(src, offset.m_value + 4), dest2);
+        }
+    }
+
     DataLabel32 store32WithAddressOffsetPatch(RegisterID src, Address address)
     {
         m_fixedWidth = true;
@@ -1586,6 +1603,17 @@
         }
     }
 
+    void storePair32(RegisterID src1, RegisterID src2, RegisterID dest)
+    {
+        storePair32(src1, src2, dest, TrustedImm32(0));
+    }
+
+    void storePair32(RegisterID src1, RegisterID src2, RegisterID dest, TrustedImm32 offset)
+    {
+        store32(src1, Address(dest, offset.m_value));
+        store32(src2, Address(dest, offset.m_value + 4));
+    }
+
     // Floating-point operations:
 
     static bool supportsFloatingPoint()

Modified: trunk/Source/_javascript_Core/assembler/MacroAssemblerX86Common.h (280577 => 280578)


--- trunk/Source/_javascript_Core/assembler/MacroAssemblerX86Common.h	2021-08-03 01:11:27 UTC (rev 280577)
+++ trunk/Source/_javascript_Core/assembler/MacroAssemblerX86Common.h	2021-08-03 01:45:11 UTC (rev 280578)
@@ -1300,6 +1300,23 @@
         m_assembler.movswl_mr(address.offset, address.base, dest);
     }
 
+    void loadPair32(RegisterID src, RegisterID dest1, RegisterID dest2)
+    {
+        loadPair32(src, TrustedImm32(0), dest1, dest2);
+    }
+
+    void loadPair32(RegisterID src, TrustedImm32 offset, RegisterID dest1, RegisterID dest2)
+    {
+        ASSERT(dest1 != dest2); // If it is the same, ldp becomes illegal instruction.
+        if (src == dest1) {
+            load32(Address(src, offset.m_value + 4), dest2);
+            load32(Address(src, offset.m_value), dest1);
+        } else {
+            load32(Address(src, offset.m_value), dest1);
+            load32(Address(src, offset.m_value + 4), dest2);
+        }
+    }
+
     void zeroExtend16To32(RegisterID src, RegisterID dest)
     {
         m_assembler.movzwl_rr(src, dest);
@@ -1349,6 +1366,17 @@
         m_assembler.movb_i8m(imm8.m_value, address.offset, address.base, address.index, address.scale);
     }
 
+    void storePair32(RegisterID src1, RegisterID src2, RegisterID dest)
+    {
+        storePair32(src1, src2, dest, TrustedImm32(0));
+    }
+
+    void storePair32(RegisterID src1, RegisterID src2, RegisterID dest, TrustedImm32 offset)
+    {
+        store32(src1, Address(dest, offset.m_value));
+        store32(src2, Address(dest, offset.m_value + 4));
+    }
+
     static ALWAYS_INLINE RegisterID getUnusedRegister(BaseIndex address)
     {
         if (address.base != X86Registers::eax && address.index != X86Registers::eax)

Modified: trunk/Source/_javascript_Core/assembler/testmasm.cpp (280577 => 280578)


--- trunk/Source/_javascript_Core/assembler/testmasm.cpp	2021-08-03 01:11:27 UTC (rev 280577)
+++ trunk/Source/_javascript_Core/assembler/testmasm.cpp	2021-08-03 01:45:11 UTC (rev 280578)
@@ -3236,6 +3236,245 @@
 
 #endif // CPU(ARM64)
 
+void testLoadStorePair32()
+{
+    constexpr uint32_t initialValue = 0x55aabb80u;
+    constexpr uint32_t value1 = 42;
+    constexpr uint32_t value2 = 0xcfbb1357u;
+
+    uint32_t buffer[10];
+
+    auto initBuffer = [&] {
+        for (unsigned i = 0; i < 10; ++i)
+            buffer[i] = initialValue + i;
+    };
+
+    struct Pair {
+        uint32_t value1;
+        uint32_t value2;
+    };
+
+    Pair pair;
+    auto initPair = [&] {
+        pair = { 0, 0 };
+    };
+
+    // Test loadPair32.
+    auto testLoadPair = [] (CCallHelpers& jit, int offset) {
+        emitFunctionPrologue(jit);
+
+        constexpr GPRReg bufferGPR = GPRInfo::argumentGPR0;
+        constexpr GPRReg pairGPR = GPRInfo::argumentGPR1;
+        jit.loadPair32(bufferGPR, CCallHelpers::TrustedImm32(offset * sizeof(uint32_t)), GPRInfo::regT2, GPRInfo::regT3);
+
+        jit.store32(GPRInfo::regT2, CCallHelpers::Address(pairGPR, 0));
+        jit.store32(GPRInfo::regT3, CCallHelpers::Address(pairGPR, sizeof(uint32_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 loadPair32 using a buffer register as a destination.
+    auto testLoadPairUsingBufferRegisterAsDestination = [] (CCallHelpers& jit, int offset) {
+        emitFunctionPrologue(jit);
+
+        constexpr GPRReg bufferGPR = GPRInfo::argumentGPR0;
+        constexpr GPRReg pairGPR = GPRInfo::argumentGPR1;
+        jit.loadPair32(bufferGPR, CCallHelpers::TrustedImm32(offset * sizeof(uint32_t)), GPRInfo::argumentGPR0, GPRInfo::regT2);
+
+        jit.store32(GPRInfo::argumentGPR0, CCallHelpers::Address(pairGPR, 0));
+        jit.store32(GPRInfo::regT2, CCallHelpers::Address(pairGPR, sizeof(uint32_t)));
+
+        emitFunctionEpilogue(jit);
+        jit.ret();
+    };
+
+    auto testLoadPairUsingBufferRegisterAsDestination0 = compile([&] (CCallHelpers& jit) {
+        testLoadPairUsingBufferRegisterAsDestination(jit, 0);
+    });
+
+    initBuffer();
+
+    initPair();
+    invoke<void>(testLoadPairUsingBufferRegisterAsDestination0, &buffer[4], &pair);
+    CHECK_EQ(pair.value1, initialValue + 4);
+    CHECK_EQ(pair.value2, initialValue + 5);
+
+    // Test storePair32.
+    auto testStorePair = [] (CCallHelpers& jit, int offset) {
+        emitFunctionPrologue(jit);
+
+        constexpr GPRReg bufferGPR = GPRInfo::argumentGPR2;
+        jit.storePair32(GPRInfo::argumentGPR0, GPRInfo::argumentGPR1, bufferGPR, CCallHelpers::TrustedImm32(offset * sizeof(unsigned)));
+
+        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 storePair32 from 1 register.
+    auto testStorePairFromOneReg = [] (CCallHelpers& jit, int offset) {
+        emitFunctionPrologue(jit);
+
+        constexpr GPRReg bufferGPR = GPRInfo::argumentGPR1;
+        jit.storePair32(GPRInfo::argumentGPR0, GPRInfo::argumentGPR0, bufferGPR, CCallHelpers::TrustedImm32(offset * sizeof(unsigned)));
+
+        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);
+}
+
 #if CPU(ARM64)
 void testLoadStorePair64Int64()
 {
@@ -3325,6 +3564,32 @@
     CHECK_EQ(pair.value1, value1);
     CHECK_EQ(pair.value2, value2);
 
+    // Test loadPair64 using a buffer register as a destination.
+    auto testLoadPairUsingBufferRegisterAsDestination = [] (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::argumentGPR0, GPRInfo::regT2);
+
+        jit.store64(GPRInfo::argumentGPR0, CCallHelpers::Address(pairGPR, 0));
+        jit.store64(GPRInfo::regT2, CCallHelpers::Address(pairGPR, sizeof(uint64_t)));
+
+        emitFunctionEpilogue(jit);
+        jit.ret();
+    };
+
+    auto testLoadPairUsingBufferRegisterAsDestination0 = compile([&] (CCallHelpers& jit) {
+        testLoadPairUsingBufferRegisterAsDestination(jit, 0);
+    });
+
+    initBuffer();
+
+    initPair();
+    invoke<void>(testLoadPairUsingBufferRegisterAsDestination0, &buffer[4], &pair);
+    CHECK_EQ(pair.value1, initialValue + 4);
+    CHECK_EQ(pair.value2, initialValue + 5);
+
     // Test storePair64.
     auto testStorePair = [] (CCallHelpers& jit, int offset) {
         emitFunctionPrologue(jit);
@@ -4891,6 +5156,7 @@
     FOR_EACH_DOUBLE_CONDITION_RUN(testCompareDoubleSameArg);
 
     RUN(testMul32WithImmediates());
+    RUN(testLoadStorePair32());
 
 #if CPU(X86_64)
     RUN(testBranchTestBit32RegReg());

Modified: trunk/Source/_javascript_Core/yarr/YarrJIT.cpp (280577 => 280578)


--- trunk/Source/_javascript_Core/yarr/YarrJIT.cpp	2021-08-03 01:11:27 UTC (rev 280577)
+++ trunk/Source/_javascript_Core/yarr/YarrJIT.cpp	2021-08-03 01:45:11 UTC (rev 280578)
@@ -299,8 +299,10 @@
 
     struct ParenContext {
         struct ParenContext* next;
-        uint32_t begin;
-        uint32_t matchAmount;
+        struct BeginAndMatchAmount {
+            uint32_t begin;
+            uint32_t matchAmount;
+        } beginAndMatchAmount;
         uintptr_t returnAddress;
         struct Subpatterns {
             unsigned start;
@@ -313,27 +315,27 @@
             return sizeof(ParenContext) + sizeof(Subpatterns) * parenContextSizes.numSubpatterns() + sizeof(uintptr_t) * parenContextSizes.frameSlots();
         }
 
-        static ptrdiff_t nextOffset()
+        static constexpr ptrdiff_t nextOffset()
         {
             return offsetof(ParenContext, next);
         }
 
-        static ptrdiff_t beginOffset()
+        static constexpr ptrdiff_t beginOffset()
         {
-            return offsetof(ParenContext, begin);
+            return offsetof(ParenContext, beginAndMatchAmount) + offsetof(BeginAndMatchAmount, begin);
         }
 
-        static ptrdiff_t matchAmountOffset()
+        static constexpr ptrdiff_t matchAmountOffset()
         {
-            return offsetof(ParenContext, matchAmount);
+            return offsetof(ParenContext, beginAndMatchAmount) + offsetof(BeginAndMatchAmount, matchAmount);
         }
 
-        static ptrdiff_t returnAddressOffset()
+        static constexpr ptrdiff_t returnAddressOffset()
         {
             return offsetof(ParenContext, returnAddress);
         }
 
-        static ptrdiff_t subpatternOffset(size_t subpattern)
+        static constexpr ptrdiff_t subpatternOffset(size_t subpattern)
         {
             return offsetof(ParenContext, subpatterns) + (subpattern - 1) * sizeof(Subpatterns);
         }
@@ -395,17 +397,30 @@
         move(headPtrRegister, freelistRegister);
     }
 
+
+    void storeBeginAndMatchAmountToParenContext(RegisterID beginGPR, RegisterID matchAmountGPR, RegisterID parenContextGPR)
+    {
+        static_assert(ParenContext::beginOffset() + 4 == ParenContext::matchAmountOffset());
+        storePair32(beginGPR, matchAmountGPR, parenContextGPR, TrustedImm32(ParenContext::beginOffset()));
+    }
+
+    void loadBeginAndMatchAmountFromParenContext(RegisterID parenContextGPR, RegisterID beginGPR, RegisterID matchAmountGPR)
+    {
+        static_assert(ParenContext::beginOffset() + 4 == ParenContext::matchAmountOffset());
+        loadPair32(parenContextGPR, TrustedImm32(ParenContext::beginOffset()), beginGPR, matchAmountGPR);
+    }
+
     void saveParenContext(RegisterID parenContextReg, RegisterID tempReg, unsigned firstSubpattern, unsigned lastSubpattern, unsigned subpatternBaseFrameLocation)
     {
-        store32(index, Address(parenContextReg, ParenContext::beginOffset()));
         loadFromFrame(subpatternBaseFrameLocation + BackTrackInfoParentheses::matchAmountIndex(), tempReg);
-        store32(tempReg, Address(parenContextReg, ParenContext::matchAmountOffset()));
+        storeBeginAndMatchAmountToParenContext(index, tempReg, parenContextReg);
         loadFromFrame(subpatternBaseFrameLocation + BackTrackInfoParentheses::returnAddressIndex(), tempReg);
         storePtr(tempReg, Address(parenContextReg, ParenContext::returnAddressOffset()));
         if (m_compileMode == JITCompileMode::IncludeSubpatterns) {
             for (unsigned subpattern = firstSubpattern; subpattern <= lastSubpattern; subpattern++) {
-                loadPtr(Address(output, (subpattern << 1) * sizeof(unsigned)), tempReg);
-                storePtr(tempReg, Address(parenContextReg, ParenContext::subpatternOffset(subpattern)));
+                static_assert(is64Bit());
+                load64(Address(output, (subpattern << 1) * sizeof(unsigned)), tempReg);
+                store64(tempReg, Address(parenContextReg, ParenContext::subpatternOffset(subpattern)));
                 clearSubpatternStart(subpattern);
             }
         }
@@ -418,16 +433,16 @@
 
     void restoreParenContext(RegisterID parenContextReg, RegisterID tempReg, unsigned firstSubpattern, unsigned lastSubpattern, unsigned subpatternBaseFrameLocation)
     {
-        load32(Address(parenContextReg, ParenContext::beginOffset()), index);
+        loadBeginAndMatchAmountFromParenContext(parenContextReg, index, tempReg);
         storeToFrame(index, subpatternBaseFrameLocation + BackTrackInfoParentheses::beginIndex());
-        load32(Address(parenContextReg, ParenContext::matchAmountOffset()), tempReg);
         storeToFrame(tempReg, subpatternBaseFrameLocation + BackTrackInfoParentheses::matchAmountIndex());
         loadPtr(Address(parenContextReg, ParenContext::returnAddressOffset()), tempReg);
         storeToFrame(tempReg, subpatternBaseFrameLocation + BackTrackInfoParentheses::returnAddressIndex());
         if (m_compileMode == JITCompileMode::IncludeSubpatterns) {
             for (unsigned subpattern = firstSubpattern; subpattern <= lastSubpattern; subpattern++) {
-                loadPtr(Address(parenContextReg, ParenContext::subpatternOffset(subpattern)), tempReg);
-                storePtr(tempReg, Address(output, (subpattern << 1) * sizeof(unsigned)));
+                static_assert(is64Bit());
+                load64(Address(parenContextReg, ParenContext::subpatternOffset(subpattern)), tempReg);
+                store64(tempReg, Address(output, (subpattern << 1) * sizeof(unsigned)));
             }
         }
         subpatternBaseFrameLocation += YarrStackSpaceForBackTrackInfoParentheses;
@@ -1296,8 +1311,7 @@
         JumpList matches;
 
         if (term->quantityType != QuantifierType::NonGreedy) {
-            load32(Address(output, (subpatternId << 1) * sizeof(int)), patternIndex);
-            load32(Address(output, ((subpatternId << 1) + 1) * sizeof(int)), patternTemp);
+            loadSubPattern(output, subpatternId, patternIndex, patternTemp);
 
             // An empty match is successful without consuming characters
             if (term->quantityType != QuantifierType::FixedCount || term->quantityMaxCount != 1) {
@@ -1328,8 +1342,7 @@
                 add32(TrustedImm32(1), characterOrTemp);
                 storeToFrame(characterOrTemp, parenthesesFrameLocation + BackTrackInfoBackReference::matchAmountIndex());
                 matches.append(branch32(Equal, Imm32(term->quantityMaxCount), characterOrTemp));
-                load32(Address(output, (subpatternId << 1) * sizeof(int)), patternIndex);
-                load32(Address(output, ((subpatternId << 1) + 1) * sizeof(int)), patternTemp);
+                loadSubPattern(output, subpatternId, patternIndex, patternTemp);
                 jump(outerLoop);
             }
             matches.link(this);
@@ -1352,8 +1365,7 @@
             storeToFrame(characterOrTemp, parenthesesFrameLocation + BackTrackInfoBackReference::matchAmountIndex());
             if (term->quantityMaxCount != quantifyInfinite)
                 matches.append(branch32(Equal, Imm32(term->quantityMaxCount), characterOrTemp));
-            load32(Address(output, (subpatternId << 1) * sizeof(int)), patternIndex);
-            load32(Address(output, ((subpatternId << 1) + 1) * sizeof(int)), patternTemp);
+            loadSubPattern(output, subpatternId, patternIndex, patternTemp);
 
             // Store current index in frame for restoring after a partial match
             storeToFrame(index, parenthesesFrameLocation + BackTrackInfoBackReference::beginIndex());
@@ -1374,8 +1386,7 @@
 
             op.m_reentry = label();
 
-            load32(Address(output, (subpatternId << 1) * sizeof(int)), patternIndex);
-            load32(Address(output, ((subpatternId << 1) + 1) * sizeof(int)), patternTemp);
+            loadSubPattern(output, subpatternId, patternIndex, patternTemp);
 
             // An empty match is successful without consuming characters
             Jump zeroLengthMatch = branch32(Equal, TrustedImm32(-1), patternIndex);
@@ -1429,8 +1440,7 @@
             loadFromFrame(parenthesesFrameLocation + BackTrackInfoBackReference::matchAmountIndex(), matchAmount);
             failures.append(branchTest32(Zero, matchAmount));
 
-            load32(Address(output, (subpatternId << 1) * sizeof(int)), patternStartIndex);
-            load32(Address(output, ((subpatternId << 1) + 1) * sizeof(int)), patternEndIndexOrLen);
+            loadSubPattern(output, subpatternId, patternStartIndex, patternEndIndexOrLen);
             sub32(patternStartIndex, patternEndIndexOrLen);
             sub32(patternEndIndexOrLen, index);
 
@@ -2515,11 +2525,12 @@
                     if (priorAlternative->m_minimumSize)
                         sub32(Imm32(priorAlternative->m_minimumSize), returnRegister);
                     if (m_compileMode == JITCompileMode::IncludeSubpatterns)
-                        store32(returnRegister, output);
-                } else
+                        storePair32(returnRegister, index, output, TrustedImm32(0));
+                } else {
                     getMatchStart(returnRegister);
-                if (m_compileMode == JITCompileMode::IncludeSubpatterns)
-                    store32(index, Address(output, 4));
+                    if (m_compileMode == JITCompileMode::IncludeSubpatterns)
+                        store32(index, Address(output, 4));
+                }
                 move(index, returnRegister2);
 
                 generateReturn();
@@ -4143,6 +4154,11 @@
 #endif
     }
 
+    void loadSubPattern(RegisterID outputGPR, unsigned subpatternId, RegisterID startIndexGPR, RegisterID endIndexOrLenGPR)
+    {
+        loadPair32(outputGPR, TrustedImm32((subpatternId << 1) * sizeof(int)), startIndexGPR, endIndexOrLenGPR);
+    }
+
 public:
     YarrGenerator(VM* vm, YarrPattern& pattern, String& patternString, YarrCodeBlock& codeBlock, CharSize charSize, JITCompileMode compileMode)
         : m_vm(vm)
@@ -4241,14 +4257,22 @@
             move(TrustedImm32(matchLimit), remainingMatchCount);
 #endif
 
+        // Initialize subpatterns' starts. And initialize matchStart if `!m_pattern.m_body->m_hasFixedSize`.
+        // If the mode is JITCompileMode::IncludeSubpatterns, then matchStart is subpatterns[0]'s start.
         if (m_compileMode == JITCompileMode::IncludeSubpatterns) {
-            for (unsigned i = 0; i < m_pattern.m_numSubpatterns + 1; ++i)
-                store32(TrustedImm32(-1), Address(output, (i << 1) * sizeof(int)));
+            unsigned subpatternId = 0;
+            // First subpatternId's start is configured to `index` if !m_pattern.m_body->m_hasFixedSize.
+            if (!m_pattern.m_body->m_hasFixedSize) {
+                setMatchStart(index);
+                ++subpatternId;
+            }
+            for (; subpatternId < m_pattern.m_numSubpatterns + 1; ++subpatternId)
+                store32(TrustedImm32(-1), Address(output, (subpatternId << 1) * sizeof(int)));
+        } else {
+            if (!m_pattern.m_body->m_hasFixedSize)
+                setMatchStart(index);
         }
 
-        if (!m_pattern.m_body->m_hasFixedSize)
-            setMatchStart(index);
-
 #if ENABLE(YARR_JIT_ALL_PARENS_EXPRESSIONS)
         if (m_containsNestedSubpatterns) {
             initParenContextFreeList();
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to