diff --git a/src/llvm_py/builders/function_lower.py b/src/llvm_py/builders/function_lower.py index 4b87449e..65e1aac1 100644 --- a/src/llvm_py/builders/function_lower.py +++ b/src/llvm_py/builders/function_lower.py @@ -11,6 +11,74 @@ from phi_wiring import ( ) +def _clear_function_local_state(builder): + """ + Phase 132-P1: Clear all function-local state at function boundary. + + Box-First Principle: Prevents cross-function ValueId/BlockId collisions + by clearing all function-scoped state when entering a new function. + + Cleared state: + 1. PhiManager.predeclared - (bid, vid) -> phi_value + 2. Resolver caches - i64_cache, ptr_cache, f64_cache, _end_i64_cache + 3. Jump-only blocks - _jump_only_blocks + 4. PHI incomings - block_phi_incomings, def_blocks + 5. String/NewBox caches - function-local string handling + """ + try: + # 1. PhiManager predeclared PHIs (bid, vid) -> phi_value + if hasattr(builder, 'phi_manager') and hasattr(builder.phi_manager, 'predeclared'): + builder.phi_manager.predeclared.clear() + except Exception: + pass + + try: + # 2. Resolver caches (all keyed by block/value IDs) + builder.resolver.i64_cache.clear() + builder.resolver.ptr_cache.clear() + builder.resolver.f64_cache.clear() + if hasattr(builder.resolver, '_end_i64_cache'): + builder.resolver._end_i64_cache.clear() + + # 3. String-related caches (function-local) + if hasattr(builder.resolver, 'string_ids'): + builder.resolver.string_ids.clear() + if hasattr(builder.resolver, 'string_literals'): + builder.resolver.string_literals.clear() + if hasattr(builder.resolver, 'string_ptrs'): + builder.resolver.string_ptrs.clear() + if hasattr(builder.resolver, 'length_cache'): + builder.resolver.length_cache.clear() + + # 4. NewBox→string-arg hints (function-local) + if hasattr(builder.resolver, 'newbox_string_args') and isinstance(builder.resolver.newbox_string_args, dict): + builder.resolver.newbox_string_args.clear() + except Exception: + pass + + try: + # 5. Jump-only blocks (bid -> pred_bid) + if hasattr(builder, '_jump_only_blocks'): + builder._jump_only_blocks.clear() + except Exception: + pass + + try: + # 6. PHI incomings and def_blocks (function-local) + if hasattr(builder, 'block_phi_incomings'): + builder.block_phi_incomings.clear() + if hasattr(builder, 'def_blocks'): + builder.def_blocks.clear() + + # Also clear resolver's references to these + if hasattr(builder.resolver, 'block_phi_incomings'): + builder.resolver.block_phi_incomings = {} + if hasattr(builder.resolver, 'def_blocks'): + builder.resolver.def_blocks.clear() + except Exception: + pass + + def lower_function(builder, func_data: Dict[str, Any]): """Lower a single MIR function to LLVM IR using the given builder context. This is a faithful extraction of NyashLLVMBuilder.lower_function. @@ -49,35 +117,8 @@ def lower_function(builder, func_data: Dict[str, Any]): builder.bb_map.clear() except Exception: builder.bb_map = {} - # Phase 132-P0: Clear phi_manager per-function to avoid ValueId collisions - try: - if hasattr(builder, 'phi_manager') and hasattr(builder.phi_manager, 'predeclared'): - builder.phi_manager.predeclared.clear() - except Exception: - pass - try: - # Reset resolver caches keyed by block names - builder.resolver.i64_cache.clear() - builder.resolver.ptr_cache.clear() - builder.resolver.f64_cache.clear() - if hasattr(builder.resolver, '_end_i64_cache'): - builder.resolver._end_i64_cache.clear() - if hasattr(builder.resolver, 'string_ids'): - builder.resolver.string_ids.clear() - if hasattr(builder.resolver, 'string_literals'): - builder.resolver.string_literals.clear() - if hasattr(builder.resolver, 'string_ptrs'): - builder.resolver.string_ptrs.clear() - if hasattr(builder.resolver, 'length_cache'): - builder.resolver.length_cache.clear() - # Also clear newbox→string-arg hints per function to avoid leakage - try: - if hasattr(builder.resolver, 'newbox_string_args') and isinstance(builder.resolver.newbox_string_args, dict): - builder.resolver.newbox_string_args.clear() - except Exception: - pass - except Exception: - pass + # Phase 132-P1: Clear all function-local state (prevent cross-function collision) + _clear_function_local_state(builder) # Phase 131-15-P1: Load value_types metadata from JSON into resolver try: