2012-06-08 5 views
14

SSE 내장 함수로 작업 한 것은 이번이 처음입니다. 인텔 SSE 내장 (SSE4.2까지)을 사용하여 간단한 코드를 더 빠른 버전으로 변환하려고합니다. 나는 많은 오류가 발생하는 것 같습니다.인텔 SSE 내장 함수를 사용하여 코드를 최적화하는 코드

코드의 스칼라 버전은 다음과 같습니다 (단순 행렬 곱셈)

 void mm(int n, double *A, double *B, double *C) 
    { 
     int i,j,k; 
     double tmp; 

     for(i = 0; i < n; i++) 
      for(j = 0; j < n; j++) { 
        tmp = 0.0; 
        for(k = 0; k < n; k++) 
          tmp += A[n*i+k] * 
            B[n*k+j]; 
        C[n*i+j] = tmp; 

       } 
      } 

이 내 버전입니다 : 내가

 void mm_sse(int n, double *A, double *B, double *C) 
     { 
     int i,j,k; 
     double tmp; 
     __m128d a_i, b_i, c_i; 

     for(i = 0; i < n; i++) 
      for(j = 0; j < n; j++) { 
        tmp = 0.0; 
        for(k = 0; k < n; k+=4) 
          a_i = __mm_load_ps(&A[n*i+k]); 
          b_i = __mm_load_ps(&B[n*k+j]); 
          c_i = __mm_load_ps(&C[n*i+j]); 

          __m128d tmp1 = __mm_mul_ps(a_i,b_i); 
          __m128d tmp2 = __mm_hadd_ps(tmp1,tmp1); 
          __m128d tmp3 = __mm_add_ps(tmp2,tmp3); 
          __mm_store_ps(&C[n*i+j], tmp3); 

      } 
     } 

이 어디에서 잘못이와 함께 갈거야 인클루드 포함했다? I는 다음과 같이 여러 가지 오류를 얻고 :

mm_vec.c (84) : 오류 : 타입의 값이 "INT"N "__m128d" A_I = __mm_load_ps (& A [형 엔티티에 할당 될 수 없다 * I + k]);

이 내가 컴파일하고 방법은 다음과 같습니다 ICC -O2 mm_vec.c -o VEC

누군가가 정확하게이 코드를 변환하는 저를 도와 주시겠습니까. 감사!

UPDATE :

 void mm_sse(int n, float *A, float *B, float *C) 
     { 
     int i,j,k; 
     float tmp; 
     __m128 a_i, b_i, c_i; 

     for(i = 0; i < n; i++) 
      for(j = 0; j < n; j++) { 
        tmp = 0.0; 
        for(k = 0; k < n; k+=4) 
          a_i = _mm_load_ps(&A[n*i+k]); 
          b_i = _mm_load_ps(&B[n*k+j]); 
          c_i = _mm_load_ps(&C[n*i+j]); 

          __m128 tmp1 = _mm_mul_ps(a_i,b_i); 
          __m128 tmp2 = _mm_hadd_ps(tmp1,tmp1); 
          __m128 tmp3 = _mm_add_ps(tmp2,tmp3); 
          _mm_store_ps(&C[n*i+j], tmp3); 


      } 
     } 

을하지만 지금은 분할 오류를 받고있는 것으로 보인다 :

는 귀하의 제안에 따라, 나는 다음과 같은 변화를 만들었습니다. 배열 A, B, C에 대해 배열 첨자에 제대로 액세스하지 않기 때문에이 사실을 알고있을 것입니다. 나는 이것에 아주 새롭고, 이것을 계속하는 방법을 모르겠습니다.

이 코드를 올바르게 처리하는 방법을 결정하는 데 도움을주십시오.

답변

9

당신은 예를 들어, 함수 이름에 너무 많은 밑줄을 가지고 있기 때문에 당신이보고있는 오류는 다음과 같습니다

__mm_mul_ps 

은 다음과 같아야합니다

_mm_mul_ps // Just one underscore up front 

때문에 C 컴파일러들은 int를 돌려 가정한다 왜냐하면 그것은 선언을 보지 못했기 때문입니다.

