#!/usr/bin/env bash
# Compile one W65816 translation unit, automatically falling back to the
# `basic` register allocator if the default `greedy` allocator hits the
# single-accumulator deadlock ("ran out of registers during register
# allocation").
#
# Why this exists: the 65816 has exactly one accumulator (the Acc16
# register class has a single physreg, A).  greedy's region-splitting
# heuristic can manufacture two A-pinned live ranges it cannot then
# unspill, and aborts.  This is a genuine hardware constraint, not a bug
# we can cheaply fix in the backend (the deadlocking vregs are greedy's
# own split products, so no pre-RA pass prevents them; verified
# 2026-06-29).  `basic` regalloc serializes the two values correctly.
#
# greedy stays the default because its codegen is smaller/faster
# everywhere it succeeds; basic is used ONLY for the rare function greedy
# cannot allocate, and ONLY for that translation unit.  This replaces the
# old hand-maintained per-file list (tests/lua/build.sh SLOW_FILES) so a
# newly-added register-heavy TU can never silently break the build.
#
# Usage: ccRegallocFallback.sh <clang> <clang-args...>
#   The args are a normal clang `-c file -o out` compile command.

set -u

if [ "$#" -lt 1 ]; then
    echo "usage: ccRegallocFallback.sh <clang> <clang-args...>" >&2
    exit 2
fi

clang="$1"
shift

# First attempt with the default (greedy) allocator.  Capture combined
# output so we can inspect it; a single-TU compile is quick, so buffering
# until completion is fine.
out="$("$clang" "$@" 2>&1)"
status=$?

if [ "$status" -eq 0 ]; then
    # Success: pass through any warnings clang produced.
    [ -n "$out" ] && printf '%s\n' "$out" >&2
    exit 0
fi

# Retry with basic regalloc ONLY for the single-accumulator deadlock.
# Any other compile error is surfaced as-is.
if printf '%s' "$out" | grep -q 'ran out of registers'; then
    echo "  (regalloc: greedy ran out of registers; retrying with -regalloc=basic)" >&2
    exec "$clang" "$@" -mllvm -regalloc=basic
fi

printf '%s\n' "$out" >&2
exit "$status"
