diff --git a/src/llvm_py/instructions/ret.py b/src/llvm_py/instructions/ret.py index 0a005ae0..1f11fff8 100644 --- a/src/llvm_py/instructions/ret.py +++ b/src/llvm_py/instructions/ret.py @@ -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 diff --git a/src/llvm_py/llvm_builder.py b/src/llvm_py/llvm_builder.py index 89565ad2..5bf193a3 100644 --- a/src/llvm_py/llvm_builder.py +++ b/src/llvm_py/llvm_builder.py @@ -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)}) diff --git a/src/llvm_py/resolver.py b/src/llvm_py/resolver.py index e8be2551..644f2995 100644 --- a/src/llvm_py/resolver.py +++ b/src/llvm_py/resolver.py @@ -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