program story

컴파일러가 일부 명령어를 복제하는 이유는 무엇입니까?

inputbox 2020. 12. 13. 09:24
반응형

컴파일러가 일부 명령어를 복제하는 이유는 무엇입니까?


때때로 컴파일러는 안전하게 제거 할 수있는 이상한 명령어 중복으로 코드를 생성합니다. 다음 코드를 고려하십시오.

int gcd(unsigned x, unsigned y) {
  return x == 0 ? y : gcd(y % x, x);
}

다음은 어셈블리 코드 ( 최적화가 활성화 된 clang 5.0 에서 생성됨 )입니다.

gcd(unsigned int, unsigned int): # @gcd(unsigned int, unsigned int)
  mov eax, esi
  mov edx, edi
  test edx, edx
  je .LBB0_1
.LBB0_2: # =>This Inner Loop Header: Depth=1
  mov ecx, edx
  xor edx, edx
  div ecx
  test edx, edx
  mov eax, ecx
  jne .LBB0_2
  mov eax, ecx
  ret
.LBB0_1:
  ret

다음 스 니펫에서 :

  mov eax, ecx
  jne .LBB0_2
  mov eax, ecx

점프가 발생하지 않으면 eax명백한 이유없이 재 할당됩니다.

다른 예는 함수 끝에있는 두 개의 ret입니다. 하나는 완벽하게 작동합니다.

컴파일러가 충분히 지능적이지 않거나 중복을 제거하지 않을 이유가 있습니까?


컴파일러는 사람들에게 명확하지 않은 최적화를 수행 할 수 있으며 명령을 제거한다고해서 항상 작업 속도가 빨라지는 것은 아닙니다.

소량의 검색은 RET가 조건부 분기 바로 뒤에있을 때 다양한 AMD 프로세서에 분기 예측 문제가 있음을 보여줍니다. 해당 슬롯을 기본적으로 작동하지 않는 것으로 채우면 성능 문제가 방지됩니다.

최신 정보:

예제 참조, "AMD64 프로세서 용 소프트웨어 최적화 가이드"( http://support.amd.com/TechDocs/25112.PDF 참조 ) 섹션 6.2에서는 다음과 같이 말합니다.

특히 다음 두 가지 상황을 피하십시오.

  • 단일 바이트 니어 리턴 RET 명령어를 대상으로하는 모든 종류의 분기 (조건부 또는 무조건 부). "예제"를 참조하십시오.

  • 단일 바이트 니어 리턴 RET 명령어 바로 전에 코드에서 발생하는 조건부 분기입니다.

또한 점프 타겟이 정렬을 가져야하는 이유에 대해 자세히 설명합니다. 이는 함수 끝에서 중복 RET를 설명 할 가능성이 높습니다.


모든 컴파일러에는 레지스터 이름 변경, 풀기, 호이 스팅 등을위한 많은 변환이 있습니다. 출력을 결합하면 보여준 것과 같은 차선의 경우가 발생할 수 있습니다. Marc Glisse는 좋은 조언을 제공합니다. 버그보고의 가치가 있습니다. Peephole Optimizer가 다음 중 하나의 명령을 버릴 수있는 기회를 설명하고 있습니다.

  • 레지스터 및 메모리 상태에 전혀 영향을주지 않습니다.
  • 함수의 사후 조건에 중요한 상태에 영향을주지 않으며 공용 API에는 중요하지 않습니다.

상징적 인 실행 기법 의 기회처럼 들립니다 . 제약 솔버가 주어진 MOV에 대한 분기점을 찾지 못하면 실제로 NOP 일 수 있습니다.

참고 URL : https://stackoverflow.com/questions/48014076/why-do-compilers-duplicate-some-instructions

반응형