Files
hakorune/docs/private/papers/paper-e-loop-signal-ir/claude_output.md

8.4 KiB
Raw Blame History

LoopSignal IR: Box×Loopによる制御統一と最小MIR設計

1. 背景と問題

NyashのMIRMiddle Intermediate Representationは現在、制御フロー命令が分散している

  • if/while/forがそれぞれ独立した命令
  • return/break/continueが個別の特殊形式
  • ジェネレータ/async/await の統一的表現がない
  • Box哲学Everything is BoxとLoop哲学Everything is Loopが未統合

問題点

  1. 最適化パスが各制御構造を個別に扱う必要がある
  2. 新しい制御構造generator/asyncの追加が困難
  3. LLVM IRへの変換が複雑各構文ごとの特殊ケース
  4. デバッグ情報DWARFの一貫性が保ちにくい

2. 目標

ユースケースを統一的に扱える最小MIR設計

  • scope - RAII/デストラクタ呼び出し
  • if/while/for - 条件分岐とループ
  • function/return - 関数呼び出しと戻り値
  • generator/yield - 中断可能な計算
  • async/await - 非同期計算(将来)

設計原則

  • Everything is Box × Everything is Loop の融合
  • 最小命令セット4命令ですべての制御を表現
  • LLVM IRへの直接的なマッピング
  • 段階的導入可能既存MIRとの共存

3. 設計

3.1 型: LoopSignal

// LoopSignal = 制御フロー + 値の統一表現
enum LoopSignal<T> {
    Next(T),     // 継続(次のイテレーション)
    Break(T),    // 脱出(ループ終了)
    Yield(T),    // 中断(ジェネレータ)
    Return(T),   // 復帰(関数終了)- オプション
}

// LLVM表現: { i8 tag, iN value }
// tag: 0=Next, 1=Break, 2=Yield, 3=Return

3.2 MIR命令

loop.begin <label> <init_block>
  ; 前提条件: スタックトップにLoopBox
  ; 事後条件: ループコンテキスト確立、init実行
  
loop.iter <label> <step_block>
  ; 前提条件: ループコンテキスト存在
  ; 事後条件: Signal生成、スタックにpush
  
loop.branch <label> <next_block> <break_block> [<yield_block>]
  ; 前提条件: スタックトップにSignal
  ; 事後条件: Signalに応じて分岐
  ; 未定義動作: 想定外のSignalタグ
  
loop.end <label> <fini_block>
  ; 前提条件: ループコンテキスト存在
  ; 事後条件: fini実行、コンテキスト破棄

3.3 Box=Loop1init/step/fini

// すべてのBoxは1回ループLoop1として表現可能
trait LoopBox {
    fn init(&mut self);           // 初期化
    fn step(&mut self) -> Signal; // 実行1回でBreak
    fn fini(&mut self);           // 終了処理
}

// RAII対応: finiでデストラクタ呼び出し

3.4 Lowering規則

scopeRAII:

scope { body } →
  loop.begin L init=nop
  loop.iter L step=body;Break
  loop.branch L next=unreachable break=done
  loop.end L fini=cleanup

while:

while(cond) { body } →
  loop.begin L init=nop
  loop.iter L step=if(cond,Next,Break)
  loop.branch L next=body_then_loop break=done
  loop.end L fini=nop

for-in:

for x in iter { body } →
  loop.begin L init=iter.init
  loop.iter L step=iter.next
  loop.branch L next=bind(x);body break=done
  loop.end L fini=iter.fini

return:

return value →
  Signal::Return(value)
  ; 関数全体がLoopBoxなので、Returnで脱出

yield:

yield value →
  Signal::Yield(value)
  ; ジェネレータのloop.branchがyield_blockを持つ

4. 例

while(true){break} の最小例

Before現在のMIR:

while_begin:
  push true
  branch_if_false while_end
  jump while_break  ; break
while_end:

AfterLoopSignal IR:

loop.begin L1 init=nop
loop.iter L1 step=push(Break(unit))
loop.branch L1 next=unreachable break=done
loop.end L1 fini=nop
done:

for-inのLoopBox化

for x in [1,2,3] { print(x) } →

loop.begin L1 init={
  iter = ArrayIterBox([1,2,3])
  iter.init()
}
loop.iter L1 step={
  signal = iter.step()  ; Next(1), Next(2), Next(3), Break
}
loop.branch L1 
  next={ x = signal.value; print(x) }
  break=done
loop.end L1 fini={
  iter.fini()  ; イテレータのクリーンアップ
}

scope=Loop1の畳み込み

