kit

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

aa64_tail_call.sh (3390B)


      1 #!/usr/bin/env bash
      2 # Structural aarch64 tail-call checks.
      3 #
      4 # These cases prove that realized tails are sibling calls:
      5 # - direct stack-arg tail calls reuse the caller's incoming stack-arg window
      6 # - direct tails lower to AARCH64_JUMP26 (`b`), not AARCH64_CALL26 (`bl`)
      7 # - indirect tails lower to `br`, not `blr`
      8 # - the caller frame is restored before the sibling branch
      9 set -euo pipefail
     10 
     11 ROOT="$(cd "$(dirname "$0")/../.." && pwd)"
     12 KIT="${KIT:-$ROOT/build/kit}"
     13 WORK="$ROOT/build/test/opt/aa64_tail_call"
     14 mkdir -p "$WORK"
     15 
     16 fail() {
     17   printf 'aa64-tail-call check FAILED: %s\n' "$1" >&2
     18   if [ -n "${2:-}" ] && [ -f "$2" ]; then
     19     sed 's/^/  | /' "$2" >&2
     20   fi
     21   exit 1
     22 }
     23 
     24 slice_func() {
     25   local src="$1" func="$2" out="$3"
     26   awk -v name="$func" '
     27     $0 ~ "^[0-9a-f]+ <" name ">:" { in_fn = 1; print; next }
     28     /^[0-9a-f]+ </ { in_fn = 0 }
     29     in_fn { print }
     30   ' "$src" > "$out"
     31 }
     32 
     33 compile_case() {
     34   local name="$1" src="$2"
     35   "$KIT" cc -target aarch64-linux-gnu -O1 -c "$src" \
     36     -o "$WORK/$name.o" > "$WORK/$name.cc.out" 2> "$WORK/$name.cc.err"
     37   "$KIT" objdump -d "$WORK/$name.o" \
     38     > "$WORK/$name.dis" 2> "$WORK/$name.objdump.err"
     39   "$KIT" objdump -r "$WORK/$name.o" \
     40     > "$WORK/$name.relocs" 2> "$WORK/$name.relocs.err"
     41 }
     42 
     43 compile_case direct_stack "$ROOT/test/toy/cases/25_tail_many_stack_args.toy"
     44 slice_func "$WORK/direct_stack.dis" caller "$WORK/direct_stack.caller.dis"
     45 
     46 if grep -Eq '\bbl\b.*target' "$WORK/direct_stack.caller.dis"; then
     47   fail 'direct stack-arg tail used bl target' "$WORK/direct_stack.caller.dis"
     48 fi
     49 if ! grep -Eq '\bb\b.*target.*AARCH64_JUMP26' "$WORK/direct_stack.caller.dis"; then
     50   fail 'direct stack-arg tail missing b target / AARCH64_JUMP26' \
     51     "$WORK/direct_stack.caller.dis"
     52 fi
     53 if ! grep -Eq '\bstr\b.*\[x29, #16\]' "$WORK/direct_stack.caller.dis" ||
     54    ! grep -Eq '\bstr\b.*\[x29, #24\]' "$WORK/direct_stack.caller.dis"; then
     55   fail 'direct stack-arg tail did not write caller incoming stack window' \
     56     "$WORK/direct_stack.caller.dis"
     57 fi
     58 if ! awk '
     59   /add[[:space:]]+sp, sp,/ { restored = 1 }
     60   /[[:space:]]b[[:space:]]+.*target.*AARCH64_JUMP26/ {
     61     found = 1; ok = restored; exit
     62   }
     63   END { exit(found && ok ? 0 : 1) }
     64 ' "$WORK/direct_stack.caller.dis"; then
     65   fail 'direct tail branched before restoring sp' "$WORK/direct_stack.caller.dis"
     66 fi
     67 if ! grep -Eq 'AARCH64_JUMP26[[:space:]]+target' "$WORK/direct_stack.relocs"; then
     68   fail 'direct tail relocation is not AARCH64_JUMP26' "$WORK/direct_stack.relocs"
     69 fi
     70 if grep -Eq 'AARCH64_CALL26[[:space:]]+target' "$WORK/direct_stack.relocs"; then
     71   fail 'direct tail emitted AARCH64_CALL26 relocation to target' \
     72     "$WORK/direct_stack.relocs"
     73 fi
     74 
     75 compile_case indirect "$ROOT/test/toy/cases/32_musttail_indirect.toy"
     76 slice_func "$WORK/indirect.dis" apply "$WORK/indirect.apply.dis"
     77 
     78 if grep -Eq '\bblr\b' "$WORK/indirect.apply.dis"; then
     79   fail 'indirect musttail used blr' "$WORK/indirect.apply.dis"
     80 fi
     81 if ! grep -Eq '\bbr[[:space:]]+x[0-9]+' "$WORK/indirect.apply.dis"; then
     82   fail 'indirect musttail missing br' "$WORK/indirect.apply.dis"
     83 fi
     84 if ! awk '
     85   /ldp[[:space:]]+x29, x30,/ { restored = 1 }
     86   /[[:space:]]br[[:space:]]+x[0-9]+/ { found = 1; ok = restored; exit }
     87   END { exit(found && ok ? 0 : 1) }
     88 ' "$WORK/indirect.apply.dis"; then
     89   fail 'indirect tail branched before restoring frame record' \
     90     "$WORK/indirect.apply.dis"
     91 fi
     92 
     93 printf 'aa64-tail-call: ok\n'