C++ 대 C로 컴파일 시 GCC 코드 생성의 큰 차이
저는 사용 가능한 다양한 SIMD 확장(MMX, SSE, AVX)에 대해 더 자세히 알아보려 x86-64 어셈블리를 가지고 약간 놀았습니다.
C나 C++ 구조가 어떻게 GCC에 의해 기계 코드로 변환되는지 확인하기 위해 훌륭한 도구인 컴파일러 탐색기를 사용해 왔습니다.
'플레이 세션' 중 하나에서 저는 GCC가 정수 배열의 간단한 런타임 초기화를 어떻게 최적화할 수 있는지 알고 싶었습니다.이 경우 저는 부호 없는 정수 2048개 배열에 0부터 2047까지의 숫자를 쓰려고 했습니다.
코드는 다음과 같습니다.
unsigned int buffer[2048];
void setup()
{
for (unsigned int i = 0; i < 2048; ++i)
{
buffer[i] = i;
}
}
최적화 및 AVX-512 지침을 활성화하는 경우-O3 -mavx512f -mtune=intelGCC 6.3은 정말 영리한 코드를 생성합니다 :)
setup():
mov eax, OFFSET FLAT:buffer
mov edx, OFFSET FLAT:buffer+8192
vmovdqa64 zmm0, ZMMWORD PTR .LC0[rip]
vmovdqa64 zmm1, ZMMWORD PTR .LC1[rip]
.L2:
vmovdqa64 ZMMWORD PTR [rax], zmm0
add rax, 64
cmp rdx, rax
vpaddd zmm0, zmm0, zmm1
jne .L2
ret
buffer:
.zero 8192
.LC0:
.long 0
.long 1
.long 2
.long 3
.long 4
.long 5
.long 6
.long 7
.long 8
.long 9
.long 10
.long 11
.long 12
.long 13
.long 14
.long 15
.LC1:
.long 16
.long 16
.long 16
.long 16
.long 16
.long 16
.long 16
.long 16
.long 16
.long 16
.long 16
.long 16
.long 16
.long 16
.long 16
.long 16
그러나 GCC C-compiler를 사용하여 flags를 추가하여 동일한 코드를 컴파일하면 어떤 결과가 발생하는지 테스트해 보았을 때-x c나 정말 놀랐었어요.
저는 동일하지는 않지만 비슷한 결과를 기대했지만 C 컴파일러는 훨씬 더 복잡하고 아마도 훨씬 느린 기계 코드를 생성하는 것 같습니다.결과 어셈블리의 크기가 너무 커서 전체를 붙여넣을 수 없지만, 이 링크를 따라 godbolt.org 에서 볼 수 있습니다.
생성된 코드의 일부분인 58번부터 83번까지는 아래와 같습니다.
.L2:
vpbroadcastd zmm0, r8d
lea rsi, buffer[0+rcx*4]
vmovdqa64 zmm1, ZMMWORD PTR .LC1[rip]
vpaddd zmm0, zmm0, ZMMWORD PTR .LC0[rip]
xor ecx, ecx
.L4:
add ecx, 1
add rsi, 64
vmovdqa64 ZMMWORD PTR [rsi-64], zmm0
cmp ecx, edi
vpaddd zmm0, zmm0, zmm1
jb .L4
sub edx, r10d
cmp r9d, r10d
lea eax, [r8+r10]
je .L1
mov ecx, eax
cmp edx, 1
mov DWORD PTR buffer[0+rcx*4], eax
lea ecx, [rax+1]
je .L1
mov esi, ecx
cmp edx, 2
mov DWORD PTR buffer[0+rsi*4], ecx
lea ecx, [rax+2]
보시다시피 이 코드는 복잡한 움직임과 점프가 많고 일반적으로 단순한 배열 초기화를 수행하는 매우 복잡한 방식처럼 느껴집니다.
생성된 코드에 왜 이렇게 큰 차이가 나죠?
일반적으로 GCC C++ 컴파일러는 C와 C++에서 모두 유효한 코드를 최적화하는 데 있어 C 컴파일러와 비교할 때 더 우수합니까?
추가 코드는 사용된 명령어가 잘못 정렬된 것을 처리하기 위한 것입니다.vmovdqa64, 64바이트 정렬이 필요합니다.
내 테스트 결과 표준이 그렇지 않더라도 gcc는 C 모드일 때 다른 모듈의 정의를 무시할 수 있습니다.이 정의는 기본 정렬 요구 사항(4바이트)만 준수할 수 있으므로 컴파일러는 더 큰 정렬에 의존할 수 없습니다.기술적으로, GCC는 다음과 같이.comm외부 정의가 정규 기호를 사용하는 동안, 이 잠정적 정의에 대한 어셈블리 지시..data부분. 하는 동안 이는 링크하는 이 기호는 다음 우선합니다 기호보다 동안 the 우선합니다 over보다 우선합니다..comm나
할 을 할 을 하도록 프로그램을 변경할 경우 참고합니다.extern unsigned int buffer[2048];그러면 C++ 버전에서도 코드가 추가됩니다.반대로 성공하는 것.static unsigned int buffer[2048];는 C 버전을 최적화된 버전으로 바꿉니다.
언급URL : https://stackoverflow.com/questions/41292971/big-differences-in-gcc-code-generation-when-compiling-as-c-vs-c
'programing' 카테고리의 다른 글
| 레지스트리에서 Windows PowerShell 세션 환경 변수를 업데이트하는 방법은 무엇입니까? (0) | 2023.09.12 |
|---|---|
| 명령 /Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang이 종료 코드 1과 함께 실패했습니다. (0) | 2023.09.12 |
| 텍스트를 포함하는 요소만 반환하고 상위 항목은 반환하지 않는 XPath (0) | 2023.09.12 |
| 공간 조인이 있는 mysql 뷰가 작동하지 않습니다. (0) | 2023.09.12 |
| 모든 부모가 있는 트리에 있는 노드의 mysql에서 부모/자녀 관계의 전체 트리 가져오기 (0) | 2023.09.12 |