MIR をコード生成 IR に lowering する
collector から生成すべきシンボルのリストが得られたので、何らかのコード生成 IR を生成する必要があります。この章では、LLVM IR を前提とします。rustc が通常使用するのはそれだからです。実際の monomorphization は、変換を行いながらその場で実行されます。
backend は
rustc_codegen_ssa::base::codegen_crate によって開始されることを思い出してください。最終的に、これは
rustc_codegen_ssa::mir::codegen_mir に到達し、そこで
MIR から LLVM IR への lowering が行われます。
コードは、特定の MIR プリミティブを扱うモジュールに分割されています。
rustc_codegen_ssa::mir::blockは、ブロックとその terminator の変換を扱います。このモジュールが行う最も複雑で、かつ最も興味深い処理は、関数呼び出しのコードを生成することであり、必要な unwinding 処理 IR も含まれます。rustc_codegen_ssa::mir::statementは MIR statement を変換します。rustc_codegen_ssa::mir::operandは MIR operand を変換します。rustc_codegen_ssa::mir::placeは MIR place 参照を変換します。rustc_codegen_ssa::mir::rvalueは MIR r-value を変換します。
関数が変換される前に、より単純で効率的な LLVM IR を生成しやすくするため、多数の単純でプリミティブな解析 pass が実行されます。そのような解析 pass の例として、どの変数が SSA に類似しているかを特定し、それらの変数については LLVM の mem2reg に頼るのではなく、直接 SSA に変換できるようにするものがあります。この解析は
rustc_codegen_ssa::mir::analyze にあります。
通常、単一の MIR basic block は LLVM basic block に対応しますが、ごく少数の例外があります。intrinsic や関数呼び出し、および assert のようなより基本的でない MIR statement は、複数の basic block を生じさせることがあります。これは、コード生成における移植性のない LLVM 固有部分への格好の導入になります。Intrinsic 生成は、間にある抽象化レベルが非常に少ないため比較的理解しやすく、rustc_codegen_llvm::intrinsic にあります。
それ以外のすべては builder interface を使用します。これは、上で説明した rustc_codegen_ssa::mir::* モジュール内で呼び出されるコードです。
TODO: 定数がどのように生成されるかを議論する