2 * Copyright (C) 2024, 2025 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, bool) : list(pcode_t), verify : bool) : list(pcode_t);
29 uses compiler.common.blob;
30 uses compiler.common.gvn;
31 uses compiler.common.evaluate;
32 uses compiler.optimize.utils;
33 uses compiler.optimize.inline;
34 uses compiler.optimize.verify;
36 fn mtos(x : var_set) : bytes
50 fn insert_instr(ctx : context, ins : instruction, pos : int) : context
52 var id := len(ctx.instrs);
54 var block := ctx.blocks[ins.bb];
55 var new_list := block.instrs[.. pos] +< id + block.instrs[pos ..];
56 ctx.blocks[ins.bb].instrs := new_list;
60 fn deactivate_arrow(ctx : context, bgi : int, pidx : int) : context
62 var p := ctx.blocks[bgi].post_list[pidx];
63 //eval debug("deleting arrow " + ntos(bgi) + "(" + ntos(pidx) + ") -> " + ntos(p));
64 if not ctx.blocks[bgi].active then
65 abort internal("deactivating an arrow from an invalid block");
66 if not ctx.blocks[p].active then
67 abort internal("deactivating an arrow to an invalid block");
69 for j := 0 to len(ctx.blocks[p].pred_list) do [
70 if ctx.blocks[p].pred_list[j] = bgi and ctx.blocks[p].pred_position[j] = pidx then [
71 ctx.blocks[p].pred_list := ctx.blocks[p].pred_list[ .. j] + ctx.blocks[p].pred_list[j + 1 ..];
72 ctx.blocks[p].pred_position := ctx.blocks[p].pred_position[ .. j] + ctx.blocks[p].pred_position[j + 1 ..];
73 for lidx := 0 to len(ctx.blocks[p].instrs) do [
74 var ins := ctx.instrs[ctx.blocks[p].instrs[lidx]];
75 if ins.opcode <> P_Phi then
77 ins.params := ins.params[.. j + 1] + ins.params[j + 2 ..];
78 ins.read_set := ins.read_set shr 1 btc 0;
79 ctx.instrs[ctx.blocks[p].instrs[lidx]] := ins;
84 ctx.blocks[bgi].post_list := ctx.blocks[bgi].post_list[ .. pidx] + ctx.blocks[bgi].post_list[pidx + 1 .. ];
85 for i := pidx to len(ctx.blocks[bgi].post_list) do [
86 var bgi_post := ctx.blocks[bgi].post_list[i];
87 var block_post := ctx.blocks[bgi_post];
88 for j := 0 to len(block_post.pred_list) do [
89 if block_post.pred_list[j] = bgi and block_post.pred_position[j] > pidx then [
90 ctx.blocks[bgi_post].pred_position[j] -= 1;
97 fn deactivate_node(ctx : context, bgi : int) : context
99 while len(ctx.blocks[bgi].pred_list) <> 0 do [
100 var pred_bgi := ctx.blocks[bgi].pred_list[0];
101 var pred_idx := ctx.blocks[bgi].pred_position[0];
102 ctx := deactivate_arrow(ctx, pred_bgi, pred_idx);
104 while len(ctx.blocks[bgi].post_list) <> 0 do [
105 ctx := deactivate_arrow(ctx, bgi, 0);
107 ctx.blocks[bgi] := basic_block.[
110 pred_list : empty(int),
111 pred_position : empty(int),
112 post_list : empty(int),
125 fn find_dominators_1(ctx : context) : context
128 var did_something := false;
129 for bgi := 1 to len(ctx.blocks) do [
130 if not ctx.blocks[bgi].active then
132 var un_set : node_set := -1;
133 for p_idx := 0 to len(ctx.blocks[bgi].pred_list) do [
134 var pred := ctx.blocks[bgi].pred_list[p_idx];
135 un_set and= ctx.blocks[pred].dom;
138 if un_set <> ctx.blocks[bgi].dom then [
139 ctx.blocks[bgi].dom := un_set;
140 did_something := true;
144 var bgi := len(ctx.blocks);
147 if not ctx.blocks[bgi].active then
149 var un_set : node_set := -1;
150 for p_idx := 0 to len(ctx.blocks[bgi].pred_list) do [
151 var pred := ctx.blocks[bgi].pred_list[p_idx];
152 un_set and= ctx.blocks[pred].dom;
155 if un_set <> ctx.blocks[bgi].dom then [
156 ctx.blocks[bgi].dom := un_set;
157 did_something := true;
161 if did_something then
166 fn find_dominators_2(ctx : context) : context
168 for bgi := 0 to len(ctx.blocks) do [
169 if not ctx.blocks[bgi].active then
171 var dom_set := ctx.blocks[bgi].dom;
172 while dom_set <> 0 do [
173 var dom : int := bsr dom_set;
175 ctx.blocks[dom].dominates bts= bgi;
177 ctx.blocks[bgi].is_idom_of := 0;
182 fn find_dominators_3(ctx : context) : context
184 for bgi := 1 to len(ctx.blocks) do [
185 if not ctx.blocks[bgi].active then
187 ctx.blocks[bgi].idom := -1;
188 var dom_set := ctx.blocks[bgi].dom btc bgi;
189 while dom_set <> 0 do [
190 var dom : int := bsr dom_set;
192 var dominates := ctx.blocks[dom].dominates btc dom;
193 if (dominates and ctx.blocks[bgi].dom btc bgi) = 0 then [
194 //eval debug("idom (" + ntos(bgi) + ") = " + ntos(dom));
195 if ctx.blocks[bgi].idom = -1 then
196 ctx.blocks[bgi].idom := dom;
198 abort internal("a block has multiple immediate dominators");
201 if ctx.blocks[bgi].idom = -1 then [
202 abort internal("a block doesn't have immediate dominator");
204 ctx.blocks[ctx.blocks[bgi].idom].is_idom_of bts= bgi;
209 fn find_dominators(ctx : context) : context
211 var n_blocks := len(ctx.blocks);
212 ctx.blocks[0].dom := 0 bts 0;
213 ctx.blocks[0].dominates := 0;
214 for i := 1 to n_blocks do [
215 var zero : node_set := 0;
216 ctx.blocks[i].dom := (zero bts n_blocks) - 1;
217 ctx.blocks[i].dominates := 0;
220 ctx := find_dominators_1(ctx);
221 ctx := find_dominators_2(ctx);
222 ctx := find_dominators_3(ctx);
224 {for bgi := 0 to n_blocks do [
225 eval debug("dom(" + ntos(bgi) + ") = " + ntos_base(ctx.blocks[bgi].dom, 2) + ", idom = " + ntos(ctx.blocks[bgi].idom));
231 fn prune_unreachable(ctx : context) : context
233 var worklist : node_set := 0 bts 0;
234 var active : node_set := 0;
236 while worklist <> 0 do [
237 var w : int := bsr worklist;
242 for post_idx := 0 to len(ctx.blocks[w].post_list) do [
243 var p := ctx.blocks[w].post_list[post_idx];
244 if not active bt p then
249 for bgi := 0 to len(ctx.blocks) do [
250 if not active bt bgi and ctx.blocks[bgi].active then [
251 //eval debug("deactivating node " + ntos(bgi));
252 ctx := deactivate_node(ctx, bgi);
259 fn join_adjacent(ctx : context) : context
261 var n_blocks := len(ctx.blocks);
262 var did_something : bool;
265 did_something := false;
266 for bgi := 0 to n_blocks do [
267 if not ctx.blocks[bgi].active then
270 var instrs := ctx.blocks[bgi].instrs;
271 if len_greater_than(instrs, 0) then [
272 var instr := ctx.instrs[instrs[0]];
273 if instr.opcode = P_Copy, instr.params[0] = instr.params[2] then [
274 ctx.blocks[bgi].instrs := ctx.blocks[bgi].instrs[1 .. ];
278 {if len(ctx.blocks[bgi].post_list) = 3 then [
279 var false_block := ctx.blocks[bgi].post_list[1];
280 if len(ctx.blocks[false_block].instrs) = 1 and ctx.instrs[ctx.blocks[false_block].instrs[0]].opcode = P_Label then [
281 if ctx.name = "fact" then eval debug("label node " + ntos(bgi) + " -> " + ntos(false_block));
283 if len(ctx.blocks[false_block].instrs) = 0 and len(ctx.blocks[false_block].post_list) = 1 then [
284 var next_block := ctx.blocks[false_block].post_list[0];
285 if ctx.name = "fact" then eval debug("empty node " + ntos(bgi) + " -> " + ntos(false_block) + " -> " + ntos(next_block));
286 for pl := 0 to len(ctx.blocks[next_block].pred_list) do [
287 if ctx.blocks[next_block].pred_list[pl] = false_block then [
288 ctx.blocks[next_block].pred_list[pl] := bgi;
289 ctx.blocks[next_block].pred_position[pl] := 1;
292 ctx.blocks[bgi].post_list[1] := next_block;
293 ctx.blocks[false_block].pred_list := empty(int);
294 ctx.blocks[false_block].post_list := empty(int);
295 ctx := deactivate_node(ctx, false_block);
296 did_something := true;
301 if len(ctx.blocks[bgi].post_list) = 1 then [
302 var post := ctx.blocks[bgi].post_list[0];
303 if len(ctx.blocks[post].pred_list) = 1 then [
304 //eval debug("joining nodes " + ntos(bgi) + " -> " + ntos(post));
306 var instrs1 := ctx.blocks[bgi].instrs;
307 var instrs2 := ctx.blocks[post].instrs;
308 for n := 0 to len(instrs2) do [
309 var in_idx := instrs2[n];
310 if ctx.instrs[in_idx].bb <> post then
311 abort internal("bb doesn't match: " + ntos(ctx.instrs[in_idx].bb) + " <> " + ntos(post) + " (opcode " + ntos(ctx.instrs[in_idx].opcode) + ")");
312 ctx.instrs[in_idx].bb := bgi;
314 if len_greater_than(instrs1, 0) then [
315 var last1 := ctx.instrs[instrs1[len(instrs1) - 1]].opcode;
316 if last1 = P_Jmp or last1 = P_Jmp_False then [
317 instrs1 := instrs1[ .. len(instrs1) - 1];
320 if len_greater_than(instrs2, 0) then [
321 var first2 := ctx.instrs[instrs2[0]].opcode;
322 if first2 = P_Label then [
323 lbl := ctx.instrs[instrs2[0]].params[0];
324 instrs2 := instrs2[1 .. ];
327 ctx.blocks[bgi].instrs := instrs1 + instrs2;
328 ctx.blocks[bgi].post_list := ctx.blocks[post].post_list;
329 for pl := 0 to len(ctx.blocks[bgi].post_list) do [
330 var p := ctx.blocks[bgi].post_list[pl];
331 for q := 0 to len(ctx.blocks[p].pred_list) do
332 if ctx.blocks[p].pred_list[q] = post then
333 ctx.blocks[p].pred_list[q] := bgi;
335 ctx.blocks[post].pred_list := empty(int);
336 ctx := deactivate_node(ctx, post);
338 if ctx.label_to_block[lbl] <> post then
339 abort internal("label doesn't match");
340 ctx.label_to_block[lbl] := -1;
342 did_something := true;
347 if did_something then
353 fn propagate_types(ctx : context) : context
355 var did_something : bool;
357 did_something := false;
358 var n_blocks := len(ctx.blocks);
359 for bgi := 0 to n_blocks do [
360 if not ctx.blocks[bgi].active then
362 var n_instrs := len(ctx.blocks[bgi].instrs);
363 for ili := 0 to n_instrs do [
364 var ins := ctx.instrs[ ctx.blocks[bgi].instrs[ili] ];
365 if ins.opcode = P_Copy then [
366 var dest : int := ins.params[0];
367 var src : int := ins.params[2];
368 var dest_rt := ctx.variables[dest].runtime_type;
369 var src_rt := T_Type;
371 src_rt := ctx.variables[src].runtime_type;
372 else if src = T_Type then
373 src_rt := T_TypeOfType;
374 if src_rt = dest_rt then
376 if src_rt = T_Undetermined then
377 ctx.variables[src].runtime_type := dest_rt;
378 else if dest_rt = T_Undetermined then
379 ctx.variables[dest].runtime_type := src_rt;
381 if src_rt >= 0, dest_rt >= 0 then
383 abort internal("copying between variables '" + ctx.variables[src].name + "', '" + ctx.variables[dest].name + "' with types " + ntos(src_rt) + " and " + ntos(dest_rt));
385 did_something := true;
389 if did_something then
394 fn set_to_mask(ins : instruction, s : param_set) : var_set
396 var r : var_set := 0;
398 var q : int := bsr s;
400 if ins.params[q] >= 0 then
401 r bts= ins.params[q];
406 fn test_uninitialized(ctx : context) : context
408 var n_blocks := len(ctx.blocks);
410 var zero : var_set := 0;
411 ctx.blocks[0].uninitialized := (zero bts len(ctx.variables)) - 1;
412 for bgi := 1 to n_blocks do [
413 if not ctx.blocks[bgi].active then
415 ctx.blocks[bgi].uninitialized := 0;
418 var worklist : node_set := 0 bts 0;
420 while worklist <> 0 do [
421 var w : int := bsr worklist;
424 var uninit := ctx.blocks[w].uninitialized;
426 for ili := 0 to len(ctx.blocks[w].instrs) do [
427 var ins := ctx.instrs[ ctx.blocks[w].instrs[ili] ];
428 //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));
429 var read_mask := set_to_mask(ins, ins.read_set);
430 var write_mask := set_to_mask(ins, ins.write_set);
431 //var free_mask := set_to_mask(ins, ins.free_set);
432 var uninit_mask := read_mask and uninit;
433 if uninit_mask <> 0 then [
435 eval dump_basic_blocks(ctx, true);
436 eval debug("read mask: " + ntos_base(read_mask, 2));
437 eval debug("write mask: " + ntos_base(write_mask, 2));
438 //eval debug("free mask: " + ntos_base(free_mask, 2));
439 for j := 0 to len(ins.params) do
440 eval debug("param: " + ntos(ins.params[j]));
441 abort internal("uninitialized variable " + ntos_base(uninit_mask, 2) + " at bb " + ntos(w) + " in " + ntos(ili) + " opc " + ntos(ins.opcode));
443 var str := "Uninitialized variable in " + ctx.name;
444 var v : int := bsf uninit_mask;
445 if len(ctx.variables[v].name) > 0 then
446 str += ": " + ctx.variables[v].name;
447 ctx := exception_make_str(context, ec_async, error_compiler_error, 0, false, str);
450 //uninit or= free_mask;
451 uninit and= not write_mask;
454 for post := 0 to len(ctx.blocks[w].post_list) do [
455 var p := ctx.blocks[w].post_list[post];
456 if (uninit and not ctx.blocks[p].uninitialized) <> 0 then [
457 ctx.blocks[p].uninitialized or= uninit;
466 fn get_pred_set(b : basic_block) : node_set
468 var pred_set : node_set := 0;
469 for j := 0 to len(b.pred_list) do
470 pred_set bts= b.pred_list[j];
474 fn find_dominance_frontiers(ctx : context) : context
476 var n_blocks := len(ctx.blocks);
478 for bgi := 0 to n_blocks do
479 ctx.blocks[bgi].df := 0;
481 for bgi := 0 to n_blocks do [
482 if not ctx.blocks[bgi].active then
484 var pred_set := get_pred_set(ctx.blocks[bgi]);
485 if popcnt pred_set >= 2 then [
486 while pred_set <> 0 do [
487 var runner : int := bsr pred_set;
488 pred_set btr= runner;
489 while runner <> ctx.blocks[bgi].idom do [
490 ctx.blocks[runner].df bts= bgi;
491 runner := ctx.blocks[runner].idom;
497 {for bgi := 0 to n_blocks do [
498 eval debug("df(" + ntos(bgi) + ") = " + ntos_base(ctx.blocks[bgi].df, 2));
504 fn process_variables(ctx : context) : context
506 for vgi := 0 to len(ctx.variables) do [
507 ctx.variables[vgi].writing_instrs := 0;
508 ctx.variables[vgi].reaching_def := -1;
510 for bgi := 0 to len(ctx.blocks) do [
511 if not ctx.blocks[bgi].active then
513 for ili := 0 to len(ctx.blocks[bgi].instrs) do [
514 var igi := ctx.blocks[bgi].instrs[ili];
515 var ins := ctx.instrs[igi];
517 var rset := ins.read_set;
519 var rd : int := bsr rset;
521 var v := ins.params[rd];
523 //ctx.variables[v].reading_instrs bts= igi;
524 //ctx.variables[v].var_active := true;
528 var wset := ins.write_set;
530 var wr : int := bsr wset;
532 var v := ins.params[wr];
534 ctx.variables[v].writing_instrs bts= igi;
542 fn is_noclone_variable(ctx : context, vgi : int) : bool
544 return popcnt(ctx.variables[vgi].writing_instrs) = 1;
547 fn insert_phi(ctx : context, vgi : int, bgi : int) : context
549 var n : int := len(ctx.blocks[bgi].pred_list);
550 var instr := create_instr(P_Phi, fill(pcode_t, vgi, n + 1), bgi);
551 ctx := insert_instr(ctx, instr, 0);
555 fn find_phi_blocks(ctx : context) : context
557 for vgi := 0 to len(ctx.variables) do [
558 if is_noclone_variable(ctx, vgi) then
561 var f : node_set := 0;
562 var w : node_set := 0;
564 var wset := ctx.variables[vgi].writing_instrs;
566 var wr : int := bsr wset;
568 if ctx.blocks[ ctx.instrs[wr].bb ].active then
569 w bts= ctx.instrs[wr].bb;
573 var x : int := bsr w;
575 var dfw := ctx.blocks[x].df;
576 //eval debug("dfs( " + ntos(x) + ") = " + ntos_base(dfw, 2));
578 var y : int := bsr dfw;
581 if not ctx.blocks[y].uninitialized bt vgi then [
582 //eval debug("insert phi for " + ntos(vgi) + " at " + ntos(y));
583 ctx := insert_phi(ctx, vgi, y);
585 if not defs_v bt y then
588 //eval debug("don't insert phi for " + ntos(vgi) + " at " + ntos(y));
598 fn clone_variable(ctx : context, vgi : int) : (variable, int)
600 var v1_idx := len(ctx.variables);
601 var v1 := new_variable;
603 v1.type_index := ctx.variables[vgi].type_index;
604 v1.runtime_type := ctx.variables[vgi].runtime_type;
605 v1.local_type := ctx.variables[vgi].local_type;
606 v1.color := ctx.variables[vgi].color;
607 v1.name := ctx.variables[vgi].name;
608 v1.is_option_type := ctx.variables[vgi].is_option_type;
613 fn update_reaching_def(ctx : context, vgi : int, bgi : int) : context
615 var r := ctx.variables[vgi].reaching_def;
617 while r <> -1, not ctx.blocks[ctx.variables[r].defining_block].dominates bt bgi do [
618 //eval debug("go up " + ntos(r) + " -> " + ntos(ctx.variables[r].reaching_def) + " dblock " + ntos(ctx.variables[r].defining_block));
619 r := ctx.variables[r].reaching_def;
621 ctx.variables[vgi].reaching_def := r;
622 //eval debug("update_reaching_def: bgi : " + ntos(bgi) + " vgi: " + ntos(vgi) + " : " + ntos(s) + " -> " + ntos(r));
626 fn rename_variables_recursive(ctx : context, bgi : int) : context
628 //eval debug("walking block " + ntos(bgi) + " (" + ntos(len(ctx.blocks[bgi].instrs)) + ")");
630 for ili := 0 to len(ctx.blocks[bgi].instrs) do [
631 var igi := ctx.blocks[bgi].instrs[ili];
632 var instr := ctx.instrs[igi];
633 if instr.opcode <> P_Phi then [
634 var read_set := instr.read_set;
635 while read_set <> 0 do [
636 var rd_idx : int := bsr read_set;
637 read_set btr= rd_idx;
638 var v := instr.params[rd_idx];
642 if is_noclone_variable(ctx, v) then
645 //eval debug("prev reaching def " + ntos(ctx.variables[v].reaching_def));
646 ctx := update_reaching_def(ctx, v, bgi);
647 if ctx.variables[v].reaching_def = -1 then
648 abort internal("bad reaching def, bgi " + ntos(bgi) + " instr " + ntos(ili) + " v " + ntos(v) + " opcode " + ntos(instr.opcode));
649 ctx.instrs[ ctx.blocks[bgi].instrs[ili] ].params[rd_idx] := ctx.variables[v].reaching_def;
650 //eval debug("processing renamed, bgi " + ntos(bgi) + " " + ntos(v) + " -> " + ntos(ctx.variables[v].reaching_def));
653 var write_set := instr.write_set;
654 while write_set <> 0 do [
655 var wr_idx : int := bsr write_set;
656 write_set btr= wr_idx;
657 var v := instr.params[wr_idx];
659 abort internal("negative v: " + ntos(v));
661 if is_noclone_variable(ctx, v) then [
662 ctx.variables[v].defining_block := bgi;
663 ctx.variables[v].defining_instr := igi;
667 ctx := update_reaching_def(ctx, v, bgi);
669 var v1, v1_idx := clone_variable(ctx, v);
670 v1.defining_block := bgi;
671 v1.defining_instr := igi;
673 ctx.instrs[ ctx.blocks[bgi].instrs[ili] ].params[wr_idx] := v1_idx;
674 v1.reaching_def := ctx.variables[v].reaching_def;
675 ctx.variables[v].reaching_def := v1_idx;
677 ctx.variables +<= v1;
679 //eval debug("renaming bgi " + ntos(bgi) + ", idx " + ntos(ili) + ", var " + ntos(v) + " -> " + ntos(v1_idx) + " opcode " + ntos(instr.opcode));
683 for p := 0 to len(ctx.blocks[bgi].post_list) do [
684 var bbb := ctx.blocks[bgi].post_list[p];
685 var post_block := ctx.blocks[bbb];
686 for idx := 0 to len(post_block.pred_list) do [
687 if post_block.pred_list[idx] = bgi then [
688 //eval debug("bgi: " + ntos(bgi) + " p:" + ntos(idx) + " bbb:" + ntos(bbb));
689 for ili := 0 to len(ctx.blocks[bbb].instrs) do [
690 var igi := ctx.blocks[bbb].instrs[ili];
691 var instr := ctx.instrs[igi];
692 if instr.opcode <> P_Phi then
695 var v := instr.params[idx + 1];
696 ctx := update_reaching_def(ctx, v, bgi);
697 //eval debug("adjusting phi, bgi " + ntos(bgi) + " bbb " + ntos(bbb) + " " + ntos(ctx.instrs[ igi ].params[idx + 1]) + " -> " + ntos(ctx.variables[v].reaching_def));
698 ctx.instrs[ igi ].params[idx + 1] := ctx.variables[v].reaching_def;
699 if ctx.variables[v].reaching_def = -1 then
700 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));
706 var is_idom_of := ctx.blocks[bgi].is_idom_of;
707 while is_idom_of <> 0 do [
708 var next : int := bsr is_idom_of;
709 is_idom_of btr= next;
710 ctx := rename_variables_recursive(ctx, next);
715 fn rename_variables(ctx : context) : context
717 return rename_variables_recursive(ctx, 0);
720 fn verify_ssa(ctx : context) : context
724 var assign_mask : var_set := 0;
725 var n_blocks := len(ctx.blocks);
726 for bgi := 0 to n_blocks do [
727 var block := ctx.blocks[bgi];
728 if not block.active then
730 for ili := 0 to len(block.instrs) do [
731 var igi := block.instrs[ili];
732 var ins := ctx.instrs[igi];
733 var write_mask := set_to_mask(ins, ins.write_set);
734 if (assign_mask and write_mask) <> 0 then [
735 abort internal("verify_ssa: variables are assigned multiple times: " + mtos(assign_mask and write_mask));
737 assign_mask or= write_mask;
744 fn remap_instruction(ins : instruction, var_map : list(int), test_write : bool) : instruction
746 var rs := ins.read_set;
748 var idx : int := bsr rs;
750 var param := ins.params[idx];
752 ins.params[idx] := var_map[param];
755 var ws := ins.write_set;
757 var idx : int := bsr ws;
759 var param := ins.params[idx];
760 if var_map[param] <> param then
761 abort internal("output variable was remapped");
767 fn remap_variable(ctx : context, vgi : int) : context
769 var v := ctx.variables[vgi].type_index;
771 var vm := ctx.var_map[v];
772 ctx.variables[vgi].type_index := vm;
773 if vm > T_Undetermined and vm < 0 then [
774 ctx.variables[vgi].runtime_type := vm;
775 ] else if vm >= 0, ctx.variables[vm].is_option_type then [
776 if ctx.variables[vm].always_flat_option then
777 ctx.variables[vgi].runtime_type := T_AlwaysFlatOption;
779 ctx.variables[vgi].runtime_type := T_FlatOption;
785 fn gvn_recursive(ctx : context, bgi : int, vals : list(int)) : context
787 for i := 0 to len(ctx.blocks[bgi].instrs) do [
788 var igi := ctx.blocks[bgi].instrs[i];
789 var ins := ctx.instrs[igi];
790 ins := remap_instruction(ins, ctx.var_map, true);
791 ctx.instrs[igi] := ins;
792 if ins.opcode = P_Copy then [
793 var dest : int := ins.params[0];
794 var src : int := ins.params[2];
795 ctx.var_map[dest] := src;
798 if ins.opcode = P_Free or
799 ins.opcode = P_Load_Local_Type or
800 ins.opcode = P_Eval or
801 ins.opcode = P_Keep or
802 ins.opcode = P_Jmp or
803 ins.opcode = P_Jmp_False or
804 ins.opcode = P_Label or
806 ins.opcode = P_Args or
807 ins.opcode = P_Return_Vars or
808 ins.opcode = P_Return or
809 ins.opcode = P_Line_Info
812 var value_list := list(pcode_t).[ ins.opcode, len(ins.params) ];
813 for i := 0 to len(ins.params) do [
814 if ins.write_set bt i then
816 var v := ins.params[i];
817 if ins.free_set bt i + 1 then
818 v and= not Flag_Free_Argument;
822 if ins.opcode = P_UnaryOp, ins.params[0] = Un_ConvertFromInt then [
823 value_list +<= ctx.variables[ins.params[1]].runtime_type;
825 if ins.opcode = P_Copy_Type_Cast then [
826 if ctx.variables[ins.params[0]].runtime_type = T_Undetermined then
828 if ctx.variables[ins.params[1]].runtime_type = T_Undetermined then
830 value_list +<= ctx.variables[ins.params[0]].runtime_type;
832 if ins.opcode = P_Load_Const then [
833 value_list +<= ctx.variables[ins.params[0]].runtime_type;
836 var value_number := gvn_encode(value_list);
837 if vals[value_number] = -1 then [
838 vals[value_number] := igi;
841 //eval debug("gvn found a case, opcode " + ntos(ins.opcode) + " vn " + ntos_base(value_number, 16));
842 var prev_ins := ctx.instrs[vals[value_number]];
843 if ins.write_set <> prev_ins.write_set then
844 abort internal("write set of the old and new instruction doesn't match");
845 var ws := ins.write_set;
847 var idx : int := bsr ws;
849 var prev_result := prev_ins.params[idx];
850 var new_result := ins.params[idx];
851 if ctx.var_map[new_result] <> new_result then
852 abort internal("variable was already remapped");
853 ctx.var_map[new_result] := prev_result;
857 var is_idom_of := ctx.blocks[bgi].is_idom_of;
858 while is_idom_of <> 0 do [
859 var next : int := bsr is_idom_of;
860 is_idom_of btr= next;
861 ctx := gvn_recursive(ctx, next, vals);
867 fn gvn(ctx : context) : context
869 var vals := infinite(-1);
871 ctx.var_map := fill(-1, len(ctx.variables));
872 for vgi := 0 to len(ctx.variables) do
873 ctx.var_map[vgi] := vgi;
875 ctx := gvn_recursive(ctx, 0, vals);
877 for vgi := 0 to len(ctx.variables) do
878 ctx := remap_variable(ctx, vgi);
883 fn verify_positive(ctx : context, vgii : int) : bool
885 var done : var_set := 0;
886 var todo : var_set := 0;
889 var vgi : int := bsr todo;
892 var v := ctx.variables[vgi];
893 var ins := ctx.instrs[v.defining_instr];
894 if ins.opcode = P_Phi then [
895 for i := 1 to len(ins.params) do [
896 var p := ins.params[i];
897 if not done bt p then
900 ] else if ins.opcode = P_BinaryOp,
901 ins.params[0] = Bin_Add or
902 ins.params[0] = Bin_Multiply or
903 ins.params[0] = Bin_Power or
904 ins.params[0] = Bin_And or
905 ins.params[0] = Bin_Or or
906 ins.params[0] = Bin_Xor or
907 ins.params[0] = Bin_Shl or
908 ins.params[0] = Bin_Shr or
909 ins.params[0] = Bin_Bts or
910 ins.params[0] = Bin_Btr or
911 ins.params[0] = Bin_Btc then [
912 var p := ins.params[3];
913 if not done bt p then
916 if not done bt p then
919 ] else if ins.opcode = P_BinaryConstOp,
921 ins.params[0] = Bin_Add or
922 ins.params[0] = Bin_Multiply or
923 ins.params[0] = Bin_Power or
924 ins.params[0] = Bin_And or
925 ins.params[0] = Bin_Or or
926 ins.params[0] = Bin_Xor or
927 ins.params[0] = Bin_Shl or
928 ins.params[0] = Bin_Shr or
929 ins.params[0] = Bin_Bts or
930 ins.params[0] = Bin_Btr or
931 ins.params[0] = Bin_Btc 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_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 v1.runtime_type = T_AlwaysFlatOption then [
1044 var op := ins.params[0];
1045 if v1_ins.opcode = P_Load_Const then [
1046 c := blob_to_int(v1_ins.params[1 .. ]);
1047 ] else if v2_ins.opcode = P_Load_Const then [
1048 c := blob_to_int(v2_ins.params[1 .. ]);
1049 op := operator_swap(op);
1053 if op = Bin_And, c = 0 then [
1055 ] else if op = Bin_Or, c = 1 then [
1057 ] else if op = Bin_Less, c = 1 then [
1059 ] else if op = Bin_LessEqual, c = 0 then [
1061 ] else if op = Bin_Greater, c = 0 then [
1063 ] else if op = Bin_GreaterEqual, c = 1 then [
1068 var params := list(pcode_t).[ ins.params[1] ] + int_to_blob(res);
1069 return create_instr(P_Load_Const, params, ins.bb), true;
1072 if v1.runtime_type <= T_SInt8, v1.runtime_type >= T_Integer128, v2_ins.opcode = P_Load_Const then [
1073 var i := blob_to_int(v2_ins.params[1 .. ]);
1074 //if v1.runtime_type <= T_SInt8, v1.runtime_type >= T_UInt128 then eval debug("evaluating constant " + ntos(i));
1075 // this logic is copied in frame_t_from_const
1076 var lower_limit, upper_limit := -#40000000, #3fffffff;
1077 if v1.runtime_type = T_Integer8 or v1.runtime_type = T_SInt8 then
1078 lower_limit, upper_limit := -#80, #80;
1079 if v1.runtime_type = T_UInt8 then
1080 lower_limit, upper_limit := #0, #100;
1081 if v1.runtime_type = T_Integer16 or v1.runtime_type = T_SInt16 then
1082 lower_limit, upper_limit := -#8000, #8000;
1083 if v1.runtime_type = T_UInt16 then
1084 lower_limit, upper_limit := #0, #10000;
1085 if v1.runtime_type = T_UInt32 or v1.runtime_type = T_UInt64 or v1.runtime_type = T_UInt128 then
1087 if i >= lower_limit, i < upper_limit then
1088 return create_instr(P_BinaryConstOp, ins.params[ .. 4] +< i, ins.bb), true;
1090 if v1.runtime_type <= T_SInt8, v1.runtime_type >= T_Integer128, v1_ins.opcode = P_Load_Const then [
1091 var new_op := operator_swap(ins.params[0]);
1092 if new_op >= 0 then [
1093 var params := ins.params;
1094 params[0] := new_op;
1095 params[2] := ins.params[4];
1096 params[3] := ins.params[5];
1097 params[4] := ins.params[2];
1098 params[5] := ins.params[3];
1099 return create_instr(P_BinaryOp, params, ins.bb), true;
1102 if v1_ins.opcode = P_IO, v1_ins.params[0] = IO_Exception_Make,
1103 v1.runtime_type <> T_AlwaysFlatOption or (v2_ins.opcode = P_IO and v2_ins.params[0] = IO_Exception_Make) then [
1104 var params := v1_ins.params;
1105 params[4] := ins.params[1];
1106 return create_instr(P_IO, params, ins.bb), true;
1108 if v2_ins.opcode = P_IO, v2_ins.params[0] = IO_Exception_Make,
1109 v1.runtime_type <> T_AlwaysFlatOption then [
1110 var params := v2_ins.params;
1111 params[4] := ins.params[1];
1112 return create_instr(P_IO, params, ins.bb), true;
1114 if ins.params[0] = Bin_Less, v2_ins.opcode = P_Array_Len then [
1115 //eval debug(ctx.name + ": P_Array_Len_Greater_Than optimized");
1116 var params := list(pcode_t).[ vgir, v2_ins.params[1], vgi1, 0 ];
1117 return create_instr(P_Array_Len_Greater_Than, params, ins.bb), true;
1121 if ins.opcode = P_BinaryConstOp then [
1122 var vgi1 := ins.params[3];
1123 var v1 := ctx.variables[vgi1];
1124 var v1_ins := ctx.instrs[v1.defining_instr];
1125 var vgir := ins.params[1];
1126 var vr := ctx.variables[vgir];
1127 if v1_ins.opcode = P_Load_Const then [
1128 var cnst := ins.params[4];
1129 var c := evaluate_binary(v1.runtime_type, vr.runtime_type, ins.params[0], v1_ins.params[1 ..], int_to_blob(cnst));
1130 if is_exception c then
1132 var params := list(pcode_t).[ ins.params[1] ] + c;
1133 return create_instr(P_Load_Const, params, ins.bb), true;
1135 if vr.runtime_type <= T_SInt8, vr.runtime_type >= T_Integer128 then [
1136 if ins.params[0] = Bin_Multiply, ins.params[4] = 2 then [
1137 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;
1139 if ins.params[0] = Bin_Shl, ins.params[4] = 1 then [
1140 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;
1145 if ins.opcode = P_UnaryOp then [
1146 var vgi1 := ins.params[3];
1147 var v1 := ctx.variables[vgi1];
1148 var v1_ins := ctx.instrs[v1.defining_instr];
1149 var vgir := ins.params[1];
1150 var vr := ctx.variables[vgir];
1151 if v1_ins.opcode = P_Load_Const then [
1153 //str := "v1: (" + ntos(vgi1) + ")"; for i := 0 to len(v1_ins.params) do [ str += " " + ntos(v1_ins.params[i]); ]; eval debug(str);
1154 var c := evaluate_unary(v1.runtime_type, vr.runtime_type, ins.params[0], v1_ins.params[1 ..]);
1155 if is_exception c then
1157 var params := list(pcode_t).[ ins.params[1] ] + c;
1158 //str := "vr:"; for i := 0 to len(params) do [ str += " " + ntos(params[i]); ]; eval debug(str);
1159 return create_instr(P_Load_Const, params, ins.bb), true;
1161 if v1_ins.opcode = P_IO, v1_ins.params[0] = IO_Exception_Make,
1162 ins.params[0] <> Un_IsException, ins.params[0] <> Un_ExceptionClass, ins.params[0] <> Un_ExceptionType, ins.params[0] <> Un_ExceptionAux then [
1163 var params := v1_ins.params;
1164 params[4] := ins.params[1];
1165 return create_instr(P_IO, params, ins.bb), true;
1167 if ins.params[0] = Un_Not, v1_ins.opcode = P_BinaryOp or v1_ins.opcode = P_BinaryConstOp then [
1168 var new_op := operator_not(v1_ins.params[0]);
1169 if new_op >= 0 then [
1170 var params := v1_ins.params;
1171 params[0] := new_op;
1172 params[1] := ins.params[1];
1173 return create_instr(v1_ins.opcode, params, ins.bb), true;
1178 if ins.opcode = P_Option_Test then [
1179 var idx := ins.params[2];
1180 var vgis := ins.params[1];
1181 var vs := ctx.variables[vgis];
1182 var vs_ins := ctx.instrs[vs.defining_instr];
1184 if vs_ins.opcode = P_Option_Create then [
1185 is_idx := vs_ins.params[1];
1186 ] else if vs_ins.opcode = P_Load_Const then [
1187 is_idx := blob_to_int(vs_ins.params[1 ..]);
1189 if is_idx >= 0 then [
1191 if idx = is_idx then
1195 return create_instr(P_Load_Const, list(pcode_t).[ ins.params[0] ] + int_to_blob(res), ins.bb), true;
1199 if ins.opcode = P_Array_Load then [
1200 if (ins.params[1] and Flag_Index_In_Range) <> 0 then
1202 var vgis := ins.params[2];
1203 var vgii := ins.params[3];
1205 var dom_set := ctx.blocks[bgi].dom;
1206 while dom_set <> 0 do [
1207 var dom : int := bsr dom_set;
1209 var bb := ctx.blocks[dom];
1210 if not bb.active then
1211 abort internal("dominator is not active");
1212 if len(bb.pred_list) = 0 then
1214 for i := 0 to len(bb.pred_list) do [
1215 if bb.pred_position[i] <> 0 then
1217 var bb_pred := ctx.blocks[bb.pred_list[i]];
1218 if len(bb_pred.instrs) = 0 then
1220 var lins := ctx.instrs[bb_pred.instrs[len(bb_pred.instrs) - 1]];
1221 if lins.opcode <> P_Jmp_False then
1223 var vgic := lins.params[0];
1224 var dins := ctx.instrs[ctx.variables[vgic].defining_instr];
1225 if dins.opcode <> P_Array_Len_Greater_Than then
1227 if dins.params[1] <> vgis or dins.params[2] <> vgii then
1230 if not verify_positive(ctx, vgii) then
1232 //eval debug(ctx.name + ": array index optimized");
1233 ins.params[1] or= Flag_Index_In_Range;
1239 if ins.opcode = P_Array_Len then [
1240 var vgis := ins.params[1];
1241 var vs := ctx.variables[vgis];
1242 var vs_ins := ctx.instrs[vs.defining_instr];
1243 if vs_ins.opcode = P_Array_Create then [
1244 return create_instr(P_Load_Const, list(pcode_t).[ ins.params[0] ] + int_to_blob(vs_ins.params[2]), ins.bb), true;
1248 if ins.opcode = P_Array_Len_Greater_Than then [
1249 var vgis := ins.params[1];
1250 var vs := ctx.variables[vgis];
1251 var vs_ins := ctx.instrs[vs.defining_instr];
1252 var vgii := ins.params[2];
1253 var vi := ctx.variables[vgii];
1254 var vi_ins := ctx.instrs[vi.defining_instr];
1255 if vs_ins.opcode = P_Array_Create and vi_ins.opcode = P_Load_Const then [
1256 var l := blob_to_int(vi_ins.params[1 ..]);
1259 if vs_ins.params[2] > l then
1263 return create_instr(P_Load_Const, list(pcode_t).[ ins.params[0] ] + int_to_blob(v), ins.bb), true;
1268 if ins.opcode = P_Array_Append then [
1269 var vgi2 := ins.params[4];
1270 var vs2 := ctx.variables[vgi2];
1271 var vs2_ins := ctx.instrs[vs2.defining_instr];
1272 if vs2_ins.opcode = P_Array_Create, vs2_ins.params[2] = 1 then [
1273 return create_instr(P_Array_Append_One, ins.params[ .. 4] +< vs2_ins.params[5], ins.bb), true;
1278 if ins.borrow <> -1, (ins.params[ins.borrow - 1] and Flag_Borrow) = 0 then [
1279 ins.params[ins.borrow - 1] or= Flag_Borrow;
1285 fn substitute_variable(ctx : context, ins : instruction) : (int, int)
1287 if ins.opcode = P_Phi then [
1288 var p := ins.params[1];
1289 for i := 2 to len(ins.params) do
1290 if ins.params[i] <> p then
1292 return ins.params[0], ins.params[1];
1295 if ins.opcode = P_Record_Load then [
1296 var idx := ins.params[3];
1297 var vgis := ins.params[2];
1298 var vs := ctx.variables[vgis];
1299 var vs_ins := ctx.instrs[vs.defining_instr];
1300 if vs_ins.opcode = P_Record_Create then [
1301 return ins.params[0], vs_ins.params[3 + idx * 2];
1304 if ins.opcode = P_Option_Load then [
1305 var idx := ins.params[3];
1306 var vgis := ins.params[2];
1307 var vs := ctx.variables[vgis];
1308 var vs_ins := ctx.instrs[vs.defining_instr];
1309 if vs_ins.opcode = P_Option_Create then [
1310 if vs_ins.params[1] = idx then [
1311 return ins.params[0], vs_ins.params[3];
1315 if ins.opcode = P_Array_Load then [
1316 var vgii := ins.params[3];
1317 var vi := ctx.variables[vgii];
1318 var vi_ins := ctx.instrs[vi.defining_instr];
1319 var vgis := ins.params[2];
1320 var vs := ctx.variables[vgis];
1321 var vs_ins := ctx.instrs[vs.defining_instr];
1322 if vi_ins.opcode = P_Load_Const and vs_ins.opcode = P_Array_Create then [
1323 var idx := blob_to_int(vi_ins.params[1 ..]);
1324 if idx >= 0 and idx < vs_ins.params[2] then [
1325 return ins.params[0], vs_ins.params[5 + idx * 2];
1328 if vi_ins.opcode = P_Load_Const and vs_ins.opcode = P_Array_Fill then [
1329 var vgll := vs_ins.params[4];
1330 var vl := ctx.variables[vgll];
1331 var vl_ins := ctx.instrs[vl.defining_instr];
1332 if vl_ins.opcode = P_Load_Const then [
1333 var idx := blob_to_int(vi_ins.params[1 ..]);
1334 var length := blob_to_int(vl_ins.params[1 ..]);
1335 if idx >= 0 and idx < length then [
1336 return ins.params[0], vs_ins.params[3];
1346 fn misc_opt(ctx : context) : context
1348 var n_blocks := len(ctx.blocks);
1352 for bgi := 0 to n_blocks do [
1353 var block := ctx.blocks[bgi];
1354 if not block.active then
1356 var l := len(block.instrs);
1357 for ili := 0 to l do [
1358 var igi := ctx.blocks[bgi].instrs[ili];
1359 var ins := ctx.instrs[igi];
1360 ins := remap_instruction(ins, ctx.var_map, false);
1361 var did_something : bool;
1362 //eval debug("simplify_instr: bb " + ntos(bgi) + ", idx " + ntos(ili));
1363 ins, did_something := simplify_instr(ctx, ins);
1364 if did_something then
1366 ctx.instrs[igi] := ins;
1368 var src, dst := substitute_variable(ctx, ins);
1369 if src >= 0, ctx.var_map[src] <> dst then [
1370 ctx.var_map[src] := dst;
1374 if ins.opcode = P_Jmp_False then [
1375 var vgi1 := ins.params[0];
1376 var v1 := ctx.variables[vgi1];
1377 var v1_ins := ctx.instrs[v1.defining_instr];
1378 var vgir := ins.params[1];
1379 var vr := ctx.variables[vgir];
1380 if v1_ins.opcode = P_Load_Const then [
1381 var const_int := blob_to_int(v1_ins.params[1 ..]);
1382 ctx.blocks[bgi].instrs := ctx.blocks[bgi].instrs[ .. l - 1];
1383 if const_int = 0 then [
1384 ctx := deactivate_arrow(ctx, bgi, 2);
1385 ctx := deactivate_arrow(ctx, bgi, 0);
1386 ] else if const_int = 1 then [
1387 ctx := deactivate_arrow(ctx, bgi, 2);
1388 ctx := deactivate_arrow(ctx, bgi, 1);
1390 abort internal("invalid constant in bool context: " + ntos(const_int));
1391 ctx.should_retry := true;
1392 ] else if v1_ins.opcode = P_IO and v1_ins.params[0] = IO_Exception_Make then [
1393 ctx.blocks[bgi].instrs := ctx.blocks[bgi].instrs[ .. l - 1];
1394 ctx := deactivate_arrow(ctx, bgi, 0);
1395 ctx := deactivate_arrow(ctx, bgi, 1);
1396 ctx.should_retry := true;
1407 fn dce(ctx : context) : context
1409 for vgi := 0 to len(ctx.variables) do [
1410 ctx.variables[vgi].color := -1;
1412 var worklist : var_set := 0;
1413 var n_blocks := len(ctx.blocks);
1414 for bgi := 0 to n_blocks do [
1415 var block := ctx.blocks[bgi];
1416 if not block.active then
1418 var l := len(block.instrs);
1419 //eval debug("block: " + ntos(bgi));
1421 var igi_last := block.instrs[l - 1];
1422 var ins := ctx.instrs[igi_last];
1423 //eval debug("l: " + ntos(l) + " opcode: " + ntos(ins.opcode));
1424 if ins.opcode = P_Return or ins.opcode = P_Jmp_False then [
1425 var read_mask := set_to_mask(ins, ins.read_set);
1426 worklist or= read_mask;
1427 //eval debug("read_mask: " + ntos_base(read_mask, 2));
1430 // function arguments must not be elided, even if they are unused
1431 var igi_first := block.instrs[0];
1432 ins := ctx.instrs[igi_first];
1433 if ins.opcode = P_Args then [
1434 var write_mask := set_to_mask(ins, ins.write_set);
1435 while write_mask <> 0 do [
1436 var vgi : int := bsr write_mask;
1437 write_mask btr= vgi;
1438 if ctx.variables[vgi].type_index <> T_Type then [
1439 ctx.variables[vgi].color := vgi;
1444 for ili := 0 to l do [
1445 var igi := block.instrs[ili];
1446 var ins := ctx.instrs[igi];
1447 if ins.opcode = P_Eval or ins.opcode = P_Keep or ins.opcode = P_Assume or ins.opcode = P_Claim then [
1448 if ins.params[0] >= 0 then
1449 worklist bts= ins.params[0];
1454 var done : var_set := 0;
1455 while worklist <> 0 do [
1456 //eval debug("worklist: " + ntos_base(worklist, 2));
1457 var vgi : int := bsr worklist;
1459 if ctx.variables[vgi].type_index <> T_Type then
1460 ctx.variables[vgi].color := vgi;
1462 var igi := ctx.variables[vgi].defining_instr;
1463 var ins := ctx.instrs[igi];
1464 var var_mask := set_to_mask(ins, ins.read_set) or set_to_mask(ins, ins.write_set);
1465 //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)));
1466 worklist or= var_mask and not done;
1472 fn dce2(ctx : context) : context
1474 for vgi := 0 to len(ctx.variables) do [
1475 ctx.variables[vgi].needed := false;
1477 var worklist : var_set := 0;
1478 for vgi := 0 to len(ctx.variables) do [
1479 ctx := remap_variable(ctx, vgi);
1480 var v := ctx.variables[vgi].type_index;
1483 if ctx.variables[vgi].color >= 0 then
1487 for bgi := 0 to len(ctx.blocks) do [
1488 if not ctx.blocks[bgi].active then
1490 if len(ctx.blocks[bgi].instrs) > 0 then [
1491 var ili := len(ctx.blocks[bgi].instrs) - 1;
1492 var igi := ctx.blocks[bgi].instrs[ili];
1493 var ins := ctx.instrs[igi];
1494 if ins.write_set = 0 then [
1495 var read_mask := set_to_mask(ins, ins.read_set);
1496 worklist or= read_mask;
1501 var done : var_set := 0;
1502 while worklist <> 0 do [
1503 //eval debug("worklist: " + ntos_base(worklist, 2));
1504 var vgi : int := bsr worklist;
1506 ctx.variables[vgi].needed := true;
1508 var igi := ctx.variables[vgi].defining_instr;
1511 var ins := ctx.instrs[igi];
1512 var var_mask := set_to_mask(ins, ins.read_set) or set_to_mask(ins, ins.write_set);
1513 //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)));
1514 worklist or= var_mask and not done;
1517 for bgi := 0 to len(ctx.blocks) do [
1518 if not ctx.blocks[bgi].active then
1521 while len_greater_than(int, ctx.blocks[bgi].instrs, ili) do [
1522 var igi := ctx.blocks[bgi].instrs[ili];
1523 var ins := ctx.instrs[igi];
1524 if ins.opcode = P_Args then
1526 var write_set := ins.write_set;
1527 if write_set = 0 then
1529 while write_set <> 0 do [
1530 var p : int := bsr write_set;
1532 var v := ins.params[p];
1533 if ctx.variables[v].needed then
1535 if ctx.variables[v].color >= 0 then
1538 ctx.blocks[bgi].instrs := ctx.blocks[bgi].instrs[ .. ili ] + ctx.blocks[bgi].instrs[ ili + 1 .. ];
1549 fn create_lt(ctx : context) : context
1551 var did_something need_retry : bool;
1553 did_something := false;
1554 need_retry := false;
1556 for vgi := 0 to len(ctx.variables) do [
1557 var v := ctx.variables[vgi];
1558 if v.local_type >= 0 then
1560 if v.defining_instr < 0 then
1562 var ins := ctx.instrs[v.defining_instr];
1563 if ins.opcode = P_Record_Type then [
1564 var ltfr := local_type_flat_record.[
1565 non_flat_record : -1,
1566 flat_types : empty(int),
1568 for i := 0 to ins.params[1] do [
1569 var l := ins.params[2 + i];
1570 if l = T_Undetermined then [
1574 ltfr.flat_types +<= l;
1575 ] else if ctx.variables[l].local_type >= 0 then [
1576 ltfr.flat_types +<= ctx.variables[l].local_type;
1583 var n, f := function_load(ins.params[2 + ins.params[1] .. ]);
1584 ltfr.non_flat_record := len(ctx.local_types);
1585 ctx.local_types +<= local_type.rec.(f);
1587 ctx.variables[vgi].local_type := len(ctx.local_types);
1588 ctx.local_types +<= local_type.flat_rec.(ltfr);
1589 did_something := true;
1590 ] else if ins.opcode = P_Array_Fixed then [
1591 var ltfa := local_type_flat_array.[
1592 flat_type : T_InvalidType,
1593 number_of_elements : 1,
1595 var shape := ins.params[2];
1596 var vt2 := ctx.variables[shape];
1597 if vt2.defining_instr < 0 then [
1600 var in2 := ctx.instrs[vt2.defining_instr];
1601 if in2.opcode <> P_Array_Create then [
1604 for i := 0 to in2.params[2] do [
1605 var d := in2.params[5 + 2 * i];
1606 var vt3 := ctx.variables[d];
1607 if vt3.defining_instr < 0 then [
1610 var in3 := ctx.instrs[vt3.defining_instr];
1611 if in3.opcode <> P_Load_Const then [
1614 var n := blob_to_int(in3.params[1 .. ]);
1615 if n <= 0 or n > #100 then [
1618 ltfa.number_of_elements *= n;
1619 if ltfa.number_of_elements > #100 then [
1623 var l := ins.params[1];
1624 if l = T_Undetermined then [
1628 ltfa.flat_type := l;
1629 ] else if ctx.variables[l].local_type >= 0 then [
1630 ltfa.flat_type := ctx.variables[l].local_type;
1636 ctx.variables[vgi].local_type := len(ctx.local_types);
1637 ctx.local_types +<= local_type.flat_array.(ltfa);
1638 did_something := true;
1642 if need_retry, did_something then
1645 for vgi := 0 to len(ctx.variables) do [
1646 var v := ctx.variables[vgi];
1647 var typ := v.type_index;
1650 var vt := ctx.variables[typ];
1651 if vt.local_type >= 0 then
1652 ctx.variables[vgi].runtime_type := vt.local_type;
1659 fn append_copy(ctx : context, dest : int, src : int, bgi : int) : context
1661 var instr := create_instr(P_Copy, list(pcode_t).[dest, 0, src], bgi);
1662 var append_idx := len(ctx.blocks[bgi].instrs);
1663 if append_idx <> 0, ctx.instrs[ctx.blocks[bgi].instrs[append_idx - 1]].opcode = P_Jmp_False then
1665 ctx := insert_instr(ctx, instr, len(ctx.blocks[bgi].instrs));
1669 fn remove_phis(ctx : context) : context
1671 for bgi := 0 to len(ctx.blocks) do [
1672 var block := ctx.blocks[bgi];
1673 if not block.active then
1675 for ili := 0 to len(block.instrs) do [
1676 var phi_instr := ctx.instrs[block.instrs[ili]];
1677 if phi_instr.opcode <> P_Phi then
1680 var v := phi_instr.params[0];
1681 var v1, v1_idx := clone_variable(ctx, v);
1682 ctx.variables +<= v1;
1684 var copy_instr := create_instr(P_Copy, list(pcode_t).[ v, 0, v1_idx ], bgi);
1685 //eval debug("change phi to copy: " + ntos(v) + " <- " + ntos(v1_idx));
1686 ctx.instrs[block.instrs[ili]] := copy_instr;
1688 for prev_block_bli := 0 to len(ctx.blocks[bgi].pred_list) do [
1689 var block := ctx.blocks[bgi];
1690 var prev_bgi := block.pred_list[prev_block_bli];
1691 var pred_pos := block.pred_position[prev_block_bli];
1692 var src := phi_instr.params[prev_block_bli + 1];
1694 var prev_block := ctx.blocks[prev_bgi];
1696 if {false and} len(prev_block.post_list) = 1 then [
1697 ctx := append_copy(ctx, v1_idx, src, prev_bgi);
1698 //eval debug("append copy " + ntos(prev_bgi) + " " + ntos(src) + " -> " + ntos(v1_idx));
1700 var nb := new_basic_block;
1701 var nb_bgi := len(ctx.blocks);
1702 //eval debug("injecting block " + ntos(nb_bgi) + " between " + ntos(prev_bgi) + " and " + ntos(bgi));
1703 nb.pred_list := list(int).[ prev_bgi ];
1704 nb.pred_position := list(int).[ pred_pos ];
1705 nb.post_list := list(int).[ bgi ];
1706 ctx.blocks[bgi].pred_list[prev_block_bli] := nb_bgi;
1707 ctx.blocks[bgi].pred_position[prev_block_bli] := 0;
1709 if prev_block.post_list[pred_pos] <> bgi then
1710 abort internal("an arrow from previous block not found");
1712 //prev_block.post_list[pred_pos] := nb_bgi;
1713 ctx.blocks[prev_bgi].post_list[pred_pos] := nb_bgi;
1716 ctx := append_copy(ctx, v1_idx, src, nb_bgi);
1725 fn var_set_2_list(vs : var_set) : list(pcode_t)
1727 var p := empty(pcode_t);
1729 var v : int := bsr vs;
1736 fn remap_variables(ctx : context, old_new : list(int)) : context
1738 for bgi := 0 to len(ctx.blocks) do [
1739 if not ctx.blocks[bgi].active then
1741 for ili := 0 to len(ctx.blocks[bgi].instrs) do [
1742 var igi := ctx.blocks[bgi].instrs[ili];
1743 var ins := ctx.instrs[igi];
1744 if ins.opcode = P_Checkpoint then [
1745 var new_set : var_set := 0;
1746 for s := 0 to len(ins.params) do [
1747 var n := old_new[ins.params[s]];
1749 new_set bts= old_new[ins.params[s]];
1751 ctx.instrs[igi].params := var_set_2_list(new_set);
1754 var s := ins.read_set or ins.write_set;
1756 var p : int := bsr s;
1758 var parm := ctx.instrs[igi].params[p];
1760 ctx.instrs[igi].params[p] := old_new[parm];
1767 fn dve(ctx : context) : context
1769 var old_new := fill(-1, len(ctx.variables));
1770 var new_old := empty(int);
1771 for vgi := 0 to len(ctx.variables) do [
1772 ctx.variables[vgi].needed := false;
1774 for bgi := 0 to len(ctx.blocks) do [
1775 if not ctx.blocks[bgi].active then
1777 for ili := 0 to len(ctx.blocks[bgi].instrs) do [
1778 var igi := ctx.blocks[bgi].instrs[ili];
1779 var ins := ctx.instrs[igi];
1780 var s := ins.read_set or ins.write_set;
1782 var p : int := bsr s;
1784 var typ := ins.params[p];
1785 while typ >= 0, not ctx.variables[typ].needed do [
1786 ctx.variables[typ].needed := true;
1787 old_new[typ] := len(new_old);
1789 typ := ctx.variables[typ].type_index;
1795 //if ctx.name = "tokenize_recursive" then eval debug("n_variables: " + ntos(len(ctx.variables)) + " -> " + ntos(len(new_old)));
1797 var new_variables := empty(variable);
1798 for i := 0 to len(new_old) do [
1799 var va := ctx.variables[new_old[i]];
1800 if va.type_index >= 0 then
1801 va.type_index := old_new[va.type_index];
1802 new_variables +<= va;
1804 ctx.variables := new_variables;
1806 ctx := remap_variables(ctx, old_new);
1811 fn encode_local_type(lt : local_type) : int
1813 var pc : list(pcode_t);
1815 pc := list(pcode_t).[ Local_Type_Record ] + function_store(lt.rec);
1816 ] else if lt is flat_rec then [
1817 pc := list(pcode_t).[ Local_Type_Flat_Record, lt.flat_rec.non_flat_record, len(lt.flat_rec.flat_types) ];
1818 for i := 0 to len(lt.flat_rec.flat_types) do [
1819 pc +<= lt.flat_rec.flat_types[i];
1821 ] else if lt is flat_array then [
1822 pc := list(pcode_t).[ Local_Type_Flat_Array, lt.flat_array.flat_type, lt.flat_array.number_of_elements ];
1824 abort internal("invalid local type");
1826 return gvn_encode(pc);
1829 fn dlte(ctx : context) : context
1831 var needed := fill(false, len(ctx.local_types));
1832 for vgi := 0 to len(ctx.variables) do [
1833 if ctx.variables[vgi].runtime_type >= 0 then
1834 needed[ctx.variables[vgi].runtime_type] := true;
1836 for bgi := 0 to len(ctx.blocks) do [
1837 if not ctx.blocks[bgi].active then
1839 for ili := 0 to len(ctx.blocks[bgi].instrs) do [
1840 var igi := ctx.blocks[bgi].instrs[ili];
1841 var ins := ctx.instrs[igi];
1842 var s := ins.lt_set;
1844 var p : int := bsr s;
1846 needed[ins.params[p]] := true;
1852 var did_something := false;
1853 for lti := 0 to len(ctx.local_types) do [
1854 if needed[lti] then [
1855 var lt := ctx.local_types[lti];
1856 if lt is flat_rec then [
1857 if not needed[lt.flat_rec.non_flat_record] then [
1858 needed[lt.flat_rec.non_flat_record] := true;
1859 did_something := true;
1861 for i := 0 to len(lt.flat_rec.flat_types) do [
1862 if lt.flat_rec.flat_types[i] >= 0 then [
1863 if not needed[lt.flat_rec.flat_types[i]] then [
1864 needed[lt.flat_rec.flat_types[i]] := true;
1865 did_something := true;
1869 ] else if lt is flat_array then [
1870 if lt.flat_array.flat_type >= 0 then [
1871 if not needed[lt.flat_array.flat_type] then [
1872 needed[lt.flat_array.flat_type] := true;
1873 did_something := true;
1879 if not did_something then
1884 var use_map := infinite(-1);
1885 var new_local_types := empty(local_type);
1886 var old_new := fill(T_InvalidType, len(ctx.local_types));
1887 for lti := 0 to len(ctx.local_types) do [
1888 if not needed[lti] then
1890 var m := encode_local_type(ctx.local_types[lti]);
1891 if use_map[m] = -1 then [
1892 use_map[m] := len(new_local_types);
1893 old_new[lti] := len(new_local_types);
1894 new_local_types +<= ctx.local_types[lti];
1896 old_new[lti] := use_map[m];
1900 if len(new_local_types) = len(ctx.local_types) then
1903 for ili := 0 to len(new_local_types) do [
1904 if new_local_types[ili] is flat_rec then [
1905 new_local_types[ili].flat_rec.non_flat_record := old_new[new_local_types[ili].flat_rec.non_flat_record];
1906 for i := 0 to len(new_local_types[ili].flat_rec.flat_types) do
1907 if new_local_types[ili].flat_rec.flat_types[i] >= 0 then
1908 new_local_types[ili].flat_rec.flat_types[i] := old_new[new_local_types[ili].flat_rec.flat_types[i]];
1909 ] else if new_local_types[ili] is flat_array then [
1910 if new_local_types[ili].flat_array.flat_type >= 0 then
1911 new_local_types[ili].flat_array.flat_type := old_new[new_local_types[ili].flat_array.flat_type];
1914 for vgi := 0 to len(ctx.variables) do [
1915 if ctx.variables[vgi].runtime_type >= 0 then
1916 ctx.variables[vgi].runtime_type := old_new[ctx.variables[vgi].runtime_type];
1918 for bgi := 0 to len(ctx.blocks) do [
1919 if not ctx.blocks[bgi].active then
1921 for ili := 0 to len(ctx.blocks[bgi].instrs) do [
1922 var igi := ctx.blocks[bgi].instrs[ili];
1923 var ins := ctx.instrs[igi];
1924 var s := ins.lt_set;
1926 var p : int := bsr s;
1928 needed[ins.params[p]] := true;
1929 ctx.instrs[igi].params[p] := old_new[ins.params[p]];
1934 ctx.local_types := new_local_types;
1935 needed := fill(true, len(ctx.local_types));
1941 fn identify_loops(ctx : context) : context
1943 var loops : node_set := 0;
1944 for bgi := 0 to len(ctx.blocks) do [
1945 if not ctx.blocks[bgi].active then
1947 var block := ctx.blocks[bgi];
1948 for ili := 0 to len(block.instrs) do [
1949 var instr := ctx.instrs[block.instrs[ili]];
1950 if instr.opcode = P_Call or instr.opcode = P_Call_Indirect then [
1951 var output := set_to_mask(instr, instr.write_set);
1952 while output <> 0 do [
1953 var o : int := bsr output;
1955 if ctx.variables[o].color <> -1 then
1965 var did_something := false;
1967 var loops2 := loops;
1968 while loops2 <> 0 do [
1969 var bgi : int := bsr loops2;
1971 var block := ctx.blocks[bgi];
1972 for i := 0 to len(block.pred_list) do [
1973 if loops bt block.pred_list[i] then
1977 did_something := true;
1980 for i := 0 to len(block.post_list) do [
1981 if loops bt block.post_list[i] then
1985 did_something := true;
1989 if not did_something then
1993 while loops <> 0 do [
1994 var bgi : int := bsr loops;
1996 var block := ctx.blocks[bgi];
1997 for ili := 0 to len(block.instrs) do [
1998 var instr := ctx.instrs[block.instrs[ili]];
1999 var read_mask := set_to_mask(instr, instr.read_set);
2000 while read_mask <> 0 do [
2001 var vgi : int := bsr read_mask;
2003 var rt := ctx.variables[vgi].runtime_type;
2004 if rt = T_AlwaysFlatOption then [
2005 ctx.variables[vgi].must_be_flat := true;
2006 ctx.variables[vgi].ra_priority += 1;
2008 if rt < 0, rt > T_FlatOption then [
2009 ctx.variables[vgi].must_be_flat := true;
2010 ctx.variables[vgi].ra_priority += 1;
2012 if rt = T_Undetermined then [
2013 ctx.variables[vgi].must_be_data := true;
2014 ctx.variables[vgi].ra_priority += 1;
2016 if rt >= 0, ctx.local_types[rt] is rec then [
2017 ctx.variables[vgi].must_be_data := true;
2018 ctx.variables[vgi].ra_priority += 1;
2023 {for vgi := 0 to len(ctx.variables) do [
2024 var rt := ctx.variables[vgi].runtime_type;
2025 if rt = T_AlwaysFlatOption then
2026 ctx.variables[vgi].must_be_flat := true;
2027 if rt < 0, rt > T_FlatOption then
2028 ctx.variables[vgi].must_be_flat := true;
2029 if rt = T_Undetermined then
2030 ctx.variables[vgi].must_be_data := true;
2031 if rt >= 0, ctx.local_types[rt] is rec then
2032 ctx.variables[vgi].must_be_data := true;
2038 fn liveness(ctx : context) : context
2040 var worklist : node_set := 0;
2041 for bgi := 0 to len(ctx.blocks) do [
2042 if not ctx.blocks[bgi].active then
2044 ctx.blocks[bgi].live_top := 0;
2045 ctx.blocks[bgi].live_bottom := 0;
2049 while worklist <> 0 do [
2050 var bgi : int := bsr worklist;
2053 var live : var_set := ctx.blocks[bgi].live_bottom;
2055 var block := ctx.blocks[bgi];
2056 var ili := len(block.instrs) - 1;
2058 var instr := ctx.instrs[block.instrs[ili]];
2060 if instr.opcode = P_Jmp_False, not live bt instr.params[0] then [
2061 live bts= instr.params[0];
2062 ctx.blocks[bgi].live_bottom := live;
2065 var read_mask := set_to_mask(instr, instr.read_set);
2066 var write_mask := set_to_mask(instr, instr.write_set);
2068 live and= not write_mask;
2073 ctx.blocks[bgi].live_top := live;
2074 block := ctx.blocks[bgi];
2076 for i := 0 to len(block.pred_list) do [
2077 var prev_bgi := block.pred_list[i];
2078 var prev_block := ctx.blocks[prev_bgi];
2079 if (live and not prev_block.live_bottom) <> 0 then [
2080 ctx.blocks[prev_bgi].live_bottom or= live;
2081 worklist bts= prev_bgi;
2089 fn update_conflict_map(cm : conflict_map, live : var_set) : conflict_map
2093 var vgi : int := bsr f;
2100 fn update_rw_conflict_map(cm : conflict_map, conflict_1 conflict_2 : var_set) : conflict_map
2102 var conflict_1_c := conflict_1;
2103 while conflict_1_c <> 0 do [
2104 var c1 : int := bsr conflict_1_c;
2105 conflict_1_c btr= c1;
2106 cm[c1] or= conflict_2;
2109 var conflict_2_c := conflict_2;
2110 while conflict_2_c <> 0 do [
2111 var c2 : int := bsr conflict_2_c;
2112 conflict_2_c btr= c2;
2113 cm[c2] or= conflict_1;
2120 fn undo_borrow(ctx : context, to_free : int, prev_live : var_set) : context
2122 var v := ctx.variables[to_free];
2123 if v.defining_instr < 0 then
2125 var ins := ctx.instrs[v.defining_instr];
2126 if ins.borrow >= 0, (ins.params[ins.borrow - 1] and Flag_Borrow) <> 0 then [
2127 var v_borrow := ins.params[ins.borrow];
2129 var v_v := ctx.variables[v_borrow];
2130 var v_def := v_v.defining_instr;
2131 if v_def >= 0 then [
2132 var v_ins := ctx.instrs[v_def];
2133 if v_ins.borrow >= 0 then [
2134 v_borrow := v_ins.params[v_ins.borrow];
2139 if not prev_live bt v_borrow then [
2140 ins.params[ins.borrow - 1] and= not Flag_Borrow;
2141 ctx.instrs[v.defining_instr] := ins;
2148 fn insert_free(ctx : context) : context
2150 var cm : conflict_map := fill(var_set, 0, len(ctx.variables));
2151 //eval debug("1: insert_free: " + ctx.name + ", " + ntos(len(ctx.variables)));
2152 for i := 0 to len(ctx.variables) do
2155 for bgi := 0 to len(ctx.blocks) do [
2156 if not ctx.blocks[bgi].active then
2159 var live : var_set := ctx.blocks[bgi].live_bottom;
2160 cm := update_conflict_map(cm, live);
2162 var block := ctx.blocks[bgi];
2164 var needs_checkpoint := false;
2165 var fused_variable := -1;
2166 for post_idx := 0 to len(block.post_list) do [
2167 var post := block.post_list[post_idx];
2168 if post < bgi then [
2169 needs_checkpoint := true;
2174 var ili := len(block.instrs) - 1;
2177 var instr1 := ctx.instrs[block.instrs[ili - 1]];
2178 var instr2 := ctx.instrs[block.instrs[ili]];
2179 if instr2.opcode = P_Jmp_False then [
2180 var bvar := instr2.params[0];
2181 var post0 := block.post_list[0];
2182 var post1 := block.post_list[1];
2183 if not ctx.blocks[post0].live_top bt bvar,
2184 not ctx.blocks[post1].live_top bt bvar then [
2185 if instr1.opcode = P_BinaryOp, instr1.params[1] = bvar then [
2186 ctx.instrs[block.instrs[ili - 1]].params[2] or= Flag_Fused_Bin_Jmp;
2187 fused_variable := bvar;
2189 if instr1.opcode = P_BinaryConstOp, instr1.params[1] = bvar then [
2190 ctx.instrs[block.instrs[ili - 1]].params[2] or= Flag_Fused_Bin_Jmp;
2191 fused_variable := bvar;
2193 if instr1.opcode = P_Array_Len_Greater_Than, instr1.params[0] = bvar then [
2194 ctx.instrs[block.instrs[ili - 1]].params[3] or= Flag_Fused_Bin_Jmp;
2195 fused_variable := bvar;
2202 var instr := ctx.instrs[block.instrs[ili]];
2204 var read_mask := set_to_mask(instr, instr.read_set);
2205 var write_mask := set_to_mask(instr, instr.write_set);
2207 var prev_live := live;
2209 live and= not write_mask;
2212 cm := update_conflict_map(cm, live);
2214 var conflict_1 := set_to_mask(instr, instr.conflict_1);
2215 var conflict_2 := set_to_mask(instr, instr.conflict_2);
2216 cm := update_rw_conflict_map(cm, conflict_1, conflict_2);
2218 var set_to_free := (read_mask or write_mask) and not prev_live;
2220 while set_to_free <> 0 do [
2221 var to_free : int := bsr set_to_free;
2222 set_to_free btr= to_free;
2223 ctx := undo_borrow(ctx, to_free, prev_live);
2226 set_to_free := write_mask and not prev_live;
2227 var freed := set_to_free;
2228 while set_to_free <> 0 do [
2229 var to_free : int := bsr set_to_free;
2230 set_to_free btr= to_free;
2232 var free_instr := create_instr(P_Free, list(pcode_t).[ to_free ], bgi);
2233 ctx := insert_instr(ctx, free_instr, ili + 1);
2234 //eval debug("2: inserting free at " + ntos(bgi) + ":" + ntos(ili + 1) + " -> " + ntos(to_free));
2237 set_to_free := read_mask and not prev_live;
2238 while set_to_free <> 0 do [
2239 var to_free : int := bsr set_to_free;
2240 set_to_free btr= to_free;
2242 var free_set : param_set := instr.free_set;
2243 while free_set <> 0 do [
2244 var param : int := bsr free_set;
2245 free_set btr= param;
2246 var v := instr.params[param];
2247 if v = to_free then [
2248 //eval debug("3: setting Flag_Free_Argument at " + ntos(bgi) + ": " + pcode_name(instr.opcode) + " param " + ntos(param) + " n " + ntos(instr.params[param-1]));
2249 if (ctx.instrs[block.instrs[ili]].params[param - 1] and Flag_Free_Argument) <> 0 then
2250 abort internal("Flag_Free_Argument is already set");
2251 ctx.instrs[block.instrs[ili]].params[param - 1] or= Flag_Free_Argument;
2252 goto skip_free_instr;
2256 if not ((write_mask and not prev_live) bt to_free) then [
2257 var free_instr := create_instr(P_Free, list(pcode_t).[ to_free ], bgi);
2258 ctx := insert_instr(ctx, free_instr, ili + 1);
2261 //eval debug("inserting free at " + ntos(bgi) + ":" + ntos(ili + 1) + " -> " + ntos(to_free));
2265 cm := update_conflict_map(cm, prev_live or freed);
2267 if instr.opcode = P_Call or instr.opcode = P_Call_Indirect then [
2268 var output := write_mask;
2269 while output <> 0 do [
2270 var o : int := bsr output;
2272 if ctx.variables[o].color <> -1 then
2277 var p_live := prev_live or write_mask;
2278 var new_live : var_set := 0;
2279 while p_live <> 0 do [
2280 var l : int := bsr p_live;
2282 if ctx.variables[l].must_be_flat or ctx.variables[l].must_be_data then
2285 var cp_instr := create_instr(P_Checkpoint, var_set_2_list(new_live), bgi);
2286 ctx := insert_instr(ctx, cp_instr, ili + 1);
2287 needs_checkpoint := false;
2294 for post_bli := 0 to len(block.post_list) do [
2295 var post_bgi := block.post_list[post_bli];
2296 //eval debug("testing cleanup: " + ntos(bgi) + " -> " + ntos(post_bli) + " -> " + ntos(post_bgi));
2297 var post_block := ctx.blocks[post_bgi];
2298 if post_block.live_top <> block.live_bottom then [
2299 if (not block.live_bottom and post_block.live_top) <> 0 then
2300 abort internal("the successor has more live variables than the predecessor");
2302 var must_free_set : var_set := block.live_bottom and not post_block.live_top;
2303 //cm := update_conflict_map(cm, post_block.live_top or must_free_set);
2304 while must_free_set <> 0 do [
2305 var to_free : int := bsr must_free_set;
2306 must_free_set btr= to_free;
2308 ctx := undo_borrow(ctx, to_free, post_block.live_top);
2310 if post_bli <= 1, to_free = fused_variable then
2313 //eval debug("4: inserting free at " + ntos(bgi) + ":" + ntos(post_bgi) + " -> " + ntos(to_free));
2314 var free_instr := create_instr(P_Free, list(pcode_t).[ to_free ], post_bgi);
2315 ctx := insert_instr(ctx, free_instr, 0);
2320 if needs_checkpoint, len(ctx.blocks[bgi].instrs) > 0 then [
2321 var live_bottom := ctx.blocks[bgi].live_bottom;
2323 var ili := len(ctx.blocks[bgi].instrs);
2325 var instr := ctx.instrs[ctx.blocks[bgi].instrs[ili - 1]];
2326 if instr.opcode = P_Jmp_False or instr.opcode = P_Return then
2328 if fused_variable >= 0 then [
2331 var instr := ctx.instrs[ctx.blocks[bgi].instrs[ili]];
2332 if instr.opcode = P_Free then [
2335 if instr.opcode = P_BinaryOp, (instr.params[2] and Flag_Fused_Bin_Jmp) <> 0 then [
2336 live_bottom bts= instr.params[3];
2337 live_bottom bts= instr.params[5];
2340 if instr.opcode = P_BinaryConstOp, (instr.params[2] and Flag_Fused_Bin_Jmp) <> 0 then [
2341 live_bottom bts= instr.params[3];
2344 if instr.opcode = P_Array_Len_Greater_Than, (instr.params[3] and Flag_Fused_Bin_Jmp) <> 0 then [
2345 live_bottom bts= instr.params[1];
2346 live_bottom bts= instr.params[2];
2349 abort internal("insert_free: invalid opcode " + ntos(instr.opcode));
2354 var new_live_bottom : var_set := 0;
2355 while live_bottom <> 0 do [
2356 var l : int := bsr live_bottom;
2358 if ctx.variables[l].must_be_flat or ctx.variables[l].must_be_data then
2359 new_live_bottom bts= l;
2361 var cp_instr := create_instr(P_Checkpoint, var_set_2_list(new_live_bottom), bgi);
2362 ctx := insert_instr(ctx, cp_instr, ili);
2371 fn compare_type_index~inline(ctx : context, v1 v2 : int) : int := ctx.variables[v1].type_index - ctx.variables[v2].type_index;
2372 fn type_index_equal(ctx : context, v1 v2 : int) : bool := compare_type_index(ctx, v1, v2) = 0;
2373 fn type_index_less(ctx : context, v1 v2 : int) : bool := compare_type_index(ctx, v1, v2) < 0;
2374 fn instance_ord_type_index(ctx : context) : class_ord(int) :=
2376 equal : type_index_equal(ctx,,),
2377 less : type_index_less(ctx,,),
2380 fn allocate_variables(ctx : context) : context
2382 var type_to_var_set : list(var_set) := fill(var_set, 0, (len(ctx.local_types) - T_Undetermined) * 4);
2383 for vgi := 0 to len(ctx.variables) do [
2384 var v := ctx.variables[vgi];
2385 if v.color = -1 then
2387 if v.runtime_type < T_Undetermined then
2388 abort internal("allocate_variables: invalid runtime_type: " + ctx.name + ", " + ntos(vgi) + "(" + v.name + "): " + ntos(v.runtime_type));
2389 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;
2390 if not ctx.cm[vgi] bt vgi then
2391 abort internal("self-bit not set for variable " + ntos(vgi));
2392 ctx.variables[vgi].color := -1;
2395 var ra_color := empty(tuple2(int, int));
2396 for t := 0 to len(type_to_var_set) do [
2397 var vs := type_to_var_set[t];
2400 var vgi : int := bsf vsl;
2402 ctx.variables[vgi].color := color;
2403 ra_color +<= mktuple2(-ctx.variables[vgi].ra_priority, color);
2404 var remaining := not ctx.cm[vgi] and vs;
2405 while remaining <> 0 do [
2406 var vgi2 := bsf remaining;
2408 remaining btr= vgi2;
2409 var old_color := ctx.variables[vgi2].color;
2410 if old_color <> -1 then
2412 remaining and= not ctx.cm[vgi2];
2413 ctx.variables[vgi2].color := color;
2414 ra_color[color].v1 -= ctx.variables[vgi2].ra_priority;
2419 ra_color := list_sort(ra_color);
2420 var cmap := fill(-1, color);
2421 for i := 0 to len(ra_color) do [
2422 cmap[ra_color[i].v2] := i;
2423 //eval debug("ra_color: " + ntos(i) + ", " + ntos(ra_color[i].v1) + ", " + ntos(ra_color[i].v2));
2426 var vars_for_color := fill(empty(int), color);
2427 for vgi := 0 to len(ctx.variables) do [
2428 var v := ctx.variables[vgi];
2429 if v.color = -1 then
2431 //eval debug(ctx.name + ": " + ntos(v.color) + " -> " + ntos(cmap[v.color]));
2432 v.color := cmap[v.color];
2433 vars_for_color[v.color] +<= vgi;
2436 var old_new := fill(-1, len(ctx.variables));
2437 for c := 0 to color do [
2438 var l := vars_for_color[c];
2439 l := list_sort(instance_ord_type_index(ctx), l);
2440 //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));
2441 var last := T_InvalidType;
2442 for i := 0 to len(l) do [
2443 var v := ctx.variables[l[i]];
2444 if v.type_index <> last then [
2445 last := v.type_index;
2448 old_new[l[i]] := new_idx;
2451 for vgi := 0 to len(ctx.variables) do [
2452 if old_new[vgi] = -1 then [
2454 old_new[vgi] := new_idx;
2459 //if ctx.name = "tokenize_recursive" then eval debug("alloc: " + ntos(len(ctx.variables)) + " -> " + ntos(non_elided) + " -> " + ntos(new_idx) + " -> " + ntos(color) + " (" + ctx.name + ")");
2461 var new_variables := fill(uninitialized(variable), new_idx);
2462 for vgi := 0 to len(ctx.variables) do [
2463 var new := old_new[vgi];
2464 if is_uninitialized(new_variables[new]) then [
2465 new_variables[new] := ctx.variables[vgi];
2466 if new_variables[new].type_index >= 0 then
2467 new_variables[new].type_index := old_new[new_variables[new].type_index];
2468 new_variables[new].name := "";
2471 ctx.variables := new_variables;
2473 ctx := remap_variables(ctx, old_new);
2478 fn remove_redundant_frees(ctx : context) : context
2480 for bgi := 0 to len(ctx.blocks) do [
2481 if not ctx.blocks[bgi].active then
2483 var freed_vars : var_set := 0;
2485 while i < len(ctx.blocks[bgi].instrs), ctx.instrs[ctx.blocks[bgi].instrs[i]].opcode = P_Free do [
2486 var v := ctx.instrs[ctx.blocks[bgi].instrs[i]].params[0];
2487 if freed_vars bt v then [
2488 ctx.blocks[bgi].instrs := ctx.blocks[bgi].instrs[ .. i] + ctx.blocks[bgi].instrs[i + 1 .. ];
2494 while i < len(ctx.blocks[bgi].instrs), ctx.instrs[ctx.blocks[bgi].instrs[i]].opcode = P_Copy do [
2495 var v1 := ctx.instrs[ctx.blocks[bgi].instrs[i]].params[0];
2496 var v2 := ctx.instrs[ctx.blocks[bgi].instrs[i]].params[2];
2498 ctx.blocks[bgi].instrs := ctx.blocks[bgi].instrs[ .. i] + ctx.blocks[bgi].instrs[i + 1 .. ];
2504 for bgi := 0 to len(ctx.blocks) do [
2505 if not ctx.blocks[bgi].active then
2507 var i := len(ctx.blocks[bgi].instrs);
2509 var instr := ctx.instrs[ctx.blocks[bgi].instrs[i - 1]];
2510 if instr.opcode = P_Jmp_False then [
2511 var false_bgi := ctx.blocks[bgi].post_list[1];
2512 var false_block := ctx.blocks[false_bgi];
2513 if len(false_block.instrs) = 0, len(false_block.post_list) = 1, len(false_block.pred_list) = 1 then [
2514 var next_bgi := false_block.post_list[0];
2515 //eval debug("folding nodes " + ntos(bgi) + ", " + ntos(false_bgi) + ", " + ntos(next_bgi));
2516 ctx.blocks[bgi].post_list[1] := next_bgi;
2517 for j := 0 to len(ctx.blocks[next_bgi].pred_list) do [
2518 if ctx.blocks[next_bgi].pred_list[j] = false_bgi then [
2519 ctx.blocks[next_bgi].pred_list[j] := bgi;
2520 ctx.blocks[next_bgi].pred_position[j] := 1;
2523 ctx.blocks[false_bgi].pred_list := empty(int);
2524 ctx.blocks[false_bgi].pred_position := empty(int);
2525 ctx.blocks[false_bgi].post_list := empty(int);
2526 ctx := deactivate_node(ctx, false_bgi);
2535 fn check_consistency(ctx : context, msg : bytes, test_no_pred : bool) : context
2539 //eval debug("check_consistency: " + msg);
2540 for i := 0 to len(ctx.blocks) do [
2541 var block := ctx.blocks[i];
2542 if not block.active then
2544 var len_pred := len(block.pred_list);
2545 if len_pred <> len(block.pred_position) then
2546 abort internal(msg + ": the length of pred_list and pred_position differ");
2547 if test_no_pred and (len_pred = 0) <> (i = 0) then
2548 abort internal(msg + ": unexpected block with no predecessors");
2549 for j := 0 to len_pred do [
2550 var pred_bgi := block.pred_list[j];
2551 var pred_pos := block.pred_position[j];
2552 var pred_block := ctx.blocks[pred_bgi];
2553 if pred_block.post_list[pred_pos] <> i then
2554 abort internal(msg + ": pred_set - post_set mismatch (" + ntos(pred_bgi) + ", " + ntos(i) + ")");
2556 for j := 0 to len(block.post_list) do [
2557 var post_bgi := block.post_list[j];
2558 var post_block := ctx.blocks[post_bgi];
2560 for k := 0 to len(post_block.pred_list) do [
2561 if post_block.pred_list[k] = i and post_block.pred_position[k] = j then
2565 abort internal(msg + ": post_set - pred_set mismatch (" + ntos(post_bgi) + ", " + ntos(i) + ", " + ntos(match) + ")");
2567 if len(block.pred_list) <> len(block.pred_position) then
2568 abort internal(msg + ": pred_list and pred_position mismatch: " + ntos(len(block.pred_list)) + " <> " + ntos(len(block.pred_position)));
2569 for pred_i := 0 to len(block.pred_list) do [
2570 var p := block.pred_list[pred_i];
2571 var q := block.pred_position[pred_i];
2572 var p_block := ctx.blocks[p];
2573 if q >= len(p_block.post_list) then
2574 abort internal(msg + ": block(" + ntos(i) + ").pred_position is too high: " + ntos(q) + " >= " + ntos(len(p_block.post_list)));
2575 if p_block.post_list[q] <> i then
2576 abort internal(msg + ": pred_position doesn't match (" + ntos(pred_i) + ", " + ntos(p) + ", " + ntos(q) + "): " + ntos(p_block.post_list[q]) + " <> " + ntos(i));
2578 for j := 0 to len(block.instrs) do [
2579 var ins := ctx.instrs[block.instrs[j]];
2581 abort internal(msg + ": basic block doesn't match");
2588 fn process_pcode(pc : list(pcode_t), get_inline : fn(function, bool) : list(pcode_t), verify : bool) : list(pcode_t)
2591 var src_type : pcode_t := T_FlatOption;
2592 var dst_type : pcode_t := T_FlatOption;
2593 var op : pcode_t := Bin_And;
2594 var src := list(pcode_t).[ 1, 0 ];
2595 var dst := list(pcode_t).[ 1, 1 ];
2596 eval debug("start evaluate");
2597 var res := evaluate(src_type, dst_type, op, src, dst);
2598 eval debug("end evaluate");
2599 var str := "result:";
2600 for i := 0 to len(res) do [
2601 str += " " + ntos_base(res[i], 16);
2606 //eval debug("process_pcode");
2608 var ft := pc[0] and Fn_Mask;
2609 if ft <> Fn_Function then [
2610 if ft <> Fn_Record and ft <> Fn_Option then
2611 abort internal("unsupported function type " + ntos(pc[0]));
2612 { no need to optimize it, it won't be executed }
2616 var ctx := load_function_context(pc);
2617 //eval debug("optimizing: " + ctx.name);
2619 var print_passes := false;
2622 if ctx.name[0] = 'Q' then [
2623 eval debug("start waiting on " + ctx.name);
2624 for i := 0 to 1000000000 do [
2626 eval debug("end waiting on " + ctx.name);
2630 ctx := check_consistency(ctx, "start", false);
2632 var num_retries := 0;
2633 var do_verify := false;
2635 ctx.should_retry := false;
2636 ctx := check_consistency(ctx, "retry_optimize", false);
2638 if print_passes then [ eval ctx; eval debug("prune_unreachable"); if is_exception ctx then eval debug("ctx exception"); ]
2639 ctx := prune_unreachable(ctx);
2640 ctx := check_consistency(ctx, "prune_unreachable", true);
2642 if print_passes then [ eval ctx; eval debug("join_adjacent"); if is_exception ctx then eval debug("ctx exception"); ]
2643 ctx := join_adjacent(ctx);
2644 ctx := check_consistency(ctx, "join_adjacent", true);
2646 if print_passes then [ eval ctx; eval debug("propagate_types"); if is_exception ctx then eval debug("ctx exception"); ]
2647 ctx := propagate_types(ctx);
2648 ctx := check_consistency(ctx, "propagate_types", true);
2650 if print_passes then [ eval ctx; eval debug("test_uninitialized"); if is_exception ctx then eval debug("ctx exception"); ]
2651 ctx := test_uninitialized(ctx);
2652 ctx := check_consistency(ctx, "test_uninitialized", true);
2654 if print_passes then [ eval ctx; eval debug("find_dominators"); if is_exception ctx then eval debug("ctx exception"); ]
2655 ctx := find_dominators(ctx);
2656 ctx := check_consistency(ctx, "find_dominators", true);
2658 if print_passes then [ eval ctx; eval debug("find_dominance_frontiers"); if is_exception ctx then eval debug("ctx exception"); ]
2659 ctx := find_dominance_frontiers(ctx);
2660 ctx := check_consistency(ctx, "find_dominance_frontiers", true);
2662 if print_passes then [ eval ctx; eval debug("process_variables"); if is_exception ctx then eval debug("ctx exception"); ]
2663 ctx := process_variables(ctx);
2664 ctx := check_consistency(ctx, "process_variables", true);
2666 if print_passes then [ eval ctx; eval debug("find_phi_blocks"); if is_exception ctx then eval debug("ctx exception"); ]
2667 ctx := find_phi_blocks(ctx);
2668 ctx := check_consistency(ctx, "find_phi_blocks", true);
2670 if print_passes then [ eval ctx; eval debug("rename_variables"); if is_exception ctx then eval debug("ctx exception"); ]
2671 ctx := rename_variables(ctx);
2672 ctx := check_consistency(ctx, "rename_variables", true);
2674 if print_passes then [ eval ctx; eval debug("verify_ssa"); if is_exception ctx then eval debug("ctx exception"); ]
2675 ctx := verify_ssa(ctx);
2676 ctx := check_consistency(ctx, "verify_ssa", true);
2678 if print_passes then [ eval ctx; eval debug("gvn"); if is_exception ctx then eval debug("ctx exception"); ]
2680 ctx := check_consistency(ctx, "gvn", true);
2682 if print_passes then [ eval ctx; eval debug("misc_opt"); if is_exception ctx then eval debug("ctx exception"); ]
2683 ctx := misc_opt(ctx);
2684 ctx := check_consistency(ctx, "misc_opt", false);
2686 if print_passes then [ eval ctx; eval debug("prune_unreachable"); if is_exception ctx then eval debug("ctx exception"); ]
2687 ctx := prune_unreachable(ctx);
2688 ctx := check_consistency(ctx, "prune_unreachable", true);
2690 if print_passes then [ eval ctx; eval debug("dce"); if is_exception ctx then eval debug("ctx exception"); ]
2692 ctx := check_consistency(ctx, "dce", true);
2694 if print_passes then [ eval ctx; eval debug("dce2"); if is_exception ctx then eval debug("ctx exception"); ]
2696 ctx := check_consistency(ctx, "dce2", true);
2698 if print_passes then [ eval ctx; eval debug("create_lt"); if is_exception ctx then eval debug("ctx exception"); ]
2699 ctx := create_lt(ctx);
2700 ctx := check_consistency(ctx, "create_lt", true);
2703 if print_passes then [ eval ctx; eval debug("verify_function"); if is_exception ctx then eval debug("ctx exception"); ]
2704 xeval verify_function(ctx);
2707 if print_passes then [ eval ctx; eval debug("remove_phis"); if is_exception ctx then eval debug("ctx exception"); ]
2708 ctx := remove_phis(ctx);
2709 ctx := check_consistency(ctx, "remove_phis", true);
2711 if print_passes then [ eval ctx; eval debug("inline_functions"); if is_exception ctx then eval debug("ctx exception"); ]
2712 ctx := inline_functions(ctx, get_inline);
2713 ctx := check_consistency(ctx, "inline_functions", false);
2715 if print_passes then [ eval ctx; eval debug("dve"); if is_exception ctx then eval debug("ctx exception"); ]
2717 ctx := check_consistency(ctx, "dve", true);
2719 if ctx.should_retry then [
2720 //eval debug("retrying optimize");
2722 goto retry_optimize;
2725 if verify and not do_verify then [
2728 goto retry_optimize;
2731 //eval debug("retries: " + ntos(num_retries));
2733 if print_passes then [ eval ctx; eval debug("join_adjacent"); if is_exception ctx then eval debug("ctx exception"); ]
2734 ctx := join_adjacent(ctx);
2735 ctx := check_consistency(ctx, "join_adjacent", true);
2737 if print_passes then [ eval ctx; eval debug("dlte"); if is_exception ctx then eval debug("ctx exception"); ]
2739 ctx := check_consistency(ctx, "dlte", true);
2741 if print_passes then [ eval ctx; eval debug("identify_loops"); if is_exception ctx then eval debug("ctx exception"); ]
2742 ctx := identify_loops(ctx);
2743 ctx := check_consistency(ctx, "liveness", true);
2745 if print_passes then [ eval ctx; eval debug("liveness"); if is_exception ctx then eval debug("ctx exception"); ]
2746 ctx := liveness(ctx);
2747 ctx := check_consistency(ctx, "liveness", true);
2749 if print_passes then [ eval ctx; eval debug("insert_free"); if is_exception ctx then eval debug("ctx exception"); ]
2750 ctx := insert_free(ctx);
2751 ctx := check_consistency(ctx, "inset_free", true);
2753 if print_passes then [ eval ctx; eval debug("allocate_variables"); if is_exception ctx then eval debug("ctx exception"); ]
2754 ctx := allocate_variables(ctx);
2755 ctx := check_consistency(ctx, "allocate_variables", true);
2757 if print_passes then [ eval ctx; eval debug("remove_redundant_frees"); if is_exception ctx then eval debug("ctx exception"); ]
2758 ctx := remove_redundant_frees(ctx);
2759 ctx := check_consistency(ctx, "remove_redundant_frees", true);
2761 if print_passes then [ eval ctx; eval debug("check_consistency"); if is_exception ctx then eval debug("ctx exception"); ]
2762 ctx := check_consistency(ctx, "end", true);
2764 var n_blocks := len(ctx.blocks);
2766 while not ctx.blocks[n_blocks - 1].active do
2769 var rpc := list(pcode_t).[
2770 Fn_Function or select(n_blocks > 1, Fn_AutoInline, 0),
2773 len(ctx.local_types),
2780 rpc += blob_store(ctx.name);
2781 for i := 0 to len(ctx.local_types) do [
2782 if ctx.local_types[i] is rec then [
2783 rpc +<= Local_Type_Record;
2784 rpc += function_store(ctx.local_types[i].rec);
2785 ] else if ctx.local_types[i] is flat_rec then [
2786 rpc +<= Local_Type_Flat_Record;
2787 rpc +<= ctx.local_types[i].flat_rec.non_flat_record;
2788 rpc +<= len(ctx.local_types[i].flat_rec.flat_types);
2789 for t := 0 to len(ctx.local_types[i].flat_rec.flat_types) do [
2790 rpc +<= ctx.local_types[i].flat_rec.flat_types[t];
2792 ] else if ctx.local_types[i] is flat_array then [
2793 rpc +<= Local_Type_Flat_Array;
2794 rpc +<= ctx.local_types[i].flat_array.flat_type;
2795 rpc +<= ctx.local_types[i].flat_array.number_of_elements;
2797 abort internal("unknown local type");
2800 for i := 0 to len(ctx.variables) do [
2801 var v := ctx.variables[i];
2802 rpc +<= v.type_index;
2803 rpc +<= v.runtime_type;
2805 rpc +<= select(v.must_be_flat, 0, VarFlag_Must_Be_Flat) or select(v.must_be_data, 0, VarFlag_Must_Be_Data);
2806 rpc += blob_store(v.name);
2811 rpc += dump_basic_blocks(ctx, false);
2813 if is_exception ctx then [
2814 pc := exception_copy(list(pcode_t), ctx);
2815 ] else if is_exception ctx.instrs then [
2816 pc := exception_copy(list(pcode_t), ctx.instrs);
2817 ] else if is_exception ctx.blocks then [
2818 pc := exception_copy(list(pcode_t), ctx.blocks);
2819 ] else if is_exception ctx.variables then [
2820 pc := exception_copy(list(pcode_t), ctx.variables);
2821 ] else if is_exception rpc then [
2822 pc := exception_copy(list(pcode_t), rpc);
2825 //eval debug("optimized: " + ctx.name);