116 lines
3.4 KiB
Python
116 lines
3.4 KiB
Python
|
|
"""
|
||
|
|
NewBox instruction lowering
|
||
|
|
Handles box creation (new StringBox(), new IntegerBox(), etc.)
|
||
|
|
"""
|
||
|
|
|
||
|
|
import llvmlite.ir as ir
|
||
|
|
from typing import Dict, List, Optional
|
||
|
|
|
||
|
|
def lower_newbox(
|
||
|
|
builder: ir.IRBuilder,
|
||
|
|
module: ir.Module,
|
||
|
|
box_type: str,
|
||
|
|
args: List[int],
|
||
|
|
dst_vid: int,
|
||
|
|
vmap: Dict[int, ir.Value],
|
||
|
|
resolver=None
|
||
|
|
) -> None:
|
||
|
|
"""
|
||
|
|
Lower MIR NewBox instruction
|
||
|
|
|
||
|
|
Creates a new box instance and returns its handle.
|
||
|
|
|
||
|
|
Args:
|
||
|
|
builder: Current LLVM IR builder
|
||
|
|
module: LLVM module
|
||
|
|
box_type: Box type name (e.g., "StringBox", "IntegerBox")
|
||
|
|
args: Constructor arguments
|
||
|
|
dst_vid: Destination value ID for box handle
|
||
|
|
vmap: Value map
|
||
|
|
resolver: Optional resolver for type handling
|
||
|
|
"""
|
||
|
|
# Look up or declare the box creation function
|
||
|
|
create_func_name = f"ny_create_{box_type}"
|
||
|
|
create_func = None
|
||
|
|
|
||
|
|
for f in module.functions:
|
||
|
|
if f.name == create_func_name:
|
||
|
|
create_func = f
|
||
|
|
break
|
||
|
|
|
||
|
|
if not create_func:
|
||
|
|
# Declare box creation function
|
||
|
|
# Signature depends on box type
|
||
|
|
i64 = ir.IntType(64)
|
||
|
|
i8 = ir.IntType(8)
|
||
|
|
|
||
|
|
if box_type in ["StringBox", "IntegerBox", "BoolBox"]:
|
||
|
|
# Built-in boxes - default constructors (no args)
|
||
|
|
# Real implementation may have optional args
|
||
|
|
func_type = ir.FunctionType(i64, [])
|
||
|
|
else:
|
||
|
|
# Generic box - variable arguments
|
||
|
|
# For now, assume no args
|
||
|
|
func_type = ir.FunctionType(i64, [])
|
||
|
|
|
||
|
|
create_func = ir.Function(module, func_type, name=create_func_name)
|
||
|
|
|
||
|
|
# Prepare arguments
|
||
|
|
call_args = []
|
||
|
|
for i, arg_id in enumerate(args):
|
||
|
|
arg_val = vmap.get(arg_id)
|
||
|
|
|
||
|
|
if not arg_val:
|
||
|
|
# Default based on box type
|
||
|
|
if box_type == "StringBox":
|
||
|
|
# Empty string
|
||
|
|
i8 = ir.IntType(8)
|
||
|
|
arg_val = ir.Constant(i8.as_pointer(), None)
|
||
|
|
else:
|
||
|
|
# Zero
|
||
|
|
arg_val = ir.Constant(ir.IntType(64), 0)
|
||
|
|
|
||
|
|
# Type conversion if needed
|
||
|
|
if box_type == "StringBox" and hasattr(arg_val, 'type'):
|
||
|
|
if isinstance(arg_val.type, ir.IntType):
|
||
|
|
# int to string ptr
|
||
|
|
i8 = ir.IntType(8)
|
||
|
|
arg_val = builder.inttoptr(arg_val, i8.as_pointer())
|
||
|
|
|
||
|
|
call_args.append(arg_val)
|
||
|
|
|
||
|
|
# Create the box
|
||
|
|
handle = builder.call(create_func, call_args, name=f"new_{box_type}")
|
||
|
|
|
||
|
|
# Store handle
|
||
|
|
vmap[dst_vid] = handle
|
||
|
|
|
||
|
|
def lower_newbox_generic(
|
||
|
|
builder: ir.IRBuilder,
|
||
|
|
module: ir.Module,
|
||
|
|
dst_vid: int,
|
||
|
|
vmap: Dict[int, ir.Value]
|
||
|
|
) -> None:
|
||
|
|
"""
|
||
|
|
Create a generic box with runtime allocation
|
||
|
|
|
||
|
|
This is used when box type is not statically known.
|
||
|
|
"""
|
||
|
|
# Look up generic allocation function
|
||
|
|
alloc_func = None
|
||
|
|
for f in module.functions:
|
||
|
|
if f.name == "ny_alloc_box":
|
||
|
|
alloc_func = f
|
||
|
|
break
|
||
|
|
|
||
|
|
if not alloc_func:
|
||
|
|
# Declare ny_alloc_box(size: i64) -> i64
|
||
|
|
i64 = ir.IntType(64)
|
||
|
|
func_type = ir.FunctionType(i64, [i64])
|
||
|
|
alloc_func = ir.Function(module, func_type, name="ny_alloc_box")
|
||
|
|
|
||
|
|
# Default box size (e.g., 64 bytes)
|
||
|
|
size = ir.Constant(ir.IntType(64), 64)
|
||
|
|
handle = builder.call(alloc_func, [size], name="new_box")
|
||
|
|
|
||
|
|
vmap[dst_vid] = handle
|