Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement __builtin_zero_non_value_bits which was recently added to MSVC for P0528R3 and P1123R0 #46030

Open
AlexGuteniev mannequin opened this issue Jul 11, 2020 · 0 comments
Labels
bugzilla Issues migrated from bugzilla c++20

Comments

@AlexGuteniev
Copy link
Mannequin

AlexGuteniev mannequin commented Jul 11, 2020

Bugzilla Link 46685
Version 10.0
OS Windows NT
CC @zygoloid

Extended Description

MSVC implements __builtin_zero_non_value_bits intrinsic.

This is needed to implement C++2a features:

  • P0528R3 Atomic Compare-And-Exchange With Padding Bits
  • P1123R0 Atomic Compare-And-Exchange With Padding Bits For atomic_ref

__builtin_zero_non_value_bits non-atomically zeros non-value bits in types such as

struct X
{
    int a;
    char b;
    // 3 bytes padding for 32-bit int
};

or

struct Y
{
    int a: 7;
    // 25 bits of padding for 32-bit int
};

For std::atomic it can be used in constructor and in store and exchange.
So compare_exchange_* would be able to use bitwise comparison, as non-value bits are always zeros

For std::atomic_ref non-atomically zeroing in constructor is apparently not an option due to possible concurrent atomic_ref instances.
Still, __builtin_zero_non_value_bits can be used.
For lock-free atomics, compute the mask as follows:

target_type v;
memset(&v, 0xff, sizeof(v));
__builtin_zero_non_value_bits(&v);
integer_type value_mask;
memcpy(&value_mask, &v, sizeof(v));

Then implement compare_exchange as follows:

for(;;)
    integer_type prev = _InterlockedCompareExchange(
                           &val, desired, expected);
    if (prev == expected) {
        return true; // Success
    }

    if ((prev ^ expected) & value_mask) {
        break; // Failure due to value bits mismatch, fail
    }
    
    // Failure due to only padding bits mismatch
    // Retry with new expectation for padding bits
    expected = (expected & value_mask) | (prev & ~value_mask);
}

For lock-based atomic_ref just apply __builtin_zero_non_value_bits both to target (under the lock) and comparand (possibly not under the lock)

std::atomic_ref method can also be used for std::atomic too for unification.

Note that:

  • In atomic_ref method, the computation of mask should defacto result in value_mask computed by compiler in case of optimization enabled
  • In atomic method __builtin_zero_non_value_bits should also work in compile time in constexpr constructor
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bugzilla Issues migrated from bugzilla c++20
Projects
Status: No status
Development

No branches or pull requests

0 participants