%-----------------------------------------------------------------------------% % 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. %-----------------------------------------------------------------------------%