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을 만들기 위해 MIR에 대해 실행되는 최적화입니다. 이는 두 가지 이유로 중요합니다. 첫째, 최종적으로 생성되는 실행 코드가 더 좋아지고, 둘째, LLVM이 해야 할 작업이 줄어들어 컴파일이 더 빨라집니다. MIR은 제네릭이므로(아직 단형화되지 않았으므로) 이러한 최적화가 특히 효과적이라는 점에 유의하십시오. 제네릭 버전을 최적화할 수 있으므로 모든 단형화 결과의 비용이 줄어듭니다!

MIR 최적화는 빌림 검사 후에 실행됩니다. MIR을 개선하기 위해 MIR에 대해 일련의 최적화 패스를 실행합니다. 일부 패스는 모든 코드에 대해 반드시 실행되어야 하고, 일부 패스는 실제로 최적화를 수행하지 않고 검사만 하며, 일부 패스는 release 모드에서만 활성화됩니다.

주어진 DefId에 대한 최적화된 MIR을 만들기 위해 optimized_mir 쿼리가 호출됩니다. 이 쿼리는 빌림 검사기가 실행되었는지, 그리고 일부 검증이 수행되었는지 확인합니다. 그런 다음 MIR을 훔쳐 와서(steal) 최적화하고, 개선된 MIR을 반환합니다.

새 최적화 추가를 위한 빠른 시작

  1. 최적화하려는 코드를 보여 주는 Rust 소스 파일을 tests/mir-opt에 만드십시오. 이 파일은 단순하게 유지해야 하므로, 최적화에 필요하지 않다면 println!이나 기타 포매팅 코드는 피하십시오. 그 이유는 println!, format! 등이 많은 MIR을 생성하여 최적화가 테스트에 어떤 영향을 주는지 이해하기 어렵게 만들 수 있기 때문입니다.

  2. MIR 덤프를 생성하려면 ./x test --bless tests/mir-opt/<your-test>.rs를 실행하십시오. 덤프하는 방법은 이 README를 참고하십시오.

  3. 현재 작업 디렉터리 상태를 커밋하십시오. 최적화를 구현하기 전에 테스트 출력을 커밋해야 하는 이유는 여러분(그리고 리뷰어)이 최적화로 무엇이 바뀌었는지 전후 diff로 확인할 수 있도록 하기 위해서입니다.

  4. compiler/rustc_mir_transform/src에 새 최적화를 구현하십시오. 이를 가장 빠르고 쉽게 하는 방법은 다음과 같습니다.

    1. 작은 최적화(예: remove_storage_markers)를 골라 새 파일에 복사하고,
    2. run_optimization_passes() 함수에 있는 목록 중 하나에 여러분의 최적화를 추가한 다음,
    3. 복사한 최적화를 수정하기 시작하십시오.
  5. MIR 덤프를 다시 생성하려면 ./x test --bless tests/mir-opt/<your-test>.rs를 다시 실행하십시오. diff를 보고 예상한 대로인지 확인하십시오.

  6. 최적화가 무언가를 망가뜨렸는지 확인하려면 ./x test tests/ui를 실행하십시오.

  7. 최적화에 문제가 있으면 조금 실험해 보고 5단계와 6단계를 반복하십시오.

  8. 커밋하고 PR을 여십시오. 아직 제대로 동작하지 않더라도 언제든지 이 작업을 할 수 있으며, 그러면 PR에서 피드백을 요청할 수 있습니다. 그런 경우에는 “WIP” PR을 여십시오(PR 제목 앞에 [WIP]를 붙이거나 다른 방식으로 작업 중임을 표시하면 됩니다).

    bless된 테스트 출력도 반드시 커밋하십시오! 이는 CI를 통과하는 데 필요하며 리뷰어에게도 매우 도움이 됩니다.

진행하다가 궁금한 점이 있으면 언제든지 Zulip의 #t-compiler/wg-mir-opt에서 질문하십시오.

최적화 패스 정의하기

실행되는 패스의 목록과 그 실행 순서는 run_optimization_passes 함수에서 정의됩니다. 이 함수에는 실행할 패스의 배열이 들어 있습니다. 배열의 각 패스는 MirPass 트레이트를 구현하는 구조체입니다. 이 배열은 &dyn MirPass 트레이트 객체의 배열입니다. 일반적으로 패스는 rustc_mir_transform 크레이트 안의 전용 모듈에 구현됩니다.

패스의 몇 가지 예는 다음과 같습니다.

  • CleanupPostBorrowck: 코드 생성이 아니라 분석에만 필요한 정보의 일부를 제거합니다.
  • ConstProp: 상수 전파를 수행합니다.

더 많은 예는 MirPass rustdocs의 “Implementors” 섹션에서 볼 수 있습니다.

MIR 최적화 수준

MIR 최적화는 완성도에 따라 여러 수준으로 나뉠 수 있습니다. 실험적인 최적화는 잘못된 컴파일을 일으키거나 컴파일 시간을 늘릴 수 있습니다. 이러한 패스는 피드백을 수집하고 패스를 더 쉽게 수정할 수 있도록 여전히 nightly 빌드에 포함됩니다. 느리거나 그 밖의 이유로 실험적인 최적화 패스를 사용하려면 -Z mir-opt-level 디버그 플래그를 지정하면 됩니다. 각 수준의 정의는 컴파일러 MCP에서 확인할 수 있습니다. MIR 패스를 개발하면서 최적화 패스를 실행해야 하는지 쿼리하려면 tcx.sess.opts.unstable_opts.mir_opt_level을 사용하여 현재 수준을 확인할 수 있습니다.