diff --git a/lang/src/mir/builder/MirBuilderBox.hako b/lang/src/mir/builder/MirBuilderBox.hako index aa67054d..2978b5cc 100644 --- a/lang/src/mir/builder/MirBuilderBox.hako +++ b/lang/src/mir/builder/MirBuilderBox.hako @@ -29,6 +29,12 @@ static box MirBuilderBox { // Main entry method emit_from_program_json_v0(program_json, opts) { + // Debug tag (dev toggle only) + using "hako.mir.builder.internal.builder_config" as BuilderConfigBox + if BuilderConfigBox.trace_enabled() == 1 { + print("[mirbuilder/entry:build]") + } + if program_json == null { print("[mirbuilder/input/null] program_json is null") return null diff --git a/lang/src/mir/builder/internal/builder_config_box.hako b/lang/src/mir/builder/internal/builder_config_box.hako index bfbe1143..1c9ba4b1 100644 --- a/lang/src/mir/builder/internal/builder_config_box.hako +++ b/lang/src/mir/builder/internal/builder_config_box.hako @@ -30,6 +30,7 @@ static box BuilderConfigBox { // Loop/JsonFrag related loop_jsonfrag_on() { return self._is_on("HAKO_MIR_BUILDER_LOOP_JSONFRAG") } + loop_force_jsonfrag_on() { return self._is_on("HAKO_MIR_BUILDER_LOOP_FORCE_JSONFRAG") } jsonfrag_normalize_on() { return self._is_on("HAKO_MIR_BUILDER_JSONFRAG_NORMALIZE") } skip_loops_on() { return self._is_on("HAKO_MIR_BUILDER_SKIP_LOOPS") } diff --git a/lang/src/mir/builder/internal/loop_opts_adapter_box.hako b/lang/src/mir/builder/internal/loop_opts_adapter_box.hako index dd9d8b15..142ffb57 100644 --- a/lang/src/mir/builder/internal/loop_opts_adapter_box.hako +++ b/lang/src/mir/builder/internal/loop_opts_adapter_box.hako @@ -27,6 +27,7 @@ static box LoopOptsBox { // Block 2 (body): i_next = i+1, jump back to loop // Block 3 (exit): ret i (final loop variable value) // Value IDs: r1=i0(0), r2=limit(N), r3=phi(i), r4=cmp, r5=i_next, r10=const(1) + // PHI semantics: r3 receives r1 from block 0 (entry), r5 from block 2 (backedge) local mir = "{\"functions\":[{\"name\":\"main\",\"params\":[],\"locals\":[],\"blocks\":[" + "{\"id\":0,\"instructions\":[" + "{\"op\":\"const\",\"dst\":1,\"value\":{\"type\":\"i64\",\"value\":0}}," + diff --git a/tools/hakorune_emit_mir.sh b/tools/hakorune_emit_mir.sh index 6aabf7d9..ba1a8d27 100644 --- a/tools/hakorune_emit_mir.sh +++ b/tools/hakorune_emit_mir.sh @@ -66,9 +66,13 @@ fi try_selfhost_builder() { local prog_json="$1" out_path="$2" + + # Builder box selection (default: hako.mir.builder) + local builder_box="${HAKO_MIR_BUILDER_BOX:-hako.mir.builder}" + local tmp_hako; tmp_hako=$(mktemp --suffix .hako) cat >"$tmp_hako" <<'HCODE' -using "hako.mir.builder" as MirBuilderBox +using "__BUILDER_BOX__" as MirBuilderBox static box Main { method main(args) { local prog_json = env.get("HAKO_BUILDER_PROGRAM_JSON") if prog_json == null { print("[builder/selfhost-first:fail:nojson]"); return 1 } @@ -81,6 +85,8 @@ static box Main { method main(args) { return 0 } } HCODE + # Substitute builder box name after heredoc to avoid shell interpolation issues + sed -i "s|__BUILDER_BOX__|$builder_box|g" "$tmp_hako" local tmp_stdout; tmp_stdout=$(mktemp) trap 'rm -f "$tmp_hako" "$tmp_stdout" || true' RETURN @@ -96,23 +102,28 @@ HCODE if [ -f "$ROOT/nyash.toml" ]; then toml_status="present" fi - echo "[builder/selfhost-first:trace] prog_json_len=$prog_len tokens=Loop:$loop_count,Compare:$cmp_count cwd=$cwd nyash.toml=$toml_status" >&2 + echo "[builder/selfhost-first:trace] builder_box=$builder_box prog_json_len=$prog_len tokens=Loop:$loop_count,Compare:$cmp_count cwd=$cwd nyash.toml=$toml_status" >&2 fi set +e # Run from repo root to ensure nyash.toml is available for using resolution + # Capture both stdout and stderr (2>&1) instead of discarding stderr (cd "$ROOT" && \ HAKO_MIR_BUILDER_INTERNAL=1 HAKO_MIR_BUILDER_REGISTRY=1 \ + HAKO_MIR_BUILDER_TRACE="${HAKO_SELFHOST_TRACE:-}" \ HAKO_MIR_BUILDER_LOOP_JSONFRAG="${HAKO_MIR_BUILDER_LOOP_JSONFRAG:-}" \ HAKO_MIR_BUILDER_LOOP_FORCE_JSONFRAG="${HAKO_MIR_BUILDER_LOOP_FORCE_JSONFRAG:-}" \ HAKO_MIR_BUILDER_JSONFRAG_NORMALIZE="${HAKO_MIR_BUILDER_JSONFRAG_NORMALIZE:-}" \ HAKO_MIR_BUILDER_JSONFRAG_PURIFY="${HAKO_MIR_BUILDER_JSONFRAG_PURIFY:-}" \ HAKO_MIR_BUILDER_NORMALIZE_TAG="${HAKO_MIR_BUILDER_NORMALIZE_TAG:-}" \ HAKO_MIR_BUILDER_DEBUG="${HAKO_MIR_BUILDER_DEBUG:-}" \ + NYASH_DISABLE_PLUGINS=1 NYASH_FILEBOX_MODE="core-ro" HAKO_PROVIDER_POLICY="safe-core-first" \ NYASH_ENABLE_USING=1 HAKO_ENABLE_USING=1 \ NYASH_PARSER_STAGE3=1 HAKO_PARSER_STAGE3=1 NYASH_PARSER_ALLOW_SEMICOLON=1 \ + NYASH_USE_NY_COMPILER=0 HAKO_USE_NY_COMPILER=0 NYASH_DISABLE_NY_COMPILER=1 HAKO_DISABLE_NY_COMPILER=1 \ + NYASH_MACRO_DISABLE=1 HAKO_MACRO_DISABLE=1 \ HAKO_BUILDER_PROGRAM_JSON="$prog_json" \ - "$NYASH_BIN" --backend vm "$tmp_hako" 2>/dev/null | tee "$tmp_stdout" >/dev/null) + "$NYASH_BIN" --backend vm "$tmp_hako" 2>&1 | tee "$tmp_stdout" >/dev/null) local rc=$? set -e @@ -123,17 +134,34 @@ HCODE echo "[builder/selfhost-first:fail:detail] Last 80 lines of output:" >&2 tail -n 80 "$tmp_stdout" >&2 || true fi - return 1 + # Don't return immediately - check for fallback below fi - if ! grep -q "\[builder/selfhost-first:ok\]" "$tmp_stdout"; then + if [ $rc -eq 0 ] && ! grep -q "\[builder/selfhost-first:ok\]" "$tmp_stdout"; then if [ "${HAKO_SELFHOST_NO_DELEGATE:-0}" = "1" ]; then echo "[builder/selfhost-first:fail:no-ok-marker]" >&2 echo "[builder/selfhost-first:fail:detail] Last 80 lines of output:" >&2 tail -n 80 "$tmp_stdout" >&2 || true fi + rc=1 + fi + + # Try min builder fallback if enabled and initial builder failed + if [ "${HAKO_SELFHOST_TRY_MIN:-0}" = "1" ] && [ $rc -ne 0 ] && [ "$builder_box" != "hako.mir.builder.min" ]; then + if [ "${HAKO_SELFHOST_NO_DELEGATE:-0}" = "1" ]; then + echo "[builder/selfhost-first:trying-min-fallback]" >&2 + fi + + # Retry with min builder + HAKO_MIR_BUILDER_BOX="hako.mir.builder.min" try_selfhost_builder "$prog_json" "$out_path" + return $? + fi + + # Return original failure if no fallback or if fallback not triggered + if [ $rc -ne 0 ]; then return 1 fi + local mir mir=$(awk '/\[MIR_OUT_BEGIN\]/{flag=1;next}/\[MIR_OUT_END\]/{flag=0}flag' "$tmp_stdout") if [ -z "$mir" ]; then return 1; fi diff --git a/tools/smokes/v2/profiles/quick/core/phase2100/stageb_loop_jsonfrag_crate_exe_canary_vm.sh b/tools/smokes/v2/profiles/quick/core/phase2100/stageb_loop_jsonfrag_crate_exe_canary_vm.sh index 236ef8a3..9f9ea601 100644 --- a/tools/smokes/v2/profiles/quick/core/phase2100/stageb_loop_jsonfrag_crate_exe_canary_vm.sh +++ b/tools/smokes/v2/profiles/quick/core/phase2100/stageb_loop_jsonfrag_crate_exe_canary_vm.sh @@ -59,13 +59,22 @@ if ! NYASH_LLVM_BACKEND=crate NYASH_LLVM_VERIFY=1 NYASH_LLVM_VERIFY_IR=1 \ exit 0 fi -# Run and just ensure it executes (RC arbitrary here because structure-only lower) +# Run and check exit code set +e "$EXE_OUT" >/dev/null 2>&1 rc=$? set -e -if [[ "$rc" -ge 0 ]]; then + +# Expected: rc=10 (limit value from loop) +if [[ "$rc" -eq 10 ]]; then echo "[PASS] stageb_loop_jsonfrag_crate_exe_canary_vm" exit 0 fi -echo "[FAIL] stageb_loop_jsonfrag_crate_exe_canary_vm (unexpected run failure)"; exit 1 + +# If rc != 10, this is a failure +echo "[FAIL] stageb_loop_jsonfrag_crate_exe_canary_vm (expected rc=10, got $rc)" +if [ -f "$IR_DUMP" ] && [ -s "$IR_DUMP" ]; then + echo "[DEBUG] First 120 lines of LLVM IR for diagnosis:" >&2 + head -n 120 "$IR_DUMP" >&2 || true +fi +exit 1