2017-10-06 20 views
2

그래서 SSE 함수 __mm_load_128을 사용하려고합니다. 어리석은 실수를 저지른 경우 SSE fo for us에 대해 매우 새로운 것입니다._declspec (align (16))은 포인터를 16 바이트에 맞춰 정렬하지 않습니다.

는 여기에 내가 뭘 잘못 0xC0000005: Access violation reading location 0xFFFFFFFF.

0xFFFFFFFF 잘 보이지 않는 비주얼 스튜디오에 내가 오류 코드

void one(__m128i *arr, char *temp) 
{ 
    // SSE needs 16 byte alignment. 
    _declspec (align(16)) __m128i *tmp = (__m128i*) temp; 

    if (((uintptr_t)tmp & 15) == 0) 
     printf("Aligned pointer"); 
    else 
     printf("%d", ((uintptr_t)tmp & 15)); // This prints as 12 

    arr[0] = _mm_load_si128(tmp); 
} 

이다.

arr 인수는, 잘 작동 _mm_loadu_128을 사용하는 것입니다 _m128i arr[5] = { 0 }

대안으로 초기화하지만 난 그것을 이해, 그것은 movdqu 명령을 생산해야하지만이 어셈블리가

arr[0] = _mm_loadu_si128(tmp); 
00D347F1 mov   eax,dword ptr [tmp] 
00D347F4 movups  xmm0,xmmword ptr [eax] 
00D347F7 movaps  xmmword ptr [ebp-100h],xmm0 
00D347FE mov   ecx,10h 
00D34803 imul  edx,ecx,0 
00D34806 add   edx,dword ptr [arr] 
00D34809 movups  xmm0,xmmword ptr [ebp-100h] 
00D34810 movups  xmmword ptr [edx],xmm0 

고마워 생성입니다 대답에서 나는 실수를 두 번이나 내 렸습니다.

  1. 소스는 최적화를 _alinged_malloc

  2. 컴파일을 사용 맞 춥니 다.

  3. 를 사용하여 C++ 캐스트하지 C

+4

원본 주소를 정렬하는 데 아무 것도하지 않습니다. 저장된 주소를 변경하지 않고 포인터를 정렬하려고합니다. 'temp'가 가리키는 버퍼가 제대로 정렬되도록해야합니다. 또한 C++ 코드에서 C 스타일 캐스트를 피해야합니다. – VTT

+2

@VTT :'(__m128i *)'는 내장 함수의 표준 스타일입니다. 'reinterpret_cast <__m128i*> (임시)'은 일반적으로 너무 부피가 크며 인텔의 내장 함수는 이미 충분히 긴 이름을 가지고 있습니다. (또한,'__m128i'는 다른 타입의 별칭을 지정할 수 있으므로 특별합니다.) –

+1

정상적인 asm 출력을 원한다면 최적화를 사용하지 않고 컴파일하지 마십시오. 'imul edx, ecx, 0 '을내는 것은 영감을 얻지 못하는 나쁜 방법입니다. 'movups'로드를 수행하지만 스택에 임시로 쏟아져서 결과를 원하는 위치에 다시 저장하기 전에로드 된로드로 다시로드합니다. 내가 말했듯이, asm이 C++을 작성할 때 상상하는 것처럼 보이게하려면 최적화를 활성화하십시오. –

답변

7

여기 세 가지 문제를 볼 수 있습니다

  1. 이 코드는 C++ 엄격 C이며,하지. 그것은 본질적으로 문제가 아니지만 질문은 C++로 태그가 붙습니다. 코드의 흐름이 내부 one
  2. 당신은 그것을 arr 또는 temp의 정렬을 변경하는 것은 불가능하다,
  3. 대 포인터정렬 사이에 어떤 포인터 포인트의 정렬을 구분하지 않습니다.

초 점 2에 초점을 맞추십시오. 포인터가 있고 포인터가 가리키는 부분이 있습니다. 나는이 두 가지의 차이점을 이미 알고 있다고 생각합니다. 당신이 _declspec (align(16)) __m128i *tmp을 쓸 때

기본적으로, 프로그램 말씀 : 당신은 스택에 포인터 tmp를 할당 할 때

이 있는지 만드는 tmp의 첫 번째 바이트 (스택)의 주소에 할당되어있는 그래서 큰 16

자체가 16에 정렬 tmp에 의해 분할 가능, 그것은 tmp를 어떤 점 모든 에 영향을주지 않습니다. 이미 데이터 정렬을 가리키는 데 temp이 필요합니다.이것은 적절한 alignas 키워드 (alignas(16) char my_buffer[16*100];)

  • aligned_alloc 같이, 데이터 정렬에 할당 할 수있는 메모리 할당 기능 동적 데이터를 할당하거나 MSVC의 _aligned_malloc_aligned_free을 요구되는 스택 데이터를 할당

    1. 의해 수행 될 수있다. How to solve the 32-byte-alignment issue for AVX load/store operations?

    메모리를 소급하여 정렬 할 수 없으므로 먼저 정렬하여 할당해야합니다. temp에 의해 전달 된 데이터가 이미 정렬되어 있는지 확인하거나 호출자가 정렬 된 데이터를 전달하도록 요구할 수없는 경우 정렬되지 않은로드/저장소를 사용하십시오.

  • +3

    C++로 컴파일하면 C++입니다. C와 비슷한 스타일로 작성되었지만 컴파일러가 해석하는 방식은 변경되지 않는다고 말할 수 있습니다. C와 C++에는 미묘한 차이가 있습니다. 아마도이 코드는 C 예제에서 나온 것이며 OP는 C++에서이 코드를 사용하고 있습니다. –

    +2

    당신은 또한'__asm ​​{mov eax, 8}'이라고 쓰고 C++ 프로그램 내에서 컴파일 할 수 있지만 어셈블리 언어는 C++로 만들지 않습니다. –

    +1

    나는 그 점에 거의 동의하지만 여전히 당신의 말을 다르게 말해야한다고 생각합니다. C++ 코드에서 C 스타일의 사용을 비판하고 싶다면, 확실히. 그렇다고해서 C 언어가 아니라는 의미입니다. 유니온 타입의 문장은 여전히 ​​정의되지 않은 동작입니다 (MSVC에서는 GNU C++과 동일하게 정의 할 것입니다).하지만 어떤면에서는 MSVC++의 일부분을 만들지 만 프로그램. MSVC 인라인 asm은 MASM과 약간의 차이가 있습니다 (예 : '0xdeadbeef'및 '0deadbeefH'를 허용 함). –