2014-07-18 3 views
7

이 질문은 직접 피연산자가있는 SSE 내장 함수에 대한 gcc (4.6.3 Ubuntu)와 언 롤링 루프의 동작과 관련이 있습니다.직접 피연산자가있는 SSE 내장 함수에 대해 루프 언 롤링을 활성화하는 gcc 옵션은 무엇입니까?

직접 피연산자가있는 내장의 예는 _mm_blend_ps입니다. 상수 일 수있는 4 비트 직접 정수를 기대합니다. 그러나 -O3 옵션을 사용하면 컴파일러가 자동으로 루프를 언 롤링하고 (루프 카운터 값을 컴파일 타임에 결정할 수있는 경우) 다른 즉 치값을 가진 해당 블렌드 명령어의 인스턴스를 여러 개 생성합니다.

이 블렌드의 즉각적인 피연산자의 16 개 개의 가능한 값을 통해 실행하는 간단한 테스트 코드 (blendsimple.c) : 그것은 가능

#include <stdio.h> 
#include <x86intrin.h> 

#define PRINT(V)    \ 
    printf("%s: ", #V);    \ 
    for (i = 3; i >= 0; i--) printf("%3g ", V[i]); \ 
    printf("\n"); 

int 
main() 
{ 
    __m128 a = _mm_set_ps(1, 2, 3, 4); 
    __m128 b = _mm_set_ps(5, 6, 7, 8); 
    int i; 
    PRINT(a); 
    PRINT(b); 
    unsigned mask; 
    __m128 r; 
    for (mask = 0; mask < 16; mask++) { 
    r = _mm_blend_ps(a, b, mask); 
    PRINT(r); 
    } 
    return 0; 
} 

는이 코드를 컴파일

gcc -Wall -march=native -O3 -o blendsimple blendsimple.c 

코드가 작동합니다. 컴파일러는 루프를 풀고 즉치 피연산자의 상수를 삽입합니다.

그러나

gcc -Wall -march=native -O2 -o blendsimple blendsimple.c 
는 고유의 혼합에 대한 다음과 같은 오류 얻을

으로 코드를 컴파일하는 경우 :

error: the last argument must be a 4-bit immediate 

가 지금은 특정 컴파일러 플래그에 활성화 된 찾을려고 노력을 - 컴파일러가 루프를 언 롤할 수 있지만 실패한 O3은 있지만 -O2에는 없습니다.

gcc -c -Q -O3 --help=optimizers > /tmp/O3-opts 
gcc -c -Q -O2 --help=optimizers > /tmp/O2-opts 
diff /tmp/O2-opts /tmp/O3-opts | grep enabled 

-O2에 의해 -O3 아니라으로 사용 가능 모든 옵션을 나열

https://gcc.gnu.org/onlinedocs/gcc-4.8.2/gcc/Overall-Options.html

에서 GCC 온라인 문서에 따라 나는 다음 명령을 실행. 내가

gcc -Wall -march=native -O2 -fgcse-after-reload -finline-functions -fipa-cp-clone -fpredictive-commoning -ftree-loop-distribute-patterns -ftree-vectorize -funswitch-loops blendsimple blendsimple.c 

을 -O2 이외에 7 개 나열된 모든 플래그를 추가 할 때 나는 행동이 정확히 -O3와 동일합니다 기대합니다. 그러나 컴파일러는 "마지막 인수는 4 비트 즉석이어야합니다"라고 불평합니다.

누구에게 어떤 문제가 있습니까? #pragma GCC optimize 또는 함수 속성을 사용하여 선택적으로 활성화 할 수 있도록이 유형의 루프 언 롤링을 사용하려면 어떤 플래그가 필요한지 알아두면 좋을 것 같습니다.

(나는 또한 -O3가 분명히 언롤 루프 옵션을 활성화하지 않음에도 놀랐습니다).

나는 도움을 주셔서 감사합니다. 이것은 SSE 프로그래밍 강의입니다.

편집 : 의견을 보내 주셔서 감사합니다. jtaylor가 옳은 것 같습니다. 나는 gcc (4.7.3, 4.8.2)의 최신 버전 2 개를 손에 넣었고 4.8.2는 최적화 수준에 관계없이 즉각적인 문제에 대해 불만을 나타 냈습니다. Moverover, 나중에 gcc 4.6.3이 -O2 -funroll-loops로 코드를 컴파일한다는 것을 알아 차렸지만, 이것 역시 4.8.2에서 실패합니다. 따라서 분명히이 기능을 신뢰할 수 없으며 Jason R이 지적했듯이 항상 cpp 또는 템플릿을 사용하여 "수동으로"언 롤해야합니다.

+0

4 비트도 -03와 immediate' . –

+0

전처리 기나 템플릿 메타 프로그래밍을 사용하여 수동으로 언 롤링을 구현할 수 있습니다 (C++로 작성하는 경우). –

+1

이 동작은 컴파일러 버그 (4.8에서 수정 됨)와 비슷하게 보입니다. 컴파일러는 여러 최적화 수준에서 오류를 발생시키지 않아야합니다. gcc는 (조건부 등을 통한) 비 즉시 성을 항상 지원해야합니다. 그들이 이후 버전에서 나중을 선택했을 것 같습니다. 어느 것이 맞습니까? 내장 함수는 기계 명령어를 중심으로 매우 얇은 래퍼로되어 있습니다. – jtaylor

답변

1

SSE 내장 함수에 익숙하지 않기 때문에 상황에 해당되는지 확실하지 않습니다.그러나 일반적으로, 당신은 특별히와 코드 섹션을 최적화하기 위해 컴파일러를 알 수 있습니다 :

#pragma GCC push_options 
#pragma GCC optimize ("unroll-loops") 

do your stuff 

#pragma GCC pop_options 

자료 : I 오류`마지막 인수 여야을 얻을 Tell gcc to specifically unroll a loop