llvm(py): introduce BuildCtx + trace hub; refactor if-merge prepass + PHI wiring into module; unify logs; ctx-enable compare/ret/call/boxcall/externcall/typeop/newbox/safepoint; curated smoke option for if-merge; README updates; keep behavior stable

This commit is contained in:
Selfhosting Dev
2025-09-17 16:11:01 +09:00
parent 2720884a20
commit a5054a271b
58 changed files with 2002 additions and 311 deletions

View File

@ -4,7 +4,7 @@ Core of Nyash's "Everything is Box" philosophy
"""
import llvmlite.ir as ir
from typing import Dict, List, Optional
from typing import Dict, List, Optional, Any
def _declare(module: ir.Module, name: str, ret, args):
for f in module.functions:
@ -47,7 +47,8 @@ def lower_boxcall(
resolver=None,
preds=None,
block_end_values=None,
bb_map=None
bb_map=None,
ctx: Optional[Any] = None,
) -> None:
"""
Lower MIR BoxCall instruction
@ -68,10 +69,43 @@ def lower_boxcall(
i8 = ir.IntType(8)
i8p = i8.as_pointer()
# Short-hands with ctx (backward-compatible fallback)
r = resolver
p = preds
bev = block_end_values
bbm = bb_map
if ctx is not None:
try:
r = getattr(ctx, 'resolver', r)
p = getattr(ctx, 'preds', p)
bev = getattr(ctx, 'block_end_values', bev)
bbm = getattr(ctx, 'bb_map', bbm)
except Exception:
pass
def _res_i64(vid: int):
if r is not None and p is not None and bev is not None and bbm is not None:
try:
return r.resolve_i64(vid, builder.block, p, bev, vmap, bbm)
except Exception:
return None
return vmap.get(vid)
# If BuildCtx is provided, prefer its maps for consistency.
if ctx is not None:
try:
if getattr(ctx, 'resolver', None) is not None:
resolver = ctx.resolver
if getattr(ctx, 'preds', None) is not None and preds is None:
preds = ctx.preds
if getattr(ctx, 'block_end_values', None) is not None and block_end_values is None:
block_end_values = ctx.block_end_values
if getattr(ctx, 'bb_map', None) is not None and bb_map is None:
bb_map = ctx.bb_map
except Exception:
pass
# Receiver value
if resolver is not None and preds is not None and block_end_values is not None and bb_map is not None:
recv_val = resolver.resolve_i64(box_vid, builder.block, preds, block_end_values, vmap, bb_map)
else:
recv_val = _res_i64(box_vid)
if recv_val is None:
recv_val = vmap.get(box_vid, ir.Constant(i64, 0))
# Minimal method bridging for strings and console
@ -96,11 +130,11 @@ def lower_boxcall(
if method_name == "substring":
# substring(start, end)
# If receiver is a handle (i64), use handle-based helper; else pointer-based API
if resolver is not None and preds is not None and block_end_values is not None and bb_map is not None:
s = resolver.resolve_i64(args[0], builder.block, preds, block_end_values, vmap, bb_map) if args else ir.Constant(i64, 0)
e = resolver.resolve_i64(args[1], builder.block, preds, block_end_values, vmap, bb_map) if len(args) > 1 else ir.Constant(i64, 0)
else:
s = _res_i64(args[0]) if args else ir.Constant(i64, 0)
if s is None:
s = vmap.get(args[0], ir.Constant(i64, 0)) if args else ir.Constant(i64, 0)
e = _res_i64(args[1]) if len(args) > 1 else ir.Constant(i64, 0)
if e is None:
e = vmap.get(args[1], ir.Constant(i64, 0)) if len(args) > 1 else ir.Constant(i64, 0)
if hasattr(recv_val, 'type') and isinstance(recv_val.type, ir.IntType):
# handle-based
@ -191,9 +225,8 @@ def lower_boxcall(
# ArrayBox.get(index) → nyash.array.get_h(handle, idx)
# MapBox.get(key) → nyash.map.get_hh(handle, key_any)
recv_h = _ensure_handle(builder, module, recv_val)
if resolver is not None and preds is not None and block_end_values is not None and bb_map is not None:
k = resolver.resolve_i64(args[0], builder.block, preds, block_end_values, vmap, bb_map) if args else ir.Constant(i64, 0)
else:
k = _res_i64(args[0]) if args else ir.Constant(i64, 0)
if k is None:
k = vmap.get(args[0], ir.Constant(i64, 0)) if args else ir.Constant(i64, 0)
callee_map = _declare(module, "nyash.map.get_hh", i64, [i64, i64])
res = builder.call(callee_map, [recv_h, k], name="map_get_hh")
@ -204,9 +237,8 @@ def lower_boxcall(
if method_name == "push":
# ArrayBox.push(val) → nyash.array.push_h(handle, val)
recv_h = _ensure_handle(builder, module, recv_val)
if resolver is not None and preds is not None and block_end_values is not None and bb_map is not None:
v0 = resolver.resolve_i64(args[0], builder.block, preds, block_end_values, vmap, bb_map) if args else ir.Constant(i64, 0)
else:
v0 = _res_i64(args[0]) if args else ir.Constant(i64, 0)
if v0 is None:
v0 = vmap.get(args[0], ir.Constant(i64, 0)) if args else ir.Constant(i64, 0)
callee = _declare(module, "nyash.array.push_h", i64, [i64, i64])
res = builder.call(callee, [recv_h, v0], name="arr_push_h")
@ -217,11 +249,11 @@ def lower_boxcall(
if method_name == "set":
# MapBox.set(key, val) → nyash.map.set_hh(handle, key_any, val_any)
recv_h = _ensure_handle(builder, module, recv_val)
if resolver is not None and preds is not None and block_end_values is not None and bb_map is not None:
k = resolver.resolve_i64(args[0], builder.block, preds, block_end_values, vmap, bb_map) if len(args) > 0 else ir.Constant(i64, 0)
v = resolver.resolve_i64(args[1], builder.block, preds, block_end_values, vmap, bb_map) if len(args) > 1 else ir.Constant(i64, 0)
else:
k = _res_i64(args[0]) if len(args) > 0 else ir.Constant(i64, 0)
if k is None:
k = vmap.get(args[0], ir.Constant(i64, 0)) if len(args) > 0 else ir.Constant(i64, 0)
v = _res_i64(args[1]) if len(args) > 1 else ir.Constant(i64, 0)
if v is None:
v = vmap.get(args[1], ir.Constant(i64, 0)) if len(args) > 1 else ir.Constant(i64, 0)
callee = _declare(module, "nyash.map.set_hh", i64, [i64, i64, i64])
res = builder.call(callee, [recv_h, k, v], name="map_set_hh")
@ -232,9 +264,8 @@ def lower_boxcall(
if method_name == "has":
# MapBox.has(key) → nyash.map.has_hh(handle, key_any)
recv_h = _ensure_handle(builder, module, recv_val)
if resolver is not None and preds is not None and block_end_values is not None and bb_map is not None:
k = resolver.resolve_i64(args[0], builder.block, preds, block_end_values, vmap, bb_map) if args else ir.Constant(i64, 0)
else:
k = _res_i64(args[0]) if args else ir.Constant(i64, 0)
if k is None:
k = vmap.get(args[0], ir.Constant(i64, 0)) if args else ir.Constant(i64, 0)
callee = _declare(module, "nyash.map.has_hh", i64, [i64, i64])
res = builder.call(callee, [recv_h, k], name="map_has_hh")