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