Post

_mm_extract_epi8 함수에 변수 사용시 compile error

주의 사항

이 글은 예전 블로그에서 옮겨온 오래 된 글입니다. 현재 상황과는 다를 수 있으며, 잘못 된 정보가 있을 수 있습니다.


정말 오랫만에 로우레벨 관련 질문을 받았습니다…

바로 아래 코드에서

1
2
3
4
5
6
7
8
9
10
11
#include <smmintrin.h>
 
int main()
{
    __m128i m_128i;
    m_128i.m128i_i16[0] = 0;
 
    for (int i = 0; i < 15; i++)
    {
        auto a = _mm_extract_epi8(m_128i, i); // <-- 컴파일 에러
    }

error C2057: expected constant expression 에러가 발생 한다는 얘기입니다.

_mm_extract_epi8 의 prototype 을 확인 해 보면 extern int _mm_extract_epi8 (__m128i /* src /, const int / index */); 입니다. 일반적으론 변수 -> const 로의 변환은 자유로우므로 문제가 없어야 하는데… 오류가 나죠.

원인은 간단한데 _mm_extract_epi8 는 C++의 “함수” 가 아니라, 기계어와 매칭되는 Intrinsics 입니다. 저게 선언되어있는 헤더가 smminstrin.h 라는 것에서도 알 수 있지요. 해당명령어는 intel 명령어이니 intel 사이트에서 한번 해당 내용을 검색 해 봅시다

Image

몇가지 정보가 나오네요. 해당 Intrinsics 에 대응되는 어셈블리는 pextrb r32, xmm, imm 이고, SSE4.1 지원이 필요하며, Latency 는 CPU 종류에 따라 2~3 클럭이네요.

여기는 Visual Studio 에 들어있는 헤더와 달리 각 파라메터에 이름이 붙어있습니다. a, 와 imm8 이네요. 그럼 imm8 은 뭐냐가 중요해지는데, 이 imm은 이름만 보면 무슨 레지스터 비슷한걸로 착각 할 수도 있는데, 실제로는 Immediate value 의 약자입니다. 한자로는 즉치값(즉시 계산되는 값) 이라고도 하는 것 같은데 C++ 프로그래머 입장에서 보자면 컴파일타임에 계산하여 결정이 가능한 상수(const) 를 이야기 합니다. 8은 뭐냐구요? 걍 bit 수 입니다. 저 값은 8bit 범위에서 작동한다는 거죠. 즉 imm8 을 풀어서 써보면 8-bit immediate value 라고 할 수 있겠습니다.

그럼 결론을 내보자면. Intrinsics 를 호출 할때는, C++의 호출/캐스팅 규칙 보다 CPU 명령어의 제약사항이 우선하며, _mm_extract_epi8 의 2번째 argument는 Immediate value 일 것을 요구하므로 변수를 사용할 수 없습니다.

기왕 하는김에 하나 더 해보자면, imm8 이라고 되어있긴 하지만, 128bit 변수를 8bit 단위로 쪼개서 값을 읽는 명령이므로, 실제 imm8의 사용 범위는 0~15 일 것입니다. 그런데 만약 그 이상의 값(ex : 16) 을 넣으면 어떻게 될까요?

Image 다행히도 컴파일러는 해당 명령어의 허용 범위를 알고 있으므로

warning C4556: value of intrinsic immediate argument ‘16’ is out of range ‘0 - 15’ warning 을 띄워 줍니다.

This post is licensed under CC BY 4.0 by the author.