#!/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 # The args are a normal clang `-c file -o out` compile command. set -u if [ "$#" -lt 1 ]; then echo "usage: ccRegallocFallback.sh " >&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"