{ let x = File("data"); x.read() } →

loop.begin L1 init={ x = File("data") }
loop.iter L1 step={ x.read(); Break }
loop.branch L1 next=unreachable break=next
loop.end L1 fini={ x.close() }  ; RAII

5. 図Mermaid

合流点を1箇所に集約したdispatch CFG

graph TD
    Start[loop.begin] --> Init[init block]
    Init --> Iter[loop.iter]
    Iter --> Step[step block]
    Step --> Signal{loop.branch}
    
    Signal -->|Next| Body[next block]
    Body --> Iter
    
    Signal -->|Break| End[loop.end]
    Signal -->|Yield| Yield[yield block]
    Yield -.->|resume| Iter
    
    End --> Fini[fini block]
    Fini --> Done[done]
    
    style Signal fill:#f9f,stroke:#333,stroke-width:4px

Signalタグに基づくswitch分岐の構造

graph LR
    Stack[Signal on Stack] --> Extract[Extract tag]
    Extract --> Switch{switch tag}
    
    Switch -->|0: Next| NextBB[next_block]
    Switch -->|1: Break| BreakBB[break_block]
    Switch -->|2: Yield| YieldBB[yield_block]
    Switch -->|3: Return| ReturnBB[return_block]
    Switch -->|default| Trap[unreachable/trap]
    
    style Switch fill:#ff9,stroke:#333,stroke-width:2px

6. 最適化と安全性

Loop1インライン化

  • 1回だけ実行されるループは完全にインライン化可能
  • loop.begin → step → loop.end を直接実行に変換

状態省略

  • ステートレスなLoopBoxはinit/finiを省略
  • LLVMのmem2regで自動的に最適化

DCE/LICM/Inline適用条件

  • DCEDead Code Elimination: unreachableなnext blockを削除
  • LICMLoop Invariant Code Motion: LoopBox内の不変式を外に移動
  • Inline: 小さなstep関数は自動インライン化

DWARF対策

  • 各loop命令に元のソース位置情報を保持
  • デバッガは論理的な制御構造として表示

7. 段階導入計画

Phase 1P1: 基礎実装

  • LoopSignal型とMIR命令の定義
  • while/forのLowering実装
  • 既存MIRとの共存層

Phase 2P2: 最適化と拡張

  • Loop1インライン化
  • generator/yieldサポート
  • LLVM IRコード生成

Phase 3P3: 完全移行

  • すべての制御構造をLoopSignal IRに
  • 旧MIRの廃止
  • async/awaitの統合

フォールバック旧MIRへの逆Lowering

loop.begin/end → nop
loop.iter → 直接実行
loop.branch → if/jump の組み合わせ

8. 関連研究と差分

アプローチ Nyash LoopSignal IR 差分
CPS変換 Signal = 限定的継続 明示的なSignal型で制御
代数的効果 Loop = エフェクトハンドラ Boxベースの具象化
ジェネレータ Yield = 中断可能Loop 統一的なSignal処理
SSA系IR phi関数の代わりにSignal 制御と値の統合

9. 成果物とKPI

メトリクス

  • MIR命令数: 30+ → 4命令
  • 制御構造の正規化率: 100%
  • LLVM IR生成コード: 50%削減
  • 最適化パス実装: 80%共通化

テスト観点

  1. 意味保存: 各Lowering前後で同じ動作
  2. 性能: Loop1は最適化後オーバーヘッドゼロ
  3. デバッグ: ソースレベルデバッグ可能
  4. 互換性: 段階的移行中も動作保証

付録

用語対比

  • Box = 空間的抽象(データ構造)
  • Loop = 時間的抽象(制御フロー)
  • LoopBox = 時空間統一オブジェクト

命令一覧

loop.begin <label> <init>   ; ループ開始
loop.iter <label> <step>    ; イテレーション
loop.branch <label> <blocks> ; 分岐
loop.end <label> <fini>     ; ループ終了

タグ割当

0: Next    ; 継続
1: Break   ; 脱出
2: Yield   ; 中断
3: Return  ; 復帰
4-255: 予約 ; 将来拡張

疑似コード集

; LoopSignal in LLVM
%signal = { i8, i64 }  ; tag + value
%tag = extractvalue %signal, 0
switch i8 %tag, label %trap [
  i8 0, label %next
  i8 1, label %break
  i8 2, label %yield
]

このRFCは、NyashのBox哲学とLoop哲学を統合し、最小限のMIR命令セットですべての制御構造を表現する設計を提案します。段階的導入により、既存システムを破壊することなく、より単純で強力なIRへの移行を可能にします。