스택큐힙리스트
GCC가 a*a*a*a*a*a를 (a*a*a)*(a*a*a)로 최적화하지 않는 이유는 무엇인가요? 본문
나는 과학 응용 프로그램에서 숫자 최적화를 수행하고 있습니다. 내가 알아낸 한 가지 문제는 GCC가 pow(a,2) 호출을 a*a으로 컴파일하여 최적화한다는 것입니다. 그러나 호출 #$!!*#^$& 는 최적화되지 않으며, 실제로는 라이브러리 함수 w , whi 를 호출하여 성능을 크게 늦출 수 있습니다. (반면, tel C++ Compiler , exe, 실행 가능한 c , wil, 는 pow(a,6)을 위한 라이브러리 호출을 제거합니다.)
내가 궁금한 것은, 내가 GCC 4.5.1과 -O3 -lm -funroll-loops -msse4 옵션을 사용하여 #$@ *&! ## $ &를 #$ *! & * ^! $ &로 대체 할 때, 5 #$ # ^ $ # ^ @ $ & 명령을 사용한다는 것이다.
movapd %xmm14, %xmm13
mulsd %xmm14, %xmm13
mulsd %xmm14, %xmm13
mulsd %xmm14, %xmm13
mulsd %xmm14, %xmm13
mulsd %xmm14, %xmm13
만약 내가 (a*a*a)*(a*a*a)를 쓰면, 그것은 생성될 것입니다.
movapd %xmm14, %xmm13
mulsd %xmm14, %xmm13
mulsd %xmm14, %xmm13
mulsd %xmm13, %xmm13
곱셈 명령어 수를 3개로 감소시키는 것입니다. icc도 비슷한 동작을 합니다.
컴파일러는 이 최적화 기법을 인식하지 못하는 이유는 무엇인가요?
답변 1
Floating Point Math is not Associative. 부동 소수점 곱셈에서 피연산자를 어떻게 그룹화하느냐에 따라 답의 숫자 정확도에 영향을 끼칩니다.
결과적으로 대부분의 컴파일러들은 부동 소수점 계산의 순서를 재배치하는 것이 확실하지 않거나 수치적 정확도에 대해 신경 쓰지 않는다는 것을 보장하지 않는 한 매우 보수적입니다. 예를 들어, 부동 소수점 연산을 재결합할 수 있게 하는 gcc의 the -fassociative-math option 또는 정확도 대 속도 트레이드오프를 가능하게 하는 -ffast-math 옵션이 있습니다.
답변 2
GCC는 왜 a*a*a*a*a*a를 (a*a*a)*(a*a*a)로 최적화하지 않을까요?
GCC는 매우 강력한 컴파일러이며, 코드를 컴파일 할 때 최적화를 수행하여 더 나은 성능을 제공합니다. 이러한 최적화는 소스 코드의 문제를 잡고 코드를 더 효율적으로 실행 할 수 있게 하는 데 도움이 됩니다.
그러나 GCC가 a*a*a*a*a*a를 (a*a*a)*(a*a*a)로 최적화하지 않는 이유는 여러 가지가 있습니다. 그중 하나는 GCC 컴파일러가 코드에서 곱셈을 최적화하는 방식입니다. 보통 GCC는 곱셈을 가속화하기 위해 로프 속성(Law-of-Associativity)을 사용합니다. 이 속성은 곱셈이 결합 법칙을 준수하면 곱셈의 순서를 바꿀 수 있다는 것을 의미합니다.
예를 들어, (a * b) * (c * d)는 a*b*c*d와 동일합니다. 이를 통해 GCC는 곱셈을 더 빠르고 효율적으로 처리 할 수 있으며, 이로 인해 코드의 실행 속도가 향상됩니다.
그러나 a*a*a*a*a*a에서는 이러한 로프 속성을 사용할 수 없습니다. 여러 개의 곱셈이 포함 된 경우 로프 속성이 모두 적용되고 결과가 완전히 다른 순서로 재배열될 수 없기 때문입니다.
따라서 GCC는이 곱셈을 최적화하는 대신 다른 방법을 사용하여 코드의 실행 속도를 최적화합니다. 이를테면 GCC는 변수의 공간적 및 시간적 지역성을 활용하여 곱셈을 더 적게 수행하고 결과를 더 잘 기억하는 방법을 사용할 수 있습니다.
결론적으로, GCC가 a*a*a*a*a*a를 (a*a*a)*(a*a*a)로 최적화하지 않는 이유는 로프 속성을 적용하여 곱셈을 최적화 할 수 없기 때문입니다. 그러나 GCC는이를 최적화하는 다른 방법을 사용하여 코드의 실행 속도를 향상시키고 효율적인 코드를 생성합니다.