자기개발/SIMD

SIMD - Unpack, Pack 함수

pi92 2021. 10. 12. 10:10

Pack과 Unpack 함수는 작은 사이즈의 pack을 가진 package 연산을 할 때 유용하게 사용된다. 오버플로 방지를 위해서는 pack과 unpack 연산을 수행해야한다. 작은 사이즈의 pack을 두 배 크기로 확장할 때 unpack을 사용한다.

 

Unpack

 

 __m128i r = _mm_unpackhi_epi32(__m128i a, __m128i b)

 

32bit interger 형 정수 4개를 담고있는 __m128i 데이터형 2개를 받아서 상위 bit 위치에 있는 2개 pack을 조합하여 새로운 128bit 데이터를 만든다. 

 

ex)

__m128i b = b3, b2, b1, b0  ,  __m128i a = a3, a2, a1, a0

__m128i r = b3, a3, b2, a2

 

 __m128i r = _mm_unpacklo_epi32(__m128i a, __m128i b)

 

32bit interger 형 정수 4개를 담고있는 __m128i 데이터형 2개를 받아서 하위 bit 위치에 있는 2개 pack을 조합하여 새로운 128bit 데이터를 만든다. 

 

ex)

__m128i b = b3, b2, b1, b0  ,  __m128i a = a3, a2, a1, a0

__m128i r = b1, a1, b0, a0

 

#include <iostream>
#include <afx.h>
using namespace std;
#include <emmintrin.h>

int main(int argc, char* argv[])
{
	__declspec(align(16)) short A[8] = { 1, 2, 3, 4, 5, 6, 7, 8 };
	__declspec(align(16)) short B[8] = { 0 };
	__declspec(align(16)) int R[4] = { 0 };

	__m128i xmmA = _mm_load_si128((__m128i*)A);
	__m128i xmmB = _mm_load_si128((__m128i*)B);

	__m128i xmmR = _mm_unpackhi_epi16(xmmA,xmmB);		//pack 연산
	_mm_store_si128((__m128i*)R, xmmR);					//결과 출력
	cout << "Unpack High : " << R[3] << ", " << R[2] << ", " << R[1] << ", " << R[0] << endl;


	xmmR = _mm_unpacklo_epi16(xmmA, xmmB);		//pack 연산
	_mm_store_si128((__m128i*)R, xmmR);			//결과 출력
	cout << "Unpack Low : " << R[3] << ", " << R[2] << ", " << R[1] << ", " << R[0] << endl;


	return 0;
}

실행 결과

Pack

 

unpack 함수를 이용하여 오버플로를 방지하고, 필요로 하는 연산을 모두 사용한 후에 원래 크기로 돌리기 위해 pack을 사용한다. 2배 크기의 pack을 절반으로 줄일 떄 사용한다. 32bit integer형 정수 4개를 담고있는 128bit 데이터형 인자 2개를 받아서 1개로 조합하는 기능을 수행한다. 아울러 각각의 pack을 32bit interger형에서 16bit short형으로 변환한다.

 

 __m128i r = _mm_packs_epi32(__m128i a, __m128i b)

 

ex)

__m128i b = b3, b2, b1, b0  ,  __m128i a = a3, a2, a1, a0

__m128i r = b3, b2, b1, b0, a3, a2, a1, a0

 

#include <iostream>
#include <afx.h>
using namespace std;
#include <emmintrin.h>

int main(int argc, char* argv[])
{
	__declspec(align(16)) int A[4] = { 1, 2, 3, 4};
	__declspec(align(16)) int B[4] = { 5, 6, 7, 8 };
	__declspec(align(16)) short R[8] = { 0 };

	__m128i xmmA = _mm_load_si128((__m128i*)A);
	__m128i xmmB = _mm_load_si128((__m128i*)B);

	__m128i xmmR = _mm_packs_epi32(xmmA,xmmB);		//pack 연산
	_mm_store_si128((__m128i*)R, xmmR);					//결과 출력
	cout << "Pack : " << R[7] << ", " << R[6] << ", " << R[5] << ", " << R[4] << ", " << R[3] << ", " << R[2] << ", " << R[1] << ", " << R[0] << endl;

	return 0;
}

실행 결과