run.sh (5598B)
1 #!/usr/bin/env bash 2 # Behavioral check for the O1 tiny-function inliner. 3 # 4 # Compiles a toy program where __user_main calls the tiny helper add1(x)=x+1, 5 # and asserts that at -O1 the `bl add1` is gone from __user_main (the helper 6 # was inlined). Also confirms the program still computes the right value via 7 # the in-process JIT. 8 set -euo pipefail 9 10 ROOT="$(cd "$(dirname "$0")/../.." && pwd)" 11 KIT="${KIT:-$ROOT/build/kit}" 12 SRC="$ROOT/test/toy/cases/135_inline_cleanup_quality.toy" 13 WORK="$ROOT/build/test/opt/inline" 14 mkdir -p "$WORK" 15 16 "$KIT" cc -target aarch64-linux-gnu -O1 -c "$SRC" \ 17 -o "$WORK/x.o" > "$WORK/cc.out" 2>&1 18 "$KIT" objdump -d "$WORK/x.o" > "$WORK/dis.out" 2>&1 19 20 # Slice out the __user_main function body. 21 awk ' 22 /^[0-9a-f]+ <__user_main>:/ { in_fn = 1; next } 23 /^[0-9a-f]+ </ { in_fn = 0 } 24 in_fn { print } 25 ' "$WORK/dis.out" > "$WORK/user_main.dis" 26 27 if grep -Eq '\bbl\b.*add1' "$WORK/user_main.dis"; then 28 printf 'tiny-inline check FAILED: add1 was not inlined into __user_main:\n' >&2 29 sed 's/^/ | /' "$WORK/user_main.dis" >&2 30 exit 1 31 fi 32 33 # The inlined body must actually be present (an add of the constant), i.e. the 34 # function is more than just a tail jump. 35 if ! grep -Eq '\badd\b' "$WORK/user_main.dis"; then 36 printf 'tiny-inline check FAILED: inlined add1 body missing from __user_main:\n' >&2 37 sed 's/^/ | /' "$WORK/user_main.dis" >&2 38 exit 1 39 fi 40 41 # Runtime correctness through the in-process JIT: main returns add1(41) == 42. 42 for opt in -O0 -O1; do 43 if "$KIT" run "$opt" -e main "$SRC" > /dev/null 2>&1; then 44 rc=0 45 else 46 rc=$? 47 fi 48 if [ "$rc" -ne 42 ]; then 49 printf 'tiny-inline runtime check FAILED at %s: exit %d (want 42)\n' \ 50 "$opt" "$rc" >&2 51 exit 1 52 fi 53 done 54 55 cat > "$WORK/dead_jt.c" <<'EOF' 56 #include <kit/cg.h> 57 int p(void) { return 0; } 58 EOF 59 "$KIT" cc -O1 -I "$ROOT/include" -c "$WORK/dead_jt.c" \ 60 -o "$WORK/dead_jt.o" > "$WORK/dead_jt.cc.out" 2>&1 61 "$KIT" nm "$WORK/dead_jt.o" > "$WORK/dead_jt.nm" 2>&1 62 if grep -q '\.Lkit_jt' "$WORK/dead_jt.nm"; then 63 printf 'O1 deferred jump-table check FAILED: dead inline leaked .Lkit_jt:\n' >&2 64 sed 's/^/ | /' "$WORK/dead_jt.nm" >&2 65 exit 1 66 fi 67 68 cat > "$WORK/live_jt.c" <<'EOF' 69 int p(int x) { 70 switch (x) { 71 case 0: return 3; 72 case 1: return 4; 73 case 2: return 5; 74 case 3: return 6; 75 case 4: return 7; 76 case 5: return 8; 77 case 6: return 9; 78 case 7: return 10; 79 default: return 11; 80 } 81 } 82 EOF 83 "$KIT" cc -O1 -c "$WORK/live_jt.c" \ 84 -o "$WORK/live_jt.o" > "$WORK/live_jt.cc.out" 2>&1 85 "$KIT" nm "$WORK/live_jt.o" > "$WORK/live_jt.nm" 2>&1 86 if grep -Eq '[[:space:]][uU][[:space:]]+\.Lkit_jt' "$WORK/live_jt.nm" || 87 ! grep -Eq '[[:space:]][dDrR][[:space:]]+\.Lkit_jt' "$WORK/live_jt.nm"; then 88 printf 'O1 deferred jump-table check FAILED: live switch table not defined:\n' >&2 89 sed 's/^/ | /' "$WORK/live_jt.nm" >&2 90 exit 1 91 fi 92 93 cat > "$WORK/dead_ro.c" <<'EOF' 94 static inline const char *q(void) { return "abc"; } 95 int p(void) { return 0; } 96 EOF 97 "$KIT" cc -O1 -c "$WORK/dead_ro.c" \ 98 -o "$WORK/dead_ro.o" > "$WORK/dead_ro.cc.out" 2>&1 99 "$KIT" nm "$WORK/dead_ro.o" > "$WORK/dead_ro.nm" 2>&1 100 if grep -q '\.Lkit_ro' "$WORK/dead_ro.nm"; then 101 printf 'O1 deferred const-data check FAILED: dead inline leaked .Lkit_ro:\n' >&2 102 sed 's/^/ | /' "$WORK/dead_ro.nm" >&2 103 exit 1 104 fi 105 106 cat > "$WORK/live_ro.c" <<'EOF' 107 extern int sink(const char *); 108 int p(void) { return sink("abc"); } 109 EOF 110 "$KIT" cc -O1 -c "$WORK/live_ro.c" \ 111 -o "$WORK/live_ro.o" > "$WORK/live_ro.cc.out" 2>&1 112 "$KIT" nm "$WORK/live_ro.o" > "$WORK/live_ro.nm" 2>&1 113 if grep -Eq '[[:space:]][uU][[:space:]]+\.Lkit_ro' "$WORK/live_ro.nm" || 114 ! grep -Eq '[[:space:]][dDrR][[:space:]]+\.Lkit_ro' "$WORK/live_ro.nm"; then 115 printf 'O1 deferred const-data check FAILED: live const data not defined:\n' >&2 116 sed 's/^/ | /' "$WORK/live_ro.nm" >&2 117 exit 1 118 fi 119 120 cat > "$WORK/live_label_addr.c" <<'EOF' 121 int p(void) { L: return &&L != 0 ? 42 : 7; } 122 int q(void) { void *x = &&L; return x != 0 ? 11 : 3; L: return 5; } 123 EOF 124 "$KIT" cc -O1 -c "$WORK/live_label_addr.c" \ 125 -o "$WORK/live_label_addr.o" > "$WORK/live_label_addr.cc.out" 2>&1 126 "$KIT" nm "$WORK/live_label_addr.o" > "$WORK/live_label_addr.nm" 2>&1 127 if grep -Eq '[[:space:]][uU][[:space:]]+\.Lcfblk' "$WORK/live_label_addr.nm"; then 128 printf 'O1 label-address check FAILED: live &&label target is undefined:\n' >&2 129 sed 's/^/ | /' "$WORK/live_label_addr.nm" >&2 130 exit 1 131 fi 132 if "$KIT" run -O1 -e p "$WORK/live_label_addr.c" \ 133 > "$WORK/live_label_addr.run.out" 2>&1; then 134 rc=0 135 else 136 rc=$? 137 fi 138 if [ "$rc" -ne 42 ]; then 139 printf 'O1 label-address runtime check FAILED: exit %d (want 42)\n' "$rc" >&2 140 sed 's/^/ | /' "$WORK/live_label_addr.run.out" >&2 141 exit 1 142 fi 143 if "$KIT" run -O1 -e q "$WORK/live_label_addr.c" \ 144 > "$WORK/live_label_addr_q.run.out" 2>&1; then 145 rc=0 146 else 147 rc=$? 148 fi 149 if [ "$rc" -ne 11 ]; then 150 printf 'O1 label-address runtime check FAILED: q exit %d (want 11)\n' \ 151 "$rc" >&2 152 sed 's/^/ | /' "$WORK/live_label_addr_q.run.out" >&2 153 exit 1 154 fi 155 156 cat > "$WORK/dead_inline_label_addr.c" <<'EOF' 157 static inline void *q(void) { L: return &&L; } 158 int p(void) { return 0; } 159 EOF 160 "$KIT" cc -O1 -c "$WORK/dead_inline_label_addr.c" \ 161 -o "$WORK/dead_inline_label_addr.o" \ 162 > "$WORK/dead_inline_label_addr.cc.out" 2>&1 163 "$KIT" nm "$WORK/dead_inline_label_addr.o" \ 164 > "$WORK/dead_inline_label_addr.nm" 2>&1 165 if grep -q '\.Lcfblk' "$WORK/dead_inline_label_addr.nm"; then 166 printf 'O1 label-address check FAILED: dead inline leaked .Lcfblk:\n' >&2 167 sed 's/^/ | /' "$WORK/dead_inline_label_addr.nm" >&2 168 exit 1 169 fi 170 171 printf 'tiny-inline: ok\n'