Files
hakorune/src/llvm_py/builders/instruction_lower.py

195 lines
8.3 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

from typing import Dict, Any
from llvmlite import ir
from trace import debug as trace_debug
# Import instruction handlers
from instructions.const import lower_const
from instructions.binop import lower_binop
from instructions.compare import lower_compare
from instructions.unop import lower_unop
from instructions.controlflow.jump import lower_jump
from instructions.controlflow.branch import lower_branch
from instructions.ret import lower_return
from instructions.copy import lower_copy
from instructions.call import lower_call
from instructions.boxcall import lower_boxcall
from instructions.externcall import lower_externcall
from instructions.typeop import lower_typeop
from instructions.newbox import lower_newbox
from instructions.safepoint import lower_safepoint
from instructions.barrier import lower_barrier
from instructions.loopform import lower_while_loopform
from instructions.controlflow.while_ import lower_while_regular
from instructions.mir_call import lower_mir_call # New unified handler
def lower_instruction(owner, builder: ir.IRBuilder, inst: Dict[str, Any], func: ir.Function):
"""Dispatch a single MIR instruction to appropriate lowering helper.
owner is the NyashLLVMBuilder instance to access module, resolver, maps, and ctx.
"""
op = inst.get("op")
# Pick current vmap context (per-block context during lowering)
vmap_ctx = getattr(owner, '_current_vmap', owner.vmap)
if op == "const":
dst = inst.get("dst")
value = inst.get("value")
lower_const(builder, owner.module, dst, value, vmap_ctx, owner.resolver)
elif op == "binop":
operation = inst.get("operation")
lhs = inst.get("lhs")
rhs = inst.get("rhs")
dst = inst.get("dst")
dst_type = inst.get("dst_type")
lower_binop(builder, owner.resolver, operation, lhs, rhs, dst,
vmap_ctx, builder.block, owner.preds, owner.block_end_values, owner.bb_map,
dst_type=dst_type)
elif op == "jump":
target = inst.get("target")
lower_jump(builder, target, owner.bb_map)
elif op == "copy":
dst = inst.get("dst")
src = inst.get("src")
lower_copy(builder, dst, src, vmap_ctx, owner.resolver, builder.block, owner.preds, owner.block_end_values, owner.bb_map, getattr(owner, 'ctx', None))
elif op == "branch":
cond = inst.get("cond")
then_bid = inst.get("then")
else_bid = inst.get("else")
lower_branch(builder, cond, then_bid, else_bid, vmap_ctx, owner.bb_map, owner.resolver, owner.preds, owner.block_end_values)
elif op == "ret":
value = inst.get("value")
lower_return(builder, value, vmap_ctx, func.function_type.return_type,
owner.resolver, owner.preds, owner.block_end_values, owner.bb_map, getattr(owner, 'ctx', None))
elif op == "phi":
# No-op here: PHIはメタのみresolverがondemand生成
return
elif op == "compare":
# Dedicated compare op
operation = inst.get("operation") or inst.get("op")
lhs = inst.get("lhs")
rhs = inst.get("rhs")
dst = inst.get("dst")
cmp_kind = inst.get("cmp_kind")
lower_compare(builder, operation, lhs, rhs, dst, vmap_ctx,
owner.resolver, builder.block, owner.preds, owner.block_end_values, owner.bb_map,
meta={"cmp_kind": cmp_kind} if cmp_kind else None,
ctx=getattr(owner, 'ctx', None))
elif op == "unop":
# Unary op: kind in {'neg','not','bitnot'}; src is operand
kind = (inst.get("kind") or inst.get("operation") or "").lower()
srcv = inst.get("src") or inst.get("operand")
dst = inst.get("dst")
lower_unop(builder, owner.resolver, kind, srcv, dst, vmap_ctx, builder.block,
owner.preds, owner.block_end_values, owner.bb_map, ctx=getattr(owner, 'ctx', None))
elif op == "mir_call":
# Unified MIR Call handling
mir_call = inst.get("mir_call", {})
dst = inst.get("dst")
lower_mir_call(owner, builder, mir_call, dst, vmap_ctx, owner.resolver)
elif op == "call":
func_name = inst.get("func")
args = inst.get("args", [])
dst = inst.get("dst")
lower_call(builder, owner.module, func_name, args, dst, vmap_ctx, owner.resolver, owner.preds, owner.block_end_values, owner.bb_map, getattr(owner, 'ctx', None))
elif op == "boxcall":
box_vid = inst.get("box")
method = inst.get("method")
args = inst.get("args", [])
dst = inst.get("dst")
lower_boxcall(builder, owner.module, box_vid, method, args, dst,
vmap_ctx, owner.resolver, owner.preds, owner.block_end_values, owner.bb_map, getattr(owner, 'ctx', None))
# Optional: honor explicit dst_type for tagging (string handle)
try:
dst_type = inst.get("dst_type")
if dst is not None and isinstance(dst_type, dict):
if dst_type.get("kind") == "handle" and dst_type.get("box_type") == "StringBox":
if hasattr(owner.resolver, 'mark_string'):
owner.resolver.mark_string(int(dst))
# Track last substring for optional esc_json fallback
try:
if isinstance(method, str) and method == 'substring' and isinstance(dst, int):
owner._last_substring_vid = int(dst)
except Exception:
pass
except Exception:
pass
elif op == "externcall":
func_name = inst.get("func")
args = inst.get("args", [])
dst = inst.get("dst")
lower_externcall(builder, owner.module, func_name, args, dst,
vmap_ctx, owner.resolver, owner.preds, owner.block_end_values, owner.bb_map, getattr(owner, 'ctx', None))
elif op == "newbox":
box_type = inst.get("type")
args = inst.get("args", [])
dst = inst.get("dst")
lower_newbox(builder, owner.module, box_type, args, dst,
vmap_ctx, owner.resolver, getattr(owner, 'ctx', None))
elif op == "typeop":
operation = inst.get("operation")
src = inst.get("src")
dst = inst.get("dst")
target_type = inst.get("target_type")
lower_typeop(builder, operation, src, dst, target_type,
vmap_ctx, owner.resolver, owner.preds, owner.block_end_values, owner.bb_map, getattr(owner, 'ctx', None))
elif op == "safepoint":
live = inst.get("live", [])
lower_safepoint(builder, owner.module, live, vmap_ctx,
resolver=owner.resolver, preds=owner.preds,
block_end_values=owner.block_end_values, bb_map=owner.bb_map,
ctx=getattr(owner, 'ctx', None))
elif op == "barrier":
barrier_type = inst.get("type", "memory")
lower_barrier(builder, barrier_type, ctx=getattr(owner, 'ctx', None))
elif op == "while":
# Experimental LoopForm lowering inside a block
cond = inst.get("cond")
body = inst.get("body", [])
owner.loop_count += 1
if not lower_while_loopform(builder, func, cond, body,
owner.loop_count, owner.vmap, owner.bb_map,
owner.resolver, owner.preds, owner.block_end_values,
getattr(owner, 'ctx', None)):
# Fallback to regular while (structured)
try:
owner.resolver._owner_lower_instruction = owner.lower_instruction
except Exception:
pass
lower_while_regular(builder, func, cond, body,
owner.loop_count, owner.vmap, owner.bb_map,
owner.resolver, owner.preds, owner.block_end_values)
else:
trace_debug(f"[Python LLVM] Unknown instruction: {op}")
# Record per-inst definition for lifetime hinting as soon as available
try:
dst_maybe = inst.get("dst")
if isinstance(dst_maybe, int) and dst_maybe in owner.vmap:
cur_bid = None
try:
cur_bid = int(str(builder.block.name).replace('bb',''))
except Exception:
pass
if cur_bid is not None:
owner.def_blocks.setdefault(dst_maybe, set()).add(cur_bid)
except Exception:
pass