2012-06-22 3 views
1

정렬,로드 및 저장 만 사용하여 2D 스텐실을 벡터화하려고합니다. 이를 위해 본질적으로 _mm_load_ps_mm_shuffle_ps을 사용하여 원하는 주소를 얻으려고합니다.SSE 내장 함수를 사용하여 2D 스텐실 벡터화

코드의 내 스칼라 버전은 다음과 같습니다

void FDTD_base (float *V, float *U, int dx, int dy, float c0, float c1, float c2, float c3, float c4) 
    { 
    int i, j, k; 

      for (j = 4; j < dy-4; j++) 
      { 
        for (i = 4; i < dx-4; i++) 
        { 

          U[j*dx+i] = (c0 * (V[j*dx+i]) //center 
            + c1 * (V[j*dx+(i-1)] + V[(j-1)*dx+i] + V[j*dx+(i+1)] + V[(j+1)*dx+i]) 
            + c2 * (V[j*dx+(i-2)] + V[(j-2)*dx+i] + V[j*dx+(i+2)] + V[(j+2)*dx+i]) 
            + c3 * (V[j*dx+(i-3)] + V[(j-3)*dx+i] + V[j*dx+(i+3)] + V[(j+3)*dx+i]) 
            + c4 * (V[j*dx+(i-4)] + V[(j-4)*dx+i] + V[j*dx+(i+4)] + V[(j+4)*dx+i])); 

        } 
      } 

     } 

