Added: - Resolver API (resolve_i64) for unified value resolution with per-block cache - llvmlite harness (Python) for rapid PHI/SSA verification - Comprehensive LLVM documentation suite: - LLVM_LAYER_OVERVIEW.md: Overall architecture and invariants - RESOLVER_API.md: Value resolution strategy - LLVM_HARNESS.md: Python verification harness Updated: - BuilderCursor applied to ALL lowering paths (externcall/newbox/arrays/maps/call) - localize_to_i64 for dominance safety in strings/compare/flow - NYASH_LLVM_DUMP_ON_FAIL=1 for debug IR output Key insight: LoopForm didn't cause problems, it just exposed existing design flaws: - Scattered value resolution (now unified via Resolver) - Inconsistent type conversion placement - Ambiguous PHI wiring responsibilities Next: Wire Resolver throughout, achieve sealed=ON green for dep_tree_min_string
84 lines
2.3 KiB
Python
84 lines
2.3 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Experimental llvmlite-based LLVM emission harness for Nyash.
|
|
|
|
Usage:
|
|
python3 tools/llvmlite_harness.py [--in MIR.json] --out OUTPUT.o
|
|
|
|
Notes:
|
|
- First cut emits a trivial ny_main that returns 0 to validate toolchain.
|
|
- Extend to lower MIR14 JSON incrementally.
|
|
"""
|
|
from __future__ import annotations
|
|
import argparse
|
|
import json
|
|
import os
|
|
import sys
|
|
|
|
try:
|
|
from llvmlite import ir, binding
|
|
except Exception as e: # noqa: BLE001
|
|
sys.stderr.write(
|
|
"llvmlite is required. Install with: python3 -m pip install llvmlite\n"
|
|
)
|
|
sys.stderr.write(f"Import error: {e}\n")
|
|
sys.exit(2)
|
|
|
|
|
|
def parse_args() -> argparse.Namespace:
|
|
ap = argparse.ArgumentParser(description="Nyash llvmlite harness")
|
|
ap.add_argument("--in", dest="in_path", help="MIR14 JSON input (optional)")
|
|
ap.add_argument("--out", dest="out_path", required=True, help="Output object file path")
|
|
return ap.parse_args()
|
|
|
|
|
|
def load_mir(path: str | None) -> dict | None:
|
|
if not path:
|
|
return None
|
|
with open(path, "r", encoding="utf-8") as f:
|
|
return json.load(f)
|
|
|
|
|
|
def build_trivial_module() -> ir.Module:
|
|
mod = ir.Module(name="nyash_harness")
|
|
mod.triple = binding.get_default_triple()
|
|
i64 = ir.IntType(64)
|
|
i8 = ir.IntType(8)
|
|
i8p = i8.as_pointer()
|
|
i8pp = i8p.as_pointer()
|
|
fn_ty = ir.FunctionType(i64, [i64, i8pp])
|
|
fn = ir.Function(mod, fn_ty, name="ny_main")
|
|
entry = fn.append_basic_block(name="entry")
|
|
b = ir.IRBuilder(entry)
|
|
b.ret(ir.Constant(i64, 0))
|
|
return mod
|
|
|
|
|
|
def emit_object(mod: ir.Module, out_path: str) -> None:
|
|
binding.initialize()
|
|
binding.initialize_native_target()
|
|
binding.initialize_native_asmprinter()
|
|
|
|
target = binding.Target.from_default_triple()
|
|
tm = target.create_target_machine()
|
|
llvm_mod = binding.parse_assembly(str(mod))
|
|
llvm_mod.verify()
|
|
obj = tm.emit_object(llvm_mod)
|
|
with open(out_path, "wb") as f:
|
|
f.write(obj)
|
|
|
|
|
|
def main() -> int:
|
|
ns = parse_args()
|
|
_mir = load_mir(ns.in_path)
|
|
# For now, ignore MIR content and emit a trivial module.
|
|
mod = build_trivial_module()
|
|
os.makedirs(os.path.dirname(ns.out_path) or ".", exist_ok=True)
|
|
emit_object(mod, ns.out_path)
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__": # pragma: no cover
|
|
raise SystemExit(main())
|
|
|