Files
mercury/compiler/mark_static_terms.m
Julien Fischer 45fdb6c451 Use expect/3 in place of require/2 throughout most of the
Estimated hours taken: 4
Branches: main

compiler/*.m:
	Use expect/3 in place of require/2 throughout most of the
	compiler.

	Use unexpected/2 (or sorry/2) in place of error/1 in more
	places.

	Fix more dodgy assertion error messages.

	s/map(prog_var, mer_type)/vartypes/ where the latter is meant.
2005-11-28 04:11:59 +00:00

220 lines
8.4 KiB
Mathematica

%-----------------------------------------------------------------------------%
% vim: ft=mercury ts=4 sw=4 et
%-----------------------------------------------------------------------------%
% Copyright (C) 2000-2005 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.
%-----------------------------------------------------------------------------%
% File: mark_static_terms.m.
% Main author: fjh.
% This module traverses the HLDS, updating the `how_to_construct' field of
% construction unifications. For each construction which can be done
% statically, i.e. whose arguments are all static, it replaces this field with
% `construct_statically'. This field is then used by the MLDS back-end to
% determine when it can generate static initialized constants rather than
% using new_object() MLDS statements.
%-----------------------------------------------------------------------------%
:- module ml_backend__mark_static_terms.
:- interface.
:- import_module hlds.hlds_module.
:- import_module hlds.hlds_pred.
%-----------------------------------------------------------------------------%
:- pred mark_static_terms(module_info::in, proc_info::in, proc_info::out)
is det.
%-----------------------------------------------------------------------------%
%-----------------------------------------------------------------------------%
:- implementation.
:- import_module hlds.hlds_data.
:- import_module hlds.hlds_goal.
:- import_module libs.compiler_util.
:- import_module parse_tree.prog_data.
:- import_module bool.
:- import_module int.
:- import_module list.
:- import_module map.
:- import_module std_util.
:- import_module svmap.
%-----------------------------------------------------------------------------%
% As we traverse the goal, we keep track of which variables are static at
% the current program point, and for each such variable, we keep
% information on how to construct it.
%
:- type static_info == map(prog_var, static_cons).
mark_static_terms(_ModuleInfo, !Proc) :-
% The ModuleInfo argument is there just for passes_aux.
proc_info_goal(!.Proc, Goal0),
map__init(StaticInfo0),
goal_mark_static_terms(Goal0, Goal, StaticInfo0, _StaticInfo),
proc_info_set_goal(Goal, !Proc).
:- pred goal_mark_static_terms(hlds_goal::in, hlds_goal::out,
static_info::in, static_info::out) is det.
goal_mark_static_terms(GoalExpr0 - GoalInfo, GoalExpr - GoalInfo, !SI) :-
goal_expr_mark_static_terms(GoalExpr0, GoalExpr, !SI).
:- pred goal_expr_mark_static_terms(hlds_goal_expr::in, hlds_goal_expr::out,
static_info::in, static_info::out) is det.
goal_expr_mark_static_terms(conj(Goals0), conj(Goals), !SI) :-
conj_mark_static_terms(Goals0, Goals, !SI).
goal_expr_mark_static_terms(par_conj(Goals0), par_conj(Goals), !SI) :-
% It's OK to treat parallel conjunctions as if they were sequential here,
% since if we mark any variables as static, the computation of those
% variables will be done at compile time.
conj_mark_static_terms(Goals0, Goals, !SI).
goal_expr_mark_static_terms(disj(Goals0), disj(Goals), !SI) :-
% We revert to the original static_info at the end of branched goals.
disj_mark_static_terms(Goals0, Goals, !.SI).
goal_expr_mark_static_terms(switch(A, B, Cases0), switch(A, B, Cases), !SI) :-
% We revert to the original static_info at the end of branched goals.
cases_mark_static_terms(Cases0, Cases, !.SI).
goal_expr_mark_static_terms(not(Goal0), not(Goal), !SI) :-
% We revert to the original static_info at the end of the negation.
goal_mark_static_terms(Goal0, Goal, !.SI, _SI).
goal_expr_mark_static_terms(scope(A, Goal0), scope(A, Goal), !SI) :-
goal_mark_static_terms(Goal0, Goal, !SI).
goal_expr_mark_static_terms(if_then_else(A, Cond0, Then0, Else0),
if_then_else(A, Cond, Then, Else), SI0, SI0) :-
% We run the Cond and the Then in sequence, and we run the Else
% in parallel with that, and then we throw away the static_infos
% we computed and revert to the original static_info at the end,
% since this was a branched goal.
goal_mark_static_terms(Cond0, Cond, SI0, SI_Cond),
goal_mark_static_terms(Then0, Then, SI_Cond, _SI_Then),
goal_mark_static_terms(Else0, Else, SI0, _SI_Else).
goal_expr_mark_static_terms(Goal @ call(_, _, _, _, _, _), Goal, !SI).
goal_expr_mark_static_terms(Goal @ generic_call(_, _, _, _), Goal, !SI).
goal_expr_mark_static_terms(unify(LHS, RHS, Mode, Unification0, Context),
unify(LHS, RHS, Mode, Unification, Context), !SI) :-
unification_mark_static_terms(Unification0, Unification, !SI).
goal_expr_mark_static_terms(Goal @ foreign_proc(_, _, _, _, _, _), Goal, !SI).
goal_expr_mark_static_terms(shorthand(_), _, !SI) :-
% These should have been expanded out by now.
unexpected(this_file, "fill_expr_slots: unexpected shorthand").
:- pred conj_mark_static_terms(hlds_goals::in, hlds_goals::out,
static_info::in, static_info::out) is det.
conj_mark_static_terms(Goals0, Goals, !SI) :-
list__map_foldl(goal_mark_static_terms, Goals0, Goals, !SI).
:- pred disj_mark_static_terms(hlds_goals::in, hlds_goals::out,
static_info::in) is det.
disj_mark_static_terms([], [], _).
disj_mark_static_terms([Goal0 | Goals0], [Goal | Goals], SI0) :-
% We throw away the static_info obtained after each branch.
goal_mark_static_terms(Goal0, Goal, SI0, _SI),
disj_mark_static_terms(Goals0, Goals, SI0).
:- pred cases_mark_static_terms(list(case)::in, list(case)::out,
static_info::in) is det.
cases_mark_static_terms([], [], _SI0).
cases_mark_static_terms([Case0 | Cases0], [Case | Cases], SI0) :-
Case0 = case(ConsId, Goal0),
% We throw away the static_info obtained after each branch.
goal_mark_static_terms(Goal0, Goal, SI0, _SI),
Case = case(ConsId, Goal),
cases_mark_static_terms(Cases0, Cases, SI0).
:- pred unification_mark_static_terms(unification::in, unification::out,
static_info::in, static_info::out) is det.
unification_mark_static_terms(Unification0, Unification, !StaticVars) :-
(
Unification0 = construct(Var, ConsId, ArgVars, D, HowToConstruct0,
F, G),
(
% If all the arguments are static, then the newly constructed
% variable is static too.
list__map(map__search(!.StaticVars), ArgVars, StaticArgs)
->
HowToConstruct = construct_statically(StaticArgs),
svmap__det_insert(Var, static_cons(ConsId, ArgVars, StaticArgs),
!StaticVars)
;
HowToConstruct = HowToConstruct0
),
( HowToConstruct = HowToConstruct0 ->
% This is a minor optimization to improve the efficiency of the
% compiler: don't bother allocating memory if we don't need to.
Unification = Unification0
;
Unification = construct(Var, ConsId, ArgVars, D, HowToConstruct,
F, G)
)
;
Unification0 = deconstruct(_Var, _ConsId, _ArgVars, _UniModes,
_CanFail, _CanCGC),
Unification = Unification0
% (
% % if the variable being deconstructed is static,
% % and the deconstruction cannot fail,
% % then the newly extracted argument variables
% % are static too
% % (XXX is the "cannot fail" bit really necessary?)
% map__search(StaticVars0, Var, Data),
% CanFail = cannot_fail
% ->
% XXX insert ArgVars into StaticVars0
% ;
% true
% )
;
Unification0 = assign(TargetVar, SourceVar),
Unification = Unification0,
(
% If the variable being assign from is static,
% then the variable being assigned to is static too.
map__search(!.StaticVars, SourceVar, Data)
->
svmap__det_insert(TargetVar, Data, !StaticVars)
;
true
)
;
Unification0 = simple_test(_, _),
Unification = Unification0
;
Unification0 = complicated_unify(_, _, _),
Unification = Unification0
).
%-----------------------------------------------------------------------------%
:- func this_file = string.
this_file = "mark_static_terms.m".
%-----------------------------------------------------------------------------%
:- end_module mark_static_terms.
%-----------------------------------------------------------------------------%