0

The bit-scan-forward function scans for the first bit, e.g:

assert(13 == __builtin_ctz(1 << 13));

Given an enum that is known at compile time, how can the result of GCC's __builtin_ctz or MSVC's _BitScanForward64 be accessed as a compile time constant?

ideasman42
  • 42,413
  • 44
  • 197
  • 320
  • https://stackoverflow.com/q/51880079/11683? – GSerg Jun 27 '21 at 21:52
  • You'd have to rely on the optimizer to recognize that it's used on a constant value and compute it at compile time. – Shawn Jun 27 '21 at 21:52
  • @Shawn it doesn't _have_ to be computed at compile time, a lookup table can be used, although it's not very elegant (see answer). – ideasman42 Jun 28 '21 at 02:10

1 Answers1

0

Posting an answer since this is possible with an exhaustive tests of all flags.

This Python script defines BITSCAN_FTD_CONSTEXPR, a macro which works for 32bit integer, failing to compile if none of the values are matched.

BITS = 32
parens = []
print("#define BITSCAN_FTD_CONSTEXPR_IMPL(a) \\")
for i in range(0, BITS + 1):
    print("    ((a) & (1u << %du) ? %d : \\" % (i, i))
print("    0", end="")
print(")" * (BITS + 1))
print(r'''
#define BITSCAN_FTD_CONSTEXPR(a) \
  ((sizeof(struct { int _isnt_zero : BITSCAN_FTD_CONSTEXPR_IMPL(a); }) ? \
        BITSCAN_FTD_CONSTEXPR_IMPL(a) : \
        0 /* Unreachable! */ ))''')
#define BITSCAN_FTD_CONSTEXPR_IMPL(a) \
    ((a) & (1u << 0u) ? 0 : \
    ((a) & (1u << 1u) ? 1 : \
    ((a) & (1u << 2u) ? 2 : \
    ((a) & (1u << 3u) ? 3 : \
    ((a) & (1u << 4u) ? 4 : \
    ((a) & (1u << 5u) ? 5 : \
    ((a) & (1u << 6u) ? 6 : \
    ((a) & (1u << 7u) ? 7 : \
    ((a) & (1u << 8u) ? 8 : \
    ((a) & (1u << 9u) ? 9 : \
    ((a) & (1u << 10u) ? 10 : \
    ((a) & (1u << 11u) ? 11 : \
    ((a) & (1u << 12u) ? 12 : \
    ((a) & (1u << 13u) ? 13 : \
    ((a) & (1u << 14u) ? 14 : \
    ((a) & (1u << 15u) ? 15 : \
    ((a) & (1u << 16u) ? 16 : \
    ((a) & (1u << 17u) ? 17 : \
    ((a) & (1u << 18u) ? 18 : \
    ((a) & (1u << 19u) ? 19 : \
    ((a) & (1u << 20u) ? 20 : \
    ((a) & (1u << 21u) ? 21 : \
    ((a) & (1u << 22u) ? 22 : \
    ((a) & (1u << 23u) ? 23 : \
    ((a) & (1u << 24u) ? 24 : \
    ((a) & (1u << 25u) ? 25 : \
    ((a) & (1u << 26u) ? 26 : \
    ((a) & (1u << 27u) ? 27 : \
    ((a) & (1u << 28u) ? 28 : \
    ((a) & (1u << 29u) ? 29 : \
    ((a) & (1u << 30u) ? 30 : \
    ((a) & (1u << 31u) ? 31 : \
    ((a) & (1u << 32u) ? 32 : \
    0)))))))))))))))))))))))))))))))))


#define BITSCAN_FTD_CONSTEXPR(a) \
  ((sizeof(struct { int _isnt_zero : BITSCAN_FTD_CONSTEXPR_IMPL(a); }) ? \
        BITSCAN_FTD_CONSTEXPR_IMPL(a) : \
        0 /* Unreachable! */ ))
  printf("Example: %i\n", BITSCAN_FTD_CONSTEXPR(1 << 12));

Print's Example: 12.


Tested to work with GCC-11 & Clang-12.

ideasman42
  • 42,413
  • 44
  • 197
  • 320