_mm_set1_ps(-87);
or any other _mm_set
intrinsic is not a valid static initializer with current compilers, because it's not treated as a constant expression.
In C++, it compiles to runtime initialization of the static
storage location (copying from a vector literal somewhere else). And if it's a static __m128
inside a function, there's a guard variable to protect it.
In C, it simply refuses to compile, because C doesn't support non-constant initializers / constructors. _mm_set
is not like a braced initializer for the underlying GNU C native vector, like @benjarobin's answer shows.
This is really dumb, and seems to be a missed-optimization in all 4 mainstream x86 C++ compilers (gcc/clang/ICC/MSVC). Even if it somehow matters that each static const __m128 var
have a distinct address, the compiler could achieve that by using initialized read-only storage instead of copying at runtime.
So it seems like constant propagation fails to go all the way to turning _mm_set
into a constant initializer even when optimization is enabled.
Never use static const __m128 var = _mm_set...
even in C++; it's inefficient.
Inside a function is even worse, but global scope is still bad.
Instead, avoid static
. You can still use const
to stop yourself from accidentally assigning something else, and to tell human readers that it's a constant. Without static
, it has no effect on where/how your variable is stored. const
on automatic storage just does compile-time checking that you don't modify the object.
const __m128 var = _mm_set1_ps(-87); // not static
Compilers are good at this, and will optimize the case where multiple functions use the same vector constant, the same way they de-duplicate string literals and put them in read-only memory.
Defining constants this way inside small helper functions is fine: compilers will hoist the constant-setup out of a loop after inlining the function.
It also lets compilers optimize away the full 16 bytes of storage, and load it with vbroadcastss xmm0, dword [mem]
, or stuff like that.