2016-10-17 16 views
1

x86_64 intrinsics에 익숙하지 않아 256 비트 벡터 레지스터를 사용하여 다음 작업을 수행하고 싶습니다. _mm256_maddubs_epi16 (a, b)를 사용하고있었습니다. 그러나이 명령은 char * char이 16 비트 최대 값을 초과 할 수 있으므로 오버플로 문제가있는 것으로 보입니다. _mm256_unpackhi_epi32 및 관련 지침을 이해하고 있습니다.intrinsics를 사용하여 요소 방향으로 두 개의 char 배열을 곱하고 그 곱셈을 int로 요약하는 방법은 무엇입니까?

누구든지 나를 자세하게 설명하고 나에게 빛을 보여줄 수 있습니까? 고맙습니다!

int sumup_char_arrays(char *A, char *B, int size) { 
    assert (size % 32 == 0); 
    int sum = 0; 
    for (int i = 0; i < size; i++) { 
     sum += A[i]*B[i]; 
    } 
    return sum; 
} 
+1

먼저 SSE 버전을 작성하는 것이 좋습니다. 16 비트로 압축을 풀고 '_mm_madd_epi16'을 사용하여 무거운 짐을 풉니 다. AVX에서 모든 문제가 발생하지 않는 초보자에게는 충분합니다. 나중에 필요할 때 SSE에서 AVX로 이동할 수 있습니다. –

답변

1

해결 방법, 특히 개선의 최종 단계를 개선하기위한 아이디어를 찾았습니다.

int sumup_char_arrays(char *A, char *B, int size) { 
    assert (size % 32 == 0); 
    int sum = 0; 
    __m256i sum_tmp; 
    for (int i = 0; i < size; i += 32) { 
     __m256i ma_l = _mm256_cvtepi8_epi16(_mm_load_si128((__m128i*)A)); 
     __m256i ma_h = _mm256_cvtepi8_epi16(_mm_load_si128((__m128i*)(A+16))); 
     __m256i mb_l = _mm256_cvtepi8_epi16(_mm_load_si128((__m128i*)B)); 
     __m256i mb_h = _mm256_cvtepi8_epi16(_mm_load_si128((__m128i*)(B+16))); 
     __m256i mc = _mm256_madd_epi16(ma_l, mb_l); 
     mc = _mm256_add_epi32(mc, _mm256_madd_epi16(ma_h, mb_h)); 
     sum_tmp = _mm256_add_epi32(mc, sum_tmp); 
     //sum += A[i]*B[i]; 
    } 
    sum_tmp = _mm256_add_epi32(sum_tmp, _mm256_permute2x128_si256(sum_tmp, sum_tmp, 0x81)); 
    sum_tmp = _mm256_add_epi32(sum_tmp, _mm256_srli_si256(sum_tmp, 8)); 
    sum_tmp = _mm256_add_epi32(sum_tmp, _mm256_srli_si256(sum_tmp, 4));   
    sum = _mm256_extract_epi32(sum_tmp, 0); 
    return sum; 
} 
+1

char 배열 중 하나가 서명되지 않은 것으로 처리되지 않는 한 나에게 좋을 것 같습니다. 따라서 [PMADDUBSW] (http://www.felixcloutier.com/x86/PMADDUBSW.html)를 사용할 수 있습니다. 수평 감소는 permute을 필요로하지 않고 추출하고 128까지만 캐스트합니다. [이 답변보기] (http://stackoverflow.com/questions/6996764/fastest-way-to-do-horizontal-float-vector-sum -on-x86) 두 코드 바이트를 절약 할 수있는 수평 합계에 대해 아마도 최적의 패턴을 찾아야합니다. –