kit

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

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'