- restore: lang/src/compiler/** (parser/emit/builder/pipeline_v2) from e917d400 - docs: docs/development/selfhosting/index-operator-hako.md - smokes(hako): tools/smokes/v2/profiles/quick/core/index_operator_hako.sh (opt-in) - smokes(vm): adjust index_operator_vm.sh for semicolon gate + stable error text - rust/parser: allow IndexExpr and assignment LHS=Index; postfix parse LBRACK chain - rust/builder: lower arr/map index to BoxCall get/set; annotate array/map literals; Fail‑Fast for unsupported types - CURRENT_TASK: mark Rust side done; add Hako tasks checklist Note: files disappeared likely due to branch FF to a lineage without lang/src/compiler; no explicit delete commit found. Added anchor checks and suggested CI guard in follow-up.
189 lines
6.6 KiB
Plaintext
189 lines
6.6 KiB
Plaintext
// LocalSSABox — 材化(materialize)/Copy 挿入の最小ポリシーを集約
|
||
// Phase 15.7: 最小実装。将来 PHI/Call 前の規約をここに集約して拡張する。
|
||
|
||
using "lang/src/shared/common/box_helpers.hako" as BoxHelpers
|
||
|
||
static box LocalSSABox {
|
||
_maybe_unwrap_instructions(insts) {
|
||
if insts == null { return null }
|
||
local repr = "" + insts
|
||
if repr.indexOf("MapBox(") == 0 {
|
||
local inner = BoxHelpers.map_get(insts, "instructions")
|
||
if inner != null { return inner }
|
||
}
|
||
return insts
|
||
}
|
||
|
||
// 汎用: copy 命令を insts(ArrayBox of Map)末尾に追加
|
||
add_copy(insts, dst, src) {
|
||
if insts == null { return 1 }
|
||
insts = me._maybe_unwrap_instructions(insts)
|
||
if insts == null { return 1 }
|
||
call("ArrayBox.push/2", insts, { op:"copy", dst: dst, src: src })
|
||
return 0
|
||
}
|
||
|
||
// PHI直後の材化(最小): いまは add_copy と同じ。将来 PHI 群スキップを実装
|
||
ensure_after_phis_copy(insts, src, dst) {
|
||
if insts == null { return 1 }
|
||
insts = me._maybe_unwrap_instructions(insts)
|
||
if insts == null { return 1 }
|
||
if BoxHelpers.is_array(insts) == 0 {
|
||
return me.add_copy(insts, dst, src)
|
||
}
|
||
local n = BoxHelpers.array_len(insts)
|
||
local i = 0
|
||
loop (i < n) {
|
||
local ins = BoxHelpers.array_get(insts, i)
|
||
if ins == null { break }
|
||
local op = BoxHelpers.map_get(ins, "op")
|
||
if op == null || op != "phi" { break }
|
||
i = i + 1
|
||
}
|
||
local insert_at = i // phi 直後
|
||
local node = { op:"copy", dst: dst, src: src }
|
||
if insert_at >= n {
|
||
call("ArrayBox.push/2", insts, node)
|
||
return 0
|
||
}
|
||
if n > 0 {
|
||
call("ArrayBox.push/2", insts, BoxHelpers.array_get(insts, n - 1))
|
||
local j = n - 1
|
||
loop (j >= insert_at) {
|
||
call("ArrayBox.set/3", insts, j + 1, BoxHelpers.array_get(insts, j))
|
||
j = j - 1
|
||
}
|
||
call("ArrayBox.set/3", insts, insert_at, node)
|
||
return 0
|
||
}
|
||
call("ArrayBox.push/2", insts, node)
|
||
return 0
|
||
}
|
||
|
||
// 新規: 定義直後に copy を挿入(安全・最小)
|
||
ensure_after_last_def_copy(insts, src, dst) {
|
||
if insts == null { return 1 }
|
||
if BoxHelpers.is_array(insts) == 0 { return 1 }
|
||
local n = BoxHelpers.array_len(insts)
|
||
local insert_at = n
|
||
// Find the first terminator index (ret/branch/jump/throw) to ensure block ends with a terminator
|
||
local term_at = n
|
||
{
|
||
local i = 0
|
||
loop(i < n) {
|
||
local ins = BoxHelpers.array_get(insts, i)
|
||
if ins != null {
|
||
local op = BoxHelpers.map_get(ins, "op")
|
||
if op == "ret" || op == "branch" || op == "jump" || op == "throw" { term_at = i break }
|
||
}
|
||
i = i + 1
|
||
}
|
||
}
|
||
// 探索: 最後に dst=src を定義した位置
|
||
{
|
||
local i = 0
|
||
loop (i < n) {
|
||
local ins = BoxHelpers.array_get(insts, i)
|
||
if ins != null {
|
||
print("[LS] checking def ins=" + ("" + ins))
|
||
local d_raw = BoxHelpers.map_get(ins, "dst")
|
||
print("[LS] dst raw=" + ("" + d_raw))
|
||
local d = BoxHelpers.value_i64(d_raw)
|
||
if d != null && d == src { insert_at = i + 1 }
|
||
}
|
||
i = i + 1
|
||
}
|
||
}
|
||
// Do not cross terminator: insert before the first terminator if present
|
||
if insert_at > term_at { insert_at = term_at }
|
||
local node = { op:"copy", dst: dst, src: src }
|
||
if insert_at >= n { call("ArrayBox.push/2", insts, node) return 0 }
|
||
// 1つ末尾に空きを作る(末尾要素を複製して押し出す)
|
||
if n > 0 {
|
||
call("ArrayBox.push/2", insts, BoxHelpers.array_get(insts, n - 1))
|
||
local j = n - 1
|
||
loop (j >= insert_at) {
|
||
call("ArrayBox.set/3", insts, j + 1, BoxHelpers.array_get(insts, j))
|
||
j = j - 1
|
||
}
|
||
call("ArrayBox.set/3", insts, insert_at, node)
|
||
return 0
|
||
}
|
||
call("ArrayBox.push/2", insts, node)
|
||
return 0
|
||
}
|
||
|
||
// calls の最小材化: 最後の ret が参照する値 src を探し、src の直後に copy(dst=src+1) を挿入する。
|
||
// mod_full: { functions: [ { blocks: [ { instructions: [...] } ] } ] }
|
||
ensure_materialize_last_ret(mod_full) {
|
||
if mod_full == null { return 1 }
|
||
local fns = BoxHelpers.map_get(mod_full, "functions")
|
||
if fns == null || BoxHelpers.array_len(fns) == 0 { return 1 }
|
||
local blocks = BoxHelpers.map_get(BoxHelpers.array_get(fns, 0), "blocks")
|
||
if blocks == null || BoxHelpers.array_len(blocks) == 0 { return 1 }
|
||
local insts = BoxHelpers.map_get(BoxHelpers.array_get(blocks, 0), "instructions")
|
||
if insts == null || BoxHelpers.array_len(insts) == 0 { return 1 }
|
||
// ret の引数を探索
|
||
local n = BoxHelpers.array_len(insts)
|
||
local src = null
|
||
{
|
||
local i = 0
|
||
loop(i < n) {
|
||
local ins = BoxHelpers.array_get(insts, i)
|
||
if ins != null {
|
||
local op = BoxHelpers.map_get(ins, "op")
|
||
if op == "ret" {
|
||
src = BoxHelpers.value_i64(BoxHelpers.map_get(ins, "value"))
|
||
}
|
||
}
|
||
i = i + 1
|
||
}
|
||
}
|
||
if src == null { return 1 }
|
||
return me.ensure_after_last_def_copy(insts, src, src + 1)
|
||
}
|
||
|
||
// ensure_cond: 最初の branch の cond を検出し、その定義直後に copy を1つ挿入(最小)
|
||
// - 形状期待: いずれかの block.instructions に { op:"branch", cond:<id>, ... }
|
||
ensure_cond(mod_full) {
|
||
if mod_full == null { return 1 }
|
||
local fns = BoxHelpers.map_get(mod_full, "functions")
|
||
if fns == null { return 1 }
|
||
local bn = BoxHelpers.array_len(fns)
|
||
if bn == 0 { return 1 }
|
||
local blocks = BoxHelpers.map_get(BoxHelpers.array_get(fns, 0), "blocks")
|
||
if blocks == null || BoxHelpers.array_len(blocks) == 0 { return 1 }
|
||
// 探索: 各ブロックの instructions から最初の branch を見つけ、そのブロックで材化
|
||
local bi = 0
|
||
local block_count = BoxHelpers.array_len(blocks)
|
||
loop (bi < block_count) {
|
||
local insts = BoxHelpers.map_get(BoxHelpers.array_get(blocks, bi), "instructions")
|
||
local insts_len = BoxHelpers.array_len(insts)
|
||
if insts_len > 0 {
|
||
local n = insts_len
|
||
local cond = null
|
||
{
|
||
local i = 0
|
||
loop(i < n) {
|
||
local ins = BoxHelpers.array_get(insts, i)
|
||
if ins != null {
|
||
local op = BoxHelpers.map_get(ins, "op")
|
||
if op == "branch" {
|
||
cond = BoxHelpers.value_i64(BoxHelpers.map_get(ins, "cond"))
|
||
break
|
||
}
|
||
}
|
||
i = i + 1
|
||
}
|
||
}
|
||
if cond != null { return me.ensure_after_last_def_copy(insts, cond, cond + 2) }
|
||
}
|
||
bi = bi + 1
|
||
}
|
||
return 1
|
||
}
|
||
|
||
}
|
||
|
||
static box LocalSSAStub { main(args) { return 0 } }
|