zero_arg.sh (2272B)
1 #!/usr/bin/env bash 2 # Behavioral check for the O1 "zero through a temp" call-arg wart (PERCALL.md 3 # item 3). A pointer-typed null argument (`(void*)0`) introduces an int->ptr 4 # IR_CONVERT between the constant's `load_imm` and the call arg. At -O1 the 5 # arg-register hint reaches the convert's def but not its load_imm source, so 6 # the source lands in a scratch (x8) and the convert emits `mov x0, x8` -- 7 # routing each zero through a temp: 8 # 9 # movz x8, 0x0 ; mov x0, x8 ; movz x8, 0x0 ; mov x1, x8 (4 insns) 10 # 11 # Optimal is `movz x0, 0x0 ; movz x1, 0x0` (2 insns, no temp). This test 12 # asserts the args are materialized directly into the arg registers. 13 set -euo pipefail 14 15 ROOT="$(cd "$(dirname "$0")/../.." && pwd)" 16 KIT="${KIT:-$ROOT/build/kit}" 17 WORK="$ROOT/build/test/opt/zero_arg" 18 mkdir -p "$WORK" 19 20 SRC="$WORK/leaf.c" 21 cat > "$SRC" <<'EOF' 22 #define NULL ((void*)0) 23 typedef struct tn { struct tn* l; struct tn* r; } treeNode; 24 treeNode* NewTreeNode(treeNode* left, treeNode* right); 25 treeNode* leaf(void) { return NewTreeNode(NULL, NULL); } 26 EOF 27 28 "$KIT" cc -target aarch64-linux-gnu -O1 -std=c99 -c "$SRC" \ 29 -o "$WORK/leaf.o" > "$WORK/cc.out" 2>&1 30 "$KIT" objdump -d "$WORK/leaf.o" > "$WORK/dis.out" 2>&1 31 32 # Slice out the leaf() function body. 33 awk ' 34 /^[0-9a-f]+ <leaf>:/ { in_fn = 1; next } 35 /^[0-9a-f]+ </ { in_fn = 0 } 36 in_fn { print } 37 ' "$WORK/dis.out" > "$WORK/leaf.dis" 38 39 fail() { 40 printf 'zero-arg check FAILED: %s\n' "$1" >&2 41 sed 's/^/ | /' "$WORK/leaf.dis" >&2 42 exit 1 43 } 44 45 # The wart: a register-to-register move into an arg register (the zero routed 46 # through a scratch temp). Optimal codegen materializes the constant straight 47 # into the arg reg, so there must be no `mov x0, x<n>` / `mov x1, x<n>`. 48 # (`movz x0, ...` is a separate mnemonic and is not matched by `\bmov x`.) 49 if grep -Eq '\bmov[[:space:]]+x[01],[[:space:]]*x[0-9]' "$WORK/leaf.dis"; then 50 fail 'arg zero routed through a scratch temp (mov x0/x1, x<n>)' 51 fi 52 53 # Both args must be loaded directly with movz into x0 and x1. 54 if ! grep -Eq '\bmovz[[:space:]]+x0,' "$WORK/leaf.dis"; then 55 fail 'arg x0 not materialized directly (movz x0, ...)' 56 fi 57 if ! grep -Eq '\bmovz[[:space:]]+x1,' "$WORK/leaf.dis"; then 58 fail 'arg x1 not materialized directly (movz x1, ...)' 59 fi 60 61 printf 'zero-arg: ok\n'