39P by lemonmint 26일전 | favorite | 댓글과 토론

컴파일러 최적화에 대한 오해

  • 최적화는 최적의 프로그램을 제공한다?
    • 컴파일러는 최적의 프로그램을 생성하는 것이 아니라, 단순화된 프로그램을 개선하는 것을 목표로 합니다.
    • 코드 크기 최적화는 가능성이 있지만, 실행 시간 최적화는 측정의 어려움, 최적 부분 구조의 부재, 하드웨어 모델의 부정확성 등으로 인해 어렵습니다.
    • 실행 시간은 코드 크기와 달리 정확한 측정이 어렵고, 여러 요인의 영향을 받으며, 최적 부분 구조를 갖지 않습니다. 예를 들어, 두 개의 루프를 개별적으로 최적화하더라도 전체 프로그램의 최적화를 위해서는 두 루프를 합쳐야 할 수도 있습니다. 또한, 컴파일 대상 하드웨어에 대한 정확한 모델이 없기 때문에 최적화가 어렵습니다. 예를 들어, goSLP는 전역적으로 최적화된 SLP 벡터화 코드를 생성하지만, 하드웨어 모델이 부정확하기 때문에 생성된 프로그램이 최적이 아닐 뿐만 아니라 LLVM보다 느릴 수도 있습니다.

분기 예측과 관련된 오해

  • 분기 가중치는 CPU의 분기 예측기에 사용된다?
    • x86 아키텍처에서 컴파일러는 분기 힌트를 생성하지 않습니다.
    • 분기 가중치는 컴파일러의 코드 블록 배치에 사용됩니다. (예: 분기 가능성이 높으면 명령어 캐시 지역성을 높이기 위해 대상 블록을 현재 블록 바로 아래에 배치)
    • 최근 Intel Redwood Cove 아키텍처에서 분기 힌트가 다시 관련성을 갖게 되었지만, 실제로 컴파일러가 이러한 힌트를 생성하는 경우는 드뭅니다.

최적화 레벨에 대한 오해

  • -O3는 -O2보다 훨씬 빠른 코드를 생성한다?
    • Clang의 경우 -O2와 -O3의 성능 차이가 크지 않으며, GCC의 경우 -O2가 Clang보다 덜 적극적이므로 약간의 차이가 있습니다.
    • -O3는 코드 크기를 거의 고려하지 않으므로 명령어 캐시 문제가 발생할 수 있습니다.
    • 벤치마킹을 통해 확인하는 것이 좋습니다.

Javascript 인터프리터와 JIT 컴파일러에 대한 오해

  • Javascript 인터프리터는 런타임에 JIT 컴파일을 수행하는 이유는 어떤 경로가 핫한지 미리 알 수 없기 때문이다?
    • 핫 경로를 아는 것만으로는 충분하지 않으며, 타입 정보도 필요합니다.
    • 타입 정보는 런타임에만 알 수 있으므로 JIT 컴파일러가 런타임에 코드를 컴파일합니다.

컴파일러와 인터프리터의 관계에 대한 오해

  • 컴파일러가 있으면 인터프리터가 필요 없다?
    • C/C++의 경우 인터프리터가 유용하지 않지만, WebAssembly와 같은 경우 인터프리터가 개발 및 사용의 용이성, 디버깅, 보안 등의 이점을 제공할 수 있습니다.

컴파일러 중간 단계에 대한 오해

  • 중간 단계(middle-end)는 대상/플랫폼에 독립적이다?
    • LLVM의 경우 중간 단계가 대상/플랫폼에 완전히 독립적이지는 않습니다.

데이터 지역성 최적화에 대한 오해

  • 컴파일러는 데이터 지역성을 최적화한다?
    • 컴파일러는 명령어 캐시 지역성을 최적화하지만, 데이터 지역성은 거의 최적화하지 않습니다.
    • 데이터 지역성 최적화는 코드에 대한 대규모 변경이 필요하며, C/C++ 컴파일러는 이러한 변경을 수행할 수 없습니다.
    • 데이터 지역성을 개선하려면 데이터 중심 설계와 같은 기법을 사용해야 합니다.

컴파일 속도에 대한 오해

  • -O0은 빠른 컴파일을 제공한다?
    • -O0은 디버깅 가능하고 예측 가능한 코드를 생성하지만, 항상 빠른 컴파일을 보장하지는 않습니다.
    • 일반적으로 -O0이 -O2보다 빠르지만, 프로젝트 규모와 컴파일러에 따라 다를 수 있습니다.
    • 빠른 컴파일을 위해서는 표준 컴파일 파이프라인을 우회하거나 (예: TinyCC), LLVM IR을 직접 생성하는 방법을 고려할 수 있습니다.

