diff --git a/apps/macros/examples/if_match_normalize_macro.nyash b/apps/macros/examples/if_match_normalize_macro.nyash new file mode 100644 index 00000000..e244b424 --- /dev/null +++ b/apps/macros/examples/if_match_normalize_macro.nyash @@ -0,0 +1,13 @@ +// if_match_normalize_macro.nyash +// Scaffold: identity expansion for now. Future: introduce join variable and +// canonical If/Match normalization (scrutinee once, guard fused) as documented +// in docs/guides/if-match-normalize.md. + +static box MacroBoxSpec { + name() { return "IfMatchNormalizeScaffold" } + + expand(json, ctx) { + return json + } +} + diff --git a/docs/reference/mir/hints.md b/docs/reference/mir/hints.md new file mode 100644 index 00000000..4e7213d9 --- /dev/null +++ b/docs/reference/mir/hints.md @@ -0,0 +1,33 @@ +# MIR Hints — Zero‑Cost Structural Guidance + +目的 +- 構造を変えずに最適な IR を導くための“軽量ヒント”集合。Release では完全に剥離(ゼロコスト)。 + +原則 +- ヒントは意味論を持たない(最適化・検証の補助のみ)。 +- 生成器はヒントなしでも正しい MIR/IR を出す。ヒントは安定化・検証・最適化誘導のために用いる。 + +ヒント一覧(MVP 案) +- hint.scope_enter(id), hint.scope_leave(id) + - スコープ境界を指示(cleanup 合流の挿入点検討に使用)。 +- hint.defer(call-list) + - defer 呼出し列の静的展開に用いる(例外未導入の間は分岐/return/loop-exit 経路へ複製)。 +- hint.join_result(var) + - If/Match 式の合流結果(join 変数)を明示。空 PHI 抑止とブロック先頭 PHI を誘導。 +- hint.loop_carrier(vars…) + - ループヘッダで同一グループ PHI へ揃える対象変数集合(LoopForm と整合)。 +- hint.loop_header, hint.loop_latch + - 自然ループの境界指示(コードレイアウト/最適化の補助)。 +- hint.no_empty_phi(検証) + - 空 PHI 禁止の検証を有効化(開発/CI向け)。 + +パイプラインでの扱い +1) Macro: If/Match 正規化・Scope 属性付与・LoopForm(while/for/foreach)整形後に、 +2) Lowering: 上記ヒントを埋める(構造は不変)。 +3) Verify: 空 PHI 不在・PHI は合流先頭・ループヘッダの PHI 整列などを確認。 +4) Strip: Release ではヒントを完全剥離(IRには一切痕跡なし)。 + +注意 +- 既存の機能(マクロ・正規化)で構造を整えた上で使う。ヒントのみでは誤構造は正せない。 +- CI の軽量ゲートでは `hint.no_empty_phi` 相当のスモークで IR 健全性を監視する。 + diff --git a/tools/test/smoke/llvm/ir_phi_hygiene_loopform.sh b/tools/test/smoke/llvm/ir_phi_hygiene_loopform.sh new file mode 100644 index 00000000..2e3ec111 --- /dev/null +++ b/tools/test/smoke/llvm/ir_phi_hygiene_loopform.sh @@ -0,0 +1,60 @@ +#!/usr/bin/env bash +set -euo pipefail + +root=$(cd "$(dirname "$0")"/../../../.. && pwd) +bin="$root/target/release/nyash" + +if [ ! -x "$bin" ]; then + echo "nyash binary not found at $bin; build first (cargo build --release --features llvm)" >&2 + exit 1 +fi + +# Enable loop normalization macro and macro engine +export NYASH_MACRO_ENABLE=1 +export NYASH_MACRO_PATHS="apps/macros/examples/loop_normalize_macro.nyash" + +# Use self-host pre-expand (auto) with PyVM only to normalize before MIR +export NYASH_USE_NY_COMPILER=1 +export NYASH_VM_USE_PY=1 + +# Use LLVM harness and dump IR +export NYASH_LLVM_USE_HARNESS=1 + +fails=0 + +check_case() { + local src="$1" + local irfile="$root/tmp/$(basename "$src" .nyash)_llvm.ll" + mkdir -p "$root/tmp" + NYASH_LLVM_DUMP_IR="$irfile" "$bin" --macro-preexpand --backend llvm "$src" >/dev/null 2>&1 || { + echo "[FAIL] LLVM run failed for $src" >&2 + fails=$((fails+1)) + return + } + if [ ! -s "$irfile" ]; then + echo "[FAIL] IR not dumped for $src" >&2 + fails=$((fails+1)) + return + } + # Hygiene checks: + # 1) No empty phi nodes (phi ... with no '[' incoming pairs) + local empty_cnt + empty_cnt=$(rg -n "\\bphi\\b" "$irfile" | rg -v "\\[" | wc -l | tr -d ' ') + if [ "${empty_cnt:-0}" != "0" ]; then + echo "[FAIL] Empty PHI detected in $irfile" >&2 + rg -n "\\bphi\\b" "$irfile" | rg -v "\\[" || true + fails=$((fails+1)) + return + fi + echo "[OK] PHI hygiene (no empty PHI): $(basename "$irfile")" +} + +check_case "apps/tests/macro_golden_loop_simple.nyash" +check_case "apps/tests/macro_golden_loop_two_vars.nyash" + +if [ "$fails" -ne 0 ]; then + exit 2 +fi +echo "[OK] LLVM PHI hygiene for LoopForm cases passed" +exit 0 +