# バイトコード拡張案の分析: 5x32 vs 64bit vs 現状維持 ## 概要 ユーザーからの技術的異議を受けて、3つのアプローチを比較検討します: 1. **現状維持 (4x32)**: `[op, v, a, s]` - 4整数 x 32ビット 2. **5x32拡張**: `[op, v, s, a_low, a_high]` - 5整数 x 32ビット 3. **64bit拡張**: `[op, v, a64, s]` - aのみ64ビット --- ## 1. ユーザーの懸念点 (正当性の評価) ### 1.1 `v` への Color Filter 移動の問題 | 懸念 | 評価 | 理由 | |-----|------|------| | Card ID > 65535 での破損 | ✅ **正当** | プロモカード等で ID が 70050+ になる可能性あり | | AI学習の複雑化 | ✅ **正当** | 「opcode が X の場合は v から色を探す」という条件分岐は NN に負担 | ### 1.2 Assembly-Style Unrolling の問題 | 懸念 | 評価 | 理由 | |-----|------|------| | MCTS深度爆発 | ✅ **正当** | 1効果 = 3-4ステップ は状態空間を不必要に拡大 | | 部分状態の探索 | ✅ **正当** | 「フィルタ済みだが選択未完了」の中間状態が増加 | ### 1.3 拡張性の欠如 | 懸念 | 評価 | 理由 | |-----|------|------| | 将来のメカニクス対応 | ✅ **正当** | 学年フィルタ、ブレードサイズ等の新規フィルタで即座に限界 | --- ## 2. パフォーマンス影響の分析 ### 2.1 Rust での影響 #### 現状 (4x32) ```rust // bytecode: Vec for chunk in bytecode.chunks(4) { let (op, v, a, s) = (chunk[0], chunk[1], chunk[2], chunk[3]); // 処理 } ``` #### 5x32拡張 ```rust // bytecode: Vec for chunk in bytecode.chunks(5) { let (op, v, s, a_low, a_high) = (chunk[0], chunk[1], chunk[2], chunk[3], chunk[4]); let a = ((a_high as u64) << 32) | (a_low as u64); // 処理 } ``` **影響**: - メモリ: **+25%** 増加 - キャッシュミス率: 若干増加 (1命令あたり 20bytes → 25bytes) - CPUサイクル: ほぼ変わらず (ビットシフトは高速) #### 64bit拡張 ```rust // bytecode: Vec または混合型 for chunk in bytecode.chunks(4) { let (op, v, a, s) = (chunk[0] as i32, chunk[1] as i32, chunk[2], chunk[3] as i32); // a は i64 } ``` **影響**: - メモリ: **+25%** 増加 (4x32=128bit → 2x32+1x64+1x32=160bit) - キャッシュミス率: 若干増加 - CPUサイクル: ほぼ変わらず (64bit演算は現代CPUで高速) ### 2.2 WGSL (GPU) での影響 #### 現状 (4x32) ```wgsl @group(0) @binding(2) var bytecode: array; fn get_instruction(ip: u32) -> vec4 { return vec4( bytecode[ip], bytecode[ip + 1u], bytecode[ip + 2u], bytecode[ip + 3u] ); } ``` #### 5x32拡張 ```wgsl @group(0) @binding(2) var bytecode: array; fn get_instruction(ip: u32) -> vec5 { // vec5 は存在しない! // WGSL には vec5 がないため、個別にロードが必要 let op = bytecode[ip]; let v = bytecode[ip + 1u]; let s = bytecode[ip + 2u]; let a_lo = bytecode[ip + 3u]; let a_hi = bytecode[ip + 4u]; let a = (u32(a_lo) | (u32(a_hi) << 32u)); // u64 として結合 // ... } ``` **影響**: - **重大**: WGSL に `vec5` が存在しないため、個別ロードが必要 - メモリアクセス: 5回/命令 (現状は4回) - レジスタ圧力: 若干増加 #### 64bit拡張 ```wgsl @group(0) @binding(2) var bytecode: array; // または混合 fn get_instruction(ip: u32) -> vec4 { // 一部が i64 // WGSL は型統一が必要 return vec4( bytecode[ip], bytecode[ip + 1u], bytecode[ip + 2u], bytecode[ip + 3u] ); } ``` **影響**: - WGSL は `array` をサポート - ただし、`op`, `v`, `s` も 64bit になるためメモリ無駄 - 混合型は WGSL で複雑化 --- ## 3. 推奨アプローチ: 5x32 拡張 ### 3.1 理由 | 基準 | 4x32 (現状) | 5x32 | 64bit | |-----|-------------|------|-------| | メモリ効率 | ✅ 最良 | 🟡 +25% | 🟡 +25% | | WGSL互換性 | ✅ 最良 | 🟡 個別ロード必要 | 🟡 型統一必要 | | 拡張性 | ❌ 不十分 | ✅ 64bit属性 | ✅ 64bit属性 | | AI学習 | ❌ 複雑な条件 | ✅ クリーン | ✅ クリーン | | 実装コスト | - | 🟡 中程度 | 🔴 高い | ### 3.2 新しいレイアウト (5x32) ``` [op, v, s, a_low, a_high] op (i32): Opcode v (i32): Value/Count (16bit) + Color Mask (6bit) + Flags (10bit) s (i32): Slot/Zone (24bit) + Flags (8bit) a (i64): Attribute Filter (64bit完全使用可能) ``` ### 3.3 64bit `a` ワードの新しいレイアウト ``` ┌─────────────────────────────────────────────────────────────────┐ │ Bit 0 : IS_OPTIONAL │ │ Bit 1 : DYNAMIC_VALUE │ │ Bits 2-3 : Card Type (0=Any, 1=Member, 2=Live) │ │ Bits 4-7 : Group ID (4 bits = 16 groups) │ │ Bits 8-12 : Unit ID (5 bits = 32 units) │ │ Bits 13-17 : Cost Threshold (5 bits = 0-31) │ │ Bit 18 : Cost Mode (0=GE, 1=LE) │ │ Bit 19 : Tapped Filter │ │ Bit 20 : Has Blade Heart │ │ Bit 21 : Not Has Blade Heart │ │ Bits 22-28 : Color Mask (7 bits = 7 colors) │ │ Bits 29-35 : Character ID 1 (7 bits = 128 chars) │ │ Bits 36-42 : Character ID 2 (7 bits) │ │ Bits 43-49 : Character ID 3 (7 bits) │ │ Bits 50-56 : Special Filter ID (7 bits) │ │ Bits 57-63 : Reserved for future use │ └─────────────────────────────────────────────────────────────────┘ ``` **改善点**: - Color Mask が `a` 内に配置 (v から分離) - Character ID が 64bit 内に収まる (切り捨て問題解決) - 将来の拡張用に 7ビット予備 --- ## 4. 実装ステップ ### Phase 1: Rust インタープリタの更新 1. **バイトコードストレージの変更** ```rust // Before pub bytecode: Vec // After pub bytecode: Vec // 5要素ごとに1命令 ``` 2. **チャンク処理の変更** ```rust // Before for chunk in bytecode.chunks(4) { ... } // After for chunk in bytecode.chunks(5) { let op = chunk[0]; let v = chunk[1]; let s = chunk[2]; let a = if chunk.len() >= 5 { ((chunk[4] as u64) << 32) | (chunk[3] as u64) } else { 0 }; // ... } ``` ### Phase 2: Python コンパイラの更新 1. **`compile()` メソッドの変更** ```python def compile(self) -> List[int]: bytecode = [] # ... 既存のロジック ... # 各命令に a_high を追加 for i in range(0, len(bytecode), 4): a = bytecode[i+2] a_low = a & 0xFFFFFFFF a_high = (a >> 32) & 0xFFFFFFFF bytecode[i+2] = a_low bytecode.insert(i+3, a_high) return bytecode ``` ### Phase 3: WGSL シェーダーの更新 1. **命令読み込みの変更** ```wgsl fn get_instruction(ip: u32) -> (i32, i32, i32, u64) { let op = bytecode[ip]; let v = bytecode[ip + 1u]; let s = bytecode[ip + 2u]; let a_lo = bytecode[ip + 3u]; let a_hi = bytecode[ip + 4u]; let a = (u32(a_lo) | (u32(a_hi) << 32u)); return (op, v, s, a); } ``` --- ## 5. パフォーマンス予測 ### 5.1 メモリ使用量 | 項目 | 現状 (4x32) | 5x32 | 増加率 | |-----|-------------|------|-------| | 1命令あたり | 16 bytes | 20 bytes | +25% | | 全カードのバイトコード | ~1.5 MB | ~1.9 MB | +25% | | GPU VRAM | ~2 MB | ~2.5 MB | +25% | ### 5.2 実行速度 | 環境 | 予測影響 | |-----|---------| | Rust (CPU) | < 1% 遅延 (メモリ帯域幅依存) | | WGSL (GPU) | 1-3% 遅延 (メモリアクセス増加) | | AI訓練 | **改善** (状態空間の削減) | ### 5.3 AI訓練への影響 | 側面 | 影響 | |-----|------| | 状態空間 | **削減** (Unrolling回避) | | MCTS深度 | **削減** (1効果 = 1ステップ) | | NN入力エンコーディング | **簡素化** (レジスタ意味が明確) | --- ## 6. 結論 **推奨**: 5x32 拡張アプローチ **理由**: 1. 64bit 属性フィルタで全ての情報を1命令に収容 2. AI訓練にとって最適 (状態空間削減) 3. 実装コストが中程度 4. 将来の拡張性を確保 **次のステップ**: 1. ユーザーの承認 2. Codeモードでの実装開始