SIMD - Unpack, Pack 함수
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;
}
실행 결과