Files
hakorune/tools/ny_mir_builder.sh
nyash-codex f6c5dc9e43 Phase 22.x WIP: LLVM backend improvements + MIR builder enhancements
LLVM backend improvements:
- Add native LLVM backend support (NYASH_LLVM_BACKEND=native)
- Add crate backend selector with priority (crate > llvmlite)
- Add native_llvm_builder.py for native IR generation
- Add NYASH_LLVM_NATIVE_TRACE=1 for IR dump

MIR builder enhancements:
- Refactor lower_if_compare_* boxes for better code generation
- Refactor lower_return_* boxes for optimized returns
- Refactor lower_loop_* boxes for loop handling
- Refactor lower_method_* boxes for method calls
- Update pattern_util_box for better pattern matching

Smoke tests:
- Add phase2100 S3 backend selector tests (17 new tests)
- Add phase2120 native backend tests (4 new tests)
- Add phase2034 MIR builder internal tests (2 new tests)
- Add phase2211 TLV shim parity test

Documentation:
- Update ENV_VARS.md with LLVM backend variables
- Update CURRENT_TASK.md with progress
- Update README.md and CHANGELOG.md

Config:
- Add NYASH_LLVM_BACKEND env support in src/config/env.rs
- Update ny_mir_builder.sh for backend selection
- Update dispatch.rs for backend routing

Tools:
- Add tools/native_llvm_builder.py
- Update smokes/v2/profiles/quick/core/phase2100/run_all.sh

Known: Many Hako builder internal files modified for optimization
2025-11-09 23:40:36 +09:00

214 lines
7.6 KiB
Bash
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.

