Separate procedures with newlines in .mod files.

llds.nl:
	Separate procedures with newlines in .mod files.

opt_util.nl, peephole.nl:
	Recognize semidet and nondet procedure epilogs. Branches to these
	epilogs are replaced by the epilogs themselves.

peephole.nl:
	Migrate if_val(Test, do_fail) before mkframe if possible.

value_number.nl:
	It now computes livevals sets at starts of blocks and uses them
	to build up a set of tables containing value number info. This
	info is not yet used, but the tables are inserted into the generated
	code if --peephole-value-number is used.

opt_debug{,.nu}.nl:
	New files containing code to support debugging of peephole and
	value_number.

Makefile.common, mercury_compile.dep:
	Accommodate new files opt_debug{,.nu}.nl.
	You may want to undo the changes to the compiler invocation
	in Makefile.common.
This commit is contained in:
Zoltan Somogyi
1994-09-28 07:54:15 +00:00
parent 9d8abad1cf
commit fc81f5ffe1
5 changed files with 1163 additions and 133 deletions

View File

@@ -250,7 +250,7 @@ output_c_procedure_list([P|Ps]) -->
:- mode output_c_procedure(in, di, uo) is det.
output_c_procedure(c_procedure(Name,Arity,Mode,Instructions)) -->
io__write_string("/*-------------------------------------"),
io__write_string("\n/*-------------------------------------"),
io__write_string("------------------------------------*/\n"),
io__write_string("/* code for predicate "),
io__write_string(Name),

234
compiler/opt_debug.m Normal file
View File

@@ -0,0 +1,234 @@
%-----------------------------------------------------------------------------%
% Debugging support for LLDS to LLDS peephole optimization.
% Main author: zs.
%-----------------------------------------------------------------------------%
:- module opt_debug.
:- interface.
:- import_module llds, value_number, peephole, list, std_util.
:- pred opt_debug__dump_tables(vn_tables, string).
:- mode opt_debug__dump_tables(in, out) is det.
:- pred opt_debug__dump_lval_to_vn(assoc_list(vn_lval, vn), string).
:- mode opt_debug__dump_lval_to_vn(in, out) is det.
:- pred opt_debug__dump_rval_to_vn(assoc_list(vn_rval, vn), string).
:- mode opt_debug__dump_rval_to_vn(in, out) is det.
:- pred opt_debug__dump_vn_to_rval(assoc_list(vn, vn_rval), string).
:- mode opt_debug__dump_vn_to_rval(in, out) is det.
:- pred opt_debug__dump_vn_to_uses(assoc_list(vn, int), string).
:- mode opt_debug__dump_vn_to_uses(in, out) is det.
:- pred opt_debug__dump_vn_to_locs(assoc_list(vn, list(vn_lval)), string).
:- mode opt_debug__dump_vn_to_locs(in, out) is det.
:- pred opt_debug__dump_vn(vn, string).
:- mode opt_debug__dump_vn(in, out) is det.
:- pred opt_debug__dump_vn_locs(list(vn_lval), string).
:- mode opt_debug__dump_vn_locs(in, out) is det.
:- pred opt_debug__dump_reg(reg, string).
:- mode opt_debug__dump_reg(in, out) is det.
:- pred opt_debug__dump_vn_lval(vn_lval, string).
:- mode opt_debug__dump_vn_lval(in, out) is det.
:- pred opt_debug__dump_vn_rval(vn_rval, string).
:- mode opt_debug__dump_vn_rval(in, out) is det.
:- pred opt_debug__dump_const(rval_const, string).
:- mode opt_debug__dump_const(in, out) is det.
:- pred opt_debug__dump_unop(unary_op, string).
:- mode opt_debug__dump_unop(in, out) is det.
:- pred opt_debug__dump_binop(operator, string).
:- mode opt_debug__dump_binop(in, out) is det.
:- pred opt_debug__dump_label(label, string).
:- mode opt_debug__dump_label(in, out) is det.
:- pred opt_debug__print_tailmap(tailmap).
:- mode opt_debug__print_tailmap(in) is det.
:- pred opt_debug__print_instmap(tailmap).
:- mode opt_debug__print_instmap(in) is det.
:- pred opt_debug__print_proclist(list(pair(label, list(instruction)))).
:- mode opt_debug__print_proclist(in) is det.
%-----------------------------------------------------------------------------%
:- implementation.
:- import_module map, string.
opt_debug__dump_lval_to_vn([], "").
opt_debug__dump_lval_to_vn([Vn_lval - Vn | Lval_to_vn_list], Str) :-
opt_debug__dump_lval_to_vn(Lval_to_vn_list, Tail_str),
opt_debug__dump_vn_lval(Vn_lval, Vn_lval_str),
opt_debug__dump_vn(Vn, Vn_str),
string__append_list([Vn_lval_str, " -> ", Vn_str, "\n", Tail_str], Str).
opt_debug__dump_tables(Vn_tables, Comment) :-
Vn_tables = vn_tables(Next_vn,
Lval_to_vn_table, Rval_to_vn_table,
Vn_to_rval_table, Vn_to_uses_table,
Vn_to_locs_table, Loc_to_vn_table),
string__int_to_string(Next_vn, Next_vn_str),
map__to_assoc_list(Lval_to_vn_table, Lval_to_vn_list),
map__to_assoc_list(Rval_to_vn_table, Rval_to_vn_list),
map__to_assoc_list(Vn_to_rval_table, Vn_to_rval_list),
map__to_assoc_list(Vn_to_uses_table, Vn_to_uses_list),
map__to_assoc_list(Vn_to_locs_table, Vn_to_locs_list),
map__to_assoc_list(Loc_to_vn_table, Loc_to_vn_list),
opt_debug__dump_lval_to_vn(Lval_to_vn_list, Lval_to_vn_str),
opt_debug__dump_rval_to_vn(Rval_to_vn_list, Rval_to_vn_str),
opt_debug__dump_vn_to_rval(Vn_to_rval_list, Vn_to_rval_str),
opt_debug__dump_vn_to_uses(Vn_to_uses_list, Vn_to_uses_str),
opt_debug__dump_vn_to_locs(Vn_to_locs_list, Vn_to_locs_str),
opt_debug__dump_lval_to_vn( Loc_to_vn_list, Loc_to_vn_str),
string__append_list([
"Next vn\n", Next_vn_str,
"\nLval to vn\n", Lval_to_vn_str,
"\nRval to vn\n", Rval_to_vn_str,
"\nVn to rval\n", Vn_to_rval_str,
"\nVn to uses\n", Vn_to_uses_str,
"\nVn to locs\n", Vn_to_locs_str,
"\nLoc to vn\n", Loc_to_vn_str], Comment).
opt_debug__dump_rval_to_vn([], "").
opt_debug__dump_rval_to_vn([Vn_rval - Vn | Rval_to_vn_list], Str) :-
opt_debug__dump_rval_to_vn(Rval_to_vn_list, Tail_str),
opt_debug__dump_vn_rval(Vn_rval, Vn_rval_str),
opt_debug__dump_vn(Vn, Vn_str),
string__append_list([Vn_rval_str, " -> ", Vn_str, "\n", Tail_str], Str).
opt_debug__dump_vn_to_rval([], "").
opt_debug__dump_vn_to_rval([Vn - Vn_rval | Vn_to_rval_list], Str) :-
opt_debug__dump_vn_to_rval(Vn_to_rval_list, Tail_str),
opt_debug__dump_vn(Vn, Vn_str),
opt_debug__dump_vn_rval(Vn_rval, Vn_rval_str),
string__append_list([Vn_str, " -> ", Vn_rval_str, "\n", Tail_str], Str).
opt_debug__dump_vn_to_uses([], "").
opt_debug__dump_vn_to_uses([Vn - Uses | Vn_to_uses_list], Str) :-
opt_debug__dump_vn_to_uses(Vn_to_uses_list, Tail_str),
opt_debug__dump_vn(Vn, Vn_str),
string__int_to_string(Uses, Uses_str),
string__append_list([Vn_str, " -> ", Uses_str, "\n", Tail_str], Str).
opt_debug__dump_vn_to_locs([], "").
opt_debug__dump_vn_to_locs([Vn - Vn_locs | Vn_to_locs_list], Str) :-
opt_debug__dump_vn_to_locs(Vn_to_locs_list, Tail_str),
opt_debug__dump_vn(Vn, Vn_str),
opt_debug__dump_vn_locs(Vn_locs, Vn_locs_str),
string__append_list([Vn_str, " -> ", Vn_locs_str, "\n", Tail_str], Str).
opt_debug__dump_vn(Vn, Str) :-
string__int_to_string(Vn, Str).
opt_debug__dump_vn_locs([], "").
opt_debug__dump_vn_locs([Lval | Lvals], Str) :-
opt_debug__dump_vn_lval(Lval, Lval_str),
opt_debug__dump_vn_locs(Lvals, Tail_str),
string__append_list([" @", Lval_str, Tail_str], Str).
opt_debug__dump_reg(r(N), Str) :-
string__int_to_string(N, N_str),
string__append_list(["r(", N_str, ")"], Str).
opt_debug__dump_reg(f(N), Str) :-
string__int_to_string(N, N_str),
string__append_list(["f(", N_str, ")"], Str).
opt_debug__dump_vn_lval(vn_reg(R), Str) :-
opt_debug__dump_reg(R, R_str),
string__append_list(["vn_reg(", R_str, ")"], Str).
opt_debug__dump_vn_lval(vn_stackvar(N), Str) :-
string__int_to_string(N, N_str),
string__append_list(["vn_stackvar(", N_str, ")"], Str).
opt_debug__dump_vn_lval(vn_framevar(N), Str) :-
string__int_to_string(N, N_str),
string__append_list(["vn_framevar(", N_str, ")"], Str).
opt_debug__dump_vn_lval(vn_succip, Str) :-
string__append_list(["vn_succip"], Str).
opt_debug__dump_vn_lval(vn_maxfr, Str) :-
string__append_list(["vn_maxfr"], Str).
opt_debug__dump_vn_lval(vn_curredoip, Str) :-
string__append_list(["vn_curredoip"], Str).
opt_debug__dump_vn_lval(vn_hp, Str) :-
string__append_list(["vn_hp"], Str).
opt_debug__dump_vn_lval(vn_sp, Str) :-
string__append_list(["vn_sp"], Str).
opt_debug__dump_vn_lval(vn_field(T, N, F), Str) :-
string__int_to_string(T, T_str),
string__int_to_string(N, N_str),
string__int_to_string(F, F_str),
string__append_list(["vn_field(", T_str, ", ", N_str, ", ",
F_str, ")"], Str).
opt_debug__dump_vn_lval(vn_temp(N), Str) :-
string__int_to_string(N, N_str),
string__append_list(["vn_temp(", N_str, ")"], Str).
opt_debug__dump_vn_rval(vn_origlval(Vn_lval), Str) :-
opt_debug__dump_vn_lval(Vn_lval, Lval_str),
string__append_list(["vn_origlval(", Lval_str, ")"], Str).
opt_debug__dump_vn_rval(vn_mkword(T, N), Str) :-
string__int_to_string(T, T_str),
string__int_to_string(N, N_str),
string__append_list(["vn_mkword(", T_str, ", ", N_str, ")"], Str).
opt_debug__dump_vn_rval(vn_const(C), Str) :-
opt_debug__dump_const(C, C_str),
string__append_list(["vn_const(", C_str, ")"], Str).
opt_debug__dump_vn_rval(vn_field(T, N, F), Str) :-
string__int_to_string(T, T_str),
string__int_to_string(N, N_str),
string__int_to_string(F, F_str),
string__append_list(["vn_field(", T_str, ", ", N_str, ", ",
F_str, ")"], Str).
opt_debug__dump_vn_rval(vn_unop(O, N), Str) :-
opt_debug__dump_unop(O, O_str),
string__int_to_string(N, N_str),
string__append_list(["vn_unop(", O_str, ", ", N_str, ")"], Str).
opt_debug__dump_vn_rval(vn_binop(O, N1, N2), Str) :-
opt_debug__dump_binop(O, O_str),
string__int_to_string(N1, N1_str),
string__int_to_string(N2, N2_str),
string__append_list(["vn_binop(", O_str, ", ", N1_str, ", ",
N2_str, ")"], Str).
opt_debug__dump_const(true, "true").
opt_debug__dump_const(false, "false").
opt_debug__dump_const(int_const(I), Str) :-
string__int_to_string(I, Str).
opt_debug__dump_const(string_const(I), Str) :-
string__append_list(["\"", I, "\""], Str).
opt_debug__dump_unop(mktag, "mktag").
opt_debug__dump_unop(tag, "tag").
opt_debug__dump_unop(mkbody, "mkbody").
opt_debug__dump_unop(body, "body").
opt_debug__dump_unop(not, "not").
opt_debug__dump_unop(cast_to_unsigned, "cast_to_unsigned").
opt_debug__dump_binop(streq, "streq").
opt_debug__dump_binop((+), "+").
opt_debug__dump_binop((-), "-").
opt_debug__dump_binop((*), "*").
opt_debug__dump_binop((/), "/").
opt_debug__dump_binop(mod, "%").
opt_debug__dump_binop(eq, "==").
opt_debug__dump_binop(ne, "!=").
opt_debug__dump_binop(and, "&&").
opt_debug__dump_binop(or, "||").
opt_debug__dump_binop((<), "<").
opt_debug__dump_binop((>), ">").
opt_debug__dump_binop((<=), "<=").
opt_debug__dump_binop((>=), ">=").

View File

@@ -44,11 +44,26 @@
:- pred opt_util__is_proceed_next(list(instruction), list(instruction)).
:- mode opt_util__is_proceed_next(in, out) is semidet.
% Is a proceed instruction (i.e. a goto(succip) instruction)
% next in the instruction list, possibly preceded by an assignment
% to r1, a restoration of succip and a det stack frame removal?
% If yes, return the instructions up to the proceed.
:- pred opt_util__is_sdproceed_next(list(instruction), list(instruction)).
:- mode opt_util__is_sdproceed_next(in, out) is semidet.
% Is a succeed instruction (i.e. a goto(do_succeed) instruction)
% next in the instruction list? If yes, return the instructions
% up to the succed.
:- pred opt_util__is_succeed_next(list(instruction), list(instruction)).
:- mode opt_util__is_succeed_next(in, out) is semidet.
% Remove the livevals instruction from the list returned by
% opt_util__is_proceed_next.
:- pred opt_util__proceed_no_livevals(list(instruction), list(instruction)).
:- mode opt_util__proceed_no_livevals(in, out) is semidet.
:- pred opt_util__filter_out_livevals(list(instruction), list(instruction)).
:- mode opt_util__filter_out_livevals(in, out) is semidet.
% Check whether an instruction can possibly branch away.
@@ -160,26 +175,83 @@ opt_util__is_this_label_next(Label, [Instr | Moreinstr], Remainder) :-
opt_util__is_proceed_next(Instrs0, Instrs_between) :-
opt_util__skip_comments_labels(Instrs0, Instrs1),
Instrs1 = [Instr1 | Instrs2],
Instr1 = assign(succip, lval(stackvar(_))) - _,
opt_util__skip_comments_labels(Instrs2, Instrs3),
( Instr1 = assign(succip, lval(stackvar(_))) - _ ->
Instr1use = Instr1,
opt_util__skip_comments_labels(Instrs2, Instrs3)
;
Instr1use = comment("no succip restoration") - "",
Instrs3 = Instrs1
),
Instrs3 = [Instr3 | Instrs4],
Instr3 = decr_sp(_) - _,
opt_util__skip_comments_labels(Instrs4, Instrs5),
( Instr3 = decr_sp(_) - _ ->
Instr3use = Instr3,
opt_util__skip_comments_labels(Instrs4, Instrs5)
;
Instr3use = comment("no sp restoration") - "",
Instrs5 = Instrs3
),
Instrs5 = [Instr5 | Instrs6],
( Instr5 = livevals(_) - _ ->
opt_util__skip_comments_labels(Instrs6, Instrs7),
Instr5use = Instr5,
opt_util__skip_comments_labels(Instrs6, Instrs7)
;
Instr5use = comment("no livevals") - "",
Instrs7 = Instrs5
),
Instrs7 = [Instr7 | _],
Instr7 = goto(succip) - _,
Instrs_between = [Instr1, Instr3, Instr5]
; Instr5 = goto(succip) - _ ->
Instrs_between = [Instr1, Instr3]
;
fail
).
Instrs_between = [Instr1use, Instr3use, Instr5use].
opt_util__proceed_no_livevals([], []).
opt_util__proceed_no_livevals([Instr0 | Instrs0], Instrs) :-
opt_util__proceed_no_livevals(Instrs0, Instrs1),
opt_util__is_sdproceed_next(Instrs0, Instrs_between) :-
opt_util__skip_comments_labels(Instrs0, Instrs1),
Instrs1 = [Instr1 | Instrs2],
( Instr1 = assign(succip, lval(stackvar(_))) - _ ->
Instr1use = Instr1,
opt_util__skip_comments_labels(Instrs2, Instrs3)
;
Instr1use = comment("no succip restoration") - "",
Instrs3 = Instrs1
),
Instrs3 = [Instr3 | Instrs4],
( Instr3 = decr_sp(_) - _ ->
Instr3use = Instr3,
opt_util__skip_comments_labels(Instrs4, Instrs5)
;
Instr3use = comment("no sp restoration") - "",
Instrs5 = Instrs3
),
Instrs5 = [Instr5 | Instrs6],
Instr5 = assign(reg(r(1)), const(_)) - _,
opt_util__skip_comments_labels(Instrs6, Instrs7),
Instrs7 = [Instr7 | Instrs8],
( Instr7 = livevals(_) - _ ->
Instr7use = Instr7,
opt_util__skip_comments_labels(Instrs8, Instrs9)
;
Instr7use = comment("no livevals") - "",
Instrs9 = Instrs7
),
Instrs9 = [Instr9 | _],
Instr9 = goto(succip) - _,
Instrs_between = [Instr1use, Instr3use, Instr5, Instr7use].
opt_util__is_succeed_next(Instrs0, Instrs_between) :-
opt_util__skip_comments_labels(Instrs0, Instrs1),
Instrs1 = [Instr1 | Instrs2],
( Instr1 = livevals(_) - _ ->
Instr1use = Instr1,
opt_util__skip_comments_labels(Instrs2, Instrs3)
;
Instr1use = comment("no livevals") - "",
Instrs3 = Instrs1
),
Instrs3 = [Instr3 | _],
Instr3 = goto(do_succeed) - _,
Instrs_between = [Instr1use].
opt_util__filter_out_livevals([], []).
opt_util__filter_out_livevals([Instr0 | Instrs0], Instrs) :-
opt_util__filter_out_livevals(Instrs0, Instrs1),
( Instr0 = livevals(_) - _Comment ->
Instrs = Instrs1
;

View File

@@ -9,16 +9,21 @@
:- module peephole.
:- interface.
:- import_module llds, options.
:- import_module map, llds, options.
:- pred peephole__optimize(option_table, c_file, c_file).
:- mode peephole__optimize(in, in, out) is det.
% the types are exported only for debugging.
:- type instmap == map(label, instruction).
:- type tailmap == map(label, list(instruction)).
%-----------------------------------------------------------------------------%
:- implementation.
:- import_module value_number, opt_util, code_util, map, bintree_set.
:- import_module string, list, require, std_util.
:- import_module value_number, opt_debug, opt_util, code_util, map.
:- import_module bintree_set, string, list, require, std_util.
%-----------------------------------------------------------------------------%
@@ -111,97 +116,83 @@ peephole__nonrepeat_opts(Options, Instructions0, Instructions) :-
% Build up a table showing the first instruction following each label.
% Then traverse the instruction list, short-circuiting jump sequences.
:- type jumpmap == map(label, instruction).
:- type procmap == map(label, list(instruction)).
:- pred peephole__short_circuit(list(instruction), list(instruction), bool).
:- mode peephole__short_circuit(in, out, out) is det.
peephole__short_circuit(Instrs0, Instrs, Mod) :-
map__init(Jumpmap0),
map__init(Instmap0),
map__init(Procmap0),
peephole__jumpopt_build_maps(Instrs0, Jumpmap0, Jumpmap,
Procmap0, Procmap),
% peephole__print_procmap(Procmap),
peephole__jumpopt_instr_list(Instrs0, Jumpmap, Procmap, Instrs, Mod).
map__init(Sdprocmap0),
map__init(Succmap0),
peephole__jumpopt_build_maps(Instrs0, Instmap0, Instmap,
Procmap0, Procmap, Sdprocmap0, Sdprocmap, Succmap0, Succmap),
% opt_debug__print_instmap(Instmap),
% opt_debug__print_tailmap(Procmap),
% opt_debug__print_tailmap(Sdprocmap),
% opt_debug__print_tailmap(Succmap),
peephole__jumpopt_instr_list(Instrs0, comment(""),
Instmap, Procmap, Sdprocmap, Succmap, Instrs, Mod).
:- pred peephole__print_procmap(procmap).
:- mode peephole__print_procmap(in) is det.
:- pred peephole__jumpopt_build_maps(list(instruction), instmap, instmap,
tailmap, tailmap, tailmap, tailmap, tailmap, tailmap).
:- mode peephole__jumpopt_build_maps(in, di, uo, di, uo, di, uo, di, uo) is det.
peephole__print_procmap(Procmap) :-
write('Procmap:'),
nl,
map__to_assoc_list(Procmap, Assoclist),
peephole__print_proclist(Assoclist).
:- pred peephole__print_proclist(list(pair(label, list(instruction)))).
:- mode peephole__print_proclist(in) is det.
peephole__print_proclist([]).
peephole__print_proclist([Label - Instrs | Assoclist]) :-
nl,
write(Label),
write(' maps to '),
write(Instrs),
nl,
peephole__print_proclist(Assoclist).
:- pred peephole__jumpopt_build_maps(list(instruction), jumpmap, jumpmap,
procmap, procmap).
:- mode peephole__jumpopt_build_maps(in, di, uo, di, uo) is det.
peephole__jumpopt_build_maps([], Jumpmap, Jumpmap, Procmap, Procmap).
peephole__jumpopt_build_maps([Instr - _Comment|Instrs],
Jumpmap0, Jumpmap, Procmap0, Procmap) :-
peephole__jumpopt_build_maps([], Instmap, Instmap, Procmap, Procmap,
Sdprocmap, Sdprocmap, Succmap, Succmap).
peephole__jumpopt_build_maps([Instr - _Comment|Instrs], Instmap0, Instmap,
Procmap0, Procmap, Sdprocmap0, Sdprocmap, Succmap0, Succmap) :-
( Instr = label(Label) ->
opt_util__skip_comments_livevals(Instrs, Instrs1),
( Instrs1 = [Nextinstr | _] ->
% write('label '),
% write(Label),
% write(' maps to '),
% write(Nextinstr),
% nl,
map__set(Jumpmap0, Label, Nextinstr, Jumpmap1)
map__set(Instmap0, Label, Nextinstr, Instmap1)
;
Jumpmap1 = Jumpmap0
Instmap1 = Instmap0
),
( opt_util__is_proceed_next(Instrs, Between) ->
% write('label '),
% write(Label),
% write(' is followed by proceed '),
% nl,
map__set(Procmap0, Label, Between, Procmap1)
( opt_util__is_proceed_next(Instrs, Between1) ->
map__set(Procmap0, Label, Between1, Procmap1)
;
Procmap1 = Procmap0
),
( opt_util__is_sdproceed_next(Instrs, Between2) ->
map__set(Sdprocmap0, Label, Between2, Sdprocmap1)
;
Sdprocmap1 = Sdprocmap0
),
( opt_util__is_succeed_next(Instrs, Between3) ->
map__set(Succmap0, Label, Between3, Succmap1)
;
Succmap1 = Succmap0
)
;
Jumpmap1 = Jumpmap0,
Procmap1 = Procmap0
Instmap1 = Instmap0,
Procmap1 = Procmap0,
Sdprocmap1 = Sdprocmap0,
Succmap1 = Succmap0
),
peephole__jumpopt_build_maps(Instrs, Jumpmap1, Jumpmap,
Procmap1, Procmap).
peephole__jumpopt_build_maps(Instrs, Instmap1, Instmap,
Procmap1, Procmap, Sdprocmap1, Sdprocmap, Succmap1, Succmap).
:- pred peephole__jumpopt_instr_list(list(instruction),
jumpmap, procmap, list(instruction), bool).
:- mode peephole__jumpopt_instr_list(in, in, in, out, out) is det.
:- pred peephole__jumpopt_instr_list(list(instruction), instr,
instmap, tailmap, tailmap, tailmap, list(instruction), bool).
:- mode peephole__jumpopt_instr_list(in, in, in, in, in, in, out, out) is det.
peephole__jumpopt_instr_list([], _Jumpmap, _Procmap, [], no).
peephole__jumpopt_instr_list([Instr0|Moreinstrs0], Jumpmap, Procmap,
Instrs, Mod) :-
peephole__jumpopt_instr_list([], _Previnstr,
_Instmap, _Procmap, _Sdprocmap, _Succmap, [], no).
peephole__jumpopt_instr_list([Instr0|Moreinstrs0], Previnstr,
Instmap, Procmap, Sdprocmap, Succmap, Instrs, Mod) :-
Instr0 = Uinstr0 - Comment0,
string__append(Comment0, " (redirected return)", Redirect),
(
Uinstr0 = call(Proc, label(Retlabel)),
map__search(Jumpmap, Retlabel, Retinstr)
map__search(Instmap, Retlabel, Retinstr)
->
peephole__jumpopt_final_dest(Retlabel, Retinstr,
Jumpmap, Destlabel, Destinstr),
Instmap, Destlabel, Destinstr),
( Retlabel = Destlabel ->
Newinstrs = [Instr0],
Mod0 = no
;
Newinstrs = [call(Proc, label(Destlabel))
- Redirect],
Newinstrs = [call(Proc, label(Destlabel)) - Redirect],
Mod0 = yes
)
; Uinstr0 = goto(label(Targetlabel)) ->
@@ -210,13 +201,27 @@ peephole__jumpopt_instr_list([Instr0|Moreinstrs0], Jumpmap, Procmap,
% is better than shortcircuiting it here
Newinstrs = [Instr0],
Mod0 = no
; Previnstr = if_val(_, label(Iftargetlabel)),
Moreinstrs0 = [label(Iftargetlabel) - _|_] ->
% eliminating the goto (by the local peephole pass)
% is better than shortcircuiting it here
Newinstrs = [Instr0],
Mod0 = no
; map__search(Procmap, Targetlabel, Between) ->
list__append(Between, [goto(succip) - "shortcircuit"],
Newinstrs),
Mod0 = yes
; map__search(Jumpmap, Targetlabel, Targetinstr) ->
; map__search(Sdprocmap, Targetlabel, Between) ->
list__append(Between, [goto(succip) - "shortcircuit"],
Newinstrs),
Mod0 = yes
; map__search(Succmap, Targetlabel, Between) ->
list__append(Between, [goto(do_succeed) - "shortcircuit"],
Newinstrs),
Mod0 = yes
; map__search(Instmap, Targetlabel, Targetinstr) ->
peephole__jumpopt_final_dest(Targetlabel, Targetinstr,
Jumpmap, Destlabel, Destinstr),
Instmap, Destlabel, Destinstr),
Destinstr = Udestinstr - _Destcomment,
string__append("shortcircuited jump: ",
Comment0, Shorted),
@@ -243,8 +248,13 @@ peephole__jumpopt_instr_list([Instr0|Moreinstrs0], Jumpmap, Procmap,
Newinstrs = [Instr0],
Mod0 = no
),
peephole__jumpopt_instr_list(Moreinstrs0, Jumpmap, Procmap,
Moreinstrs, Mod1),
( ( Uinstr0 = comment(_) ; Uinstr0 = livevals(_) ) ->
Newprevinstr = Previnstr
;
Newprevinstr = Uinstr0
),
peephole__jumpopt_instr_list(Moreinstrs0, Newprevinstr,
Instmap, Procmap, Sdprocmap, Succmap, Moreinstrs, Mod1),
list__append(Newinstrs, Moreinstrs, Instrs),
( Mod0 = no, Mod1 = no ->
Mod = no
@@ -252,7 +262,7 @@ peephole__jumpopt_instr_list([Instr0|Moreinstrs0], Jumpmap, Procmap,
Mod = yes
).
:- pred peephole__jumpopt_final_dest(label, instruction, jumpmap,
:- pred peephole__jumpopt_final_dest(label, instruction, instmap,
label, instruction).
:- mode peephole__jumpopt_final_dest(in, in, in, out, out) is det.
@@ -260,11 +270,11 @@ peephole__jumpopt_instr_list([Instr0|Moreinstrs0], Jumpmap, Procmap,
% the moment since the compiler never generates code containing
% infinite loops, but it may cause problems in the future.
peephole__jumpopt_final_dest(Srclabel, Srcinstr, Jumpmap,
peephole__jumpopt_final_dest(Srclabel, Srcinstr, Instmap,
Destlabel, Destinstr) :-
(
Srcinstr = goto(label(Targetlabel)) - Comment,
map__search(Jumpmap, Targetlabel, Targetinstr)
map__search(Instmap, Targetlabel, Targetinstr)
->
% write('goto short-circuit from '),
% write(Srclabel),
@@ -272,10 +282,10 @@ peephole__jumpopt_final_dest(Srclabel, Srcinstr, Jumpmap,
% write(Targetlabel),
% nl,
peephole__jumpopt_final_dest(Targetlabel, Targetinstr,
Jumpmap, Destlabel, Destinstr)
Instmap, Destlabel, Destinstr)
;
Srcinstr = label(Targetlabel) - Comment,
map__search(Jumpmap, Targetlabel, Targetinstr)
map__search(Instmap, Targetlabel, Targetinstr)
->
% write('fallthrough short-circuit from '),
% write(Srclabel),
@@ -283,7 +293,7 @@ peephole__jumpopt_final_dest(Srclabel, Srcinstr, Jumpmap,
% write(Targetlabel),
% nl,
peephole__jumpopt_final_dest(Targetlabel, Targetinstr,
Jumpmap, Destlabel, Destinstr)
Instmap, Destlabel, Destinstr)
;
Destlabel = Srclabel,
Destinstr = Srcinstr
@@ -300,29 +310,57 @@ peephole__jumpopt_final_dest(Srclabel, Srcinstr, Jumpmap,
:- pred peephole__local_opt(list(instruction), list(instruction), bool).
:- mode peephole__local_opt(in, out, out) is det.
peephole__local_opt([], [], no).
peephole__local_opt([Instr0 - Comment|Instructions0], Instructions, Mod) :-
peephole__local_opt(Instructions0, Instructions1, Mod0),
peephole__opt_instr(Instr0, Comment, Instructions1, Instructions, Mod1),
peephole__local_opt(Instrs0, Instrs, Mod) :-
map__init(Procmap0),
peephole__local_build_maps(Instrs0, Procmap0, Procmap),
peephole__local_opt_2(Instrs0, Instrs, Procmap, Mod).
:- pred peephole__local_build_maps(list(instruction), tailmap, tailmap).
:- mode peephole__local_build_maps(in, di, uo) is det.
peephole__local_build_maps([], Procmap, Procmap).
peephole__local_build_maps([Instr - _Comment|Instrs], Procmap0, Procmap) :-
( Instr = label(Label) ->
( opt_util__is_proceed_next(Instrs, Between) ->
map__set(Procmap0, Label, Between, Procmap1)
;
Procmap1 = Procmap0
)
;
Procmap1 = Procmap0
),
peephole__local_build_maps(Instrs, Procmap1, Procmap).
:- pred peephole__local_opt_2(list(instruction), list(instruction),
tailmap, bool).
:- mode peephole__local_opt_2(in, out, in, out) is det.
peephole__local_opt_2([], [], _, no).
peephole__local_opt_2([Instr0 - Comment|Instructions0], Instructions,
Procmap, Mod) :-
peephole__local_opt_2(Instructions0, Instructions1, Procmap, Mod0),
peephole__opt_instr(Instr0, Comment, Procmap,
Instructions1, Instructions, Mod1),
( Mod0 = no, Mod1 = no ->
Mod = no
;
Mod = yes
).
:- pred peephole__opt_instr(instr, string, list(instruction),
list(instruction), bool).
:- mode peephole__opt_instr(in, in, in, out, out) is det.
:- pred peephole__opt_instr(instr, string, tailmap,
list(instruction), list(instruction), bool).
:- mode peephole__opt_instr(in, in, in, in, out, out) is det.
peephole__opt_instr(Instr0, Comment0, Instructions0, Instructions, Mod) :-
peephole__opt_instr(Instr0, Comment0, Procmap, Instructions0, Instructions,
Mod) :-
(
opt_util__skip_comments(Instructions0, Instructions1),
peephole__opt_instr_2(Instr0, Comment0, Instructions1,
peephole__opt_instr_2(Instr0, Comment0, Procmap, Instructions1,
Instructions2)
->
( Instructions2 = [Instr2 - Comment2 | Instructions3] ->
peephole__opt_instr(Instr2, Comment2, Instructions3,
Instructions, _)
peephole__opt_instr(Instr2, Comment2, Procmap,
Instructions3, Instructions, _)
;
Instructions = Instructions2
),
@@ -332,9 +370,9 @@ peephole__opt_instr(Instr0, Comment0, Instructions0, Instructions, Mod) :-
Mod = no
).
:- pred peephole__opt_instr_2(instr, string, list(instruction),
list(instruction)).
:- mode peephole__opt_instr_2(in, in, in, out) is semidet.
:- pred peephole__opt_instr_2(instr, string, tailmap,
list(instruction), list(instruction)).
:- mode peephole__opt_instr_2(in, in, in, in, out) is semidet.
% A `call' followed by a `proceed' can be replaced with a `tailcall'.
%
@@ -343,6 +381,7 @@ peephole__opt_instr(Instr0, Comment0, Instructions0, Instructions, Mod) :-
% livevals(L1) livevals(L1)
% call(Foo, &&ret); tailcall(Foo)
% <comments, labels> <comments, labels>
% ... ...
% ret: => ret:
% <comments, labels> <comments, labels>
% succip = ... succip = ...
@@ -359,30 +398,16 @@ peephole__opt_instr(Instr0, Comment0, Instructions0, Instructions, Mod) :-
%
% I have some doubt about the validity of using L1 unchanged.
peephole__opt_instr_2(livevals(Livevals), Comment, Instrs0, Instrs) :-
peephole__opt_instr_2(livevals(Livevals), Comment, Procmap, Instrs0, Instrs) :-
opt_util__skip_comments(Instrs0, Instrs1),
Instrs1 = [call(CodeAddress, label(ContLabel)) - Comment2 | Instrs2],
opt_util__is_this_label_next(ContLabel, Instrs2, Instrs3),
opt_util__is_proceed_next(Instrs3, Instrs_to_proceed),
opt_util__proceed_no_livevals(Instrs_to_proceed, Instrs_to_insert),
Instrs1 = [call(CodeAddress, label(ContLabel)) - Comment2 | _],
map__search(Procmap, ContLabel, Instrs_to_proceed),
opt_util__filter_out_livevals(Instrs_to_proceed, Instrs_to_insert),
string__append(Comment, " (redirected return)", Redirect),
list__append(Instrs_to_insert,
[livevals(Livevals) - Comment2,
goto(CodeAddress) - Redirect | Instrs0], Instrs).
% if a `mkframe' is followed by a `modframe', with the instructions
% in between containing only straight-line code, we can delete the
% `modframe' and instead just set the redoip directly in the `mkframe'.
%
% mkframe(D, S, _) => mkframe(D, S, Redoip)
% <straightline instrs> <straightline instrs>
% modframe(Redoip)
peephole__opt_instr_2(mkframe(Descr, Slots, _), Comment, Instrs0, Instrs) :-
opt_util__next_modframe(Instrs0, [], Redoip, Skipped, Rest),
list__append(Skipped, Rest, Instrs1),
Instrs = [mkframe(Descr, Slots, Redoip) - Comment | Instrs1].
% a `goto' can be deleted if the target of the jump is the very
% next instruction.
%
@@ -392,7 +417,8 @@ peephole__opt_instr_2(mkframe(Descr, Slots, _), Comment, Instrs0, Instrs) :-
%
% dead code after a `goto' is deleted in label-elim.
peephole__opt_instr_2(goto(label(Label)), _Comment, Instrs0, Instrs) :-
peephole__opt_instr_2(goto(label(Label)), _Comment, _Procmap,
Instrs0, Instrs) :-
opt_util__is_this_label_next(Label, Instrs0, _),
Instrs = Instrs0.
@@ -411,7 +437,8 @@ peephole__opt_instr_2(goto(label(Label)), _Comment, Instrs0, Instrs) :-
% <comments, labels> next:
% next:
peephole__opt_instr_2(if_val(Rval, label(Target)), _C1, Instrs0, Instrs) :-
peephole__opt_instr_2(if_val(Rval, label(Target)), _C1, _Procmap,
Instrs0, Instrs) :-
opt_util__skip_comments_livevals(Instrs0, Instrs1),
( Instrs1 = [goto(Somewhere) - C2 | Instrs2] ->
opt_util__is_this_label_next(Target, Instrs2, _),
@@ -422,6 +449,63 @@ peephole__opt_instr_2(if_val(Rval, label(Target)), _C1, Instrs0, Instrs) :-
Instrs = Instrs0
).
% if a `mkframe' is followed by a `modframe', with the instructions
% in between containing only straight-line code, we can delete the
% `modframe' and instead just set the redoip directly in the `mkframe'.
%
% mkframe(D, S, _) => mkframe(D, S, Redoip)
% <straightline instrs> <straightline instrs>
% modframe(Redoip)
peephole__opt_instr_2(mkframe(Descr, Slots, _), Comment, _Procmap,
Instrs0, Instrs) :-
opt_util__next_modframe(Instrs0, [], Redoip, Skipped, Rest),
list__append(Skipped, Rest, Instrs1),
Instrs = [mkframe(Descr, Slots, Redoip) - Comment | Instrs1].
% if a `mkframe' is followed by a test that can fail, we try to
% swap the two instructions to avoid doing the mkframe unnecessarily.
%
% mkframe(D, S, dofail) => if_val(test, redo)
% if_val(test, redo/fail) mkframe(D, S, dofail)
%
% mkframe(D, S, label) => if_val(test, redo)
% if_val(test, fail) mkframe(D, S, label)
%
% mkframe(D, S, label) => mkframe(D, S, label)
% if_val(test, redo) if_val(test, label)
peephole__opt_instr_2(mkframe(Descr, Slots, Redoip), Comment, _Procmap,
Instrs0, Instrs) :-
opt_util__skip_comments_livevals(Instrs0, Instrs1),
Instrs1 = [Instr1 | Instrs2],
Instr1 = if_val(Test, Target) - Comment2,
(
Redoip = do_fail,
( Target = do_redo ; Target = do_fail)
->
Instrs = [if_val(Test, do_redo) - Comment2,
mkframe(Descr, Slots, do_fail) - Comment | Instrs2]
;
Redoip = label(_)
->
(
Target = do_fail
->
Instrs = [if_val(Test, do_redo) - Comment2,
mkframe(Descr, Slots, Redoip) - Comment | Instrs2]
;
Target = do_redo
->
Instrs = [mkframe(Descr, Slots, Redoip) - Comment,
if_val(Test, Redoip) - Comment2 | Instrs2]
;
fail
)
;
fail
).
%-----------------------------------------------------------------------------%
% Build up a table showing which labels are branched to.

View File

@@ -14,18 +14,658 @@
:- pred value_number__optimize(list(instruction), list(instruction)).
:- mode value_number__optimize(in, out) is det.
% the rest are exported only for debugging.
:- type lvalset == bintree_set(lval).
:- type livemap == map(label, lvalset).
:- type vn == int.
:- type lval_to_vn_table == map(vn_lval, vn).
:- type rval_to_vn_table == map(vn_rval, vn).
:- type vn_to_rval_table == map(vn, vn_rval).
:- type vn_to_uses_table == map(vn, int).
:- type vn_to_locs_table == map(vn, list(vn_lval)).
:- type loc_to_vn_table == map(vn_lval, vn).
:- type vn_tables ---> vn_tables(vn, lval_to_vn_table, rval_to_vn_table,
vn_to_rval_table, vn_to_uses_table,
vn_to_locs_table, loc_to_vn_table).
:- type vn_lval ---> vn_reg(reg)
; vn_stackvar(int)
; vn_framevar(int)
; vn_succip
; vn_maxfr
; vn_curredoip
; vn_hp
; vn_sp
; vn_field(tag, vn, int) % lval
; vn_temp(int).
% these lvals do not have vn_lval parallels
% lvar(var)
:- type vn_rval ---> vn_origlval(vn_lval)
; vn_mkword(tag, vn) % rval
; vn_const(rval_const)
; vn_field(tag, vn, int) % rval
; vn_unop(unary_op, vn) % rval
; vn_binop(operator, vn, vn). % rval, rval
% these rvals do not have vn_rval parallels
% vn_create(tag, list(rval))
% var(var)
%-----------------------------------------------------------------------------%
:- implementation.
:- import_module code_util, map, bintree_set, string, require, std_util.
:- import_module opt_util, opt_debug, map, bintree_set.
:- import_module int, string, require, std_util.
%-----------------------------------------------------------------------------%
% XXX map__update/set should be det, should call error if key not already there
% XXX should simplify expression
% Find straight-line code sequences and optimize them using
% value numbering.
value_number__optimize(Instructions, Instructions).
value_number__optimize(Instrs0, Instrs) :-
map__init(Livemap0),
bintree_set__init(Livevals0),
list__reverse(Instrs0, Backinstrs),
value_number__build_livemap(Backinstrs, Livevals0, no,
Livemap0, Livemap),
value_number__insert_livemap(Livemap, Instrs0, Instrs1),
value_number__opt_instrs(Instrs1, Livemap, Instrs).
:- end_module value_number.
:- pred value_number__insert_livemap(livemap, list(instruction),
list(instruction)).
:- mode value_number__insert_livemap(in, di, uo) is det.
%-----------------------------------------------------------------------------%
value_number__insert_livemap(_Livemap, [], []).
value_number__insert_livemap(Livemap, [Instr0 | Instrs0], Instrs) :-
value_number__insert_livemap(Livemap, Instrs0, Instrs1),
Instr0 = Uinstr0 - _Comment,
( Uinstr0 = label(Label) ->
( map__search(Livemap, Label, Livevals) ->
Instrs = [Instr0, livevals(Livevals) - "auto" | Instrs1]
;
error("no livevals info about a label")
)
;
Instrs = [Instr0 | Instrs1]
).
:- pred value_number__build_livemap(list(instruction), lvalset,
bool, livemap, livemap).
:- mode value_number__build_livemap(in, in, in, di, uo) is det.
value_number__build_livemap([], _, _, Livemap, Livemap).
value_number__build_livemap([Instr|Moreinstrs], Livevals0, Ccode0,
Livemap0, Livemap) :-
Instr = Uinstr - _Comment,
( Uinstr = call(_, _) ->
opt_util__skip_comments(Moreinstrs, Moreinstrs1),
(
Moreinstrs1 = [Nextinstr | Evenmoreinstrs],
Nextinstr = Nextuinstr - Nextcomment,
Nextuinstr = livevals(Livevals2prime)
->
Livevals2 = Livevals2prime,
Livemap1 = Livemap0,
Moreinstrs2 = Evenmoreinstrs,
Ccode1 = Ccode0
;
% Moreinstrs1 = [Nextinstr | Evenmoreinstrs],
% Nextinstr = Nextuinstr - Nextcomment,
% write(Instr),
% nl,
% write(Nextinstr),
% nl,
% Livevals2 = Livevals0,
% Livemap1 = Livemap0,
% Moreinstrs2 = Evenmoreinstrs,
% Ccode1 = Ccode0
error("call not preceded by livevals")
)
; Uinstr = goto(Codeaddr) ->
opt_util__skip_comments(Moreinstrs, Moreinstrs1),
opt_util__livevals_addr(Codeaddr, Livevals_needed),
( Livevals_needed = yes ->
(
Moreinstrs1 = [Nextinstr | Evenmoreinstrs],
Nextinstr = Nextuinstr - Nextcomment,
Nextuinstr = livevals(Livevals2prime)
->
Livevals2 = Livevals2prime,
Livemap1 = Livemap0,
Moreinstrs2 = Evenmoreinstrs,
Ccode1 = Ccode0
;
error("tailcall not preceded by livevals")
)
; Codeaddr = label(Label) ->
( map__search(Livemap0, Label, Livevals2prime) ->
Livevals2 = Livevals2prime,
Livemap1 = Livemap0,
Moreinstrs2 = Moreinstrs,
Ccode1 = Ccode0
;
error("cannot handle backwards local gotos")
)
;
Livevals2 = Livevals0,
Livemap1 = Livemap0,
Moreinstrs2 = Moreinstrs,
Ccode1 = Ccode0
)
; Uinstr = label(Label) ->
( Ccode0 = no ->
map__set(Livemap0, Label, Livevals0, Livemap1)
;
Livemap1 = Livemap0
),
Livevals2 = Livevals0,
Moreinstrs2 = Moreinstrs,
Ccode1 = Ccode0
; ( Uinstr = incr_sp(_) ; Uinstr = decr_sp(_)) ->
value_number__make_live(lval(sp), Livevals0, Livevals2),
Livemap1 = Livemap0,
Moreinstrs2 = Moreinstrs,
Ccode1 = Ccode0
; Uinstr = incr_hp(_) ->
value_number__make_live(lval(hp), Livevals0, Livevals2),
Livemap1 = Livemap0,
Moreinstrs2 = Moreinstrs,
Ccode1 = Ccode0
; Uinstr = if_val(Rval, _) ->
value_number__make_live(Rval, Livevals0, Livevals2),
Livemap1 = Livemap0,
Moreinstrs2 = Moreinstrs,
Ccode1 = Ccode0
; Uinstr = assign(Lval, Rval) ->
value_number__make_dead(Lval, Livevals0, Livevals1),
value_number__make_live(Rval, Livevals1, Livevals2),
Livemap1 = Livemap0,
Moreinstrs2 = Moreinstrs,
Ccode1 = Ccode0
; Uinstr = c_code(_) ->
Livemap1 = Livemap0,
Livevals2 = Livevals0,
Moreinstrs2 = Moreinstrs,
Ccode1 = yes
;
Livemap1 = Livemap0,
Livevals2 = Livevals0,
Moreinstrs2 = Moreinstrs,
Ccode1 = Ccode0
),
value_number__build_livemap(Moreinstrs2, Livevals2, Ccode1,
Livemap1, Livemap).
% Set all lvals found in this rval to live.
:- pred value_number__make_live(rval, lvalset, lvalset).
:- mode value_number__make_live(in, di, uo) is det.
value_number__make_live(lval(Lval), Livevals0, Livevals) :-
bintree_set__insert(Livevals0, Lval, Livevals).
value_number__make_live(var(_), Livevals0, Livevals0) :-
error("var rval should not propagate to value_number").
value_number__make_live(create(_, _, _), Livevals0, Livevals0) :-
error("create rval should not propagate to value_number").
value_number__make_live(mkword(_, Rval), Livevals0, Livevals) :-
value_number__make_live(Rval, Livevals0, Livevals).
value_number__make_live(field(_, Rval, _), Livevals0, Livevals) :-
value_number__make_live(Rval, Livevals0, Livevals).
value_number__make_live(const(_), Livevals0, Livevals0).
value_number__make_live(unop(_, Rval), Livevals0, Livevals) :-
value_number__make_live(Rval, Livevals0, Livevals).
value_number__make_live(binop(_, Rval1, Rval2), Livevals0, Livevals) :-
value_number__make_live(Rval1, Livevals0, Livevals1),
value_number__make_live(Rval2, Livevals1, Livevals).
% Set this lval to dead.
:- pred value_number__make_dead(lval, lvalset, lvalset).
:- mode value_number__make_dead(in, di, uo) is det.
value_number__make_dead(Lval, Livevals0, Livevals) :-
bintree_set__delete(Livevals0, Lval, Livevals).
% Optimize instructions, assume we are outside of a block.
:- pred value_number__opt_instrs(list(instruction), livemap,
list(instruction)).
:- mode value_number__opt_instrs(in, in, out) is det.
value_number__opt_instrs([], _, []).
value_number__opt_instrs([Instr0 | Instrs0], Livemap, Instrs) :-
Instr0 = Uinstr0 - _Comment0,
(
Uinstr0 = label(Label),
map__search(Livemap, Label, _Livevals)
->
value_number__init_tables(Vn_tables0),
value_number__opt_block(Instrs0, Vn_tables0, Livemap, no,
Instrs1),
Instrs = [Instr0 | Instrs1]
% value_number__opt_instrs(Instrs0, Livemap, Instrs1),
% Instrs = [Instr0 | Instrs1]
;
value_number__opt_instrs(Instrs0, Livemap, Instrs1),
Instrs = [Instr0 | Instrs1]
).
% Initialize the tables for optimizing a block of instructions.
:- pred value_number__init_tables(vn_tables).
:- mode value_number__init_tables(out) is det.
value_number__init_tables(Vn_tables) :-
map__init(Lval_to_vn_table0),
map__init(Rval_to_vn_table0),
map__init(Vn_to_rval_table0),
map__init(Vn_to_uses_table0),
map__init(Vn_to_locs_table0),
map__init(Loc_to_vn_table0),
Vn_tables = vn_tables(0,
Lval_to_vn_table0, Rval_to_vn_table0,
Vn_to_rval_table0, Vn_to_uses_table0,
Vn_to_locs_table0, Loc_to_vn_table0).
% Optimize instructions, assume we are inside of a block.
:- pred value_number__opt_block(list(instruction), vn_tables, livemap,
maybe(bintree_set(lval)), list(instruction)).
:- mode value_number__opt_block(in, in, in, in, out) is det.
value_number__opt_block([], _Vn_tables, _Livemap, _Last_livevals, []) :-
error("block has no terminator").
value_number__opt_block([Instr0 | Instrs0],
Vn_tables, Livemap, Last_livevals, Instrs) :-
value_number__handle_instr(Instr0, Vn_tables, Livemap,
Last_livevals, Instrs0, Instrs).
:- pred value_number__handle_instr(instruction, vn_tables, livemap,
maybe(bintree_set(lval)), list(instruction), list(instruction)).
:- mode value_number__handle_instr(in, in, in, in, in, out) is det.
value_number__handle_instr(Instr0, Vn_tables0, Livemap, Last_livevals,
Instrs0, Instrs) :-
% should be converted to if-then-elses when np efficiency is important
Instr0 = Uinstr0 - Comment,
(
Uinstr0 = comment(_),
value_number__opt_block(Instrs0, Vn_tables0, Livemap,
no, Instrs1),
Instrs = [Instr0 | Instrs1]
;
Uinstr0 = livevals(Livevals),
value_number__opt_block(Instrs0, Vn_tables0, Livemap,
yes(Livevals), Instrs1),
Instrs = [Instr0 | Instrs1]
;
Uinstr0 = block(_, _),
error("block should not be found in handle_instr")
;
Uinstr0 = assign(Lval, Rval),
% the next call does the counting of the new use
value_number__use_rval_find_vn(Rval, Vn,
Vn_tables0, Vn_tables1),
value_number__lval_to_vnlval(Lval, Vn_lval,
Vn_tables1, Vn_tables2),
Vn_tables2 = vn_tables(Next_vn2,
Lval_to_vn_table2, Rval_to_vn_table2,
Vn_to_rval_table2, Vn_to_uses_table2,
Vn_to_locs_table2, Loc_to_vn_table2),
( map__search(Lval_to_vn_table2, Vn_lval, Old_vn) ->
map__lookup(Vn_to_uses_table2, Old_vn, Old_vn_uses2),
Old_vn_uses3 is Old_vn_uses2 - 1,
map__set(Vn_to_uses_table2, Old_vn, Old_vn_uses3,
Vn_to_uses_table3)
;
Vn_to_uses_table3 = Vn_to_uses_table2
),
map__set(Lval_to_vn_table2, Vn_lval, Vn, Lval_to_vn_table3),
Vn_tables3 = vn_tables(Next_vn2,
Lval_to_vn_table3, Rval_to_vn_table2,
Vn_to_rval_table2, Vn_to_uses_table3,
Vn_to_locs_table2, Loc_to_vn_table2),
value_number__opt_block(Instrs0, Vn_tables3, Livemap,
no, Instrs1),
Instrs = [Instr0 | Instrs1]
;
Uinstr0 = call(_, _),
( Last_livevals = yes(Livevals) ->
% flush
true
;
error("call not preceded by livevals")
),
value_number__opt_instrs(Instrs0, Livemap, Instrs1),
opt_debug__dump_tables(Vn_tables0, Newcomment),
Instrs = [comment(Newcomment) - "", Instr0 | Instrs1]
;
Uinstr0 = mkframe(_, _, _),
value_number__opt_block(Instrs0, Vn_tables0, Livemap,
no, Instrs1),
Instrs = [Instr0 | Instrs1]
;
Uinstr0 = modframe(_),
value_number__opt_block(Instrs0, Vn_tables0, Livemap,
no, Instrs1),
Instrs = [Instr0 | Instrs1]
;
Uinstr0 = label(_),
opt_util__skip_comments(Instrs0, Instrs1),
( Instrs1 = [livevals(_Nextlivevals) - _ | _] ->
% XXX flush all these livevals
true
;
% flush all livevals or maybe abort
true
),
value_number__opt_block(Instrs1, Vn_tables0, Livemap,
no, Instrs2),
Instrs = [Instr0 | Instrs2]
% opt_debug__dump_label(L, L_str),
% string__append_list(["label ", L_str, " in handle_instr"], Str),
% error(Str)
;
Uinstr0 = goto(_),
( Last_livevals = yes(Livevals) ->
% flush
true
;
error("goto not preceded by livevals")
),
value_number__opt_instrs(Instrs0, Livemap, Instrs1),
opt_debug__dump_tables(Vn_tables0, Newcomment),
Instrs = [comment(Newcomment) - "", Instr0 | Instrs1]
;
Uinstr0 = computed_goto(_, _),
( Last_livevals = yes(Livevals) ->
% flush
true
;
error("computed goto not preceded by livevals")
),
value_number__opt_instrs(Instrs0, Livemap, Instrs1),
opt_debug__dump_tables(Vn_tables0, Newcomment),
Instrs = [comment(Newcomment) - "", Instr0 | Instrs1]
;
Uinstr0 = c_code(_),
error("c_code in handle_instr")
;
Uinstr0 = if_val(_, _),
% XXX flush values live at Code_addr
value_number__opt_block(Instrs0, Vn_tables0, Livemap,
no, Instrs1),
opt_debug__dump_tables(Vn_tables0, Newcomment),
Instrs = [comment(Newcomment) - "", Instr0 | Instrs1]
;
Uinstr0 = incr_sp(N),
value_number__opt_block(Instrs0, Vn_tables0, Livemap,
no, Instrs1),
Instrs = [Instr0 | Instrs1]
;
Uinstr0 = decr_sp(N),
value_number__opt_block(Instrs0, Vn_tables0, Livemap,
no, Instrs1),
Instrs = [Instr0 | Instrs1]
;
Uinstr0 = incr_hp(N),
value_number__handle_instr(assign(hp,
binop((+), lval(hp), const(int_const(N)))) - Comment,
Vn_tables0, Livemap, Last_livevals, Instrs0, Instrs)
).
:- pred value_number__use_rval_find_vn(rval, vn, vn_tables, vn_tables).
:- mode value_number__use_rval_find_vn(in, out, di, uo) is det.
value_number__use_rval_find_vn(lval(Lval), Vn, Vn_tables0, Vn_tables) :-
value_number__use_lval_find_vn(Lval, Vn, Vn_tables0, Vn_tables).
value_number__use_rval_find_vn(var(_), _, _Vn_tables, _) :-
error("value_number should never get rval: var").
value_number__use_rval_find_vn(create(_, _, _), _, _Vn_tables, _) :-
error("value_number should never get rval: create").
value_number__use_rval_find_vn(mkword(Tag, Rval), Vn, Vn_tables0, Vn_tables) :-
value_number__use_rval_find_vn(Rval, Sub_vn, Vn_tables0, Vn_tables1),
value_number__use_vnrval_find_vn(vn_mkword(Tag, Sub_vn), Vn,
Vn_tables1, Vn_tables).
value_number__use_rval_find_vn(unop(Op, Rval), Vn, Vn_tables0, Vn_tables) :-
value_number__use_rval_find_vn(Rval, Sub_vn, Vn_tables0, Vn_tables1),
value_number__use_vnrval_find_vn(vn_unop(Op, Sub_vn), Vn,
Vn_tables1, Vn_tables).
value_number__use_rval_find_vn(const(Const), Vn, Vn_tables0, Vn_tables) :-
value_number__use_vnrval_find_vn(vn_const(Const), Vn,
Vn_tables0, Vn_tables).
value_number__use_rval_find_vn(field(Tag, Rval, Slot), Vn,
Vn_tables0, Vn_tables) :-
value_number__use_rval_find_vn(Rval, Sub_vn, Vn_tables0, Vn_tables1),
value_number__use_vnrval_find_vn(vn_field(Tag, Sub_vn, Slot), Vn,
Vn_tables1, Vn_tables).
value_number__use_rval_find_vn(binop(Op, Left_rval, Right_rval), Vn,
Vn_tables0, Vn_tables) :-
value_number__use_rval_find_vn(Left_rval, Left_vn,
Vn_tables0, Vn_tables1),
value_number__use_rval_find_vn(Right_rval, Right_vn,
Vn_tables1, Vn_tables2),
value_number__use_vnrval_find_vn(vn_binop(Op, Left_vn, Right_vn), Vn,
Vn_tables2, Vn_tables).
:- pred value_number__use_vnrval_find_vn(vn_rval, vn, vn_tables, vn_tables).
:- mode value_number__use_vnrval_find_vn(in, out, di, uo) is det.
value_number__use_vnrval_find_vn(Vn_rval, Vn, Vn_tables0, Vn_tables) :-
value_number__simplify_vnrval(Vn_rval, Vn_rval1,
Vn_tables0, Vn_tables1),
value_number__lookup_vnrval(Vn_rval1, Vn, Vn_tables1, Vn_tables).
% Simplify the vnrval by partially evaluating expressions involving
% integer constants. To make this simpler, swap the arguments of
% commutative expressions around to put the constants on the right
% side.
%
% The simplification has to be done on vn_rvals and not on rvals
% even though this complicates the code. The reason is that an
% expression such as r1 + 4 can be simplified if we know that
% r1 was defined as r2 + 8.
%
% This code should decrement the use counts of value numbers that
% the incoming vn_rval refers to that the outgoing vn_rval does not,
% but this is not yet implemented. In any case, we probably don't need
% accurate use counts on constants.
:- pred value_number__simplify_vnrval(vn_rval, vn_rval, vn_tables, vn_tables).
:- mode value_number__simplify_vnrval(in, out, di, uo) is det.
value_number__simplify_vnrval(Vn_rval0, Vn_rval, Vn_tables0, Vn_tables) :-
Vn_tables0 = vn_tables(_Next_vn0,
_Lval_to_vn_table0, _Rval_to_vn_table0,
Vn_to_rval_table0, _Vn_to_uses_table0,
_Vn_to_locs_table0, _Loc_to_vn_table0),
( Vn_rval0 = vn_binop((+), Vn1, Vn2) ->
map__lookup(Vn_to_rval_table0, Vn1, Vn_rval1),
map__lookup(Vn_to_rval_table0, Vn2, Vn_rval2),
( Vn_rval1 = vn_const(int_const(I1)) ->
( Vn_rval2 = vn_const(int_const(I2)) ->
I is I1 + I2,
Vn_rval = vn_const(int_const(I)),
Vn_tables = Vn_tables0
; Vn_rval2 = vn_binop((+), Vn21, Vn22) ->
map__lookup(Vn_to_rval_table0, Vn22, Vn_rval22),
( Vn_rval22 = vn_const(int_const(I22)) ->
I is I1 + I22,
value_number__use_vnrval_find_vn(
vn_const(int_const(I)), Vn_i,
Vn_tables0, Vn_tables),
Vn_rval = vn_binop((+), Vn21, Vn_i)
;
Vn_rval = vn_binop((+), Vn2, Vn1),
Vn_tables = Vn_tables0
)
;
Vn_rval = vn_binop((+), Vn2, Vn1),
Vn_tables = Vn_tables0
)
; Vn_rval1 = vn_binop((+), Vn11, Vn12) ->
map__lookup(Vn_to_rval_table0, Vn12, Vn_rval12),
( Vn_rval12 = vn_const(int_const(I12)) ->
( Vn_rval2 = vn_const(int_const(I2)) ->
I is I12 + I2,
value_number__use_vnrval_find_vn(
vn_const(int_const(I)), Vn_i,
Vn_tables0, Vn_tables),
Vn_rval = vn_binop((+), Vn11, Vn_i)
; Vn_rval2 = vn_binop((+), Vn21, Vn22) ->
map__lookup(Vn_to_rval_table0, Vn22, Vn_rval22),
( Vn_rval22 = vn_const(int_const(I22)) ->
I is I12 + I22,
value_number__use_vnrval_find_vn(
vn_binop((+), Vn11, Vn21), Vn_e,
Vn_tables0, Vn_tables1),
value_number__use_vnrval_find_vn(
vn_const(int_const(I)), Vn_i,
Vn_tables1, Vn_tables),
Vn_rval = vn_binop((+), Vn_e, Vn_i)
;
value_number__use_vnrval_find_vn(
vn_binop((+), Vn2, Vn11), Vn_e,
Vn_tables0, Vn_tables),
Vn_rval = vn_binop((+), Vn_e, Vn12)
)
;
Vn_rval = Vn_rval0,
Vn_tables = Vn_tables0
)
;
Vn_rval = vn_binop((+), Vn2, Vn1),
Vn_tables = Vn_tables0
)
;
Vn_rval = Vn_rval0,
Vn_tables = Vn_tables0
)
; Vn_rval0 = vn_binop((-), Vn1, Vn2) ->
map__lookup(Vn_to_rval_table0, Vn2, Vn_rval2),
( Vn_rval2 = vn_const(int_const(I2)) ->
NI2 is 0 - I2,
value_number__use_vnrval_find_vn(vn_const(int_const(NI2)),
Vn2prime, Vn_tables0, Vn_tables1),
value_number__simplify_vnrval(vn_binop((+), Vn1, Vn2prime),
Vn_rval, Vn_tables1, Vn_tables)
;
% XXX more simplification opportunities exist
Vn_rval = Vn_rval0,
Vn_tables = Vn_tables0
)
;
% XXX more simplification opportunities exist
Vn_rval = Vn_rval0,
Vn_tables = Vn_tables0
).
:- pred value_number__lookup_vnrval(vn_rval, vn, vn_tables, vn_tables).
:- mode value_number__lookup_vnrval(in, out, di, uo) is det.
value_number__lookup_vnrval(Vn_rval, Vn, Vn_tables0, Vn_tables) :-
Vn_tables0 = vn_tables(Next_vn0,
Lval_to_vn_table0, Rval_to_vn_table0,
Vn_to_rval_table0, Vn_to_uses_table0,
Vn_to_locs_table0, Loc_to_vn_table0),
( map__search(Rval_to_vn_table0, Vn_rval, Vn_prime) ->
Vn = Vn_prime,
map__lookup(Vn_to_uses_table0, Vn, Usecount),
Usecount1 is Usecount + 1,
map__set(Vn_to_uses_table0, Vn, Usecount1, Vn_to_uses_table1),
Vn_tables = vn_tables(Next_vn0,
Lval_to_vn_table0, Rval_to_vn_table0,
Vn_to_rval_table0, Vn_to_uses_table1,
Vn_to_locs_table0, Loc_to_vn_table0)
;
Vn = Next_vn0,
Next_vn1 is Next_vn0 + 1,
map__set(Rval_to_vn_table0, Vn_rval, Vn, Rval_to_vn_table1),
map__set(Vn_to_rval_table0, Vn, Vn_rval, Vn_to_rval_table1),
map__set(Vn_to_uses_table0, Vn, 1, Vn_to_uses_table1),
Vn_tables = vn_tables(Next_vn1,
Lval_to_vn_table0, Rval_to_vn_table1,
Vn_to_rval_table1, Vn_to_uses_table1,
Vn_to_locs_table0, Loc_to_vn_table0)
).
:- pred value_number__use_lval_find_vn(lval, vn, vn_tables, vn_tables).
:- mode value_number__use_lval_find_vn(in, out, di, uo) is det.
value_number__use_lval_find_vn(Lval, Vn, Vn_tables0, Vn_tables) :-
value_number__lval_to_vnlval(Lval, Vn_lval, Vn_tables0, Vn_tables1),
Vn_tables1 = vn_tables(Next_vn1,
Lval_to_vn_table1, Rval_to_vn_table1,
Vn_to_rval_table1, Vn_to_uses_table1,
Vn_to_locs_table1, Loc_to_vn_table1),
( map__search(Lval_to_vn_table1, Vn_lval, Vn_prime) ->
Vn = Vn_prime,
map__lookup(Vn_to_uses_table1, Vn, Usecount1),
Usecount2 is Usecount1 + 1,
map__set(Vn_to_uses_table1, Vn, Usecount2, Vn_to_uses_table2),
Vn_tables = vn_tables(Next_vn1,
Lval_to_vn_table1, Rval_to_vn_table1,
Vn_to_rval_table1, Vn_to_uses_table2,
Vn_to_locs_table1, Loc_to_vn_table1)
;
Vn = Next_vn1,
Next_vn2 is Next_vn1 + 1,
map__set(Lval_to_vn_table1, Vn_lval, Vn,
Lval_to_vn_table2),
map__set(Rval_to_vn_table1, vn_origlval(Vn_lval), Vn,
Rval_to_vn_table2),
map__set(Vn_to_rval_table1, Vn, vn_origlval(Vn_lval),
Vn_to_rval_table2),
map__set(Vn_to_uses_table1, Vn, 1,
Vn_to_uses_table2),
map__set(Vn_to_locs_table1, Vn, [Vn_lval],
Vn_to_locs_table2),
map__set(Loc_to_vn_table1, Vn_lval, Vn,
Loc_to_vn_table2),
Vn_tables = vn_tables(Next_vn2,
Lval_to_vn_table2, Rval_to_vn_table2,
Vn_to_rval_table2, Vn_to_uses_table2,
Vn_to_locs_table2, Loc_to_vn_table2)
).
:- pred value_number__lval_to_vnlval(lval, vn_lval, vn_tables, vn_tables).
:- mode value_number__lval_to_vnlval(in, out, di, uo) is det.
value_number__lval_to_vnlval(reg(Reg), vn_reg(Reg), Vn_tables, Vn_tables).
value_number__lval_to_vnlval(succip, vn_succip, Vn_tables, Vn_tables).
value_number__lval_to_vnlval(maxfr, vn_maxfr, Vn_tables, Vn_tables).
value_number__lval_to_vnlval(curredoip, vn_curredoip, Vn_tables, Vn_tables).
value_number__lval_to_vnlval(hp, vn_hp, Vn_tables, Vn_tables).
value_number__lval_to_vnlval(sp, vn_sp, Vn_tables, Vn_tables).
value_number__lval_to_vnlval(stackvar(Slot), vn_stackvar(Slot),
Vn_tables, Vn_tables).
value_number__lval_to_vnlval(framevar(Slot), vn_framevar(Slot),
Vn_tables, Vn_tables).
value_number__lval_to_vnlval(temp(No), vn_temp(No),
Vn_tables, Vn_tables).
value_number__lval_to_vnlval(field(Tag, Lval, Slot), vn_field(Tag, Vn, Slot),
Vn_tables0, Vn_tables) :-
value_number__use_lval_find_vn(Lval, Vn, Vn_tables0, Vn_tables).
value_number__lval_to_vnlval(lvar(_Var), _, _Vn_tables, _) :-
error("Lvar detected in value_number").
:- pred value_number__flush_lval(vn_lval, vn_tables, vn_tables,
int, int, list(instr)).
:- mode value_number__flush_lval(in, di, uo, in, out, out) is det.
% value_number__flush_lval(Vn_lval, Vn_tables0, Vn_tables, Temp0, Temp, Instrs) :-
% Vn_tables0 = vn_tables(Next_vn0,
% Lval_to_vn_table0, Rval_to_vn_table0,
% Vn_to_rval_table0, Vn_to_uses_table0,
% Vn_to_locs_table0, Loc_to_vn_table0).
% % more to come
% given a list of root vn_lval/vn pairs, construct a list of vn before vn pairs
% do a topological sort, breaking minimal cycles with temp lvals