2025-09-12 20:40:48 +09:00
|
|
|
"""
|
|
|
|
|
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],
|
2025-09-13 15:37:58 +09:00
|
|
|
vmap: Dict[int, ir.Value],
|
|
|
|
|
resolver=None
|
2025-09-12 20:40:48 +09:00
|
|
|
) -> 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
|
|
|
|
|
|
2025-09-14 04:51:33 +09:00
|
|
|
elif const_type == 'string' or (isinstance(const_type, dict) and const_type.get('kind') in ('handle','ptr') and const_type.get('box_type') == 'StringBox'):
|
2025-09-14 00:44:28 +09:00
|
|
|
# String constant - create global and immediately box to i64 handle
|
2025-09-12 20:40:48 +09:00
|
|
|
i8 = ir.IntType(8)
|
|
|
|
|
str_val = str(const_val)
|
✨ Python LLVM backend implementation (experimental)
- Created llvmlite-based LLVM backend in src/llvm_py/
- Implemented all MIR14 instructions (const, binop, jump, branch, ret, compare, phi, call, boxcall, externcall, typeop, newbox, safepoint, barrier)
- Experimental LoopForm support
- ~2000 lines of clean Python code vs complex Rust/inkwell
- Useful for PHI/SSA validation and rapid prototyping
- Added documentation to CLAUDE.md
This was created while waiting for ChatGPT's investigation of BuilderCursor issues.
2025-09-12 20:55:13 +09:00
|
|
|
str_bytes = str_val.encode('utf-8') + b'\0'
|
2025-09-13 15:37:58 +09:00
|
|
|
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
|
2025-09-14 00:44:28 +09:00
|
|
|
# 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
|
2025-09-13 19:49:03 +09:00
|
|
|
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)
|
2025-09-14 04:51:33 +09:00
|
|
|
# Keep raw pointer for potential pointer-API sites (e.g., console.log)
|
|
|
|
|
try:
|
|
|
|
|
resolver.string_ptrs[dst] = gep
|
|
|
|
|
except Exception:
|
|
|
|
|
pass
|
2025-09-12 20:40:48 +09:00
|
|
|
|
|
|
|
|
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)
|
2025-09-13 15:37:58 +09:00
|
|
|
vmap[dst] = ir.Constant(i64, 0)
|