kit

kit
git clone https://git.ryansepassi.com/git/kit.git
Log | Files | Refs | README

commit 6e16d41536712479f63a338cbacd62feca3dfddf
parent 60a5068f6d4ba9b42645f2f1b01fabe1a9bf6a6e
Author: Ryan Sepassi <rsepassi@gmail.com>
Date:   Tue, 26 May 2026 17:50:55 -0700

test: add C and W paths to default test-toy; add W path to parse runner

toy/run.sh: default PATHS from "RL" to "RLCW". C and W are already
gated to opt=0 only inside the runner, so no duplicate work at higher
opt levels.

parse/run.sh: add W path (cc -target wasm32-none + cfree run -e
test_main). Phased-rollout panics surface as SKIP. Adds .wasm.skip
sidecar support and T_W timing. Also plumbs CFREE into the runner's
env default (was hardcoded to build/cfree).

test.mk: add test-wasm-c target (parse corpus under W path, ALLOW_SKIP
until the corpus is mostly green); add it to TEST_TARGETS.

Diffstat:
Mtest/parse/run.sh | 85++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------
Mtest/test.mk | 12++++++++++++
Mtest/toy/run.sh | 5+++--
3 files changed, 93 insertions(+), 9 deletions(-)

diff --git a/test/parse/run.sh b/test/parse/run.sh @@ -1,8 +1,8 @@ #!/usr/bin/env bash # test/parse/run.sh — file-driven C-parser test harness. # -# For each test/parse/cases/*.c, runs up to five paths (the test/cg path -# matrix minus W; DWARF directives may be added later via .dwarf sidecars): +# For each test/parse/cases/*.c, runs up to six paths (DWARF directives may +# be added later via .dwarf sidecars): # # D in-process JIT — parse-runner --jit FILE.c → exit code matches # expected. No file I/O. aarch64 host only. @@ -16,6 +16,13 @@ # Host arch must match cross target. Cases that hit an # unimplemented C-target method are reported as SKIP # (not FAIL) so phased backend rollout is tolerated. +# W wasm roundtrip — cfree cc -target wasm32-none -c case.c -> .wasm, then +# cfree run -e test_main on it (the lang/wasm frontend +# re-lowers to native CG, JITs, calls test_main). +# Exercises the Wasm CGTarget (C -> wasm). Opt-in and +# opt=0 only; host arch must match cross target (the +# re-lowering JITs for the host). Phased-rollout panics +# ("wasm: ... not yet implemented") report SKIP. # # Reuses the test/link harness binaries (cfree-roundtrip, link-exe-runner, # jit-runner) and test/link/harness/start.c verbatim. @@ -25,11 +32,12 @@ # <name>.skip — single-line reason. Treated as failure unless # CFREE_TEST_ALLOW_SKIP=1 (matching the rest of # the test suite). +# <name>.wasm.skip — single-line reason; opts the case out of path W only. # # Filtering: # ./run.sh [name_filter] [paths] # name_filter substring match against case basename -# paths subset of "DREJC" (default "DREJ" — C opt-in) +# paths subset of "DREJCW" (default "DREJ" — C and W opt-in) # Equivalent env vars: CFREE_TEST_FILTER, CFREE_TEST_PATHS. # # Optimization levels: @@ -50,6 +58,7 @@ LINK_TEST_DIR="$ROOT/test/link" BUILD_DIR="$ROOT/build/test" LIB_AR="$ROOT/build/libcfree.a" +CFREE="${CFREE:-$ROOT/build/cfree}" PARSE_RUNNER="$BUILD_DIR/parse-runner" ROUNDTRIP_BIN="$BUILD_DIR/cfree-roundtrip" LINK_EXE_RUNNER="$BUILD_DIR/link-exe-runner" @@ -105,7 +114,8 @@ case "$PATHS" in *R*) RUN_R=1;; *) RUN_R=0;; esac case "$PATHS" in *E*) RUN_E=1;; *) RUN_E=0;; esac case "$PATHS" in *J*) RUN_J=1;; *) RUN_J=0;; esac case "$PATHS" in *C*) RUN_C=1;; *) RUN_C=0;; esac -T_D=0; T_R=0; T_E=0; T_J=0; T_C=0 +case "$PATHS" in *W*) RUN_W=1;; *) RUN_W=0;; esac +T_D=0; T_R=0; T_E=0; T_J=0; T_C=0; T_W=0 now_ms() { python3 -c 'import time;print(int(time.time()*1000))'; } mkdir -p "$BUILD_DIR" "$BUILD_DIR/parse" @@ -163,6 +173,7 @@ replay_events() { E) T_E=$(( T_E + b )) ;; J) T_J=$(( T_J + b )) ;; C) T_C=$(( T_C + b )) ;; + W) T_W=$(( T_W + b )) ;; esac ;; QUEUE_E) @@ -405,7 +416,7 @@ FILTERED_CASES=() # loop flags as "missing worker result". Restrict to opt=0 in that case. case_opt_levels="$OPT_LEVELS" if [ $RUN_D -eq 0 ] && [ $RUN_R -eq 0 ] && [ $RUN_E -eq 0 ] && \ - [ $RUN_J -eq 0 ] && [ $RUN_C -eq 1 ]; then + [ $RUN_J -eq 0 ] && { [ $RUN_C -eq 1 ] || [ $RUN_W -eq 1 ]; }; then case_opt_levels="0" fi for src in "${CASES[@]}"; do @@ -630,6 +641,66 @@ run_parse_case() { emit_event "$event" SKIP "$name/C" "host arch != $TEST_ARCH (C target is target-locked)" fi fi + + # ---- Path W: cc -target wasm32-none + cfree run ---------------------- + # Compile the case straight to a .wasm via the Wasm CGTarget, then run it + # with `cfree run -e test_main` (the lang/wasm frontend re-lowers the + # module to native CG, JITs it, and calls test_main). Mirrors the toy + # runner's W path. Like path C it is target-agnostic, so it does not + # depend on the cross-target arch; but the re-lowering JITs for the host, + # so it only runs when the host arch matches the cross-target. + # + # The Wasm CGTarget ignores -O for opt purposes (the wasm frontend picks + # its own native opt level when re-lowering), so W runs at opt=0 only. + # Phased-rollout panics ("wasm: <feature> not yet implemented" and the + # "unsupported"/"supported in v1" variants) surface as SKIP, not FAIL, so + # the signal stays "real regressions". A `<name>.wasm.skip` sidecar opts a + # case out of path W with a reason. + run_w=$RUN_W + if [ $run_w -eq 1 ] && [ "$opt" != "0" ]; then + run_w=0 + fi + if [ $run_w -eq 1 ] && [ -e "$TEST_DIR/cases/$base_name.wasm.skip" ]; then + emit_event "$event" SKIP "$name/W" \ + "$(head -n1 "$TEST_DIR/cases/$base_name.wasm.skip")" + run_w=0 + fi + if [ $run_w -eq 1 ] && [ $is_native_target -eq 0 ]; then + emit_event "$event" SKIP "$name/W" "host arch != $TEST_ARCH (no native JIT for re-lowering)" + run_w=0 + fi + if [ $run_w -eq 1 ]; then + local wasm w_cc_err w_run_err w_rc w_missing + wasm="$work/$base_name.wasm" + w_cc_err="$work/w.cc.err" + w_run_err="$work/w.run.err" + t0=$(now_ms) + if ! "$CFREE" cc -O0 -target wasm32-none -c "$src" -o "$wasm" \ + >"$work/w.cc.out" 2>"$w_cc_err"; then + dt=$(( $(now_ms) - t0 )); emit_event "$event" TIME W "$dt" + w_missing=$(grep -oE 'wasm(32 ABI| target)?: .*(not yet implemented|not (yet )?supported|unsupported [a-z_0-9]+|max [0-9]+ supported|supported in v1)' \ + "$w_cc_err" 2>/dev/null | head -n1 || true) + if [ -n "$w_missing" ]; then + emit_event "$event" SKIP "$name/W" "$w_missing" + else + emit_event "$event" FAIL "$name/W (cc -target wasm32-none failed; see $w_cc_err)" + fi + else + # Validate by exit code only (like paths D/J/C). cc stderr is not a + # failure on its own: legitimate non-fatal diagnostics such as + # `#warning` print there while compilation succeeds and the program + # still runs. A real compile failure already took the branch above; + # a real run failure shows up as an exit-code mismatch. + "$CFREE" run -e test_main "$wasm" >"$work/w.run.out" 2>"$w_run_err" + w_rc=$? + dt=$(( $(now_ms) - t0 )); emit_event "$event" TIME W "$dt" + if [ "$w_rc" -eq "$expected_byte" ]; then + emit_event "$event" PASS "$name/W (${dt}ms)" + else + emit_event "$event" FAIL "$name/W (expected $expected_byte got $w_rc, ${dt}ms)" + fi + fi + fi return 0 } @@ -685,8 +756,8 @@ if [ ${#SKIP_NAMES[@]} -gt 0 ] && [ "$ALLOW_SKIP" != "1" ]; then fi printf '\nResults: %s pass, %s fail, %s skip\n' "$PASS" "$FAIL" "$SKIP" -printf 'Time: D=%dms R=%dms E=%dms (batch %dms) J=%dms C=%dms\n' \ - "$T_D" "$T_R" "$T_E" "$T_E_BATCH" "$T_J" "$T_C" +printf 'Time: D=%dms R=%dms E=%dms (batch %dms) J=%dms C=%dms W=%dms\n' \ + "$T_D" "$T_R" "$T_E" "$T_E_BATCH" "$T_J" "$T_C" "$T_W" if [ $FAIL -gt 0 ]; then exit 1; fi if [ $SKIP -gt 0 ] && [ "$ALLOW_SKIP" != "1" ]; then exit 1; fi diff --git a/test/test.mk b/test/test.mk @@ -77,6 +77,7 @@ TEST_TARGETS = \ test-smoke-x64 \ test-toy \ test-wasm \ + test-wasm-c \ test-wasm-front \ test-wasm-target \ test-wasm-toy \ @@ -135,6 +136,17 @@ test-cbackend: bin test-wasm-toy: bin @CFREE_TEST_PATHS=W CFREE_TEST_ALLOW_SKIP=1 CFREE=$(abspath $(BIN)) sh test/toy/run.sh +# test-wasm-c: opt-in C -> Wasm -> JIT roundtrip, the C-frontend analogue of +# test-wasm-toy. Runs the test/parse corpus under the W path (compile +# -target wasm32-none, then `cfree run -e test_main` the .wasm, which routes +# back through the lang/wasm frontend to native CG). The C corpus exercises +# far more of the language than the toy corpus, so expect many SKIPs for +# not-yet-implemented Wasm lowerings; the target makes that progress visible +# without adding noise to the default `test` summary. Drop +# `CFREE_TEST_ALLOW_SKIP=1` once the corpus is mostly green. +test-wasm-c: bin $(PARSE_RUNNER) + @CFREE_TEST_PATHS=W CFREE_TEST_ALLOW_SKIP=1 CFREE=$(abspath $(BIN)) bash test/parse/run.sh + test-pp: test-pp-ok test-pp-err test-pp-ok: bin diff --git a/test/toy/run.sh b/test/toy/run.sh @@ -31,7 +31,8 @@ # ./run.sh [name_filter] [paths] # CFREE_TEST_FILTER / CFREE_TEST_PATHS, where paths is a subset of "RLXCW". # X is opt-in cross-arch cc+ld+exec for aa64, x64, and rv64. -# C is opt-in C-source emit; W is opt-in Wasm roundtrip; default paths are "RL". +# C and W run only at O0 even when included with other opt levels. +# Default paths are "RLCW"; override with CFREE_TEST_PATHS. # CFREE_TOY_OPT_LEVELS selects optimization levels, default "0 1 2". set -u @@ -42,7 +43,7 @@ BUILD_DIR="$ROOT/build/test/toy" CFREE="${CFREE:-$ROOT/build/cfree}" FILTER="${1:-${CFREE_TEST_FILTER:-}}" -PATHS="${2:-${CFREE_TEST_PATHS:-RL}}" +PATHS="${2:-${CFREE_TEST_PATHS:-RLCW}}" case "$PATHS" in *R*) RUN_R=1;; *) RUN_R=0;; esac case "$PATHS" in *L*) RUN_L=1;; *) RUN_L=0;; esac case "$PATHS" in *X*) RUN_X=1;; *) RUN_X=0;; esac