current_task: refresh notes; cleanup unified; LLVM(harness): finalize_phis ownership, ret simplified, uses-predeclare; method-postfix cleanup return: PHI head grouping final TODOs

This commit is contained in:
Selfhosting Dev
2025-09-19 02:43:33 +09:00
parent 5e818eeb7e
commit 2d870664d5
3 changed files with 44 additions and 109 deletions

View File

@ -56,52 +56,29 @@ def lower_return(
ret_val = tmp0
if ret_val is None:
if resolver is not None and preds is not None and block_end_values is not None and bb_map is not None:
# Multi-pred special case: construct a PHI at block head and wire per-pred values
# to keep PHIs grouped at top and avoid late synthesis that violates ordering.
cur_bid = int(str(builder.block.name).replace('bb','')) if hasattr(builder.block, 'name') else -1
pred_ids = [p for p in preds.get(cur_bid, []) if p != cur_bid] if isinstance(preds, dict) else []
if isinstance(value_id, int) and len(pred_ids) > 1 and isinstance(return_type, ir.IntType):
# Create PHI at block head
btop = ir.IRBuilder(builder.block)
try:
btop.position_at_start(builder.block)
except Exception:
pass
ph = btop.phi(return_type, name=f"res_phi_{value_id}_{cur_bid}")
# Wire per-pred end values
for pred_bid in pred_ids:
pred_bb = bb_map.get(pred_bid) if isinstance(bb_map, dict) else None
if pred_bb is None:
continue
val = resolver._value_at_end_i64(value_id, pred_bid, preds, block_end_values, vmap, bb_map)
if not hasattr(val, 'type'):
val = ir.Constant(return_type, 0)
ph.add_incoming(val, pred_bb)
ret_val = ph
# Resolve direct value; PHIは finalize_phis に一任
if isinstance(return_type, ir.PointerType):
ret_val = resolver.resolve_ptr(value_id, builder.block, preds, block_end_values, vmap)
else:
# Resolve direct value
if isinstance(return_type, ir.PointerType):
ret_val = resolver.resolve_ptr(value_id, builder.block, preds, block_end_values, vmap)
is_stringish = False
if hasattr(resolver, 'is_stringish'):
try:
is_stringish = resolver.is_stringish(int(value_id))
except Exception:
is_stringish = False
if is_stringish and hasattr(resolver, 'string_ptrs') and int(value_id) in getattr(resolver, 'string_ptrs'):
p = resolver.string_ptrs[int(value_id)]
i8p = ir.IntType(8).as_pointer()
i64 = ir.IntType(64)
boxer = None
for f in builder.module.functions:
if f.name == 'nyash.box.from_i8_string':
boxer = f; break
if boxer is None:
boxer = ir.Function(builder.module, ir.FunctionType(i64, [i8p]), name='nyash.box.from_i8_string')
ret_val = builder.call(boxer, [p], name='ret_ptr2h')
else:
is_stringish = False
if hasattr(resolver, 'is_stringish'):
try:
is_stringish = resolver.is_stringish(int(value_id))
except Exception:
is_stringish = False
if is_stringish and hasattr(resolver, 'string_ptrs') and int(value_id) in getattr(resolver, 'string_ptrs'):
p = resolver.string_ptrs[int(value_id)]
i8p = ir.IntType(8).as_pointer()
i64 = ir.IntType(64)
boxer = None
for f in builder.module.functions:
if f.name == 'nyash.box.from_i8_string':
boxer = f; break
if boxer is None:
boxer = ir.Function(builder.module, ir.FunctionType(i64, [i8p]), name='nyash.box.from_i8_string')
ret_val = builder.call(boxer, [p], name='ret_ptr2h')
else:
ret_val = resolver.resolve_i64(value_id, builder.block, preds, block_end_values, vmap, bb_map)
ret_val = resolver.resolve_i64(value_id, builder.block, preds, block_end_values, vmap, bb_map)
if ret_val is None:
# Default to vmap (non-PHI) if available

View File

@ -30,6 +30,7 @@ from instructions.barrier import lower_barrier
from instructions.loopform import lower_while_loopform
from instructions.controlflow.while_ import lower_while_regular
from phi_wiring import setup_phi_placeholders as _setup_phi_placeholders, finalize_phis as _finalize_phis
from phi_wiring import ensure_phi as _ensure_phi
from trace import debug as trace_debug
from trace import phi as trace_phi
try:
@ -753,26 +754,8 @@ class NyashLLVMBuilder:
except Exception:
pass
instructions = block_data.get("instructions", [])
# Ensure JSON-declared PHIs are materialized at block start before any terminator
try:
phi_insts = [inst for inst in (instructions or []) if inst.get('op') == 'phi']
if phi_insts:
btop = ir.IRBuilder(bb)
btop.position_at_start(bb)
for pinst in phi_insts:
dstp = pinst.get('dst')
if isinstance(dstp, int):
cur = self.vmap.get(dstp)
need_new = True
try:
need_new = not (cur is not None and hasattr(cur, 'add_incoming'))
except Exception:
need_new = True
if need_new:
phi = btop.phi(self.i64, name=f"phi_{dstp}")
self.vmap[dstp] = phi
except Exception:
pass
# JSON-declared PHIs are not materialized here; placeholders are created uniformly
# via ensure_phi in finalize_phis to keep PHIs grouped at block head.
# Partition into body ops and terminators
body_ops: List[Dict[str, Any]] = []
term_ops: List[Dict[str, Any]] = []
@ -1112,41 +1095,14 @@ class NyashLLVMBuilder:
bb = self.bb_map.get(block_id)
if bb is None:
continue
b = ir.IRBuilder(bb)
try:
b.position_at_start(bb)
except Exception:
pass
for dst_vid, incoming in (dst_map or {}).items():
try:
trace_phi_json({"phi": "finalize_dst", "block": int(block_id), "dst": int(dst_vid), "incoming": [(int(v), int(b)) for (b, v) in [(b, v) for (v, b) in (incoming or [])]]})
except Exception:
pass
# Ensure placeholder exists at block head
# Prefer predeclared ret-phi when available and force using it.
predecl = getattr(self, 'predeclared_ret_phis', {}) if hasattr(self, 'predeclared_ret_phis') else {}
phi = predecl.get((int(block_id), int(dst_vid))) if predecl else None
if phi is not None:
# Bind as canonical target
self.vmap[dst_vid] = phi
else:
phi = self.vmap.get(dst_vid)
# Ensure we target a PHI belonging to the current block; if a
# global mapping points to a PHI in another block (due to
# earlier localization), create/replace with a local PHI.
need_local_phi = False
try:
if not (phi is not None and hasattr(phi, 'add_incoming')):
need_local_phi = True
else:
bb_of_phi = getattr(getattr(phi, 'basic_block', None), 'name', None)
if bb_of_phi != bb.name:
need_local_phi = True
except Exception:
need_local_phi = True
if need_local_phi:
phi = b.phi(self.i64, name=f"phi_{dst_vid}")
self.vmap[dst_vid] = phi
# Ensure placeholder exists at block head with common helper
phi = _ensure_phi(self, int(block_id), int(dst_vid), bb)
self.vmap[int(dst_vid)] = phi
n = getattr(phi, 'name', b'').decode() if hasattr(getattr(phi, 'name', None), 'decode') else str(getattr(phi, 'name', ''))
try:
trace_phi_json({"phi": "finalize_target", "block": int(block_id), "dst": int(dst_vid), "ir": str(n)})

View File

@ -104,6 +104,14 @@ class Resolver:
bmap = self.block_phi_incomings.get(block_id)
if isinstance(bmap, dict) and value_id in bmap:
existing_cur = vmap.get(value_id)
# Fallback: try builder/global vmap when local map lacks placeholder
try:
if (existing_cur is None or not hasattr(existing_cur, 'add_incoming')) and hasattr(self, 'global_vmap') and isinstance(self.global_vmap, dict):
gcand = self.global_vmap.get(value_id)
if gcand is not None and hasattr(gcand, 'add_incoming'):
existing_cur = gcand
except Exception:
pass
# Use placeholder only if it belongs to the current block; otherwise
# create/ensure a local PHI at the current block head to dominate uses.
is_phi_here = False
@ -118,21 +126,11 @@ class Resolver:
if is_phi_here:
self.i64_cache[cache_key] = existing_cur
return existing_cur
# Materialize a local PHI placeholder at block start and bind to vmap
b = ir.IRBuilder(current_block)
try:
b.position_at_start(current_block)
except Exception:
pass
phi_local = b.phi(self.i64, name=f"phi_{value_id}")
vmap[value_id] = phi_local
try:
if isinstance(getattr(self, 'global_vmap', None), dict):
self.global_vmap[value_id] = phi_local
except Exception:
pass
self.i64_cache[cache_key] = phi_local
return phi_local
# Do not synthesize PHI here; expect predeclared placeholder exists.
# Fallback to 0 to keep IR consistent if placeholder is missing (should be rare).
zero = ir.Constant(self.i64, 0)
self.i64_cache[cache_key] = zero
return zero
except Exception:
pass
@ -220,6 +218,10 @@ class Resolver:
# Return existing placeholder if present; do not create a new PHI here.
trace_phi(f"[resolve] use placeholder PHI: bb{cur_bid} v{value_id}")
placeholder = vmap.get(value_id)
if (placeholder is None or not hasattr(placeholder, 'add_incoming')) and hasattr(self, 'global_vmap') and isinstance(self.global_vmap, dict):
cand = self.global_vmap.get(value_id)
if cand is not None and hasattr(cand, 'add_incoming'):
placeholder = cand
result = placeholder if (placeholder is not None and hasattr(placeholder, 'add_incoming')) else ir.Constant(self.i64, 0)
else:
# No declared PHI and multi-pred: do not synthesize; fallback to zero