kit

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

o1_cmp_imm.sh (3438B)


      1 #!/usr/bin/env bash
      2 # Structural checks for the -O1 W6 peephole tightening (O1.md W6), in
      3 # src/opt/pass_combine.c (mir_combine):
      4 #
      5 #   A. cmp-immediate folding: a small constant that reaches a compare through a
      6 #      register (because its load_imm was separated from the cmp by a call
      7 #      barrier, so it sits in a callee-saved reg) folds into the cmp's inline
      8 #      immediate. The constant tracker is invalidated precisely (only the regs a
      9 #      call clobbers), so a constant in a callee-saved register survives the
     10 #      call and the compare becomes `cmp wN,#k` with no `movz` of that constant.
     11 #
     12 #   B. address-mode constant-add + offset fold: `add xN,xM,#k; ldr [xN,#j]`
     13 #      collapses to `ldr [xM,#k+j]` so the explicit address-build add disappears
     14 #      when it is otherwise dead.
     15 #
     16 # Both are local, target-agnostic, and keep -O1 linear. The checks pin the
     17 # resulting disassembly on aarch64 (the reference backend), where the patterns
     18 # have stable mnemonics.
     19 set -euo pipefail
     20 
     21 ROOT="$(cd "$(dirname "$0")/../.." && pwd)"
     22 KIT="${KIT:-$ROOT/build/kit}"
     23 WORK="$ROOT/build/test/opt/o1_cmp_imm"
     24 mkdir -p "$WORK"
     25 
     26 SRC="$WORK/case.c"
     27 cat > "$SRC" <<'EOF'
     28 extern int side(void);
     29 /* A: a small constant K materialized before a call (it survives in a callee-
     30  * saved register across the call), then compared. The constant must fold into
     31  * the cmp's immediate -- `cmp wN,#42` -- with no surviving `movz wM,#42`. */
     32 int cmp_after_call(int x) {
     33   const int K = 42;
     34   side();
     35   return x > K;
     36 }
     37 /* B: a base+constant add feeding a plain (no-index) load. The add should fold
     38  * into the load offset so no `add xN,xM,#16` address build survives -- just a
     39  * single `ldr xD,[xM,#...]`. */
     40 struct S { long a, b, c; };
     41 long off_fold(struct S *p) {
     42   long *q = (long *)((char *)p + 8);
     43   return *q;
     44 }
     45 EOF
     46 
     47 OBJ="$WORK/case.o"
     48 "$KIT" cc -target aarch64-linux-gnu -O1 -std=c11 -c "$SRC" \
     49   -o "$OBJ" > "$WORK/cc.out" 2>&1
     50 "$KIT" objdump -d "$OBJ" > "$WORK/dis.out" 2>&1
     51 
     52 fn_body() { # $1 = symbol name -> stdout body
     53   awk -v want="$1" '
     54     $0 ~ ("^[0-9a-f]+ <" want ">:") { in_fn = 1; next }
     55     /^[0-9a-f]+ </ { in_fn = 0 }
     56     in_fn { print }
     57   ' "$WORK/dis.out"
     58 }
     59 
     60 fail() {
     61   printf 'o1_cmp_imm FAILED: %s\n' "$1" >&2
     62   printf '  --- disassembly ---\n' >&2
     63   sed 's/^/  | /' "$WORK/dis.out" >&2
     64   exit 1
     65 }
     66 
     67 # A: cmp_after_call must compare against the immediate (`cmp wN, #42`) and must
     68 #    NOT keep a `movz wM, #42` (the constant materialization the fold removes).
     69 A="$(fn_body _cmp_after_call)"
     70 [ -n "$A" ] || A="$(fn_body cmp_after_call)"
     71 [ -n "$A" ] || fail "cmp_after_call not found"
     72 printf '%s\n' "$A" | grep -Eq 'cmp[[:space:]]+w[0-9]+, #42' \
     73   || fail "expected 'cmp wN, #42' (cmp-immediate fold did not fire)"
     74 if printf '%s\n' "$A" | grep -Eq 'movz[[:space:]]+w[0-9]+, 0x2a\b'; then
     75   fail "constant 42 still materialized with movz (cmp-imm fold incomplete)"
     76 fi
     77 
     78 # B: off_fold must load with a single ldr and a folded offset; no `add xN,xM,#8`
     79 #    address build should survive for the field offset.
     80 B="$(fn_body _off_fold)"
     81 [ -n "$B" ] || B="$(fn_body off_fold)"
     82 [ -n "$B" ] || fail "off_fold not found"
     83 printf '%s\n' "$B" | grep -Eq '\bldr\b' || fail "expected a ldr in off_fold"
     84 if printf '%s\n' "$B" | grep -Eq 'add[[:space:]]+x[0-9]+, x[0-9]+, #8\b'; then
     85   fail "explicit 'add xN,xM,#8' address build survived (offset fold did not fire)"
     86 fi
     87 
     88 printf 'o1_cmp_imm: OK (cmp wN,#k fold across barrier; add+offset fold)\n'