kit

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

redundant_frame_sub.sh (3224B)


      1 #!/usr/bin/env bash
      2 # Structural check for the -O1 local frame-address `sub`-CSE (O1.md W1a).
      3 #
      4 # An `IR_ADDR_OF` of a frame-local materializes a frame-slot address into a
      5 # register; under the W1.1 x29-at-bottom layout aarch64 builds it as a positive
      6 # `add xN, x29, #k` off the frame base. Two back-to-back addr-of's of the *same*
      7 # local recompute the identical `add xN, x29, #k`. The W1a peephole in
      8 # src/opt/pass_combine.c (mir_combine) tracks the still-live earlier producer and
      9 # rewrites the recompute into a register move (`mov xN, xM`), so the second
     10 # address build vanishes. (Before W1.1 the build was a negative `sub xN,x29,#k`;
     11 # W1.1 made frame addressing positive, but the W1a CSE still applies to the add.)
     12 #
     13 # This pins the resulting disassembly on aarch64 (the reference backend), where
     14 # the pattern has a stable mnemonic. Each local is addressed twice as adjacent
     15 # call arguments; with the peephole only ONE `add xN, x29, #k` survives per
     16 # distinct constant K, and the duplicate becomes a `mov`.
     17 set -euo pipefail
     18 
     19 ROOT="$(cd "$(dirname "$0")/../.." && pwd)"
     20 KIT="${KIT:-$ROOT/build/kit}"
     21 WORK="$ROOT/build/test/opt/redundant_frame_sub"
     22 mkdir -p "$WORK"
     23 
     24 SRC="$WORK/case.c"
     25 cat > "$SRC" <<'EOF'
     26 extern void sink4(char *, char *, char *, char *);
     27 /* Two distinct locals at frame offsets past stur's -256 range; each is passed
     28  * twice as adjacent arguments, so the frontend records two IR_ADDR_OF of the
     29  * same slot back-to-back. Without W1a each lowers to its own `sub xN,x29,#k`. */
     30 void g(void) {
     31   char a[600], b[600];
     32   sink4(a, a, b, b);
     33 }
     34 EOF
     35 
     36 OBJ="$WORK/case.o"
     37 "$KIT" cc -target aarch64-linux-gnu -O1 -std=c11 -c "$SRC" \
     38   -o "$OBJ" > "$WORK/cc.out" 2>&1
     39 "$KIT" objdump -d "$OBJ" > "$WORK/dis.out" 2>&1
     40 
     41 fn_body() { # $1 = symbol name -> stdout body
     42   awk -v want="$1" '
     43     $0 ~ ("^[0-9a-f]+ <" want ">:") { in_fn = 1; next }
     44     /^[0-9a-f]+ </ { in_fn = 0 }
     45     in_fn { print }
     46   ' "$WORK/dis.out"
     47 }
     48 
     49 fail() {
     50   printf 'redundant_frame_sub FAILED: %s\n' "$1" >&2
     51   printf '  --- disassembly ---\n' >&2
     52   sed 's/^/  | /' "$WORK/dis.out" >&2
     53   exit 1
     54 }
     55 
     56 B="$(fn_body _g)"
     57 [ -n "$B" ] || B="$(fn_body g)"
     58 [ -n "$B" ] || fail "g not found in disassembly"
     59 
     60 # For each distinct constant K appearing in `add xN, x29, #K`, the address is
     61 # built exactly once; a back-to-back recompute of the same K must NOT survive.
     62 # Collect the K constants and assert no duplicates.
     63 KS="$(printf '%s\n' "$B" | grep -oE 'add[[:space:]]+x[0-9]+, x29, #[0-9]+' \
     64        | grep -oE '#[0-9]+$' | sort)"
     65 [ -n "$KS" ] || fail "expected at least one 'add xN, x29, #k' frame-address build"
     66 
     67 DUP="$(printf '%s\n' "$KS" | uniq -d || true)"
     68 if [ -n "$DUP" ]; then
     69   fail "duplicate frame-address build survived (add xN, x29, #k recomputed for: $DUP)"
     70 fi
     71 
     72 # Sanity: the de-duplicated address must be reused via a register move, so the
     73 # body should contain at least one `mov xN, xM` (the CSE'd copy) — confirms the
     74 # peephole rewrote the recompute rather than the case simply not arising.
     75 if ! printf '%s\n' "$B" | grep -Eq 'mov[[:space:]]+x[0-9]+, x[0-9]+'; then
     76   fail "expected a 'mov xN, xM' reusing the CSE'd frame address"
     77 fi
     78 
     79 printf 'redundant_frame_sub: OK (no duplicate add xN,x29,#k; address reused via mov)\n'