Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Way to effectively call _BitScanReverse or __builtin_clz in constexpr functions?

It seems that _BitScanReverse, despite being an intrinsic and not a real function, can't be called in a constexpr function in Visual C++. I'm aware that I can implement this operation myself in a much slower way, which would be fine for the case where it's evaluated at compile-time but it's unfortunate that it wouldn't just be the 1-clock-cycle, single CPU instruction (BSR) for the case where it's evaluated at run-time. I haven't tried __builtin_clz in GCC/Clang yet, but it might or might not have the same sort of issue, and I want this code to work across the major compilers, (with a slow fallback for non-GCC, non-Clang, non-VC compilers).

Ideas/Questions:

Is there an easy way to have a function use one block of code when evaluating at compile-time, so that it can be constexpr-safe, and a different block of code for run-time, so that it can be fast? (If so, this would also be relevant to a few other questions I have.)

Alternatively, is there a way to trick the compiler into being able to evaluate _BitScanReverse for constexpr code?

Side question:

Is there any word of plans to eventually add this to the C++ standard? They've added std::log2 and std::ilogb, but those both go through floating-point numbers, instead of just doing one BSR, (or CLZ and a subtraction on ARM chips).

like image 292
Neil Dickson Avatar asked Oct 09 '17 20:10

Neil Dickson


1 Answers

For C++20 you can use std::bit_width and others form <bit> header

template< class T >
constexpr T bit_width(T x) noexcept;
#include <bit>
#include <bitset>
#include <iostream>
#include <array>

using BitArray = std::array<unsigned, 8>;

constexpr BitArray Bits() {
    BitArray bits;
    for (unsigned x{0}; x != 8; ++x)
      bits[x] = std::bit_width(x);
    return bits;
}

auto main() -> int {
    constexpr BitArray bits = Bits();

    for (unsigned x{0}; x != 8; ++x) {
        std::cout
            << "bit_width( "
            << std::bitset<4>{x} << " ) = "
            << bits[x] << " "
            << std::bit_width(x) << '\n';
    }
}

Try it on Godbolt

like image 134
Surt Avatar answered Sep 27 '22 19:09

Surt