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 } }
|