2012-08-13 4 views
4

위를 참조하십시오. 나는 샘플 기능에 쓴 : 왜 그LLVM이 최적화 부동 소수점 명령어를 전달하지 않는 이유는 무엇입니까?

source.ll:

define i32 @bleh(i32 %x) { 
entry: 
    %addtmp = add i32 %x, %x 
    %addtmp1 = add i32 %addtmp, %x 
    %addtmp2 = add i32 %addtmp1, %x 
    %addtmp3 = add i32 %addtmp2, %x 
    %addtmp4 = add i32 %addtmp3, 1 
    %addtmp5 = add i32 %addtmp4, 2 
    %addtmp6 = add i32 %addtmp5, 3 
    %multmp = mul i32 %x, 3 
    %addtmp7 = add i32 %addtmp6, %multmp 
    ret i32 %addtmp7 
} 

source-fp.ll:

define double @bleh(double %x) { 
entry: 
    %addtmp = fadd double %x, %x 
    %addtmp1 = fadd double %addtmp, %x 
    %addtmp2 = fadd double %addtmp1, %x 
    %addtmp3 = fadd double %addtmp2, %x 
    %addtmp4 = fadd double %addtmp3, 1.000000e+00 
    %addtmp5 = fadd double %addtmp4, 2.000000e+00 
    %addtmp6 = fadd double %addtmp5, 3.000000e+00 
    %multmp = fmul double %x, 3.000000e+00 
    %addtmp7 = fadd double %addtmp6, %multmp 
    ret double %addtmp7 
} 

이다 나는,555,533 그

opt -O3 source[-fp].ll -o opt.source[-fp].ll -S

를 사용하여 두 기능을 최적화 할 때3210은 최적화되었지만 double은 최적화되지 않습니까? fadd이 하나의 fmul에 결합 될 것으로 예상됩니다. 대신 정확히 똑같아 보입니다.

플래그가 다르게 설정 되었기 때문입니까? double에 대해 수행 할 수없는 i32에 대해 가능한 특정 최적화에 대해 알고 있습니다. 그러나 간단한 상수 폴딩의 부재는 나의 이해를 넘어서는 것이다.

저는 LLVM 3.1을 사용하고 있습니다.

+3

GCC가 왜 * a * a * a *를 (a * a * a) * (a * a * a)로 최적화하지 않는지 확실하지 않지만 관련성이 높습니다.)?] (http://stackoverflow.com/q/6430448/395760) – delnan

+3

@delan 비슷한 부동 소수점 질문과 마찬가지로, 실제로 이것은 중복입니다. 질문의 세부 사항이 다를지라도 답은 동일합니다. 이 질문에 대한 좋은 대답은 부동 소수점 산술의 비 연관성과 언급 - 양적 수학을 지적 할 것입니다. –

+0

감사합니다. 링크 된 질문에 대한 대답은 http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html에서 찾아 볼 수 있으며 모호성에 대한 섹션을 강조합니다. – f00id

답변

7

아니요 최적화가 가능하다는 것은 사실이 아닙니다. fadd과 같이 일반적으로 (

%addtmp = fadd double %x, %x 

이 첫 번째 줄에 안전하게 fmul double %x 2.0e+0로 변환 할 수 있지만, 실제로 대부분의 아키텍처에 최적화 아니다 : 나는 변환을하고 허용되지 않는 곳 보여 처음 몇 줄을 통해 갈거야 fmul보다 빠르거나 빠르며 상수 2.0을 생성 할 필요가 없습니다. 오버플로가 발생하지 않도록주의하십시오.이 작업은 정확합니다 (2의 제곱으로 모든 비율 조정과 동일).

%addtmp1 = fadd double %addtmp, %x 

이 줄은 fmul double %x 3.0e+0으로 변환 될 수 있습니다. 왜 이것이 합법적 인 변형인가? %addtmp을 생성 한 계산이 정확했기 때문에 x * 3 또는 x + x + x으로 계산 되든 하나의 반올림 만 발생했습니다. 이것들은 IEEE-754 기본 연산이므로 정확하게 반올림되므로 결과는 같은 방법입니다. 오버플로는 어떨까요? 다른 쪽도 않는 한 오버플로 할 수 없습니다.

%addtmp2 = fadd double %addtmp1, %x 

이것은 상수 * x로 합법적으로 변환 할 수없는 첫 번째 줄입니다. 4 * x은 아무런 반올림없이 정확하게 계산되지만, 은 두 번의 반올림이 발생합니다. x + x + x은 한 번 반올림 한 다음 x을 두 번 추가 할 수 있습니다.

%addtmp3 = fadd double %addtmp2, %x 

여기입니다. 5 * x은 한 번의 반올림을 초래합니다. x + x + x + x + x에는 3이 발생합니다.

유용하게 변형 될 수있는 유일한 행은 x + x + x3 * x으로 바꿉니다. 그러나 서브 표현식 x + x은 이미 다른 위치에 있으므로 옵티마이 저가이 변환을 사용하지 않기로 선택할 수 있습니다 (그렇지 않은 경우 기존 부분 결과를 이용할 수 있기 때문에).

+0

그 상세한 대답을 가져 주셔서 감사합니다. 그러므로'fmul double % x 2.0e + 0'과 상수 값의 전파는'fadd'를 반복하는 것보다 느립니다. 아니면 반올림 문제가 누락 되었습니까? – f00id

+0

'2 * x'와'x + x'는 수치 적으로 같습니다. 그러나 공통 아키텍처에서 'x + x'는'2 * x '보다 느리지 않으며 때로는 더 빠릅니다. 따라서 일반적으로 최적화 프로그램이'2 * x'를 사용할 이유가 없습니다. –

+0

그러나'% y1 = fadd double % x, % x','% y2 = fadd double % y1, % y1'과 같은 것을하는 것보다'x + x'를 두 번 (그리고 나서'x ' % res = fadd double % y2, % x'. 아마도 오도 된 'fmul'을 강조하고 싶지 않았습니다. – f00id

관련 문제