chore: Phase 25.1 完了 - LoopForm v2/Stage1 CLI/環境変数削減 + Phase 26-D からの変更

Phase 25.1 完了成果:
-  LoopForm v2 テスト・ドキュメント・コメント完備
  - 4ケース(A/B/C/D)完全テストカバレッジ
  - 最小再現ケース作成(SSAバグ調査用)
  - SSOT文書作成(loopform_ssot.md)
  - 全ソースに [LoopForm] コメントタグ追加

-  Stage-1 CLI デバッグ環境構築
  - stage1_cli.hako 実装
  - stage1_bridge.rs ブリッジ実装
  - デバッグツール作成(stage1_debug.sh/stage1_minimal.sh)
  - アーキテクチャ改善提案文書

-  環境変数削減計画策定
  - 25変数の完全調査・分類
  - 6段階削減ロードマップ(25→5、80%削減)
  - 即時削除可能変数特定(NYASH_CONFIG/NYASH_DEBUG)

Phase 26-D からの累積変更:
- PHI実装改善(ExitPhiBuilder/HeaderPhiBuilder等)
- MIRビルダーリファクタリング
- 型伝播・最適化パス改善
- その他約300ファイルの累積変更

🎯 技術的成果:
- SSAバグ根本原因特定(条件分岐内loop変数変更)
- Region+next_iパターン適用完了(UsingCollectorBox等)
- LoopFormパターン文書化・テスト化完了
- セルフホスティング基盤強化

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: ChatGPT <noreply@openai.com>
Co-Authored-By: Task Assistant <task@anthropic.com>
This commit is contained in:
nyash-codex
2025-11-21 06:25:17 +09:00
parent baf028a94f
commit f9d100ce01
366 changed files with 14322 additions and 5236 deletions

View File