내 벡터 지금까지 코드의 버전을 참조하십시오

 for (j = 4; j < dy-4; j++) 
    { 
      for (i = 4; i < dx-4; i+=4) 
      { 
        __m128 b = _mm_load_ps(&V[j*dx+i]); 
        center = _mm_mul_ps(b,c0_i); 
        a = _mm_load_ps(&V[j*dx+(i-4)]); 
        c = _mm_load_ps(&V[j*dx+(i+4)]); 

        d = _mm_load_ps(&V[(j-4)*dx+i]); 
        e = _mm_load_ps(&V[(j+4)*dx+i]); 

        u_i2 = _mm_shuffle_ps(a,b,_MM_SHUFFLE(1,0,3,2));//i-2 
        u_i6 = _mm_shuffle_ps(b,c,_MM_SHUFFLE(1,0,3,2));//i+2 

        u_i1 = _mm_shuffle_ps(u_i2,b,_MM_SHUFFLE(2,1,2,1));//i-1 
        u_i5 = _mm_shuffle_ps(b,u_i6,_MM_SHUFFLE(2,1,2,1));//i+1 

        u_i3 = _mm_shuffle_ps(a,u_i2,_MM_SHUFFLE(2,1,2,1));//i-3 
        u_i7 = _mm_shuffle_ps(u_i6,c,_MM_SHUFFLE(2,1,2,1));//i+3 

        u_i4 = a; //i-4 
        u_i8 = c; //i+4 

누군가가 J-1의 위치를 ​​얻기에 좀 도와 줄래, J + 1 ..... j-4, j + 4이다.

이 작동하지 않습니다

    u_j2 = _mm_shuffle_ps(d,b,_MM_SHUFFLE(1,0,3,2));//j-2 (this is incorrect) 
        u_j6 = _mm_shuffle_ps(b,e,_MM_SHUFFLE(1,0,3,2));//j+2 

        u_j1 = _mm_shuffle_ps(u_j2,b,_MM_SHUFFLE(2,1,2,1));//j-1 
        u_j5 = _mm_shuffle_ps(b,u_j6,_MM_SHUFFLE(2,1,2,1));//j+1 

        u_j3 = _mm_shuffle_ps(d,u_j2,_MM_SHUFFLE(2,1,2,1));//j-3 
        u_j7 = _mm_shuffle_ps(u_j6,e,_MM_SHUFFLE(2,1,2,1));//j+3 

        u_j4 = d; //j-4 (this is fine) 
        u_j8 = e; //j+4 

나는 정렬되지 않은로드를 사용하지 않고 (j-1)*dx+i, (j+1)*dx+1 ..... (j-4)*dx+i(j+4)*dx+i을 얻는 방법을 결정하는 데에만 도움이 필요합니다.

가능성있는 해결책으로 에 저장된 주소에 변위 3*dx을 추가하여 (j-1)*dx+i을 얻는 것을 생각했습니다. 그리고, 에 저장된 주소에 3*dx의 변위를 빼서 (j+1)*dx+i을 얻습니다. 마찬가지로 주소가 d 인 경우 2*dx을 추가하여 j-2 등을 얻습니다. 하지만 SSE 내장 함수를 사용하여이 전략을 구현하는 방법을 알지 못합니다.

도와주세요. Intel icc 컴파일러를 사용하고 있습니다.

+0

중복 가능성 http://stackoverflow.com/questions/11085924/segmentation-fault-while-working-with-sse-intrinsics-due-to ([분할 오류가 잘못되어 메모리 배열에 SSE 내장 함수 작업하는 동안] -incorrect-memory-ali) –

+0

@Paul : 정확하지 않습니다. stride 값이있을 때'mm_shuffle_ps'를 사용하는 방법을 결정하려고합니다.이전 게시물은 1D 슬라이딩 윈도우 용이었습니다. 이것은 2D 슬라이딩 윈도우입니다.이 슬라이딩 윈도우는 새로운 차원으로 복잡해졌습니다. 어떤 도움이라도 매우 도움이 될 것입니다. – PGOnTheGo

+0

귀하의 모든 제약 조건은 확실합니까? 예 : 절대 정렬되지 않은로드 및 상점이 없습니까? Nehalem 이후의 Intel CPU에서 특히 효율적으로 동일한 계산을 표현하는 다른 방법이 있지만 정렬되지 않은로드 및 저장이 필요합니다. –

답변

0

"누군가 j-1, j + 1 ..... j-4, j + 4의 위치를 ​​얻는 데 도움을 줄 수 있습니까?" - 이들은 셔플을 필요로하지 않습니다. 그들은 이미 귀하의 SIMD 레인과 정렬되어 있습니다.

u_j2 = _mm_load_ps(&V[(j-2)*dx+i]); 
u_j6 = _mm_load_ps(&V[(j+2)*dx+i]); 
u_j1 = _mm_load_ps(&V[(j-1)*dx+i]); 
u_j5 = _mm_load_ps(&V[(j+1)*dx+i]); 
// and so forth 

당신 확실히 수없는 이러한 값이 d (예를 들어)에 V[j-4, i], V[j-4, i+1], V[j-4, i+2], V[j-4, i+3] 있으며, 그 중 V[j-2, i]를 얻을 수 없기 때문에 당신이 가능한 재 배열에 의해 de으로 표시 한 변수에서.

팁 : SIMD 레인에 관해 생각해보십시오. 그것은 당신이 수평으로 재배치 할 필요가 있지만 수직으로 재배치 할 필요가 없다는 것을 분명히합니다.

팁 : 내부 루프 카운터가 증가 할 때 (i+=4) 발생하는 상황을 고려하십시오. 마지막 루프에서 u_i5 (V[j, i+1..i+5])는 현재 루프의 u_i3 (V[j, i-3..i+1])이되었습니다. 행에있는 데이터의 각 오프셋 버전을 최소한 두 번 계산합니다. 아마도 루프를 몇 번 풀고 모든 추가 작업을하지 않아도됩니다.

팁 : 왜 AVX를 사용하지 않습니까? 필요한 경우 _mm256_permute_ps (및 필요한 경우 _mm256_permute2f128_ps)를 사용하여 해당로드 명령어를 섞습니다. 두 배의 SIMD 레지스터가 있고 대부분의 AVX 명령어는 SSE 명령어와 마찬가지로 최신 CPU에서 여전히 한 사이클 만 사용하기 때문에 거의 두 배 더 빠릅니다.

+0

@Hello_PG :이 질문에 대한 답변을보십시오. 만약 그렇다면, 당신이 받아들이고 upvote하면 나는 그것을 감사하겠습니다. 감사! –

관련 문제