Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

MIR에서 바이너리까지

이 가이드의 앞선 모든 장에는 한 가지 공통점이 있습니다. 실행 가능한 기계어 코드를 전혀 생성하지 않았다는 점입니다! 이 장에서는 그 모든 것이 바뀝니다.

지금까지 컴파일러가 텍스트 형식의 원시 소스 코드를 받아 MIR로 변환하는 방법을 살펴보았습니다. 또한 컴파일러가 코드에 대해 다양한 분석을 수행하여 타입 오류나 라이프타임 오류 같은 것을 탐지하는 방법도 살펴보았습니다. 이제 마침내 MIR을 받아 실행 가능한 기계어 코드를 만들어 보겠습니다.

참고: 컴파일러의 이 부분은 흔히 백엔드라고 불립니다. 이 용어는 여러 의미로 쓰이는데, 컴파일러 소스에서는 보통 “코드 생성 백엔드”(즉, LLVM, Cranelift 또는 GCC)를 가리키기 때문입니다. 이 부분에서 “백엔드“라는 단어가 나오면 보통 “코드 생성 백엔드“를 가리키는 것입니다.

그렇다면 무엇을 해야 하겠습니까?

  1. 먼저 코드를 생성할 대상의 집합을 수집해야 합니다. 특히 구체 타입에 대한 코드를 생성해야 하므로, 제네릭 타입을 어떤 구체 타입으로 대체할지 알아내야 합니다. 구체 타입에 대한 코드를 생성하는 것(즉, 각 구체 타입마다 코드의 사본을 내보내는 것)을 단형화라고 하므로, 모든 구체 타입을 수집하는 과정을 단형화 수집이라고 합니다.
  2. 다음으로, 수집한 각 구체 타입에 대해 MIR을 코드 생성 IR(보통 LLVM IR)로 실제로 낮춰야 합니다.
  3. 마지막으로 코드 생성 백엔드를 호출해야 합니다. 코드 생성 백엔드는 여러 최적화 패스를 실행하고, 실행 가능한 코드를 생성하며, 이를 링크하여 실행 가능한 바이너리를 만듭니다.

코드 생성을 위한 코드는 몇 가지 요인 때문에 실제로 다소 복잡합니다:

  • 여러 코드 생성 백엔드(LLVM, Cranelift, GCC)를 지원합니다. 백엔드 코드를 가능한 한 많이 공유하려고 하므로, 상당 부분이 코드 생성 구현에 대해 제네릭합니다. 이 때문에 추상화 계층이 여러 겹인 경우가 많습니다.
  • 성능을 위해 코드 생성은 다른 스레드에서 비동기적으로 수행됩니다.
  • 실제 코드 생성은 서드파티 라이브러리(세 백엔드 중 하나)가 수행합니다.

일반적으로 rustc_codegen_ssa 크레이트에는 백엔드에 독립적인 코드가 있고, rustc_codegen_llvm 크레이트에는 LLVM 코드 생성에 특화된 코드가 있습니다.

아주 높은 수준에서 보면 진입점은 rustc_codegen_ssa::base::codegen_crate입니다. 이 함수는 이 장의 나머지 부분에서 설명하는 과정을 시작합니다.