2 * Copyright (C) 2024 Mikulas Patocka
4 * This file is part of Ajla.
6 * Ajla is free software: you can redistribute it and/or modify it under the
7 * terms of the GNU General Public License as published by the Free Software
8 * Foundation, either version 3 of the License, or (at your option) any later
11 * Ajla is distributed in the hope that it will be useful, but WITHOUT ANY
12 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
13 * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License along with
16 * Ajla. If not, see <https://www.gnu.org/licenses/>.
19 private unit compiler.optimize.ssa;
21 uses compiler.optimize.defs;
23 fn process_pcode(pc : list(pcode_t), get_inline : fn(function) : list(pcode_t)) : list(pcode_t);
29 uses compiler.optimize.utils;
30 uses compiler.optimize.evaluate;
31 uses compiler.optimize.inline;
32 uses compiler.common.gvn;
34 fn mtos(x : var_set) : bytes
48 fn insert_instr(ctx : context, ins : instruction, pos : int) : context
50 var id := len(ctx.instrs);
52 var block := ctx.blocks[ins.bb];
53 var new_list := block.instrs[.. pos] +< id + block.instrs[pos ..];
54 ctx.blocks[ins.bb].instrs := new_list;
58 fn deactivate_arrow(ctx : context, bgi : int, pidx : int) : context
60 var p := ctx.blocks[bgi].post_list[pidx];
61 //eval debug("deleting arrow " + ntos(bgi) + "(" + ntos(pidx) + ") -> " + ntos(p));
62 if not ctx.blocks[bgi].active then
63 abort internal("deactivating an arrow from an invalid block");
64 if not ctx.blocks[p].active then
65 abort internal("deactivating an arrow to an invalid block");
67 for j := 0 to len(ctx.blocks[p].pred_list) do [
68 if ctx.blocks[p].pred_list[j] = bgi and ctx.blocks[p].pred_position[j] = pidx then [
69 ctx.blocks[p].pred_list := ctx.blocks[p].pred_list[ .. j] + ctx.blocks[p].pred_list[j + 1 ..];
70 ctx.blocks[p].pred_position := ctx.blocks[p].pred_position[ .. j] + ctx.blocks[p].pred_position[j + 1 ..];
71 for lidx := 0 to len(ctx.blocks[p].instrs) do [
72 var ins := ctx.instrs[ctx.blocks[p].instrs[lidx]];
73 if ins.opcode <> P_Phi then
75 ins.params := ins.params[.. j + 1] + ins.params[j + 2 ..];
76 ins.read_set := ins.read_set shr 1 btc 0;
77 ctx.instrs[ctx.blocks[p].instrs[lidx]] := ins;
82 ctx.blocks[bgi].post_list := ctx.blocks[bgi].post_list[ .. pidx] + ctx.blocks[bgi].post_list[pidx + 1 .. ];
83 for i := pidx to len(ctx.blocks[bgi].post_list) do [
84 var bgi_post := ctx.blocks[bgi].post_list[i];
85 var block_post := ctx.blocks[bgi_post];
86 for j := 0 to len(block_post.pred_list) do [
87 if block_post.pred_list[j] = bgi and block_post.pred_position[j] > pidx then [
88 ctx.blocks[bgi_post].pred_position[j] -= 1;
95 fn deactivate_node(ctx : context, bgi : int) : context
97 while len(ctx.blocks[bgi].pred_list) <> 0 do [
98 var pred_bgi := ctx.blocks[bgi].pred_list[0];
99 var pred_idx := ctx.blocks[bgi].pred_position[0];
100 ctx := deactivate_arrow(ctx, pred_bgi, pred_idx);
102 while len(ctx.blocks[bgi].post_list) <> 0 do [
103 ctx := deactivate_arrow(ctx, bgi, 0);
105 ctx.blocks[bgi] := basic_block.[
108 pred_list : empty(int),
109 pred_position : empty(int),
110 post_list : empty(int),
123 fn find_dominators_1(ctx : context) : context
126 var did_something := false;
127 for bgi := 1 to len(ctx.blocks) do [
128 if not ctx.blocks[bgi].active then
130 var un_set : node_set := -1;
131 for p_idx := 0 to len(ctx.blocks[bgi].pred_list) do [
132 var pred := ctx.blocks[bgi].pred_list[p_idx];
133 un_set and= ctx.blocks[pred].dom;
136 if un_set <> ctx.blocks[bgi].dom then [
137 ctx.blocks[bgi].dom := un_set;
138 did_something := true;
142 var bgi := len(ctx.blocks);
145 if not ctx.blocks[bgi].active then
147 var un_set : node_set := -1;
148 for p_idx := 0 to len(ctx.blocks[bgi].pred_list) do [
149 var pred := ctx.blocks[bgi].pred_list[p_idx];
150 un_set and= ctx.blocks[pred].dom;
153 if un_set <> ctx.blocks[bgi].dom then [
154 ctx.blocks[bgi].dom := un_set;
155 did_something := true;
159 if did_something then
164 fn find_dominators_2(ctx : context) : context
166 for bgi := 0 to len(ctx.blocks) do [
167 if not ctx.blocks[bgi].active then
169 var dom_set := ctx.blocks[bgi].dom;
170 while dom_set <> 0 do [
171 var dom : int := bsr dom_set;
173 ctx.blocks[dom].dominates bts= bgi;
175 ctx.blocks[bgi].is_idom_of := 0;
180 fn find_dominators_3(ctx : context) : context
182 for bgi := 1 to len(ctx.blocks) do [
183 if not ctx.blocks[bgi].active then
185 ctx.blocks[bgi].idom := -1;
186 var dom_set := ctx.blocks[bgi].dom btc bgi;
187 while dom_set <> 0 do [
188 var dom : int := bsr dom_set;
190 var dominates := ctx.blocks[dom].dominates btc dom;
191 if (dominates and ctx.blocks[bgi].dom btc bgi) = 0 then [
192 //eval debug("idom (" + ntos(bgi) + ") = " + ntos(dom));
193 if ctx.blocks[bgi].idom = -1 then
194 ctx.blocks[bgi].idom := dom;
196 abort internal("a block has multiple immediate dominators");
199 if ctx.blocks[bgi].idom = -1 then [
200 abort internal("a block doesn't have immediate dominator");
202 ctx.blocks[ctx.blocks[bgi].idom].is_idom_of bts= bgi;
207 fn find_dominators(ctx : context) : context
209 var n_blocks := len(ctx.blocks);
210 ctx.blocks[0].dom := 0 bts 0;
211 ctx.blocks[0].dominates := 0;
212 for i := 1 to n_blocks do [
213 var zero : node_set := 0;
214 ctx.blocks[i].dom := (zero bts n_blocks) - 1;
215 ctx.blocks[i].dominates := 0;
218 ctx := find_dominators_1(ctx);
219 ctx := find_dominators_2(ctx);
220 ctx := find_dominators_3(ctx);
222 {for bgi := 0 to n_blocks do [
223 eval debug("dom(" + ntos(bgi) + ") = " + ntos_base(ctx.blocks[bgi].dom, 2) + ", idom = " + ntos(ctx.blocks[bgi].idom));
229 fn prune_unreachable(ctx : context) : context
231 var worklist : node_set := 0 bts 0;
232 var active : node_set := 0;
234 while worklist <> 0 do [
235 var w : int := bsr worklist;
240 for post_idx := 0 to len(ctx.blocks[w].post_list) do [
241 var p := ctx.blocks[w].post_list[post_idx];
242 if not active bt p then
247 for bgi := 0 to len(ctx.blocks) do [
248 if not active bt bgi and ctx.blocks[bgi].active then [
249 //eval debug("deactivating node " + ntos(bgi));
250 ctx := deactivate_node(ctx, bgi);
257 fn join_adjacent(ctx : context) : context
259 var n_blocks := len(ctx.blocks);
260 var did_something : bool;
263 did_something := false;
264 for bgi := 0 to n_blocks do [
265 if not ctx.blocks[bgi].active then
268 var instrs := ctx.blocks[bgi].instrs;
269 if len_greater_than(instrs, 0) then [
270 var instr := ctx.instrs[instrs[0]];
271 if instr.opcode = P_Copy, instr.params[0] = instr.params[2] then [
272 ctx.blocks[bgi].instrs := ctx.blocks[bgi].instrs[1 .. ];
276 {if len(ctx.blocks[bgi].post_list) = 3 then [
277 var false_block := ctx.blocks[bgi].post_list[1];
278 if len(ctx.blocks[false_block].instrs) = 1 and ctx.instrs[ctx.blocks[false_block].instrs[0]].opcode = P_Label then [
279 if ctx.name = "fact" then eval debug("label node " + ntos(bgi) + " -> " + ntos(false_block));
281 if len(ctx.blocks[false_block].instrs) = 0 and len(ctx.blocks[false_block].post_list) = 1 then [
282 var next_block := ctx.blocks[false_block].post_list[0];
283 if ctx.name = "fact" then eval debug("empty node " + ntos(bgi) + " -> " + ntos(false_block) + " -> " + ntos(next_block));
284 for pl := 0 to len(ctx.blocks[next_block].pred_list) do [
285 if ctx.blocks[next_block].pred_list[pl] = false_block then [
286 ctx.blocks[next_block].pred_list[pl] := bgi;
287 ctx.blocks[next_block].pred_position[pl] := 1;
290 ctx.blocks[bgi].post_list[1] := next_block;
291 ctx.blocks[false_block].pred_list := empty(int);
292 ctx.blocks[false_block].post_list := empty(int);
293 ctx := deactivate_node(ctx, false_block);
294 did_something := true;
299 if len(ctx.blocks[bgi].post_list) = 1 then [
300 var post := ctx.blocks[bgi].post_list[0];
301 if len(ctx.blocks[post].pred_list) = 1 then [
302 //eval debug("joining nodes " + ntos(bgi) + " -> " + ntos(post));
304 var instrs1 := ctx.blocks[bgi].instrs;
305 var instrs2 := ctx.blocks[post].instrs;
306 for n := 0 to len(instrs2) do [
307 var in_idx := instrs2[n];
308 if ctx.instrs[in_idx].bb <> post then
309 abort internal("bb doesn't match: " + ntos(ctx.instrs[in_idx].bb) + " <> " + ntos(post) + " (opcode " + ntos(ctx.instrs[in_idx].opcode) + ")");
310 ctx.instrs[in_idx].bb := bgi;
312 if len_greater_than(instrs1, 0) then [
313 var last1 := ctx.instrs[instrs1[len(instrs1) - 1]].opcode;
314 if last1 = P_Jmp or last1 = P_Jmp_False then [
315 instrs1 := instrs1[ .. len(instrs1) - 1];
318 if len_greater_than(instrs2, 0) then [
319 var first2 := ctx.instrs[instrs2[0]].opcode;
320 if first2 = P_Label then [
321 lbl := ctx.instrs[instrs2[0]].params[0];
322 instrs2 := instrs2[1 .. ];
325 ctx.blocks[bgi].instrs := instrs1 + instrs2;
326 ctx.blocks[bgi].post_list := ctx.blocks[post].post_list;
327 for pl := 0 to len(ctx.blocks[bgi].post_list) do [
328 var p := ctx.blocks[bgi].post_list[pl];
329 for q := 0 to len(ctx.blocks[p].pred_list) do
330 if ctx.blocks[p].pred_list[q] = post then
331 ctx.blocks[p].pred_list[q] := bgi;
333 ctx.blocks[post].pred_list := empty(int);
334 ctx := deactivate_node(ctx, post);
336 if ctx.label_to_block[lbl] <> post then
337 abort internal("label doesn't match");
338 ctx.label_to_block[lbl] := -1;
340 did_something := true;
345 if did_something then
351 fn propagate_types(ctx : context) : context
353 var did_something : bool;
355 did_something := false;
356 var n_blocks := len(ctx.blocks);
357 for bgi := 0 to n_blocks do [
358 if not ctx.blocks[bgi].active then
360 var n_instrs := len(ctx.blocks[bgi].instrs);
361 for ili := 0 to n_instrs do [
362 var ins := ctx.instrs[ ctx.blocks[bgi].instrs[ili] ];
363 if ins.opcode = P_Copy then [
364 var dest : int := ins.params[0];
365 var src : int := ins.params[2];
366 var dest_rt := ctx.variables[dest].runtime_type;
367 var src_rt := T_Type;
369 src_rt := ctx.variables[src].runtime_type;
370 else if src = T_Type then
371 src_rt := T_TypeOfType;
372 if src_rt = dest_rt then
374 if src_rt = T_Undetermined then
375 ctx.variables[src].runtime_type := dest_rt;
376 else if dest_rt = T_Undetermined then
377 ctx.variables[dest].runtime_type := src_rt;
379 if src_rt >= 0, dest_rt >= 0 then
381 abort internal("copying between variables '" + ctx.variables[src].name + "', '" + ctx.variables[dest].name + "' with types " + ntos(src_rt) + " and " + ntos(dest_rt));
383 did_something := true;
387 if did_something then
392 fn set_to_mask(ins : instruction, s : param_set) : var_set
394 var r : var_set := 0;
396 var q : int := bsr s;
398 if ins.params[q] >= 0 then
399 r bts= ins.params[q];
404 fn test_uninitialized(ctx : context) : context
406 var n_blocks := len(ctx.blocks);
408 var zero : var_set := 0;
409 ctx.blocks[0].uninitialized := (zero bts len(ctx.variables)) - 1;
410 for bgi := 1 to n_blocks do [
411 if not ctx.blocks[bgi].active then
413 ctx.blocks[bgi].uninitialized := 0;
416 var worklist : node_set := 0 bts 0;
418 while worklist <> 0 do [
419 var w : int := bsr worklist;
422 var uninit := ctx.blocks[w].uninitialized;
424 for ili := 0 to len(ctx.blocks[w].instrs) do [
425 var ins := ctx.instrs[ ctx.blocks[w].instrs[ili] ];
426 //eval debug("opcode " + ntos(ins.opcode) + " rd " + ntos_base(ins.read_set, 2) + " wr " + ntos_base(ins.write_set, 2) + " fr " + ntos_base(ins.free_set, 2));
427 var read_mask := set_to_mask(ins, ins.read_set);
428 var write_mask := set_to_mask(ins, ins.write_set);
429 //var free_mask := set_to_mask(ins, ins.free_set);
430 var uninit_mask := read_mask and uninit;
431 if uninit_mask <> 0 then [
433 eval dump_basic_blocks(ctx, true);
434 eval debug("read mask: " + ntos_base(read_mask, 2));
435 eval debug("write mask: " + ntos_base(write_mask, 2));
436 //eval debug("free mask: " + ntos_base(free_mask, 2));
437 for j := 0 to len(ins.params) do
438 eval debug("param: " + ntos(ins.params[j]));
439 abort internal("uninitialized variable " + ntos_base(uninit_mask, 2) + " at bb " + ntos(w) + " in " + ntos(ili) + " opc " + ntos(ins.opcode));
441 var str := "Uninitialized variable in " + ctx.name;
442 var v : int := bsf uninit_mask;
443 if len(ctx.variables[v].name) > 0 then
444 str += ": " + ctx.variables[v].name;
445 ctx := exception_make_str(context, ec_async, error_compiler_error, 0, true, str);
448 //uninit or= free_mask;
449 uninit and= not write_mask;
452 for post := 0 to len(ctx.blocks[w].post_list) do [
453 var p := ctx.blocks[w].post_list[post];
454 if (uninit and not ctx.blocks[p].uninitialized) <> 0 then [
455 ctx.blocks[p].uninitialized or= uninit;
464 fn get_pred_set(b : basic_block) : node_set
466 var pred_set : node_set := 0;
467 for j := 0 to len(b.pred_list) do
468 pred_set bts= b.pred_list[j];
472 fn find_dominance_frontiers(ctx : context) : context
474 var n_blocks := len(ctx.blocks);
476 for bgi := 0 to n_blocks do
477 ctx.blocks[bgi].df := 0;
479 for bgi := 0 to n_blocks do [
480 if not ctx.blocks[bgi].active then
482 var pred_set := get_pred_set(ctx.blocks[bgi]);
483 if popcnt pred_set >= 2 then [
484 while pred_set <> 0 do [
485 var runner : int := bsr pred_set;
486 pred_set btr= runner;
487 while runner <> ctx.blocks[bgi].idom do [
488 ctx.blocks[runner].df bts= bgi;
489 runner := ctx.blocks[runner].idom;
495 {for bgi := 0 to n_blocks do [
496 eval debug("df(" + ntos(bgi) + ") = " + ntos_base(ctx.blocks[bgi].df, 2));
502 fn process_variables(ctx : context) : context
504 for vgi := 0 to len(ctx.variables) do [
505 ctx.variables[vgi].writing_instrs := 0;
506 ctx.variables[vgi].reaching_def := -1;
508 for bgi := 0 to len(ctx.blocks) do [
509 if not ctx.blocks[bgi].active then
511 for ili := 0 to len(ctx.blocks[bgi].instrs) do [
512 var igi := ctx.blocks[bgi].instrs[ili];
513 var ins := ctx.instrs[igi];
515 var rset := ins.read_set;
517 var rd : int := bsr rset;
519 var v := ins.params[rd];
521 //ctx.variables[v].reading_instrs bts= igi;
522 //ctx.variables[v].var_active := true;
526 var wset := ins.write_set;
528 var wr : int := bsr wset;
530 var v := ins.params[wr];
532 ctx.variables[v].writing_instrs bts= igi;
540 fn is_noclone_variable(ctx : context, vgi : int) : bool
542 return popcnt(ctx.variables[vgi].writing_instrs) = 1;
545 fn insert_phi(ctx : context, vgi : int, bgi : int) : context
547 var n : int := len(ctx.blocks[bgi].pred_list);
548 var instr := create_instr(P_Phi, fill(pcode_t, vgi, n + 1), bgi);
549 ctx := insert_instr(ctx, instr, 0);
553 fn find_phi_blocks(ctx : context) : context
555 for vgi := 0 to len(ctx.variables) do [
557 if is_noclone_variable(ctx, vgi) then
560 var f : node_set := 0;
561 var w : node_set := 0;
563 var wset := ctx.variables[vgi].writing_instrs;
565 var wr : int := bsr wset;
567 if ctx.blocks[ ctx.instrs[wr].bb ].active then
568 w bts= ctx.instrs[wr].bb;
572 var x : int := bsr w;
574 var dfw := ctx.blocks[x].df;
575 //eval debug("dfs( " + ntos(x) + ") = " + ntos_base(dfw, 2));
577 var y : int := bsr dfw;
580 if not ctx.blocks[y].uninitialized bt vgi then [
581 //eval debug("insert phi for " + ntos(vgi) + " at " + ntos(y));
582 ctx := insert_phi(ctx, vgi, y);
584 if not defs_v bt y then
587 //eval debug("don't insert phi for " + ntos(vgi) + " at " + ntos(y));
597 fn clone_variable(ctx : context, vgi : int) : (variable, int)
599 var v1_idx := len(ctx.variables);
600 var v1 := new_variable;
602 v1.type_index := ctx.variables[vgi].type_index;
603 v1.runtime_type := ctx.variables[vgi].runtime_type;
604 v1.local_type := ctx.variables[vgi].local_type;
605 v1.color := ctx.variables[vgi].color;
606 v1.name := ctx.variables[vgi].name;
607 v1.is_option_type := ctx.variables[vgi].is_option_type;
612 fn update_reaching_def(ctx : context, vgi : int, bgi : int) : context
614 var r := ctx.variables[vgi].reaching_def;
616 while r <> -1, not ctx.blocks[ctx.variables[r].defining_block].dominates bt bgi do [
617 //eval debug("go up " + ntos(r) + " -> " + ntos(ctx.variables[r].reaching_def) + " dblock " + ntos(ctx.variables[r].defining_block));
618 r := ctx.variables[r].reaching_def;
620 ctx.variables[vgi].reaching_def := r;
621 //eval debug("update_reaching_def: bgi : " + ntos(bgi) + " vgi: " + ntos(vgi) + " : " + ntos(s) + " -> " + ntos(r));
625 fn rename_variables_recursive(ctx : context, bgi : int) : context
627 //eval debug("walking block " + ntos(bgi) + " (" + ntos(len(ctx.blocks[bgi].instrs)) + ")");
629 for ili := 0 to len(ctx.blocks[bgi].instrs) do [
630 var igi := ctx.blocks[bgi].instrs[ili];
631 var instr := ctx.instrs[igi];
632 if instr.opcode <> P_Phi then [
633 var read_set := instr.read_set;
634 while read_set <> 0 do [
635 var rd_idx : int := bsr read_set;
636 read_set btr= rd_idx;
637 var v := instr.params[rd_idx];
641 if is_noclone_variable(ctx, v) then
644 //eval debug("prev reaching def " + ntos(ctx.variables[v].reaching_def));
645 ctx := update_reaching_def(ctx, v, bgi);
646 if ctx.variables[v].reaching_def = -1 then
647 abort internal("bad reaching def, bgi " + ntos(bgi) + " instr " + ntos(ili) + " v " + ntos(v) + " opcode " + ntos(instr.opcode));
648 ctx.instrs[ ctx.blocks[bgi].instrs[ili] ].params[rd_idx] := ctx.variables[v].reaching_def;
649 //eval debug("processing renamed, bgi " + ntos(bgi) + " " + ntos(v) + " -> " + ntos(ctx.variables[v].reaching_def));
652 var write_set := instr.write_set;
653 while write_set <> 0 do [
654 var wr_idx : int := bsr write_set;
655 write_set btr= wr_idx;
656 var v := instr.params[wr_idx];
658 abort internal("negative v: " + ntos(v));
660 if is_noclone_variable(ctx, v) then [
661 ctx.variables[v].defining_block := bgi;
662 ctx.variables[v].defining_instr := igi;
666 ctx := update_reaching_def(ctx, v, bgi);
668 var v1, v1_idx := clone_variable(ctx, v);
669 v1.defining_block := bgi;
670 v1.defining_instr := igi;
672 ctx.instrs[ ctx.blocks[bgi].instrs[ili] ].params[wr_idx] := v1_idx;
673 v1.reaching_def := ctx.variables[v].reaching_def;
674 ctx.variables[v].reaching_def := v1_idx;
676 ctx.variables +<= v1;
678 //eval debug("renaming bgi " + ntos(bgi) + ", idx " + ntos(ili) + ", var " + ntos(v) + " -> " + ntos(v1_idx) + " opcode " + ntos(instr.opcode));
682 for p := 0 to len(ctx.blocks[bgi].post_list) do [
683 var bbb := ctx.blocks[bgi].post_list[p];
684 var post_block := ctx.blocks[bbb];
685 for idx := 0 to len(post_block.pred_list) do [
686 if post_block.pred_list[idx] = bgi then [
687 //eval debug("bgi: " + ntos(bgi) + " p:" + ntos(idx) + " bbb:" + ntos(bbb));
688 for ili := 0 to len(ctx.blocks[bbb].instrs) do [
689 var igi := ctx.blocks[bbb].instrs[ili];
690 var instr := ctx.instrs[igi];
691 if instr.opcode <> P_Phi then
694 var v := instr.params[idx + 1];
695 ctx := update_reaching_def(ctx, v, bgi);
696 //eval debug("adjusting phi, bgi " + ntos(bgi) + " bbb " + ntos(bbb) + " " + ntos(ctx.instrs[ igi ].params[idx + 1]) + " -> " + ntos(ctx.variables[v].reaching_def));
697 ctx.instrs[ igi ].params[idx + 1] := ctx.variables[v].reaching_def;
698 if ctx.variables[v].reaching_def = -1 then
699 abort internal("phi with uninitialized argument " + ntos(ctx.instrs[ ctx.blocks[bbb].instrs[ili]].params[0]) + ", bbb " + ntos(bbb) + ", instr " + ntos(ili) + " opcode " + ntos(instr.opcode) + " v " + ntos(v));
705 var is_idom_of := ctx.blocks[bgi].is_idom_of;
706 while is_idom_of <> 0 do [
707 var next : int := bsr is_idom_of;
708 is_idom_of btr= next;
709 ctx := rename_variables_recursive(ctx, next);
714 fn rename_variables(ctx : context) : context
716 return rename_variables_recursive(ctx, 0);
719 fn verify_ssa(ctx : context) : context
723 var assign_mask : var_set := 0;
724 var n_blocks := len(ctx.blocks);
725 for bgi := 0 to n_blocks do [
726 var block := ctx.blocks[bgi];
727 if not block.active then
729 for ili := 0 to len(block.instrs) do [
730 var igi := block.instrs[ili];
731 var ins := ctx.instrs[igi];
732 var write_mask := set_to_mask(ins, ins.write_set);
733 if (assign_mask and write_mask) <> 0 then [
734 abort internal("verify_ssa: variables are assigned multiple times: " + mtos(assign_mask and write_mask));
736 assign_mask or= write_mask;
743 fn remap_instruction(ins : instruction, var_map : list(int), test_write : bool) : instruction
745 var rs := ins.read_set;
747 var idx : int := bsr rs;
749 var param := ins.params[idx];
751 ins.params[idx] := var_map[param];
754 var ws := ins.write_set;
756 var idx : int := bsr ws;
758 var param := ins.params[idx];
759 if var_map[param] <> param then
760 abort internal("output variable was remapped");
766 fn remap_variable(ctx : context, vgi : int) : context
768 var v := ctx.variables[vgi].type_index;
770 var vm := ctx.var_map[v];
771 ctx.variables[vgi].type_index := vm;
772 if vm > T_Undetermined and vm < 0 then
773 ctx.variables[vgi].runtime_type := vm;
774 else if vm >= 0, ctx.variables[vm].is_option_type then
775 ctx.variables[vgi].runtime_type := T_FlatOption;
780 fn gvn_recursive(ctx : context, bgi : int, vals : list(int)) : context
782 for i := 0 to len(ctx.blocks[bgi].instrs) do [
783 var igi := ctx.blocks[bgi].instrs[i];
784 var ins := ctx.instrs[igi];
785 ins := remap_instruction(ins, ctx.var_map, true);
786 ctx.instrs[igi] := ins;
787 if ins.opcode = P_Copy then [
788 var dest : int := ins.params[0];
789 var src : int := ins.params[2];
790 ctx.var_map[dest] := src;
793 if ins.opcode = P_Free or
794 ins.opcode = P_Load_Local_Type or
795 ins.opcode = P_Eval or
796 ins.opcode = P_Keep or
797 ins.opcode = P_Jmp or
798 ins.opcode = P_Jmp_False or
799 ins.opcode = P_Label or
801 ins.opcode = P_Args or
802 ins.opcode = P_Return_Vars or
803 ins.opcode = P_Return or
804 ins.opcode = P_Line_Info
807 var value_list := list(pcode_t).[ ins.opcode, len(ins.params) ];
808 for i := 0 to len(ins.params) do [
809 if ins.write_set bt i then
811 var v := ins.params[i];
812 if ins.free_set bt i + 1 then
813 v and= not Flag_Free_Argument;
817 if ins.opcode = P_UnaryOp, ins.params[0] = Un_ConvertFromInt then [
818 value_list +<= ctx.variables[ins.params[1]].runtime_type;
820 if ins.opcode = P_Copy_Type_Cast then [
821 if ctx.variables[ins.params[0]].runtime_type = T_Undetermined then
823 if ctx.variables[ins.params[1]].runtime_type = T_Undetermined then
825 value_list +<= ctx.variables[ins.params[0]].runtime_type;
827 if ins.opcode = P_Load_Const then [
828 value_list +<= ctx.variables[ins.params[0]].runtime_type;
831 var value_number := gvn_encode(value_list);
832 if vals[value_number] = -1 then [
833 vals[value_number] := igi;
836 //eval debug("gvn found a case, opcode " + ntos(ins.opcode) + " vn " + ntos_base(value_number, 16));
837 var prev_ins := ctx.instrs[vals[value_number]];
838 if ins.write_set <> prev_ins.write_set then
839 abort internal("write set of the old and new instruction doesn't match");
840 var ws := ins.write_set;
842 var idx : int := bsr ws;
844 var prev_result := prev_ins.params[idx];
845 var new_result := ins.params[idx];
846 if ctx.var_map[new_result] <> new_result then
847 abort internal("variable was already remapped");
848 ctx.var_map[new_result] := prev_result;
852 var is_idom_of := ctx.blocks[bgi].is_idom_of;
853 while is_idom_of <> 0 do [
854 var next : int := bsr is_idom_of;
855 is_idom_of btr= next;
856 ctx := gvn_recursive(ctx, next, vals);
862 fn gvn(ctx : context) : context
864 var vals := infinite(-1);
866 ctx.var_map := fill(-1, len(ctx.variables));
867 for vgi := 0 to len(ctx.variables) do
868 ctx.var_map[vgi] := vgi;
870 ctx := gvn_recursive(ctx, 0, vals);
872 for vgi := 0 to len(ctx.variables) do
873 ctx := remap_variable(ctx, vgi);
878 fn verify_positive(ctx : context, vgii : int) : bool
880 var done : var_set := 0;
881 var todo : var_set := 0;
884 var vgi : int := bsr todo;
887 var v := ctx.variables[vgi];
888 var ins := ctx.instrs[v.defining_instr];
889 if ins.opcode = P_Phi then [
890 for i := 1 to len(ins.params) do [
891 var p := ins.params[i];
892 if not done bt p then
895 ] else if ins.opcode = P_BinaryOp,
896 ins.params[0] = Bin_Add or
897 ins.params[0] = Bin_Multiply or
898 ins.params[0] = Bin_Power or
899 ins.params[0] = Bin_And or
900 ins.params[0] = Bin_Or or
901 ins.params[0] = Bin_Xor or
902 ins.params[0] = Bin_Shl or
903 ins.params[0] = Bin_Shr or
904 ins.params[0] = Bin_Bts or
905 ins.params[0] = Bin_Btr or
906 ins.params[0] = Bin_Btc then [
907 var p := ins.params[3];
908 if not done bt p then
911 if not done bt p then
914 ] else if ins.opcode = P_BinaryConstOp,
916 ins.params[0] = Bin_Add or
917 ins.params[0] = Bin_Multiply or
918 ins.params[0] = Bin_Power or
919 ins.params[0] = Bin_And or
920 ins.params[0] = Bin_Or or
921 ins.params[0] = Bin_Xor or
922 ins.params[0] = Bin_Shl or
923 ins.params[0] = Bin_Shr or
924 ins.params[0] = Bin_Bts or
925 ins.params[0] = Bin_Btr or
926 ins.params[0] = Bin_Btc then [
927 var p := ins.params[3];
928 if not done bt p then
931 ] else if ins.opcode = P_UnaryOp, ins.params[0] = Un_Inc then [
932 var p := ins.params[3];
933 if not done bt p then
936 ] else if ins.opcode = P_Load_Const then [
937 var l := blob_to_int(ins.params[1 ..]);
947 fn operator_not~inline(op : pcode_t) : pcode_t
949 if op = Bin_Equal then return Bin_NotEqual;
950 if op = Bin_NotEqual then return Bin_Equal;
951 if op = Bin_Less then return Bin_GreaterEqual;
952 if op = Bin_GreaterEqual then return Bin_Less;
953 if op = Bin_LessEqual then return Bin_Greater;
954 if op = Bin_Greater then return Bin_LessEqual;
958 fn operator_swap~inline(op : pcode_t) : pcode_t
960 if op = Bin_Add then return op;
961 if op = Bin_Multiply then return op;
962 if op = Bin_And then return op;
963 if op = Bin_Or then return op;
964 if op = Bin_Xor then return op;
965 if op = Bin_Equal then return op;
966 if op = Bin_NotEqual then return op;
967 if op = Bin_Less then return Bin_Greater;
968 if op = Bin_LessEqual then return Bin_GreaterEqual;
969 if op = Bin_Greater then return Bin_Less;
970 if op = Bin_GreaterEqual then return Bin_LessEqual;
974 fn simplify_instr(ctx : context, ins : instruction) : (instruction, bool)
976 if ins.opcode = P_Load_Local_Type then [
977 var params := list(pcode_t).[ IO_Exception_Make, 1, 0, 4, ins.params[0], ec_sync, error_optimizer_error, 0, 1 ];
978 return create_instr(P_IO, params, ins.bb), true;
980 if ins.opcode = P_Curry then [
981 var vgi := ins.params[3];
982 var v := ctx.variables[vgi];
983 var fn_ins := ctx.instrs[v.defining_instr];
984 if fn_ins.opcode = P_Load_Fn then [
985 fn_ins.params[0] := ins.params[0];
986 fn_ins.params[1] += ins.params[1];
987 fn_ins.params += ins.params[4 .. ];
988 return create_instr(P_Load_Fn, fn_ins.params, ins.bb), true;
990 if fn_ins.opcode = P_Curry then [
991 fn_ins.params[0] := ins.params[0];
992 fn_ins.params[1] += ins.params[1];
993 fn_ins.params += ins.params[4 .. ];
994 return create_instr(P_Curry, fn_ins.params, ins.bb), true;
998 if ins.opcode = P_Call_Indirect then [
999 var vgi := ins.params[4];
1000 var v := ctx.variables[vgi];
1001 var fn_ins := ctx.instrs[v.defining_instr];
1002 if fn_ins.opcode = P_Load_Fn then [
1003 var fn_spec_len := function_specifier_length(fn_ins.params[3 .. ]);
1004 var fn_args := fn_ins.params[3 + fn_spec_len .. ];
1005 var call_params := list(pcode_t).[ ins.params[0], ins.params[1], ins.params[2] + fn_ins.params[1]] + fn_ins.params[3 .. 3 + fn_spec_len] + fn_args + ins.params[5 .. ];
1006 if fn_ins.params[2] = Call_Mode_Type or fn_ins.params[2] = Call_Mode_Flat then
1007 call_params[0] := fn_ins.params[2];
1008 else if call_params[0] = Call_Mode_Unspecified then
1009 call_params[0] := fn_ins.params[2];
1010 return create_instr(P_Call, call_params, ins.bb), true;
1012 if fn_ins.opcode = P_Curry then [
1013 ins.params[2] += fn_ins.params[1];
1014 ins.params[4] := fn_ins.params[3];
1015 var call_indirect_params := ins.params[0 .. 5] + fn_ins.params[4 .. ] + ins.params[5 .. ];
1016 return create_instr(P_Call_Indirect, call_indirect_params, ins.bb), true;
1020 if ins.opcode = P_BinaryOp then [
1021 var vgi1 := ins.params[3];
1022 var v1 := ctx.variables[vgi1];
1023 var v1_ins := ctx.instrs[v1.defining_instr];
1024 var vgi2 := ins.params[5];
1025 var v2 := ctx.variables[vgi2];
1026 var v2_ins := ctx.instrs[v2.defining_instr];
1027 var vgir := ins.params[1];
1028 var vr := ctx.variables[vgir];
1029 //eval debug("test const vgi " + ntos(vgi1) + " " + ntos(vgi2));
1030 //eval debug("test const " + ntos(v1_ins.opcode) + " " + ntos(v2_ins.opcode));
1031 if v1_ins.opcode = P_Load_Const and v2_ins.opcode = P_Load_Const then [
1033 //str := "v1: (" + ntos(vgi1) + ")"; for i := 0 to len(v1_ins.params) do [ str += " " + ntos(v1_ins.params[i]); ]; eval debug(str);
1034 //str := "v2: (" + ntos(vgi2) + ")"; for i := 0 to len(v2_ins.params) do [ str += " " + ntos(v2_ins.params[i]); ]; eval debug(str);
1035 var c := evaluate_binary(v1.runtime_type, vr.runtime_type, ins.params[0], v1_ins.params[1 ..], v2_ins.params[1 ..]);
1036 if is_exception c then
1038 var params := list(pcode_t).[ ins.params[1] ] + c;
1039 //str := "vr:"; for i := 0 to len(params) do [ str += " " + ntos(params[i]); ]; eval debug(str);
1040 return create_instr(P_Load_Const, params, ins.bb), true;
1042 if vr.runtime_type <= T_SInt8, vr.runtime_type >= T_Integer128 then [
1043 if ins.params[0] = Bin_Add, v2_ins.opcode = P_Load_Const, v2_ins.params[1] = 1, v2_ins.params[2] = 1 then [
1044 return create_instr(P_UnaryOp, list(pcode_t).[ Un_Inc, ins.params[1], ins.params[2], ins.params[3] ], ins.bb), true;
1046 if ins.params[0] = Bin_Subtract, v2_ins.opcode = P_Load_Const, v2_ins.params[1] = 1, v2_ins.params[2] = 1 then [
1047 return create_instr(P_UnaryOp, list(pcode_t).[ Un_Dec, ins.params[1], ins.params[2], ins.params[3] ], ins.bb), true;
1049 if ins.params[0] = Bin_Multiply, v2_ins.opcode = P_Load_Const, v2_ins.params[1] = 1, v2_ins.params[2] = 2 then [
1050 return create_instr(P_BinaryOp, list(pcode_t).[ Bin_Add, ins.params[1], ins.params[2], ins.params[3], ins.params[2], ins.params[3] ], ins.bb), true;
1052 if ins.params[0] = Bin_Shl, v2_ins.opcode = P_Load_Const, v2_ins.params[1] = 1, v2_ins.params[2] = 1 then [
1053 return create_instr(P_BinaryOp, list(pcode_t).[ Bin_Add, ins.params[1], ins.params[2], ins.params[3], ins.params[2], ins.params[3] ], ins.bb), true;
1056 if v1.runtime_type <= T_SInt8, v1.runtime_type >= T_Integer128, v2_ins.opcode = P_Load_Const then [
1057 var i := blob_to_int(v2_ins.params[1 .. ]);
1058 //if v1.runtime_type <= T_SInt8, v1.runtime_type >= T_UInt128 then eval debug("evaluating constant " + ntos(i));
1059 // this logic is copied in frame_t_from_const
1060 var lower_limit, upper_limit := -#40000000, #3fffffff;
1061 if v1.runtime_type = T_Integer8 or v1.runtime_type = T_SInt8 then
1062 lower_limit, upper_limit := -#80, #80;
1063 if v1.runtime_type = T_UInt8 then
1064 lower_limit, upper_limit := #0, #100;
1065 if v1.runtime_type = T_Integer16 or v1.runtime_type = T_SInt16 then
1066 lower_limit, upper_limit := -#8000, #8000;
1067 if v1.runtime_type = T_UInt16 then
1068 lower_limit, upper_limit := #0, #10000;
1069 if v1.runtime_type = T_UInt32 or v1.runtime_type = T_UInt64 or v1.runtime_type = T_UInt128 then
1071 if i >= lower_limit, i < upper_limit then
1072 return create_instr(P_BinaryConstOp, ins.params[ .. 4] +< i, ins.bb), true;
1074 if v1.runtime_type <= T_SInt8, v1.runtime_type >= T_Integer128, v1_ins.opcode = P_Load_Const then [
1075 var new_op := operator_swap(ins.params[0]);
1076 if new_op >= 0 then [
1077 var params := ins.params;
1078 params[0] := new_op;
1079 params[2] := ins.params[4];
1080 params[3] := ins.params[5];
1081 params[4] := ins.params[2];
1082 params[5] := ins.params[3];
1083 return create_instr(P_BinaryOp, params, ins.bb), true;
1086 if v1_ins.opcode = P_IO, v1_ins.params[0] = IO_Exception_Make,
1087 v1.runtime_type <> T_FlatOption or (v2_ins.opcode = P_IO and v2_ins.params[0] = IO_Exception_Make) then [
1088 var params := v1_ins.params;
1089 params[4] := ins.params[1];
1090 return create_instr(P_IO, params, ins.bb), true;
1092 if v2_ins.opcode = P_IO, v2_ins.params[0] = IO_Exception_Make,
1093 v1.runtime_type <> T_FlatOption then [
1094 var params := v2_ins.params;
1095 params[4] := ins.params[1];
1096 return create_instr(P_IO, params, ins.bb), true;
1098 if ins.params[0] = Bin_Less, v2_ins.opcode = P_Array_Len then [
1099 //eval debug(ctx.name + ": P_Array_Len_Greater_Than optimized");
1100 var params := list(pcode_t).[ vgir, v2_ins.params[1], vgi1, 0 ];
1101 return create_instr(P_Array_Len_Greater_Than, params, ins.bb), true;
1105 if ins.opcode = P_BinaryConstOp then [
1106 var vgi1 := ins.params[3];
1107 var v1 := ctx.variables[vgi1];
1108 var v1_ins := ctx.instrs[v1.defining_instr];
1109 var vgir := ins.params[1];
1110 var vr := ctx.variables[vgir];
1111 if v1_ins.opcode = P_Load_Const then [
1112 var cnst := ins.params[4];
1113 var c := evaluate_binary(v1.runtime_type, vr.runtime_type, ins.params[0], v1_ins.params[1 ..], int_to_blob(cnst));
1114 if is_exception c then
1116 var params := list(pcode_t).[ ins.params[1] ] + c;
1117 return create_instr(P_Load_Const, params, ins.bb), true;
1119 if vr.runtime_type <= T_SInt8, vr.runtime_type >= T_Integer128 then [
1120 if ins.params[0] = Bin_Add, ins.params[4] = 1 then [
1121 return create_instr(P_UnaryOp, list(pcode_t).[ Un_Inc, ins.params[1], ins.params[2], ins.params[3] ], ins.bb), true;
1123 if ins.params[0] = Bin_Subtract, ins.params[4] = 1 then [
1124 return create_instr(P_UnaryOp, list(pcode_t).[ Un_Dec, ins.params[1], ins.params[2], ins.params[3] ], ins.bb), true;
1126 if ins.params[0] = Bin_Multiply, ins.params[4] = 2 then [
1127 return create_instr(P_BinaryOp, list(pcode_t).[ Bin_Add, ins.params[1], ins.params[2], ins.params[3], ins.params[2], ins.params[3] ], ins.bb), true;
1129 if ins.params[0] = Bin_Shl, ins.params[4] = 1 then [
1130 return create_instr(P_BinaryOp, list(pcode_t).[ Bin_Add, ins.params[1], ins.params[2], ins.params[3], ins.params[2], ins.params[3] ], ins.bb), true;
1135 if ins.opcode = P_UnaryOp then [
1136 var vgi1 := ins.params[3];
1137 var v1 := ctx.variables[vgi1];
1138 var v1_ins := ctx.instrs[v1.defining_instr];
1139 var vgir := ins.params[1];
1140 var vr := ctx.variables[vgir];
1141 if v1_ins.opcode = P_Load_Const then [
1143 //str := "v1: (" + ntos(vgi1) + ")"; for i := 0 to len(v1_ins.params) do [ str += " " + ntos(v1_ins.params[i]); ]; eval debug(str);
1144 var c := evaluate_unary(v1.runtime_type, vr.runtime_type, ins.params[0], v1_ins.params[1 ..]);
1145 if is_exception c then
1147 var params := list(pcode_t).[ ins.params[1] ] + c;
1148 //str := "vr:"; for i := 0 to len(params) do [ str += " " + ntos(params[i]); ]; eval debug(str);
1149 return create_instr(P_Load_Const, params, ins.bb), true;
1151 if v1_ins.opcode = P_IO, v1_ins.params[0] = IO_Exception_Make,
1152 ins.params[0] <> Un_IsException, ins.params[0] <> Un_ExceptionClass, ins.params[0] <> Un_ExceptionType, ins.params[0] <> Un_ExceptionAux then [
1153 var params := v1_ins.params;
1154 params[4] := ins.params[1];
1155 return create_instr(P_IO, params, ins.bb), true;
1157 if ins.params[0] = Un_Not, v1_ins.opcode = P_BinaryOp then [
1158 var new_op := operator_not(v1_ins.params[0]);
1159 if new_op >= 0 then [
1160 var params := v1_ins.params;
1161 params[0] := new_op;
1162 params[1] := ins.params[1];
1163 return create_instr(P_BinaryOp, params, ins.bb), true;
1168 if ins.opcode = P_Option_Test then [
1169 var idx := ins.params[2];
1170 var vgis := ins.params[1];
1171 var vs := ctx.variables[vgis];
1172 var vs_ins := ctx.instrs[vs.defining_instr];
1174 if vs_ins.opcode = P_Option_Create then [
1175 is_idx := vs_ins.params[1];
1176 ] else if vs_ins.opcode = P_Load_Const then [
1177 is_idx := blob_to_int(vs_ins.params[1 ..]);
1179 if is_idx >= 0 then [
1181 if idx = is_idx then
1185 return create_instr(P_Load_Const, list(pcode_t).[ ins.params[0] ] + int_to_blob(res), ins.bb), true;
1189 if ins.opcode = P_Array_Load then [
1190 if (ins.params[1] and Flag_Index_In_Range) <> 0 then
1192 var vgis := ins.params[2];
1193 var vgii := ins.params[3];
1195 var dom_set := ctx.blocks[bgi].dom;
1196 while dom_set <> 0 do [
1197 var dom : int := bsr dom_set;
1199 var bb := ctx.blocks[dom];
1200 if not bb.active then
1201 abort internal("dominator is not active");
1202 if len(bb.pred_list) = 0 then
1204 for i := 0 to len(bb.pred_list) do [
1205 if bb.pred_position[i] <> 0 then
1207 var bb_pred := ctx.blocks[bb.pred_list[i]];
1208 if len(bb_pred.instrs) = 0 then
1210 var lins := ctx.instrs[bb_pred.instrs[len(bb_pred.instrs) - 1]];
1211 if lins.opcode <> P_Jmp_False then
1213 var vgic := lins.params[0];
1214 var dins := ctx.instrs[ctx.variables[vgic].defining_instr];
1215 if dins.opcode <> P_Array_Len_Greater_Than then
1217 if dins.params[1] <> vgis or dins.params[2] <> vgii then
1220 if not verify_positive(ctx, vgii) then
1222 //eval debug(ctx.name + ": array index optimized");
1223 ins.params[1] or= Flag_Index_In_Range;
1229 if ins.opcode = P_Array_Len then [
1230 var vgis := ins.params[1];
1231 var vs := ctx.variables[vgis];
1232 var vs_ins := ctx.instrs[vs.defining_instr];
1233 if vs_ins.opcode = P_Array_Create then [
1234 return create_instr(P_Load_Const, list(pcode_t).[ ins.params[0] ] + int_to_blob(vs_ins.params[2]), ins.bb), true;
1238 if ins.opcode = P_Array_Len_Greater_Than then [
1239 var vgis := ins.params[1];
1240 var vs := ctx.variables[vgis];
1241 var vs_ins := ctx.instrs[vs.defining_instr];
1242 var vgii := ins.params[2];
1243 var vi := ctx.variables[vgii];
1244 var vi_ins := ctx.instrs[vi.defining_instr];
1245 if vs_ins.opcode = P_Array_Create and vi_ins.opcode = P_Load_Const then [
1246 var l := blob_to_int(vi_ins.params[1 ..]);
1249 if vs_ins.params[2] > l then
1253 return create_instr(P_Load_Const, list(pcode_t).[ ins.params[0] ] + int_to_blob(v), ins.bb), true;
1258 if ins.opcode = P_Array_Append then [
1259 var vgi2 := ins.params[4];
1260 var vs2 := ctx.variables[vgi2];
1261 var vs2_ins := ctx.instrs[vs2.defining_instr];
1262 if vs2_ins.opcode = P_Array_Create, vs2_ins.params[2] = 1 then [
1263 return create_instr(P_Array_Append_One, ins.params[ .. 4] +< vs2_ins.params[5], ins.bb), true;
1268 if ins.borrow <> -1, (ins.params[ins.borrow - 1] and Flag_Borrow) = 0 then [
1269 ins.params[ins.borrow - 1] or= Flag_Borrow;
1275 fn substitute_variable(ctx : context, ins : instruction) : (int, int)
1277 if ins.opcode = P_Phi then [
1278 var p := ins.params[1];
1279 for i := 2 to len(ins.params) do
1280 if ins.params[i] <> p then
1282 return ins.params[0], ins.params[1];
1285 if ins.opcode = P_Record_Load then [
1286 var idx := ins.params[3];
1287 var vgis := ins.params[2];
1288 var vs := ctx.variables[vgis];
1289 var vs_ins := ctx.instrs[vs.defining_instr];
1290 if vs_ins.opcode = P_Record_Create then [
1291 return ins.params[0], vs_ins.params[3 + idx * 2];
1294 if ins.opcode = P_Option_Load then [
1295 var idx := ins.params[3];
1296 var vgis := ins.params[2];
1297 var vs := ctx.variables[vgis];
1298 var vs_ins := ctx.instrs[vs.defining_instr];
1299 if vs_ins.opcode = P_Option_Create then [
1300 if vs_ins.params[1] = idx then [
1301 return ins.params[0], vs_ins.params[3];
1305 if ins.opcode = P_Array_Load then [
1306 var vgii := ins.params[3];
1307 var vi := ctx.variables[vgii];
1308 var vi_ins := ctx.instrs[vi.defining_instr];
1309 var vgis := ins.params[2];
1310 var vs := ctx.variables[vgis];
1311 var vs_ins := ctx.instrs[vs.defining_instr];
1312 if vi_ins.opcode = P_Load_Const and vs_ins.opcode = P_Array_Create then [
1313 var idx := blob_to_int(vi_ins.params[1 ..]);
1314 if idx >= 0 and idx < vs_ins.params[2] then [
1315 return ins.params[0], vs_ins.params[5 + idx * 2];
1318 if vi_ins.opcode = P_Load_Const and vs_ins.opcode = P_Array_Fill then [
1319 var vgll := vs_ins.params[4];
1320 var vl := ctx.variables[vgll];
1321 var vl_ins := ctx.instrs[vl.defining_instr];
1322 if vl_ins.opcode = P_Load_Const then [
1323 var idx := blob_to_int(vi_ins.params[1 ..]);
1324 var length := blob_to_int(vl_ins.params[1 ..]);
1325 if idx >= 0 and idx < length then [
1326 return ins.params[0], vs_ins.params[3];
1336 fn misc_opt(ctx : context) : context
1338 var n_blocks := len(ctx.blocks);
1342 for bgi := 0 to n_blocks do [
1343 var block := ctx.blocks[bgi];
1344 if not block.active then
1346 var l := len(block.instrs);
1347 for ili := 0 to l do [
1348 var igi := ctx.blocks[bgi].instrs[ili];
1349 var ins := ctx.instrs[igi];
1350 ins := remap_instruction(ins, ctx.var_map, false);
1351 var did_something : bool;
1352 //eval debug("simplify_instr: bb " + ntos(bgi) + ", idx " + ntos(ili));
1353 ins, did_something := simplify_instr(ctx, ins);
1354 if did_something then
1356 ctx.instrs[igi] := ins;
1358 var src, dst := substitute_variable(ctx, ins);
1359 if src >= 0, ctx.var_map[src] <> dst then [
1360 ctx.var_map[src] := dst;
1364 if ins.opcode = P_Jmp_False then [
1365 var vgi1 := ins.params[0];
1366 var v1 := ctx.variables[vgi1];
1367 var v1_ins := ctx.instrs[v1.defining_instr];
1368 var vgir := ins.params[1];
1369 var vr := ctx.variables[vgir];
1370 if v1_ins.opcode = P_Load_Const then [
1371 var const_int := blob_to_int(v1_ins.params[1 ..]);
1372 ctx.blocks[bgi].instrs := ctx.blocks[bgi].instrs[ .. l - 1];
1373 if const_int = 0 then [
1374 ctx := deactivate_arrow(ctx, bgi, 2);
1375 ctx := deactivate_arrow(ctx, bgi, 0);
1376 ] else if const_int = 1 then [
1377 ctx := deactivate_arrow(ctx, bgi, 2);
1378 ctx := deactivate_arrow(ctx, bgi, 1);
1380 abort internal("invalid constant in bool context: " + ntos(const_int));
1381 ctx.should_retry := true;
1382 ] else if v1_ins.opcode = P_IO and v1_ins.params[0] = IO_Exception_Make then [
1383 ctx.blocks[bgi].instrs := ctx.blocks[bgi].instrs[ .. l - 1];
1384 ctx := deactivate_arrow(ctx, bgi, 0);
1385 ctx := deactivate_arrow(ctx, bgi, 1);
1386 ctx.should_retry := true;
1397 fn dce(ctx : context) : context
1399 for vgi := 0 to len(ctx.variables) do [
1400 ctx.variables[vgi].color := -1;
1402 var worklist : var_set := 0;
1403 var n_blocks := len(ctx.blocks);
1404 for bgi := 0 to n_blocks do [
1405 var block := ctx.blocks[bgi];
1406 if not block.active then
1408 var l := len(block.instrs);
1409 //eval debug("block: " + ntos(bgi));
1411 var igi_last := block.instrs[l - 1];
1412 var ins := ctx.instrs[igi_last];
1413 //eval debug("l: " + ntos(l) + " opcode: " + ntos(ins.opcode));
1414 if ins.opcode = P_Return or ins.opcode = P_Jmp_False then [
1415 var read_mask := set_to_mask(ins, ins.read_set);
1416 worklist or= read_mask;
1417 //eval debug("read_mask: " + ntos_base(read_mask, 2));
1420 // function arguments must not be elided, even if they are unused
1421 var igi_first := block.instrs[0];
1422 ins := ctx.instrs[igi_first];
1423 if ins.opcode = P_Args then [
1424 var write_mask := set_to_mask(ins, ins.write_set);
1425 while write_mask <> 0 do [
1426 var vgi : int := bsr write_mask;
1427 write_mask btr= vgi;
1428 if ctx.variables[vgi].type_index <> T_Type then [
1429 ctx.variables[vgi].color := vgi;
1434 for ili := 0 to l do [
1435 var igi := block.instrs[ili];
1436 var ins := ctx.instrs[igi];
1437 if ins.opcode = P_Eval or ins.opcode = P_Keep then [
1438 if ins.params[0] >= 0 then
1439 worklist bts= ins.params[0];
1444 var done : var_set := 0;
1445 while worklist <> 0 do [
1446 //eval debug("worklist: " + ntos_base(worklist, 2));
1447 var vgi : int := bsr worklist;
1449 if ctx.variables[vgi].type_index <> T_Type then
1450 ctx.variables[vgi].color := vgi;
1452 var igi := ctx.variables[vgi].defining_instr;
1453 var ins := ctx.instrs[igi];
1454 var var_mask := set_to_mask(ins, ins.read_set) or set_to_mask(ins, ins.write_set);
1455 //eval debug("variable " + ntos(vgi) + " defined at " + ntos(igi) + " opcode " + ntos(ins.opcode) + " read_mask " + mtos(set_to_mask(ins, ins.read_set)) + " write_mask " + mtos(set_to_mask(ins, ins.write_set)));
1456 worklist or= var_mask and not done;
1462 fn dce2(ctx : context) : context
1464 for vgi := 0 to len(ctx.variables) do [
1465 ctx.variables[vgi].needed := false;
1467 var worklist : var_set := 0;
1468 for vgi := 0 to len(ctx.variables) do [
1469 ctx := remap_variable(ctx, vgi);
1470 var v := ctx.variables[vgi].type_index;
1473 if ctx.variables[vgi].color >= 0 then
1477 for bgi := 0 to len(ctx.blocks) do [
1478 if not ctx.blocks[bgi].active then
1480 if len(ctx.blocks[bgi].instrs) > 0 then [
1481 var ili := len(ctx.blocks[bgi].instrs) - 1;
1482 var igi := ctx.blocks[bgi].instrs[ili];
1483 var ins := ctx.instrs[igi];
1484 if ins.write_set = 0 then [
1485 var read_mask := set_to_mask(ins, ins.read_set);
1486 worklist or= read_mask;
1491 var done : var_set := 0;
1492 while worklist <> 0 do [
1493 //eval debug("worklist: " + ntos_base(worklist, 2));
1494 var vgi : int := bsr worklist;
1496 ctx.variables[vgi].needed := true;
1498 var igi := ctx.variables[vgi].defining_instr;
1501 var ins := ctx.instrs[igi];
1502 var var_mask := set_to_mask(ins, ins.read_set) or set_to_mask(ins, ins.write_set);
1503 //eval debug("variable " + ntos(vgi) + " defined at " + ntos(igi) + " opcode " + ntos(ins.opcode) + " read_mask " + mtos(set_to_mask(ins, ins.read_set)) + " write_mask " + mtos(set_to_mask(ins, ins.write_set)));
1504 worklist or= var_mask and not done;
1507 for bgi := 0 to len(ctx.blocks) do [
1508 if not ctx.blocks[bgi].active then
1511 while len_greater_than(int, ctx.blocks[bgi].instrs, ili) do [
1512 var igi := ctx.blocks[bgi].instrs[ili];
1513 var ins := ctx.instrs[igi];
1514 if ins.opcode = P_Args then
1516 var write_set := ins.write_set;
1517 if write_set = 0 then
1519 while write_set <> 0 do [
1520 var p : int := bsr write_set;
1522 var v := ins.params[p];
1523 if ctx.variables[v].needed then
1525 if ctx.variables[v].color >= 0 then
1528 ctx.blocks[bgi].instrs := ctx.blocks[bgi].instrs[ .. ili ] + ctx.blocks[bgi].instrs[ ili + 1 .. ];
1539 fn create_lt(ctx : context) : context
1541 var did_something need_retry : bool;
1543 did_something := false;
1544 need_retry := false;
1546 for vgi := 0 to len(ctx.variables) do [
1547 var v := ctx.variables[vgi];
1548 if v.local_type >= 0 then
1550 if v.defining_instr < 0 then
1552 var ins := ctx.instrs[v.defining_instr];
1553 if ins.opcode = P_Record_Type then [
1554 var ltfr := local_type_flat_record.[
1555 non_flat_record : -1,
1556 flat_types : empty(int),
1558 for i := 0 to ins.params[1] do [
1559 var l := ins.params[2 + i];
1560 if l = T_Undetermined then [
1564 ltfr.flat_types +<= l;
1565 ] else if ctx.variables[l].local_type >= 0 then [
1566 ltfr.flat_types +<= ctx.variables[l].local_type;
1573 var n, f := function_load(ins.params[2 + ins.params[1] .. ]);
1574 ltfr.non_flat_record := len(ctx.local_types);
1575 ctx.local_types +<= local_type.rec.(f);
1577 ctx.variables[vgi].local_type := len(ctx.local_types);
1578 ctx.local_types +<= local_type.flat_rec.(ltfr);
1579 did_something := true;
1580 ] else if ins.opcode = P_Array_Fixed then [
1581 var ltfa := local_type_flat_array.[
1582 flat_type : T_InvalidType,
1583 number_of_elements : 1,
1585 var shape := ins.params[2];
1586 var vt2 := ctx.variables[shape];
1587 if vt2.defining_instr < 0 then [
1590 var in2 := ctx.instrs[vt2.defining_instr];
1591 if in2.opcode <> P_Array_Create then [
1594 for i := 0 to in2.params[2] do [
1595 var d := in2.params[5 + 2 * i];
1596 var vt3 := ctx.variables[d];
1597 if vt3.defining_instr < 0 then [
1600 var in3 := ctx.instrs[vt3.defining_instr];
1601 if in3.opcode <> P_Load_Const then [
1604 var n := blob_to_int(in3.params[1 .. ]);
1605 if n <= 0 or n > #100 then [
1608 ltfa.number_of_elements *= n;
1609 if ltfa.number_of_elements > #100 then [
1613 var l := ins.params[1];
1614 if l = T_Undetermined then [
1618 ltfa.flat_type := l;
1619 ] else if ctx.variables[l].local_type >= 0 then [
1620 ltfa.flat_type := ctx.variables[l].local_type;
1626 ctx.variables[vgi].local_type := len(ctx.local_types);
1627 ctx.local_types +<= local_type.flat_array.(ltfa);
1628 did_something := true;
1632 if need_retry, did_something then
1635 for vgi := 0 to len(ctx.variables) do [
1636 var v := ctx.variables[vgi];
1637 var typ := v.type_index;
1640 var vt := ctx.variables[typ];
1641 if vt.local_type >= 0 then
1642 ctx.variables[vgi].runtime_type := vt.local_type;
1649 fn append_copy(ctx : context, dest : int, src : int, bgi : int) : context
1651 var instr := create_instr(P_Copy, list(pcode_t).[dest, 0, src], bgi);
1652 var append_idx := len(ctx.blocks[bgi].instrs);
1653 if append_idx <> 0, ctx.instrs[ctx.blocks[bgi].instrs[append_idx - 1]].opcode = P_Jmp_False then
1655 ctx := insert_instr(ctx, instr, len(ctx.blocks[bgi].instrs));
1659 fn remove_phis(ctx : context) : context
1661 for bgi := 0 to len(ctx.blocks) do [
1662 var block := ctx.blocks[bgi];
1663 if not block.active then
1665 for ili := 0 to len(block.instrs) do [
1666 var phi_instr := ctx.instrs[block.instrs[ili]];
1667 if phi_instr.opcode <> P_Phi then
1670 var v := phi_instr.params[0];
1671 var v1, v1_idx := clone_variable(ctx, v);
1672 ctx.variables +<= v1;
1674 var copy_instr := create_instr(P_Copy, list(pcode_t).[ v, 0, v1_idx ], bgi);
1675 //eval debug("change phi to copy: " + ntos(v) + " <- " + ntos(v1_idx));
1676 ctx.instrs[block.instrs[ili]] := copy_instr;
1678 for prev_block_bli := 0 to len(ctx.blocks[bgi].pred_list) do [
1679 var block := ctx.blocks[bgi];
1680 var prev_bgi := block.pred_list[prev_block_bli];
1681 var pred_pos := block.pred_position[prev_block_bli];
1682 var src := phi_instr.params[prev_block_bli + 1];
1684 var prev_block := ctx.blocks[prev_bgi];
1686 if {false and} len(prev_block.post_list) = 1 then [
1687 ctx := append_copy(ctx, v1_idx, src, prev_bgi);
1688 //eval debug("append copy " + ntos(prev_bgi) + " " + ntos(src) + " -> " + ntos(v1_idx));
1690 var nb := new_basic_block;
1691 var nb_bgi := len(ctx.blocks);
1692 //eval debug("injecting block " + ntos(nb_bgi) + " between " + ntos(prev_bgi) + " and " + ntos(bgi));
1693 nb.pred_list := list(int).[ prev_bgi ];
1694 nb.pred_position := list(int).[ pred_pos ];
1695 nb.post_list := list(int).[ bgi ];
1696 ctx.blocks[bgi].pred_list[prev_block_bli] := nb_bgi;
1697 ctx.blocks[bgi].pred_position[prev_block_bli] := 0;
1699 if prev_block.post_list[pred_pos] <> bgi then
1700 abort internal("an arrow from previous block not found");
1702 //prev_block.post_list[pred_pos] := nb_bgi;
1703 ctx.blocks[prev_bgi].post_list[pred_pos] := nb_bgi;
1706 ctx := append_copy(ctx, v1_idx, src, nb_bgi);
1715 fn var_set_2_list(vs : var_set) : list(pcode_t)
1717 var p := empty(pcode_t);
1719 var v : int := bsr vs;
1726 fn remap_variables(ctx : context, old_new : list(int)) : context
1728 for bgi := 0 to len(ctx.blocks) do [
1729 if not ctx.blocks[bgi].active then
1731 for ili := 0 to len(ctx.blocks[bgi].instrs) do [
1732 var igi := ctx.blocks[bgi].instrs[ili];
1733 var ins := ctx.instrs[igi];
1734 if ins.opcode = P_Checkpoint then [
1735 var new_set : var_set := 0;
1736 for s := 0 to len(ins.params) do [
1737 var n := old_new[ins.params[s]];
1739 new_set bts= old_new[ins.params[s]];
1741 ctx.instrs[igi].params := var_set_2_list(new_set);
1744 var s := ins.read_set or ins.write_set;
1746 var p : int := bsr s;
1748 var parm := ctx.instrs[igi].params[p];
1750 ctx.instrs[igi].params[p] := old_new[parm];
1757 fn dve(ctx : context) : context
1759 var old_new := fill(-1, len(ctx.variables));
1760 var new_old := empty(int);
1761 for vgi := 0 to len(ctx.variables) do [
1762 ctx.variables[vgi].needed := false;
1764 for bgi := 0 to len(ctx.blocks) do [
1765 if not ctx.blocks[bgi].active then
1767 for ili := 0 to len(ctx.blocks[bgi].instrs) do [
1768 var igi := ctx.blocks[bgi].instrs[ili];
1769 var ins := ctx.instrs[igi];
1770 var s := ins.read_set or ins.write_set;
1772 var p : int := bsr s;
1774 var typ := ins.params[p];
1775 if typ >= 0, not ctx.variables[typ].needed then [
1776 ctx.variables[typ].needed := true;
1777 old_new[typ] := len(new_old);
1784 //if ctx.name = "tokenize_recursive" then eval debug("n_variables: " + ntos(len(ctx.variables)) + " -> " + ntos(len(new_old)));
1786 var new_variables := empty(variable);
1787 for i := 0 to len(new_old) do [
1788 var va := ctx.variables[new_old[i]];
1789 if va.type_index >= 0 then
1790 va.type_index := old_new[va.type_index];
1791 new_variables +<= va;
1793 ctx.variables := new_variables;
1795 ctx := remap_variables(ctx, old_new);
1800 fn encode_local_type(lt : local_type) : int
1802 var pc : list(pcode_t);
1804 pc := list(pcode_t).[ Local_Type_Record ] + function_store(lt.rec);
1805 ] else if lt is flat_rec then [
1806 pc := list(pcode_t).[ Local_Type_Flat_Record, lt.flat_rec.non_flat_record, len(lt.flat_rec.flat_types) ];
1807 for i := 0 to len(lt.flat_rec.flat_types) do [
1808 pc +<= lt.flat_rec.flat_types[i];
1810 ] else if lt is flat_array then [
1811 pc := list(pcode_t).[ Local_Type_Flat_Array, lt.flat_array.flat_type, lt.flat_array.number_of_elements ];
1813 abort internal("invalid local type");
1815 return gvn_encode(pc);
1818 fn dlte(ctx : context) : context
1820 var needed := fill(false, len(ctx.local_types));
1821 for vgi := 0 to len(ctx.variables) do [
1822 if ctx.variables[vgi].runtime_type >= 0 then
1823 needed[ctx.variables[vgi].runtime_type] := true;
1825 for bgi := 0 to len(ctx.blocks) do [
1826 if not ctx.blocks[bgi].active then
1828 for ili := 0 to len(ctx.blocks[bgi].instrs) do [
1829 var igi := ctx.blocks[bgi].instrs[ili];
1830 var ins := ctx.instrs[igi];
1831 var s := ins.lt_set;
1833 var p : int := bsr s;
1835 needed[ins.params[p]] := true;
1841 var did_something := false;
1842 for lti := 0 to len(ctx.local_types) do [
1843 if needed[lti] then [
1844 var lt := ctx.local_types[lti];
1845 if lt is flat_rec then [
1846 if not needed[lt.flat_rec.non_flat_record] then [
1847 needed[lt.flat_rec.non_flat_record] := true;
1848 did_something := true;
1850 for i := 0 to len(lt.flat_rec.flat_types) do [
1851 if lt.flat_rec.flat_types[i] >= 0 then [
1852 if not needed[lt.flat_rec.flat_types[i]] then [
1853 needed[lt.flat_rec.flat_types[i]] := true;
1854 did_something := true;
1858 ] else if lt is flat_array then [
1859 if lt.flat_array.flat_type >= 0 then [
1860 if not needed[lt.flat_array.flat_type] then [
1861 needed[lt.flat_array.flat_type] := true;
1862 did_something := true;
1868 if not did_something then
1873 var use_map := infinite(-1);
1874 var new_local_types := empty(local_type);
1875 var old_new := fill(T_InvalidType, len(ctx.local_types));
1876 for lti := 0 to len(ctx.local_types) do [
1877 if not needed[lti] then
1879 var m := encode_local_type(ctx.local_types[lti]);
1880 if use_map[m] = -1 then [
1881 use_map[m] := len(new_local_types);
1882 old_new[lti] := len(new_local_types);
1883 new_local_types +<= ctx.local_types[lti];
1885 old_new[lti] := use_map[m];
1889 if len(new_local_types) = len(ctx.local_types) then
1892 for ili := 0 to len(new_local_types) do [
1893 if new_local_types[ili] is flat_rec then [
1894 new_local_types[ili].flat_rec.non_flat_record := old_new[new_local_types[ili].flat_rec.non_flat_record];
1895 for i := 0 to len(new_local_types[ili].flat_rec.flat_types) do
1896 if new_local_types[ili].flat_rec.flat_types[i] >= 0 then
1897 new_local_types[ili].flat_rec.flat_types[i] := old_new[new_local_types[ili].flat_rec.flat_types[i]];
1898 ] else if new_local_types[ili] is flat_array then [
1899 if new_local_types[ili].flat_array.flat_type >= 0 then
1900 new_local_types[ili].flat_array.flat_type := old_new[new_local_types[ili].flat_array.flat_type];
1903 for vgi := 0 to len(ctx.variables) do [
1904 if ctx.variables[vgi].runtime_type >= 0 then
1905 ctx.variables[vgi].runtime_type := old_new[ctx.variables[vgi].runtime_type];
1907 for bgi := 0 to len(ctx.blocks) do [
1908 if not ctx.blocks[bgi].active then
1910 for ili := 0 to len(ctx.blocks[bgi].instrs) do [
1911 var igi := ctx.blocks[bgi].instrs[ili];
1912 var ins := ctx.instrs[igi];
1913 var s := ins.lt_set;
1915 var p : int := bsr s;
1917 needed[ins.params[p]] := true;
1918 ctx.instrs[igi].params[p] := old_new[ins.params[p]];
1923 ctx.local_types := new_local_types;
1924 needed := fill(true, len(ctx.local_types));
1930 fn identify_loops(ctx : context) : context
1932 var loops : node_set := 0;
1933 for bgi := 0 to len(ctx.blocks) do [
1934 if not ctx.blocks[bgi].active then
1936 var block := ctx.blocks[bgi];
1937 for ili := 0 to len(block.instrs) do [
1938 var instr := ctx.instrs[block.instrs[ili]];
1939 if instr.opcode = P_Call or instr.opcode = P_Call_Indirect then [
1940 var output := set_to_mask(instr, instr.write_set);
1941 while output <> 0 do [
1942 var o : int := bsr output;
1944 if ctx.variables[o].color <> -1 then
1954 var did_something := false;
1956 var loops2 := loops;
1957 while loops2 <> 0 do [
1958 var bgi : int := bsr loops2;
1960 var block := ctx.blocks[bgi];
1961 for i := 0 to len(block.pred_list) do [
1962 if loops bt block.pred_list[i] then
1966 did_something := true;
1969 for i := 0 to len(block.post_list) do [
1970 if loops bt block.post_list[i] then
1974 did_something := true;
1978 if not did_something then
1982 while loops <> 0 do [
1983 var bgi : int := bsr loops;
1985 var block := ctx.blocks[bgi];
1986 for ili := 0 to len(block.instrs) do [
1987 var instr := ctx.instrs[block.instrs[ili]];
1988 var read_mask := set_to_mask(instr, instr.read_set);
1989 while read_mask <> 0 do [
1990 var vgi : int := bsr read_mask;
1992 var rt := ctx.variables[vgi].runtime_type;
1993 if rt < 0, rt >= T_FlatOption then [
1994 ctx.variables[vgi].must_be_flat := true;
1995 ctx.variables[vgi].ra_priority += 1;
1997 if rt = T_Undetermined then [
1998 ctx.variables[vgi].must_be_data := true;
1999 ctx.variables[vgi].ra_priority += 1;
2001 if rt >= 0, ctx.local_types[rt] is rec then [
2002 ctx.variables[vgi].must_be_data := true;
2003 ctx.variables[vgi].ra_priority += 1;
2008 {for vgi := 0 to len(ctx.variables) do [
2009 var rt := ctx.variables[vgi].runtime_type;
2010 if rt < 0, rt >= T_FlatOption then
2011 ctx.variables[vgi].must_be_flat := true;
2012 if rt = T_Undetermined then
2013 ctx.variables[vgi].must_be_data := true;
2014 if rt >= 0, ctx.local_types[rt] is rec then
2015 ctx.variables[vgi].must_be_data := true;
2021 fn liveness(ctx : context) : context
2023 var worklist : node_set := 0;
2024 for bgi := 0 to len(ctx.blocks) do [
2025 if not ctx.blocks[bgi].active then
2027 ctx.blocks[bgi].live_top := 0;
2028 ctx.blocks[bgi].live_bottom := 0;
2032 while worklist <> 0 do [
2033 var bgi : int := bsr worklist;
2036 var live : var_set := ctx.blocks[bgi].live_bottom;
2038 var block := ctx.blocks[bgi];
2039 var ili := len(block.instrs) - 1;
2041 var instr := ctx.instrs[block.instrs[ili]];
2043 if instr.opcode = P_Jmp_False, not live bt instr.params[0] then [
2044 live bts= instr.params[0];
2045 ctx.blocks[bgi].live_bottom := live;
2048 var read_mask := set_to_mask(instr, instr.read_set);
2049 var write_mask := set_to_mask(instr, instr.write_set);
2051 live and= not write_mask;
2056 ctx.blocks[bgi].live_top := live;
2057 block := ctx.blocks[bgi];
2059 for i := 0 to len(block.pred_list) do [
2060 var prev_bgi := block.pred_list[i];
2061 var prev_block := ctx.blocks[prev_bgi];
2062 if (live and not prev_block.live_bottom) <> 0 then [
2063 ctx.blocks[prev_bgi].live_bottom or= live;
2064 worklist bts= prev_bgi;
2072 fn update_conflict_map(cm : conflict_map, live : var_set) : conflict_map
2076 var vgi : int := bsr f;
2083 fn update_rw_conflict_map(cm : conflict_map, conflict_1 conflict_2 : var_set) : conflict_map
2085 var conflict_1_c := conflict_1;
2086 while conflict_1_c <> 0 do [
2087 var c1 : int := bsr conflict_1_c;
2088 conflict_1_c btr= c1;
2089 cm[c1] or= conflict_2;
2092 var conflict_2_c := conflict_2;
2093 while conflict_2_c <> 0 do [
2094 var c2 : int := bsr conflict_2_c;
2095 conflict_2_c btr= c2;
2096 cm[c2] or= conflict_1;
2103 fn undo_borrow(ctx : context, to_free : int, prev_live : var_set) : context
2105 var v := ctx.variables[to_free];
2106 if v.defining_instr < 0 then
2108 var ins := ctx.instrs[v.defining_instr];
2109 if ins.borrow >= 0, (ins.params[ins.borrow - 1] and Flag_Borrow) <> 0 then [
2110 var v_borrow := ins.params[ins.borrow];
2112 var v_v := ctx.variables[v_borrow];
2113 var v_def := v_v.defining_instr;
2114 if v_def >= 0 then [
2115 var v_ins := ctx.instrs[v_def];
2116 if v_ins.borrow >= 0 then [
2117 v_borrow := v_ins.params[v_ins.borrow];
2122 if not prev_live bt v_borrow then [
2123 ins.params[ins.borrow - 1] and= not Flag_Borrow;
2124 ctx.instrs[v.defining_instr] := ins;
2131 fn insert_free(ctx : context) : context
2133 var cm : conflict_map := fill(var_set, 0, len(ctx.variables));
2134 //eval debug("1: insert_free: " + ctx.name + ", " + ntos(len(ctx.variables)));
2135 for i := 0 to len(ctx.variables) do
2138 for bgi := 0 to len(ctx.blocks) do [
2139 if not ctx.blocks[bgi].active then
2142 var live : var_set := ctx.blocks[bgi].live_bottom;
2143 cm := update_conflict_map(cm, live);
2145 var block := ctx.blocks[bgi];
2147 var needs_checkpoint := false;
2148 var fused_variable := -1;
2149 for post_idx := 0 to len(block.post_list) do [
2150 var post := block.post_list[post_idx];
2151 if post < bgi then [
2152 needs_checkpoint := true;
2157 var ili := len(block.instrs) - 1;
2160 var instr1 := ctx.instrs[block.instrs[ili - 1]];
2161 var instr2 := ctx.instrs[block.instrs[ili]];
2162 if instr2.opcode = P_Jmp_False then [
2163 var bvar := instr2.params[0];
2164 var post0 := block.post_list[0];
2165 var post1 := block.post_list[1];
2166 if not ctx.blocks[post0].live_top bt bvar,
2167 not ctx.blocks[post1].live_top bt bvar then [
2168 if instr1.opcode = P_BinaryOp, instr1.params[1] = bvar then [
2169 ctx.instrs[block.instrs[ili - 1]].params[2] or= Flag_Fused_Bin_Jmp;
2170 fused_variable := bvar;
2172 if instr1.opcode = P_BinaryConstOp, instr1.params[1] = bvar then [
2173 ctx.instrs[block.instrs[ili - 1]].params[2] or= Flag_Fused_Bin_Jmp;
2174 fused_variable := bvar;
2176 if instr1.opcode = P_Array_Len_Greater_Than, instr1.params[0] = bvar then [
2177 ctx.instrs[block.instrs[ili - 1]].params[3] or= Flag_Fused_Bin_Jmp;
2178 fused_variable := bvar;
2185 var instr := ctx.instrs[block.instrs[ili]];
2187 var read_mask := set_to_mask(instr, instr.read_set);
2188 var write_mask := set_to_mask(instr, instr.write_set);
2190 var prev_live := live;
2192 live and= not write_mask;
2195 cm := update_conflict_map(cm, live);
2197 var conflict_1 := set_to_mask(instr, instr.conflict_1);
2198 var conflict_2 := set_to_mask(instr, instr.conflict_2);
2199 cm := update_rw_conflict_map(cm, conflict_1, conflict_2);
2201 var set_to_free := (read_mask or write_mask) and not prev_live;
2203 while set_to_free <> 0 do [
2204 var to_free : int := bsr set_to_free;
2205 set_to_free btr= to_free;
2206 ctx := undo_borrow(ctx, to_free, prev_live);
2209 set_to_free := write_mask and not prev_live;
2210 var freed := set_to_free;
2211 while set_to_free <> 0 do [
2212 var to_free : int := bsr set_to_free;
2213 set_to_free btr= to_free;
2215 var free_instr := create_instr(P_Free, list(pcode_t).[ to_free ], bgi);
2216 ctx := insert_instr(ctx, free_instr, ili + 1);
2217 //eval debug("2: inserting free at " + ntos(bgi) + ":" + ntos(ili + 1) + " -> " + ntos(to_free));
2220 set_to_free := read_mask and not prev_live;
2221 while set_to_free <> 0 do [
2222 var to_free : int := bsr set_to_free;
2223 set_to_free btr= to_free;
2225 var free_set : param_set := instr.free_set;
2226 while free_set <> 0 do [
2227 var param : int := bsr free_set;
2228 free_set btr= param;
2229 var v := instr.params[param];
2230 if v = to_free then [
2231 //eval debug("3: setting Flag_Free_Argument at " + ntos(bgi) + ": " + pcode_name(instr.opcode) + " param " + ntos(param) + " n " + ntos(instr.params[param-1]));
2232 if (ctx.instrs[block.instrs[ili]].params[param - 1] and Flag_Free_Argument) <> 0 then
2233 abort internal("Flag_Free_Argument is already set");
2234 ctx.instrs[block.instrs[ili]].params[param - 1] or= Flag_Free_Argument;
2235 goto skip_free_instr;
2239 if not ((write_mask and not prev_live) bt to_free) then [
2240 var free_instr := create_instr(P_Free, list(pcode_t).[ to_free ], bgi);
2241 ctx := insert_instr(ctx, free_instr, ili + 1);
2244 //eval debug("inserting free at " + ntos(bgi) + ":" + ntos(ili + 1) + " -> " + ntos(to_free));
2248 cm := update_conflict_map(cm, prev_live or freed);
2250 if instr.opcode = P_Call or instr.opcode = P_Call_Indirect then [
2251 var output := write_mask;
2252 while output <> 0 do [
2253 var o : int := bsr output;
2255 if ctx.variables[o].color <> -1 then
2260 var p_live := prev_live or write_mask;
2261 var new_live : var_set := 0;
2262 while p_live <> 0 do [
2263 var l : int := bsr p_live;
2265 if ctx.variables[l].must_be_flat or ctx.variables[l].must_be_data then
2268 var cp_instr := create_instr(P_Checkpoint, var_set_2_list(new_live), bgi);
2269 ctx := insert_instr(ctx, cp_instr, ili + 1);
2270 needs_checkpoint := false;
2277 for post_bli := 0 to len(block.post_list) do [
2278 var post_bgi := block.post_list[post_bli];
2279 //eval debug("testing cleanup: " + ntos(bgi) + " -> " + ntos(post_bli) + " -> " + ntos(post_bgi));
2280 var post_block := ctx.blocks[post_bgi];
2281 if post_block.live_top <> block.live_bottom then [
2282 if (not block.live_bottom and post_block.live_top) <> 0 then
2283 abort internal("the successor has more live variables than the predecessor");
2285 var must_free_set : var_set := block.live_bottom and not post_block.live_top;
2286 //cm := update_conflict_map(cm, post_block.live_top or must_free_set);
2287 while must_free_set <> 0 do [
2288 var to_free : int := bsr must_free_set;
2289 must_free_set btr= to_free;
2291 ctx := undo_borrow(ctx, to_free, post_block.live_top);
2293 if post_bli <= 1, to_free = fused_variable then
2296 //eval debug("4: inserting free at " + ntos(bgi) + ":" + ntos(post_bgi) + " -> " + ntos(to_free));
2297 var free_instr := create_instr(P_Free, list(pcode_t).[ to_free ], post_bgi);
2298 ctx := insert_instr(ctx, free_instr, 0);
2303 if needs_checkpoint, len(ctx.blocks[bgi].instrs) > 0 then [
2304 var live_bottom := ctx.blocks[bgi].live_bottom;
2306 var ili := len(ctx.blocks[bgi].instrs);
2308 var instr := ctx.instrs[ctx.blocks[bgi].instrs[ili - 1]];
2309 if instr.opcode = P_Jmp_False or instr.opcode = P_Return then
2311 if fused_variable >= 0 then [
2314 var instr := ctx.instrs[ctx.blocks[bgi].instrs[ili]];
2315 if instr.opcode = P_Free then [
2318 if instr.opcode = P_BinaryOp, (instr.params[2] and Flag_Fused_Bin_Jmp) <> 0 then [
2319 live_bottom bts= instr.params[3];
2320 live_bottom bts= instr.params[5];
2323 if instr.opcode = P_BinaryConstOp, (instr.params[2] and Flag_Fused_Bin_Jmp) <> 0 then [
2324 live_bottom bts= instr.params[3];
2327 if instr.opcode = P_Array_Len_Greater_Than, (instr.params[3] and Flag_Fused_Bin_Jmp) <> 0 then [
2328 live_bottom bts= instr.params[1];
2329 live_bottom bts= instr.params[2];
2332 abort internal("insert_free: invalid opcode " + ntos(instr.opcode));
2337 var new_live_bottom : var_set := 0;
2338 while live_bottom <> 0 do [
2339 var l : int := bsr live_bottom;
2341 if ctx.variables[l].must_be_flat or ctx.variables[l].must_be_data then
2342 new_live_bottom bts= l;
2344 var cp_instr := create_instr(P_Checkpoint, var_set_2_list(new_live_bottom), bgi);
2345 ctx := insert_instr(ctx, cp_instr, ili);
2354 fn compare_type_index~inline(ctx : context, v1 v2 : int) : int := ctx.variables[v1].type_index - ctx.variables[v2].type_index;
2355 fn type_index_equal(ctx : context, v1 v2 : int) : bool := compare_type_index(ctx, v1, v2) = 0;
2356 fn type_index_less(ctx : context, v1 v2 : int) : bool := compare_type_index(ctx, v1, v2) < 0;
2357 fn instance_ord_type_index(ctx : context) : class_ord(int) :=
2359 equal : type_index_equal(ctx,,),
2360 less : type_index_less(ctx,,),
2363 fn allocate_variables(ctx : context) : context
2365 var type_to_var_set : list(var_set) := fill(var_set, 0, (len(ctx.local_types) - T_Undetermined) * 4);
2366 for vgi := 0 to len(ctx.variables) do [
2367 var v := ctx.variables[vgi];
2368 if v.color = -1 then
2370 if v.runtime_type < T_Undetermined then
2371 abort internal("allocate_variables: invalid runtime_type: " + ctx.name + ", " + ntos(vgi) + "(" + v.name + "): " + ntos(v.runtime_type));
2372 type_to_var_set[(v.runtime_type - T_Undetermined) * 4 + select(v.must_be_flat, 0, 1) + select(v.must_be_data, 0, 2)] bts= vgi;
2373 if not ctx.cm[vgi] bt vgi then
2374 abort internal("self-bit not set for variable " + ntos(vgi));
2375 ctx.variables[vgi].color := -1;
2378 var ra_color := empty(tuple2(int, int));
2379 for t := 0 to len(type_to_var_set) do [
2380 var vs := type_to_var_set[t];
2383 var vgi : int := bsf vsl;
2385 ctx.variables[vgi].color := color;
2386 ra_color +<= mktuple2(-ctx.variables[vgi].ra_priority, color);
2387 var remaining := not ctx.cm[vgi] and vs;
2388 while remaining <> 0 do [
2389 var vgi2 := bsf remaining;
2391 remaining btr= vgi2;
2392 var old_color := ctx.variables[vgi2].color;
2393 if old_color <> -1 then
2395 remaining and= not ctx.cm[vgi2];
2396 ctx.variables[vgi2].color := color;
2397 ra_color[color].v1 -= ctx.variables[vgi2].ra_priority;
2402 ra_color := list_sort(ra_color);
2403 var cmap := fill(-1, color);
2404 for i := 0 to len(ra_color) do [
2405 cmap[ra_color[i].v2] := i;
2406 //eval debug("ra_color: " + ntos(i) + ", " + ntos(ra_color[i].v1) + ", " + ntos(ra_color[i].v2));
2409 var vars_for_color := fill(empty(int), color);
2410 for vgi := 0 to len(ctx.variables) do [
2411 var v := ctx.variables[vgi];
2412 if v.color = -1 then
2414 //eval debug(ctx.name + ": " + ntos(v.color) + " -> " + ntos(cmap[v.color]));
2415 v.color := cmap[v.color];
2416 vars_for_color[v.color] +<= vgi;
2419 var old_new := fill(-1, len(ctx.variables));
2420 for c := 0 to color do [
2421 var l := vars_for_color[c];
2422 l := list_sort(instance_ord_type_index(ctx), l);
2423 //if ctx.name = "tokenize_recursive" then for i := 0 to len(l) do eval debug("color " + ntos(c) + ": " + ntos(ctx.variables[l[i]].type_index));
2424 var last := T_InvalidType;
2425 for i := 0 to len(l) do [
2426 var v := ctx.variables[l[i]];
2427 if v.type_index <> last then [
2428 last := v.type_index;
2431 old_new[l[i]] := new_idx;
2434 for vgi := 0 to len(ctx.variables) do [
2435 if old_new[vgi] = -1 then [
2437 old_new[vgi] := new_idx;
2442 //if ctx.name = "tokenize_recursive" then eval debug("alloc: " + ntos(len(ctx.variables)) + " -> " + ntos(non_elided) + " -> " + ntos(new_idx) + " -> " + ntos(color) + " (" + ctx.name + ")");
2444 var new_variables := fill(uninitialized(variable), new_idx);
2445 for vgi := 0 to len(ctx.variables) do [
2446 var new := old_new[vgi];
2447 if is_uninitialized(new_variables[new]) then [
2448 new_variables[new] := ctx.variables[vgi];
2449 if new_variables[new].type_index >= 0 then
2450 new_variables[new].type_index := old_new[new_variables[new].type_index];
2451 new_variables[new].name := "";
2454 ctx.variables := new_variables;
2456 ctx := remap_variables(ctx, old_new);
2461 fn remove_redundant_frees(ctx : context) : context
2463 for bgi := 0 to len(ctx.blocks) do [
2464 if not ctx.blocks[bgi].active then
2466 var freed_vars : var_set := 0;
2468 while i < len(ctx.blocks[bgi].instrs), ctx.instrs[ctx.blocks[bgi].instrs[i]].opcode = P_Free do [
2469 var v := ctx.instrs[ctx.blocks[bgi].instrs[i]].params[0];
2470 if freed_vars bt v then [
2471 ctx.blocks[bgi].instrs := ctx.blocks[bgi].instrs[ .. i] + ctx.blocks[bgi].instrs[i + 1 .. ];
2477 while i < len(ctx.blocks[bgi].instrs), ctx.instrs[ctx.blocks[bgi].instrs[i]].opcode = P_Copy do [
2478 var v1 := ctx.instrs[ctx.blocks[bgi].instrs[i]].params[0];
2479 var v2 := ctx.instrs[ctx.blocks[bgi].instrs[i]].params[2];
2481 ctx.blocks[bgi].instrs := ctx.blocks[bgi].instrs[ .. i] + ctx.blocks[bgi].instrs[i + 1 .. ];
2487 for bgi := 0 to len(ctx.blocks) do [
2488 if not ctx.blocks[bgi].active then
2490 var i := len(ctx.blocks[bgi].instrs);
2492 var instr := ctx.instrs[ctx.blocks[bgi].instrs[i - 1]];
2493 if instr.opcode = P_Jmp_False then [
2494 var false_bgi := ctx.blocks[bgi].post_list[1];
2495 var false_block := ctx.blocks[false_bgi];
2496 if len(false_block.instrs) = 0, len(false_block.post_list) = 1, len(false_block.pred_list) = 1 then [
2497 var next_bgi := false_block.post_list[0];
2498 //eval debug("folding nodes " + ntos(bgi) + ", " + ntos(false_bgi) + ", " + ntos(next_bgi));
2499 ctx.blocks[bgi].post_list[1] := next_bgi;
2500 for j := 0 to len(ctx.blocks[next_bgi].pred_list) do [
2501 if ctx.blocks[next_bgi].pred_list[j] = false_bgi then [
2502 ctx.blocks[next_bgi].pred_list[j] := bgi;
2503 ctx.blocks[next_bgi].pred_position[j] := 1;
2506 ctx.blocks[false_bgi].pred_list := empty(int);
2507 ctx.blocks[false_bgi].pred_position := empty(int);
2508 ctx.blocks[false_bgi].post_list := empty(int);
2509 ctx := deactivate_node(ctx, false_bgi);
2518 fn check_consistency(ctx : context, msg : bytes, test_no_pred : bool) : context
2522 //eval debug("check_consistency: " + msg);
2523 for i := 0 to len(ctx.blocks) do [
2524 var block := ctx.blocks[i];
2525 if not block.active then
2527 var len_pred := len(block.pred_list);
2528 if len_pred <> len(block.pred_position) then
2529 abort internal(msg + ": the length of pred_list and pred_position differ");
2530 if test_no_pred and (len_pred = 0) <> (i = 0) then
2531 abort internal(msg + ": unexpected block with no predecessors");
2532 for j := 0 to len_pred do [
2533 var pred_bgi := block.pred_list[j];
2534 var pred_pos := block.pred_position[j];
2535 var pred_block := ctx.blocks[pred_bgi];
2536 if pred_block.post_list[pred_pos] <> i then
2537 abort internal(msg + ": pred_set - post_set mismatch (" + ntos(pred_bgi) + ", " + ntos(i) + ")");
2539 for j := 0 to len(block.post_list) do [
2540 var post_bgi := block.post_list[j];
2541 var post_block := ctx.blocks[post_bgi];
2543 for k := 0 to len(post_block.pred_list) do [
2544 if post_block.pred_list[k] = i and post_block.pred_position[k] = j then
2548 abort internal(msg + ": post_set - pred_set mismatch (" + ntos(post_bgi) + ", " + ntos(i) + ", " + ntos(match) + ")");
2550 if len(block.pred_list) <> len(block.pred_position) then
2551 abort internal(msg + ": pred_list and pred_position mismatch: " + ntos(len(block.pred_list)) + " <> " + ntos(len(block.pred_position)));
2552 for pred_i := 0 to len(block.pred_list) do [
2553 var p := block.pred_list[pred_i];
2554 var q := block.pred_position[pred_i];
2555 var p_block := ctx.blocks[p];
2556 if q >= len(p_block.post_list) then
2557 abort internal(msg + ": block(" + ntos(i) + ").pred_position is too high: " + ntos(q) + " >= " + ntos(len(p_block.post_list)));
2558 if p_block.post_list[q] <> i then
2559 abort internal(msg + ": pred_position doesn't match (" + ntos(pred_i) + ", " + ntos(p) + ", " + ntos(q) + "): " + ntos(p_block.post_list[q]) + " <> " + ntos(i));
2561 for j := 0 to len(block.instrs) do [
2562 var ins := ctx.instrs[block.instrs[j]];
2564 abort internal(msg + ": basic block doesn't match");
2571 fn process_pcode(pc : list(pcode_t), get_inline : fn(function) : list(pcode_t)) : list(pcode_t)
2574 var src_type : pcode_t := T_FlatOption;
2575 var dst_type : pcode_t := T_FlatOption;
2576 var op : pcode_t := Bin_And;
2577 var src := list(pcode_t).[ 1, 0 ];
2578 var dst := list(pcode_t).[ 1, 1 ];
2579 eval debug("start evaluate");
2580 var res := evaluate(src_type, dst_type, op, src, dst);
2581 eval debug("end evaluate");
2582 var str := "result:";
2583 for i := 0 to len(res) do [
2584 str += " " + ntos_base(res[i], 16);
2589 //eval debug("process_pcode");
2591 var ft := pc[0] and Fn_Mask;
2592 if ft <> Fn_Function then [
2593 if ft <> Fn_Record and ft <> Fn_Option then
2594 abort internal("unsupported function type " + ntos(pc[0]));
2595 { no need to optimize it, it won't be executed }
2599 var ctx := load_function_context(pc);
2600 //eval debug("optimizing: " + ctx.name);
2602 var print_passes := false;
2605 if ctx.name[0] = 'Q' then [
2606 eval debug("start waiting on " + ctx.name);
2607 for i := 0 to 1000000000 do [
2609 eval debug("end waiting on " + ctx.name);
2613 ctx := check_consistency(ctx, "start", false);
2615 var num_retries := 0;
2617 ctx.should_retry := false;
2618 ctx := check_consistency(ctx, "retry_optimize", false);
2620 if print_passes then [ eval ctx; eval debug("prune_unreachable"); if is_exception ctx then eval debug("ctx exception"); ]
2621 ctx := prune_unreachable(ctx);
2622 ctx := check_consistency(ctx, "prune_unreachable", true);
2624 if print_passes then [ eval ctx; eval debug("join_adjacent"); if is_exception ctx then eval debug("ctx exception"); ]
2625 ctx := join_adjacent(ctx);
2626 ctx := check_consistency(ctx, "join_adjacent", true);
2628 if print_passes then [ eval ctx; eval debug("propagate_types"); if is_exception ctx then eval debug("ctx exception"); ]
2629 ctx := propagate_types(ctx);
2630 ctx := check_consistency(ctx, "propagate_types", true);
2632 if print_passes then [ eval ctx; eval debug("test_uninitialized"); if is_exception ctx then eval debug("ctx exception"); ]
2633 ctx := test_uninitialized(ctx);
2634 ctx := check_consistency(ctx, "test_uninitialized", true);
2636 if print_passes then [ eval ctx; eval debug("find_dominators"); if is_exception ctx then eval debug("ctx exception"); ]
2637 ctx := find_dominators(ctx);
2638 ctx := check_consistency(ctx, "find_dominators", true);
2640 if print_passes then [ eval ctx; eval debug("find_dominance_frontiers"); if is_exception ctx then eval debug("ctx exception"); ]
2641 ctx := find_dominance_frontiers(ctx);
2642 ctx := check_consistency(ctx, "find_dominance_frontiers", true);
2644 if print_passes then [ eval ctx; eval debug("process_variables"); if is_exception ctx then eval debug("ctx exception"); ]
2645 ctx := process_variables(ctx);
2646 ctx := check_consistency(ctx, "process_variables", true);
2648 if print_passes then [ eval ctx; eval debug("find_phi_blocks"); if is_exception ctx then eval debug("ctx exception"); ]
2649 ctx := find_phi_blocks(ctx);
2650 ctx := check_consistency(ctx, "find_phi_blocks", true);
2652 if print_passes then [ eval ctx; eval debug("rename_variables"); if is_exception ctx then eval debug("ctx exception"); ]
2653 ctx := rename_variables(ctx);
2654 ctx := check_consistency(ctx, "rename_variables", true);
2656 if print_passes then [ eval ctx; eval debug("verify_ssa"); if is_exception ctx then eval debug("ctx exception"); ]
2657 ctx := verify_ssa(ctx);
2658 ctx := check_consistency(ctx, "verify_ssa", true);
2660 if print_passes then [ eval ctx; eval debug("gvn"); if is_exception ctx then eval debug("ctx exception"); ]
2662 ctx := check_consistency(ctx, "gvn", true);
2664 if print_passes then [ eval ctx; eval debug("misc_opt"); if is_exception ctx then eval debug("ctx exception"); ]
2665 ctx := misc_opt(ctx);
2666 ctx := check_consistency(ctx, "misc_opt", false);
2668 if print_passes then [ eval ctx; eval debug("prune_unreachable"); if is_exception ctx then eval debug("ctx exception"); ]
2669 ctx := prune_unreachable(ctx);
2670 ctx := check_consistency(ctx, "prune_unreachable", true);
2672 if print_passes then [ eval ctx; eval debug("dce"); if is_exception ctx then eval debug("ctx exception"); ]
2674 ctx := check_consistency(ctx, "dce", true);
2676 if print_passes then [ eval ctx; eval debug("dce2"); if is_exception ctx then eval debug("ctx exception"); ]
2678 ctx := check_consistency(ctx, "dce2", true);
2680 if print_passes then [ eval ctx; eval debug("create_lt"); if is_exception ctx then eval debug("ctx exception"); ]
2681 ctx := create_lt(ctx);
2682 ctx := check_consistency(ctx, "create_lt", true);
2684 if print_passes then [ eval ctx; eval debug("remove_phis"); if is_exception ctx then eval debug("ctx exception"); ]
2685 ctx := remove_phis(ctx);
2686 ctx := check_consistency(ctx, "remove_phis", true);
2688 if print_passes then [ eval ctx; eval debug("inline_functions"); if is_exception ctx then eval debug("ctx exception"); ]
2689 ctx := inline_functions(ctx, get_inline);
2690 ctx := check_consistency(ctx, "inline_functions", false);
2692 if print_passes then [ eval ctx; eval debug("dve"); if is_exception ctx then eval debug("ctx exception"); ]
2694 ctx := check_consistency(ctx, "dve", true);
2696 if ctx.should_retry then [
2697 //eval debug("retrying optimize");
2699 goto retry_optimize;
2702 //eval debug("retries: " + ntos(num_retries));
2704 if print_passes then [ eval ctx; eval debug("join_adjacent"); if is_exception ctx then eval debug("ctx exception"); ]
2705 ctx := join_adjacent(ctx);
2706 ctx := check_consistency(ctx, "join_adjacent", true);
2708 if print_passes then [ eval ctx; eval debug("dlte"); if is_exception ctx then eval debug("ctx exception"); ]
2710 ctx := check_consistency(ctx, "dlte", true);
2712 if print_passes then [ eval ctx; eval debug("identify_loops"); if is_exception ctx then eval debug("ctx exception"); ]
2713 ctx := identify_loops(ctx);
2714 ctx := check_consistency(ctx, "liveness", true);
2716 if print_passes then [ eval ctx; eval debug("liveness"); if is_exception ctx then eval debug("ctx exception"); ]
2717 ctx := liveness(ctx);
2718 ctx := check_consistency(ctx, "liveness", true);
2720 if print_passes then [ eval ctx; eval debug("insert_free"); if is_exception ctx then eval debug("ctx exception"); ]
2721 ctx := insert_free(ctx);
2722 ctx := check_consistency(ctx, "inset_free", true);
2724 if print_passes then [ eval ctx; eval debug("allocate_variables"); if is_exception ctx then eval debug("ctx exception"); ]
2725 ctx := allocate_variables(ctx);
2726 ctx := check_consistency(ctx, "allocate_variables", true);
2728 if print_passes then [ eval ctx; eval debug("remove_redundant_frees"); if is_exception ctx then eval debug("ctx exception"); ]
2729 ctx := remove_redundant_frees(ctx);
2730 ctx := check_consistency(ctx, "remove_redundant_frees", true);
2732 if print_passes then [ eval ctx; eval debug("check_consistency"); if is_exception ctx then eval debug("ctx exception"); ]
2733 ctx := check_consistency(ctx, "end", true);
2735 var rpc := list(pcode_t).[
2739 len(ctx.local_types),
2746 rpc += blob_store(ctx.name);
2747 for i := 0 to len(ctx.local_types) do [
2748 if ctx.local_types[i] is rec then [
2749 rpc +<= Local_Type_Record;
2750 rpc += function_store(ctx.local_types[i].rec);
2751 ] else if ctx.local_types[i] is flat_rec then [
2752 rpc +<= Local_Type_Flat_Record;
2753 rpc +<= ctx.local_types[i].flat_rec.non_flat_record;
2754 rpc +<= len(ctx.local_types[i].flat_rec.flat_types);
2755 for t := 0 to len(ctx.local_types[i].flat_rec.flat_types) do [
2756 rpc +<= ctx.local_types[i].flat_rec.flat_types[t];
2758 ] else if ctx.local_types[i] is flat_array then [
2759 rpc +<= Local_Type_Flat_Array;
2760 rpc +<= ctx.local_types[i].flat_array.flat_type;
2761 rpc +<= ctx.local_types[i].flat_array.number_of_elements;
2763 abort internal("unknown local type");
2766 for i := 0 to len(ctx.variables) do [
2767 var v := ctx.variables[i];
2768 rpc +<= v.type_index;
2769 rpc +<= v.runtime_type;
2771 rpc +<= select(v.must_be_flat, 0, VarFlag_Must_Be_Flat) or select(v.must_be_data, 0, VarFlag_Must_Be_Data);
2772 rpc += blob_store(v.name);
2777 rpc += dump_basic_blocks(ctx, false);
2779 if is_exception ctx then [
2780 pc := exception_copy(list(pcode_t), ctx);
2781 ] else if is_exception ctx.instrs then [
2782 pc := exception_copy(list(pcode_t), ctx.instrs);
2783 ] else if is_exception ctx.blocks then [
2784 pc := exception_copy(list(pcode_t), ctx.blocks);
2785 ] else if is_exception ctx.variables then [
2786 pc := exception_copy(list(pcode_t), ctx.variables);
2787 ] else if is_exception rpc then [
2788 pc := exception_copy(list(pcode_t), rpc);
2791 //eval debug("optimized: " + ctx.name);