DirectXMath: SSE4.1 and SSE4.2

The SSE4 instruction set consists of two parts, referred as SSE4.1 and 4.2. The intrinsics are located in the smmintrin.h header. The SSE4.1 instruction set is the most interesting for DirectXMath, while SSE 4.2 adds some more specialized instructions for CRC checks and string handling. The key new features are a flexible dot-product instruction, float4 vector rounding, a 2-vector ‘mux’ blend, and some specialized extract/insert operations.

A number of DirectXMath functions can be replaced with a single intrinsic when using SSE4.1.

XMVector2Dot(V1,V2) _mm_dp_ps( V1, V2, 0x3f )
XMVector3Dot(V1,V2) _mm_dp_ps( V1, V2, 0x7f )
XMVector4Dot(V1,V2) _mm_dp_ps( V1, V2, 0xff )
XMVectorRound(V) _mm_round_ps( V, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC )
XMVectorTruncate(V) _mm_round_ps( V, _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC )
XMVectorFloor(V) _mm_floor_ps( V )
XMVectorCeiling(V) _mm_ceil_ps( V )

The bit insert/extract instructions provide some specific optimization cases for vector accessors and setters. Here are the “Y” element versions, which can be extrapolated to the “Z” and “W” element versions very easily. Note that the standard scalar SSE/SSE2 mov already provides efficient support for the “X” element.

 inline void XMVectorGetYPtr(float *y, FXMVECTOR V)
 *((int*)y) = _mm_extract_ps( V, 1 );

 inline uint32_t XMVectorGetIntY(FXMVECTOR V)
 __m128i V1 = _mm_castps_si128( V );
 return static_cast<uint32_t>( _mm_extract_epi32( V1, 1 ) );

 inline void XMVectorGetIntYPtr(uint32_t *y, FXMVECTOR V)
 __m128i V1 = _mm_castps_si128( V );
 *y = static_cast<uint32_t>( _mm_extract_epi32( V1, 1 ) );

 inline XMVECTOR XMVectorSetY(FXMVECTOR V, float y)
 XMVECTOR vResult = _mm_set_ss(y);
 vResult = _mm_insert_ps( V, vResult, 0x10 );
 return vResult;

 inline XMVECTOR XMVectorSetIntY(FXMVECTOR V, uint32_t y)
 __m128i vResult = _mm_castps_si128( V );
 vResult =
 _mm_insert_epi32( vResult, static_cast<int>(y), 1 );
 return _mm_castsi128_ps( vResult );

The _mm_blend_ps instruction can be used as special-cases for the XMVectorPermute<> template. We’ll make more use of these in a future installment.

XMVectorPermute<4,1,2,3>(V1,V2) _mm_blend_ps(V1,V2,0x1)
XMVectorPermute<0,5,2,3>(V1,V2) _mm_blend_ps(V1,V2,0x2)
XMVectorPermute<4,5,2,3>(V1,V2) _mm_blend_ps(V1,V2,0x3)
XMVectorPermute<0,1,6,3>(V1,V2) _mm_blend_ps(V1,V2,0x4)
XMVectorPermute<4,1,6,3>(V1,V2) _mm_blend_ps(V1,V2,0x5)
XMVectorPermute<0,5,6,3>(V1,V2) _mm_blend_ps(V1,V2,0x6)
XMVectorPermute<4,5,6,3>(V1,V2) _mm_blend_ps(V1,V2,0x7)
XMVectorPermute<0,1,2,7>(V1,V2) _mm_blend_ps(V1,V2,0x8)
XMVectorPermute<4,1,2,7>(V1,V2) _mm_blend_ps(V1,V2,0x9)
XMVectorPermute<0,5,2,7>(V1,V2) _mm_blend_ps(V1,V2,0xA)
XMVectorPermute<4,5,2,7>(V1,V2) _mm_blend_ps(V1,V2,0xB)
XMVectorPermute<0,1,6,7>(V1,V2) _mm_blend_ps(V1,V2,0xC)
XMVectorPermute<4,1,6,7>(V1,V2) _mm_blend_ps(V1,V2,0xD)
XMVectorPermute<0,5,6,7>(V1,V2) _mm_blend_ps(V1,V2,0xE)

Processor Support

SSE4.1 is supported on Intel Core 2 (“Penryn”), Intel Core i7 (“Nehalem”), AMD Bulldozer, and later processors.

SSE 4.1 and SSE4.2 are supported on Intel Core i7 (“Nehalem”), AMD Bulldozer, and later processors.

int CPUInfo[4] = {-1};
 __cpuid( CPUInfo, 0 );
 bool bSSE4_1 = false;
 bool bSSE4_2 = false;
 if ( CPUInfo[0] > 0 )
 __cpuid(CPUInfo, 1 );
 bSSE4_1 = (CPUInfo[2] & 0x80000) != 0;
 bSSE4_2 = (CPUInfo[2] & 0x100000) != 0;

Compiler Support

Support for SSE4.1 and SSE4.2 intrinsics was added to Visual Studio 2010.

Utility Code

Update: The source for this project is now available on GitHub under the MIT license.

Xbox One: This platform supports SSE4a, SSE4.1, and SSE4.2.

See also: SSE, SSE2, and ARM-NEON; SSE3 and SSSE3; AVX; F16C and FMA; AVX2

Comments (2)

  1. Sorry for my stupid question,

    Does this mean that we can use DirectXMath even on non windows platform?



  2. walbourn says:

    DirectXMath is supported for a number of Microsoft platforms and is included in the related SDK. I cover the Xbox 360 math story in my introduction blog post and XNAMath 2.05.

    The DirectXMath library version shipping in the Windows 8 SDK is subject to the Windows 8 SDK EULA.

    The library itself depends mostly on the compiler and officially only supports Visual Studio 2010 and Visual Studio 2012. It is likley that it can compile with the Intel compiler if using the Windows 8.0 SDK or the "SAL2 fixups" I mentioned in my intro blog post.

    The _XM_NO_INTRINSICS_ scalar mode is essentially Standard C++ code that is technically portable across any platform with a C++11 compiler. There is only a single Windows OS API use and it's optional.