refactor(llvm-py): Box-First refactoring of ret.py (Phase 1-2)
Extract two responsibility Boxes following Box-First principle: 1. UnreachableReturnHandlerBox (Phase 1) - Handle unreachable block returns with Fail-Fast principle - Implements Phase 284-P2 unreachable semantics - Moved os/sys imports to file header 2. ReturnTypeAdjusterBox (Phase 2) - Handle ptr↔int conversion and int width adjustment - Isolate type coercion logic for LLVM compatibility - Support truncate/extend for integer width mismatches Changes: - File size: 205→249 lines (+21% for better organization) - Reduced lower_return() complexity - Preserved all Phase 284-P2 comments and semantics - No breaking changes Tests: - phase286_pattern5_return_min.hako: PASS (exit 7) - phase284_p2_return_in_loop_llvm.sh: PASS - Quick profile: 154/154 PASS 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@ -3,6 +3,8 @@ Return instruction lowering
|
||||
Handles void and value returns
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import llvmlite.ir as ir
|
||||
from typing import Dict, Optional, Any
|
||||
try:
|
||||
@ -11,6 +13,74 @@ try:
|
||||
except Exception:
|
||||
_phi_at_block_head = None
|
||||
|
||||
|
||||
class UnreachableReturnHandlerBox:
|
||||
"""
|
||||
Box-First principle: Single Responsibility - Handle unreachable block returns
|
||||
Phase 284-P2: Implements Fail-Fast principle for unreachable blocks
|
||||
"""
|
||||
|
||||
@staticmethod
|
||||
def handle_null_return(builder: ir.IRBuilder, return_type: ir.Type) -> None:
|
||||
"""
|
||||
Handle unreachable blocks with Fail-Fast principle
|
||||
|
||||
MIR may generate unreachable blocks with null return values (e.g., loop(true) exit).
|
||||
LLVM type-checks all blocks, so we must match the function signature.
|
||||
Use 'unreachable' to satisfy type system AND crash if executed (Fail-Fast).
|
||||
|
||||
Args:
|
||||
builder: Current LLVM IR builder
|
||||
return_type: Expected return type
|
||||
"""
|
||||
if isinstance(return_type, ir.VoidType):
|
||||
# True void function: keep original behavior
|
||||
builder.ret_void()
|
||||
else:
|
||||
# Non-void function with null return: emit unreachable
|
||||
# This satisfies LLVM's type checker (no return needed after unreachable)
|
||||
# AND crashes immediately if the "unreachable" block is ever reached
|
||||
builder.unreachable()
|
||||
|
||||
|
||||
class ReturnTypeAdjusterBox:
|
||||
"""
|
||||
Box-First principle: Single Responsibility - Adjust return value types to match function signature
|
||||
Handles ptr↔int conversion and int width adjustment
|
||||
"""
|
||||
|
||||
@staticmethod
|
||||
def adjust_type(builder: ir.IRBuilder, ret_val: ir.Value, return_type: ir.Type) -> ir.Value:
|
||||
"""
|
||||
Adjust return value type if needed
|
||||
|
||||
Args:
|
||||
builder: Current LLVM IR builder
|
||||
ret_val: Return value to adjust
|
||||
return_type: Expected return type
|
||||
|
||||
Returns:
|
||||
Adjusted return value
|
||||
"""
|
||||
# Type adjustment if needed
|
||||
if hasattr(ret_val, 'type') and ret_val.type != return_type:
|
||||
if isinstance(return_type, ir.IntType) and ret_val.type.is_pointer:
|
||||
# ptr to int
|
||||
ret_val = builder.ptrtoint(ret_val, return_type, name="ret_p2i")
|
||||
elif isinstance(return_type, ir.PointerType) and isinstance(ret_val.type, ir.IntType):
|
||||
# int to ptr
|
||||
ret_val = builder.inttoptr(ret_val, return_type, name="ret_i2p")
|
||||
elif isinstance(return_type, ir.IntType) and isinstance(ret_val.type, ir.IntType):
|
||||
# int to int conversion
|
||||
if return_type.width < ret_val.type.width:
|
||||
# Truncate
|
||||
ret_val = builder.trunc(ret_val, return_type)
|
||||
elif return_type.width > ret_val.type.width:
|
||||
# Zero extend
|
||||
ret_val = builder.zext(ret_val, return_type)
|
||||
return ret_val
|
||||
|
||||
|
||||
def lower_return(
|
||||
builder: ir.IRBuilder,
|
||||
value_id: Optional[int],
|
||||
@ -45,18 +115,8 @@ def lower_return(
|
||||
except Exception:
|
||||
pass
|
||||
if value_id is None:
|
||||
# Phase 284-P2: Handle unreachable blocks with Fail-Fast principle
|
||||
# MIR may generate unreachable blocks with null return values (e.g., loop(true) exit).
|
||||
# LLVM type-checks all blocks, so we must match the function signature.
|
||||
# Use 'unreachable' to satisfy type system AND crash if executed (Fail-Fast).
|
||||
if isinstance(return_type, ir.VoidType):
|
||||
# True void function: keep original behavior
|
||||
builder.ret_void()
|
||||
else:
|
||||
# Non-void function with null return: emit unreachable
|
||||
# This satisfies LLVM's type checker (no return needed after unreachable)
|
||||
# AND crashes immediately if the "unreachable" block is ever reached
|
||||
builder.unreachable()
|
||||
# Delegate to UnreachableReturnHandlerBox (Box-First principle)
|
||||
UnreachableReturnHandlerBox.handle_null_return(builder, return_type)
|
||||
else:
|
||||
# Get return value (prefer resolver)
|
||||
ret_val = None
|
||||
@ -64,7 +124,6 @@ def lower_return(
|
||||
if isinstance(value_id, int):
|
||||
tmp0 = vmap.get(value_id)
|
||||
# Phase 132 Debug: trace vmap lookup
|
||||
import os, sys
|
||||
if os.environ.get('NYASH_LLVM_VMAP_TRACE') == '1':
|
||||
found = "FOUND" if tmp0 is not None else "MISSING"
|
||||
print(f"[vmap/ret] value_id={value_id} {found} in vmap, keys={sorted(list(vmap.keys())[:20])}", file=sys.stderr)
|
||||
@ -182,23 +241,9 @@ def lower_return(
|
||||
ret_val = phi
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# Type adjustment if needed
|
||||
if hasattr(ret_val, 'type') and ret_val.type != return_type:
|
||||
if isinstance(return_type, ir.IntType) and ret_val.type.is_pointer:
|
||||
# ptr to int
|
||||
ret_val = builder.ptrtoint(ret_val, return_type, name="ret_p2i")
|
||||
elif isinstance(return_type, ir.PointerType) and isinstance(ret_val.type, ir.IntType):
|
||||
# int to ptr
|
||||
ret_val = builder.inttoptr(ret_val, return_type, name="ret_i2p")
|
||||
elif isinstance(return_type, ir.IntType) and isinstance(ret_val.type, ir.IntType):
|
||||
# int to int conversion
|
||||
if return_type.width < ret_val.type.width:
|
||||
# Truncate
|
||||
ret_val = builder.trunc(ret_val, return_type)
|
||||
elif return_type.width > ret_val.type.width:
|
||||
# Zero extend
|
||||
ret_val = builder.zext(ret_val, return_type)
|
||||
|
||||
|
||||
# Delegate type adjustment to ReturnTypeAdjusterBox (Box-First principle)
|
||||
ret_val = ReturnTypeAdjusterBox.adjust_type(builder, ret_val, return_type)
|
||||
|
||||
# Emit return; no further instructions should be emitted in this block
|
||||
builder.ret(ret_val)
|
||||
|
||||
Reference in New Issue
Block a user