[llvm-bugs] [Bug 46685] New: Implement __builtin_zero_non_value_bits which was recently added to MSVC for P0528R3 and P1123R0

via llvm-bugs llvm-bugs at lists.llvm.org
Sat Jul 11 05:46:40 PDT 2020


https://bugs.llvm.org/show_bug.cgi?id=46685

            Bug ID: 46685
           Summary: Implement __builtin_zero_non_value_bits which was
                    recently added to MSVC for P0528R3 and P1123R0
           Product: clang
           Version: 10.0
          Hardware: PC
                OS: Windows NT
            Status: NEW
          Severity: normal
          Priority: P
         Component: C++2a
          Assignee: unassignedclangbugs at nondot.org
          Reporter: gutenev at gmail.com
                CC: blitzrakete at gmail.com, erik.pilkington at gmail.com,
                    llvm-bugs at lists.llvm.org, richard-llvm at metafoo.co.uk

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

-- 
You are receiving this mail because:
You are on the CC list for the bug.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-bugs/attachments/20200711/0824943b/attachment-0001.html>


More information about the llvm-bugs mailing list