2011-12-15 5 views
7
SSE3에서

의 PALIGNR 명령은 다음과 수행 128 비트. 진부하게도 intrinsic 함수 _mm256_alignr_epi8 (VPALIGNR)은 256 비트 레지스터에서만 _mm_alignr_epi8과 동일한 연산을 수행한다고 믿었습니다. 슬프게도 그러나, 정확히는 그렇지 않습니다. 사실 _mm256_alignr_epi8은 256 비트 레지스터를 2 128 비트 레지스터로 취급하고 인접한 두 개의 128 비트 레지스터에서 2 "정렬"연산을 수행합니다. _mm_alignr_epi8과 같은 작업을 효과적으로 수행하지만 한 번에 2 개의 레지스터를 사용합니다. 가장 명확하게 여기에 설명 있어요 : 현재 내 솔루션입니다_mm_alignr_epi8 AVX2에 해당하는 (PALIGNR는)

_mm256_alignr_epi8_mm_alignr_epi8를 계속 사용하는 YMM (256 비트) 등록을 분할하여 두 개의 XMM (128 비트) (높고 낮음) 레지스터로,과 같이 :

__m128i xmm_ymm1_hi = _mm256_extractf128_si256(ymm1, 0); 
__m128i xmm_ymm1_lo = _mm256_extractf128_si256(ymm1, 1); 
__m128i xmm_ymm2_hi = _mm256_extractf128_si256(ymm2, 0); 
__m128i xmm_ymm_aligned_lo = _mm_alignr_epi8(xmm_ymm1_lo, xmm_ymm1_hi, 1); 
__m128i xmm_ymm_aligned_hi = _mm_alignr_epi8(xmm_ymm2_hi, xmm_ymm1_lo, 1); 
__m256i xmm_ymm_aligned = _mm256_set_m128i(xmm_ymm_aligned_lo, xmm_ymm_aligned_hi); 

이 방법은 효과가 있지만 더 좋은 방법이 있어야합니다. 동일한 결과를 얻기 위해 사용해야하는 "일반"AVX2 명령어가 있습니까?

답변

2

나는이 때문이다 가지고 올 수 있었던 유일한 해결책 :

나는 거의 동일한 솔루션에 그것도> = 16 바이트의 변화를 처리하는 것을 제외하고 생각
static inline __m256i _mm256_alignr_epi8(const __m256i v0, const __m256i v1, const int n) 
{ 
    if (n < 16) 
    { 
    __m128i v0h = _mm256_extractf128_si256(v0, 0); 
    __m128i v0l = _mm256_extractf128_si256(v0, 1); 
    __m128i v1h = _mm256_extractf128_si256(v1, 0); 
    __m128i vouth = _mm_alignr_epi8(v0l, v0h, n); 
    __m128i voutl = _mm_alignr_epi8(v1h, v0l, n); 
    __m256i vout = _mm256_set_m128i(voutl, vouth); 
    return vout; 
    } 
    else 
    { 
    __m128i v0h = _mm256_extractf128_si256(v0, 1); 
    __m128i v0l = _mm256_extractf128_si256(v1, 0); 
    __m128i v1h = _mm256_extractf128_si256(v1, 1); 
    __m128i vouth = _mm_alignr_epi8(v0l, v0h, n - 16); 
    __m128i voutl = _mm_alignr_epi8(v1h, v0l, n - 16); 
    __m256i vout = _mm256_set_m128i(voutl, vouth); 
    return vout; 
    } 
} 

.

+0

그래, 그것도 같은 해결책입니다. 하지만 이것이 유일한 방법이라면 AVX2 명령어의 설계자가 큰 감독처럼 보입니다. – eladidan

+0

컴파일 할 수 없습니다 ... 컴파일 오류가 발생합니다. "심각한 오류 : 내장 매개 변수는 즉각적인 값이어야합니다" 다음 줄에 : "__m128i vouth = _mm_alignr_epi8 (v0l, v0h, n);". 대체로, n은 이교도가 아니기 때문에. 어떻게 이것을 우회 할 수 있었습니까? 나는 인텔 C++ 컴파일러 – eladidan

+0

을 사용하고 있습니다. n이 컴파일시의 상수 일 때만 제게 적합합니다. 인텔 ICC 컴파일러도 사용하고 있지만 C++보다는 C++로 컴파일하면 차이가 있습니다. gcc로 나를 위해 일합니다. –

4

무엇을 palignr에 사용하고 계십니까? 데이터 정렬을 처리하는 경우에만 정렬되지 않은로드를 대신 사용하십시오. 이들은 일반적으로 최신 Intel μ 아키텍처에서 "충분히 빠름"(그리고 많은 코드 크기를 절약 할 수 있습니다).

다른 이유로 인해 palignr과 같은 동작이 필요한 경우 정렬되지 않은로드 지원을 활용하여 분기없이 수행 할 수 있습니다. 완전히로드 저장소가 아니라면, 아마도 이것이 선호되는 관용어 일 것입니다. 정확히 palignr를 사용하는 방법이 에 대한 자세한 정보를 제공 할 수있는 경우

static inline __m256i _mm256_alignr_epi8(const __m256i v0, const __m256i v1, const int n) 
{ 
    // Do whatever your compiler needs to make this buffer 64-byte aligned. 
    // You want to avoid the possibility of a page-boundary crossing load. 
    char buffer[64]; 

    // Two aligned stores to fill the buffer. 
    _mm256_store_si256((__m256i *)&buffer[0], v0); 
    _mm256_store_si256((__m256i *)&buffer[32], v1); 

    // Misaligned load to get the data we want. 
    return _mm256_loadu_si256((__m256i *)&buffer[n]); 
} 

, 나는 아마 더 도움이 될 수 있습니다.

+0

대기 시간은 인텔 CPU의 상점 전달 실속으로 인한 대기 시간이 ~ 10 사이클이 추가되기 때문에 지연 시간은 그리 좋지 않습니다. Store-forwarding Stall이 처리량 문제 인 경우 IDK. 그들은 그렇지 않을 수도 있습니다. –

+1

@PeterCordes : 처리량 위험이없고 대기 시간 만 발생합니다. 여기에서 설명한 방법은 저장 장치가 대기 시간을 숨기기 위해 끌어 올 수 있거나 저장된 데이터를 다양한 다른 정렬을 추출하기 위해 다시 사용할 수있는 상황에서 의미가 있습니다. 물론 AVX-512에는 일반적으로 더 나은 솔루션 인 2 소스 셔플이 있습니다. –

+0

좋은 점은 동일한 두 벡터에 서로 다른 창을 생성하는 데 적합합니다. 또한 런타임 가변 시프트 수에 유용합니다. –

관련 문제