이 외에도 다른 문제가 있습니다. 동일한 명령어의 double 및 single float 변형에 대한 호출을 혼합하는 것처럼 보입니다.

__m128d a_i, b_i, c_i; 

하지만 당신은 전화 :

예를 들어, 당신은

__mm_load_ps(&A[n*i+k]); 

__m128 아닌 __m128d 반환 - 당신이 전화하고 싶었 : 대신

_mm_load_pd 

. 다른 지침에 대해서도 마찬가지로 두 쌍의 쌍으로 작업하기를 원할 경우.


당신은 설명 할 수없는 세그먼트 오류를보고있는 및 SSE 코드에서 나는 당신이 메모리 정렬에 문제가있어 추측하는 경향이있을 거라고 경우 - SSE의 내장 함수에 전달 된 포인터를 (주로 1)는 16해야 바이트 정렬. 코드에서 check this with a simple assert을 수행하거나 디버거에서 검사 할 수 있습니다 (올바르게 정렬 된 경우 포인터의 마지막 자리가 0이 될 것으로 예상 함).

맞지 않는 경우 올바르게 정렬해야합니다. new/malloc()에 할당되지 않은 것들에 대한 당신은 컴파일러 확장 (예 : with gcc)와 함께이 작업을 수행 할 수 있습니다

float a[16] __attribute__ ((aligned (16))); 

의 gcc 버전이와 스택 정렬에 대한 몇 가지 다른주의 사항을 지원하기에 충분히 큰 최대 정렬을 가지고 제공 . 동적으로 할당 된 저장소의 경우 플랫폼 전용 확장 프로그램 (예 :

float *a=NULL; 
posix_memalign(&a, __alignof__(__m128), sizeof(float)*16); 

(나는 C++ 11이 일을 더 좋은 휴대용 방법이있을 수 있습니다 생각하지만 난 아직에 확실히 100 % 아니에요) : posix_memalign 적합한 스토리지를 할당합니다.

1는 정렬되지 않은로드 및 저장을 할 수 있도록 몇 가지 지침이 있습니다,하지만 그들은로드를 정렬하는 모든 가능한 피하는 가치에 비해 대단히 느리다.

+0

저는 gcc가 아닌 icc로 작업하고 있습니다. a_i = _mm_load_ps (& A [n * i + k]);가 올바른 접근 방법이라고 생각하십니까? 필자가 다른 곳에 게시 한 예 (인텔 내장 문서에도 있음)에는 매우 기본적인 예제가 있습니다. 배열 A, B, C는 모두 malloc으로 할당되었습니다. – PGOnTheGo

+1

@Hello_PG로드 자체가 잘못되었습니다. 하지만 c_i를로드 할 필요는 없습니다. 대부분의 경우 ICC는 gcc와 동일한 확장 기능을 가지고 있습니다. 저는 이것이 정렬을위한 경우라고 생각합니다. ICC보다는 개인적으로 GCC에 더 익숙해 졌기 때문에 저는 그것을 자격을 얻었고 찾을 방법을 알고있는 문서에 링크되었습니다. malloc은 모든 플랫폼에서 적절한 정렬을 보장하지 않으므로 posix_memalign이 필요할 것입니다. 내가 제안한 주장이 실패 했나요? – Flexo

+0

A와 같이 메모리를 할당하려고하면 A = (float *) _ aligned_malloc (dimension * dimension * sizeof (float), 16); 컴파일 오류가 발생합니다 : icc로'aligned_malloc '에 대한 참조가 정의되지 않았습니다. 이것은 컴파일하는 방법입니다. icc -O2 mm_vec.c -o vec2 – PGOnTheGo

3

로드 및 저장이 항상 16 바이트 정렬 주소에 액세스하는지 확인해야합니다. 또는 어떤 이유로 든 보장 할 수없는 경우 _mm_load_ps/_mm_store_ps 대신 _mm_loadu_ps/_mm_storeu_ps을 사용하십시오. 효율성이 떨어지지 만 잘못 정렬 된 주소는 충돌하지 않습니다.

관련 문제