phase0_guardrails.sh (7297B)
1 #!/usr/bin/env bash 2 set -euo pipefail 3 4 ROOT="$(cd "$(dirname "$0")/../.." && pwd)" 5 BIN="${KIT_BIN:-$ROOT/build/kit}" 6 TMP="${TMPDIR:-/tmp}/kit-opt-phase0.$$" 7 8 mkdir -p "$TMP" 9 trap 'rm -rf "$TMP"' EXIT 10 11 write_branch_liveness() { 12 cat >"$TMP/branch_liveness.c" <<'SRC' 13 int main() { 14 int x = 7; 15 int y = 0; 16 if (x) 17 y = x + 3; 18 else 19 y = x + 5; 20 return y == 10 ? 0 : 1; 21 } 22 SRC 23 } 24 25 write_call_clobber() { 26 cat >"$TMP/call_clobber.c" <<'SRC' 27 static int bump(int x) { return x + 1; } 28 int main() { 29 int a = 3; 30 int b = 5; 31 int c = bump(a); 32 return (a == 3 && b == 5 && c == 4) ? 0 : 1; 33 } 34 SRC 35 } 36 37 write_scalar_local() { 38 cat >"$TMP/scalar_local.c" <<'SRC' 39 int main() { 40 int x = 40; 41 x = x + 2; 42 return x == 42 ? 0 : 1; 43 } 44 SRC 45 } 46 47 write_late_addrof_join() { 48 cat >"$TMP/late_addrof_join.c" <<'SRC' 49 int main() { 50 int x = 5; 51 if (x == 5) 52 x = 40; 53 else 54 x = 1; 55 int *p = &x; 56 *p = *p + 2; 57 return x == 42 ? 0 : 1; 58 } 59 SRC 60 } 61 62 write_spills() { 63 { 64 printf 'int main() {\n' 65 for i in $(seq 0 39); do 66 printf ' int a%d = %d;\n' "$i" "$i" 67 done 68 printf ' int s = 0;\n' 69 for i in $(seq 0 39); do 70 printf ' s += a%d;\n' "$i" 71 done 72 printf ' return s == 780 ? 0 : 1;\n' 73 printf '}\n' 74 } >"$TMP/spills.c" 75 } 76 77 write_many_small_functions() { 78 { 79 for i in $(seq 0 31); do 80 printf 'static int f%d(int x) { return x + %d; }\n' "$i" "$i" 81 done 82 printf 'int main() {\n int s = 0;\n' 83 for i in $(seq 0 31); do 84 printf ' s += f%d(1);\n' "$i" 85 done 86 printf ' return s == 528 ? 0 : 1;\n}\n' 87 } >"$TMP/many_small_functions.c" 88 } 89 90 write_large_straight_line() { 91 local expected=0 92 local x=3 93 { 94 printf 'int main() {\n int s = 0;\n' 95 for i in $(seq 0 127); do 96 expected=$((expected + i * ((x + i) & 7))) 97 printf ' s += %d * ((%d + %d) & 7);\n' "$i" "$x" "$i" 98 done 99 printf ' return s == %d ? 0 : 1;\n}\n' "$expected" 100 } >"$TMP/large_straight_line.c" 101 } 102 103 write_many_stack_args_o1() { 104 local nargs=96 105 local expected=0 106 { 107 printf 'static int sink_many(' 108 for i in $(seq 0 $((nargs - 1))); do 109 if [ "$i" -gt 0 ]; then printf ','; fi 110 printf 'int a%d' "$i" 111 done 112 printf ') {\n int s = 0;\n' 113 for i in $(seq 0 $((nargs - 1))); do 114 local p=$(( (i * 17 + 3) % 101 + 1 )) 115 expected=$(( (expected + ((5 + i) & 255) * p) & 255 )) 116 printf ' s = (s + a%d * %d) & 255;\n' "$i" "$p" 117 done 118 printf ' return s;\n}\n' 119 printf 'int main() {\n' 120 for i in $(seq 0 $((nargs - 1))); do 121 printf ' int v%d = (5 + %d) & 255;\n' "$i" "$i" 122 done 123 printf ' int s = sink_many(' 124 for i in $(seq 0 $((nargs - 1))); do 125 if [ "$i" -gt 0 ]; then printf ','; fi 126 printf 'v%d' "$i" 127 done 128 printf ');\n' 129 printf ' return s == %d ? 0 : 1;\n' "$expected" 130 printf '}\n' 131 } >"$TMP/many_stack_args_o1.c" 132 } 133 134 write_mutable_vreg_o2() { 135 cat >"$TMP/mutable_vreg_o2.c" <<'SRC' 136 int main() { 137 int x = 40; 138 x = x + 1; 139 x = x + 1; 140 return x == 42 ? 0 : 1; 141 } 142 SRC 143 } 144 145 write_loop_phi_o2() { 146 cat >"$TMP/loop_phi_o2.c" <<'SRC' 147 int main() { 148 int x = 0; 149 int i = 0; 150 while (i < 7) { 151 x = x + i; 152 i = i + 1; 153 } 154 return x == 21 ? 0 : 1; 155 } 156 SRC 157 } 158 159 write_call_across_o2() { 160 cat >"$TMP/call_across_o2.c" <<'SRC' 161 static int bump(int x) { return x + 1; } 162 int main() { 163 int x = 10; 164 int y = bump(x); 165 x = x + y; 166 return x == 21 ? 0 : 1; 167 } 168 SRC 169 } 170 171 write_dense_switch_o2() { 172 cat >"$TMP/dense_switch_o2.c" <<'SRC' 173 int main() { 174 int x = 14; 175 switch (x) { 176 case 10: return 1; 177 case 11: return 2; 178 case 12: return 3; 179 case 13: return 4; 180 case 14: return 0; 181 case 15: return 6; 182 default: return 7; 183 } 184 } 185 SRC 186 } 187 188 write_switch_join_add_o2() { 189 cat >"$TMP/switch_join_add_o2.c" <<'SRC' 190 int main() { 191 int tag = 2; 192 int value = 0; 193 switch (tag) { 194 case 0: 195 value = 10; 196 break; 197 case 1: 198 case 2: 199 value = 40; 200 break; 201 default: 202 value = 0; 203 break; 204 } 205 return value + 2 == 42 ? 0 : 1; 206 } 207 SRC 208 } 209 210 write_inline_wrapper_o2() { 211 cat >"$TMP/inline_wrapper_o2.c" <<'SRC' 212 static int add1(int x) { return x + 1; } 213 int main() { return add1(41) == 42 ? 0 : 1; } 214 SRC 215 } 216 217 run_case() { 218 local name="$1" 219 local src="$2" 220 for opt in -O0 -O1; do 221 "$BIN" run "$opt" "$src" >/dev/null 222 done 223 printf 'phase0 %-24s O0/O1 OK\n' "$name" 224 } 225 226 run_o1_case() { 227 local name="$1" 228 local src="$2" 229 "$BIN" run -O1 "$src" >/dev/null 230 printf 'phase0 %-24s O1 OK\n' "$name" 231 } 232 233 run_o2_case() { 234 local name="$1" 235 local src="$2" 236 "$BIN" run -O2 "$src" >/dev/null 237 printf 'phase0 %-24s O2 OK\n' "$name" 238 } 239 240 run_inline_o2_case() { 241 local name="$1" 242 local src="$2" 243 local err="$TMP/${name}.metrics.err" 244 "$BIN" run --time -O2 "$src" >/dev/null 2>"$err" 245 if ! grep -q "opt.inline.inlined" "$err"; then 246 echo "phase0 $name: expected O2 inline metric" >&2 247 sed -n '1,160p' "$err" >&2 248 exit 1 249 fi 250 printf 'phase0 %-24s O2 inline OK\n' "$name" 251 } 252 253 check_metrics() { 254 local src="$TMP/branch_liveness.c" 255 local err="$TMP/metrics.err" 256 "$BIN" run --time -O1 "$src" >/dev/null 2>"$err" 257 for metric in \ 258 opt.live.blocks \ 259 opt.live.active_words \ 260 opt.live.bitset_words_touched \ 261 opt.live.dataflow_iterations \ 262 opt.live.dataflow_block_visits \ 263 opt.ranges \ 264 opt.range_points \ 265 opt.range_raw_points \ 266 opt.range_max_per_preg \ 267 opt.range_max_length \ 268 opt.range_whole_block_spans \ 269 opt.range.point_visits \ 270 opt.range.preg_scans \ 271 opt.range.live_words_touched \ 272 opt.dde.live_words_touched \ 273 opt.alloc.used_loc_words \ 274 opt.alloc.hard_loc_words \ 275 opt.alloc.stack_loc_words \ 276 opt.alloc.stack_slots \ 277 opt.alloc.hard_point_visits \ 278 opt.alloc.stack_point_visits \ 279 opt.alloc.hard_word_ors \ 280 opt.alloc.stack_word_ors \ 281 opt.alloc.hard_mark_points \ 282 opt.alloc.stack_mark_points \ 283 opt.alloc.spills \ 284 opt.rewrite.reloads \ 285 opt.rewrite.stores \ 286 opt.rewrite.inserted_insts \ 287 opt.rewrite.live_words_touched; do 288 if ! grep -q "$metric" "$err"; then 289 echo "phase0 metrics: missing $metric" >&2 290 sed -n '1,160p' "$err" >&2 291 exit 1 292 fi 293 done 294 printf 'phase0 metrics OK\n' 295 } 296 297 write_branch_liveness 298 write_call_clobber 299 write_scalar_local 300 write_late_addrof_join 301 write_spills 302 write_many_small_functions 303 write_large_straight_line 304 write_many_stack_args_o1 305 write_mutable_vreg_o2 306 write_loop_phi_o2 307 write_call_across_o2 308 write_dense_switch_o2 309 write_switch_join_add_o2 310 write_inline_wrapper_o2 311 312 run_case branch_liveness "$TMP/branch_liveness.c" 313 run_case call_clobber "$TMP/call_clobber.c" 314 run_case scalar_local "$TMP/scalar_local.c" 315 run_case late_addrof_join "$TMP/late_addrof_join.c" 316 run_case spills "$TMP/spills.c" 317 run_case many_small_functions "$TMP/many_small_functions.c" 318 run_case large_straight_line "$TMP/large_straight_line.c" 319 run_o1_case many_stack_args "$TMP/many_stack_args_o1.c" 320 run_o2_case mutable_vreg "$TMP/mutable_vreg_o2.c" 321 run_o2_case loop_phi "$TMP/loop_phi_o2.c" 322 run_o2_case call_across "$TMP/call_across_o2.c" 323 run_o2_case dense_switch "$TMP/dense_switch_o2.c" 324 run_o2_case switch_join_add "$TMP/switch_join_add_o2.c" 325 run_inline_o2_case inline_wrapper "$TMP/inline_wrapper_o2.c" 326 check_metrics 327 328 printf 'phase0 identified inline-asm stress: test/parse/cases/asm_01_grammar.c\n'