I'm writing a piece of code using GCC's vector extensions (__attribute__((vector_size(x)))
) that needs several constant masks. These masks are simple enough to fill in sequentially, but adding them as vector literals is tedious and error prone, not to mention limiting potential changes in vector size.
Is it possible to generate the constants using a constexpr function?
I've tried generating the values like this:
using u8v = uint8_t __attribute__((vector_size(64)));
auto generate_mask = []() constexpr {
u8v ret;
for (size_t i = 0; i < sizeof(u8v); ++i) {
ret[i] = i & 0xff;
}
return ret;
};
constexpr auto mask = generate_mask();
but GCC says modification of u8v
is not a constant expression.
Is there some workaround, using G++ with C++20 features?
Technically possible, but complicated to the point of being unusable. An example unrelated to SIMD.
Still, the workarounds aren’t that bad.
SIMD vectors can’t be embedded into instruction stream anyway. Doesn’t matter your code says constexpr auto mask
, in reality the compiler will generate the complete vector, place the data in the read-only segment of your binary, and load from there as needed.
The exception is when your vector can be generated faster than RAM loads. A vector with all zeroes can be made without RAM access with vpxor
, a vector with all bits set can be made with vpcmpeqd
, and vectors with the same value in all lanes can be made with broadcast instructions. Anything else will result in full-vector load from the binary.
This means you can replace your constexpr
with const
and the binary will be the same. If that code is in a header file, ideally you’d also want __declspec(selectany)
when building with VC++, or in your case the GCC’s equivalent is __attribute__((weak))