Files
hakorune/src/llvm_py/instructions/const.py

100 lines
3.3 KiB
Python
Raw Normal View History

"""
Const instruction lowering
Handles integer, float, string, and void constants
"""
import llvmlite.ir as ir
from typing import Dict, Any
def lower_const(
builder: ir.IRBuilder,
module: ir.Module,
dst: int,
value: Dict[str, Any],
vmap: Dict[int, ir.Value],
resolver=None
) -> None:
"""
Lower MIR Const instruction
Args:
builder: Current LLVM IR builder
module: LLVM module
dst: Destination value ID
value: Const value dict with 'type' and 'value' fields
vmap: Value map (value_id -> llvm value)
"""
const_type = value.get('type', 'void')
const_val = value.get('value')
if const_type == 'i64':
# Integer constant
i64 = ir.IntType(64)
llvm_val = ir.Constant(i64, int(const_val))
vmap[dst] = llvm_val
elif const_type == 'f64':
# Float constant
f64 = ir.DoubleType()
llvm_val = ir.Constant(f64, float(const_val))
vmap[dst] = llvm_val
elif const_type == 'string' or (isinstance(const_type, dict) and const_type.get('kind') in ('handle','ptr') and const_type.get('box_type') == 'StringBox'):
# String constant - create global and immediately box to i64 handle
i8 = ir.IntType(8)
str_val = str(const_val)
str_bytes = str_val.encode('utf-8') + b'\0'
arr_ty = ir.ArrayType(i8, len(str_bytes))
str_const = ir.Constant(arr_ty, bytearray(str_bytes))
try:
fn = builder.block.parent
fn_name = getattr(fn, 'name', 'fn')
except Exception:
fn_name = 'fn'
base = f".str.{fn_name}.{dst}"
existing = {g.name for g in module.global_values}
name = base
n = 1
while name in existing:
name = f"{base}.{n}"; n += 1
g = ir.GlobalVariable(module, arr_ty, name=name)
g.initializer = str_const
g.linkage = 'private'
g.global_constant = True
# GEP to first element and box to handle immediately
i32 = ir.IntType(32)
c0 = ir.Constant(i32, 0)
gep = builder.gep(g, [c0, c0], inbounds=True)
i8p = i8.as_pointer()
boxer_ty = ir.FunctionType(ir.IntType(64), [i8p])
boxer = None
for f in module.functions:
if f.name == 'nyash.box.from_i8_string':
boxer = f
break
if boxer is None:
boxer = ir.Function(module, boxer_ty, name='nyash.box.from_i8_string')
handle = builder.call(boxer, [gep], name=f"const_str_h_{dst}")
vmap[dst] = handle
if resolver is not None:
if hasattr(resolver, 'string_literals'):
resolver.string_literals[dst] = str_val
# Mark this value-id as string-ish to guide '+' and '==' lowering
if hasattr(resolver, 'mark_string'):
resolver.mark_string(dst)
# Keep raw pointer for potential pointer-API sites (e.g., console.log)
try:
resolver.string_ptrs[dst] = gep
except Exception:
pass
elif const_type == 'void':
# Void/null constant - use i64 zero
i64 = ir.IntType(64)
vmap[dst] = ir.Constant(i64, 0)
else:
# Unknown type - default to i64 zero
i64 = ir.IntType(64)
vmap[dst] = ir.Constant(i64, 0)