Files
mercury/compiler/mark_static_terms.m
Zoltan Somogyi b21e9e459a Delete all calls to get_progress_output_stream ...
... and almost all calls to get_error_output_stream. Replace them
with ProgressStreams and ErrorStreams passed down from higher in the
call tree.

Use ProgressStreams, not ErrorStreams, to write out error messages about
any failures of filesystem operations. These are not appropriate to put
into a module's .err file, since they are not about an error in the
Mercury code of the module.

compiler/globals.m:
    Delete the predicates that return progress streams, and the mutable
    behind them.

compiler/passes_aux.m:
    Delete the predicates that return progress streams. Delete the
    versions of the progress-message-writing predicates that didn't get
    the progress stream from their caller.

compiler/*.m:
    Pass around ProgressStreams and/or ErrorStreams explicitly,
    as mentioned at the top of log message.

    In a few places, don't write out error_specs to ErrorStream,
    returning it to be printed by our caller, or its caller etc instead.
    In some of those places, this allowed the deletion an existing
    ErrorStream argument.

    Given that get_{progress,error}_output_stream took a ModuleName input,
    deleting some of the calls to those predicates left ModuleName unused.
    Delete such unused ModuleNames.

    In a few places, change argument orders to conform to our usual
    programming style.

    Fix too-long lines.
2023-10-17 20:41:33 +11:00

244 lines
9.5 KiB
Mathematica

%-----------------------------------------------------------------------------%
% vim: ft=mercury ts=4 sw=4 et
%-----------------------------------------------------------------------------%
% Copyright (C) 2000-2012 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'. The main use of this information is in the MLDS
% backend, to determine when we can generate static constants instead of
% calling new_object(). However, other parts of the compiler may also use
% this information.
%
%-----------------------------------------------------------------------------%
:- module hlds.mark_static_terms.
:- interface.
:- import_module hlds.hlds_module.
:- import_module bool.
:- import_module io.
%-----------------------------------------------------------------------------%
:- pred maybe_mark_static_terms(io.text_output_stream::in, bool::in, bool::in,
module_info::in, module_info::out, io::di, io::uo) is det.
%-----------------------------------------------------------------------------%
%-----------------------------------------------------------------------------%
:- implementation.
:- import_module hlds.hlds_goal.
:- import_module hlds.hlds_pred.
:- import_module hlds.passes_aux.
:- import_module libs.
:- import_module libs.file_util.
:- import_module libs.globals.
:- import_module libs.optimization_options.
:- import_module parse_tree.
:- import_module parse_tree.prog_data.
:- import_module list.
:- import_module require.
:- import_module set_tree234.
%-----------------------------------------------------------------------------%
maybe_mark_static_terms(ProgressStream, Verbose, Stats, !HLDS, !IO) :-
module_info_get_globals(!.HLDS, Globals),
globals.get_opt_tuple(Globals, OptTuple),
SGCells = OptTuple ^ ot_use_static_ground_cells,
(
SGCells = use_static_ground_cells,
maybe_write_string(ProgressStream, Verbose,
"% Marking static ground terms...\n", !IO),
maybe_flush_output(ProgressStream, Verbose, !IO),
process_valid_nonimported_procs(update_proc(mark_static_terms), !HLDS),
maybe_write_string(ProgressStream, Verbose,
"% done.\n", !IO),
maybe_report_stats(ProgressStream, Stats, !IO)
;
SGCells = do_not_use_static_ground_cells
).
%-----------------------------------------------------------------------------%
% As we traverse the goal, we keep track of which variables are static at
% the current program point.
%
:- type static_info == set_tree234(prog_var).
:- pred mark_static_terms(module_info::in, proc_info::in, proc_info::out)
is det.
mark_static_terms(_ModuleInfo, !Proc) :-
% The ModuleInfo argument is there just for passes_aux.
proc_info_get_goal(!.Proc, Goal0),
StaticInfo0 = set_tree234.init,
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(Goal0, Goal, !SI) :-
Goal0 = hlds_goal(GoalExpr0, GoalInfo),
Goal = hlds_goal(GoalExpr, GoalInfo),
(
GoalExpr0 = conj(ConjType, Goals0),
% 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),
GoalExpr = conj(ConjType, Goals)
;
GoalExpr0 = disj(Goals0),
% We revert to the original static_info at the end of branched goals.
disj_mark_static_terms(Goals0, Goals, !.SI),
GoalExpr = disj(Goals)
;
GoalExpr0 = switch(Var, CanFail, Cases0),
% We revert to the original static_info at the end of branched goals.
cases_mark_static_terms(Cases0, Cases, !.SI),
GoalExpr = switch(Var, CanFail, Cases)
;
GoalExpr0 = negation(SubGoal0),
% We revert to the original static_info at the end of the negation.
goal_mark_static_terms(SubGoal0, SubGoal, !.SI, _SI),
GoalExpr = negation(SubGoal)
;
GoalExpr0 = scope(Reason, SubGoal0),
( if
Reason = from_ground_term(TermVar, from_ground_term_construct)
then
% These scopes already have all their unifications marked
% as construct_statically.
set_tree234.insert(TermVar, !SI),
GoalExpr = GoalExpr0
else
goal_mark_static_terms(SubGoal0, SubGoal, !SI),
GoalExpr = scope(Reason, SubGoal)
)
;
GoalExpr0 = if_then_else(Vars, Cond0, Then0, Else0),
SI0 = !.SI,
% 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),
GoalExpr = if_then_else(Vars, Cond, Then, Else)
;
( GoalExpr0 = plain_call(_, _, _, _, _, _)
; GoalExpr = generic_call(_, _, _, _, _)
; GoalExpr = call_foreign_proc(_, _, _, _, _, _, _)
),
GoalExpr = GoalExpr0
;
GoalExpr0 = unify(LHS, RHS, Mode, Unification0, Context),
unification_mark_static_terms(Unification0, Unification, !SI),
GoalExpr = unify(LHS, RHS, Mode, Unification, Context)
;
GoalExpr0 = shorthand(_),
% These should have been expanded out by now.
unexpected($pred, "shorthand")
).
:- pred conj_mark_static_terms(list(hlds_goal)::in, list(hlds_goal)::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(list(hlds_goal)::in, list(hlds_goal)::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(MainConsId, OtherConsIds, Goal0),
% We throw away the static_info obtained after each branch.
goal_mark_static_terms(Goal0, Goal, SI0, _SI),
Case = case(MainConsId, OtherConsIds, 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, ArgModes,
HowToConstruct0, Unique, SubInfo),
% If all the arguments are static, then the newly constructed variable
% is static too.
( if list.all_true(set_tree234.contains(!.StaticVars), ArgVars) then
HowToConstruct = construct_statically(marked_static),
set_tree234.insert(Var, !StaticVars),
% This is a minor optimization to improve the efficiency of the
% compiler: don't bother allocating memory if we don't need to.
( if HowToConstruct = HowToConstruct0 then
Unification = Unification0
else
Unification = construct(Var, ConsId, ArgVars, ArgModes,
HowToConstruct, Unique, SubInfo)
)
else
Unification = Unification0
)
;
Unification0 = deconstruct(_Var, _ConsId, _ArgVars, _UniModes,
_CanFail, _CanCGC),
Unification = Unification0
% ( if
% % 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
% then
% XXX insert ArgVars into StaticVars0
% else
% true
% )
;
Unification0 = assign(TargetVar, SourceVar),
Unification = Unification0,
% If the variable being assigned from is static, then the variable
% being assigned to is static too.
( if set_tree234.contains(!.StaticVars, SourceVar) then
set_tree234.insert(TargetVar, !StaticVars)
else
true
)
;
( Unification0 = simple_test(_, _)
; Unification0 = complicated_unify(_, _, _)
),
Unification = Unification0
).
%-----------------------------------------------------------------------------%
:- end_module hlds.mark_static_terms.
%-----------------------------------------------------------------------------%