コンテンツにスキップ

Cerune IR(HIR)

**Cerune IR(HIR)**は、構文解析・意味検証・型解決の後に作られる、バックエンドに依存しない中間表現です。ソースコードの意味を確定した状態で保持し、複数の実行経路とコード生成経路の入力になります。

Ceruneソース
↓ Lexer / Parser
AST
↓ 意味解析・名前解決・型解決・共通展開
Cerune IR (HIR)
├─ IR Executor → run / run-ir
├─ MIR変換・検証 → run-mir / SSA / Native LIR → ASM・Object
├─ Bytecode → run-vm
└─ C / LLVM / QBE / WAT向けの内部表現 → emit-*

各バックエンドが個別に言語の意味を決め直すのではなく、フロントエンドで解決した情報を使って対象の表現に変換します。Nativeの生成はMIR経由ですが、C・LLVM・QBE・WATなどはHIRからそれぞれの経路へ変換します。

情報 HIRでの扱い
式の型 i64、f32、string、配列や名前付き型などの具体的な型に解決済み
型推論 inferは解決済みで、実行時の動的型として残らない
名前の参照 束縛を識別するIDで区別し、同名のシャドーイングも区別
数値変換 変換元・変換先の型を保持し、明示変換であることを区別
制御構文 if、while、for、break、continueを構造として保持
出自 文・式のNodeIdと、ソース位置を示すSpanを保持

例えば、value: infer = 42;のinferはHIRを作る前に具体的な型へ解決されます。バックエンドが独自に再推論する必要はありません。

HIRはSSA形式ではありません。 制御フローの基本ブロックや明示的な一時値、Native固有のABI・格納位置などは、後続のMIR・LIRやバックエンドの段階で扱います。

HIRの文と式には、同じコンパイル内で一意なNodeIdを割り当てます。emit-irでは#0、#1のように表示されます。

NodeIdはどのHIR要素かを示し、Spanは元ソースのどの範囲かを示します。SpanはUTF-8のバイト位置で、開始位置を含み終了位置を含みません。同じ範囲に対応する複数の要素でも、別のNodeIdを持てます。

これらのIDは編集をまたいで永続するものではありません。同じ入力とコンパイラ版の、同じコンパイル結果の中で対応を調べるために使います。

後続のMIRや生成命令は、元のHIR要素とソース範囲への対応情報を保持できます。生成した命令がソースに直接対応しない場合は、コンパイラ生成であることを区別します。

Ceruneリポジトリのルートで、次のコマンドを実行します。

ターミナルウィンドウ
cerune emit-ir examples/ir_execution.ceru
cerune emit-ir examples/ir_stages/control_flow.ceru -o control_flow.ceir

emit-irは型や参照を解決したHIRの観測テキストを出力します。省略時は標準出力へ表示され、-oでファイルに保存できます。

ただし、保存した.ceirを読み込んで実行するCLIではありません。ソースを読み込んでHIRを構築する処理と、観測テキストの出力を区別してください。

ターミナルウィンドウ
cerune run examples/ir_execution.ceru
cerune run-ir examples/ir_execution.ceru
cerune run-vm examples/ir_execution.ceru

runとrun-irは、構築済みHIRの文・式をIR Executorで直接実行します。Bytecodeへの変換も、VMへの実行委譲も行いません。run-vmはBytecodeへ変換してVMで実行する別経路です。

IR Executorは構造化された分岐・ループをそのまま実行し、式の評価順、短絡評価、配列の値コピー、停止条件などについて共通の言語規則に従います。

実行結果の比較はできますが、emit-irは実行履歴を記録するコマンドではありません。

ターミナルウィンドウ
cerune emit-ir examples/ir_stages/control_flow.ceru
cerune emit-mir examples/ir_stages/control_flow.ceru
cerune run-mir examples/ir_stages/control_flow.ceru

MIRでは基本ブロックや分岐を明示し、操作ごとのhir=#Nなどから元のHIR要素へ戻れます。生成ASMとの対応を同じコンパイルで保存したい場合はobserveを使います。

ターミナルウィンドウ
cerune observe examples/ir_stages/control_flow.ceru --target x86_64-unknown-linux-gnu -o target/control-flow-observation

observeは--targetとまだ存在しない出力ディレクトリを指定する-oが必要です。親ディレクトリは事前に作成してください。観測結果にはソース本文も含まれますが、プログラムの実行やリンクは行いません。

変換後の表現についてはMIRを参照してください。

  • HIRは機械語や汎用マシンIRの代わりではなく、Ceruneの意味を表現するための中間表現です。
  • HIRの意味上の整数型と、バックエンドで選ぶ物理的な格納幅を混同しないでください。
  • 内部のRustバックエンドIRは、安定した公開シリアライズ形式ではありません。
  • 最適化は暗黙の変換として追加するのではなく、明示的に選択・観測できる段階として設計されています。

仕様・実装の詳細は次を参照してください。