목차

SSE

Streaming SIMD Extension. x86 아키텍쳐의 확장 SIMD 명령어 집합으로, 여러 데이터를 대상으로 동시에 (병렬적으로) 같은 명령어를 수행하는데 최적화되어있다. single precision floating point 연산에 특화되어 있으나 SSE 2 부터 정수형 및 배정도 (double precision floating point) 실수형 또한 지원한다. 반복되는 수치 연산 및 그래픽스 연산에 큰 도움이 된다.

그 외

구현 조건

SSE 로 구현하기 앞서 다음 사항을 확인해보자.

헤더

#include <xmmintrin.h>      // SSE
#include <emmintrin.h>      // SSE 2
#include <pmmintrin.h>      // SSE 3
#include <tmmintrin.h>      // SSE 3 Extension
#include <smmintrin.h>      // SSE 4.1
#include <nmmintrin.h>      // SSE 4.2

사용 구조체

아래는 SSE 연산을 위한 자료형이며 XMM 레지스터와 1:1 대응된다.

SSE 2 부터 integer 및 double 형 데이터를 지원한다. 각각 __m128i, __m128d.

// xmmintrin.h
typedef union __declspec(intrin_type) _CRT_ALIGN(16) __m128 {
     float               m128_f32[4];
     unsigned __int64    m128_u64[2];
     __int8              m128_i8[16];
     __int16             m128_i16[8];
     __int32             m128_i32[4];
     __int64             m128_i64[2];
     unsigned __int8     m128_u8[16];
     unsigned __int16    m128_u16[8];
     unsigned __int32    m128_u32[4];
 } __m128;
 
// emmintrin.h
typedef union __declspec(intrin_type) _CRT_ALIGN(16) __m128i {
    __int8              m128i_i8[16];
    __int16             m128i_i16[8];
    __int32             m128i_i32[4];    
    __int64             m128i_i64[2];
    unsigned __int8     m128i_u8[16];
    unsigned __int16    m128i_u16[8];
    unsigned __int32    m128i_u32[4];
    unsigned __int64    m128i_u64[2];
} __m128i;
 
typedef struct __declspec(intrin_type) _CRT_ALIGN(16) __m128d {
    double              m128d_f64[2];
} __m128d;

SSE Intrinsic

Vector 클래스

Intel 이 추가적으로 제공한 편의 클래스이며 아래의 특징이 있다.

헤더는 아래와 같다.

#include <fvec.h>    // single precision  Vector 클래스
#include <dvec.h>    // integer(__m128i) 및 double(__m128d) 형 지원 Vector 클래스.

한 예로 F32vec4 는 32bit floating point 원소 4개로 이루어진 자료형을 다루기 위한 클래스이다.1)

fvec.h
class F32vec4
{
protected:
   	 __m128 vec;
public:
 
	/* Constructors: __m128, 4 floats, 1 float */
	F32vec4() {}
 
	/* initialize 4 SP FP with __m128 data type */
	F32vec4(__m128 m)					{ vec = m;}
 
	/* initialize 4 SP FPs with 4 floats */
	F32vec4(float f3, float f2, float f1, float f0)		{ vec= _mm_set_ps(f3,f2,f1,f0); }
 
	/* Explicitly initialize each of 4 SP FPs with same float */
	explicit F32vec4(float f)	{ vec = _mm_set_ps1(f); }
 
	/* Explicitly initialize each of 4 SP FPs with same double */
	explicit F32vec4(double d)	{ vec = _mm_set_ps1((float) d); }
 
	/* Assignment operations */
 
	F32vec4& operator =(float f) { vec = _mm_set_ps1(f); return *this; }
 
	F32vec4& operator =(double d) { vec = _mm_set_ps1((float) d); return *this; }
 
	/* Conversion functions */
	operator  __m128() const	{ return vec; }		/* Convert to __m128 */
 
 	/* Logical Operators */
	friend F32vec4 operator &(const F32vec4 &a, const F32vec4 &b) { return _mm_and_ps(a,b); }
	friend F32vec4 operator |(const F32vec4 &a, const F32vec4 &b) { return _mm_or_ps(a,b); }
	friend F32vec4 operator ^(const F32vec4 &a, const F32vec4 &b) { return _mm_xor_ps(a,b); }
 
	/* Arithmetic Operators */
	friend F32vec4 operator +(const F32vec4 &a, const F32vec4 &b) { return _mm_add_ps(a,b); }
	friend F32vec4 operator -(const F32vec4 &a, const F32vec4 &b) { return _mm_sub_ps(a,b); }
	friend F32vec4 operator *(const F32vec4 &a, const F32vec4 &b) { return _mm_mul_ps(a,b); }
	friend F32vec4 operator /(const F32vec4 &a, const F32vec4 &b) { return _mm_div_ps(a,b); }
 
	F32vec4& operator =(const F32vec4 &a) { vec = a.vec; return *this; }
	F32vec4& operator =(const __m128 &avec) { vec = avec; return *this; }
	F32vec4& operator +=(F32vec4 &a) { return *this = _mm_add_ps(vec,a); }
	F32vec4& operator -=(F32vec4 &a) { return *this = _mm_sub_ps(vec,a); }
	F32vec4& operator *=(F32vec4 &a) { return *this = _mm_mul_ps(vec,a); }
	F32vec4& operator /=(F32vec4 &a) { return *this = _mm_div_ps(vec,a); }
	F32vec4& operator &=(F32vec4 &a) { return *this = _mm_and_ps(vec,a); }
	F32vec4& operator |=(F32vec4 &a) { return *this = _mm_or_ps(vec,a); }
	F32vec4& operator ^=(F32vec4 &a) { return *this = _mm_xor_ps(vec,a); }
 
        ... // 이하 생략
}

따라서 이런 식으로 사용이 가능하다.

F32vec4 a, b, c;
 
a = b + c;

참조

1) 대다수 사용되는 타입이므로 이 클래스를 참고하며 용례를 익히면 된다.