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 最適化とは、codegen の前によりよい MIR を生成するために MIR 上で実行される最適化です。 これは 2 つの理由で重要です。第一に、最終的に生成される実行可能コードがよりよいものになります。 第二に、LLVM が行う作業が少なくなるため、コンパイルが速くなります。MIR はジェネリックである(まだ 単相化されていない)ため、これらの最適化は特に効果的であることに注意してください。 ジェネリック版を最適化できるため、すべての単相化がより低コストになります!

MIR 最適化は借用チェックの後に実行されます。MIR を改善するため、一連の最適化 パスを MIR に対して実行します。一部のパスはすべてのコードで実行する必要があり、 一部のパスは実際には最適化を行わず、何らかのチェックだけを行います。また、一部の パスは release モードでのみ有効になります。

optimized_mir クエリは、指定された DefId の最適化済み MIR を生成するために呼び出されます。このクエリは、借用チェッカーが実行済みであり、 いくつかの検証が行われていることを確認します。その後、MIR を奪取し、 それを最適化して、改善された MIR を返します。

新しい最適化を追加するためのクイックスタート

  1. 最適化したいコードを示す Rust ソースファイルを tests/mir-opt に作成します。 これはシンプルに保つべきなので、その最適化に必要でない場合は println! やその他のフォーマット コードを避けてください。その理由は、println!format! などは大量の MIR を生成し、 その最適化がテストに対して何を行うのかを理解しにくくする可能性があるためです。

  2. ./x test --bless tests/mir-opt/<your-test>.rs を実行して MIR ダンプを生成します。何をダンプするかについての手順は、この README を読んでください。

  3. 現在の作業ディレクトリの状態をコミットします。最適化を実装する前にテスト出力をコミットすべき理由は、 その最適化によって何が変わったのかについて、あなた(およびレビュアー)が前後の差分を確認できるようにするためです。

  4. compiler/rustc_mir_transform/src に新しい最適化を実装します。 これを行う最速かつ最も簡単な方法は、次のとおりです。

    1. 小さな最適化(たとえば remove_storage_markers)を選び、それを新しいファイルにコピーする。
    2. あなたの最適化を run_optimization_passes() 関数内のいずれかのリストに追加する。
    3. その後、コピーした最適化の変更を開始する。
  5. ./x test --bless tests/mir-opt/<your-test>.rs を再実行して、 MIR ダンプを再生成します。差分を見て、それが期待どおりかどうかを確認します。

  6. ./x test tests/ui を実行して、あなたの最適化によって何かが壊れていないかを確認します。

  7. あなたの最適化に問題がある場合は、少し実験し、 手順 5 と 6 を繰り返します。

  8. コミットして PR を開きます。これはいつ行ってもよく、まだ動作していない場合でも、 PR 上でフィードバックを求めることができます。その場合は、「WIP」PR (PR タイトルの先頭に [WIP] を付けるか、作業中であることを別の方法で明記します)を開いてください。

    blessed されたテスト出力も必ずコミットしてください!CI を通すために必要であり、 レビュアーにとっても非常に役立ちます。

途中で質問がある場合は、Zulip の #t-compiler/wg-mir-opt で遠慮なく聞いてください。

最適化パスの定義

実行されるパスの一覧とそれらが実行される順序は、 run_optimization_passes 関数によって定義されています。この関数には、実行するパスの配列が含まれています。 配列内の各パスは、MirPass トレイトを実装する構造体です。 この配列は &dyn MirPass トレイトオブジェクトの配列です。通常、パスは rustc_mir_transform クレートの独自のモジュール内に実装されます。

パスの例をいくつか挙げます。

  • CleanupPostBorrowck: codegen ではなく解析にのみ必要な情報の一部を削除します。
  • ConstProp: 定数伝播を行います。

さらに多くの例については、MirPass rustdoc の「Implementors」セクションを参照できます。

MIR 最適化レベル

MIR 最適化には、さまざまな完成度のレベルがあります。実験的な 最適化は、誤コンパイルを引き起こしたり、コンパイル時間を遅くしたりする可能性があります。 これらのパスは、フィードバックを集め、パスを変更しやすくするために、nightly ビルドには引き続き含まれています。 低速な最適化パスやその他の実験的な最適化パスでの作業を有効にするには、 -Z mir-opt-level デバッグフラグを指定できます。レベルの定義は compiler MCP にあります。MIR パスを開発していて、自分の最適化パスを実行すべきかどうかを問い合わせたい場合は、 tcx.sess.opts.unstable_opts.mir_opt_level を使用して現在のレベルを確認できます。