fix(mir): PHI検証panic修正 - update_cfg()を検証前に呼び出し

A案実装: debug_verify_phi_inputs呼び出し前にCFG predecessorを更新

修正箇所(7箇所):
- src/mir/builder/phi.rs:50, 73, 132, 143
- src/mir/builder/ops.rs:273, 328, 351

根本原因:
- Branch/Jump命令でsuccessorは即座に更新
- predecessorはupdate_cfg()で遅延再構築
- PHI検証が先に実行されてpredecessor未更新でpanic

解決策:
- 各debug_verify_phi_inputs呼び出し前に
  if let Some(func) = self.current_function.as_mut() {
      func.update_cfg();
  }
  を挿入してCFGを同期

影響: if/else文、論理演算子(&&/||)のPHI生成が正常動作
This commit is contained in:
nyash-codex
2025-11-01 13:28:56 +09:00
parent 149ec61d4d
commit 6a452b2dca
174 changed files with 2432 additions and 1014 deletions

View File

@ -41,14 +41,14 @@ static box AotPrepBox {
local k1 = "\"value\":{\"type\":\"i64\",\"value\":"
local a_pos = body.indexOf(k1, p0)
if a_pos < 0 { return "" }
a_pos = a_pos + k1.size()
a_pos = a_pos + k1.length()
local a_s = JsonCursorBox.digits_from(body, a_pos)
if a_s == null || a_s == "" { return "" }
local p1 = body.indexOf("\"op\":\"const\"", a_pos)
if p1 < 0 { return "" }
local b_pos = body.indexOf(k1, p1)
if b_pos < 0 { return "" }
b_pos = b_pos + k1.size()
b_pos = b_pos + k1.length()
local b_s = JsonCursorBox.digits_from(body, b_pos)
if b_s == null || b_s == "" { return "" }
// operation symbol
@ -69,15 +69,15 @@ static box AotPrepBox {
// Build folded instruction array: [const rv -> dst:1, ret 1]
local folded = "[{\"op\":\"const\",\"dst\":1,\"value\":{\"type\":\"i64\",\"value\":" + (""+rv) + "}},{\"op\":\"ret\",\"value\":1}]"
// Splice back into whole JSON and return
return json.substring(0, start+1) + folded + json.substring(end, json.size())
return json.substring(0, start+1) + folded + json.substring(end, json.length())
}
_to_i64(s) {
// crude but sufficient for our immediate range
local i = 0; local neg = 0
if s.size() > 0 && s.substring(0,1) == "-" { neg = 1; i = 1 }
if s.length() > 0 && s.substring(0,1) == "-" { neg = 1; i = 1 }
local out = 0
loop (i < s.size()) {
loop (i < s.length()) {
local ch = s.substring(i, i+1)
if ch < "0" || ch > "9" { break }
out = out * 10 + (ch - "0")
@ -99,7 +99,7 @@ static box AotPrepBox {
local p = json.indexOf(pat, i)
if p < 0 { break }
// Parse dst number
local pnum = p + pat.size()
local pnum = p + pat.length()
local digits = JsonCursorBox.digits_from(json, pnum)
if digits == null || digits == "" { i = p + 1; continue }
local dst_s = digits
@ -114,7 +114,7 @@ static box AotPrepBox {
local obj_end = me._seek_object_end(json, obj_start)
if obj_end < 0 { i = p + 1; continue }
// Validate dst is unused after this object
local tail = json.substring(obj_end+1, json.size())
local tail = json.substring(obj_end+1, json.length())
// Search common reference patterns: ":<dst>" after a key
local ref = ":" + dst_s
if tail.indexOf(ref) >= 0 {
@ -124,11 +124,11 @@ static box AotPrepBox {
local cut_left = obj_start
local cut_right = obj_end + 1
// Trim a single trailing comma to keep JSON valid in arrays
if cut_right < json.size() {
if cut_right < json.length() {
local ch = json.substring(cut_right, cut_right+1)
if ch == "," { cut_right = cut_right + 1 }
}
json = json.substring(0, cut_left) + json.substring(cut_right, json.size())
json = json.substring(0, cut_left) + json.substring(cut_right, json.length())
changed = 1
i = cut_left
}
@ -140,13 +140,13 @@ static box AotPrepBox {
// Handles nested objects and string literals with escapes.
_seek_object_end(s, start) {
if s == null { return -1 }
if start < 0 || start >= s.size() { return -1 }
if start < 0 || start >= s.length() { return -1 }
if s.substring(start, start+1) != "{" { return -1 }
local i = start
local depth = 0
local in_str = 0
local esc = 0
loop (i < s.size()) {
loop (i < s.length()) {
local ch = s.substring(i, i+1)
if in_str == 1 {
if esc == 1 { esc = 0 }