O0 とデバッグ

計算、定数式、記憶領域、デバッグ対応情報を保存するルールです。

Wave Foundation

保存モデル

O0はデバッグのためにオリジナルtypedIRの計算・変数・制御フローを保存します。未使用の結果と構造的に到達不能なブロックも維持します。検証は誤った IR を診断し、ブロックの削除や操作を簡素化しません。

機械語を生成するために必要な変換は、別々のサブIRで行われます。変換後もオリジナルIDとの対応を維持しなければなりません。 typed IR 保存がすべて IR 演算と機械命令の一対一対応を意味するわけではありません。

O0で行わない変換

変換 O0動作
インライニング 呼び出しと関数の境界を維持
Tail-call変換 一般呼び出し・返還構造を維持
死んだコードを削除 未使用の計算と到達不能なブロックを維持
ランタイム定数の折りたたみ 元の操作を維持
共通計算を合わせる 別々の計算を維持
ローカル変数ストレージスペースの再利用 各ストレージスペースを維持
フレームポインタを省略 フレームポインタを保持
文字列の自動マージ 別個の文字列オブジェクトを保持

たとえば、2 つの定数を加算するランタイム演算は、結果を使用しなくても加算として残ります。条件が定数の分岐も元の制御フロー構造を維持します。

コンパイル時定数

コンパイル時定数宣言は、typed初期化式と評価結果を一緒に保存します。これは、通常のランタイムコマンドの定数折りたたみとは異なります。

初期化式が1 + 2の宣言には加算式と結果3が一緒に残ります。この例は式の意味を説明し、特定のソース言語の宣言文法ではありません。結果は静的データを構成するときに使用でき、初期化式をランタイム加算に置き換えることはありません。

未使用・到達不可能な宣言も識別できなければなりません。同じ名前の宣言がお互いを隠しても、名前・宣言ID・参照に区分されなければなりません。検証は、誤った参照、依存性循環、誤った型、元の式と一致しない保存結果を拒否します。

到達不可能なソース文

return・break・continue 後の文章も連結されていないブロックに残ります。この文のため、前のterminatorを変更したり、新しい実行パスを作成したりしないでください。到達不可能な文章内の誤った式も診断します。

この保存規則により、元のプログラム構造を調べることができます。 terminator 後の文が実際に実行されるという意味ではありません。

保存されるIRの例

以下は、バリデータを通過したモジュールの現在のプリンタ出力です。未使用の計算、コンパイル時の宣言、リンクされていないブロックが一緒に表示されます。

module {
  format_version 2
  semantics_version 1
  target "x86_64-whale-linux"
  datalayout { ptr=64, endian=little }

  declare @f0 "preserved": whale () -> void, linkage internal

  fn @preserved() -> void, id @f0 {
  entry:
    %v0: i32 = const i32 1
    %v1: i32 = const i32 2
    %v2: i32 = add i32 %v0, %v1
    %v3: i32 = const_decl "count" add(i32 1, i32 2) => const i32 3
    ret void
  unreachable.cont:
    %v4: i32 = const i32 4
    %v5: i32 = const i32 5
    %v6: i32 = add i32 %v4, %v5
    ret void
  }

}

%v2は使用先がなくてもaddのままです。 %v3は別個のconst_declであり、add(i32 1, i32 2)式と評価結果3を一緒に保存します。 unreachable.contには入ってくる幹線がないので、ret voidの後に実行パスを追加せずに%v6加算を確認できます。

検証はこのコマンドとブロックを保存します。この例は、IR構成、検証、出力を示しており、native実行またはDWARF出力が提供されるという意味ではありません。

ソースとスタック情報

デバッグインタフェースは、DWARF5の関数情報、ソース行、デフォルトのローカル変数、呼び出しフレーム情報を使用します。下位表現に変換しても、関数・地域変数情報と元のIR識別子の対応を維持しなければなりません。

AMD64プロファイルはフレームポインタを保持し、redzoneを使用しません。呼び出しフレーム情報はスタック調査に使用され、例外unwindingサポートを意味しません。 trapはデストラクタやunwindingを保証せずに実行を終了します。

DWARF出力とnative実行の提供可否はツールチェーンの概要を参照してください。 O1以上最適化の動作は、このO0参照の範囲外です。