Files
mercury/compiler/mark_static_terms.m
Zoltan Somogyi ba93a52fe7 This diff changes a few types from being defined as equivalent to a pair
Estimated hours taken: 10
Branches: main

This diff changes a few types from being defined as equivalent to a pair
to being discriminated union types with their own function symbol. This
was motivated by an error message (one of many, but the one that broke
the camel's back) about "-" being used in an ambiguous manner. It will
reduce the number of such messages in the future, and will make compiler
data structures easier to inspect in the debugger.

The most important type changed by far is hlds_goal, whose function symbol
is now "hlds_goal". Second and third in importance are llds.instruction
(function symbol "llds_instr") and prog_item.m's item_and_context (function
symbol "item_and_context"). There are some others as well.

In several places, I rearranged predicates to factor the deconstruction of
goals into hlds_goal_expr and hlds_goal_into out of each clause into a single
point. In many places, I changed variable names that used "Goal" to refer
to just hlds_goal_exprs to use "GoalExpr" instead. I also changed variable
names that used "Item" to refer to item_and_contexts to use "ItemAndContext"
instead. This should make reading such code less confusing.

I renamed some function symbols and predicates to avoid ambiguities.

I only made one algorithmic change (at least intentionally).
In assertion.m, comparing two goals for equality now ignores goal_infos
for all kinds of goals, whereas previously it ignored them for most kinds
of goals, but for shorthand goals it was insisting on them being equal.
This seemed to me to be a bug. Pete, can you confirm this?
2007-01-06 09:23:59 +00:00

217 lines
8.3 KiB
Mathematica

%-----------------------------------------------------------------------------%
% vim: ft=mercury ts=4 sw=4 et
%-----------------------------------------------------------------------------%
% Copyright (C) 2000-2007 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_goal.
:- import_module libs.compiler_util.
:- import_module parse_tree.prog_data.
:- import_module list.
:- import_module map.
:- import_module pair.
:- 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_get_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(hlds_goal(GoalExpr0, GoalInfo),
hlds_goal(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(ConjType, Goals0), conj(ConjType, 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(negation(Goal0), negation(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 @ plain_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 @ call_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.
%-----------------------------------------------------------------------------%