mirror of
https://github.com/Mercury-Language/mercury.git
synced 2026-04-29 16:24:43 +00:00
Estimated hours taken: 30+
arg_info:
Fix allocation to work properly for --args compact.
bytecode*:
Handle complex deconstruction unifications. Not really tested because
I can't find a test case.
bytecode_gen, call_gen, code_util:
Use the new method to handle builtin predicates/functions. We now
handle reverse mode arithmetic and unary plus/minus as builtins.
code_gen, code_init, follow_vars, hlds_pred:
Put back the initial follow_vars field of the proc_info, since this
may allow the code generator to emit better code at the starts of
of predicates.
inlining:
Don't inline recursive predicates.
goals_util:
Add a predicate to find out if a goal calls a particular predicate.
Used in inlining to find out if a predicate is recursive.
unused_args:
Remove code that used to set the mode of unused args to free->free.
Since this changes the arg from top_in to top_unused *without* code
in other modules being aware of the change, this screws up --args
compact.
llds, llds_out, garbage_out:
Prepare for the move to the new type_info structure by adding a new
"module" type for defining structures holding type_infos. Not
currently generated or output.
llds, opt_debug, opt_util, vn_type, vn_cost, vn_temploc:
Change the argument of temp to be a reg, not an int, allowing
floating point temporaries.
vn_type:
Add information about the number of floating point registers and
temporaries to the parameter structure (these are currently unused).
llds, dupelim, frameopt, livemap, middle_rec, value_number, vn_filter,
vn_verify:
Add an extra field to blocks giving the number of float temporaries.
options:
Add parameters to configure the number of floating point registers
and temporaries.
mercury_compile:
Add an extra excess assign phase at the start of the middle pass.
This should reduce the size of the code manipulated by the other
phases, and gives more accurate size information to inlining.
(The excess assign phase before code generation is I think still
needed since optimizations can introduce such assignments.)
value_number:
Optimize code sequences before and after assignments to curfr
separately, since such assignments change the meaning of framevars.
This fixes the bug that caused singleton variable warnings to contain
garbage.
vn_block, vn_flush, vn_order, vn_util:
Add special handling of assignments to curfr. This is probably
unnecessary after my change to value_number, and will be removed
again shortly :-(
vn_flush:
Improve the code generated by value numbering (1) by computing values
into the place that needs them in some special circumstances, and
(2) by fixing a bug that did not consider special registers to be
as fast as r1 etc.
vn_util:
Improve the code generated by value numbering by removing duplicates
from the list of uses of a value before trying to find out if there
is more than one use.
simplify:
Avoid overzealous optimization of main --> { ..., error(...) }.
handle_options:
Fix an error message.
code_aux:
Break an excessive long line.
426 lines
13 KiB
Mathematica
426 lines
13 KiB
Mathematica
%-----------------------------------------------------------------------------%
|
|
% Copyright (C) 1995 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.
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% livemap.nl - module to build up a map that gives
|
|
% the set of live lvals at each label.
|
|
|
|
% Author: zs.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- module livemap.
|
|
|
|
:- interface.
|
|
|
|
:- import_module bool, list, set, map, std_util.
|
|
:- import_module llds.
|
|
|
|
:- type livemap == map(label, lvalset).
|
|
:- type lvalset == set(lval).
|
|
|
|
% Build up a map of what lvals are live at each label.
|
|
% This step must be iterated in the presence of backward
|
|
% branches, which at the moment are generated by middle
|
|
% recursion and the construction of closures.
|
|
|
|
:- pred livemap__build(list(instruction), bool, livemap).
|
|
:- mode livemap__build(in, out, out) is det.
|
|
|
|
:- implementation.
|
|
|
|
:- import_module opt_util, require, string.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
livemap__build(Instrs, Ccode, Livemap) :-
|
|
map__init(Livemap0),
|
|
list__reverse(Instrs, BackInstrs),
|
|
livemap__build_2(BackInstrs, Livemap0, Ccode, Livemap).
|
|
|
|
:- pred livemap__build_2(list(instruction), livemap, bool, livemap).
|
|
% :- mode livemap__build_2(in, di, out, uo) is det.
|
|
:- mode livemap__build_2(in, in, out, out) is det.
|
|
|
|
livemap__build_2(Backinstrs, Livemap0, Ccode, Livemap) :-
|
|
set__init(Livevals0),
|
|
livemap__build_livemap(Backinstrs, Livevals0, no, Ccode1,
|
|
Livemap0, Livemap1),
|
|
( Ccode1 = yes ->
|
|
Ccode = yes,
|
|
Livemap = Livemap1
|
|
; livemap__equal_livemaps(Livemap0, Livemap1) ->
|
|
Ccode = no,
|
|
Livemap = Livemap1
|
|
;
|
|
livemap__build_2(Backinstrs, Livemap1, Ccode, Livemap)
|
|
).
|
|
|
|
:- pred livemap__equal_livemaps(livemap, livemap).
|
|
:- mode livemap__equal_livemaps(in, in) is semidet.
|
|
|
|
livemap__equal_livemaps(Livemap1, Livemap2) :-
|
|
map__keys(Livemap1, Labels),
|
|
livemap__equal_livemaps_keys(Labels, Livemap1, Livemap2).
|
|
|
|
:- pred livemap__equal_livemaps_keys(list(label), livemap, livemap).
|
|
:- mode livemap__equal_livemaps_keys(in, in, in) is semidet.
|
|
|
|
livemap__equal_livemaps_keys([], _Livemap1, _Livemap2).
|
|
livemap__equal_livemaps_keys([Label | Labels], Livemap1, Livemap2) :-
|
|
map__lookup(Livemap1, Label, Liveset1),
|
|
map__lookup(Livemap2, Label, Liveset2),
|
|
set__equal(Liveset1, Liveset2),
|
|
livemap__equal_livemaps_keys(Labels, Livemap1, Livemap2).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% Build up a map of what lvals are live at each label.
|
|
% The input instruction sequence is reversed.
|
|
|
|
:- pred livemap__build_livemap(list(instruction), lvalset, bool, bool,
|
|
livemap, livemap).
|
|
% :- mode livemap__build_livemap(in, in, in, out, di, uo) is det.
|
|
:- mode livemap__build_livemap(in, in, in, out, in, out) is det.
|
|
|
|
livemap__build_livemap([], _, Ccode, Ccode, Livemap, Livemap).
|
|
livemap__build_livemap([Instr0 | Instrs0], Livevals0, Ccode0, Ccode,
|
|
Livemap0, Livemap) :-
|
|
livemap__build_livemap_instr(Instr0, Instrs0, Instrs1,
|
|
Livevals0, Livevals1, Ccode0, Ccode1, Livemap0, Livemap1),
|
|
livemap__build_livemap(Instrs1, Livevals1,
|
|
Ccode1, Ccode, Livemap1, Livemap).
|
|
|
|
:- pred livemap__build_livemap_instr(instruction, list(instruction),
|
|
list(instruction), lvalset, lvalset, bool, bool, livemap, livemap).
|
|
% :- mode livemap__build_livemap_instr(in, di, uo, di, uo, in, out, di, uo)
|
|
% is det.
|
|
:- mode livemap__build_livemap_instr(in, in, out, in, out, in, out, in, out)
|
|
is det.
|
|
|
|
livemap__build_livemap_instr(Instr0, Instrs0, Instrs,
|
|
Livevals0, Livevals, Ccode0, Ccode, Livemap0, Livemap) :-
|
|
Instr0 = Uinstr0 - _,
|
|
(
|
|
Uinstr0 = comment(_),
|
|
Livemap = Livemap0,
|
|
Livevals = Livevals0,
|
|
Instrs = Instrs0,
|
|
Ccode = Ccode0
|
|
;
|
|
Uinstr0 = livevals(_),
|
|
error("livevals found in backward scan in build_livemap")
|
|
;
|
|
Uinstr0 = block(_, _, _),
|
|
error("block found in backward scan in build_livemap")
|
|
;
|
|
Uinstr0 = assign(Lval, Rval),
|
|
|
|
% Make dead the variable assigned, but make any variables
|
|
% needed to access it live. Make the variables in the assigned
|
|
% expression live as well.
|
|
% The deletion has to be done first. If the assigned-to lval
|
|
% appears on the right hand side as well as the left, then we
|
|
% want make_live to put it back into the liveval set.
|
|
|
|
set__delete(Livevals0, Lval, Livevals1),
|
|
opt_util__lval_access_rvals(Lval, Rvals),
|
|
livemap__make_live([Rval | Rvals], Livevals1, Livevals),
|
|
Livemap = Livemap0,
|
|
Instrs = Instrs0,
|
|
Ccode = Ccode0
|
|
;
|
|
Uinstr0 = call(_, _, _, _),
|
|
livemap__look_for_livevals(Instrs0, Instrs,
|
|
Livevals0, Livevals, "call", yes, _),
|
|
Livemap = Livemap0,
|
|
Ccode = Ccode0
|
|
;
|
|
Uinstr0 = mkframe(_, _, _),
|
|
Livemap = Livemap0,
|
|
Livevals = Livevals0,
|
|
Instrs = Instrs0,
|
|
Ccode = Ccode0
|
|
;
|
|
Uinstr0 = modframe(_),
|
|
Livemap = Livemap0,
|
|
Livevals = Livevals0,
|
|
Instrs = Instrs0,
|
|
Ccode = Ccode0
|
|
;
|
|
Uinstr0 = label(Label),
|
|
map__det_insert(Livemap0, Label, Livevals0, Livemap),
|
|
Livevals = Livevals0,
|
|
Instrs = Instrs0,
|
|
Ccode = Ccode0
|
|
;
|
|
Uinstr0 = goto(CodeAddr),
|
|
opt_util__livevals_addr(CodeAddr, LivevalsNeeded),
|
|
livemap__look_for_livevals(Instrs0, Instrs,
|
|
Livevals0, Livevals1, "goto", LivevalsNeeded, Found),
|
|
( Found = yes ->
|
|
Livevals3 = Livevals1
|
|
; CodeAddr = label(Label) ->
|
|
set__init(Livevals2),
|
|
livemap__insert_label_livevals([Label],
|
|
Livemap0, Livevals2, Livevals3)
|
|
; ( CodeAddr = do_redo ; CodeAddr = do_fail ) ->
|
|
Livevals3 = Livevals1
|
|
;
|
|
error("unknown label type in build_livemap")
|
|
),
|
|
livemap__special_code_addr(CodeAddr, MaybeSpecial),
|
|
( MaybeSpecial = yes(Special) ->
|
|
set__insert(Livevals3, Special, Livevals)
|
|
;
|
|
Livevals = Livevals3
|
|
),
|
|
Livemap = Livemap0,
|
|
Ccode = Ccode0
|
|
;
|
|
Uinstr0 = computed_goto(_, Labels),
|
|
set__init(Livevals1),
|
|
livemap__insert_label_livevals(Labels, Livemap0,
|
|
Livevals1, Livevals),
|
|
Livemap = Livemap0,
|
|
Instrs = Instrs0,
|
|
Ccode = Ccode0
|
|
;
|
|
Uinstr0 = c_code(_),
|
|
Livemap = Livemap0,
|
|
Livevals = Livevals0,
|
|
Instrs = Instrs0,
|
|
Ccode = yes
|
|
;
|
|
Uinstr0 = if_val(Rval, CodeAddr),
|
|
livemap__look_for_livevals(Instrs0, Instrs,
|
|
Livevals0, Livevals1, "if_val", no, Found),
|
|
(
|
|
Found = yes,
|
|
% This if_val was put here by middle_rec.
|
|
Livevals3 = Livevals1
|
|
;
|
|
Found = no,
|
|
livemap__make_live([Rval], Livevals1, Livevals2),
|
|
( CodeAddr = label(Label) ->
|
|
livemap__insert_label_livevals([Label],
|
|
Livemap0, Livevals2, Livevals3)
|
|
;
|
|
Livevals3 = Livevals2
|
|
)
|
|
),
|
|
livemap__special_code_addr(CodeAddr, MaybeSpecial),
|
|
( MaybeSpecial = yes(Special) ->
|
|
set__insert(Livevals3, Special, Livevals)
|
|
;
|
|
Livevals = Livevals3
|
|
),
|
|
Livemap = Livemap0,
|
|
Ccode = Ccode0
|
|
;
|
|
Uinstr0 = incr_hp(Lval, _, Rval),
|
|
|
|
% Make dead the variable assigned, but make any variables
|
|
% needed to access it live. Make the variables in the size
|
|
% expression live as well.
|
|
% The use of the size expression occurs after the assignment
|
|
% to lval, but the two should never have any variables in
|
|
% common. This is why doing the deletion first works.
|
|
|
|
set__delete(Livevals0, Lval, Livevals1),
|
|
opt_util__lval_access_rvals(Lval, Rvals),
|
|
livemap__make_live([Rval | Rvals], Livevals1, Livevals),
|
|
Livemap = Livemap0,
|
|
Instrs = Instrs0,
|
|
Ccode = Ccode0
|
|
;
|
|
Uinstr0 = mark_hp(Lval),
|
|
opt_util__lval_access_rvals(Lval, Rvals),
|
|
livemap__make_live(Rvals, Livevals0, Livevals),
|
|
Livemap = Livemap0,
|
|
Instrs = Instrs0,
|
|
Ccode = Ccode0
|
|
;
|
|
Uinstr0 = restore_hp(Rval),
|
|
livemap__make_live([Rval], Livevals0, Livevals),
|
|
Livemap = Livemap0,
|
|
Instrs = Instrs0,
|
|
Ccode = Ccode0
|
|
;
|
|
Uinstr0 = store_ticket(Lval),
|
|
opt_util__lval_access_rvals(Lval, Rvals),
|
|
livemap__make_live(Rvals, Livevals0, Livevals),
|
|
Livemap = Livemap0,
|
|
Instrs = Instrs0,
|
|
Ccode = Ccode0
|
|
;
|
|
Uinstr0 = restore_ticket(Rval),
|
|
livemap__make_live([Rval], Livevals0, Livevals),
|
|
Livemap = Livemap0,
|
|
Instrs = Instrs0,
|
|
Ccode = Ccode0
|
|
;
|
|
Uinstr0 = discard_ticket,
|
|
Livevals = Livevals0,
|
|
Livemap = Livemap0,
|
|
Instrs = Instrs0,
|
|
Ccode = Ccode0
|
|
;
|
|
Uinstr0 = incr_sp(_),
|
|
Livevals = Livevals0,
|
|
Livemap = Livemap0,
|
|
Instrs = Instrs0,
|
|
Ccode = Ccode0
|
|
;
|
|
Uinstr0 = decr_sp(_),
|
|
Livevals = Livevals0,
|
|
Livemap = Livemap0,
|
|
Instrs = Instrs0,
|
|
Ccode = Ccode0
|
|
;
|
|
Uinstr0 = pragma_c(_, _, _, _),
|
|
Livemap = Livemap0,
|
|
Livevals = Livevals0,
|
|
Instrs = Instrs0,
|
|
Ccode = yes
|
|
).
|
|
|
|
:- pred livemap__look_for_livevals(list(instruction), list(instruction),
|
|
lvalset, lvalset, string, bool, bool).
|
|
% :- mode livemap__look_for_livevals(di, uo, di, uo, in, in, out) is det.
|
|
:- mode livemap__look_for_livevals(in, out, in, out, in, in, out) is det.
|
|
|
|
livemap__look_for_livevals(Instrs0, Instrs, Livevals0, Livevals,
|
|
Site, Compulsory, Found) :-
|
|
opt_util__skip_comments(Instrs0, Instrs1),
|
|
( Instrs1 = [livevals(Livevals1) - _ | Instrs2] ->
|
|
livemap__filter_livevals(Livevals1, Livevals),
|
|
Instrs = Instrs2,
|
|
Found = yes
|
|
; Compulsory = yes ->
|
|
string__append(Site, " not preceded by livevals", Msg),
|
|
error(Msg)
|
|
;
|
|
Instrs = Instrs1,
|
|
Livevals = Livevals0,
|
|
Found = no
|
|
).
|
|
|
|
% What lval (if any) is consulted when we branch to a code address?
|
|
|
|
:- pred livemap__special_code_addr(code_addr, maybe(lval)).
|
|
:- mode livemap__special_code_addr(in, out) is det.
|
|
|
|
livemap__special_code_addr(label(_), no).
|
|
livemap__special_code_addr(imported(_), no).
|
|
livemap__special_code_addr(succip, yes(succip)).
|
|
livemap__special_code_addr(do_succeed(_), yes(succip(lval(curfr)))).
|
|
livemap__special_code_addr(do_redo, yes(redoip(lval(maxfr)))).
|
|
livemap__special_code_addr(do_fail, no).
|
|
livemap__special_code_addr(do_det_closure, no).
|
|
livemap__special_code_addr(do_semidet_closure, no).
|
|
livemap__special_code_addr(do_nondet_closure, no).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% Set all lvals found in this rval to live, with the exception of
|
|
% fields, since they are treated specially (the later stages consider
|
|
% them to be live even if they are not explicitly in the live set).
|
|
|
|
:- pred livemap__make_live(list(rval), lvalset, lvalset).
|
|
% :- mode livemap__make_live(in, di, uo) is det.
|
|
:- mode livemap__make_live(in, in, out) is det.
|
|
|
|
livemap__make_live([], Livevals, Livevals).
|
|
livemap__make_live([Rval | Rvals], Livevals0, Livevals) :-
|
|
(
|
|
Rval = lval(Lval),
|
|
( Lval = field(_, Rval1, Rval2) ->
|
|
livemap__make_live([Rval1, Rval2], Livevals0, Livevals1)
|
|
;
|
|
copy(Lval, Lval1),
|
|
set__insert(Livevals0, Lval1, Livevals1)
|
|
)
|
|
;
|
|
Rval = create(_, _, _),
|
|
Livevals1 = Livevals0
|
|
;
|
|
Rval = mkword(_, Rval1),
|
|
livemap__make_live([Rval1], Livevals0, Livevals1)
|
|
;
|
|
Rval = const(_),
|
|
Livevals1 = Livevals0
|
|
;
|
|
Rval = unop(_, Rval1),
|
|
livemap__make_live([Rval1], Livevals0, Livevals1)
|
|
;
|
|
Rval = binop(_, Rval1, Rval2),
|
|
livemap__make_live([Rval1, Rval2], Livevals0, Livevals1)
|
|
;
|
|
Rval = var(_),
|
|
error("var rval should not propagate to the optimizer")
|
|
),
|
|
livemap__make_live(Rvals, Livevals1, Livevals).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- pred livemap__filter_livevals(lvalset, lvalset).
|
|
:- mode livemap__filter_livevals(in, out) is det.
|
|
|
|
livemap__filter_livevals(Livevals0, Livevals) :-
|
|
set__to_sorted_list(Livevals0, Livelist),
|
|
set__init(Livevals1),
|
|
livemap__insert_proper_livevals(Livelist, Livevals1, Livevals).
|
|
|
|
:- pred livemap__insert_label_livevals(list(label), livemap, lvalset, lvalset).
|
|
% :- mode livemap__insert_label_livevals(in, in, di, uo) is det.
|
|
:- mode livemap__insert_label_livevals(in, in, in, out) is det.
|
|
|
|
livemap__insert_label_livevals([], _, Livevals, Livevals).
|
|
livemap__insert_label_livevals([Label | Labels], Livemap, Livevals0, Livevals) :-
|
|
( map__search(Livemap, Label, LabelLivevals) ->
|
|
set__to_sorted_list(LabelLivevals, Livelist),
|
|
livemap__insert_proper_livevals(Livelist, Livevals0, Livevals1)
|
|
;
|
|
Livevals1 = Livevals0
|
|
),
|
|
livemap__insert_label_livevals(Labels, Livemap, Livevals1, Livevals).
|
|
|
|
:- pred livemap__insert_proper_livevals(list(lval), lvalset, lvalset).
|
|
% :- mode livemap__insert_proper_livevals(in, di, uo) is det.
|
|
:- mode livemap__insert_proper_livevals(in, in, out) is det.
|
|
|
|
livemap__insert_proper_livevals([], Livevals, Livevals).
|
|
livemap__insert_proper_livevals([Live | Livelist], Livevals0, Livevals) :-
|
|
livemap__insert_proper_liveval(Live, Livevals0, Livevals1),
|
|
livemap__insert_proper_livevals(Livelist, Livevals1, Livevals).
|
|
|
|
% Make sure that we insert general register and stack references only.
|
|
|
|
:- pred livemap__insert_proper_liveval(lval, lvalset, lvalset).
|
|
% :- mode livemap__insert_proper_liveval(in, di, uo) is det.
|
|
:- mode livemap__insert_proper_liveval(in, in, out) is det.
|
|
|
|
livemap__insert_proper_liveval(Live, Livevals0, Livevals) :-
|
|
( Live = reg(_) ->
|
|
copy(Live, Live1),
|
|
set__insert(Livevals0, Live1, Livevals)
|
|
; Live = stackvar(_) ->
|
|
copy(Live, Live1),
|
|
set__insert(Livevals0, Live1, Livevals)
|
|
; Live = framevar(_) ->
|
|
copy(Live, Live1),
|
|
set__insert(Livevals0, Live1, Livevals)
|
|
;
|
|
Livevals = Livevals0
|
|
).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%-----------------------------------------------------------------------------%
|