mirror of
https://github.com/Mercury-Language/mercury.git
synced 2025-12-19 07:45:09 +00:00
Estimated hours taken: 8 Branches: main analysis/analysis.m: browser/browse.m: compiler/accumulator.m: compiler/assertion.m: compiler/atsort.m: compiler/c_util.m: compiler/check_typeclass.m: compiler/clause_to_proc.m: compiler/code_gen.m: compiler/code_model.m: compiler/const_prop.m: compiler/constraint.m: compiler/dead_proc_elim.m: compiler/delay_construct.m: compiler/dependency_graph.m: compiler/det_analysis.m: compiler/det_report.m: compiler/export.m: compiler/fact_table.m: compiler/follow_code.m: compiler/graph_colour.m: compiler/hlds_module.m: compiler/inlining.m: compiler/llds.m: compiler/make_hlds.m: compiler/mercury_to_mercury.m: compiler/ml_tailcall.m: compiler/ml_unify_gen.m: compiler/mmc_analysis.m: compiler/mode_errors.m: compiler/passes_aux.m: compiler/post_typecheck.m: compiler/size_prof.m: compiler/switch_util.m: compiler/table_gen.m: compiler/term_errors.m: compiler/transform_llds.m: compiler/type_util.m: compiler/unify_gen.m: compiler/unneeded_code.m: compiler/unused_args.m: Bring these modules up to our current coding standards. Use predmode declarations and state variable syntax where relevant. Reorder arguments where this is needed for the use state variables. Make the orders of predicate definitions correspond to the order of their declarations. Replace some overly large lambda expressions with named predicates. Convert some predicates to functions where this makes their use more convenient. Use field access notation where convenient. Fix any inconsistent indentation. Remove module prefixes on predicate names where this is necessary to allow sane indentation. In several places, use predicates from error_util.m to print error messages. Apart from this, there are no changes in algorithms. In some places, conform to the changes below. compiler/error_util.m: compiler/hlds_error_util.m: Add new variants of existing predicates for use in some of the changed modules above. compiler/hlds_out.m: Add some functions to convert values of some HLDS types as strings, for use in preparing the arguments of the new calls to predicates in error_util.m. Change the implementations of the predicates that print values of those types to call those functions instead of allowing code duplication. compiler/llds.m: Add some field names to allow use of field updates where relevant. tests/invalid/assert_in_interface.err_exp: tests/invalid/multisoln_func.err_exp: tests/invalid/tricky_assert1.err_exp: Update the expected outputs of these test cases to allow for them being generated by error_util.m, and hence being better formatted than before.
279 lines
11 KiB
Mathematica
279 lines
11 KiB
Mathematica
%-----------------------------------------------------------------------------%
|
|
% Copyright (C) 2001-2004 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: delay_construct.m
|
|
%
|
|
% Author: zs.
|
|
%
|
|
% This module transforms sequences of goals in procedure bodies.
|
|
% It looks for a unification that constructs a ground term followed by
|
|
% primitive goals, at least one of which can fail, and none of which take
|
|
% the variable representing the cell as their input. Such code sequences
|
|
% cause the cell to be constructed even if the following goal would fail,
|
|
% which is wasteful. This module therefore reorders the sequence, moving the
|
|
% construction unification past all the semidet primitives it can.
|
|
%
|
|
% The reason we don't move the construction past calls or composite goals
|
|
% is that this may require storing the input arguments of the construction on
|
|
% the stack, which may cause a slowdown bigger than the speedup available from
|
|
% not having to construct the cell on some execution paths.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- module transform_hlds__delay_construct.
|
|
|
|
:- interface.
|
|
|
|
:- import_module hlds__hlds_module.
|
|
:- import_module hlds__hlds_pred.
|
|
:- import_module io.
|
|
|
|
:- pred delay_construct_proc(pred_id::in, proc_id::in, module_info::in,
|
|
proc_info::in, proc_info::out, io::di, io::uo) is det.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- implementation.
|
|
|
|
:- import_module check_hlds__inst_match.
|
|
:- import_module hlds__hlds_data.
|
|
:- import_module hlds__hlds_goal.
|
|
:- import_module hlds__instmap.
|
|
:- import_module hlds__passes_aux.
|
|
:- import_module libs__globals.
|
|
:- import_module parse_tree__prog_data.
|
|
|
|
:- import_module bool, list, set, std_util, require.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
delay_construct_proc(PredId, ProcId, ModuleInfo, !ProcInfo, !IO) :-
|
|
write_proc_progress_message("% Delaying construction unifications in ",
|
|
PredId, ProcId, ModuleInfo, !IO),
|
|
globals__io_get_globals(Globals, !IO),
|
|
module_info_pred_info(ModuleInfo, PredId, PredInfo),
|
|
delay_construct_proc_no_io(PredInfo, ModuleInfo, Globals,
|
|
!ProcInfo).
|
|
|
|
:- pred delay_construct_proc_no_io(pred_info::in, module_info::in, globals::in,
|
|
proc_info::in, proc_info::out) is det.
|
|
|
|
delay_construct_proc_no_io(PredInfo, ModuleInfo, Globals, !ProcInfo) :-
|
|
body_should_use_typeinfo_liveness(PredInfo, Globals,
|
|
BodyTypeinfoLiveness),
|
|
proc_info_vartypes(!.ProcInfo, VarTypes),
|
|
proc_info_typeinfo_varmap(!.ProcInfo, TypeInfoVarMap),
|
|
proc_info_get_initial_instmap(!.ProcInfo, ModuleInfo, InstMap0),
|
|
DelayInfo = delay_construct_info(ModuleInfo, BodyTypeinfoLiveness,
|
|
VarTypes, TypeInfoVarMap),
|
|
proc_info_goal(!.ProcInfo, Goal0),
|
|
delay_construct_in_goal(Goal0, InstMap0, DelayInfo, Goal),
|
|
proc_info_set_goal(Goal, !ProcInfo).
|
|
|
|
:- type delay_construct_info
|
|
---> delay_construct_info(
|
|
module_info :: module_info,
|
|
body_typeinfo_liveness :: bool,
|
|
vartypes :: vartypes,
|
|
type_info_varmap :: type_info_varmap
|
|
).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- pred delay_construct_in_goal(hlds_goal::in, instmap::in,
|
|
delay_construct_info::in, hlds_goal::out) is det.
|
|
|
|
delay_construct_in_goal(GoalExpr0 - GoalInfo0, InstMap0, DelayInfo, Goal) :-
|
|
(
|
|
GoalExpr0 = conj(Goals0),
|
|
goal_info_get_determinism(GoalInfo0, Detism),
|
|
determinism_components(Detism, CanFail, MaxSoln),
|
|
(
|
|
% If the conjunction cannot fail, then its conjuncts
|
|
% cannot fail either, so we have no hope of pushing a
|
|
% construction past a failing goal.
|
|
%
|
|
% If the conjuntion contains goals that can succeed
|
|
% more than once, which is possible if MaxSoln is
|
|
% at_most_many or at_most_many_cc, then moving a
|
|
% construction to the right may increase the number of
|
|
% times the construction is executed. We are therefore
|
|
% careful to make sure delay_construct_in_conj doesn't
|
|
% move constructions across goals that succeed more
|
|
% than once.
|
|
%
|
|
% If the conjunction cannot succeed, i.e. MaxSoln is
|
|
% at_most_zero, there is no point in trying to speed it
|
|
% up.
|
|
|
|
CanFail = can_fail,
|
|
MaxSoln \= at_most_zero
|
|
->
|
|
delay_construct_in_conj(Goals0, InstMap0, DelayInfo,
|
|
set__init, [], Goals1)
|
|
;
|
|
Goals1 = Goals0
|
|
),
|
|
delay_construct_in_goals(Goals1, InstMap0, DelayInfo, Goals),
|
|
Goal = conj(Goals) - GoalInfo0
|
|
;
|
|
GoalExpr0 = par_conj(Goals0),
|
|
delay_construct_in_goals(Goals0, InstMap0, DelayInfo, Goals),
|
|
Goal = par_conj(Goals) - GoalInfo0
|
|
;
|
|
GoalExpr0 = disj(Goals0),
|
|
delay_construct_in_goals(Goals0, InstMap0, DelayInfo, Goals),
|
|
Goal = disj(Goals) - GoalInfo0
|
|
;
|
|
GoalExpr0 = not(NegGoal0),
|
|
delay_construct_in_goal(NegGoal0, InstMap0, DelayInfo, NegGoal),
|
|
Goal = not(NegGoal) - GoalInfo0
|
|
;
|
|
GoalExpr0 = switch(Var, CanFail, Cases0),
|
|
delay_construct_in_cases(Cases0, InstMap0, DelayInfo, Cases),
|
|
Goal = switch(Var, CanFail, Cases) - GoalInfo0
|
|
;
|
|
GoalExpr0 = if_then_else(Vars, Cond0, Then0, Else0),
|
|
Cond0 = _ - CondInfo0,
|
|
goal_info_get_instmap_delta(CondInfo0, CondInstMapDelta),
|
|
instmap__apply_instmap_delta(InstMap0, CondInstMapDelta,
|
|
InstMapThen),
|
|
delay_construct_in_goal(Cond0, InstMap0, DelayInfo, Cond),
|
|
delay_construct_in_goal(Then0, InstMapThen, DelayInfo, Then),
|
|
delay_construct_in_goal(Else0, InstMap0, DelayInfo, Else),
|
|
Goal = if_then_else(Vars, Cond, Then, Else) - GoalInfo0
|
|
;
|
|
GoalExpr0 = some(Var, CanRemove, SubGoal0),
|
|
delay_construct_in_goal(SubGoal0, InstMap0, DelayInfo, SubGoal),
|
|
Goal = some(Var, CanRemove, SubGoal) - GoalInfo0
|
|
;
|
|
GoalExpr0 = generic_call(_, _, _, _),
|
|
Goal = GoalExpr0 - GoalInfo0
|
|
;
|
|
GoalExpr0 = call(_, _, _, _, _, _),
|
|
Goal = GoalExpr0 - GoalInfo0
|
|
;
|
|
GoalExpr0 = unify(_, _, _, _, _),
|
|
Goal = GoalExpr0 - GoalInfo0
|
|
;
|
|
GoalExpr0 = foreign_proc(_, _, _, _, _, _, _),
|
|
Goal = GoalExpr0 - GoalInfo0
|
|
;
|
|
GoalExpr0 = shorthand(_),
|
|
% these should have been expanded out by now
|
|
error("delay_construct_in_goal: unexpected shorthand")
|
|
).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% We maintain a list of delayed construction unifications that construct ground
|
|
% terms, and the set of variables they define.
|
|
%
|
|
% When we find other construction unifications, we add them to the list.
|
|
% It does not matter if they depend on other delayed construction unifications;
|
|
% when we put them back into the conjunction, we do so in the original order.
|
|
%
|
|
% There are several reasons why we may not be able to delay a construction
|
|
% unification past a conjunct. The conjunct may not be a primitive goal,
|
|
% or it may be impure; in either case, we must insert all the delayed
|
|
% construction unifications before it. The conjunct may also require the value
|
|
% of a variable defined by a construction unification. In such cases, we could
|
|
% drop before that goal only the construction unifications that define the
|
|
% variables needed by the conjunct, either directly or indirectly through
|
|
% the values required by some of those construction unifications. However,
|
|
% separating out this set of delayed constructions from the others would
|
|
% require somewhat complex code, and it is not clear that there would be any
|
|
% significant benefit. We therefore insert *all* the delayed constructions
|
|
% before a goal if the goal requires *any* of the variables bound by the
|
|
% constructions.
|
|
%
|
|
% The instmap we pass around is the one that we construct from the original
|
|
% conjunction order. At each point, it reflects the bindings made by the
|
|
% conjuncts so far *plus* the bindings made by the delayed goals.
|
|
|
|
:- pred delay_construct_in_conj(list(hlds_goal)::in, instmap::in,
|
|
delay_construct_info::in, set(prog_var)::in, list(hlds_goal)::in,
|
|
list(hlds_goal)::out) is det.
|
|
|
|
delay_construct_in_conj([], _, _, _, RevDelayedGoals, DelayedGoals) :-
|
|
list__reverse(RevDelayedGoals, DelayedGoals).
|
|
delay_construct_in_conj([Goal0 | Goals0], InstMap0, DelayInfo,
|
|
ConstructedVars0, RevDelayedGoals0, Goals) :-
|
|
Goal0 = GoalExpr0 - GoalInfo0,
|
|
goal_info_get_instmap_delta(GoalInfo0, InstMapDelta0),
|
|
instmap__apply_instmap_delta(InstMap0, InstMapDelta0, InstMap1),
|
|
(
|
|
GoalExpr0 = unify(_, _, _, Unif, _),
|
|
Unif = construct(Var, _, Args, _, _, _, _),
|
|
Args = [_ | _], % We are constructing a cell, not a constant
|
|
instmap__lookup_var(InstMap0, Var, Inst0),
|
|
inst_is_free(DelayInfo ^ module_info, Inst0),
|
|
instmap__lookup_var(InstMap1, Var, Inst1),
|
|
inst_is_ground(DelayInfo ^ module_info, Inst1)
|
|
->
|
|
set__insert(ConstructedVars0, Var, ConstructedVars1),
|
|
RevDelayedGoals1 = [Goal0 | RevDelayedGoals0],
|
|
delay_construct_in_conj(Goals0, InstMap1, DelayInfo,
|
|
ConstructedVars1, RevDelayedGoals1, Goals)
|
|
;
|
|
Goal0 = GoalExpr0 - GoalInfo0,
|
|
delay_construct_skippable(GoalExpr0, GoalInfo0),
|
|
goal_info_get_nonlocals(GoalInfo0, NonLocals),
|
|
proc_info_maybe_complete_with_typeinfo_vars(NonLocals,
|
|
DelayInfo ^ body_typeinfo_liveness,
|
|
DelayInfo ^ vartypes,
|
|
DelayInfo ^ type_info_varmap, CompletedNonLocals),
|
|
set__intersect(CompletedNonLocals, ConstructedVars0,
|
|
Intersection),
|
|
set__empty(Intersection),
|
|
\+ goal_info_has_feature(GoalInfo0, impure),
|
|
\+ goal_info_has_feature(GoalInfo0, semipure)
|
|
->
|
|
delay_construct_in_conj(Goals0, InstMap1, DelayInfo,
|
|
ConstructedVars0, RevDelayedGoals0, Goals1),
|
|
Goals = [Goal0 | Goals1]
|
|
;
|
|
list__reverse(RevDelayedGoals0, DelayedGoals),
|
|
delay_construct_in_conj(Goals0, InstMap1, DelayInfo,
|
|
set__init, [], Goals1),
|
|
list__append(DelayedGoals, [Goal0 | Goals1], Goals)
|
|
).
|
|
|
|
:- pred delay_construct_skippable(hlds_goal_expr::in, hlds_goal_info::in)
|
|
is semidet.
|
|
|
|
delay_construct_skippable(GoalExpr, GoalInfo) :-
|
|
(
|
|
GoalExpr = unify(_, _, _, _, _)
|
|
;
|
|
GoalExpr = call(_, _, _, inline_builtin, _, _)
|
|
),
|
|
goal_info_get_determinism(GoalInfo, Detism),
|
|
determinism_components(Detism, _CanFail, MaxSoln),
|
|
MaxSoln \= at_most_many.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- pred delay_construct_in_goals(list(hlds_goal)::in, instmap::in,
|
|
delay_construct_info::in, list(hlds_goal)::out) is det.
|
|
|
|
delay_construct_in_goals([], _, _, []).
|
|
delay_construct_in_goals([Goal0 | Goals0], InstMap0, DelayInfo,
|
|
[Goal | Goals]) :-
|
|
delay_construct_in_goal(Goal0, InstMap0, DelayInfo, Goal),
|
|
delay_construct_in_goals(Goals0, InstMap0, DelayInfo, Goals).
|
|
|
|
:- pred delay_construct_in_cases(list(case)::in, instmap::in,
|
|
delay_construct_info::in, list(case)::out) is det.
|
|
|
|
delay_construct_in_cases([], _, _, []).
|
|
delay_construct_in_cases([case(Cons, Goal0) | Cases0], InstMap0, DelayInfo,
|
|
[case(Cons, Goal) | Cases]) :-
|
|
delay_construct_in_goal(Goal0, InstMap0, DelayInfo, Goal),
|
|
delay_construct_in_cases(Cases0, InstMap0, DelayInfo, Cases).
|
|
|
|
%-----------------------------------------------------------------------------%
|