Changeset 278856 in webkit


Ignore:
Timestamp:
Jun 14, 2021 6:04:01 PM (3 years ago)
Author:
mark.lam@apple.com
Message:

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.
  1. Add ARM64 disassembler support ldp and stp for FP registers. This includes fixing A64DOpcodeLoadStoreRegisterPair::mask to not exclude the FP versions of the instructions.
  1. Add ARM64Assembler query methods for determining if an immediate is encodable as the signed 12 bit immediate of ldp and stp instructions.
  1. 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.
  1. 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.
  1. 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:
Location:
trunk/Source/JavaScriptCore
Files:
7 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/ChangeLog

    r278846 r278856  
     12021-06-14  Mark Lam  <mark.lam@apple.com>
     2
     3        Add ldp and stp support for FP registers, plus some bug fixes.
     4        https://bugs.webkit.org/show_bug.cgi?id=226998
     5        rdar://79313717
     6
     7        Reviewed by Robin Morisset.
     8
     9        This patch does the following:
     10        1. Add ldp and stp support for FP registers.
     11           This simply entails providing wrappers that take FPRegisterID and passing true
     12           for the V bit to the underlying loadStoreRegisterPairXXX encoding function.
     13           V is for vector (aka floating point).  This will cause bit 26 in the instruction
     14           to be set indicating that it's loading / storing floating point registers.
     15
     16        2. Add ARM64 disassembler support ldp and stp for FP registers.
     17           This includes fixing A64DOpcodeLoadStoreRegisterPair::mask to not exclude the
     18           FP versions of the instructions.
     19
     20        3. Add ARM64Assembler query methods for determining if an immediate is encodable
     21           as the signed 12 bit immediate of ldp and stp instructions.
     22
     23        4. Fix ldp and stp offset form to take an int instead of an unsigned.  The
     24           immediate it takes is a 12-bit signed int, not unsigned.
     25
     26        5. In loadStoreRegisterPairXXX encoding functions used by the forms of ldp and stp,
     27           RELEASE_ASSERT that the passed in immediate is encodable.  Unlike ldur / stur,
     28           there is no form of ldp / stp that takes the offset in a register that can be
     29           used as a fail over.  Hence, if the immediate is not encodable, this is a
     30           non-recoverable event.  The client is responsible for ensuring that the offset
     31           is encodable.
     32
     33        6. Added some testmasm tests for testing the offset form (as opposed to PreIndex
     34           and PostIndex forms) of ldp and stp.  We currently only use the offset form
     35           in our JITs.
     36
     37        * assembler/ARM64Assembler.h:
     38        (JSC::ARM64Assembler::isValidLDPImm):
     39        (JSC::ARM64Assembler::isValidLDPFPImm):
     40        (JSC::ARM64Assembler::ldp):
     41        (JSC::ARM64Assembler::ldnp):
     42        (JSC::ARM64Assembler::isValidSTPImm):
     43        (JSC::ARM64Assembler::isValidSTPFPImm):
     44        (JSC::ARM64Assembler::stp):
     45        (JSC::ARM64Assembler::stnp):
     46        (JSC::ARM64Assembler::loadStoreRegisterPairPostIndex):
     47        (JSC::ARM64Assembler::loadStoreRegisterPairPreIndex):
     48        (JSC::ARM64Assembler::loadStoreRegisterPairOffset):
     49        (JSC::ARM64Assembler::loadStoreRegisterPairNonTemporal):
     50        * assembler/AssemblerCommon.h:
     51        (JSC::isValidSignedImm7):
     52        * assembler/MacroAssemblerARM64.h:
     53        (JSC::MacroAssemblerARM64::loadPair64):
     54        (JSC::MacroAssemblerARM64::storePair64):
     55        * assembler/testmasm.cpp:
     56        (JSC::testLoadStorePair64Int64):
     57        (JSC::testLoadStorePair64Double):
     58        * disassembler/ARM64/A64DOpcode.cpp:
     59        (JSC::ARM64Disassembler::A64DOpcodeLoadStoreRegisterPair::format):
     60        * disassembler/ARM64/A64DOpcode.h:
     61
    1622021-06-14  Yijia Huang  <yijia_huang@apple.com>
    263
  • trunk/Source/JavaScriptCore/assembler/ARM64Assembler.h

    r275285 r278856  
    11/*
    2  * Copyright (C) 2012-2020 Apple Inc. All rights reserved.
     2 * Copyright (C) 2012-2021 Apple Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    11161116
    11171117    template<int datasize>
     1118    ALWAYS_INLINE static bool isValidLDPImm(int immediate)
     1119    {
     1120        unsigned immedShiftAmount = memPairOffsetShift(false, MEMPAIROPSIZE_INT(datasize));
     1121        return isValidSignedImm7(immediate, immedShiftAmount);
     1122    }
     1123
     1124    template<int datasize>
     1125    ALWAYS_INLINE static bool isValidLDPFPImm(int immediate)
     1126    {
     1127        unsigned immedShiftAmount = memPairOffsetShift(true, MEMPAIROPSIZE_FP(datasize));
     1128        return isValidSignedImm7(immediate, immedShiftAmount);
     1129    }
     1130
     1131    template<int datasize>
    11181132    ALWAYS_INLINE void ldp(RegisterID rt, RegisterID rt2, RegisterID rn, PairPostIndex simm)
    11191133    {
     
    11301144
    11311145    template<int datasize>
    1132     ALWAYS_INLINE void ldp(RegisterID rt, RegisterID rt2, RegisterID rn, unsigned pimm = 0)
    1133     {
    1134         CHECK_DATASIZE();
    1135         insn(loadStoreRegisterPairOffset(MEMPAIROPSIZE_INT(datasize), false, MemOp_LOAD, pimm, rn, rt, rt2));
    1136     }
    1137 
    1138     template<int datasize>
    1139     ALWAYS_INLINE void ldnp(RegisterID rt, RegisterID rt2, RegisterID rn, unsigned pimm = 0)
    1140     {
    1141         CHECK_DATASIZE();
    1142         insn(loadStoreRegisterPairNonTemporal(MEMPAIROPSIZE_INT(datasize), false, MemOp_LOAD, pimm, rn, rt, rt2));
     1146    ALWAYS_INLINE void ldp(RegisterID rt, RegisterID rt2, RegisterID rn, int simm = 0)
     1147    {
     1148        CHECK_DATASIZE();
     1149        insn(loadStoreRegisterPairOffset(MEMPAIROPSIZE_INT(datasize), false, MemOp_LOAD, simm, rn, rt, rt2));
     1150    }
     1151
     1152    template<int datasize>
     1153    ALWAYS_INLINE void ldnp(RegisterID rt, RegisterID rt2, RegisterID rn, int simm = 0)
     1154    {
     1155        CHECK_DATASIZE();
     1156        insn(loadStoreRegisterPairNonTemporal(MEMPAIROPSIZE_INT(datasize), false, MemOp_LOAD, simm, rn, rt, rt2));
     1157    }
     1158
     1159    template<int datasize>
     1160    ALWAYS_INLINE void ldp(FPRegisterID rt, FPRegisterID rt2, RegisterID rn, PairPostIndex simm)
     1161    {
     1162        CHECK_DATASIZE();
     1163        insn(loadStoreRegisterPairPostIndex(MEMPAIROPSIZE_FP(datasize), true, MemOp_LOAD, simm, rn, rt, rt2));
     1164    }
     1165
     1166    template<int datasize>
     1167    ALWAYS_INLINE void ldp(FPRegisterID rt, FPRegisterID rt2, RegisterID rn, PairPreIndex simm)
     1168    {
     1169        CHECK_DATASIZE();
     1170        insn(loadStoreRegisterPairPreIndex(MEMPAIROPSIZE_FP(datasize), true, MemOp_LOAD, simm, rn, rt, rt2));
     1171    }
     1172
     1173    template<int datasize>
     1174    ALWAYS_INLINE void ldp(FPRegisterID rt, FPRegisterID rt2, RegisterID rn, int simm = 0)
     1175    {
     1176        CHECK_DATASIZE();
     1177        insn(loadStoreRegisterPairOffset(MEMPAIROPSIZE_FP(datasize), true, MemOp_LOAD, simm, rn, rt, rt2));
     1178    }
     1179
     1180    template<int datasize>
     1181    ALWAYS_INLINE void ldnp(FPRegisterID rt, FPRegisterID rt2, RegisterID rn, int simm = 0)
     1182    {
     1183        CHECK_DATASIZE();
     1184        insn(loadStoreRegisterPairNonTemporal(MEMPAIROPSIZE_FP(datasize), true, MemOp_LOAD, simm, rn, rt, rt2));
    11431185    }
    11441186
     
    17451787
    17461788    template<int datasize>
     1789    ALWAYS_INLINE static bool isValidSTPImm(int immediate)
     1790    {
     1791        return isValidLDPImm<datasize>(immediate);
     1792    }
     1793
     1794    template<int datasize>
     1795    ALWAYS_INLINE static bool isValidSTPFPImm(int immediate)
     1796    {
     1797        return isValidLDPFPImm<datasize>(immediate);
     1798    }
     1799
     1800    template<int datasize>
    17471801    ALWAYS_INLINE void stp(RegisterID rt, RegisterID rt2, RegisterID rn, PairPostIndex simm)
    17481802    {
     
    17591813
    17601814    template<int datasize>
    1761     ALWAYS_INLINE void stp(RegisterID rt, RegisterID rt2, RegisterID rn, unsigned pimm = 0)
    1762     {
    1763         CHECK_DATASIZE();
    1764         insn(loadStoreRegisterPairOffset(MEMPAIROPSIZE_INT(datasize), false, MemOp_STORE, pimm, rn, rt, rt2));
    1765     }
    1766 
    1767     template<int datasize>
    1768     ALWAYS_INLINE void stnp(RegisterID rt, RegisterID rt2, RegisterID rn, unsigned pimm = 0)
    1769     {
    1770         CHECK_DATASIZE();
    1771         insn(loadStoreRegisterPairNonTemporal(MEMPAIROPSIZE_INT(datasize), false, MemOp_STORE, pimm, rn, rt, rt2));
     1815    ALWAYS_INLINE void stp(RegisterID rt, RegisterID rt2, RegisterID rn, int simm = 0)
     1816    {
     1817        CHECK_DATASIZE();
     1818        insn(loadStoreRegisterPairOffset(MEMPAIROPSIZE_INT(datasize), false, MemOp_STORE, simm, rn, rt, rt2));
     1819    }
     1820
     1821    template<int datasize>
     1822    ALWAYS_INLINE void stnp(RegisterID rt, RegisterID rt2, RegisterID rn, int simm = 0)
     1823    {
     1824        CHECK_DATASIZE();
     1825        insn(loadStoreRegisterPairNonTemporal(MEMPAIROPSIZE_INT(datasize), false, MemOp_STORE, simm, rn, rt, rt2));
     1826    }
     1827
     1828    template<int datasize>
     1829    ALWAYS_INLINE void stp(FPRegisterID rt, FPRegisterID rt2, RegisterID rn, PairPostIndex simm)
     1830    {
     1831        CHECK_DATASIZE();
     1832        insn(loadStoreRegisterPairPostIndex(MEMPAIROPSIZE_FP(datasize), true, MemOp_STORE, simm, rn, rt, rt2));
     1833    }
     1834
     1835    template<int datasize>
     1836    ALWAYS_INLINE void stp(FPRegisterID rt, FPRegisterID rt2, RegisterID rn, PairPreIndex simm)
     1837    {
     1838        CHECK_DATASIZE();
     1839        insn(loadStoreRegisterPairPreIndex(MEMPAIROPSIZE_FP(datasize), true, MemOp_STORE, simm, rn, rt, rt2));
     1840    }
     1841
     1842    template<int datasize>
     1843    ALWAYS_INLINE void stp(FPRegisterID rt, FPRegisterID rt2, RegisterID rn, int simm = 0)
     1844    {
     1845        CHECK_DATASIZE();
     1846        insn(loadStoreRegisterPairOffset(MEMPAIROPSIZE_FP(datasize), true, MemOp_STORE, simm, rn, rt, rt2));
     1847    }
     1848
     1849    template<int datasize>
     1850    ALWAYS_INLINE void stnp(FPRegisterID rt, FPRegisterID rt2, RegisterID rn, int simm = 0)
     1851    {
     1852        CHECK_DATASIZE();
     1853        insn(loadStoreRegisterPairNonTemporal(MEMPAIROPSIZE_FP(datasize), true, MemOp_STORE, simm, rn, rt, rt2));
    17721854    }
    17731855
     
    35453627        ASSERT(V || (size != MemPairOp_LoadSigned_32) || (opc == MemOp_LOAD)); // There isn't an integer store signed.
    35463628        unsigned immedShiftAmount = memPairOffsetShift(V, size);
     3629        RELEASE_ASSERT(isValidSignedImm7(immediate, immedShiftAmount));
    35473630        int imm7 = immediate >> immedShiftAmount;
    35483631        ASSERT((imm7 << immedShiftAmount) == immediate && isInt<7>(imm7));
     
    35763659        ASSERT(V || (size != MemPairOp_LoadSigned_32) || (opc == MemOp_LOAD)); // There isn't an integer store signed.
    35773660        unsigned immedShiftAmount = memPairOffsetShift(V, size);
     3661        RELEASE_ASSERT(isValidSignedImm7(immediate, immedShiftAmount));
    35783662        int imm7 = immediate >> immedShiftAmount;
    35793663        ASSERT((imm7 << immedShiftAmount) == immediate && isInt<7>(imm7));
     
    35933677        ASSERT(V || (size != MemPairOp_LoadSigned_32) || (opc == MemOp_LOAD)); // There isn't an integer store signed.
    35943678        unsigned immedShiftAmount = memPairOffsetShift(V, size);
     3679        RELEASE_ASSERT(isValidSignedImm7(immediate, immedShiftAmount));
    35953680        int imm7 = immediate >> immedShiftAmount;
    35963681        ASSERT((imm7 << immedShiftAmount) == immediate && isInt<7>(imm7));
     
    36103695        ASSERT(V || (size != MemPairOp_LoadSigned_32) || (opc == MemOp_LOAD)); // There isn't an integer store signed.
    36113696        unsigned immedShiftAmount = memPairOffsetShift(V, size);
     3697        RELEASE_ASSERT(isValidSignedImm7(immediate, immedShiftAmount));
    36123698        int imm7 = immediate >> immedShiftAmount;
    36133699        ASSERT((imm7 << immedShiftAmount) == immediate && isInt<7>(imm7));
  • trunk/Source/JavaScriptCore/assembler/AssemblerCommon.h

    r254843 r278856  
    11/*
    2  * Copyright (C) 2012-2019 Apple Inc. All rights reserved.
     2 * Copyright (C) 2012-2021 Apple Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    7575}
    7676
     77ALWAYS_INLINE bool isValidSignedImm7(int32_t value, int alignmentShiftAmount)
     78{
     79    constexpr int32_t disallowedHighBits = 32 - 7;
     80    int32_t shiftedValue = value >> alignmentShiftAmount;
     81    bool fitsIn7Bits = shiftedValue == ((shiftedValue << disallowedHighBits) >> disallowedHighBits);
     82    bool hasCorrectAlignment = value == (shiftedValue << alignmentShiftAmount);
     83    return fitsIn7Bits && hasCorrectAlignment;
     84}
     85
    7786class ARM64LogicalImmediate {
    7887public:
  • trunk/Source/JavaScriptCore/assembler/MacroAssemblerARM64.h

    r278846 r278856  
    12451245    }
    12461246
     1247    void loadPair64(RegisterID src, FPRegisterID dest1, FPRegisterID dest2)
     1248    {
     1249        loadPair64(src, TrustedImm32(0), dest1, dest2);
     1250    }
     1251
     1252    void loadPair64(RegisterID src, TrustedImm32 offset, FPRegisterID dest1, FPRegisterID dest2)
     1253    {
     1254        m_assembler.ldp<64>(dest1, dest2, src, offset.m_value);
     1255    }
     1256
    12471257    void abortWithReason(AbortReason reason)
    12481258    {
     
    15671577    {
    15681578        m_assembler.stnp<64>(src1, src2, dest, offset.m_value);
     1579    }
     1580
     1581    void storePair64(FPRegisterID src1, FPRegisterID src2, RegisterID dest)
     1582    {
     1583        storePair64(src1, src2, dest, TrustedImm32(0));
     1584    }
     1585
     1586    void storePair64(FPRegisterID src1, FPRegisterID src2, RegisterID dest, TrustedImm32 offset)
     1587    {
     1588        m_assembler.stp<64>(src1, src2, dest, offset.m_value);
    15691589    }
    15701590
  • trunk/Source/JavaScriptCore/assembler/testmasm.cpp

    r278846 r278856  
    18511851#endif // CPU(X86_64) || CPU(ARM64)
    18521852
     1853#if CPU(ARM64)
     1854void testLoadStorePair64Int64()
     1855{
     1856    constexpr uint64_t initialValue = 0x5555aaaabbbb8800ull;
     1857    constexpr uint64_t value1 = 42;
     1858    constexpr uint64_t value2 = 0xcafebabe12345678ull;
     1859
     1860    uint64_t buffer[10];
     1861
     1862    auto initBuffer = [&] {
     1863        for (unsigned i = 0; i < 10; ++i)
     1864            buffer[i] = initialValue + i;
     1865    };
     1866
     1867    struct Pair {
     1868        uint64_t value1;
     1869        uint64_t value2;
     1870    };
     1871
     1872    Pair pair;
     1873    auto initPair = [&] {
     1874        pair = { 0, 0 };
     1875    };
     1876
     1877    // Test loadPair64.
     1878    auto testLoadPair = [] (CCallHelpers& jit, int offset) {
     1879        emitFunctionPrologue(jit);
     1880
     1881        constexpr GPRReg bufferGPR = GPRInfo::argumentGPR0;
     1882        constexpr GPRReg pairGPR = GPRInfo::argumentGPR1;
     1883        jit.loadPair64(bufferGPR, CCallHelpers::TrustedImm32(offset * sizeof(CPURegister)), GPRInfo::regT2, GPRInfo::regT3);
     1884
     1885        jit.store64(GPRInfo::regT2, CCallHelpers::Address(pairGPR, 0));
     1886        jit.store64(GPRInfo::regT3, CCallHelpers::Address(pairGPR, sizeof(uint64_t)));
     1887
     1888        emitFunctionEpilogue(jit);
     1889        jit.ret();
     1890    };
     1891
     1892    auto testLoadPair0 = compile([&] (CCallHelpers& jit) {
     1893        testLoadPair(jit, 0);
     1894    });
     1895
     1896    initBuffer();
     1897
     1898    initPair();
     1899    invoke<void>(testLoadPair0, &buffer[4], &pair);
     1900    CHECK_EQ(pair.value1, initialValue + 4);
     1901    CHECK_EQ(pair.value2, initialValue + 5);
     1902
     1903    initPair();
     1904    buffer[4] = value1;
     1905    buffer[5] = value2;
     1906    invoke<void>(testLoadPair0, &buffer[4], &pair);
     1907    CHECK_EQ(pair.value1, value1);
     1908    CHECK_EQ(pair.value2, value2);
     1909
     1910    auto testLoadPairMinus2 = compile([&] (CCallHelpers& jit) {
     1911        testLoadPair(jit, -2);
     1912    });
     1913
     1914    initPair();
     1915    invoke<void>(testLoadPairMinus2, &buffer[4], &pair);
     1916    CHECK_EQ(pair.value1, initialValue + 4 - 2);
     1917    CHECK_EQ(pair.value2, initialValue + 5 - 2);
     1918
     1919    initPair();
     1920    buffer[4 - 2] = value2;
     1921    buffer[5 - 2] = value1;
     1922    invoke<void>(testLoadPairMinus2, &buffer[4], &pair);
     1923    CHECK_EQ(pair.value1, value2);
     1924    CHECK_EQ(pair.value2, value1);
     1925
     1926    auto testLoadPairPlus3 = compile([&] (CCallHelpers& jit) {
     1927        testLoadPair(jit, 3);
     1928    });
     1929
     1930    initPair();
     1931    invoke<void>(testLoadPairPlus3, &buffer[4], &pair);
     1932    CHECK_EQ(pair.value1, initialValue + 4 + 3);
     1933    CHECK_EQ(pair.value2, initialValue + 5 + 3);
     1934
     1935    initPair();
     1936    buffer[4 + 3] = value1;
     1937    buffer[5 + 3] = value2;
     1938    invoke<void>(testLoadPairPlus3, &buffer[4], &pair);
     1939    CHECK_EQ(pair.value1, value1);
     1940    CHECK_EQ(pair.value2, value2);
     1941
     1942    // Test storePair64.
     1943    auto testStorePair = [] (CCallHelpers& jit, int offset) {
     1944        emitFunctionPrologue(jit);
     1945
     1946        constexpr GPRReg bufferGPR = GPRInfo::argumentGPR2;
     1947        jit.storePair64(GPRInfo::argumentGPR0, GPRInfo::argumentGPR1, bufferGPR, CCallHelpers::TrustedImm32(offset * sizeof(CPURegister)));
     1948
     1949        emitFunctionEpilogue(jit);
     1950        jit.ret();
     1951    };
     1952
     1953    auto testStorePair0 = compile([&] (CCallHelpers& jit) {
     1954        testStorePair(jit, 0);
     1955    });
     1956
     1957    initBuffer();
     1958    invoke<void>(testStorePair0, value1, value2, &buffer[4]);
     1959    CHECK_EQ(buffer[0], initialValue + 0);
     1960    CHECK_EQ(buffer[1], initialValue + 1);
     1961    CHECK_EQ(buffer[2], initialValue + 2);
     1962    CHECK_EQ(buffer[3], initialValue + 3);
     1963    CHECK_EQ(buffer[4], value1);
     1964    CHECK_EQ(buffer[5], value2);
     1965    CHECK_EQ(buffer[6], initialValue + 6);
     1966    CHECK_EQ(buffer[7], initialValue + 7);
     1967    CHECK_EQ(buffer[8], initialValue + 8);
     1968    CHECK_EQ(buffer[9], initialValue + 9);
     1969
     1970    auto testStorePairMinus2 = compile([&] (CCallHelpers& jit) {
     1971        testStorePair(jit, -2);
     1972    });
     1973
     1974    initBuffer();
     1975    invoke<void>(testStorePairMinus2, value1, value2, &buffer[4]);
     1976    CHECK_EQ(buffer[0], initialValue + 0);
     1977    CHECK_EQ(buffer[1], initialValue + 1);
     1978    CHECK_EQ(buffer[2], value1);
     1979    CHECK_EQ(buffer[3], value2);
     1980    CHECK_EQ(buffer[4], initialValue + 4);
     1981    CHECK_EQ(buffer[5], initialValue + 5);
     1982    CHECK_EQ(buffer[6], initialValue + 6);
     1983    CHECK_EQ(buffer[7], initialValue + 7);
     1984    CHECK_EQ(buffer[8], initialValue + 8);
     1985    CHECK_EQ(buffer[9], initialValue + 9);
     1986
     1987    auto testStorePairPlus3 = compile([&] (CCallHelpers& jit) {
     1988        testStorePair(jit, 3);
     1989    });
     1990
     1991    initBuffer();
     1992    invoke<void>(testStorePairPlus3, value1, value2, &buffer[4]);
     1993    CHECK_EQ(buffer[0], initialValue + 0);
     1994    CHECK_EQ(buffer[1], initialValue + 1);
     1995    CHECK_EQ(buffer[2], initialValue + 2);
     1996    CHECK_EQ(buffer[3], initialValue + 3);
     1997    CHECK_EQ(buffer[4], initialValue + 4);
     1998    CHECK_EQ(buffer[5], initialValue + 5);
     1999    CHECK_EQ(buffer[6], initialValue + 6);
     2000    CHECK_EQ(buffer[7], value1);
     2001    CHECK_EQ(buffer[8], value2);
     2002    CHECK_EQ(buffer[9], initialValue + 9);
     2003
     2004    // Test storePair64 from 1 register.
     2005    auto testStorePairFromOneReg = [] (CCallHelpers& jit, int offset) {
     2006        emitFunctionPrologue(jit);
     2007
     2008        constexpr GPRReg bufferGPR = GPRInfo::argumentGPR1;
     2009        jit.storePair64(GPRInfo::argumentGPR0, GPRInfo::argumentGPR0, bufferGPR, CCallHelpers::TrustedImm32(offset * sizeof(CPURegister)));
     2010
     2011        emitFunctionEpilogue(jit);
     2012        jit.ret();
     2013    };
     2014
     2015    auto testStorePairFromOneReg0 = compile([&] (CCallHelpers& jit) {
     2016        testStorePairFromOneReg(jit, 0);
     2017    });
     2018
     2019    initBuffer();
     2020    invoke<void>(testStorePairFromOneReg0, value2, &buffer[4]);
     2021    CHECK_EQ(buffer[0], initialValue + 0);
     2022    CHECK_EQ(buffer[1], initialValue + 1);
     2023    CHECK_EQ(buffer[2], initialValue + 2);
     2024    CHECK_EQ(buffer[3], initialValue + 3);
     2025    CHECK_EQ(buffer[4], value2);
     2026    CHECK_EQ(buffer[5], value2);
     2027    CHECK_EQ(buffer[6], initialValue + 6);
     2028    CHECK_EQ(buffer[7], initialValue + 7);
     2029    CHECK_EQ(buffer[8], initialValue + 8);
     2030    CHECK_EQ(buffer[9], initialValue + 9);
     2031
     2032    auto testStorePairFromOneRegMinus2 = compile([&] (CCallHelpers& jit) {
     2033        testStorePairFromOneReg(jit, -2);
     2034    });
     2035
     2036    initBuffer();
     2037    invoke<void>(testStorePairFromOneRegMinus2, value1, &buffer[4]);
     2038    CHECK_EQ(buffer[0], initialValue + 0);
     2039    CHECK_EQ(buffer[1], initialValue + 1);
     2040    CHECK_EQ(buffer[2], value1);
     2041    CHECK_EQ(buffer[3], value1);
     2042    CHECK_EQ(buffer[4], initialValue + 4);
     2043    CHECK_EQ(buffer[5], initialValue + 5);
     2044    CHECK_EQ(buffer[6], initialValue + 6);
     2045    CHECK_EQ(buffer[7], initialValue + 7);
     2046    CHECK_EQ(buffer[8], initialValue + 8);
     2047    CHECK_EQ(buffer[9], initialValue + 9);
     2048
     2049    auto testStorePairFromOneRegPlus3 = compile([&] (CCallHelpers& jit) {
     2050        testStorePairFromOneReg(jit, 3);
     2051    });
     2052
     2053    initBuffer();
     2054    invoke<void>(testStorePairFromOneRegPlus3, value2, &buffer[4]);
     2055    CHECK_EQ(buffer[0], initialValue + 0);
     2056    CHECK_EQ(buffer[1], initialValue + 1);
     2057    CHECK_EQ(buffer[2], initialValue + 2);
     2058    CHECK_EQ(buffer[3], initialValue + 3);
     2059    CHECK_EQ(buffer[4], initialValue + 4);
     2060    CHECK_EQ(buffer[5], initialValue + 5);
     2061    CHECK_EQ(buffer[6], initialValue + 6);
     2062    CHECK_EQ(buffer[7], value2);
     2063    CHECK_EQ(buffer[8], value2);
     2064    CHECK_EQ(buffer[9], initialValue + 9);
     2065}
     2066
     2067void testLoadStorePair64Double()
     2068{
     2069    constexpr double initialValue = 10000.275;
     2070    constexpr double value1 = 42.89;
     2071    constexpr double value2 = -555.321;
     2072
     2073    double buffer[10];
     2074
     2075    auto initBuffer = [&] {
     2076        for (unsigned i = 0; i < 10; ++i)
     2077            buffer[i] = initialValue + i;
     2078    };
     2079
     2080    struct Pair {
     2081        double value1;
     2082        double value2;
     2083    };
     2084
     2085    Pair pair;
     2086    auto initPair = [&] {
     2087        pair = { 0, 0 };
     2088    };
     2089
     2090    // Test loadPair64.
     2091    auto testLoadPair = [] (CCallHelpers& jit, int offset) {
     2092        emitFunctionPrologue(jit);
     2093
     2094        constexpr GPRReg bufferGPR = GPRInfo::argumentGPR0;
     2095        constexpr GPRReg pairGPR = GPRInfo::argumentGPR1;
     2096        jit.loadPair64(bufferGPR, CCallHelpers::TrustedImm32(offset * sizeof(double)), FPRInfo::fpRegT0, FPRInfo::fpRegT1);
     2097
     2098        jit.storeDouble(FPRInfo::fpRegT0, CCallHelpers::Address(pairGPR, 0));
     2099        jit.storeDouble(FPRInfo::fpRegT1, CCallHelpers::Address(pairGPR, sizeof(uint64_t)));
     2100
     2101        emitFunctionEpilogue(jit);
     2102        jit.ret();
     2103    };
     2104
     2105    auto testLoadPair0 = compile([&] (CCallHelpers& jit) {
     2106        testLoadPair(jit, 0);
     2107    });
     2108
     2109    initBuffer();
     2110
     2111    initPair();
     2112    invoke<void>(testLoadPair0, &buffer[4], &pair);
     2113    CHECK_EQ(pair.value1, initialValue + 4);
     2114    CHECK_EQ(pair.value2, initialValue + 5);
     2115
     2116    initPair();
     2117    buffer[4] = value1;
     2118    buffer[5] = value2;
     2119    invoke<void>(testLoadPair0, &buffer[4], &pair);
     2120    CHECK_EQ(pair.value1, value1);
     2121    CHECK_EQ(pair.value2, value2);
     2122
     2123    auto testLoadPairMinus2 = compile([&] (CCallHelpers& jit) {
     2124        testLoadPair(jit, -2);
     2125    });
     2126
     2127    initPair();
     2128    invoke<void>(testLoadPairMinus2, &buffer[4], &pair);
     2129    CHECK_EQ(pair.value1, initialValue + 4 - 2);
     2130    CHECK_EQ(pair.value2, initialValue + 5 - 2);
     2131
     2132    initPair();
     2133    buffer[4 - 2] = value2;
     2134    buffer[5 - 2] = value1;
     2135    invoke<void>(testLoadPairMinus2, &buffer[4], &pair);
     2136    CHECK_EQ(pair.value1, value2);
     2137    CHECK_EQ(pair.value2, value1);
     2138
     2139    auto testLoadPairPlus3 = compile([&] (CCallHelpers& jit) {
     2140        testLoadPair(jit, 3);
     2141    });
     2142
     2143    initPair();
     2144    invoke<void>(testLoadPairPlus3, &buffer[4], &pair);
     2145    CHECK_EQ(pair.value1, initialValue + 4 + 3);
     2146    CHECK_EQ(pair.value2, initialValue + 5 + 3);
     2147
     2148    initPair();
     2149    buffer[4 + 3] = value1;
     2150    buffer[5 + 3] = value2;
     2151    invoke<void>(testLoadPairPlus3, &buffer[4], &pair);
     2152    CHECK_EQ(pair.value1, value1);
     2153    CHECK_EQ(pair.value2, value2);
     2154
     2155    // Test storePair64.
     2156    auto testStorePair = [] (CCallHelpers& jit, int offset) {
     2157        emitFunctionPrologue(jit);
     2158
     2159        constexpr GPRReg bufferGPR = GPRInfo::argumentGPR2;
     2160        jit.move64ToDouble(GPRInfo::argumentGPR0, FPRInfo::fpRegT0);
     2161        jit.move64ToDouble(GPRInfo::argumentGPR1, FPRInfo::fpRegT1);
     2162        jit.storePair64(FPRInfo::fpRegT0, FPRInfo::fpRegT1, bufferGPR, CCallHelpers::TrustedImm32(offset * sizeof(double)));
     2163
     2164        emitFunctionEpilogue(jit);
     2165        jit.ret();
     2166    };
     2167
     2168    auto asInt64 = [] (double value) {
     2169        return bitwise_cast<int64_t>(value);
     2170    };
     2171
     2172    auto testStorePair0 = compile([&] (CCallHelpers& jit) {
     2173        testStorePair(jit, 0);
     2174    });
     2175
     2176    initBuffer();
     2177    invoke<void>(testStorePair0, asInt64(value1), asInt64(value2), &buffer[4]);
     2178    CHECK_EQ(buffer[0], initialValue + 0);
     2179    CHECK_EQ(buffer[1], initialValue + 1);
     2180    CHECK_EQ(buffer[2], initialValue + 2);
     2181    CHECK_EQ(buffer[3], initialValue + 3);
     2182    CHECK_EQ(buffer[4], value1);
     2183    CHECK_EQ(buffer[5], value2);
     2184    CHECK_EQ(buffer[6], initialValue + 6);
     2185    CHECK_EQ(buffer[7], initialValue + 7);
     2186    CHECK_EQ(buffer[8], initialValue + 8);
     2187    CHECK_EQ(buffer[9], initialValue + 9);
     2188
     2189    auto testStorePairMinus2 = compile([&] (CCallHelpers& jit) {
     2190        testStorePair(jit, -2);
     2191    });
     2192
     2193    initBuffer();
     2194    invoke<void>(testStorePairMinus2, asInt64(value1), asInt64(value2), &buffer[4]);
     2195    CHECK_EQ(buffer[0], initialValue + 0);
     2196    CHECK_EQ(buffer[1], initialValue + 1);
     2197    CHECK_EQ(buffer[2], value1);
     2198    CHECK_EQ(buffer[3], value2);
     2199    CHECK_EQ(buffer[4], initialValue + 4);
     2200    CHECK_EQ(buffer[5], initialValue + 5);
     2201    CHECK_EQ(buffer[6], initialValue + 6);
     2202    CHECK_EQ(buffer[7], initialValue + 7);
     2203    CHECK_EQ(buffer[8], initialValue + 8);
     2204    CHECK_EQ(buffer[9], initialValue + 9);
     2205
     2206    auto testStorePairPlus3 = compile([&] (CCallHelpers& jit) {
     2207        testStorePair(jit, 3);
     2208    });
     2209
     2210    initBuffer();
     2211    invoke<void>(testStorePairPlus3, asInt64(value1), asInt64(value2), &buffer[4]);
     2212    CHECK_EQ(buffer[0], initialValue + 0);
     2213    CHECK_EQ(buffer[1], initialValue + 1);
     2214    CHECK_EQ(buffer[2], initialValue + 2);
     2215    CHECK_EQ(buffer[3], initialValue + 3);
     2216    CHECK_EQ(buffer[4], initialValue + 4);
     2217    CHECK_EQ(buffer[5], initialValue + 5);
     2218    CHECK_EQ(buffer[6], initialValue + 6);
     2219    CHECK_EQ(buffer[7], value1);
     2220    CHECK_EQ(buffer[8], value2);
     2221    CHECK_EQ(buffer[9], initialValue + 9);
     2222
     2223    // Test storePair64 from 1 register.
     2224    auto testStorePairFromOneReg = [] (CCallHelpers& jit, int offset) {
     2225        emitFunctionPrologue(jit);
     2226
     2227        constexpr GPRReg bufferGPR = GPRInfo::argumentGPR1;
     2228        jit.move64ToDouble(GPRInfo::argumentGPR0, FPRInfo::fpRegT0);
     2229        jit.storePair64(FPRInfo::fpRegT0, FPRInfo::fpRegT0, bufferGPR, CCallHelpers::TrustedImm32(offset * sizeof(double)));
     2230
     2231        emitFunctionEpilogue(jit);
     2232        jit.ret();
     2233    };
     2234
     2235    auto testStorePairFromOneReg0 = compile([&] (CCallHelpers& jit) {
     2236        testStorePairFromOneReg(jit, 0);
     2237    });
     2238
     2239    initBuffer();
     2240    invoke<void>(testStorePairFromOneReg0, asInt64(value2), &buffer[4]);
     2241    CHECK_EQ(buffer[0], initialValue + 0);
     2242    CHECK_EQ(buffer[1], initialValue + 1);
     2243    CHECK_EQ(buffer[2], initialValue + 2);
     2244    CHECK_EQ(buffer[3], initialValue + 3);
     2245    CHECK_EQ(buffer[4], value2);
     2246    CHECK_EQ(buffer[5], value2);
     2247    CHECK_EQ(buffer[6], initialValue + 6);
     2248    CHECK_EQ(buffer[7], initialValue + 7);
     2249    CHECK_EQ(buffer[8], initialValue + 8);
     2250    CHECK_EQ(buffer[9], initialValue + 9);
     2251
     2252    auto testStorePairFromOneRegMinus2 = compile([&] (CCallHelpers& jit) {
     2253        testStorePairFromOneReg(jit, -2);
     2254    });
     2255
     2256    initBuffer();
     2257    invoke<void>(testStorePairFromOneRegMinus2, asInt64(value1), &buffer[4]);
     2258    CHECK_EQ(buffer[0], initialValue + 0);
     2259    CHECK_EQ(buffer[1], initialValue + 1);
     2260    CHECK_EQ(buffer[2], value1);
     2261    CHECK_EQ(buffer[3], value1);
     2262    CHECK_EQ(buffer[4], initialValue + 4);
     2263    CHECK_EQ(buffer[5], initialValue + 5);
     2264    CHECK_EQ(buffer[6], initialValue + 6);
     2265    CHECK_EQ(buffer[7], initialValue + 7);
     2266    CHECK_EQ(buffer[8], initialValue + 8);
     2267    CHECK_EQ(buffer[9], initialValue + 9);
     2268
     2269    auto testStorePairFromOneRegPlus3 = compile([&] (CCallHelpers& jit) {
     2270        testStorePairFromOneReg(jit, 3);
     2271    });
     2272
     2273    initBuffer();
     2274    invoke<void>(testStorePairFromOneRegPlus3, asInt64(value2), &buffer[4]);
     2275    CHECK_EQ(buffer[0], initialValue + 0);
     2276    CHECK_EQ(buffer[1], initialValue + 1);
     2277    CHECK_EQ(buffer[2], initialValue + 2);
     2278    CHECK_EQ(buffer[3], initialValue + 3);
     2279    CHECK_EQ(buffer[4], initialValue + 4);
     2280    CHECK_EQ(buffer[5], initialValue + 5);
     2281    CHECK_EQ(buffer[6], initialValue + 6);
     2282    CHECK_EQ(buffer[7], value2);
     2283    CHECK_EQ(buffer[8], value2);
     2284    CHECK_EQ(buffer[9], initialValue + 9);
     2285}
     2286#endif // CPU(ARM64)
     2287
    18532288void testProbeReadsArgumentRegisters()
    18542289{
     
    27623197
    27633198#if CPU(ARM64)
     3199    RUN(testLoadStorePair64Int64());
     3200    RUN(testLoadStorePair64Double());
    27643201    RUN(testMul32SignExtend());
    27653202    RUN(testSub32Args());
  • trunk/Source/JavaScriptCore/disassembler/ARM64/A64DOpcode.cpp

    r272892 r278856  
    11/*
    2  * Copyright (C) 2012, 2016 Apple Inc. All rights reserved.
     2 * Copyright (C) 2012-2021 Apple Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    7373    OPCODE_GROUP_ENTRY(0x0b, A64DOpcodeAddSubtractExtendedRegister),
    7474    OPCODE_GROUP_ENTRY(0x0b, A64DOpcodeAddSubtractShiftedRegister),
     75    OPCODE_GROUP_ENTRY(0x0c, A64DOpcodeLoadStoreRegisterPair),
     76    OPCODE_GROUP_ENTRY(0x0d, A64DOpcodeLoadStoreRegisterPair),
    7577    OPCODE_GROUP_ENTRY(0x11, A64DOpcodeAddSubtractImmediate),
    7678    OPCODE_GROUP_ENTRY(0x12, A64DOpcodeMoveWide),
     
    13641366    unsigned offsetShift;
    13651367    if (vBit()) {
    1366         appendFPRegisterName(rt(), size());
    1367         appendSeparator();
    1368         appendFPRegisterName(rt2(), size());
     1368        appendFPRegisterName(rt(), size() + 2);
     1369        appendSeparator();
     1370        appendFPRegisterName(rt2(), size() + 2);
    13691371        offsetShift = size() + 2;
    13701372    } else {
  • trunk/Source/JavaScriptCore/disassembler/ARM64/A64DOpcode.h

    r272892 r278856  
    11/*
    2  * Copyright (C) 2012-2019 Apple Inc. All rights reserved.
     2 * Copyright (C) 2012-2021 Apple Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    788788class A64DOpcodeLoadStoreRegisterPair : public A64DOpcodeLoadStore {
    789789public:
    790     static constexpr uint32_t mask = 0x3a000000;
     790    static constexpr uint32_t mask = 0x38000000;
    791791    static constexpr uint32_t pattern = 0x28000000;
    792792
Note: See TracChangeset for help on using the changeset viewer.