kit

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

redundant_copy_ext.sh (3375B)


      1 #!/usr/bin/env bash
      2 # Structural checks for the -O1 redundant copy / extension canonicalizations:
      3 #
      4 #   A. simplify_addr_of:  addr_of [base + 0] (the `&*p` / `p+0` idiom) folds to
      5 #      a copy, so it no longer lowers to a `add base, #0` register move that
      6 #      copy-prop must then chase.
      7 #   B. convert_noop:      a same-width, same-class convert (e.g. a pointer
      8 #      bitcast `int* -> char*`) folds to a copy that propagates away.
      9 #   C. try_combine_exts:  a ZEXT of a plain (zero-extending) narrow load is
     10 #      redundant -- the load already cleared the upper bits -- so it collapses
     11 #      to a copy and usually disappears.
     12 #
     13 # All three are local, target-agnostic, and keep -O1 linear. The checks below
     14 # pin the resulting disassembly on aarch64 (the reference backend), where the
     15 # patterns have stable mnemonics (`add xN, xM, #0`, `uxtb wD, wS` after a
     16 # zero-extending `ldrb`).
     17 set -euo pipefail
     18 
     19 ROOT="$(cd "$(dirname "$0")/../.." && pwd)"
     20 KIT="${KIT:-$ROOT/build/kit}"
     21 WORK="$ROOT/build/test/opt/redundant_copy_ext"
     22 mkdir -p "$WORK"
     23 
     24 SRC="$WORK/case.c"
     25 cat > "$SRC" <<'EOF'
     26 struct T { long a, b; };
     27 /* A: struct copy through `&*p` -- the frontend records addr_of[base+0]. */
     28 void copy_struct(struct T *d, struct T *s) { *d = *s; }
     29 /* B: a pointer bitcast that records a same-width convert. */
     30 unsigned char *as_bytes(unsigned long *p) { return (unsigned char *)p; }
     31 /* C: integer promotion of a freshly loaded narrow unsigned value. */
     32 int low_nibble_is_four(const unsigned char *p) { return (p[0] & 0xf) == 4; }
     33 EOF
     34 
     35 OBJ="$WORK/case.o"
     36 "$KIT" cc -target aarch64-linux-gnu -O1 -std=c11 -c "$SRC" \
     37   -o "$OBJ" > "$WORK/cc.out" 2>&1
     38 "$KIT" objdump -d "$OBJ" > "$WORK/dis.out" 2>&1
     39 
     40 fn_body() { # $1 = symbol name -> stdout body
     41   awk -v want="$1" '
     42     $0 ~ ("^[0-9a-f]+ <" want ">:") { in_fn = 1; next }
     43     /^[0-9a-f]+ </ { in_fn = 0 }
     44     in_fn { print }
     45   ' "$WORK/dis.out"
     46 }
     47 
     48 fail() {
     49   printf 'redundant_copy_ext FAILED: %s\n' "$1" >&2
     50   printf '  --- disassembly ---\n' >&2
     51   sed 's/^/  | /' "$WORK/dis.out" >&2
     52   exit 1
     53 }
     54 
     55 # A: no `add xN, xM, #0` move-as-add anywhere (every copy_struct / as_bytes
     56 #    address pass should be a real load/store or a copy that propagated away).
     57 if grep -Eq 'add\sx[0-9]+, x[0-9]+, #0$' "$WORK/dis.out"; then
     58   fail "found 'add xN, xM, #0' (unfolded addr_of[base+0] copy)"
     59 fi
     60 
     61 # B: as_bytes is a pure pointer bitcast -- the whole body is prologue/epilogue
     62 #    plus a single move of the argument into the return register; there must be
     63 #    no convert/extend instruction for the cast.
     64 B="$(fn_body _as_bytes)"
     65 [ -n "$B" ] || B="$(fn_body as_bytes)"
     66 [ -n "$B" ] || fail "as_bytes not found in disassembly"
     67 if printf '%s\n' "$B" | grep -Eq '\b(uxtb|uxth|uxtw|sxtb|sxth|sxtw)\b'; then
     68   fail "as_bytes pointer bitcast emitted an extension"
     69 fi
     70 
     71 # C: low_nibble_is_four loads a byte (zero-extending ldrb) and must NOT follow
     72 #    it with a redundant uxtb -- the ZEXT collapsed into the load.
     73 C="$(fn_body _low_nibble_is_four)"
     74 [ -n "$C" ] || C="$(fn_body low_nibble_is_four)"
     75 [ -n "$C" ] || fail "low_nibble_is_four not found in disassembly"
     76 printf '%s\n' "$C" | grep -Eq '\bldrb\b' || fail "expected a ldrb in low_nibble_is_four"
     77 if printf '%s\n' "$C" | grep -Eq '\buxtb\b'; then
     78   fail "redundant uxtb after zero-extending ldrb survived"
     79 fi
     80 
     81 printf 'redundant_copy_ext: OK (addr_of[base+0], pointer bitcast, zext-of-load)\n'