VirtualBox

Changeset 104795 in vbox for trunk/include


Ignore:
Timestamp:
May 27, 2024 8:08:37 PM (8 months ago)
Author:
vboxsync
Message:

iprt/asm.h: Added ASMAtomic[Uo]WriteU128[U|v2] and ASMAtomic[Uo]ReadU128[U]. bugref:10687

Location:
trunk/include/iprt
Files:
2 edited

Legend:

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

    r103082 r104795  
    25602560 */
    25612561DECLINLINE(bool) ASMAtomicCmpXchgU128U(volatile RTUINT128U *pu128, const RTUINT128U u128New,
    2562                                         const RTUINT128U u128Old, PRTUINT128U pu128Old) RT_NOTHROW_DEF
     2562                                       const RTUINT128U u128Old, PRTUINT128U pu128Old) RT_NOTHROW_DEF
    25632563{
    25642564# if (defined(__clang_major__) || defined(__GNUC__)) && defined(RT_ARCH_ARM64)
     
    35233523
    35243524
     3525/** @def RTASM_HAVE_READ_U128
     3526 * Defined in the target architecture supports atomic reading of 128-bit
     3527 * integers.
     3528 *
     3529 * The define value is zero if both ordered and unordered reads are implemented
     3530 * using ASMAtomicCmpXchgU128v2().  It is 1 if unordered reads are done natively
     3531 * w/o cmpxchg and 3 if both variants are done natively w/o cmpxchg.
     3532 *
     3533 * @note AMD64: Caller must check for cmpxchg16b support before use and make
     3534 *       sure variables are writable (won't be changed).
     3535 * @sa   RTASM_HAVE_CMP_XCHG_U128, RTASM_HAVE_WRITE_U128
     3536 */
     3537#if defined(RT_ARCH_ARM64) || defined(DOXYGEN_RUNNING)
     3538# define RTASM_HAVE_READ_U128   3
     3539#elif defined(RTASM_HAVE_CMP_XCHG_U128)
     3540# define RTASM_HAVE_READ_U128   0
     3541#endif
     3542
     3543#ifdef RTASM_HAVE_READ_U128
     3544
     3545/**
     3546 * Atomically reads an unsigned 128-bit value, ordered.
     3547 *
     3548 * @returns Current *pu128 value
     3549 * @param   pu128   Pointer to the 128-bit variable to read.
     3550 *                  The memory pointed to must be writable.
     3551 *
     3552 * @remarks AMD64: Requires the memory to be both readable and writable.
     3553 * @remarks AMD64: Requires support for cmpxchg16b.
     3554 */
     3555DECLINLINE(uint128_t) ASMAtomicReadU128(volatile uint128_t RT_FAR *pu128) RT_NOTHROW_DEF
     3556{
     3557    Assert(!((uintptr_t)pu128 & 15));
     3558# if defined(__GNUC__) && defined(RT_ARCH_ARM64)
     3559    RTUINT128U u128Ret;
     3560    __asm__ __volatile__("Lstart_ASMAtomicReadU128_%=:\n\t"
     3561                         RTASM_ARM_DMB_SY
     3562                         "ldp     %[uRetLo], %[uRetHi], %[pMem]\n\t"
     3563                         RTASM_ARM_DMB_SY
     3564                         : [uRetHi] "=r" (u128Ret.s.Hi)
     3565                         , [uRetLo] "=r" (u128Ret.s.Lo)
     3566                         : [pMem]   "Q"  (*pu128)
     3567                         : );
     3568    return u128Ret.u;
     3569# else
     3570    uint128_t u128Ret;
     3571    ASMAtomicCmpXchgU128v2(pu128, 0, 0, 0, 0, &u128Ret);
     3572    return u128Ret;
     3573# endif
     3574}
     3575
     3576/**
     3577 * Atomically reads an unsigned 128-bit value, ordered.
     3578 *
     3579 * @returns Current *pu128 value
     3580 * @param   pu128   Pointer to the 128-bit variable to read.
     3581 *                  The memory pointed to must be writable.
     3582 *
     3583 * @remarks AMD64: Requires the memory to be both readable and writable.
     3584 * @remarks AMD64: Requires support for cmpxchg16b.
     3585 */
     3586DECLINLINE(RTUINT128U) ASMAtomicReadU128U(volatile RTUINT128U RT_FAR *pu128) RT_NOTHROW_DEF
     3587{
     3588    Assert(!((uintptr_t)pu128 & 15));
     3589    RTUINT128U u128Ret;
     3590# if defined(__GNUC__) && defined(RT_ARCH_ARM64)
     3591    __asm__ __volatile__("Lstart_ASMAtomicReadU128U_%=:\n\t"
     3592                         RTASM_ARM_DMB_SY
     3593                         "ldp     %[uRetLo], %[uRetHi], %[pMem]\n\t"
     3594                         RTASM_ARM_DMB_SY
     3595                         : [uRetHi] "=r" (u128Ret.s.Hi)
     3596                         , [uRetLo] "=r" (u128Ret.s.Lo)
     3597                         : [pMem]   "Q"  (*pu128)
     3598                         : );
     3599    return u128Ret;
     3600# else
     3601    ASMAtomicCmpXchgU128v2(&pu128->u, 0, 0, 0, 0, &u128Ret.u);
     3602    return u128Ret;
     3603# endif
     3604}
     3605
     3606
     3607/**
     3608 * Atomically reads an unsigned 128-bit value, unordered.
     3609 *
     3610 * @returns Current *pu128 value
     3611 * @param   pu128   Pointer to the 128-bit variable to read.
     3612 *                  The memory pointed to must be writable.
     3613 *
     3614 * @remarks AMD64: Requires the memory to be both readable and writable.
     3615 * @remarks AMD64: Requires support for cmpxchg16b.
     3616 * @remarks AMD64: Is ordered.
     3617 */
     3618DECLINLINE(uint128_t) ASMAtomicUoReadU128(volatile uint128_t RT_FAR *pu128) RT_NOTHROW_DEF
     3619{
     3620    Assert(!((uintptr_t)pu128 & 15));
     3621# if defined(__GNUC__) && defined(RT_ARCH_ARM64)
     3622    RTUINT128U u128Ret;
     3623    __asm__ __volatile__("Lstart_ASMAtomicUoReadU128_%=:\n\t"
     3624                         "ldp     %[uRetLo], %[uRetHi], %[pMem]\n\t"
     3625                         : [uRetHi] "=r" (u128Ret.s.Hi)
     3626                         , [uRetLo] "=r" (u128Ret.s.Lo)
     3627                         : [pMem]   "Q"  (*pu128)
     3628                         : );
     3629    return u128Ret.u;
     3630
     3631# elif defined(RT_ARCH_AMD64) && 0
     3632    /* This doesn't work because __m128i can't be made volatile and we're not
     3633       able to force MSC (2019) to emit _mm_load_si128 (besides it emits movdqu
     3634       instead of movdqa). */
     3635    __m128i uTmpSse   = _mm_load_si128((__m128i volatile *)pu128);
     3636    __m128i uTmpSseHi = _mm_srli_si128(uTmpSse, 64 / 8);
     3637    RTUINT128U u128Ret;
     3638    u128Ret.s.Lo = (uint64_t)_mm_cvtsi128_si64(uTmpSse);
     3639    u128Ret.s.Hi = (uint64_t)_mm_cvtsi128_si64(uTmpSseHi);
     3640    return u128Ret.u;
     3641
     3642# else
     3643    return ASMAtomicReadU128(pu128);
     3644# endif
     3645}
     3646
     3647/**
     3648 * Atomically reads an unsigned 128-bit value, unordered.
     3649 *
     3650 * @returns Current *pu128 value
     3651 * @param   pu128   Pointer to the 128-bit variable to read.
     3652 *                  The memory pointed to must be writable.
     3653 *
     3654 * @remarks AMD64: Requires the memory to be both readable and writable.
     3655 * @remarks AMD64: Requires support for cmpxchg16b.
     3656 * @remarks AMD64: Is ordered.
     3657 */
     3658DECLINLINE(RTUINT128U) ASMAtomicUoReadU128U(volatile RTUINT128U RT_FAR *pu128) RT_NOTHROW_DEF
     3659{
     3660    Assert(!((uintptr_t)pu128 & 15));
     3661# if defined(__GNUC__) && defined(RT_ARCH_ARM64)
     3662    RTUINT128U u128Ret;
     3663    __asm__ __volatile__("Lstart_ASMAtomicUoReadU128U_%=:\n\t"
     3664                         "ldp     %[uRetLo], %[uRetHi], %[pMem]\n\t"
     3665                         : [uRetHi] "=r" (u128Ret.s.Hi)
     3666                         , [uRetLo] "=r" (u128Ret.s.Lo)
     3667                         : [pMem]   "Q"  (*pu128)
     3668                         : );
     3669    return u128Ret;
     3670# else
     3671    return ASMAtomicReadU128U(pu128);
     3672# endif
     3673}
     3674
     3675#endif /* RTASM_HAVE_READ_U128 */
     3676
    35253677/**
    35263678 * Atomically reads a size_t value, ordered.
     
    40524204}
    40534205
     4206
     4207/** @def RTASM_HAVE_WRITE_U128
     4208 * Defined in the target architecture supports atomic of 128-bit integers.
     4209 *
     4210 * The define value is zero if both ordered and unordered writes are implemented
     4211 * using ASMAtomicCmpXchgU128v2().  It is 1 if unordered writes are done
     4212 * natively w/o cmpxchg and 3 if both variants are done natively w/o cmpxchg.
     4213 *
     4214 * @note AMD64: Caller must check for cmpxchg16b support before use.
     4215 * @sa   RTASM_HAVE_CMP_XCHG_U128
     4216 */
     4217#if defined(RT_ARCH_ARM64) || defined(DOXYGEN_RUNNING)
     4218# define RTASM_HAVE_WRITE_U128  3
     4219#elif defined(RTASM_HAVE_CMP_XCHG_U128)
     4220# define RTASM_HAVE_WRITE_U128  0
     4221#endif
     4222
     4223#ifdef RTASM_HAVE_WRITE_U128
     4224
     4225/**
     4226 * Atomically writes an unsigned 128-bit value, ordered.
     4227 *
     4228 * @param   pu128       Pointer to the variable to overwrite.  Must be aligned
     4229 *                      on 16 byte boundrary.
     4230 * @param   u64Hi       The high 64 bits of the new value.
     4231 * @param   u64Lo       The low 64 bits of the new value.
     4232 */
     4233DECLINLINE(void) ASMAtomicWriteU128v2(volatile uint128_t *pu128, const uint64_t u64Hi, const uint64_t u64Lo) RT_NOTHROW_DEF
     4234{
     4235    Assert(!((uintptr_t)pu128 & 15));
     4236# if defined(__GNUC__) && defined(RT_ARCH_ARM64)
     4237    __asm__ __volatile__("Lstart_ASMAtomicWriteU128v2_%=:\n\t"
     4238# if 0 && defined(RTASM_ARM64_USE_FEAT_LSE128) /** @todo hw support?  test + debug */
     4239                         RTASM_ARM_DMB_SY
     4240                         "swpp    %[uValueLo], %[uValueHi], %[pMem]\n\t"
     4241# else
     4242                         RTASM_ARM_DMB_SY
     4243                         "stp     %[uValueLo], %[uValueHi], %[pMem]\n\t"
     4244                         "dmb     sy\n\t"
     4245# endif
     4246                         : [pMem]     "+Q" (*pu128)
     4247                         : [uValueHi] "r"  (u64Hi)
     4248                         , [uValueLo] "r"  (u64Lo)
     4249                         : );
     4250
     4251# else
     4252    RTUINT128U u128Old;
     4253#  ifdef RT_COMPILER_WITH_128BIT_INT_TYPES
     4254    u128Old.u = *pu128;
     4255#  else
     4256    u128Old.u.Lo = pu128->Lo;
     4257    u128Old.u.Hi = pu128->Hi;
     4258#  endif
     4259    while (!ASMAtomicCmpXchgU128v2(pu128, u64Hi, u64Lo, u128Old.s.Hi, u128Old.s.Lo, &u128Old.u))
     4260    { }
     4261# endif
     4262}
     4263
     4264
     4265/**
     4266 * Atomically writes an unsigned 128-bit value, ordered.
     4267 *
     4268 * @param   pu128       Pointer to the variable to overwrite.  Must be aligned
     4269 *                      on 16 byte boundrary.
     4270 * @param   u64Hi       The high 64 bits of the new value.
     4271 * @param   u64Lo       The low 64 bits of the new value.
     4272 * @note    This is ordered on AMD64.
     4273 */
     4274DECLINLINE(void) ASMAtomicUoWriteU128v2(volatile uint128_t *pu128, const uint64_t u64Hi, const uint64_t u64Lo) RT_NOTHROW_DEF
     4275{
     4276    Assert(!((uintptr_t)pu128 & 15));
     4277# if defined(__GNUC__) && defined(RT_ARCH_ARM64)
     4278    __asm__ __volatile__("Lstart_ASMAtomicUoWriteU128v2_%=:\n\t"
     4279                         "stp     %[uValueLo], %[uValueHi], %[pMem]\n\t"
     4280                         : [pMem]     "+Q" (*pu128)
     4281                         : [uValueHi] "r"  (u64Hi)
     4282                         , [uValueLo] "r"  (u64Lo)
     4283                         : );
     4284
     4285# else
     4286    RTUINT128U u128Old;
     4287#  ifdef RT_COMPILER_WITH_128BIT_INT_TYPES
     4288    u128Old.u = *pu128;
     4289#  else
     4290    u128Old.u.Lo = pu128->Lo;
     4291    u128Old.u.Hi = pu128->Hi;
     4292#  endif
     4293    while (!ASMAtomicCmpXchgU128v2(pu128, u64Hi, u64Lo, u128Old.s.Hi, u128Old.s.Lo, &u128Old.u))
     4294    { }
     4295# endif
     4296}
     4297
     4298
     4299/**
     4300 * Atomically writes an unsigned 128-bit value, ordered.
     4301 *
     4302 * @param   pu128       Pointer to the variable to overwrite.  Must be aligned
     4303 *                      on 16 byte boundrary.
     4304 * @param   u128        The the new value.
     4305 */
     4306DECLINLINE(void) ASMAtomicWriteU128(volatile uint128_t *pu128, const uint128_t u128) RT_NOTHROW_DEF
     4307{
     4308# ifdef RT_COMPILER_WITH_128BIT_INT_TYPES
     4309    ASMAtomicWriteU128v2(pu128, (uint64_t)(u128 >> 64), (uint64_t)u128);
     4310# else
     4311    ASMAtomicWriteU128v2(pu128, u128.Hi, u128.Lo);
     4312# endif
     4313}
     4314
     4315
     4316/**
     4317 * Atomically writes an unsigned 128-bit value, unordered.
     4318 *
     4319 * @param   pu128       Pointer to the variable to overwrite.  Must be aligned
     4320 *                      on 16 byte boundrary.
     4321 * @param   u128        The the new value.
     4322 * @note    This is ordered on AMD64.
     4323 */
     4324DECLINLINE(void) ASMAtomicUoWriteU128(volatile uint128_t *pu128, const uint128_t u128) RT_NOTHROW_DEF
     4325{
     4326# ifdef RT_COMPILER_WITH_128BIT_INT_TYPES
     4327    ASMAtomicUoWriteU128v2(pu128, (uint64_t)(u128 >> 64), (uint64_t)u128);
     4328# else
     4329    ASMAtomicUoWriteU128v2(pu128, u128.Hi, u128.Lo);
     4330# endif
     4331}
     4332
     4333
     4334/**
     4335 * Atomically writes an unsigned 128-bit value, ordered.
     4336 *
     4337 * @param   pu128       Pointer to the variable to overwrite.  Must be aligned
     4338 *                      on 16 byte boundrary.
     4339 * @param   u128        The the new value.
     4340 */
     4341DECLINLINE(void) ASMAtomicWriteU128U(volatile RTUINT128U *pu128, const RTUINT128U u128) RT_NOTHROW_DEF
     4342{
     4343    ASMAtomicWriteU128v2(&pu128->u, u128.s.Hi, u128.s.Lo);
     4344}
     4345
     4346
     4347/**
     4348 * Atomically writes an unsigned 128-bit value, unordered.
     4349 *
     4350 * @param   pu128       Pointer to the variable to overwrite.  Must be aligned
     4351 *                      on 16 byte boundrary.
     4352 * @param   u128        The the new value.
     4353 * @note    This is ordered on AMD64.
     4354 */
     4355DECLINLINE(void) ASMAtomicUoWriteU128U(volatile RTUINT128U *pu128, const RTUINT128U u128) RT_NOTHROW_DEF
     4356{
     4357    ASMAtomicUoWriteU128v2(&pu128->u, u128.s.Hi, u128.s.Lo);
     4358}
     4359
     4360#endif /* RTASM_HAVE_WRITE_U128 */
    40544361
    40554362/**
  • trunk/include/iprt/types.h

    r101140 r104795  
    496496/**
    497497 * 128-bit unsigned integer union.
     498 *
     499 * @note This is not necessarily automatically 16 byte aligned. Sorry.
    498500 */
    499501#pragma pack(1)
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