템플릿 컴파일 속도에 대한 오해

  • 템플릿은 컴파일 속도가 느리다?
    • C++ 템플릿이 컴파일 속도가 느린 것은 C++의 컴파일 모델 때문입니다.
    • 템플릿 자체가 컴파일 속도를 크게 저하시키는 것은 아닙니다.
    • Dlang의 표준 라이브러리 Phobos는 많은 템플릿을 사용하지만 빠른 속도로 컴파일됩니다.

개별 컴파일의 효용성에 대한 오해

  • 개별 컴파일은 항상 가치가 있다?
    • 개별 컴파일은 링크 시간이 오래 걸릴 수 있습니다.
    • 많은 프로젝트에서 유니티 빌드(모든 코드를 단일 파일에 포함)가 더 나은 성능을 제공합니다.
    • 유니티 빌드는 전체 프로그램 최적화, 컴파일 속도 향상, 에러 로그 개선 등의 이점을 제공합니다.
    • 개별 컴파일이 유니티 빌드보다 나은 경우는 드뭅니다.

링크 시간 최적화(LTO)에 대한 오해

  • 링크 시간 최적화(LTO)는 왜 링크 시간에 발생하는가?
    • LTO는 전체 프로그램 최적화를 위해 수행됩니다.
    • 이론적으로는 중간 단계에서 전체 프로그램 최적화를 수행하는 것이 더 합리적이지만, C/C++ 빌드 시스템의 현실적인 문제 (소스 파일 찾기 및 호출 관계 파악의 어려움) 때문에 링크 시간에 수행됩니다.
    • 링커는 모든 오브젝트 파일을 찾을 수 있으므로, 컴파일러는 링커가 액세스할 수 있도록 오브젝트 파일에 LLVM IR과 같은 중간 언어 표현을 포함시킵니다.

인라이닝 최적화에 대한 오해

  • 인라이닝은 주로 함수 호출 명령어를 제거하기 때문에 유용하다?
    • 함수 호출 명령어를 제거하는 것은 이점이지만, 인라이닝의 가장 큰 이점은 다른 최적화를 가능하게 하는 것입니다.
    • 인라이닝은 함수 간 최적화를 가능하게 합니다.
    • 인라이닝을 통해 여러 함수의 코드가 하나의 함수로 합쳐지면, 기존의 함수 내 최적화 기법을 적용할 수 있습니다.

인라인 키워드의 역할에 대한 오해

  • 인라인 키워드는 인라이닝 최적화와 관련이 있는가?
    • C++의 인라인 키워드는 원래 최적화 프로그램에 대한 힌트로 사용되었지만, C++98 이후로는 "여러 정의 허용"을 의미하게 되었습니다.
    • LLVM의 경우 인라인 키워드가 있으면 inlinehint 속성을 추가하고 인라이닝 임계값을 높이지만, 그 영향은 크지 않습니다.
    • 함수를 항상 인라인하려면 always_inline 지정자를 사용해야 합니다.

컴파일러 학습 자료에 대한 오해

  • LLVM은 학습하기 가장 좋은 컴파일러이다?
    • LLVM은 교육적인 측면도 있지만, 다양한 사용 사례를 지원하기 때문에 복잡하고 방대합니다.
    • 컴파일러 개발 학습을 위해서는 Go 컴파일러, LDC, DMD 등 더 작고 단순한 컴파일러를 먼저 살펴보는 것이 좋습니다.

정의되지 않은 동작(Undefined Behavior)에 대한 오해

  • 정의되지 않은 동작은 최적화만 가능하게 한다?

    • 정의되지 않은 동작은 최적화를 비활성화할 수도 있습니다.
  • 컴파일러는 정의되지 않은 동작을 "단순히" 정의할 수 있다?

    • 컴파일러는 정의되지 않은 동작을 정의할 수 있지만, 성능에 영향을 미칠 수 있습니다.
    • 컴파일러가 모든 정의되지 않은 동작을 플랫폼의 동작으로 정의하는 것은 이상적이지만, 현실적으로 쉽지 않습니다.

AI 기반 코드 생성에 대한 오해

  • 99% 정확도의 코드 생성은 괜찮다?
    • 컴파일러에서 생성된 코드의 99% 정확도는 실제로 사용하기 어렵습니다.
    • 코드의 1% 오류는 디버깅 및 유지보수에 큰 어려움을 초래합니다.
    • 대규모 프로젝트에서는 1% 오류가 매우 심각한 문제를 일으킬 수 있습니다.
    • 현재 LLM은 컴파일러에 비해 매우 느리기 때문에 온라인 코드 생성에 적합하지 않습니다.