Vector initialization used to be such a mess. You would think that creating a SIMD vector from its scalars would be easy to standardize, no?
Consider Motorola Altivec PIM style initialization. The SIMD vector in Altivec is a new built-in type initialized with the following syntax:
__vector signed int v = (__vector signed int) (1, 2, 3, 4); // element sequence is 1, 2, 3, 4
__vector signed int w = (__vector signed int) (1); // each element is 1
This style is supported by most standard OS X compilers: Apple gcc, Metrowerks Codewarrior and IBM XLC. However, the syntax actually means something else in the C89, C99 and C++98 standards and as such often confuses the poor parsers that have to decipher it. For example, within C++ template functions it is sometimes seen as an incorrect cast, or compile-time constants are not recognized as such. And finally, you cannot use variables to initialize.
Now look at the mainline gcc syntax for the same:
__vector signed int v = (__vector unsigned int) {1, 2, 3, 4}; // element sequence is 1, 2, 3, 4
__vector signed int w = (__vector unsigned int) {1}; // first element is 1, rest is 0
This style is equivalent to the C99 array initialization syntax, but is an error with C89 and C++98. Unfortunately, this syntax is not supported by the standard OS X compilers. More dangerously, the single element initializer does something different from the PIM-style version.
The situation gets worse on the Intel side. With the Visual C++ .NET 2003 compiler syntax, the SIMD vector is not a new built-in type but a union, so the following works:
__m128i v = {1, 2, 3, 4}; // element sequence is 1, 2, 3, 4
__m128i w = {1}; // first element is 1, rest is undefined
Unlike with the Altivec compilers, you can't initialize a temporary this way since Visual C++ doesn't support C99. And of course, its yet another incompatible syntax and difference with single element initializer.
Enter macstl's Grand Unified Theory of vector initialization.
You can initialize a vector statically with constants:
vec <int, 4> v = vec <int, 4>::set <1, 2, 3, 4> (); // element sequence is 1, 2, 3, 4
vec <int, 4> w = vec <int, 4>::fill <1> (); // each element is 1
Amazingly this syntax works identically on all OS X compilers and also on Visual C++ .NET, a different architecture. Its now clear which initializer sets individual elements, and which initializer fills all the elements.
On Altivec, the library will also transparently substitute 1 and 2 opcode VPERM sequences for some constants, avoiding the slower load from L1 cache.
One drawback: floating point vectors have to be initialized with unsigned integers, since C++ doesn't allow floating point numbers for non-type template parameters.
You can also initialize a vector dynamically with either constants or variables:
vec <int, 4> v = vec <int, 4>::set (1, 2, 3, 4); // element sequence is 1, 2, 3, 4
vec <int, 4> w = vec <int, 4>::fill (1); // each element is 1
Dynamic initialization is more flexible but can be slower than static initialization. It also yields a more intuitive syntax for floating point vectors.