The types used for intrinsics The type system for Intel intrinsics is a little strange. For example from xmmintrin.h: So there is one set of types that are used in the function prototypes of the API, and the internal types that are used in the implementation. Notice the special attribute __may_alias__. From the GCC documentation:
Accesses through pointers to types with this attribute are not subject to type-based alias analysis, but are instead assumed to be able to alias any other type of objects. ... This extension exists to support some vector APIs, in which pointers to one vector type are permitted to alias pointers to a different vector type.
There are a couple of issues here: The use of __may_alias__ in the API seems to force the compiler to assume aliasing of any parameter passed by reference. The GCC vector builtin type system (example above) is slightly different syntax from the original Altivec __vector types. Internally the two typedef forms may represent the same 128-bit vector type, but for early source parsing and overloaded vector builtins they are handled differently. The data type used at the interface may not be the correct type for the implied operation. Normally the compiler assumes that parameters of different size do not overlap in storage, which allows more optimization. However parameters for different vector element sizes [char | short | int | long] are all passed and returned as type __m128i (defined as vector long long). This may not matter when using x86 built-ins but does matter when the implementation uses C vector extensions or in our case using PowerPC overloaded vector built-ins (). For the latter cases the type must be correct for the compiler to generate the correct code for the type (char, short, int, long) () for overloaded builtin operations. There is also concern that excessive use of __may_alias__ will limit compiler optimization. We are not sure how important this attribute is to the correct operation of the API.  So at a later stage we should experiment with removing it from our implementation for PowerPC. The good news is that PowerISA has good support for 128-bit vectors and (with the addition of VSX) all the required vector data (char, short, int, long, float, double) types. However Intel supports a wider variety of the vector sizes  than PowerISA does. This started with the 64-bit MMX vector support that preceded SSE and extends to 256-bit and 512-bit vectors of AVX, AVX2, and AVX512 that followed SSE. Within the GCC Intel intrinsic implementation these are all implemented as vector attribute extensions of the appropriate  size (   __vector_size__ ({8 | 16 | 32, and 64}). For the PowerPC target  GCC currently only supports the native __vector_size__ ( 16 ). These we can support directly in VMX/VSX registers and associated instructions. GCC will compile code with other   __vector_size__ values, but the resulting types are treated as simple arrays of the element type. This does not allow the compiler to use the vector registers for parameter passing and return values. For example this intrinsic from immintrin.h: And test case: Current GCC generates: : 970: 10 00 20 39 li r9,16 974: 98 26 80 7d lxvd2x vs12,0,r4 978: 98 2e 40 7d lxvd2x vs10,0,r5 97c: 20 00 e0 38 li r7,32 980: f8 ff e1 fb std r31,-8(r1) 984: b1 ff 21 f8 stdu r1,-80(r1) 988: 30 00 00 39 li r8,48 98c: 98 4e 04 7c lxvd2x vs0,r4,r9 990: 98 4e 65 7d lxvd2x vs11,r5,r9 994: 00 53 8c f1 xvadddp vs12,vs12,vs10 998: 00 00 c1 e8 ld r6,0(r1) 99c: 78 0b 3f 7c mr r31,r1 9a0: 00 5b 00 f0 xvadddp vs0,vs0,vs11 9a4: c1 ff c1 f8 stdu r6,-64(r1) 9a8: 98 3f 9f 7d stxvd2x vs12,r31,r7 9ac: 98 47 1f 7c stxvd2x vs0,r31,r8 9b0: 98 3e 9f 7d lxvd2x vs12,r31,r7 9b4: 98 46 1f 7c lxvd2x vs0,r31,r8 9b8: 50 00 3f 38 addi r1,r31,80 9bc: f8 ff e1 eb ld r31,-8(r1) 9c0: 98 1f 80 7d stxvd2x vs12,0,r3 9c4: 98 4f 03 7c stxvd2x vs0,r3,r9 9c8: 20 00 80 4e blr]]> The compiler treats the parameters and return value as scalar arrays, which are passed by reference. The operation is vectorized in this case, but the 256-bit result is returned through storage. This is not what we want to see for a simple 4 by double add. It would be better if we can pass and return MMX () and AVX () values as PowerPC registers and avoid the storage references. If we can get the parameter and return values as registers, this example will reduce to: : 970: xvadddp vs34,vs34,vs36 974: xvadddp vs35,vs35,vs37 978: blr]]> So the PowerISA VMX/VSX facilities and GCC compiler support for 128-bit/16-byte vectors and associated vector built-ins are well matched to implementing equivalent X86 SSE intrinsic functions. However implementing the older MMX (64-bit) and the latest AVX (256 / 512-bit) extensions requires more thought and some ingenuity.