kit

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

roundtrip_toy.sh (6377B)


      1 #!/usr/bin/env bash
      2 # test/asm/roundtrip_toy.sh — L2 exec round-trip over the Toy corpus (native),
      3 # on the shared corpus harness (test/lib/kit_corpus.sh).
      4 #
      5 # The Toy frontend exercises the full CG op set, and each case carries an
      6 # exit-code oracle (test/toy/cases/<name>.expected). This lane reuses that
      7 # corpus for free round-trip coverage far beyond the hand-written
      8 # test/asm/roundtrip/ set: for every case, compare the DIRECT compile to the
      9 # round-tripped one and require the same exit code.
     10 #
     11 # One lane (L2) emitting two exec sub-results over the re-assembled object,
     12 # both compared to the case's exit-code oracle (test/toy/cases/<name>.expected,
     13 # default 0):
     14 #     /run:  kit cc -S | kit as | kit run <obj>    (in-process JIT)
     15 #     /ld:   kit cc -S | kit as | kit ld | ./a.out (native link + exec)
     16 #
     17 # Native target (aarch64 macOS here): kit run propagates main()'s return as
     18 # the process exit, so the oracle is the exit code. This found a real miscompile
     19 # (a multiply-high the disassembler couldn't decode, dropped by `as` until the
     20 # `.inst` fix) that the hand corpus never reached.
     21 #
     22 # Opt levels: KIT_TEST_OPTS (default "O0 O1"). Each case runs at every level.
     23 #
     24 # Any case that hits a `cc -S` symbolizer gap is quarantined via a whole-case
     25 # <name>.skip-style entry in SKIP below so the lane stays green and gates
     26 # regressions. Opt-in.
     27 #
     28 # Every lane hook writes only under $KIT_WORK and records via kit_*, so the runner
     29 # is parallel-safe (KIT_ASM_PARALLEL flips dispatch); the /run-then-/ld
     30 # ordering is preserved inside the lane body.
     31 set -u
     32 
     33 ROOT="$(cd "$(dirname "$0")/../.." && pwd)"
     34 export KIT_LIB_DIR="$ROOT/test/lib"
     35 . "$ROOT/test/lib/kit_corpus.sh"
     36 
     37 KIT_BIN="${KIT:-$ROOT/build/kit}"
     38 CASES="$ROOT/test/toy/cases"
     39 BUILD_DIR="$ROOT/build/test/asm/roundtrip_toy"
     40 
     41 # Opt axis. KIT_TEST_OPTS carries the "O"-prefixed levels (e.g. "O0 O1"); the
     42 # engine matrix wants the bare digits, and the lane builds "-O<level>".
     43 OPTS="${KIT_TEST_OPTS:-O0 O1}"
     44 OPT_LEVELS=""
     45 for _o in $OPTS; do OPT_LEVELS="$OPT_LEVELS ${_o#O}"; done
     46 
     47 FILTER="${1:-${KIT_TEST_FILTER:-}}"
     48 export KIT_TEST_FILTER="$FILTER"
     49 
     50 PAR="${KIT_ASM_PARALLEL:-1}"
     51 
     52 # Whole-case SKIP set (known cc -S symbolizer gaps). Quarantines a case on a
     53 # *separate*, known gap so the lane stays green and gates regressions:
     54 # - 141_threadlocal_mutate: a thread-local access emits an unsymbolized
     55 #   `adrp x, 0x0` (the TLS GOT/descriptor reloc is not yet symbolized in cc -S),
     56 #   which `as` rejects ("adr/adrp: symbol required"). This is TLS symbolization,
     57 #   tracked separately from named-section round-trip. See
     58 #   doc/ASM_ROUNDTRIP_TESTING.md.
     59 # Named sections now round-trip (closed 118_decl_extra_attrs): cc -S emits the
     60 # section with its "flags"/@type/entsize in GNU-as syntax and `as` reconstructs
     61 # it.
     62 SKIP="141_threadlocal_mutate"
     63 
     64 # strip the leading "<path>: " prefix off a diagnostic's first line.
     65 rt_diag() { head -n1 "$1" 2>/dev/null | sed 's|.*: ||'; }
     66 
     67 # KIT_READ_CASE hook: apply the whole-case SKIP quarantine. The engine already
     68 # reads <name>.expected into KIT_EXPECTED (default 0); we just mask it to a byte
     69 # to match the original `exp=$((exp & 255))`.
     70 rt_read_case() {
     71     case " $SKIP " in
     72         *" $KIT_BASE "*) KIT_SKIP_CASE="known cc -S symbolizer gap"; return ;;
     73     esac
     74     KIT_EXPECTED=$(( KIT_EXPECTED & 255 ))
     75 }
     76 
     77 # ---- the single L2 lane ----------------------------------------------------
     78 # cc -S | as, then run the re-assembled object two ways, each compared to the
     79 # exit-code oracle. /run uses the in-process JIT; /ld links a real native
     80 # executable and runs it through the OS loader. Native host only (no -target).
     81 kit_lane_L2() {
     82     local s="$KIT_WORK/s.s" rt="$KIT_WORK/rt.o"
     83     # Shared cc -S | as steps. A failure here is a SINGLE result for the case
     84     # (matching the original's one-fail-then-skip-rest behavior), not one per
     85     # sub-result — the /run and /ld sub-results only exist once an object does.
     86     if ! "$KIT_BIN" cc -S "-O$KIT_OPT" "$KIT_SRC" -o "$s" 2>"$KIT_WORK/ccs.err"; then
     87         kit_fail "$KIT_NAME cc-S" "cc -S failed"; return
     88     fi
     89     if ! "$KIT_BIN" as "$s" -o "$rt" 2>"$KIT_WORK/as.err"; then
     90         kit_fail "$KIT_NAME as" "as: $(rt_diag "$KIT_WORK/as.err")"; return
     91     fi
     92 
     93     # Sub-result /run: kit run JIT-links and executes the object in-process.
     94     "$KIT_BIN" run "$rt" >"$KIT_WORK/out" 2>"$KIT_WORK/run.err"; local rc=$?
     95     if [ -s "$KIT_WORK/run.err" ]; then
     96         kit_fail "$KIT_NAME/run" "$(rt_diag "$KIT_WORK/run.err")"
     97     elif [ "$rc" -eq "$KIT_EXPECTED" ]; then
     98         kit_pass "$KIT_NAME/run"
     99     else
    100         kit_fail "$KIT_NAME/run" "exit $rc != $KIT_EXPECTED"
    101     fi
    102 
    103     # Sub-result /ld: kit ld links a real native executable; run it via the OS
    104     # loader and compare exit. Exercises kit ld (layout + relocation + image
    105     # emit) and a real process exit — none of which the JIT 'run' path covers.
    106     if ! "$KIT_BIN" ld "$rt" -o "$KIT_WORK/a.out" 2>"$KIT_WORK/ld.err" || [ -s "$KIT_WORK/ld.err" ]; then
    107         kit_fail "$KIT_NAME/ld" "$(rt_diag "$KIT_WORK/ld.err")"; return
    108     fi
    109     chmod +x "$KIT_WORK/a.out" 2>/dev/null || true
    110     "$KIT_WORK/a.out" >"$KIT_WORK/ldout" 2>"$KIT_WORK/ldrun.err"; local ldrc=$?
    111     if [ -s "$KIT_WORK/ldrun.err" ]; then
    112         kit_fail "$KIT_NAME/ld" "$(rt_diag "$KIT_WORK/ldrun.err")"
    113     elif [ "$ldrc" -eq "$KIT_EXPECTED" ]; then
    114         kit_pass "$KIT_NAME/ld"
    115     else
    116         kit_fail "$KIT_NAME/ld" "exit $ldrc != $KIT_EXPECTED"
    117     fi
    118 }
    119 
    120 # ---- drive the corpus ------------------------------------------------------
    121 
    122 if [ ! -x "$KIT_BIN" ]; then
    123     printf 'roundtrip-toy: FATAL kit missing — run "make bin"\n' >&2
    124     exit 1
    125 fi
    126 mkdir -p "$BUILD_DIR"
    127 
    128 # Skips are informational (e.g. the 141_threadlocal_mutate quarantine), as in
    129 # the original which exited 0 regardless of skips — do not gate on skips.
    130 KIT_SKIP_IS_FAILURE=0
    131 
    132 # Native host, no -target. The L2 lane uses no tuple-specific behavior; pin a
    133 # single nominal tuple so the engine runs each case once per opt level.
    134 KIT_LABEL=test-asm-roundtrip-toy KIT_BUILD_DIR="$BUILD_DIR" \
    135   KIT_CORPUS_GLOBS="$CASES/*.toy" KIT_CORPUS_EXT=toy KIT_SIDECAR_DIR="$CASES" \
    136   KIT_LANES="L2" KIT_OPT_LEVELS="$OPT_LEVELS" KIT_TUPLES="native-native" \
    137   KIT_TARGETS_EXT="" KIT_READ_CASE=rt_read_case KIT_PARALLELIZABLE="$PAR" \
    138   kit_corpus_run
    139 
    140 kit_summary test-asm-roundtrip-toy
    141 kit_exit