VirtualBox

Changeset 93837 in vbox


Ignore:
Timestamp:
Feb 18, 2022 11:14:59 AM (3 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
150043
Message:

iprt/asm.h: Added ASMAtomicCmpXchgU128 and friends for AMD64 and ARM64, implemented ASMAtomicCmpWriteU128 et al for ARM64. bugref:9898

Location:
trunk
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/include/iprt/asm.h

    r93759 r93837  
    14301430}
    14311431
    1432 #if defined(RT_ARCH_AMD64) || defined(DOXYGEN_RUNNING)
     1432#if defined(RT_ARCH_AMD64) || defined(RT_ARCH_ARM64) || defined(DOXYGEN_RUNNING)
    14331433
    14341434/** @def RTASM_HAVE_CMP_WRITE_U128
    1435  * Indicates that we've got ASMAtomicCmpWriteU128() available.  */
     1435 * Indicates that we've got ASMAtomicCmpWriteU128(), ASMAtomicCmpWriteU128v2()
     1436 * and ASMAtomicCmpWriteExU128() available. */
    14361437# define RTASM_HAVE_CMP_WRITE_U128 1
    14371438
     
    14631464    ai64Cmp[1] = u64OldHi;
    14641465    return _InterlockedCompareExchange128((__int64 volatile *)pu128, u64NewHi, u64NewLo, ai64Cmp) != 0;
     1466
     1467#  elif (defined(__clang_major__) || defined(__GNUC__)) && defined(RT_ARCH_ARM64)
     1468    return __sync_bool_compare_and_swap(pu128, ((uint128_t)u64OldHi << 64) | u64OldLo, ((uint128_t)u64NewHi << 64) | u64NewLo);
    14651469
    14661470#  elif defined(RT_ARCH_AMD64)
     
    15061510{
    15071511# ifdef RT_COMPILER_WITH_128BIT_INT_TYPES
     1512#  if (defined(__clang_major__) || defined(__GNUC__)) && defined(RT_ARCH_ARM64)
     1513    return __sync_bool_compare_and_swap(pu128, u128Old, u128New);
     1514#  else
    15081515    return ASMAtomicCmpWriteU128v2(pu128, (uint64_t)(u128New >> 64), (uint64_t)u128New,
    15091516                                   (uint64_t)(u128Old >> 64), (uint64_t)u128Old);
     1517#  endif
    15101518# else
    15111519    return ASMAtomicCmpWriteU128v2(pu128, u128New.Hi, u128New.Lo, u128Old.Hi, u128Old.Lo);
     
    15201528                                        const RTUINT128U u128Old) RT_NOTHROW_DEF
    15211529{
     1530# if (defined(__clang_major__) || defined(__GNUC__)) && defined(RT_ARCH_ARM64)
     1531    return ASMAtomicCmpWriteU128(&pu128->u, u128New.u, u128Old.u);
     1532# else
    15221533    return ASMAtomicCmpWriteU128v2(&pu128->u, u128New.s.Hi, u128New.s.Lo, u128Old.s.Hi, u128Old.s.Lo);
    1523 }
    1524 
    1525 #endif /* RT_ARCH_AMD64 */
    1526 
     1534# endif
     1535}
     1536
     1537#endif /* RT_ARCH_AMD64 || RT_ARCH_ARM64 */
    15271538
    15281539/**
     
    21802191    return ASMAtomicCmpXchgExU64((volatile uint64_t RT_FAR *)pi64, (uint64_t)i64, (uint64_t)i64Old, (uint64_t RT_FAR *)pi64Old);
    21812192}
     2193
     2194#if defined(RT_ARCH_AMD64) || defined(RT_ARCH_ARM64) || defined(DOXYGEN_RUNNING)
     2195
     2196/** @def RTASM_HAVE_CMP_XCHG_U128
     2197 * Indicates that we've got ASMAtomicCmpSwapU128(), ASMAtomicCmpSwapU128v2()
     2198 * and ASMAtomicCmpSwapExU128() available. */
     2199# define RTASM_HAVE_CMP_XCHG_U128 1
     2200
     2201
     2202/**
     2203 * Atomically compare and exchange an unsigned 128-bit value, ordered.
     2204 *
     2205 * @returns true if exchange was done.
     2206 * @returns false if exchange wasn't done.
     2207 *
     2208 * @param   pu128       Pointer to the 128-bit variable to update.
     2209 * @param   u64NewHi    The high 64 bits of the value to assign to *pu128.
     2210 * @param   u64NewLo    The low 64 bits of the value to assign to *pu128.
     2211 * @param   u64OldHi    The high 64-bit of the value to compare with.
     2212 * @param   u64OldLo    The low 64-bit of the value to compare with.
     2213 * @param   pu128Old    Where to return the old value.
     2214 *
     2215 * @remarks AMD64: Not present in the earliest CPUs, so check CPUID.
     2216 */
     2217# if (RT_INLINE_ASM_EXTERNAL_TMP_ARM && !RT_INLINE_ASM_USES_INTRIN)
     2218DECLASM(bool) ASMAtomicCmpXchgU128v2(volatile uint128_t *pu128, const uint64_t u64NewHi, const uint64_t u64NewLo,
     2219                                     const uint64_t u64OldHi, const uint64_t u64OldLo, uint128_t *pu128Old) RT_NOTHROW_PROTO;
     2220# else
     2221DECLINLINE(bool) ASMAtomicCmpXchgU128v2(volatile uint128_t *pu128, const uint64_t u64NewHi, const uint64_t u64NewLo,
     2222                                        const uint64_t u64OldHi, const uint64_t u64OldLo, uint128_t *pu128Old) RT_NOTHROW_DEF
     2223{
     2224#  if RT_INLINE_ASM_USES_INTRIN
     2225    pu128Old->Hi = u64OldHi;
     2226    pu128Old->Lo = u64OldLo;
     2227    AssertCompileMemberOffset(uint128_t, Lo, 0);
     2228    return _InterlockedCompareExchange128((__int64 volatile *)pu128, u64NewHi, u64NewLo, (__int64 *)&pu128Old->Lo) != 0;
     2229
     2230#  elif (defined(__clang_major__) || defined(__GNUC__)) && defined(RT_ARCH_ARM64)
     2231    uint128_t const uCmp = ((uint128_t)u64OldHi << 64) | u64OldLo;
     2232    uint128_t const uOld = __sync_val_compare_and_swap(pu128, uCmp, ((uint128_t)u64NewHi << 64) | u64NewLo);
     2233    *pu128Old = uOld;
     2234    return uCmp == uOld;
     2235
     2236#  elif defined(RT_ARCH_AMD64)
     2237#   if RT_INLINE_ASM_GNU_STYLE
     2238    uint8_t bRet;
     2239    uint64_t u64RetHi, u64RetLo;
     2240    __asm__ __volatile__("lock; cmpxchg16b %3\n\t"
     2241                         "setz  %b0\n\t"
     2242                         : "=r" (bRet)
     2243                         , "=a" (u64RetLo)
     2244                         , "=d" (u64RetHi)
     2245                         , "+m" (*pu128)
     2246                         : "a" (u64OldLo)
     2247                         , "d" (u64OldHi)
     2248                         , "b" (u64NewLo)
     2249                         , "c" (u64NewHi)
     2250                         : "cc");
     2251    *pu128Old = ((uint128_t)u64RetHi << 64) | u64RetLo;
     2252    return (bool)bRet;
     2253#   else
     2254#    error "Port me"
     2255#   endif
     2256#  else
     2257#   error "Port me"
     2258#  endif
     2259}
     2260# endif
     2261
     2262
     2263/**
     2264 * Atomically compare and exchange an unsigned 128-bit value, ordered.
     2265 *
     2266 * @returns true if exchange was done.
     2267 * @returns false if exchange wasn't done.
     2268 *
     2269 * @param   pu128       Pointer to the 128-bit variable to update.
     2270 * @param   u128New     The 128-bit value to assign to *pu128.
     2271 * @param   u128Old     The value to compare with.
     2272 * @param   pu128Old    Where to return the old value.
     2273 *
     2274 * @remarks AMD64: Not present in the earliest CPUs, so check CPUID.
     2275 */
     2276DECLINLINE(bool) ASMAtomicCmpXchgU128(volatile uint128_t *pu128, const uint128_t u128New,
     2277                                      const uint128_t u128Old, uint128_t *pu128Old) RT_NOTHROW_DEF
     2278{
     2279# ifdef RT_COMPILER_WITH_128BIT_INT_TYPES
     2280#  if (defined(__clang_major__) || defined(__GNUC__)) && defined(RT_ARCH_ARM64)
     2281    uint128_t const uSwapped = __sync_val_compare_and_swap(pu128, u128Old, u128New);
     2282    *pu128Old = uSwapped;
     2283    return uSwapped == u128Old;
     2284#  else
     2285    return ASMAtomicCmpXchgU128v2(pu128, (uint64_t)(u128New >> 64), (uint64_t)u128New,
     2286                                  (uint64_t)(u128Old >> 64), (uint64_t)u128Old, pu128Old);
     2287#  endif
     2288# else
     2289    return ASMAtomicCmpXchgU128v2(pu128, u128New.Hi, u128New.Lo, u128Old.Hi, u128Old.Lo, pu128Old);
     2290# endif
     2291}
     2292
     2293
     2294/**
     2295 * RTUINT128U wrapper for ASMAtomicCmpXchgU128.
     2296 */
     2297DECLINLINE(bool) ASMAtomicCmpXchgU128U(volatile RTUINT128U *pu128, const RTUINT128U u128New,
     2298                                        const RTUINT128U u128Old, PRTUINT128U pu128Old) RT_NOTHROW_DEF
     2299{
     2300# if (defined(__clang_major__) || defined(__GNUC__)) && defined(RT_ARCH_ARM64)
     2301    return ASMAtomicCmpXchgU128(&pu128->u, u128New.u, u128Old.u, &pu128Old->u);
     2302# else
     2303    return ASMAtomicCmpXchgU128v2(&pu128->u, u128New.s.Hi, u128New.s.Lo, u128Old.s.Hi, u128Old.s.Lo, &pu128Old->u);
     2304# endif
     2305}
     2306
     2307#endif /* RT_ARCH_AMD64 || RT_ARCH_ARM64 */
     2308
     2309
    21822310
    21832311/** @def ASMAtomicCmpXchgExHandle
  • trunk/src/VBox/Runtime/testcase/tstRTInlineAsm.cpp

    r93755 r93837  
    15491549                                                                     u128B = RTUINT128_INIT_C(0x80040008008efd, 0x40080004004def)),
    15501550                           true, 0xfff40ff8f08ef3, 0x4ee8ee04cc4de4);
     1551
     1552    /* Make sure the v2 version works too (arm) */
     1553    CHECK_OP_AND_VAL_128_C(bool, "%d", pu128, ASMAtomicCmpWriteU128v2(&pu128->u,
     1554                                                                      UINT64_C(0x95487930069587), UINT64_C(0x89958490385964),
     1555                                                                      UINT64_C(0xfff40ff8f08ef3), UINT64_C(0x4ee8ee04cc4de4)),
     1556                           true, 0x95487930069587, 0x89958490385964);
     1557    CHECK_OP_AND_VAL_128_C(bool, "%d", pu128, ASMAtomicCmpWriteU128v2(&pu128->u,
     1558                                                                      UINT64_C(0x99969404869434), UINT64_C(0x11049309994567),
     1559                                                                      UINT64_C(0x33f40ff8f08eff), UINT64_C(0x99e8ee04cc4dee)),
     1560                           false, 0x95487930069587, 0x89958490385964);
    15511561}
    15521562#endif /* RTASM_HAVE_CMP_WRITE_U128 */
     
    16981708}
    16991709
     1710DECLINLINE(void) tstASMAtomicCmpXchgU128Worker(RTUINT128U volatile *pu128)
     1711{
     1712    pu128->s.Lo = UINT64_C(0xffffffffffffff);
     1713    pu128->s.Hi = UINT64_C(0xffffffffffffff);
     1714
     1715    RTUINT128U u128A, u128B;
     1716    RTUINT128U const u128OldInit = RTUINT128_INIT_C(0x4242424242424242, 0x2222222222222222);
     1717    RTUINT128U       u128Old     = u128OldInit;
     1718    CHECK_OP_AND_VAL_128_C(bool, "%d", pu128, ASMAtomicCmpXchgU128U(pu128,
     1719                                                                    u128A = RTUINT128_INIT_C(0, 0),
     1720                                                                    u128B = RTUINT128_INIT_C(0, 0),
     1721                                                                    &u128Old),
     1722                           false, 0xffffffffffffff, 0xffffffffffffff);
     1723    CHECKVAL128_C(&u128Old, 0xffffffffffffff, 0xffffffffffffff);
     1724
     1725    u128Old = u128OldInit;
     1726    CHECK_OP_AND_VAL_128_C(bool, "%d", pu128, ASMAtomicCmpXchgU128U(pu128,
     1727                                                                    u128A = RTUINT128_INIT_C(0, 0),
     1728                                                                    u128B = RTUINT128_INIT_C(0xffffffffffffff, 0xffffffffffffff),
     1729                                                                    &u128Old),
     1730                           true, 0, 0);
     1731    CHECKVAL128_C(&u128Old, 0xffffffffffffff, 0xffffffffffffff);
     1732
     1733    u128Old = u128OldInit;
     1734    CHECK_OP_AND_VAL_128_C(bool, "%d", pu128, ASMAtomicCmpXchgU128U(pu128,
     1735                                                                    u128A = RTUINT128_INIT_C(0x80040008008efd, 0x40080004004def),
     1736                                                                    u128B = RTUINT128_INIT_C(0, 1),
     1737                                                                    &u128Old),
     1738                           false, 0, 0);
     1739    CHECKVAL128_C(&u128Old, 0, 0);
     1740
     1741    u128Old = u128OldInit;
     1742    CHECK_OP_AND_VAL_128_C(bool, "%d", pu128, ASMAtomicCmpXchgU128U(pu128,
     1743                                                                    u128A = RTUINT128_INIT_C(0x80040008008efd, 0x40080004004def),
     1744                                                                    u128B = RTUINT128_INIT_C(1, 0),
     1745                                                                    &u128Old),
     1746                           false, 0, 0);
     1747    CHECKVAL128_C(&u128Old, 0, 0);
     1748
     1749    u128Old = u128OldInit;
     1750    CHECK_OP_AND_VAL_128_C(bool, "%d", pu128, ASMAtomicCmpXchgU128U(pu128,
     1751                                                                    u128A = RTUINT128_INIT_C(0x80040008008efd, 0x40080004004def),
     1752                                                                    u128B = RTUINT128_INIT_C(0, 0),
     1753                                                                    &u128Old),
     1754                           true, 0x80040008008efd, 0x40080004004def);
     1755    CHECKVAL128_C(&u128Old, 0, 0);
     1756
     1757    u128Old = u128OldInit;
     1758    CHECK_OP_AND_VAL_128_C(bool, "%d", pu128, ASMAtomicCmpXchgU128U(pu128,
     1759                                                                    u128A = RTUINT128_INIT_C(0xfff40ff8f08ef3, 0x4ee8ee04cc4de4),
     1760                                                                    u128B = RTUINT128_INIT_C(0x80040008008efd, 0),
     1761                                                                    &u128Old),
     1762                           false, 0x80040008008efd, 0x40080004004def);
     1763    CHECKVAL128_C(&u128Old, 0x80040008008efd, 0x40080004004def);
     1764
     1765    u128Old = u128OldInit;
     1766    CHECK_OP_AND_VAL_128_C(bool, "%d", pu128, ASMAtomicCmpXchgU128U(pu128,
     1767                                                                    u128A = RTUINT128_INIT_C(0xfff40ff8f08ef3, 0x4ee8ee04cc4de4),
     1768                                                                    u128B = RTUINT128_INIT_C(0, 0x40080004004def),
     1769                                                                    &u128Old),
     1770                           false, 0x80040008008efd, 0x40080004004def);
     1771    CHECKVAL128_C(&u128Old, 0x80040008008efd, 0x40080004004def);
     1772
     1773    u128Old = u128OldInit;
     1774    CHECK_OP_AND_VAL_128_C(bool, "%d", pu128, ASMAtomicCmpXchgU128U(pu128,
     1775                                                                    u128A = RTUINT128_INIT_C(0xfff40ff8f08ef3, 0x4ee8ee04cc4de4),
     1776                                                                    u128B = RTUINT128_INIT_C(0x80040008008efd, 0x40080004004def),
     1777                                                                    &u128Old),
     1778                           true, 0xfff40ff8f08ef3, 0x4ee8ee04cc4de4);
     1779    CHECKVAL128_C(&u128Old, 0x80040008008efd, 0x40080004004def);
     1780
     1781    /* Make sure the v2 version works too (arm) */
     1782    u128Old = u128OldInit;
     1783    CHECK_OP_AND_VAL_128_C(bool, "%d", pu128, ASMAtomicCmpXchgU128v2(&pu128->u,
     1784                                                                     UINT64_C(0x78039485960543), UINT64_C(0x97058437294586),
     1785                                                                     UINT64_C(0xfff40ff8f08ef3), UINT64_C(0x4ee8ee04cc4de4),
     1786                                                                     &u128Old.u),
     1787                           true, 0x78039485960543, 0x97058437294586);
     1788    CHECKVAL128_C(&u128Old, 0xfff40ff8f08ef3, 0x4ee8ee04cc4de4);
     1789
     1790    u128Old = u128OldInit;
     1791    CHECK_OP_AND_VAL_128_C(bool, "%d", pu128, ASMAtomicCmpXchgU128v2(&pu128->u,
     1792                                                                     UINT64_C(0x13495874560495), UINT64_C(0x12304896098597),
     1793                                                                     UINT64_C(0xfff40ff8f08ef3), UINT64_C(0x4ee8ee04cc4de4),
     1794                                                                     &u128Old.u),
     1795                           false, 0x78039485960543, 0x97058437294586);
     1796    CHECKVAL128_C(&u128Old, 0x78039485960543, 0x97058437294586);
     1797}
     1798
    17001799
    17011800static void tstASMAtomicCmpXchgEx(void)
     
    17051804    DO_SIMPLE_TEST(ASMAtomicCmpXchgExU32, uint32_t);
    17061805    DO_SIMPLE_TEST(ASMAtomicCmpXchgExU64, uint64_t);
     1806#ifdef RTASM_HAVE_CMP_XCHG_U128
     1807# ifdef RT_ARCH_AMD64
     1808    if (ASMCpuId_ECX(1) & X86_CPUID_FEATURE_ECX_CX16)
     1809# endif
     1810    {
     1811        RTTestISub("ASMAtomicCmpXchgU128");
     1812        DO_SIMPLE_TEST_NO_SUB_NO_STACK(tstASMAtomicCmpXchgU128Worker, RTUINT128U);
     1813    }
     1814#endif
    17071815}
    17081816
     
    28012909    static uint64_t volatile s_u64;
    28022910    static int64_t  volatile s_i64;
     2911#if defined(RTASM_HAVE_CMP_WRITE_U128) || defined(RTASM_HAVE_CMP_XCHG_U128)
     2912    static RTUINT128U volatile s_u128;
     2913#endif
    28032914    static uint8_t  s_u8Old;
    28042915    static int8_t   s_i8Old;
     
    28092920    static uint64_t s_u64Old;
    28102921    static int64_t  s_i64Old;
     2922#if defined(RTASM_HAVE_CMP_WRITE_U128) || defined(RTASM_HAVE_CMP_XCHG_U128)
     2923    static RTUINT128U s_u128Old;
     2924    RTUINT128U u128Tmp1, u128Tmp2;
     2925# ifdef RT_ARCH_AMD64
     2926    bool const fHaveCmpXchg128 = RT_BOOL(ASMCpuId_ECX(1) & X86_CPUID_FEATURE_ECX_CX16);
     2927# else
     2928    bool const fHaveCmpXchg128 = true;
     2929# endif
     2930#endif
    28112931    unsigned i;
    28122932    const unsigned cRounds = _16M;       /* Must be multiple of 8 */
     
    29173037    BENCH(ASMAtomicCmpXchgU64(&s_u64, 0, 0),     "ASMAtomicCmpXchgU64");
    29183038    BENCH(ASMAtomicCmpXchgS64(&s_i64, 0, 0),     "ASMAtomicCmpXchgS64");
     3039#ifdef RTASM_HAVE_CMP_WRITE_U128
     3040    if (fHaveCmpXchg128)
     3041        BENCH(ASMAtomicCmpWriteU128U(&s_u128, u128Tmp1 = RTUINT128_INIT_C(0, 0), u128Tmp2 = RTUINT128_INIT_C(0, 0)),
     3042              "ASMAtomicCmpWriteU128U");
     3043#endif
    29193044    BENCH(ASMAtomicCmpXchgU8(&s_u8, 0, 1),       "ASMAtomicCmpXchgU8/neg");
    29203045    BENCH(ASMAtomicCmpXchgS8(&s_i8, 0, 1),       "ASMAtomicCmpXchgS8/neg");
     
    29253050    BENCH(ASMAtomicCmpXchgU64(&s_u64, 0, 1),     "ASMAtomicCmpXchgU64/neg");
    29263051    BENCH(ASMAtomicCmpXchgS64(&s_i64, 0, 1),     "ASMAtomicCmpXchgS64/neg");
     3052#ifdef RTASM_HAVE_CMP_WRITE_U128
     3053    if (fHaveCmpXchg128)
     3054        BENCH(ASMAtomicCmpWriteU128U(&s_u128, u128Tmp1 = RTUINT128_INIT_C(0, 0), u128Tmp2 = RTUINT128_INIT_C(0, 1)),
     3055              "ASMAtomicCmpWriteU128U/neg");
     3056#endif
    29273057    BENCH(ASMAtomicCmpXchgExU8(&s_u8, 0, 0, &s_u8Old),    "ASMAtomicCmpXchgExU8");
    29283058    BENCH(ASMAtomicCmpXchgExS8(&s_i8, 0, 0, &s_i8Old),    "ASMAtomicCmpXchgExS8");
     
    29333063    BENCH(ASMAtomicCmpXchgExU64(&s_u64, 0, 0, &s_u64Old), "ASMAtomicCmpXchgExU64");
    29343064    BENCH(ASMAtomicCmpXchgExS64(&s_i64, 0, 0, &s_i64Old), "ASMAtomicCmpXchgExS64");
     3065#ifdef RTASM_HAVE_CMP_XCHG_U128
     3066    if (fHaveCmpXchg128)
     3067        BENCH(ASMAtomicCmpXchgU128U(&s_u128, u128Tmp1 = RTUINT128_INIT_C(0, 0), u128Tmp2 = RTUINT128_INIT_C(0, 0), &s_u128Old),
     3068              "ASMAtomicCmpXchgU128U");
     3069#endif
    29353070    BENCH(ASMAtomicCmpXchgExU8(&s_u8, 0, 1, &s_u8Old),    "ASMAtomicCmpXchgExU8/neg");
    29363071    BENCH(ASMAtomicCmpXchgExS8(&s_i8, 0, 1, &s_i8Old),    "ASMAtomicCmpXchgExS8/neg");
     
    29413076    BENCH(ASMAtomicCmpXchgExU64(&s_u64, 0, 1, &s_u64Old), "ASMAtomicCmpXchgExU64/neg");
    29423077    BENCH(ASMAtomicCmpXchgExS64(&s_i64, 0, 1, &s_i64Old), "ASMAtomicCmpXchgExS64/neg");
     3078#ifdef RTASM_HAVE_CMP_XCHG_U128
     3079    if (fHaveCmpXchg128)
     3080        BENCH(ASMAtomicCmpXchgU128U(&s_u128, u128Tmp1 = RTUINT128_INIT_C(0, 0), u128Tmp2 = RTUINT128_INIT_C(0, 1), &s_u128Old),
     3081              "ASMAtomicCmpXchgU128U/neg");
     3082#endif
    29433083    BENCH(ASMAtomicIncU32(&s_u32),               "ASMAtomicIncU32");
    29443084    BENCH(ASMAtomicIncS32(&s_i32),               "ASMAtomicIncS32");
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette