mirror of
https://github.com/Mercury-Language/mercury.git
synced 2026-04-22 12:53:47 +00:00
Estimated hours taken: 2.5 Some more changes to minimize the complexity of the intermodule dependencies. In particular, ensure that bytecode.m does not need to import llds.m. compiler/llds.m: compiler/builtin_ops.m: Move the definitions of the unary_op and binary_op types into a new module `builtin_ops'. These types are used by three of the different back-ends (bytecode, llds, and mlds) and therefore deserve to be in their own module. compiler/bytecode.m: Define a type `byte_reg_type' and use that instead of llds__reg_type. Delete the import of module llds. compiler/notes/compiler_design.html: Document the new module builtin_ops. compiler/rl_exprn.m: Add a comment explaining why we need to import llds (and builtin_ops). compiler/base_type_layout.m: compiler/bytecode.m: compiler/code_util.m: compiler/dense_switch.m: compiler/ite_gen.m: compiler/jumpopt.m: compiler/llds_out.m: compiler/lookup_switch.m: compiler/middle_rec.m: compiler/opt_debug.m: compiler/opt_util.m: compiler/rl_exprn.m: compiler/string_switch.m: compiler/tag_switch.m: compiler/transform_llds.m: compiler/unify_gen.m: compiler/value_number.m: compiler/vn_block.m: compiler/vn_cost.m: compiler/vn_flush.m: compiler/vn_type.m: compiler/vn_util.m: compiler/vn_verify.m: Add imports of module builtin_ops to lots of modules that imported llds.
1188 lines
42 KiB
Mathematica
1188 lines
42 KiB
Mathematica
%-----------------------------------------------------------------------------%
|
|
% Copyright (C) 1994-1999 The University of Melbourne.
|
|
% This file may only be copied under the terms of the GNU General
|
|
% Public License - see the file COPYING in the Mercury distribution.
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% value_number.m - optimization of straight-line LLDS code.
|
|
|
|
% Author: zs.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- module value_number.
|
|
|
|
:- interface.
|
|
|
|
:- import_module llds.
|
|
:- import_module list, set, io.
|
|
|
|
% Find straight-line code sequences and optimize them using
|
|
% value numbering.
|
|
|
|
:- pred value_number_main(list(instruction), set(label), list(instruction),
|
|
io__state, io__state).
|
|
:- mode value_number_main(in, in, out, di, uo) is det.
|
|
|
|
% The main value numbering pass introduces references to temporary
|
|
% variables whose values need be preserved only within an extended
|
|
% basic block. The post_main pass looks for references to temporaries
|
|
% and introduces block instructions whenever it sees them. These
|
|
% block instructions go from the first reference to a temporary
|
|
% to the end of its extended basic block.
|
|
|
|
:- pred value_number__post_main(list(instruction), list(instruction)).
|
|
:- mode value_number__post_main(in, out) is det.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- implementation.
|
|
|
|
:- import_module builtin_ops.
|
|
:- import_module vn_type, vn_table, vn_block, vn_order, vn_flush, vn_temploc.
|
|
:- import_module vn_cost, vn_debug, vn_util, vn_verify, vn_filter.
|
|
:- import_module opt_debug, opt_util, peephole, labelopt.
|
|
:- import_module globals, options, livemap, code_util.
|
|
|
|
:- import_module map, bimap, require, int, string, std_util, assoc_list.
|
|
:- import_module bool.
|
|
|
|
% We can't find out what variables are used by C code sequences,
|
|
% so we don't optimize any predicates containing them.
|
|
|
|
value_number_main(Instrs0, LayoutLabelSet, Instrs) -->
|
|
{ opt_util__get_prologue(Instrs0, ProcLabel,
|
|
LabelInstr, Comments, Instrs1) },
|
|
{ opt_util__new_label_no(Instrs1, 1000, N0) },
|
|
{ value_number__prepare_for_vn([LabelInstr | Instrs1], ProcLabel,
|
|
no, AllocSet, BreakSet, N0, N, Instrs2) },
|
|
{ labelopt__build_useset(Instrs2, LayoutLabelSet, UseSet) },
|
|
{ livemap__build(Instrs2, MaybeLiveMap) },
|
|
(
|
|
{ MaybeLiveMap = yes(LiveMap) },
|
|
vn_debug__livemap_msg(LiveMap),
|
|
value_number__procedure(Instrs2, LiveMap, UseSet,
|
|
AllocSet, BreakSet, N, Instrs3),
|
|
{ list__append(Comments, Instrs3, Instrs) }
|
|
;
|
|
% Can't find live lvals and thus can't perform value numbering
|
|
% if there is a c_code or a pragma_c in the instructions.
|
|
{ MaybeLiveMap = no },
|
|
{ Instrs = Instrs0 }
|
|
).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% Instructions such as if_val(tag(r1) == 1 && field(1, r1, N) = X)
|
|
% pose a problem for value numbering. The field reference will be
|
|
% extracted into a register before the if, and this extraction will
|
|
% cause an unaligned access if done before the tag test. Similar
|
|
% problems can arise even if the code before the && does not contain
|
|
% a tag operator, since this may have been applied earlier.
|
|
%
|
|
% By converting all boolean operations in if_vals into multiple
|
|
% if_vals, we are preventing this from happening.
|
|
%
|
|
% Value numbering currently combines multiple heap pointer
|
|
% increments into a single heap pointer increment. If we're
|
|
% using conservative garbage collection, this would create
|
|
% invalid code (unless the collector was compiled with
|
|
% -DALL_INTERIOR_POINTERS, which would be very bad for
|
|
% performance). Hence, if GC=conservative we must not
|
|
% perform value numbering on a block that contains more
|
|
% than one heap pointer increment.
|
|
%
|
|
% We therefore insert new labels before every occurrence of incr_hp,
|
|
% with the exception of the first one in each basic block. This allows
|
|
% vn_block__divide_into_blocks to break up such blocks into smaller
|
|
% blocks, with each smaller block having at most one incr_hp.
|
|
%
|
|
% Assignments to curfr change the meaning of framevars. Moving
|
|
% any reference (read or write) to a framevar across such an assignment
|
|
% will result in invalid code. The only really safe way to handle the
|
|
% situation is to ensure that such assignments do not get lumped
|
|
% together with other statements when doing value numbering. We
|
|
% therefore insert labels before and after such assignments.
|
|
% Our caller will break the code sequence at these labels.
|
|
%
|
|
% Mkframe operations also change curfr, and therefore get the
|
|
% same treatment. We also apply this treatment to (1) assignments to
|
|
% the control slots in nondet stack frames, since otherwise a bug
|
|
% in the rest of value numbering may cause them to be improperly
|
|
% deleted, and (b) uses of those control slots in the form of
|
|
% branches to do_redo and do_fail, since otherwise assignments
|
|
% to stack variables may be moved across them.
|
|
|
|
:- pred value_number__prepare_for_vn(list(instruction), proc_label,
|
|
bool, set(label), set(label), int, int, list(instruction)).
|
|
:- mode value_number__prepare_for_vn(in, in, in, out, out, in, out, out) is det.
|
|
|
|
value_number__prepare_for_vn([], _, _, AllocSet, BreakSet, N, N, []) :-
|
|
set__init(AllocSet),
|
|
set__init(BreakSet).
|
|
value_number__prepare_for_vn([Instr0 | Instrs0], ProcLabel,
|
|
SeenAlloc, AllocSet, BreakSet, N0, N, Instrs) :-
|
|
Instr0 = Uinstr0 - _Comment,
|
|
( Uinstr0 = if_val(Test, TrueAddr) ->
|
|
( ( TrueAddr = do_redo ; TrueAddr = do_fail ) ->
|
|
MaybeBeforeLabel = yes(local(ProcLabel, N0)),
|
|
N1 is N0 + 1
|
|
;
|
|
MaybeBeforeLabel = no,
|
|
N1 = N0
|
|
),
|
|
( Instrs0 = [label(OldFalseLabel) - _ | _] ->
|
|
FalseLabel = OldFalseLabel,
|
|
MaybeNewFalseLabel = no,
|
|
N2 = N1
|
|
;
|
|
FalseLabel = local(ProcLabel, N1),
|
|
MaybeNewFalseLabel = yes(FalseLabel),
|
|
N2 is N1 + 1
|
|
),
|
|
FalseAddr = label(FalseLabel),
|
|
value_number__breakup_complex_if(Test, TrueAddr, FalseAddr,
|
|
FalseAddr, ProcLabel, N2, N3, IfInstrs),
|
|
value_number__prepare_for_vn(Instrs0, ProcLabel,
|
|
SeenAlloc, AllocSet, BreakSet0, N3, N, Instrs1),
|
|
( MaybeNewFalseLabel = yes(NewFalseLabel) ->
|
|
FalseInstr = label(NewFalseLabel) - "vn false label",
|
|
list__append(IfInstrs, [FalseInstr | Instrs1], Instrs2)
|
|
;
|
|
list__append(IfInstrs, Instrs1, Instrs2)
|
|
),
|
|
( MaybeBeforeLabel = yes(BeforeLabel) ->
|
|
set__insert(BreakSet0, BeforeLabel, BreakSet1),
|
|
set__insert(BreakSet1, FalseLabel, BreakSet),
|
|
BeforeInstr = label(BeforeLabel) - "vn before label",
|
|
Instrs = [BeforeInstr | Instrs2]
|
|
;
|
|
BreakSet = BreakSet0,
|
|
Instrs = Instrs2
|
|
)
|
|
; Uinstr0 = incr_hp(_, _, _, _) ->
|
|
( SeenAlloc = yes ->
|
|
N1 is N0 + 1,
|
|
NewLabel = local(ProcLabel, N0),
|
|
value_number__prepare_for_vn(Instrs0, ProcLabel,
|
|
yes, AllocSet0, BreakSet, N1, N, Instrs1),
|
|
set__insert(AllocSet0, NewLabel, AllocSet),
|
|
LabelInstr = label(NewLabel) - "vn incr divide label",
|
|
Instrs = [LabelInstr, Instr0 | Instrs1]
|
|
;
|
|
value_number__prepare_for_vn(Instrs0, ProcLabel,
|
|
yes, AllocSet, BreakSet, N0, N, Instrs1),
|
|
Instrs = [Instr0 | Instrs1]
|
|
)
|
|
;
|
|
(
|
|
Uinstr0 = assign(Target, _),
|
|
(
|
|
Target = curfr
|
|
;
|
|
Target = maxfr
|
|
;
|
|
Target = redoip(_)
|
|
;
|
|
Target = succip(_)
|
|
;
|
|
Target = prevfr(_)
|
|
;
|
|
Target = succfr(_)
|
|
)
|
|
;
|
|
Uinstr0 = mkframe(_, _)
|
|
)
|
|
->
|
|
N1 is N0 + 1,
|
|
BeforeLabel = local(ProcLabel, N0),
|
|
BeforeInstr = label(BeforeLabel) - "vn stack ctrl before label",
|
|
N2 is N1 + 1,
|
|
AfterLabel = local(ProcLabel, N1),
|
|
AfterInstr = label(AfterLabel) - "vn stack ctrl after label",
|
|
value_number__prepare_for_vn(Instrs0, ProcLabel,
|
|
yes, AllocSet, BreakSet0, N2, N, Instrs1),
|
|
set__insert(BreakSet0, BeforeLabel, BreakSet1),
|
|
set__insert(BreakSet1, AfterLabel, BreakSet),
|
|
Instrs = [BeforeInstr, Instr0, AfterInstr | Instrs1]
|
|
;
|
|
value_number__prepare_for_vn(Instrs0, ProcLabel,
|
|
SeenAlloc, AllocSet, BreakSet, N0, N, Instrs1),
|
|
Instrs = [Instr0 | Instrs1]
|
|
).
|
|
|
|
:- pred value_number__breakup_complex_if(rval, code_addr, code_addr, code_addr,
|
|
proc_label, int, int, list(instruction)).
|
|
:- mode value_number__breakup_complex_if(in, in, in, in, in, in, out, out)
|
|
is det.
|
|
|
|
value_number__breakup_complex_if(Test, TrueAddr, FalseAddr, NextAddr,
|
|
ProcLabel, N0, N, Instrs) :-
|
|
( Test = binop(and, Test1, Test2) ->
|
|
NewLabel = local(ProcLabel, N0),
|
|
NewAddr = label(NewLabel),
|
|
N1 is N0 + 1,
|
|
value_number__breakup_complex_if(Test1, NewAddr, FalseAddr,
|
|
NewAddr, ProcLabel, N1, N2, Instrs1),
|
|
value_number__breakup_complex_if(Test2, TrueAddr, FalseAddr,
|
|
NextAddr, ProcLabel, N2, N, Instrs2),
|
|
list__append(Instrs1, [label(NewLabel) - "" | Instrs2], Instrs)
|
|
; Test = binop(or, Test1, Test2) ->
|
|
NewLabel = local(ProcLabel, N0),
|
|
NewAddr = label(NewLabel),
|
|
N1 is N0 + 1,
|
|
value_number__breakup_complex_if(Test1, TrueAddr, NewAddr,
|
|
NewAddr, ProcLabel, N1, N2, Instrs1),
|
|
value_number__breakup_complex_if(Test2, TrueAddr, FalseAddr,
|
|
NextAddr, ProcLabel, N2, N, Instrs2),
|
|
list__append(Instrs1, [label(NewLabel) - "" | Instrs2], Instrs)
|
|
; Test = unop(not, Test1) ->
|
|
value_number__breakup_complex_if(Test1, FalseAddr, TrueAddr,
|
|
NextAddr, ProcLabel, N0, N, Instrs)
|
|
;
|
|
N = N0,
|
|
( NextAddr = FalseAddr ->
|
|
Instrs = [if_val(Test, TrueAddr) - ""]
|
|
; NextAddr = TrueAddr ->
|
|
code_util__neg_rval(Test, NegTest),
|
|
Instrs = [if_val(NegTest, FalseAddr) - ""]
|
|
;
|
|
Instrs = [if_val(Test, TrueAddr) - "",
|
|
goto(FalseAddr) - ""]
|
|
)
|
|
).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% Optimize the code of a procedure.
|
|
|
|
:- pred value_number__procedure(list(instruction), livemap, set(label),
|
|
set(label), set(label), int, list(instruction), io__state, io__state).
|
|
:- mode value_number__procedure(in, in, in, in, in, in, out, di, uo) is det.
|
|
|
|
value_number__procedure(Instrs0, LiveMap, UseSet, AllocSet, BreakSet,
|
|
N0, OptInstrs) -->
|
|
globals__io_get_globals(Globals),
|
|
{ opt_util__gather_comments(Instrs0, Comments, Instrs1) },
|
|
{ globals__get_gc_method(Globals, GC) },
|
|
( { GC = conservative } ->
|
|
{ set__union(UseSet, AllocSet, DivideSet0) }
|
|
;
|
|
{ DivideSet0 = UseSet }
|
|
),
|
|
{ set__union(DivideSet0, BreakSet, DivideSet) },
|
|
vn_debug__cost_header_msg("procedure before value numbering"),
|
|
vn_debug__dump_instrs(Instrs1),
|
|
{ vn_block__divide_into_blocks(Instrs1, DivideSet, Blocks) },
|
|
{ globals__get_options(Globals, OptionTable) },
|
|
{ vn_type__init_params(OptionTable, Params) },
|
|
value_number__optimize_blocks(Blocks, LiveMap, Params, N0, OptBlocks0,
|
|
[], RevTuples),
|
|
{ list__condense([Comments | OptBlocks0], OptInstrs0) },
|
|
{ opt_util__propagate_livevals(OptInstrs0, OptInstrs1) },
|
|
vn_debug__cost_header_msg("procedure after non-pred value numbering"),
|
|
vn_debug__dump_instrs(OptInstrs1),
|
|
{ globals__lookup_bool_option(Globals, pred_value_number, PredVn) },
|
|
( { PredVn = yes } ->
|
|
% Predicate wide value numbering tries to delete assignments
|
|
% to variables when the target location already contains the
|
|
% right value. However, if this assignment is in a loop,
|
|
% then this eliminated assignment may be exactly what put the
|
|
% right value in the right location. For example, we can't
|
|
% delete the assignment to r1 in the following code:
|
|
%
|
|
% L1:
|
|
% r1 = r2
|
|
% goto L1
|
|
%
|
|
% If opt_util__propagate_livevals changes any livevals
|
|
% instructions, we also can't apply predicate wide value
|
|
% numbering, since its input (OptBlocks) contains the
|
|
% old livevals sets.
|
|
(
|
|
{ value_number__has_no_backward_branches(Instrs0) },
|
|
{ OptInstrs1 = OptInstrs0 }
|
|
->
|
|
{ list__reverse(RevTuples, Tuples) },
|
|
value_number__process_parallel_tuples(Tuples,
|
|
OptBlocks0, LiveMap, Params, OptBlocks),
|
|
{ list__condense([Comments | OptBlocks], OptInstrs2) },
|
|
{ opt_util__propagate_livevals(OptInstrs2, OptInstrs) },
|
|
vn_debug__cost_header_msg("procedure after parallels"),
|
|
vn_debug__dump_instrs(OptInstrs)
|
|
;
|
|
vn_debug__cost_header_msg("parallels do not apply"),
|
|
{ OptInstrs = OptInstrs0 }
|
|
)
|
|
;
|
|
{ OptInstrs = OptInstrs0 }
|
|
).
|
|
|
|
:- pred value_number__optimize_blocks(list(list(instruction)), livemap,
|
|
vn_params, int, list(list(instruction)), list(maybe(vn_ctrl_tuple)),
|
|
list(maybe(vn_ctrl_tuple)), io__state, io__state).
|
|
% :- mode value_number__optimize_blocks(in, in, in, in, out, di, uo, di, uo)
|
|
% is det.
|
|
:- mode value_number__optimize_blocks(in, in, in, in, out, in, out, di, uo)
|
|
is det.
|
|
|
|
value_number__optimize_blocks([], _, _, _, [], Tuples, Tuples) --> [].
|
|
value_number__optimize_blocks([Block0 | Blocks0], LiveMap, Params, LabelNo0,
|
|
[Block | Blocks], RevTuples0, RevTuples) -->
|
|
value_number__optimize_block(Block0, LiveMap, Params, [],
|
|
LabelNo0, LabelNo1, Block, RevTuples0, RevTuples1),
|
|
value_number__optimize_blocks(Blocks0, LiveMap, Params, LabelNo1,
|
|
Blocks, RevTuples1, RevTuples).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- pred value_number__optimize_block(list(instruction), livemap, vn_params,
|
|
list(parentry), int, int, list(instruction), list(maybe(vn_ctrl_tuple)),
|
|
list(maybe(vn_ctrl_tuple)), io__state, io__state).
|
|
:- mode value_number__optimize_block(in, in, in, in, in, out, out, in, out,
|
|
di, uo) is det.
|
|
|
|
value_number__optimize_block(Instrs0, LiveMap, Params, ParEntries,
|
|
LabelNo0, LabelNo, Instrs, RevTuples0, RevTuples) -->
|
|
(
|
|
{ list__reverse(Instrs0, RevInstrs) },
|
|
{ RevInstrs = [LastInstr - _ | _] },
|
|
{ opt_util__can_instr_fall_through(LastInstr, yes) }
|
|
->
|
|
% The block ends with a call to an erroneous procedure
|
|
% and its never to be used return label
|
|
{ Instrs = Instrs0 },
|
|
{ LabelNo = LabelNo0 },
|
|
{ RevTuples = [no | RevTuples0] }
|
|
;
|
|
value_number__optimize_fragment(Instrs0, LiveMap, Params,
|
|
ParEntries, LabelNo0, Tuple, Instrs),
|
|
vn_debug__tuple_msg(no, Instrs, Tuple),
|
|
{ Tuple = tuple(_, _, _, LabelNo, _) },
|
|
{ RevTuples = [yes(Tuple) | RevTuples0] }
|
|
).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% Optimize a fragment of a block. This may be the entire block,
|
|
% or it may be a part of the block; we optimize parts of blocks if
|
|
% a conflict prevents us from optimizing the whole block together.
|
|
|
|
:- pred value_number__optimize_fragment(list(instruction), livemap, vn_params,
|
|
list(parentry), int, vn_ctrl_tuple, list(instruction),
|
|
io__state, io__state).
|
|
:- mode value_number__optimize_fragment(in, in, in, in, in, out, out, di, uo)
|
|
is det.
|
|
|
|
value_number__optimize_fragment(Instrs0, LiveMap, Params, ParEntries, LabelNo0,
|
|
Tuple, Instrs) -->
|
|
globals__io_get_gc_method(GC),
|
|
(
|
|
{ GC = conservative },
|
|
{ opt_util__count_incr_hp(Instrs0, NumIncrs) },
|
|
{ NumIncrs >= 2 }
|
|
->
|
|
vn_debug__cost_header_msg("fragment with the error"),
|
|
vn_debug__dump_instrs(Instrs0),
|
|
{ error("instruction sequence with several incr_hps in value_number__optimize_fragment") }
|
|
;
|
|
value_number__optimize_fragment_2(Instrs0, LiveMap, Params,
|
|
ParEntries, LabelNo0, Tuple, Instrs)
|
|
).
|
|
|
|
:- pred value_number__optimize_fragment_2(list(instruction), livemap, vn_params,
|
|
list(parentry), int, vn_ctrl_tuple, list(instruction),
|
|
io__state, io__state).
|
|
:- mode value_number__optimize_fragment_2(in, in, in, in, in, out, out, di, uo)
|
|
is det.
|
|
|
|
value_number__optimize_fragment_2(Instrs0, LiveMap, Params, ParEntries,
|
|
LabelNo0, Tuple, Instrs) -->
|
|
( { Instrs0 = [Uinstr0Prime - _ | _] } ->
|
|
{ Uinstr0 = Uinstr0Prime },
|
|
vn_debug__fragment_msg(Uinstr0)
|
|
;
|
|
{ error("empty instruction sequence in value_number__optimize_fragment") }
|
|
),
|
|
{ vn_block__build_block_info(Instrs0, LiveMap, Params, ParEntries,
|
|
LabelNo0, VnTables0, Liveset0, SeenIncr0, Tuple0) },
|
|
{ Tuple0 = tuple(Ctrl, Ctrlmap, Flushmap, LabelNo, _Parmap) },
|
|
|
|
{ vn_util__build_uses(Liveset0, Ctrlmap, VnTables0, VnTables1) },
|
|
|
|
vn_order__order(Liveset0, VnTables1, SeenIncr0, Ctrl, Ctrlmap,
|
|
Flushmap, Res),
|
|
(
|
|
{ Res = success(VnTables2, Order) },
|
|
{ vn_temploc__init_templocs(Params, Liveset0, VnTables2,
|
|
Templocs0) },
|
|
vn_flush__nodelist(Order, Ctrlmap, VnTables2, Templocs0,
|
|
Params, Instrs1),
|
|
|
|
{ value_number__push_decr_sp_back(Instrs1, Instrs2) },
|
|
{ value_number__push_incr_sp_forw(Instrs2, Instrs3) },
|
|
{ value_number__push_livevals_back(Instrs3, Instrs4) },
|
|
{ vn_filter__block(Instrs4, Instrs5) },
|
|
globals__io_get_gc_method(GC_Method),
|
|
{ peephole__optimize(GC_Method, Instrs5, Instrs6, _) },
|
|
|
|
vn_debug__cost_header_msg("original code sequence"),
|
|
vn_cost__block_cost(Instrs0, Params, yes, OrigCost),
|
|
( { Instrs5 = Instrs6 } ->
|
|
[]
|
|
;
|
|
vn_debug__cost_header_msg("unfiltered code sequence"),
|
|
vn_cost__block_cost(Instrs4, Params, yes, _)
|
|
),
|
|
|
|
vn_debug__cost_header_msg("new code sequence"),
|
|
vn_cost__block_cost(Instrs6, Params, yes, VnCost),
|
|
|
|
globals__io_lookup_int_option(vn_fudge, VnFudge),
|
|
|
|
(
|
|
{ VnCost < OrigCost },
|
|
{
|
|
assoc_list__keys(Instrs0, Uinstrs0),
|
|
assoc_list__keys(Instrs6, Uinstrs6),
|
|
list__sublist(Uinstrs6, Uinstrs0)
|
|
;
|
|
VnCost * 1000 < OrigCost * VnFudge
|
|
}
|
|
->
|
|
vn_debug__cost_msg(yes, OrigCost, VnCost),
|
|
{ vn_block__build_block_info(Instrs6, LiveMap, Params,
|
|
ParEntries, LabelNo0, VnTables6, Liveset6,
|
|
SeenIncr6, Tuple6) },
|
|
vn_verify__ok(Instrs6, Uinstr0, SeenIncr0, SeenIncr6,
|
|
Liveset0, Liveset6, VnTables0, VnTables6, OK),
|
|
( { OK = yes } ->
|
|
{ Instrs = Instrs6 },
|
|
{ Tuple = Tuple6 }
|
|
;
|
|
{ Instrs = Instrs0 },
|
|
{ Tuple = Tuple0 }
|
|
)
|
|
;
|
|
vn_debug__cost_msg(no, OrigCost, VnCost),
|
|
{ Instrs = Instrs0 },
|
|
{ Tuple = Tuple0 }
|
|
),
|
|
vn_debug__tuple_msg(yes(no), Instrs, Tuple)
|
|
;
|
|
{ Res = failure(MaybeLabel) },
|
|
(
|
|
{ MaybeLabel = yes(RestartLabel) }
|
|
% ( { MaybeLabel = yes(RestartLabelPrime) } ->
|
|
% { RestartLabel = RestartLabelPrime }
|
|
% ;
|
|
% { map__init(Positions) },
|
|
% { value_number__find_restart_label(0, Positions,
|
|
% Ctrlmap, Flushmap, no, RestartLabel) }
|
|
% )
|
|
->
|
|
value_number__try_again(Instrs0, [], RestartLabel,
|
|
LiveMap, Params, LabelNo, Instrs)
|
|
;
|
|
value_number__last_ditch(Instrs0,
|
|
LiveMap, Params, LabelNo, Instrs)
|
|
),
|
|
{ vn_block__build_block_info(Instrs, LiveMap, Params,
|
|
ParEntries, LabelNo0, _, _, _, Tuple) },
|
|
vn_debug__tuple_msg(yes(yes), Instrs, Tuple)
|
|
).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- pred value_number__find_restart_label(int, flushmapentry, ctrlmap, flushmap,
|
|
maybe(label), label).
|
|
:- mode value_number__find_restart_label(in, in, in, in, in, out) is semidet.
|
|
|
|
value_number__find_restart_label(Ctrl0, Positions0, Ctrlmap, Flushmap,
|
|
PrevLabel0, RestartLabel) :-
|
|
map__search(Ctrlmap, Ctrl0, VnInstr),
|
|
map__search(Flushmap, Ctrl0, FlushmapEntry),
|
|
(
|
|
VnInstr = vn_label(Label)
|
|
->
|
|
PrevLabel1 = yes(Label)
|
|
;
|
|
PrevLabel1 = PrevLabel0
|
|
),
|
|
(
|
|
map__to_assoc_list(FlushmapEntry, NewPositions),
|
|
value_number__compatible_positions(NewPositions, Positions0,
|
|
Positions1)
|
|
->
|
|
Ctrl1 is Ctrl0 + 1,
|
|
value_number__find_restart_label(Ctrl1, Positions1,
|
|
Ctrlmap, Flushmap, PrevLabel1, RestartLabel)
|
|
;
|
|
PrevLabel1 = yes(RestartLabel)
|
|
).
|
|
|
|
:- pred value_number__compatible_positions(assoc_list(vnlval, vn),
|
|
flushmapentry, flushmapentry).
|
|
:- mode value_number__compatible_positions(in, in, out) is semidet.
|
|
|
|
value_number__compatible_positions([], Positions, Positions).
|
|
value_number__compatible_positions([Entry | Entries], Positions0, Positions) :-
|
|
Entry = Vnlval - Vn,
|
|
( map__search(Positions0, Vnlval, OldVn) ->
|
|
Vn = OldVn,
|
|
Positions1 = Positions0
|
|
;
|
|
map__det_insert(Positions0, Vnlval, Vn, Positions1)
|
|
),
|
|
value_number__compatible_positions(Entries, Positions1, Positions).
|
|
|
|
:- pred value_number__try_again(list(instruction), list(instruction), label,
|
|
livemap, vn_params, int, list(instruction), io__state, io__state).
|
|
:- mode value_number__try_again(in, in, in, in, in, in, out, di, uo) is det.
|
|
|
|
value_number__try_again([], RevInstrs, _Label, LiveMap, Params, LabelNo0,
|
|
Instrs) -->
|
|
{ list__reverse(RevInstrs, Instrs0) },
|
|
value_number__last_ditch(Instrs0, LiveMap, Params, LabelNo0, Instrs).
|
|
value_number__try_again([Instr0 | Instrs0], RevInstrs0, RestartLabel, LiveMap,
|
|
Params, LabelNo0, Instrs) -->
|
|
( { Instr0 = label(RestartLabel) - _ } ->
|
|
( { RevInstrs0 = [] } ->
|
|
value_number__last_ditch(Instrs0, LiveMap, Params,
|
|
LabelNo0, Instrs1),
|
|
{ Instrs = [Instr0 | Instrs1] }
|
|
;
|
|
vn_debug__divide_msg(Instr0),
|
|
%
|
|
% we need to append a `goto' instruction at the
|
|
% end of the fragment so that optimize_fragment
|
|
% can know what is live at the end.
|
|
%
|
|
{ GotoInstr = goto(label(RestartLabel)) - "" },
|
|
{ list__reverse([GotoInstr | RevInstrs0],
|
|
FrontInstrs0) },
|
|
value_number__optimize_fragment(FrontInstrs0, LiveMap,
|
|
Params, [], LabelNo0, _, FrontInstrs1),
|
|
value_number__optimize_fragment(Instrs0, LiveMap,
|
|
Params, [], LabelNo0, _, BackInstrs),
|
|
%
|
|
% we need to get rid of the introduced goto,
|
|
% which should still be at the end of FrontInstrs1,
|
|
% otherwise we would violate the invariant that
|
|
% labels in the middle of a block are not targets
|
|
% of branches.
|
|
%
|
|
{ list__reverse(FrontInstrs1, RevInstrs1) },
|
|
{ RevInstrs1 = [GotoInstr | RevInstrs2] ->
|
|
list__reverse(RevInstrs2, FrontInstrs)
|
|
;
|
|
error("value_number__try_again: lost goto")
|
|
},
|
|
{ list__append(FrontInstrs, [Instr0 | BackInstrs],
|
|
Instrs) }
|
|
)
|
|
;
|
|
{ RevInstrs1 = [Instr0 | RevInstrs0] },
|
|
value_number__try_again(Instrs0, RevInstrs1, RestartLabel,
|
|
LiveMap, Params, LabelNo0, Instrs)
|
|
).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- pred value_number__last_ditch(list(instruction), livemap, vn_params, int,
|
|
list(instruction), io__state, io__state).
|
|
:- mode value_number__last_ditch(in, in, in, in, out, di, uo) is det.
|
|
|
|
value_number__last_ditch([], _, _, _, []) --> [].
|
|
value_number__last_ditch([Instr0 | Instrs0], LiveMap, Params, LabelNo0,
|
|
Instrs) -->
|
|
(
|
|
{ Instr0 = Uinstr0 - _ },
|
|
{
|
|
Uinstr0 = if_val(_, _)
|
|
;
|
|
Uinstr0 = restore_hp(_)
|
|
;
|
|
Uinstr0 = mark_hp(_)
|
|
}
|
|
->
|
|
vn_debug__restart_msg(Instr0),
|
|
value_number__optimize_fragment(Instrs0, LiveMap, Params,
|
|
[], LabelNo0, _, Instrs1),
|
|
{ Instrs = [Instr0 | Instrs1] }
|
|
;
|
|
value_number__last_ditch(Instrs0, LiveMap, Params,
|
|
LabelNo0, Instrs1),
|
|
{ Instrs = [Instr0 | Instrs1] }
|
|
).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- pred value_number__process_parallel_tuples(list(maybe(vn_ctrl_tuple)),
|
|
list(list(instruction)), livemap, vn_params, list(list(instruction)),
|
|
io__state, io__state).
|
|
:- mode value_number__process_parallel_tuples(in, in, in, in, out, di, uo)
|
|
is det.
|
|
|
|
value_number__process_parallel_tuples(Tuples0, Blocks0, LiveMap, Params,
|
|
Blocks) -->
|
|
{ list__length(Tuples0, TupleLength) },
|
|
{ list__length(Blocks0, BlockLength) },
|
|
( { TupleLength = BlockLength } ->
|
|
value_number__process_parallel_tuples_2(Blocks0, Tuples0,
|
|
LiveMap, Params, Blocks0, Blocks1, Extras),
|
|
{ value_number__insert_new_blocks(Extras, Blocks1, Blocks) }
|
|
;
|
|
{ error("number of tuples and blocks differ") }
|
|
).
|
|
|
|
:- pred value_number__insert_new_blocks(assoc_list(label, list(instruction)),
|
|
list(list(instruction)), list(list(instruction))).
|
|
:- mode value_number__insert_new_blocks(in, in, out) is det.
|
|
|
|
value_number__insert_new_blocks([], Blocks, Blocks).
|
|
value_number__insert_new_blocks([Label - Extra | Extras], Blocks0, Blocks) :-
|
|
value_number__find_block_by_label(Blocks0, Label, Before, LabelBlock,
|
|
After),
|
|
list__condense([Before, [Extra, LabelBlock], After], Blocks1),
|
|
value_number__insert_new_blocks(Extras, Blocks1, Blocks).
|
|
|
|
:- pred value_number__process_parallel_tuples_2(list(list(instruction)),
|
|
list(maybe(vn_ctrl_tuple)), livemap, vn_params,
|
|
list(list(instruction)), list(list(instruction)),
|
|
assoc_list(label, list(instruction)), io__state, io__state).
|
|
:- mode value_number__process_parallel_tuples_2(in, in, in, in, in, out, out,
|
|
di, uo) is det.
|
|
|
|
value_number__process_parallel_tuples_2([], _, _, _, _, [], []) --> [].
|
|
value_number__process_parallel_tuples_2([Block0 | Blocks0], MaybeTuples0,
|
|
LiveMap, Params, AllBlocks, [Block | Blocks], Extras) -->
|
|
{ MaybeTuples0 = [MaybeTuple0Prime | MaybeTuples1Prime] ->
|
|
MaybeTuple0 = MaybeTuple0Prime,
|
|
MaybeTuples1 = MaybeTuples1Prime
|
|
;
|
|
error("tuples and blocks not in sync")
|
|
},
|
|
(
|
|
{ MaybeTuple0 = yes(Tuple) },
|
|
value_number__process_parallel_tuple(Block0, Tuple,
|
|
LiveMap, Params, AllBlocks, Block, Extras1)
|
|
;
|
|
{ MaybeTuple0 = no },
|
|
{ Block = Block0 },
|
|
{ Extras1 = [] }
|
|
),
|
|
value_number__process_parallel_tuples_2(Blocks0, MaybeTuples1,
|
|
LiveMap, Params, AllBlocks, Blocks, Extras2),
|
|
{ list__append(Extras1, Extras2, Extras) }.
|
|
|
|
:- pred value_number__process_parallel_tuple(list(instruction), vn_ctrl_tuple,
|
|
livemap, vn_params, list(list(instruction)), list(instruction),
|
|
assoc_list(label, list(instruction)), io__state, io__state).
|
|
:- mode value_number__process_parallel_tuple(in, in, in, in, in, out, out,
|
|
di, uo) is det.
|
|
|
|
value_number__process_parallel_tuple(Block0, tuple(_, _, _, _, Parmap),
|
|
LiveMap, Params, AllBlocks, Block, Extras) -->
|
|
{ map__values(Parmap, ParList) },
|
|
( { value_number__all_empty_lists(ParList) } ->
|
|
{ Block = Block0 },
|
|
{ Extras = [] }
|
|
;
|
|
value_number__process_parallel_nodes(ParList, LiveMap, Params,
|
|
Block0, AllBlocks, Block, Extras)
|
|
).
|
|
|
|
:- pred value_number__all_empty_lists(list(list(T))).
|
|
:- mode value_number__all_empty_lists(in) is semidet.
|
|
|
|
value_number__all_empty_lists([]).
|
|
value_number__all_empty_lists([[] | Lists]) :-
|
|
value_number__all_empty_lists(Lists).
|
|
|
|
:- pred value_number__process_parallel_nodes(list(list(parallel)), livemap,
|
|
vn_params, list(instruction), list(list(instruction)),
|
|
list(instruction), assoc_list(label, list(instruction)),
|
|
io__state, io__state).
|
|
:- mode value_number__process_parallel_nodes(in, in, in, in, in, out, out,
|
|
di, uo) is det.
|
|
|
|
value_number__process_parallel_nodes([], _, _, Block, _, Block, []) --> [].
|
|
value_number__process_parallel_nodes([Par0 | Pars1], LiveMap, Params,
|
|
Block0, AllBlocks, Block, Extras) -->
|
|
{ vn_block__split_at_next_ctrl_instr(Block0, Start, NodeInstr,
|
|
Block1) },
|
|
value_number__process_parallels(Par0, LiveMap, Params,
|
|
NodeInstr, NewNodeInstr, AllBlocks, Extras1),
|
|
value_number__process_parallel_nodes(Pars1, LiveMap, Params,
|
|
Block1, AllBlocks, Block2, Extras2),
|
|
{ list__condense([Start, [NewNodeInstr], Block2], Block) },
|
|
{ list__append(Extras1, Extras2, Extras) }.
|
|
|
|
:- pred value_number__process_parallels(list(parallel), livemap, vn_params,
|
|
instruction, instruction, list(list(instruction)),
|
|
assoc_list(label, list(instruction)), io__state, io__state).
|
|
:- mode value_number__process_parallels(in, in, in, in, out, in, out, di, uo)
|
|
is det.
|
|
|
|
value_number__process_parallels(Pars, LiveMap, Params, Instr0, Instr,
|
|
AllBlocks, Extras) -->
|
|
{ Instr0 = Uinstr0 - Comment },
|
|
( { Pars = [] } ->
|
|
{ Instr = Instr0 },
|
|
{ Extras = []}
|
|
; { Uinstr0 = if_val(Rval, label(Label)) } ->
|
|
( { Pars = [Par] } ->
|
|
( { Par = parallel(Label, _NewLabel, _ParEntries) } ->
|
|
value_number__process_parallel(Par, LiveMap,
|
|
Params, AllBlocks, FinalLabel, Extras),
|
|
{ Instr = if_val(Rval, label(FinalLabel))
|
|
- Comment }
|
|
;
|
|
{ error("wrong label in parallel for if_val") }
|
|
)
|
|
;
|
|
{ error("more than one parallel for if_val") }
|
|
)
|
|
; { Uinstr0 = goto(label(Label)) } ->
|
|
( { Pars = [Par] } ->
|
|
( { Par = parallel(Label, _NewLabel, _ParEntries) } ->
|
|
value_number__process_parallel(Par, LiveMap,
|
|
Params, AllBlocks, FinalLabel, Extras),
|
|
{ Instr = goto(label(FinalLabel)) - Comment }
|
|
;
|
|
{ error("wrong label in parallel for goto") }
|
|
)
|
|
;
|
|
{ error("more than one parallel for goto") }
|
|
)
|
|
; { Uinstr0 = computed_goto(Rval, Labels) } ->
|
|
{ value_number__pair_labels_pars(Labels, Pars, LabelPars) },
|
|
vn_debug__computed_goto_msg(Labels, Pars, LabelPars),
|
|
value_number__process_parallel_list(LabelPars, LiveMap,
|
|
Params, AllBlocks, FinalLabels, Extras),
|
|
{ Instr = computed_goto(Rval, FinalLabels) - Comment }
|
|
;
|
|
{ Instr = Instr0 },
|
|
{ Extras = [] }
|
|
).
|
|
|
|
:- pred value_number__pair_labels_pars(list(label), list(parallel),
|
|
assoc_list(label, maybe(parallel))).
|
|
:- mode value_number__pair_labels_pars(in, in, out) is det.
|
|
|
|
value_number__pair_labels_pars([], Pars, []) :-
|
|
( Pars = [] ->
|
|
true
|
|
;
|
|
error("parallel without corresponding label")
|
|
).
|
|
value_number__pair_labels_pars([Label | Labels0], Pars0,
|
|
[Label - MaybePar | LabelPars]) :-
|
|
( value_number__find_parallel_for_label(Pars0, Label, Par, Pars1) ->
|
|
MaybePar = yes(Par),
|
|
Pars2 = Pars1
|
|
;
|
|
MaybePar = no,
|
|
Pars2 = Pars0
|
|
),
|
|
value_number__pair_labels_pars(Labels0, Pars2, LabelPars).
|
|
|
|
:- pred value_number__find_parallel_for_label(list(parallel), label, parallel,
|
|
list(parallel)).
|
|
:- mode value_number__find_parallel_for_label(in, in, out, out) is semidet.
|
|
|
|
value_number__find_parallel_for_label([Par0 | Pars0], Label, Par, Rest) :-
|
|
( Par0 = parallel(Label, _, _) ->
|
|
Par = Par0,
|
|
Rest = Pars0
|
|
;
|
|
value_number__find_parallel_for_label(Pars0, Label, Par, Rest1),
|
|
Rest = [Par0 | Rest1]
|
|
).
|
|
|
|
:- pred value_number__process_parallel_list(assoc_list(label, maybe(parallel)),
|
|
livemap, vn_params, list(list(instruction)), list(label),
|
|
assoc_list(label, list(instruction)), io__state, io__state).
|
|
:- mode value_number__process_parallel_list(in, in, in, in, out, out, di, uo)
|
|
is det.
|
|
|
|
value_number__process_parallel_list([], _, _, _, [], []) --> [].
|
|
value_number__process_parallel_list([OldLabel - MaybePar | LabelPars],
|
|
LiveMap, Params, AllBlocks, [Label | Labels], Extras) -->
|
|
( { MaybePar = yes(Par) } ->
|
|
( { Par = parallel(OldLabel, _, _) } ->
|
|
[]
|
|
;
|
|
{ error("wrong label in parallel for computed_goto") }
|
|
),
|
|
value_number__process_parallel(Par, LiveMap, Params,
|
|
AllBlocks, Label, Extras1),
|
|
value_number__process_parallel_list(LabelPars, LiveMap, Params,
|
|
AllBlocks, Labels, Extras2),
|
|
{ list__append(Extras1, Extras2, Extras) }
|
|
;
|
|
{ Label = OldLabel },
|
|
value_number__process_parallel_list(LabelPars, LiveMap, Params,
|
|
AllBlocks, Labels, Extras)
|
|
).
|
|
|
|
:- pred value_number__process_parallel(parallel, livemap, vn_params,
|
|
list(list(instruction)), label, assoc_list(label, list(instruction)),
|
|
io__state, io__state).
|
|
:- mode value_number__process_parallel(in, in, in, in, out, out, di, uo) is det.
|
|
|
|
value_number__process_parallel(Par, LiveMap, Params, AllBlocks, FinalLabel,
|
|
Extras) -->
|
|
vn_debug__parallel_msg(Par),
|
|
{ Par = parallel(OldLabel, NewLabel, ParEntries) },
|
|
{ value_number__find_block_by_label(AllBlocks, OldLabel, _, Block, _) },
|
|
value_number__optimize_block(Block, LiveMap, Params, ParEntries,
|
|
2000, _, NewBlock0, [], _),
|
|
vn_cost__block_cost(Block, Params, no, OrigCost),
|
|
vn_cost__block_cost(NewBlock0, Params, no, ParCost),
|
|
{
|
|
ParCost < OrigCost
|
|
->
|
|
FinalLabel = NewLabel,
|
|
( NewBlock0 = [label(OldLabel) - Comment | Rest0] ->
|
|
opt_util__filter_out_labels(Rest0, Rest),
|
|
NewBlock = [label(NewLabel) - Comment | Rest],
|
|
Extras = [OldLabel - NewBlock]
|
|
;
|
|
error("block starts with wrong label")
|
|
)
|
|
;
|
|
FinalLabel = OldLabel,
|
|
Extras = []
|
|
}.
|
|
|
|
% Given a list of blocks and a label, return the blocks before the
|
|
% labelled block, the labelled block itself, and the following blocks.
|
|
|
|
:- pred value_number__find_block_by_label(list(list(instruction)), label,
|
|
list(list(instruction)), list(instruction), list(list(instruction))).
|
|
% :- mode value_number__find_block_by_label(di, in, uo, uo, uo) is det.
|
|
:- mode value_number__find_block_by_label(in, in, out, out, out) is det.
|
|
|
|
value_number__find_block_by_label([], Label, _, _, _) :-
|
|
opt_debug__dump_label(Label, L_str),
|
|
string__append("Cannot find block with label ", L_str, Str),
|
|
error(Str).
|
|
value_number__find_block_by_label([Block | Blocks], Label, Before, LabelBlock,
|
|
After) :-
|
|
( Block = [FirstInstr | _] ->
|
|
( FirstInstr = label(Label) - _ ->
|
|
Before = [],
|
|
LabelBlock = Block,
|
|
After = Blocks
|
|
;
|
|
value_number__find_block_by_label(Blocks, Label,
|
|
Before0, LabelBlock, After),
|
|
Before = [Block | Before0]
|
|
)
|
|
;
|
|
error("found empty block")
|
|
).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- pred value_number__push_decr_sp_back(list(instruction), list(instruction)).
|
|
% :- mode value_number__push_decr_sp_back(di, uo) is det.
|
|
:- mode value_number__push_decr_sp_back(in, out) is det.
|
|
|
|
value_number__push_decr_sp_back([], []).
|
|
value_number__push_decr_sp_back([Instr0 | Instrs0], Instrs) :-
|
|
( Instr0 = decr_sp(N) - _ ->
|
|
value_number__push_decr_sp_back_2(Instrs0, N, Instrs)
|
|
;
|
|
value_number__push_decr_sp_back(Instrs0, Instrs1),
|
|
Instrs = [Instr0 | Instrs1]
|
|
).
|
|
|
|
:- pred value_number__push_decr_sp_back_2(list(instruction), int,
|
|
list(instruction)).
|
|
% :- mode value_number__push_decr_sp_back_2(di, in, uo) is det.
|
|
:- mode value_number__push_decr_sp_back_2(in, in, out) is det.
|
|
|
|
value_number__push_decr_sp_back_2([], N, [decr_sp(N) - ""]).
|
|
value_number__push_decr_sp_back_2([Instr0 | Instrs0], N, Instrs) :-
|
|
Instr0 = Uinstr0 - _,
|
|
value_number__boundary_instr(Uinstr0, Boundary),
|
|
(
|
|
Boundary = yes,
|
|
Instrs = [decr_sp(N) - "", Instr0 | Instrs0],
|
|
opt_util__block_refers_stackvars([Instr0 | Instrs], Ref),
|
|
(
|
|
Ref = yes,
|
|
error("cannot push decr_sp back enough")
|
|
;
|
|
Ref = no
|
|
)
|
|
;
|
|
Boundary = no,
|
|
value_number__push_decr_sp_back_2(Instrs0, N, Instrs1),
|
|
Instrs = [Instr0 | Instrs1]
|
|
).
|
|
|
|
:- pred value_number__push_incr_sp_forw(list(instruction), list(instruction)).
|
|
% :- mode value_number__push_incr_sp_forw(di, uo) is det.
|
|
:- mode value_number__push_incr_sp_forw(in, out) is det.
|
|
|
|
value_number__push_incr_sp_forw(Instrs0, Instrs) :-
|
|
list__reverse(Instrs0, Instrs1),
|
|
value_number__push_incr_sp_forw_rev(Instrs1, MaybeFrameSize, Instrs2),
|
|
(
|
|
MaybeFrameSize = yes(N),
|
|
value_number__push_save_succip_forw_rev(Instrs2, N, Instrs3)
|
|
;
|
|
MaybeFrameSize = no,
|
|
Instrs3 = Instrs2
|
|
),
|
|
list__reverse(Instrs3, Instrs).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- pred value_number__push_incr_sp_forw_rev(list(instruction), maybe(int),
|
|
list(instruction)).
|
|
% :- mode value_number__push_incr_sp_forw_rev(di, out, uo) is det.
|
|
:- mode value_number__push_incr_sp_forw_rev(in, out, out) is det.
|
|
|
|
value_number__push_incr_sp_forw_rev([], no, []).
|
|
value_number__push_incr_sp_forw_rev([Instr0 | Instrs0], MaybeFrameSize,
|
|
Instrs) :-
|
|
( Instr0 = incr_sp(N, Msg) - _ ->
|
|
value_number__push_incr_sp_forw_rev_2(Instrs0, N, Msg, Instrs),
|
|
MaybeFrameSize = yes(N)
|
|
;
|
|
value_number__push_incr_sp_forw_rev(Instrs0, MaybeFrameSize,
|
|
Instrs1),
|
|
Instrs = [Instr0 | Instrs1]
|
|
).
|
|
|
|
:- pred value_number__push_incr_sp_forw_rev_2(list(instruction), int, string,
|
|
list(instruction)).
|
|
:- mode value_number__push_incr_sp_forw_rev_2(in, in, in, out) is det.
|
|
|
|
value_number__push_incr_sp_forw_rev_2([], N, Msg, [incr_sp(N, Msg) - ""]).
|
|
value_number__push_incr_sp_forw_rev_2([Instr0 | Instrs0], N, Msg, Instrs) :-
|
|
Instr0 = Uinstr0 - _,
|
|
value_number__boundary_instr(Uinstr0, Boundary),
|
|
(
|
|
Boundary = yes,
|
|
Instrs = [incr_sp(N, Msg) - "", Instr0 | Instrs0],
|
|
opt_util__block_refers_stackvars([Instr0 | Instrs], Ref),
|
|
(
|
|
Ref = yes,
|
|
error("cannot push incr_sp forward enough")
|
|
;
|
|
Ref = no
|
|
)
|
|
;
|
|
Boundary = no,
|
|
value_number__push_incr_sp_forw_rev_2(Instrs0, N, Msg, Instrs1),
|
|
Instrs = [Instr0 | Instrs1]
|
|
).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- pred value_number__push_save_succip_forw_rev(list(instruction), int,
|
|
list(instruction)).
|
|
% :- mode value_number__push_save_succip_forw_rev(di, in, uo) is det.
|
|
:- mode value_number__push_save_succip_forw_rev(in, in, out) is det.
|
|
|
|
value_number__push_save_succip_forw_rev([], _, []).
|
|
value_number__push_save_succip_forw_rev([Instr0 | Instrs0], FrameSize,
|
|
Instrs) :-
|
|
( Instr0 = assign(stackvar(FrameSize), lval(succip)) - _ ->
|
|
value_number__push_save_succip_forw_rev_2(Instrs0, FrameSize,
|
|
Instrs)
|
|
;
|
|
value_number__push_save_succip_forw_rev(Instrs0, FrameSize,
|
|
Instrs1),
|
|
Instrs = [Instr0 | Instrs1]
|
|
).
|
|
|
|
:- pred value_number__push_save_succip_forw_rev_2(list(instruction), int,
|
|
list(instruction)).
|
|
% :- mode value_number__push_save_succip_forw_rev_2(di, in, uo) is det.
|
|
:- mode value_number__push_save_succip_forw_rev_2(in, in, out) is det.
|
|
|
|
value_number__push_save_succip_forw_rev_2([], _FrameSize, _) :-
|
|
error("succip save without incr_sp").
|
|
value_number__push_save_succip_forw_rev_2([Instr0 | Instrs0], FrameSize,
|
|
Instrs) :-
|
|
Instr0 = Uinstr0 - _,
|
|
( Uinstr0 = incr_sp(FrameSize, _) ->
|
|
Instrs = [assign(stackvar(FrameSize), lval(succip)) - "",
|
|
Instr0 | Instrs0]
|
|
;
|
|
value_number__push_save_succip_forw_rev_2(Instrs0, FrameSize,
|
|
Instrs1),
|
|
Instrs = [Instr0 | Instrs1]
|
|
).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- pred value_number__push_livevals_back(list(instruction), list(instruction)).
|
|
% :- mode value_number__push_livevals_back(di, uo) is det.
|
|
:- mode value_number__push_livevals_back(in, out) is det.
|
|
|
|
value_number__push_livevals_back([], []).
|
|
value_number__push_livevals_back([Instr0 | Instrs0], Instrs) :-
|
|
( Instr0 = livevals(Livevals) - _ ->
|
|
value_number__push_livevals_back_2(Instrs0, Livevals, Instrs)
|
|
;
|
|
value_number__push_livevals_back(Instrs0, Instrs1),
|
|
Instrs = [Instr0 | Instrs1]
|
|
).
|
|
|
|
:- pred value_number__push_livevals_back_2(list(instruction), lvalset,
|
|
list(instruction)).
|
|
% :- mode value_number__push_livevals_back_2(di, in, uo) is det.
|
|
:- mode value_number__push_livevals_back_2(in, in, out) is det.
|
|
|
|
value_number__push_livevals_back_2([], Livevals, [livevals(Livevals) - ""]).
|
|
value_number__push_livevals_back_2([Instr0 | Instrs0], Livevals, Instrs) :-
|
|
Instr0 = Uinstr0 - _,
|
|
value_number__boundary_instr(Uinstr0, Boundary),
|
|
opt_util__can_instr_branch_away(Uinstr0, CanBranch),
|
|
( Boundary = yes, CanBranch = yes ->
|
|
value_number__push_livevals_back([Instr0 | Instrs0], Instrs1),
|
|
Instrs = [livevals(Livevals) - "" | Instrs1]
|
|
;
|
|
value_number__push_livevals_back_2(Instrs0, Livevals, Instrs1),
|
|
Instrs = [Instr0 | Instrs1]
|
|
).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% Return true if we must treat this instruction as a boundary
|
|
% instruction, i.e. an instruction across which it is neither safe
|
|
% nor necessary to push stack frame setup or teardown instructions
|
|
% (incr_sp, livevals and decr_sp).
|
|
|
|
:- pred value_number__boundary_instr(instr, bool).
|
|
:- mode value_number__boundary_instr(in, out) is det.
|
|
|
|
value_number__boundary_instr(comment(_), no).
|
|
value_number__boundary_instr(livevals(_), no).
|
|
value_number__boundary_instr(block(_, _, _), no).
|
|
value_number__boundary_instr(assign(Lval,_), Boundary) :-
|
|
( Lval = redoip(_) ->
|
|
Boundary = yes
|
|
;
|
|
Boundary = no
|
|
).
|
|
value_number__boundary_instr(call(_, _, _, _), yes).
|
|
value_number__boundary_instr(mkframe(_, _), yes).
|
|
value_number__boundary_instr(label(_), yes).
|
|
value_number__boundary_instr(goto(_), yes).
|
|
value_number__boundary_instr(computed_goto(_, _), yes).
|
|
value_number__boundary_instr(c_code(_), yes).
|
|
value_number__boundary_instr(if_val(_, _), yes).
|
|
value_number__boundary_instr(incr_hp(_, _, _, _), no).
|
|
value_number__boundary_instr(mark_hp(_), no).
|
|
value_number__boundary_instr(restore_hp(_), no).
|
|
value_number__boundary_instr(store_ticket(_), no).
|
|
value_number__boundary_instr(reset_ticket(_, _), no).
|
|
value_number__boundary_instr(discard_ticket, no).
|
|
value_number__boundary_instr(mark_ticket_stack(_), no).
|
|
value_number__boundary_instr(discard_tickets_to(_), no).
|
|
value_number__boundary_instr(incr_sp(_, _), yes).
|
|
value_number__boundary_instr(decr_sp(_), yes).
|
|
value_number__boundary_instr(init_sync_term(_, _), no).
|
|
value_number__boundary_instr(fork(_, _, _), yes).
|
|
value_number__boundary_instr(join_and_terminate(_), yes).
|
|
value_number__boundary_instr(join_and_continue(_, _), yes).
|
|
value_number__boundary_instr(pragma_c(_, _, _, _, _), yes).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- pred value_number__has_no_backward_branches(list(instruction)).
|
|
:- mode value_number__has_no_backward_branches(in) is semidet.
|
|
|
|
value_number__has_no_backward_branches(Instrs) :-
|
|
set__init(Labels),
|
|
value_number__has_no_backward_branches_2(Instrs, Labels).
|
|
|
|
:- pred value_number__has_no_backward_branches_2(list(instruction), set(label)).
|
|
:- mode value_number__has_no_backward_branches_2(in, in) is semidet.
|
|
|
|
value_number__has_no_backward_branches_2([], _).
|
|
value_number__has_no_backward_branches_2([Instr - _ | Instrs], SoFar0) :-
|
|
(
|
|
Instr = label(Label)
|
|
->
|
|
set__insert(SoFar0, Label, SoFar)
|
|
;
|
|
opt_util__instr_labels(Instr, LabelRefs, _),
|
|
value_number__no_old_labels(LabelRefs, SoFar0),
|
|
SoFar = SoFar0
|
|
),
|
|
value_number__has_no_backward_branches_2(Instrs, SoFar).
|
|
|
|
:- pred value_number__no_old_labels(list(label), set(label)).
|
|
:- mode value_number__no_old_labels(in, in) is semidet.
|
|
|
|
value_number__no_old_labels([], _SoFar).
|
|
value_number__no_old_labels([Label | Labels], SoFar) :-
|
|
\+ set__member(Label, SoFar),
|
|
value_number__no_old_labels(Labels, SoFar).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
value_number__post_main(Instrs0, Instrs) :-
|
|
value_number__post_main_2(Instrs0, 0, 0, [], Instrs).
|
|
|
|
% R is the number of the highest numbered tempr variable seen so far;
|
|
% R = 0 means we haven't seen any temp variables. Similarly, F is the
|
|
% highest numbered tempf variable seen so far. RevSofar is a
|
|
% reversed list of instructions starting with the first instruction
|
|
% in this block that accesses a temp variable. Invariant: RevSofar
|
|
% is always empty if R = 0 and F = 0.
|
|
|
|
:- pred value_number__post_main_2(list(instruction), int, int,
|
|
list(instruction), list(instruction)).
|
|
:- mode value_number__post_main_2(in, in, in, in, out) is det.
|
|
|
|
value_number__post_main_2([], R, F, RevSofar, []) :-
|
|
( RevSofar = [_|_] ->
|
|
error("procedure ends with fallthrough")
|
|
; ( R > 0 ; F > 0 ) ->
|
|
error("procedure ends without closing block")
|
|
;
|
|
true
|
|
).
|
|
value_number__post_main_2([Instr0 | Instrs0], R0, F0, RevSofar, Instrs) :-
|
|
Instr0 = Uinstr0 - _Comment0,
|
|
opt_util__count_temps_instr(Uinstr0, R0, R1, F0, F1),
|
|
( ( R1 > 0 ; F1 > 0) ->
|
|
( opt_util__can_instr_fall_through(Uinstr0, no) ->
|
|
list__reverse([Instr0 | RevSofar], BlockInstrs),
|
|
value_number__post_main_2(Instrs0, 0, 0, [], Instrs1),
|
|
Instrs = [block(R1, F1, BlockInstrs) - "" | Instrs1]
|
|
; Uinstr0 = label(_) ->
|
|
list__reverse(RevSofar, BlockInstrs),
|
|
value_number__post_main_2(Instrs0, 0, 0, [], Instrs1),
|
|
Instrs = [block(R1, F1, BlockInstrs) - "", Instr0
|
|
| Instrs1]
|
|
;
|
|
value_number__post_main_2(Instrs0, R1, F1,
|
|
[Instr0 | RevSofar], Instrs)
|
|
)
|
|
;
|
|
value_number__post_main_2(Instrs0, 0, 0, [], Instrs1),
|
|
Instrs = [Instr0 | Instrs1]
|
|
).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%-----------------------------------------------------------------------------%
|