@ -1,9 +1,9 @@
use super::mir_json::common as mirjson_common;
use crate::mir::{
function::{FunctionSignature, MirFunction, MirModule},
BasicBlock, BasicBlockId, ConstValue, EffectMask, MirInstruction, MirType, ValueId,
};
use serde_json::Value;
use super::mir_json::common as mirjson_common;
/// Parse minimal MIR JSON v0 (no schema_version, root has `functions` and each function has `blocks`).
/// Supported ops (minimal): const(i64), copy, compare(op/lhs/rhs), branch(cond/then/else), jump(target), phi(dst,incoming), ret(value?).
@ -36,7 +36,8 @@ pub fn parse_mir_v0_to_module(json: &str) -> Result<MirModule, String> {
.get(0)
.and_then(|b| b.get("id"))
.and_then(|id| id.as_u64())
.ok_or_else(|| format!("function '{}' entry block missing id", func_name))? as u32;
.ok_or_else(|| format!("function '{}' entry block missing id", func_name))?
as u32;
let entry_bb = BasicBlockId::new(entry_id);
let mut signature = FunctionSignature {
@ -52,7 +53,8 @@ pub fn parse_mir_v0_to_module(json: &str) -> Result<MirModule, String> {
let block_id = block
.get("id")
.and_then(|id| id.as_u64())
.ok_or_else(|| format!("function '{}' block missing id", func_name))? as u32;
.ok_or_else(|| format!("function '{}' block missing id", func_name))?
as u32;
let bb_id = BasicBlockId::new(block_id);
if mir_fn.get_block(bb_id).is_none() {
mir_fn.add_block(BasicBlock::new(bb_id));
@ -64,95 +66,185 @@ pub fn parse_mir_v0_to_module(json: &str) -> Result<MirModule, String> {
let instructions = block
.get("instructions")
.and_then(|insts| insts.as_array())
.ok_or_else(|| format!("function '{}' block {} missing instructions array", func_name, block_id))?;
.ok_or_else(|| {
format!(
"function '{}' block {} missing instructions array",
func_name, block_id
)
})?;
for inst in instructions {
let op = inst
.get("op")
.and_then(|o| o.as_str())
.ok_or_else(|| format!("function '{}' block {} missing op field", func_name, block_id))?;
let op = inst.get("op").and_then(|o| o.as_str()).ok_or_else(|| {
format!(
"function '{}' block {} missing op field",
func_name, block_id
)
})?;
match op {
"const" => {
let dst = require_u64(inst, "dst", "const dst")? as u32;
let vobj = inst.get("value").ok_or_else(|| "const missing value".to_string())?;
let vobj = inst
.get("value")
.ok_or_else(|| "const missing value".to_string())?;
let val = parse_const_value(vobj)?;
block_ref.add_instruction(MirInstruction::Const { dst: ValueId::new(dst), value: val });
block_ref.add_instruction(MirInstruction::Const {
dst: ValueId::new(dst),
value: val,
});
max_value_id = max_value_id.max(dst + 1);
}
"copy" => {
let dst = require_u64(inst, "dst", "copy dst")? as u32;
let src = require_u64(inst, "src", "copy src")? as u32;
block_ref.add_instruction(MirInstruction::Copy { dst: ValueId::new(dst), src: ValueId::new(src) });
block_ref.add_instruction(MirInstruction::Copy {
dst: ValueId::new(dst),
src: ValueId::new(src),
});
max_value_id = max_value_id.max(dst + 1);
}
"binop" => {
let dst = require_u64(inst, "dst", "binop dst")? as u32;
let lhs = require_u64(inst, "lhs", "binop lhs")? as u32;
let rhs = require_u64(inst, "rhs", "binop rhs")? as u32;
let operation = inst.get("operation").and_then(Value::as_str).ok_or_else(|| "binop missing operation".to_string())?;
let operation = inst
.get("operation")
.and_then(Value::as_str)
.ok_or_else(|| "binop missing operation".to_string())?;
let bop = parse_binop(operation)?;
block_ref.add_instruction(MirInstruction::BinOp { dst: ValueId::new(dst), op: bop, lhs: ValueId::new(lhs), rhs: ValueId::new(rhs) });
block_ref.add_instruction(MirInstruction::BinOp {
dst: ValueId::new(dst),
op: bop,
lhs: ValueId::new(lhs),
rhs: ValueId::new(rhs),
});
max_value_id = max_value_id.max(dst + 1);
}
"compare" => {
let dst = require_u64(inst, "dst", "compare dst")? as u32;
let lhs = require_u64(inst, "lhs", "compare lhs")? as u32;
let rhs = require_u64(inst, "rhs", "compare rhs")? as u32;
let operation = inst.get("operation").and_then(Value::as_str).unwrap_or("==");
let operation = inst
.get("operation")
.and_then(Value::as_str)
.unwrap_or("==");
let cop = parse_compare(operation)?;
block_ref.add_instruction(MirInstruction::Compare { dst: ValueId::new(dst), op: cop, lhs: ValueId::new(lhs), rhs: ValueId::new(rhs) });
block_ref.add_instruction(MirInstruction::Compare {
dst: ValueId::new(dst),
op: cop,
lhs: ValueId::new(lhs),
rhs: ValueId::new(rhs),
});
max_value_id = max_value_id.max(dst + 1);
}
"branch" => {
let cond = require_u64(inst, "cond", "branch cond")? as u32;
let then_bb = require_u64(inst, "then", "branch then")? as u32;
let else_bb = require_u64(inst, "else", "branch else")? as u32;
block_ref.add_instruction(MirInstruction::Branch { condition: ValueId::new(cond), then_bb: BasicBlockId::new(then_bb), else_bb: BasicBlockId::new(else_bb) });
block_ref.add_instruction(MirInstruction::Branch {
condition: ValueId::new(cond),
then_bb: BasicBlockId::new(then_bb),
else_bb: BasicBlockId::new(else_bb),
});
}
"jump" => {
let target = require_u64(inst, "target", "jump target")? as u32;
block_ref.add_instruction(MirInstruction::Jump { target: BasicBlockId::new(target) });
block_ref.add_instruction(MirInstruction::Jump {
target: BasicBlockId::new(target),
});
}
"phi" => {
let dst = require_u64(inst, "dst", "phi dst")? as u32;
let incoming = inst.get("incoming").and_then(Value::as_array).ok_or_else(|| "phi incoming missing".to_string())?;
let incoming = inst
.get("incoming")
.and_then(Value::as_array)
.ok_or_else(|| "phi incoming missing".to_string())?;
let mut pairs = Vec::with_capacity(incoming.len());
for entry in incoming {
let pair = entry.as_array().ok_or_else(|| "phi incoming entry must be array".to_string())?;
if pair.len() != 2 { return Err("phi incoming entry must have 2 elements".into()); }
let val = pair[0].as_u64().ok_or_else(|| "phi incoming value must be integer".to_string())? as u32;
let bb = pair[1].as_u64().ok_or_else(|| "phi incoming block must be integer".to_string())? as u32;
let pair = entry
.as_array()
.ok_or_else(|| "phi incoming entry must be array".to_string())?;
if pair.len() != 2 {
return Err("phi incoming entry must have 2 elements".into());
}
let val = pair[0]
.as_u64()
.ok_or_else(|| "phi incoming value must be integer".to_string())?
as u32;
let bb = pair[1]
.as_u64()
.ok_or_else(|| "phi incoming block must be integer".to_string())?
as u32;
pairs.push((BasicBlockId::new(bb), ValueId::new(val)));
}
block_ref.add_instruction(MirInstruction::Phi { dst: ValueId::new(dst), inputs: pairs });
block_ref.add_instruction(MirInstruction::Phi {
dst: ValueId::new(dst),
inputs: pairs,
});
max_value_id = max_value_id.max(dst + 1);
}
"ret" => {
let value = inst.get("value").and_then(|v| v.as_u64()).map(|v| ValueId::new(v as u32));
let value = inst
.get("value")
.and_then(|v| v.as_u64())
.map(|v| ValueId::new(v as u32));
block_ref.add_instruction(MirInstruction::Return { value });
if let Some(val) = value { signature.return_type = MirType::Integer; max_value_id = max_value_id.max(val.as_u32() + 1); } else { signature.return_type = MirType::Void; }
if let Some(val) = value {
signature.return_type = MirType::Integer;
max_value_id = max_value_id.max(val.as_u32() + 1);
} else {
signature.return_type = MirType::Void;
}
}
"newbox" => {
let dst = require_u64(inst, "dst", "newbox dst")? as u32;
let ty = inst.get("type").and_then(Value::as_str).ok_or_else(|| "newbox missing type".to_string())?.to_string();
let args_v = inst.get("args").and_then(Value::as_array).cloned().unwrap_or_default();
let ty = inst
.get("type")
.and_then(Value::as_str)
.ok_or_else(|| "newbox missing type".to_string())?
.to_string();
let args_v = inst
.get("args")
.and_then(Value::as_array)
.cloned()
.unwrap_or_default();
let mut args: Vec<ValueId> = Vec::with_capacity(args_v.len());
for a in args_v {
let id = a.as_u64().ok_or_else(|| "newbox arg must be integer".to_string())? as u32;
let id = a
.as_u64()
.ok_or_else(|| "newbox arg must be integer".to_string())?
as u32;
args.push(ValueId::new(id));
}
block_ref.add_instruction(MirInstruction::NewBox { dst: ValueId::new(dst), box_type: ty, args });
block_ref.add_instruction(MirInstruction::NewBox {
dst: ValueId::new(dst),
box_type: ty,
args,
});
max_value_id = max_value_id.max(dst + 1);
}
"boxcall" => {
// { op:"boxcall", box:<vid>, method:"name", args:[vid...], dst?:<vid> }
let box_id = require_u64(inst, "box", "boxcall box")? as u32;
let method = inst.get("method").and_then(Value::as_str).ok_or_else(|| "boxcall missing method".to_string())?.to_string();
let dst_opt = inst.get("dst").and_then(Value::as_u64).map(|v| ValueId::new(v as u32));
let args_v = inst.get("args").and_then(Value::as_array).cloned().unwrap_or_default();
let method = inst
.get("method")
.and_then(Value::as_str)
.ok_or_else(|| "boxcall missing method".to_string())?
.to_string();
let dst_opt = inst
.get("dst")
.and_then(Value::as_u64)
.map(|v| ValueId::new(v as u32));
let args_v = inst
.get("args")
.and_then(Value::as_array)
.cloned()
.unwrap_or_default();
let mut args: Vec<ValueId> = Vec::with_capacity(args_v.len());
for a in args_v {
let id = a.as_u64().ok_or_else(|| "boxcall arg must be integer".to_string())? as u32;
let id = a
.as_u64()
.ok_or_else(|| "boxcall arg must be integer".to_string())?
as u32;
args.push(ValueId::new(id));
}
block_ref.add_instruction(MirInstruction::BoxCall {
@ -163,7 +255,9 @@ pub fn parse_mir_v0_to_module(json: &str) -> Result<MirModule, String> {
args,
effects: EffectMask::READ,
});
if let Some(dv) = dst_opt { max_value_id = max_value_id.max(dv.as_u32() + 1); }
if let Some(dv) = dst_opt {
max_value_id = max_value_id.max(dv.as_u32() + 1);
}
}
other => {
return Err(format!("unsupported op '{}' in mir_json_v0 loader", other));
@ -181,7 +275,9 @@ pub fn parse_mir_v0_to_module(json: &str) -> Result<MirModule, String> {
}
fn require_u64(node: &Value, key: &str, context: &str) -> Result<u64, String> {
node.get(key).and_then(Value::as_u64).ok_or_else(|| format!("{} missing field '{}'", context, key))
node.get(key)
.and_then(Value::as_u64)
.ok_or_else(|| format!("{} missing field '{}'", context, key))
}
fn parse_const_value(value_obj: &Value) -> Result<ConstValue, String> {