mirror of
https://github.com/Mercury-Language/mercury.git
synced 2025-12-15 05:44:58 +00:00
355 lines
13 KiB
Mathematica
355 lines
13 KiB
Mathematica
%-----------------------------------------------------------------------------%
|
|
% Copyright (C) 1995-1997 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: constraint.m
|
|
% Main author: bromage.
|
|
%
|
|
% This module will eventually perform constraint propagation on
|
|
% an entire module. At the moment, though, it just does propagation
|
|
% within a single goal.
|
|
%
|
|
% The constraint propagation transformation attempts to improve
|
|
% the efficiency of a generate-and-test style program by statically
|
|
% scheduling constraints as early as possible, where a "constraint"
|
|
% is any goal which has no output and can fail.
|
|
%
|
|
% XXX Code is broken. Do not attempt to compile using the
|
|
% --constraint-propagation option!
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- module constraint.
|
|
|
|
:- interface.
|
|
|
|
:- import_module hlds_module.
|
|
:- import_module io.
|
|
|
|
:- pred constraint_propagation(module_info, module_info, io__state, io__state).
|
|
:- mode constraint_propagation(in, out, di, uo) is det.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- implementation.
|
|
|
|
:- import_module hlds_pred, hlds_goal, hlds_data.
|
|
:- import_module mode_util, passes_aux, code_aux, prog_data, instmap.
|
|
:- import_module delay_info, mode_info, inst_match, modes, mode_debug.
|
|
:- import_module transform, options, globals.
|
|
:- import_module mercury_to_mercury, hlds_out, dependency_graph.
|
|
|
|
:- import_module bool, list, map, set, std_util, assoc_list, string.
|
|
:- import_module varset, term, require.
|
|
|
|
:- type constraint == hlds_goal.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
constraint_propagation(ModuleInfo0, ModuleInfo) -->
|
|
{ module_info_ensure_dependency_info(ModuleInfo0, ModuleInfo1) },
|
|
{ module_info_dependency_info(ModuleInfo1, DepInfo) },
|
|
{ hlds_dependency_info_get_dependency_ordering(DepInfo, DepOrd) },
|
|
constraint_propagation2(DepOrd, ModuleInfo1, ModuleInfo).
|
|
|
|
:- pred constraint_propagation2(dependency_ordering, module_info, module_info,
|
|
io__state, io__state).
|
|
:- mode constraint_propagation2(in, in, out, di, uo) is det.
|
|
constraint_propagation2([], ModuleInfo, ModuleInfo) --> [].
|
|
constraint_propagation2([C | Cs], ModuleInfo0, ModuleInfo) -->
|
|
constraint_propagation3(C, ModuleInfo0, ModuleInfo1),
|
|
constraint_propagation2(Cs, ModuleInfo1, ModuleInfo).
|
|
|
|
:- pred constraint_propagation3(list(pred_proc_id), module_info, module_info,
|
|
io__state, io__state).
|
|
:- mode constraint_propagation3(in, in, out, di, uo) is det.
|
|
constraint_propagation3([], ModuleInfo, ModuleInfo) --> [].
|
|
constraint_propagation3([proc(Pred, Proc) | Rest], ModuleInfo0, ModuleInfo) -->
|
|
constraint__propagate_in_proc(Pred, Proc, ModuleInfo0, ModuleInfo1),
|
|
modecheck_proc(Proc, Pred, ModuleInfo1, ModuleInfo2, Errs),
|
|
( { Errs \= 0 } ->
|
|
{ error("constraint_propagation3") }
|
|
;
|
|
[]
|
|
),
|
|
constraint_propagation3(Rest, ModuleInfo2, ModuleInfo).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- pred constraint__propagate_in_proc(pred_id, proc_id, module_info,
|
|
module_info, io__state, io__state).
|
|
:- mode constraint__propagate_in_proc(in, in, in, out, di, uo) is det.
|
|
constraint__propagate_in_proc(PredId, ProcId, ModuleInfo0, ModuleInfo,
|
|
IoState0, IoState) :-
|
|
module_info_preds(ModuleInfo0, PredTable0),
|
|
map__lookup(PredTable0, PredId, PredInfo0),
|
|
pred_info_procedures(PredInfo0, ProcTable0),
|
|
map__lookup(ProcTable0, ProcId, ProcInfo0),
|
|
|
|
proc_info_goal(ProcInfo0, Goal0),
|
|
proc_info_variables(ProcInfo0, VarSet0),
|
|
varset__vars(VarSet0, VarList),
|
|
set__list_to_set(VarList, VarSet1),
|
|
|
|
proc_info_get_initial_instmap(ProcInfo0, ModuleInfo0, InstMap0),
|
|
proc_info_context(ProcInfo0, Context),
|
|
mode_info_init(IoState0, ModuleInfo0, PredId, ProcId,
|
|
Context, VarSet1, InstMap0, ModeInfo0),
|
|
|
|
constraint__propagate_goal(Goal0, Goal, ModeInfo0, ModeInfo),
|
|
|
|
mode_info_get_io_state(ModeInfo, IoState),
|
|
mode_info_get_varset(ModeInfo, VarSet),
|
|
mode_info_get_var_types(ModeInfo, VarTypes),
|
|
mode_info_get_module_info(ModeInfo, ModuleInfo1),
|
|
|
|
proc_info_set_variables(ProcInfo0, VarSet, ProcInfo1),
|
|
proc_info_set_vartypes(ProcInfo1, VarTypes, ProcInfo2),
|
|
proc_info_set_goal(ProcInfo2, Goal, ProcInfo),
|
|
|
|
map__set(ProcTable0, ProcId, ProcInfo, ProcTable),
|
|
pred_info_set_procedures(PredInfo0, ProcTable, PredInfo),
|
|
map__set(PredTable0, PredId, PredInfo, PredTable),
|
|
module_info_set_preds(ModuleInfo1, PredTable, ModuleInfo).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- pred constraint__propagate_goal(hlds_goal, hlds_goal,
|
|
mode_info, mode_info).
|
|
:- mode constraint__propagate_goal(in, out,
|
|
mode_info_di, mode_info_uo) is det.
|
|
|
|
constraint__propagate_goal(Goal0 - GoalInfo, Goal - GoalInfo) -->
|
|
mode_info_dcg_get_instmap(InstMap0),
|
|
{ goal_info_get_instmap_delta(GoalInfo, DeltaInstMap) },
|
|
{ instmap__apply_instmap_delta(InstMap0, DeltaInstMap, InstMap) },
|
|
mode_info_set_instmap(InstMap),
|
|
constraint__propagate_goal_2(Goal0, Goal),
|
|
mode_info_set_instmap(InstMap).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- pred constraint__propagate_goal_2(hlds_goal_expr, hlds_goal_expr,
|
|
mode_info, mode_info).
|
|
:- mode constraint__propagate_goal_2(in, out,
|
|
mode_info_di, mode_info_uo) is det.
|
|
|
|
constraint__propagate_goal_2(conj(Goals0), conj(Goals)) -->
|
|
mode_checkpoint(enter, "conj"),
|
|
constraint__propagate_conj(Goals0, Goals),
|
|
mode_checkpoint(exit, "conj").
|
|
|
|
constraint__propagate_goal_2(disj(Goals0, SM), disj(Goals, SM)) -->
|
|
mode_checkpoint(enter, "disj"),
|
|
constraint__propagate_disj(Goals0, Goals),
|
|
mode_checkpoint(exit, "disj").
|
|
|
|
constraint__propagate_goal_2(switch(Var, Det, Cases0, SM),
|
|
switch(Var, Det, Cases, SM)) -->
|
|
mode_checkpoint(enter, "switch"),
|
|
constraint__propagate_cases(Cases0, Cases),
|
|
mode_checkpoint(exit, "switch").
|
|
|
|
constraint__propagate_goal_2(if_then_else(Vars, Cond0, Then0, Else0, SM),
|
|
if_then_else(Vars, Cond, Then, Else, SM)) -->
|
|
mode_checkpoint(enter, "if_then_else"),
|
|
mode_info_dcg_get_instmap(InstMap0),
|
|
constraint__propagate_goal(Cond0, Cond),
|
|
% mode_info_dcg_get_instmap(InstMap1),
|
|
constraint__propagate_goal(Then0, Then),
|
|
mode_info_set_instmap(InstMap0),
|
|
constraint__propagate_goal(Else0, Else),
|
|
mode_checkpoint(exit, "if_then_else").
|
|
|
|
constraint__propagate_goal_2(not(Goal0), not(Goal)) -->
|
|
mode_checkpoint(enter, "not"),
|
|
constraint__propagate_goal(Goal0, Goal),
|
|
mode_checkpoint(exit, "not").
|
|
|
|
constraint__propagate_goal_2(some(Vars, Goal0), some(Vars, Goal)) -->
|
|
mode_checkpoint(enter, "some"),
|
|
constraint__propagate_goal(Goal0, Goal),
|
|
mode_checkpoint(exit, "some").
|
|
|
|
constraint__propagate_goal_2(
|
|
higher_order_call(A, B, C, D, E),
|
|
higher_order_call(A, B, C, D, E)) -->
|
|
mode_checkpoint(enter, "higher-order call"),
|
|
mode_checkpoint(exit, "higher-order call").
|
|
|
|
constraint__propagate_goal_2(
|
|
call(PredId, ProcId, ArgVars, Builtin, Sym, Context),
|
|
call(PredId, ProcId, ArgVars, Builtin, Sym, Context)) -->
|
|
mode_checkpoint(enter, "call"),
|
|
mode_checkpoint(exit, "call").
|
|
|
|
constraint__propagate_goal_2(unify(A,B,C,D,E), unify(A,B,C,D,E)) -->
|
|
mode_checkpoint(enter, "unify"),
|
|
mode_checkpoint(exit, "unify").
|
|
|
|
constraint__propagate_goal_2(
|
|
pragma_c_code(A, B, C, D, E, F, G, H),
|
|
pragma_c_code(A, B, C, D, E, F, G, H)) -->
|
|
mode_checkpoint(enter, "pragma_c_code"),
|
|
mode_checkpoint(exit, "pragma_c_code").
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- pred constraint__propagate_disj(list(hlds_goal), list(hlds_goal),
|
|
mode_info, mode_info).
|
|
:- mode constraint__propagate_disj(in, out,
|
|
mode_info_di, mode_info_uo) is det.
|
|
|
|
constraint__propagate_disj([], []) --> [].
|
|
constraint__propagate_disj([Goal0|Goals0], [Goal|Goals]) -->
|
|
mode_info_dcg_get_instmap(InstMap0),
|
|
constraint__propagate_goal(Goal0, Goal),
|
|
mode_info_set_instmap(InstMap0),
|
|
constraint__propagate_disj(Goals0, Goals).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- pred constraint__propagate_cases(list(case), list(case),
|
|
mode_info, mode_info).
|
|
:- mode constraint__propagate_cases(in, out,
|
|
mode_info_di, mode_info_uo) is det.
|
|
|
|
constraint__propagate_cases([], []) --> [].
|
|
constraint__propagate_cases([case(Cons, Goal0)|Goals0],
|
|
[case(Cons, Goal)|Goals]) -->
|
|
mode_info_dcg_get_instmap(InstMap0),
|
|
constraint__propagate_goal(Goal0, Goal),
|
|
mode_info_set_instmap(InstMap0),
|
|
constraint__propagate_cases(Goals0, Goals).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% constraint__propagate_conj detects the constraints in
|
|
% a conjunction and moves them to as early as possible
|
|
% in the list.
|
|
|
|
:- pred constraint__propagate_conj(list(hlds_goal), list(hlds_goal),
|
|
mode_info, mode_info).
|
|
:- mode constraint__propagate_conj(in, out,
|
|
mode_info_di, mode_info_uo) is det.
|
|
|
|
constraint__propagate_conj(Goals0, Goals) -->
|
|
=(ModeInfo0),
|
|
{ mode_info_get_delay_info(ModeInfo0, DelayInfo0) },
|
|
{ delay_info__enter_conj(DelayInfo0, DelayInfo1) },
|
|
mode_info_set_delay_info(DelayInfo1),
|
|
% mode_info_add_goals_live_vars(Goals0),
|
|
|
|
mode_info_dcg_get_instmap(InstMap0),
|
|
constraint__find_constraints(Goals0, Goals1, Constraints1),
|
|
mode_info_set_instmap(InstMap0),
|
|
% constraint__distribute_constraints(Constraints1, Goals1, Goals),
|
|
{ list__append(Constraints1, Goals1, Goals2) },
|
|
transform__reschedule_conj(Goals2, Goals),
|
|
|
|
=(ModeInfo1),
|
|
{ mode_info_get_delay_info(ModeInfo1, DelayInfo2) },
|
|
{ delay_info__leave_conj(DelayInfo2, DelayedGoals, DelayInfo3) },
|
|
mode_info_set_delay_info(DelayInfo3),
|
|
|
|
( { DelayedGoals = [] } ->
|
|
[]
|
|
;
|
|
{ error("constraint__propagate_conj") }
|
|
).
|
|
|
|
:- pred constraint__find_constraints(list(hlds_goal), list(hlds_goal),
|
|
list(constraint), mode_info, mode_info).
|
|
:- mode constraint__find_constraints(in, out, out,
|
|
mode_info_di, mode_info_uo) is det.
|
|
|
|
constraint__find_constraints([], [], []) --> [].
|
|
constraint__find_constraints([Goal0 | Goals0], Goals, Constraints) -->
|
|
mode_info_dcg_get_instmap(InstMap0),
|
|
constraint__propagate_goal(Goal0, Goal1),
|
|
% mode_info_dcg_get_instmap(InstMap1),
|
|
{ Goal1 = Goal1Goal - Goal1Info },
|
|
( { Goal1Goal = conj(Goal1List) } ->
|
|
{ list__append(Goal1List, Goals0, Goals1) },
|
|
mode_info_set_instmap(InstMap0),
|
|
constraint__find_constraints(Goals1, Goals, Constraints)
|
|
;
|
|
constraint__find_constraints(Goals0, Goals1, Constraints0),
|
|
=(ModeInfo),
|
|
( { constraint__is_constraint(Goal1Info, ModeInfo) } ->
|
|
{ Constraints = [Goal1 | Constraints0] },
|
|
{ Goals = Goals1 }
|
|
;
|
|
{ Constraints = Constraints0 },
|
|
{ Goals = [Goal1 | Goals1] }
|
|
)
|
|
).
|
|
|
|
%:- pred constraint__distribute_constraints(list(constraint), list(hlds_goal),
|
|
% list(hlds_goal), mode_info, mode_info).
|
|
%:- mode constraint__distribute_constraints(in, in, out,
|
|
% mode_info_di, mode_info_uo) is det.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- pred constraint__is_constraint(hlds_goal_info, mode_info).
|
|
:- mode constraint__is_constraint(in, mode_info_ui) is semidet.
|
|
|
|
constraint__is_constraint(GoalInfo, ModeInfo) :-
|
|
goal_info_get_determinism(GoalInfo, Det),
|
|
constraint__determinism(Det),
|
|
constraint__no_output_vars(GoalInfo, ModeInfo).
|
|
|
|
:- pred constraint__no_output_vars(hlds_goal_info, mode_info).
|
|
:- mode constraint__no_output_vars(in, mode_info_ui) is semidet.
|
|
|
|
constraint__no_output_vars(GoalInfo, ModeInfo) :-
|
|
goal_info_get_instmap_delta(GoalInfo, InstMapDelta),
|
|
goal_info_get_nonlocals(GoalInfo, Vars),
|
|
mode_info_get_module_info(ModeInfo, ModuleInfo),
|
|
mode_info_get_instmap(ModeInfo, InstMap),
|
|
instmap__no_output_vars(InstMap, InstMapDelta, Vars, ModuleInfo).
|
|
|
|
% constraint__determinism(Det) is true iff Det is
|
|
% a possible determinism of a constraint. The
|
|
% determinisms which use a model_semi code model
|
|
% are obviously constraints. Should erroneous
|
|
% also be treated as a constraint?
|
|
:- pred constraint__determinism(determinism).
|
|
:- mode constraint__determinism(in) is semidet.
|
|
constraint__determinism(semidet).
|
|
constraint__determinism(failure).
|
|
% constraint__determinism(erroneous). % maybe
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- pred mode_info_write_string(string, mode_info, mode_info).
|
|
:- mode mode_info_write_string(in, mode_info_di, mode_info_uo) is det.
|
|
|
|
mode_info_write_string(Msg, ModeInfo0, ModeInfo) :-
|
|
mode_info_get_io_state(ModeInfo0, IOState0),
|
|
io__write_string(Msg, IOState0, IOState),
|
|
mode_info_set_io_state(ModeInfo0, IOState, ModeInfo).
|
|
|
|
:- pred mode_info_write_goal(hlds_goal, int, mode_info, mode_info).
|
|
:- mode mode_info_write_goal(in, in, mode_info_di, mode_info_uo) is det.
|
|
|
|
mode_info_write_goal(Goal, Indent, ModeInfo0, ModeInfo) :-
|
|
mode_info_get_io_state(ModeInfo0, IOState0),
|
|
% globals__io_lookup_bool_option(debug_modes, DoCheckPoint,
|
|
% IOState0, IOState1),
|
|
IOState0 = IOState1,
|
|
( semidet_succeed ->
|
|
mode_info_get_module_info(ModeInfo0, ModuleInfo),
|
|
mode_info_get_varset(ModeInfo0, VarSet),
|
|
hlds_out__write_goal(Goal, ModuleInfo, VarSet, no, Indent, "",
|
|
IOState1, IOState)
|
|
;
|
|
IOState = IOState1
|
|
),
|
|
mode_info_set_io_state(ModeInfo0, IOState, ModeInfo).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%-----------------------------------------------------------------------------%
|