Files
tms-c-compiler/scripts/tests/m3/diff/check.sh
T

192 lines
6.6 KiB
Bash
Executable File

#!/bin/sh
# M3 differential TI-compiler control-flow/Xlib check.
#
# scripts/tests/m3/diff/check.sh
#
# The stored ti-branch.s/ti-xhello.s are one-time outputs of the 1987 TI
# compiler (GSP C Compiler 2.01) under DOSBox. CI never runs DOSBox: this
# script greps the stored golden files and compares their ABI shape with the
# assembly our compiler emits for the equivalent C.
#
# The oracle is the ABI shape, not instruction selection. Each requirement
# accepts the TI spellings and ours:
#
# sumto a conditional branch and an unconditional loop back-edge,
# result in A8, RETS 2
# max2 a conditional branch, result in A8, RETS 2
# xhello nine argument pushes for XCreateSimpleWindow (background first,
# display last), and the ROM bit displacements 0x480 (Display.screens)
# / 0x40 (Screen.root)
#
# TI emits JRLE/JRUC where we emit JAxx/JAUC; both are accepted. TI prints the
# displacements as decimal 1152/64, so 480h/40h are accepted too.
#
# Our branch.c is built exactly like the M3 gate: tms-clang -O2 with the
# -replexitval=never optimizer (that rewrite would turn sumto's loop into an
# i33 multiply, which the target cannot select), then llc -O0.
#
# Overridable: TMS_CLANG TMS_OPT TMS_BITADDR TMS_LLC TI_BRANCH TI_XHELLO
set -eu
ROOT=$(cd "$(dirname "$0")/../../../.." && pwd)
DIR=$ROOT/scripts/tests/m3/diff
SRC=$ROOT/scripts/m3
LLVM_BIN=${LLVM_BIN:-$ROOT/build/llvm-clean-build/bin}
TMS_CLANG=${TMS_CLANG:-$LLVM_BIN/clang}
TMS_OPT=${TMS_OPT:-$LLVM_BIN/opt}
TMS_BITADDR=${TMS_BITADDR:-$ROOT/tools/tms-bitaddr/tms-bitaddr}
TMS_LLC=${TMS_LLC:-$LLVM_BIN/llc}
TI_BRANCH=${TI_BRANCH:-$DIR/ti-branch.s}
TI_XHELLO=${TI_XHELLO:-$DIR/ti-xhello.s}
export TMS_CLANG TMS_OPT TMS_BITADDR
fail() {
echo "M3 diff: FAIL: $*" >&2
exit 1
}
for tool in "$TMS_CLANG" "$TMS_OPT" "$TMS_BITADDR" "$TMS_LLC"; do
[ -x "$tool" ] || fail "missing tool: $tool"
done
[ -f "$TI_BRANCH" ] || fail "stored TI golden missing: $TI_BRANCH"
[ -f "$TI_XHELLO" ] || fail "stored TI golden missing: $TI_XHELLO"
TMP=$(mktemp -d "${TMPDIR:-/tmp}/m3-diff.XXXXXX")
trap 'rm -rf "$TMP"' EXIT HUP INT TERM
# branch.c is generated through a wrapper so only this file keeps its loop.
OPT_NOREPLEXIT=$TMP/opt-noreplexit
printf '#!/bin/sh\nexec "%s" -replexitval=never "$@"\n' "$TMS_OPT" > "$OPT_NOREPLEXIT"
chmod +x "$OPT_NOREPLEXIT"
echo "== compile our branch.s and xhello.s"
TMS_OPT=$OPT_NOREPLEXIT "$ROOT/scripts/tms-clang" -O2 -I "$SRC" \
-o "$TMP/branch.ll" "$SRC/branch.c"
"$TMS_LLC" -march=tms34010 -O0 -filetype=asm "$TMP/branch.ll" -o "$TMP/branch.s"
"$ROOT/scripts/tms-clang" -O2 -I "$SRC" \
-o "$TMP/xhello.ll" "$SRC/xhello.c"
"$TMS_LLC" -march=tms34010 -O0 -filetype=asm "$TMP/xhello.ll" -o "$TMP/xhello.s"
echo " branch.s: $(grep -c . "$TMP/branch.s") lines"
echo " xhello.s: $(grep -c . "$TMP/xhello.s") lines"
# Our llc output has `;` end-of-line comments (`; %bb.0`). Strip them so a
# comment cannot satisfy a check; TI asm has none.
for f in "$TMP/branch.s" "$TMP/xhello.s"; do
sed 's/;.*//' "$f" > "$f.code"
done
# body FILE FUNC: from `_func:` to the next .globl/.end.
body() {
awk -v want="_$2:" '
$1 == want { infn = 1; next }
infn && ($1 == ".globl" || $1 == ".end") { exit }
infn { print }
' "$1"
}
require() {
_file=$1
_pat=$2
_what=$3
if grep -Eiq "$_pat" "$_file"; then
echo " ok $_what"
return 0
fi
echo "M3 diff: FAIL: missing $_what" >&2
echo " pattern: $_pat" >&2
sed 's/^/ /' "$_file" >&2
exit 1
}
require_rets2() {
require "$1" '^[[:space:]]*RETS[[:space:]]+2([[:space:]]|$)' "$2"
}
# A conditional branch: JA/JR plus a condition suffix. JAUC/JRUC/JRU do not
# match because their suffix is U/UC.
COND='^[[:space:]]*J[A-Z]*(EQ|NE|LT|LE|GT|GE|V|NV|P|N|Z|NZ|PL|MI)[[:space:]]'
# An unconditional branch: our JAUC, TI's JRUC (and bare JRU).
UNCOND='^[[:space:]]*J(AUC|RUC|RU|UMP)[[:space:]]'
# has_backedge FILE: true when a branch targets a label defined earlier in the
# same function body. TI closes the loop with the conditional JRLE L4; we
# close it with the unconditional JAUC LBB0_1, so either form counts.
has_backedge() {
awk '
/^[A-Za-z_][A-Za-z0-9_]*:/ {
lbl = $1
sub(/:$/, "", lbl)
pos[lbl] = NR
next
}
/^[[:space:]]*J/ {
if ($2 in pos && pos[$2] < NR)
found = 1
}
END { exit found ? 0 : 1 }
' "$1"
}
check_branch() { # check_branch FILE LABEL
_f=$1
body "$_f" sumto > "$TMP/sumto.body"
body "$_f" max2 > "$TMP/max2.body"
require "$TMP/sumto.body" "$COND" "$2: sumto has a conditional branch"
require "$TMP/sumto.body" "$UNCOND" "$2: sumto has an unconditional branch"
if ! has_backedge "$TMP/sumto.body"; then
echo "M3 diff: FAIL: $2: sumto has no loop back-edge" >&2
sed 's/^/ /' "$TMP/sumto.body" >&2
exit 1
fi
echo " ok $2: sumto branches back to the loop"
require_rets2 "$TMP/sumto.body" "$2: sumto ends with RETS 2"
require "$TMP/max2.body" "$COND" "$2: max2 has a conditional branch"
require_rets2 "$TMP/max2.body" "$2: max2 ends with RETS 2"
}
echo "== ABI shape: TI golden"
check_branch "$TI_BRANCH" "TI"
echo "== ABI shape: our compiler"
check_branch "$TMP/branch.s.code" "ours"
# Count the argument pushes since the previous CALLA, then require nine for
# XCreateSimpleWindow. Both compilers push the last argument first: display,
# root, x, y, width, height, border_width, border, background.
count_xcreate_pushes() {
awk '
/^_xhello:/ { infn = 1; n = 0; next }
!infn { next }
/CALLA[[:space:]]+_XCreateSimpleWindow/ { print n; exit }
/CALLA/ { n = 0; next }
/MOVE[[:space:]]+[^,]+,[[:space:]]*\*(STK|A14)\+/ { n++ }
' "$1"
}
for pair in "$TI_XHELLO:TI" "$TMP/xhello.s.code:ours"; do
f=${pair%%:*}
who=${pair##*:}
pushes=$(count_xcreate_pushes "$f")
[ -n "$pushes" ] || fail "$who xhello has no CALLA _XCreateSimpleWindow"
[ "$pushes" = "9" ] \
|| fail "$who XCreateSimpleWindow has $pushes argument pushes, want 9"
echo " ok $who: XCreateSimpleWindow takes nine argument pushes"
done
HEX480='(0x480|480h|[^0-9a-f]1152[^0-9a-f])'
HEX40='(0x40|40h|[^0-9a-f]64[^0-9a-f])'
check_offsets() { # check_offsets FILE WHO
_f=$1
_who=$2
body "$_f" xhello > "$TMP/xhello.body"
require "$TMP/xhello.body" "$HEX480" "$_who: Display.screens at bit 0x480"
require "$TMP/xhello.body" "$HEX40" "$_who: Screen.root at bit 0x40"
}
echo "== ROM bit displacements"
check_offsets "$TI_XHELLO" "TI"
check_offsets "$TMP/xhello.s.code" "ours"
echo "M3 diff: PASS"