112 lines
3.9 KiB
Python
112 lines
3.9 KiB
Python
|
|
"""
|
||
|
|
Resolver API (Python version)
|
||
|
|
Based on src/backend/llvm/compiler/codegen/instructions/resolver.rs
|
||
|
|
"""
|
||
|
|
|
||
|
|
from typing import Dict, Optional, Any, Tuple
|
||
|
|
import llvmlite.ir as ir
|
||
|
|
|
||
|
|
class Resolver:
|
||
|
|
"""
|
||
|
|
Centralized value resolution with per-block caching.
|
||
|
|
Following the Core Invariants from LLVM_LAYER_OVERVIEW.md:
|
||
|
|
- Resolver-only reads
|
||
|
|
- Localize at block start (PHI creation)
|
||
|
|
- Cache per (block, value) to avoid redundant PHIs
|
||
|
|
"""
|
||
|
|
|
||
|
|
def __init__(self, builder: ir.IRBuilder, module: ir.Module):
|
||
|
|
self.builder = builder
|
||
|
|
self.module = module
|
||
|
|
|
||
|
|
# Caches: (block_name, value_id) -> llvm value
|
||
|
|
self.i64_cache: Dict[Tuple[str, int], ir.Value] = {}
|
||
|
|
self.ptr_cache: Dict[Tuple[str, int], ir.Value] = {}
|
||
|
|
self.f64_cache: Dict[Tuple[str, int], ir.Value] = {}
|
||
|
|
|
||
|
|
# Type shortcuts
|
||
|
|
self.i64 = ir.IntType(64)
|
||
|
|
self.i8p = ir.IntType(8).as_pointer()
|
||
|
|
self.f64_type = ir.DoubleType()
|
||
|
|
|
||
|
|
def resolve_i64(
|
||
|
|
self,
|
||
|
|
value_id: int,
|
||
|
|
current_block: ir.Block,
|
||
|
|
preds: Dict[str, list],
|
||
|
|
block_end_values: Dict[str, Dict[int, Any]],
|
||
|
|
vmap: Dict[int, Any]
|
||
|
|
) -> ir.Value:
|
||
|
|
"""
|
||
|
|
Resolve a MIR value as i64 dominating the current block.
|
||
|
|
Creates PHI at block start if needed, caches the result.
|
||
|
|
"""
|
||
|
|
cache_key = (current_block.name, value_id)
|
||
|
|
|
||
|
|
# Check cache
|
||
|
|
if cache_key in self.i64_cache:
|
||
|
|
return self.i64_cache[cache_key]
|
||
|
|
|
||
|
|
# Get predecessor blocks
|
||
|
|
pred_names = preds.get(current_block.name, [])
|
||
|
|
|
||
|
|
if not pred_names:
|
||
|
|
# Entry block or no predecessors
|
||
|
|
base_val = vmap.get(value_id, ir.Constant(self.i64, 0))
|
||
|
|
result = self._coerce_to_i64(base_val)
|
||
|
|
else:
|
||
|
|
# Create PHI at block start
|
||
|
|
saved_pos = self.builder.block
|
||
|
|
self.builder.position_at_start(current_block)
|
||
|
|
|
||
|
|
phi = self.builder.phi(self.i64, name=f"loc_i64_{value_id}")
|
||
|
|
|
||
|
|
# Add incoming values from predecessors
|
||
|
|
for pred_name in pred_names:
|
||
|
|
pred_vals = block_end_values.get(pred_name, {})
|
||
|
|
val = pred_vals.get(value_id, ir.Constant(self.i64, 0))
|
||
|
|
coerced = self._coerce_to_i64(val)
|
||
|
|
# Note: In real implementation, need pred block reference
|
||
|
|
phi.add_incoming(coerced, pred_name) # Simplified
|
||
|
|
|
||
|
|
# Restore position
|
||
|
|
if saved_pos:
|
||
|
|
self.builder.position_at_end(saved_pos)
|
||
|
|
|
||
|
|
result = phi
|
||
|
|
|
||
|
|
# Cache and return
|
||
|
|
self.i64_cache[cache_key] = result
|
||
|
|
return result
|
||
|
|
|
||
|
|
def resolve_ptr(self, value_id: int, current_block: ir.Block,
|
||
|
|
preds: Dict, block_end_values: Dict, vmap: Dict) -> ir.Value:
|
||
|
|
"""Resolve as i8* pointer"""
|
||
|
|
# Similar to resolve_i64 but with pointer type
|
||
|
|
# TODO: Implement
|
||
|
|
pass
|
||
|
|
|
||
|
|
def resolve_f64(self, value_id: int, current_block: ir.Block,
|
||
|
|
preds: Dict, block_end_values: Dict, vmap: Dict) -> ir.Value:
|
||
|
|
"""Resolve as f64"""
|
||
|
|
# Similar pattern
|
||
|
|
# TODO: Implement
|
||
|
|
pass
|
||
|
|
|
||
|
|
def _coerce_to_i64(self, val: Any) -> ir.Value:
|
||
|
|
"""Coerce various types to i64"""
|
||
|
|
if isinstance(val, ir.Constant) and val.type == self.i64:
|
||
|
|
return val
|
||
|
|
elif hasattr(val, 'type') and val.type.is_pointer:
|
||
|
|
# ptr to int
|
||
|
|
return self.builder.ptrtoint(val, self.i64)
|
||
|
|
elif hasattr(val, 'type') and isinstance(val.type, ir.IntType):
|
||
|
|
# int to int (extend/trunc)
|
||
|
|
if val.type.width < 64:
|
||
|
|
return self.builder.zext(val, self.i64)
|
||
|
|
elif val.type.width > 64:
|
||
|
|
return self.builder.trunc(val, self.i64)
|
||
|
|
return val
|
||
|
|
else:
|
||
|
|
# Default zero
|
||
|
|
return ir.Constant(self.i64, 0)
|