#!/usr/bin/env bash
# ny_mir_builder.sh — Minimal MIR Builder CLI (shell wrapper)
# Purpose: consume Nyash JSON IR and emit {obj|exe|ll|json} using the existing nyash LLVM harness.
set -euo pipefail
[[ "${NYASH_CLI_VERBOSE:-0}" == "1" ]] && set -x
usage() {
cat << USAGE
Usage: tools/ny_mir_builder.sh [--in <file>|--stdin] [--emit {obj|exe|ll|json}] -o <out> [--target <triple>] [--nyrt <path>] [--quiet] [--verify-llvm]
Notes:
- This is a Phase-15 shell wrapper that leverages the nyash LLVM harness.
- Input must be Nyash JSON IR (v0/v1). When --stdin is used, reads from stdin.
- For --emit exe, NyRT must be built (crates/nyrt). Use default paths if --nyrt omitted.
USAGE
}
IN_MODE="stdin" # stdin | file
IN_FILE=""
EMIT="obj" # obj | exe | ll | json
OUT=""
TARGET=""
NYRT_DIR=""
VERIFY=0
QUIET=0
# Backend selection (21.11): default to 'crate' when ny-llvmc is available, otherwise fallback to llvmlite.
# Explicit env NYASH_LLVM_BACKEND overrides this auto-detection.
if [[ -n "${NYASH_LLVM_BACKEND:-}" ]]; then
BACKEND="${NYASH_LLVM_BACKEND}"
else
if [[ -x "./target/release/ny-llvmc" ]]; then
BACKEND="crate"
else
BACKEND="llvmlite"
fi
fi
while [[ $# -gt 0 ]]; do
case "$1" in
-h|--help) usage; exit 0 ;;
--in) IN_MODE="file"; IN_FILE="$2"; shift 2 ;;
--stdin) IN_MODE="stdin"; shift ;;
--emit) EMIT="$2"; shift 2 ;;
-o) OUT="$2"; shift 2 ;;
--target) TARGET="$2"; shift 2 ;;
--nyrt) NYRT_DIR="$2"; shift 2 ;;
--verify-llvm) VERIFY=1; shift ;;
--quiet) QUIET=1; shift ;;
*) echo "unknown arg: $1" >&2; usage; exit 2 ;;
esac
done
if [[ -z "$OUT" ]]; then
case "$EMIT" in
obj) OUT="$(pwd)/target/aot_objects/a.o" ;;
ll) OUT="$(pwd)/target/aot_objects/a.ll" ;;
exe) OUT="a.out" ;;
json) OUT="/dev/stdout" ;;
*) echo "error: invalid emit kind: $EMIT" >&2; exit 2 ;;
esac
fi
# Require LLVM18 only for llvmlite backend
if [[ "${NYASH_LLVM_BACKEND:-$BACKEND}" == "llvmlite" ]]; then
if ! command -v llvm-config-18 >/dev/null 2>&1; then
echo "error: llvm-config-18 not found (install LLVM 18 dev)" >&2
exit 3
fi
fi
# Build nyash + NyRT as neededskip allowed
LLVM_FEATURE=${NYASH_LLVM_FEATURE:-llvm}
SKIP_BUILD=${NYASH_LLVM_SKIP_BUILD:-0}
BUILD_TIMEOUT=${NYASH_LLVM_BUILD_TIMEOUT:-180}
if [[ "$SKIP_BUILD" != "1" ]]; then
if [[ "$LLVM_FEATURE" == "llvm-inkwell-legacy" ]]; then
_LLVMPREFIX=$(llvm-config-18 --prefix)
timeout "$BUILD_TIMEOUT" \
LLVM_SYS_181_PREFIX="${_LLVMPREFIX}" LLVM_SYS_180_PREFIX="${_LLVMPREFIX}" \
cargo build --release -j 24 --features "${LLVM_FEATURE}" >/dev/null
else
timeout "$BUILD_TIMEOUT" cargo build --release -j 24 --features "${LLVM_FEATURE}" >/dev/null
fi
# Prebuild ny-llvmc when using crate backend
if [[ "$BACKEND" == "crate" ]]; then
(cd "$(dirname "$0")/.." && timeout "$BUILD_TIMEOUT" cargo build --release -j 24 -p nyash-llvm-compiler >/dev/null) || true
fi
if [[ "$EMIT" == "exe" ]]; then
(cd crates/nyrt && timeout "$BUILD_TIMEOUT" cargo build --release -j 24 >/dev/null)
fi
fi
mkdir -p "$PWD/target/aot_objects"
# Prepare input
_STDIN_BUF=""
if [[ "$IN_MODE" == "stdin" ]]; then
# Read all to a temp file to allow re-use
_TMP_JSON=$(mktemp)
cat > "$_TMP_JSON"
IN_FILE="$_TMP_JSON"
fi
cleanup() { [[ -n "${_TMP_JSON:-}" && -f "$_TMP_JSON" ]] && rm -f "$_TMP_JSON" || true; }
trap cleanup EXIT
case "$EMIT" in
json)
# Normalization placeholder: currently pass-through
cat "$IN_FILE" > "$OUT"
[[ "$QUIET" == "0" ]] && echo "OK json:$OUT"
;;
ll)
# Ask nyash harness to dump LLVM IR (if supported via env)
export NYASH_LLVM_DUMP_LL=1
export NYASH_LLVM_LL_OUT="$OUT"
if [[ "$VERIFY" == "1" ]]; then export NYASH_LLVM_VERIFY=1; fi
# Prefer 'hakorune' binary if present (nyash is deprecated)
BIN="./target/release/hakorune"
[[ -x "$BIN" ]] || BIN="./target/release/nyash"
if [[ "$LLVM_FEATURE" == "llvm-inkwell-legacy" ]]; then
cat "$IN_FILE" | NYASH_LLVM_USE_HARNESS=1 LLVM_SYS_181_PREFIX="${_LLVMPREFIX}" LLVM_SYS_180_PREFIX="${_LLVMPREFIX}" \
"$BIN" --backend llvm --ny-parser-pipe >/dev/null || true
else
cat "$IN_FILE" | NYASH_LLVM_USE_HARNESS=1 \
"$BIN" --backend llvm --ny-parser-pipe >/dev/null || true
fi
if [[ ! -f "$OUT" ]]; then echo "error: failed to produce $OUT" >&2; exit 4; fi
[[ "$QUIET" == "0" ]] && echo "OK ll:$OUT"
;;
obj)
case "$BACKEND" in
crate)
BIN_NYLLVMC="./target/release/ny-llvmc"
if [[ ! -x "$BIN_NYLLVMC" ]]; then
echo "error: ny-llvmc not found (cargo build -p nyash-llvm-compiler)" >&2; exit 4
fi
rm -f "$OUT"
"$BIN_NYLLVMC" --in "$IN_FILE" --emit obj --out "$OUT" >/dev/null 2>&1 || { echo "error: ny-llvmc failed" >&2; exit 4; }
;;
native)
if ! command -v llc >/dev/null 2>&1; then
echo "error: llc not found (install LLVM tools)" >&2; exit 4
fi
rm -f "$OUT"
if ! python3 "$PWD/tools/native_llvm_builder.py" --in "$IN_FILE" --emit obj --out "$OUT" >/dev/null 2>&1; then
echo "error: native builder failed" >&2; exit 4
fi
;;
llvmlite|*)
# Directly use llvmlite harness with MIR v1 JSON input
rm -f "$OUT"
if ! python3 "$PWD/tools/llvmlite_harness.py" --in "$IN_FILE" --out "$OUT" >/dev/null 2>&1; then
echo "error: harness failed to produce $OUT" >&2; exit 4
fi
;;
esac
if [[ ! -f "$OUT" ]]; then echo "error: failed to produce $OUT" >&2; exit 4; fi
[[ "$QUIET" == "0" ]] && echo "OK obj:$OUT"
;;
exe)
# Emit obj then link
OBJ="$PWD/target/aot_objects/__tmp_builder.o"
rm -f "$OBJ"
case "$BACKEND" in
crate)
BIN_NYLLVMC="./target/release/ny-llvmc"
if [[ ! -x "$BIN_NYLLVMC" ]]; then
echo "error: ny-llvmc not found (cargo build -p nyash-llvm-compiler)" >&2; exit 4
fi
# Produce exe directly via ny-llvmc (lets ny-llvmc link)
LIBS="${HAKO_AOT_LDFLAGS:-}"
if ! "$BIN_NYLLVMC" --in "$IN_FILE" --emit exe --nyrt target/release --libs "$LIBS" --out "$OUT" >/dev/null 2>&1; then
echo "error: ny-llvmc failed to link exe" >&2; exit 4
fi
;;
native)
if ! command -v llc >/dev/null 2>&1; then
echo "error: llc not found (install LLVM tools)" >&2; exit 4
fi
if ! python3 "$PWD/tools/native_llvm_builder.py" --in "$IN_FILE" --emit obj --out "$OBJ" >/dev/null 2>&1; then
echo "error: native builder failed to produce object $OBJ" >&2; exit 4
fi
if [[ ! -f "$OBJ" ]]; then echo "error: failed to produce object $OBJ" >&2; exit 4; fi
# Link with NyRT (same as llvmlite branch)
NYRT_BASE=${NYRT_DIR:-"$PWD/crates/nyash_kernel"}
cc "$OBJ" \
-L target/release \
-L "$NYRT_BASE/target/release" \
-Wl,--whole-archive -lnyash_kernel -Wl,--no-whole-archive \
-lpthread -ldl -lm -o "$OUT"
;;
llvmlite|*)
if ! python3 "$PWD/tools/llvmlite_harness.py" --in "$IN_FILE" --out "$OBJ" >/dev/null 2>&1; then
echo "error: harness failed to produce object $OBJ" >&2; exit 4
fi
if [[ ! -f "$OBJ" ]]; then echo "error: failed to produce object $OBJ" >&2; exit 4; fi
# Link with NyRT
NYRT_BASE=${NYRT_DIR:-"$PWD/crates/nyash_kernel"}
cc "$OBJ" \
-L target/release \
-L "$NYRT_BASE/target/release" \
-Wl,--whole-archive -lnyash_kernel -Wl,--no-whole-archive \
-lpthread -ldl -lm -o "$OUT"
;;
esac
[[ "$QUIET" == "0" ]] && echo "OK exe:$OUT"
;;
*) echo "error: invalid emit kind: $EMIT" >&2; exit 2 ;;
esac
exit 0