diff --git a/lang/src/llvm_ir/boxes/aot_prep/passes/numeric_core.hako b/lang/src/llvm_ir/boxes/aot_prep/passes/numeric_core.hako index 76b10340..24e07fd0 100644 --- a/lang/src/llvm_ir/boxes/aot_prep/passes/numeric_core.hako +++ b/lang/src/llvm_ir/boxes/aot_prep/passes/numeric_core.hako @@ -22,10 +22,41 @@ static box AotPrepNumericCoreBox { // Phase 25 MVP: Build type table and transform BoxCall → Call local tmap = AotPrepNumericCoreBox.build_type_table(text, trace) - // Propagate MatI64 type through simple PHI chains(全incomingがMatI64ならdstもMatI64とみなす) - tmap = AotPrepNumericCoreBox.propagate_phi_types(text, tmap, trace) local copy_map = AotPrepNumericCoreBox.build_copy_map(text, trace) + // Iterative type propagation: alternate copy and phi propagation to handle chains + // like: MatI64.new() → r2 → copy → r10 → phi → r15 → copy → r31 + local iter = 0 + loop(iter < 4) { + tmap = AotPrepNumericCoreBox.propagate_copy_types(text, tmap, trace) + tmap = AotPrepNumericCoreBox.propagate_phi_types(text, tmap, trace) + iter = iter + 1 + } + + // Diagnostic: show all MatI64 vids if trace enabled + if trace != null && ("" + trace) == "1" { + local mat_vids = new ArrayBox() + local keys = tmap.keys() + local ki = 0 + loop(ki < keys.size()) { + local key = keys.get(ki) + if tmap.get(key) == "MatI64" { + mat_vids.push("r" + key) + } + ki = ki + 1 + } + if mat_vids.size() > 0 { + local vids_str = "" + local vi = 0 + loop(vi < mat_vids.size()) { + if vi > 0 { vids_str = vids_str + "," } + vids_str = vids_str + mat_vids.get(vi) + vi = vi + 1 + } + print("[aot/numeric_core] MatI64 vids: " + vids_str) + } + } + local result = AotPrepNumericCoreBox.transform_boxcalls(text, tmap, copy_map, trace) // If nothing happened and trace is ON, surface a hint @@ -94,13 +125,6 @@ static box AotPrepNumericCoreBox { } } } - } else if op == "copy" { - // Propagate type through copy - local dst = AotPrepNumericCoreBox.read_digits_field(inst, "dst") - local src = AotPrepNumericCoreBox.read_digits_field(inst, "src") - if dst != "" && src != "" && tmap.has(src) { - tmap.set(dst, tmap.get(src)) - } } pos = obj_end + 1 @@ -149,6 +173,42 @@ static box AotPrepNumericCoreBox { return cmap } + // Propagate MatI64 type through copy instructions + // Scans all copy ops and propagates type from src to dst + propagate_copy_types(text, tmap, trace) { + local pos = 0 + loop(true) { + local op_marker = text.indexOf("\"op\":\"", pos) + if op_marker < 0 { break } + + local obj_start = text.substring(0, op_marker).lastIndexOf("{") + if obj_start < 0 { pos = op_marker + 1 continue } + + local obj_end = AotPrepHelpers._seek_object_end(text, obj_start) + if obj_end <= obj_start { pos = op_marker + 1 continue } + + local inst = text.substring(obj_start, obj_end + 1) + local op = AotPrepNumericCoreBox.read_field(inst, "op") + + if op == "copy" { + local dst = AotPrepNumericCoreBox.read_digits_field(inst, "dst") + local src = AotPrepNumericCoreBox.read_digits_field(inst, "src") + if dst != "" && src != "" && tmap.has(src) && !tmap.has(dst) { + local src_type = tmap.get(src) + if src_type == "MatI64" { + tmap.set(dst, "MatI64") + if trace != null && ("" + trace) == "1" { + print("[aot/numeric_core] copy-prop MatI64: r" + src + " → r" + dst) + } + } + } + } + + pos = obj_end + 1 + } + return tmap + } + // Propagate MatI64 type information through phi nodes. // Policy: 「少なくとも1つ MatI64 で、かつMatI64以外の型が混ざっていない」場合に dst を MatI64 とみなす。 propagate_phi_types(text, tmap, trace) { @@ -158,10 +218,17 @@ static box AotPrepNumericCoreBox { changed = 0 local pos = 0 loop(true) { - local obj_start = text.indexOf("{", pos) - if obj_start < 0 { break } + // Find next "op":" marker (same pattern as build_type_table/propagate_copy_types) + local op_marker = text.indexOf("\"op\":\"", pos) + if op_marker < 0 { break } + + // Find the start of this instruction object (the { before "op") + local obj_start = text.substring(0, op_marker).lastIndexOf("{") + if obj_start < 0 { pos = op_marker + 1 continue } + + // Find the end of this instruction object local obj_end = AotPrepHelpers._seek_object_end(text, obj_start) - if obj_end <= obj_start { pos = obj_start + 1 continue } + if obj_end <= obj_start { pos = op_marker + 1 continue } local inst = text.substring(obj_start, obj_end + 1) local op = AotPrepNumericCoreBox.read_field(inst, "op") @@ -197,7 +264,7 @@ static box AotPrepNumericCoreBox { tmap.set(dst, "MatI64") changed = 1 if trace != null && ("" + trace) == "1" { - print("[aot/numeric_core] phi-prop MatI64 at r" + dst) + print("[aot/numeric_core] phi-prop MatI64: r" + dst) } } } @@ -259,6 +326,23 @@ static box AotPrepNumericCoreBox { } } + // Diagnostic logging for skipped transformations + if should_transform == 0 && method == "mul_naive" { + local reason = "unknown" + if box_vid == "" { + reason = "no_box_vid" + } else if !tmap.has(box_vid) { + reason = "type_unknown" + } else if tmap.get(box_vid) != "MatI64" { + reason = "type_conflict (expected MatI64, got " + tmap.get(box_vid) + ")" + } + + if trace != null && ("" + trace) == "1" { + local dst = AotPrepNumericCoreBox.read_digits_field(inst, "dst") + print("[aot/numeric_core] skip mul_naive@r" + dst + ": box=r" + box_vid + " reason=" + reason) + } + } + if should_transform == 1 { // Transform BoxCall → Call // Copy text before this boxcall