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:
@ -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> {
|
||||
|
||||
Reference in New Issue
Block a user