Files
hakorune/src/llvm_py/instructions/controlflow/while_.py

88 lines
3.2 KiB
Python

"""
Lowering helpers for while-control flow (regular structured)
"""
from typing import List, Dict, Any
import llvmlite.ir as ir
from instructions.safepoint import insert_automatic_safepoint
def lower_while_regular(
builder: ir.IRBuilder,
func: ir.Function,
cond_vid: int,
body_insts: List[Dict[str, Any]],
loop_id: int,
vmap: Dict[int, ir.Value],
bb_map: Dict[int, ir.Block],
resolver,
preds,
block_end_values,
):
"""Create a minimal while in IR: cond -> body -> cond, with exit.
The body instructions are lowered using the caller's dispatcher.
"""
i1 = ir.IntType(1)
i64 = ir.IntType(64)
# Create basic blocks: cond -> body -> cond, and exit
cond_bb = func.append_basic_block(name=f"while{loop_id}_cond")
body_bb = func.append_basic_block(name=f"while{loop_id}_body")
exit_bb = func.append_basic_block(name=f"while{loop_id}_exit")
# Jump from current to cond
builder.branch(cond_bb)
# Cond block
cbuild = ir.IRBuilder(cond_bb)
try:
# Resolve against the condition block to localize dominance
cond_val = resolver.resolve_i64(cond_vid, cond_bb, preds, block_end_values, vmap, bb_map)
except Exception:
cond_val = vmap.get(cond_vid)
if cond_val is None:
cond_val = ir.Constant(i1, 0)
# Normalize to i1
if hasattr(cond_val, 'type'):
if isinstance(cond_val.type, ir.IntType) and cond_val.type.width == 64:
zero64 = ir.Constant(i64, 0)
cond_val = cbuild.icmp_unsigned('!=', cond_val, zero64, name="while_cond_i1")
elif isinstance(cond_val.type, ir.PointerType):
nullp = ir.Constant(cond_val.type, None)
cond_val = cbuild.icmp_unsigned('!=', cond_val, nullp, name="while_cond_p1")
elif isinstance(cond_val.type, ir.IntType) and cond_val.type.width == 1:
# already i1
pass
else:
# Fallback: treat as false
cond_val = ir.Constant(i1, 0)
else:
cond_val = ir.Constant(i1, 0)
# Insert a safepoint at loop header to allow cooperative GC
try:
import os
if os.environ.get('NYASH_LLVM_AUTO_SAFEPOINT', '1') == '1':
insert_automatic_safepoint(cbuild, builder.block.parent.module, "loop_header")
except Exception:
pass
cbuild.cbranch(cond_val, body_bb, exit_bb)
# Body block
bbuild = ir.IRBuilder(body_bb)
# The caller must provide a dispatcher to lower body_insts; do a simple inline here.
# We expect the caller to have a method lower_instruction(builder, inst, func).
lower_instruction = getattr(resolver, '_owner_lower_instruction', None)
if lower_instruction is None:
raise RuntimeError('resolver._owner_lower_instruction not set (needs NyashLLVMBuilder.lower_instruction)')
for sub in body_insts:
if bbuild.block.terminator is not None:
cont = func.append_basic_block(name=f"cont_bb_{bbuild.block.name}")
bbuild.position_at_end(cont)
lower_instruction(bbuild, sub, func)
# Ensure terminator: if not terminated, branch back to cond
if bbuild.block.terminator is None:
bbuild.branch(cond_bb)
# Continue at exit
builder.position_at_end(exit_bb)