[m-rev.] for review: constraint propagation [2]

Simon Taylor stayl at cs.mu.OZ.AU
Sat Aug 11 03:30:02 AEST 2001


On 05-Aug-2001, Fergus Henderson <fjh at cs.mu.OZ.AU> wrote:
> On 02-Aug-2001, Simon Taylor <stayl at cs.mu.OZ.AU> wrote:
> > % File: constraint.m
> > % Main author: stayl.
> > %
> > % 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.
> 
> s/any goal/any pure goal/
> 
> You should also mention that goals which can loop are not treated as
> constraints.

Done.

> > constraint__propagate_constraints_in_goal(Goal0, Goal) -->
> > 	% We need to strip off any existing constraint markers first.
> > 	% Constraint markers are meant to indicate where a constraint
> > 	% is meant to be attached to a call, and that deforest.m should
> > 	% consider creating a specialized version for the call.
> > 	% If deforest.m rearranges the goal, the constraints may
> > 	% not remain next to the call.
> > 	{ Goal1 = strip_constraint_markers(Goal0) },
> > 	constraint__propagate_goal(Goal1, [], Goal).
> 
> The documentation in the interface doesn't mention anything about
> constraint markers.  It should.

Fixed.

> > constraint__annotate_conj_constraints(ModuleInfo, 
> > 		[Conjunct | RevConjuncts0],
> > 		Constraints0, Goals0, Goals) -->
> > 	{ Goal = GoalExpr - GoalInfo },
> > 	{ goal_info_get_nonlocals(GoalInfo, NonLocals) },
> > 	{ Conjunct = annotated_conjunct(Goal, ChangedVars,
> > 			OutputVars, IncompatibleInstVars) },
> 
> It would help to write the unification Conjunct = ...  before Goal = ...,
> so that the order in the source matches the order in which it will be executed.
Done.
 
> > 	% Find all constraints which depend on the
> > 	% output variables of the goal.
> > :- pred constraint__filter_dependent_constraints(set(prog_var), set(prog_var),
> > 		list(constraint), list(constraint), list(constraint),
> > 		list(constraint), list(constraint)).
> > :- mode constraint__filter_dependent_constraints(in, in, in,
> > 		in, out, in, out) is det.
> >

> I had a lot of difficulty reviewing this predicate.
> More comments would help.
> E.g. document the meaning of the arguments.
> 
> I had difficulty relating the comments in the body to the code.
> There's two categories "ToAttach" and "Others",
> and the comment mentions "reorder"/"don't reorder",
> but it took me quite a while to figure out whether putting something
> in ToAttach meant that it wouldn't get reordered or that it would get
> reordered.  And I'm not sure what each of the two disjuncts in
> the condition of the if-then-else are supposed to be testing.
> 
> Understanding what this code is trying to do is quite complicated and so I
> think it justifies more than the usual level of documentation.

Documentation improved, and some bugs removed.

> I wondered whether `any' insts might cause problems here,
> particularly since `any' matches_initial free and vice versa.

I've changed the code so that it is very conservative with `any' insts
(they are always considered to be outputs).
 
> >  mercury_compile__maybe_deforestation(HLDS0, Verbose, Stats, HLDS) -->
> >       globals__io_lookup_bool_option(deforestation, Deforest),
> > -     ( { Deforest = yes } ->
> > -             maybe_write_string(Verbose, "% Deforestation...\n"),
> > +     globals__io_lookup_bool_option(constraint_propagation, Constraints),
> > +     ( { Deforest = yes ; Constraints = yes } ->
> > +             maybe_write_string(Verbose,
> > +                     "% Deforestation and/or constraint propagation...\n"),
> >               maybe_flush_output(Verbose),
> 
> I think it would be worth changing that to output
> 
> 	"Deforestation"
> 	"Deforestation and constraint propagation"
> or just
> 	"Constraint propagation"
> 
> depending on the option settings, rather than output "and/or".

Done.

Here's a relative diff.

Simon.



Estimated hours taken: 90

Constraint propagation.

compiler/constraint.m:
	Push constraints left and inwards as much as possible
	within a goal. This module has been completely rewritten.

compiler/deforest.m:
	Push constraints within a goal before processing it.

	Make specialized versions for calls with constrained outputs.

	Rerun determinism inference on specialized versions
	when constraint propagation has been run, because the
	determinism can change from nondet to semidet.

compiler/pd_util.m:
	Add pd_util__propagate_constraints, which uses constraint.m
	to push constraints within a goal.

	Add some documentation for the exported predicates.

compiler/pd_term.m:
	Add support for checking termination of the optimization process
	for constraint propagation, which differs from deforestation
	in that the conjunctions selected for optimization don't
	necessarily have a call at both ends.

compiler/pd_debug.m:
	Print some extra information when `--debug-pd' is enabled.

compiler/mercury_compile.m:
	Check whether constraint propagation should be performed when
	working out whether to run the deforestation pass.

compiler/make_hlds.m:
	Add `no_inline' markers to the "recursive" procedures
	introduced for builtins to stop constraint propagation
	attempting to specialize such procedures.

compiler/hlds_pred.m:
	Don't fill in the declared determinism field of the predicates
	introduced by `hlds_pred__define_new_pred', so that rerunning
	determinism inference will compute a more accurate determinism.

compiler/inlining.m:
	Requantify before recomputing instmap_deltas, not after.

compiler/det_analsysis.m:
	Disable reporting of errors and warnings when rerunning
	determinism analysis after constraint propagation.

compiler/options.m:
	Add documentation for `--constraint-propagation'.

	Add option `--local-constraint-propagation', which makes
	deforestation call constraint.m to move constraints within
	a goal, but does not create specialized versions of procedures
	for which there are calls with constrained outputs.

compiler/handle_options.m:
	`--constraint-propagation' implies `--local-constraint-propagation'.

compiler/notes/compiler_design.html:
	Change the documentation to show that constraint.m is now part
	of the deforestation pass.

NEWS:
	Announce the new transformation.

doc/user_guide.texi:
	Document the new options.

tests/hard_coded/Mmakefile:
tests/hard_coded/constraint.{m,exp}:
tests/hard_coded/constraint_order.{m,exp}:
	Test cases.


--- constraint.m.old	Fri Aug 10 17:06:42 2001
+++ constraint.m	Sat Aug 11 03:14:53 2001
@@ -1,5 +1,3 @@
-Index: compiler/constraint.m
-===================================================================
 %-----------------------------------------------------------------------------%
 % Copyright (C) 2001 The University of Melbourne.
 % This file may only be copied under the terms of the GNU General
@@ -11,7 +9,7 @@
 % 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.
+% is any pure goal which has no outputs, can fail and cannot loop.
 %
 %-----------------------------------------------------------------------------%
 
@@ -27,7 +25,8 @@
 	% constraint__propagate_constraints_in_goal pushes constraints
 	% left and inward within a single goal. Specialized versions of
 	% procedures which are called with constrained outputs are created
-	% by deforest.m.
+	% by deforest.m. Goals which deforest.m should try to propagate
+	% into calls are annotated with a `constraint' goal feature.
 :- pred constraint__propagate_constraints_in_goal(hlds_goal, hlds_goal,
 		constraint_info, constraint_info).
 :- mode constraint__propagate_constraints_in_goal(in, out, in, out) is det.
@@ -74,15 +73,11 @@
 	% left of the goal if that is allowed.
 	{ goal_to_conj_list(Goal0, Goals0) },
 	constraint__propagate_conj(Goals0, Constraints, Goals),
-	{ Goals = [Goal1] ->
-		Goal = Goal1
-	;
-		goal_list_nonlocals(Goals, NonLocals),
-		goal_list_instmap_delta(Goals, Delta),
-		goal_list_determinism(Goals, ConjDetism),
-		goal_info_init(NonLocals, Delta, ConjDetism, GoalInfo),
-		conj_list_to_goal(Goals, GoalInfo, Goal)
-	}.
+	{ goal_list_nonlocals(Goals, NonLocals) },
+	{ goal_list_instmap_delta(Goals, Delta) },
+	{ goal_list_determinism(Goals, ConjDetism) },
+	{ goal_info_init(NonLocals, Delta, ConjDetism, GoalInfo) },
+	{ conj_list_to_goal(Goals, GoalInfo, Goal) }.
 
 :- pred constraint__propagate_conj_sub_goal(hlds_goal, list(constraint),
 		hlds_goals, constraint_info, constraint_info).
@@ -243,12 +238,12 @@
 		in, out) is det.
 
 constraint__propagate_conj(Goals0, Constraints, Goals) -->
+	constraint_info_update_changed(Constraints),
 	( { Goals0 = [] } ->
 		{ constraint__flatten_constraints(Constraints, Goals) }
 	; { Goals0 = [Goal0], Constraints = [] } ->
 		constraint__propagate_conj_sub_goal(Goal0, [], Goals)
 	;
-		constraint_info_update_changed(Constraints),
 		InstMap0 =^ instmap,
 		ModuleInfo =^ module_info,
 		VarTypes =^ vartypes,
@@ -272,7 +267,9 @@
 
 	instmap__apply_instmap_delta(InstMap0, InstMapDelta, InstMap),
 	instmap_changed_vars(InstMap0, InstMap, VarTypes,
-		ModuleInfo, ChangedVars),
+		ModuleInfo, ChangedVars0),
+
+	instmap__vars_list(InstMap, InstMapVars),
 
 	% Restrict the set of changed variables down to the set
 	% for which the new inst is not an acceptable subsitute
@@ -286,15 +283,28 @@
 			\+ inst_matches_initial(InstAfter, InstBefore,
 				map__lookup(VarTypes, Var), ModuleInfo)
 		),
-	IncompatibleInstVars = set__filter(InCompatible, ChangedVars), 
+	IncompatibleInstVars = set__list_to_set(
+			list__filter(InCompatible, InstMapVars)),
 
+	%
+	% This will consider variables with inst `any' to be bound by
+	% the goal, so goals which have non-locals with inst `any' will
+	% not be considered to be constraints. XXX This is too conservative.
+	%
 	Bound = (pred(Var::in) is semidet :-
 			instmap__lookup_var(InstMap0, Var, InstBefore),
 			instmap_delta_search_var(InstMapDelta, Var, InstAfter),
 			\+ inst_matches_binding(InstAfter, InstBefore,
 				map__lookup(VarTypes, Var), ModuleInfo)
 		),
-	BoundVars = set__filter(Bound, ChangedVars),
+	BoundVars = set__list_to_set(list__filter(Bound, InstMapVars)),
+
+	% 
+	% Make sure that variables with inst `any' are placed in
+	% the changed vars set. XXX This is too conservative, but
+	% avoids unexpected reorderings.
+	%
+	set__union(ChangedVars0, BoundVars, ChangedVars),
 
 	AnnotatedConjunct = annotated_conjunct(Goal, ChangedVars, BoundVars,
 				IncompatibleInstVars),
@@ -367,10 +377,10 @@
 constraint__annotate_conj_constraints(ModuleInfo, 
 		[Conjunct | RevConjuncts0],
 		Constraints0, Goals0, Goals) -->
-	{ Goal = GoalExpr - GoalInfo },
-	{ goal_info_get_nonlocals(GoalInfo, NonLocals) },
 	{ Conjunct = annotated_conjunct(Goal, ChangedVars,
 			OutputVars, IncompatibleInstVars) },
+	{ Goal = GoalExpr - GoalInfo },
+	{ goal_info_get_nonlocals(GoalInfo, NonLocals) },
 	(
 		% Propagate goals with no output variables which can fail.
 		% Propagating cc_nondet goals would be tricky, because we
@@ -382,6 +392,12 @@
 		{ Detism = semidet
 		; Detism = failure
 		},
+
+		%
+		% XXX This is probably a bit too conservative. For
+		% example, `any->any' moded non-locals are considered
+		% to be outputs.
+		%
 		{ set__empty(OutputVars) },
 
 		% Don't propagate impure goals.
@@ -414,7 +430,12 @@
 	->
 		{ Goals1 = [Goal - [] | Goals0] },
 		constraint__add_constant_construction(ConstructVar, Goal,
-			Constraints0, Constraints1)
+			Constraints0, Constraints1),
+
+		% If the constraint was the only use of the constant,
+		% the old goal can be removed. We need to rerun
+		% quantification to work that out.
+		^ changed := yes
 	;	
 		% Prune away the constraints after a goal
 		% which cannot succeed -- they can never be
@@ -422,6 +443,7 @@
 		{ goal_info_get_determinism(GoalInfo, Detism) },
 		{ determinism_components(Detism, _, at_most_zero) }
 	->
+		constraint_info_update_changed(Constraints0),
 		{ Constraints1 = [] },
 		{ Goals1 = [Goal - [] | Goals0] }	
 	;
@@ -443,22 +465,23 @@
 		{ globals__lookup_bool_option(Globals, fully_strict, yes) }
 	->
 		{ constraint__filter_dependent_constraints(NonLocals,
-			ChangedVars, Constraints0, [], ConstraintsToAttach,
-			[], OtherConstraints) },
-		{ constraint__flatten_constraints(OtherConstraints,
-			ConstraintGoals) },
-		{ list__map(add_empty_constraints, ConstraintGoals,
+			ChangedVars, Constraints0, DependentConstraints,
+			IndependentConstraints) },
+		{ constraint__flatten_constraints(IndependentConstraints,
+			IndependentConstraintGoals) },
+		{ list__map(add_empty_constraints, IndependentConstraintGoals,
 			GoalsAndConstraints) },
 		{ Goals1 = 
-			[attach_constraints(Goal, ConstraintsToAttach)
+			[attach_constraints(Goal, DependentConstraints)
 				| GoalsAndConstraints]
 			++ Goals0 },
 		{ Constraints1 = [] }
 	;
 		{ constraint__filter_dependent_constraints(NonLocals,
-			OutputVars, Constraints0, [], ConstraintsToAttach,
-			[], Constraints1) },
-		{ Goals1 = [attach_constraints(Goal, ConstraintsToAttach)
+			OutputVars, Constraints0, DependentConstraints,
+			IndependentConstraints) },
+		{ Constraints1 = IndependentConstraints },
+		{ Goals1 = [attach_constraints(Goal, DependentConstraints)
 				| Goals0] }
 	),
 	constraint__annotate_conj_constraints(ModuleInfo, RevConjuncts0, 
@@ -530,41 +553,73 @@
 
 %-----------------------------------------------------------------------------%
 
-	% Find all constraints which depend on the
-	% output variables of the goal.
+	% constraints__filter_dependent_constraints(GoalNonLocals,
+	%	GoalOutputVars, Constraints, DependentConstraints,
+	% 	IndependentConstraints)
+	%
+	% Find all constraints which depend on the output variables
+	% of the current goal in the conjunction being processed.
+	% The DependentConstraints should be pushed into the current goal.
+	% The IndependentConstraints should be moved to the left of
+	% the current goal, if the purity and termination properties
+	% of the current goal allow that.
+:- pred constraint__filter_dependent_constraints(set(prog_var), set(prog_var),
+		list(constraint), list(constraint), list(constraint)).
+:- mode constraint__filter_dependent_constraints(in, in, in,
+		out, out) is det.
+
+constraint__filter_dependent_constraints(NonLocals, GoalOutputVars,
+		Constraints, Dependent, Independent) :-
+	constraint__filter_dependent_constraints(NonLocals, GoalOutputVars,
+		Constraints, [], Dependent, [], Independent).
+
 :- pred constraint__filter_dependent_constraints(set(prog_var), set(prog_var),
 		list(constraint), list(constraint), list(constraint),
 		list(constraint), list(constraint)).
 :- mode constraint__filter_dependent_constraints(in, in, in,
 		in, out, in, out) is det.
 
-constraint__filter_dependent_constraints(_NonLocals, _Vars, [],
-		RevToAttach, ToAttach, RevOthers, Others) :-
-	list__reverse(RevToAttach, ToAttach),
-	list__reverse(RevOthers, Others).
+constraint__filter_dependent_constraints(_NonLocals, _OutputVars, [],
+		RevDependent, Dependent, RevIndependent, Independent) :-
+	list__reverse(RevDependent, Dependent),
+	list__reverse(RevIndependent, Independent).
 constraint__filter_dependent_constraints(NonLocals, GoalOutputVars,
-		[Constraint | Goals], ToAttach0, ToAttach, Others0, Others) :-
+		[Constraint | Constraints], Dependent0, Dependent,
+		Independent0, Independent) :-
 	Constraint = constraint(ConstraintGoal, _, IncompatibleInstVars, _),
 	ConstraintGoal = _ - ConstraintGoalInfo,
 	goal_info_get_nonlocals(ConstraintGoalInfo, ConstraintNonLocals),
-	set__intersect(ConstraintNonLocals, GoalOutputVars,
-		OutputVarsUsedByConstraint),
 
-	% Don't reorder a constraint which changes the inst of
-	% a variable in such a way that the new inst is incompatible
-	% with the old inst (e.g. by losing uniqueness),
-	% with any goal which has that variable in its non-locals set.
-	%
-	% Don't reorder a constraint with another constraint which
-	% changes the instantiatedness of one of its input variables.
-	set__intersect(NonLocals, IncompatibleInstVars,
-		IncompatibleInstVarsUsedByGoal),
 	(
 		(
-			set__empty(OutputVarsUsedByConstraint),
-			set__empty(IncompatibleInstVarsUsedByGoal)
+			%
+			% A constraint is not independent of a goal
+			% if it uses any of the output variables
+			% of that goal.
+			%
+			set__intersect(ConstraintNonLocals, GoalOutputVars,
+				OutputVarsUsedByConstraint),
+			\+ set__empty(OutputVarsUsedByConstraint)
+		;
+			%
+			% A constraint is not independent of a goal
+			% if it changes the inst of a non-local of the goal
+			% in such a way that the new inst is incompatible
+			% with the old inst (e.g. by losing uniqueness),
+			%
+			set__intersect(NonLocals, IncompatibleInstVars,
+				IncompatibleInstVarsUsedByGoal),
+			\+ set__empty(IncompatibleInstVarsUsedByGoal)
 		;
-			list__member(EarlierConstraint, ToAttach0),
+			% 
+			% A constraint is not independent of a goal if
+			% it uses any variables whose instantiatedness is
+			% changed by any the of the constraints already
+			% attached to the goal (the dependent constraints
+			% will be attached to the goal to be pushed into
+			% it by constraint__propagate_conj_sub_goal).
+			%
+			list__member(EarlierConstraint, Dependent0),
 			EarlierConstraint = constraint(_,
 				EarlierChangedVars, _, _),
 			set__intersect(EarlierChangedVars, ConstraintNonLocals,
@@ -572,14 +627,14 @@
 			\+ set__empty(EarlierConstraintIntersection)
 		)
 	->
-		Others1 = [Constraint | Others0],
-		ToAttach1 = ToAttach0
+		Independent1 = Independent0,
+		Dependent1 = [Constraint | Dependent0]
 	;
-		Others1 = Others0,
-		ToAttach1 = [Constraint | ToAttach0]
+		Independent1 = [Constraint | Independent0],
+		Dependent1 = Dependent0
 	),
 	constraint__filter_dependent_constraints(NonLocals, GoalOutputVars,
-		Goals, ToAttach1, ToAttach, Others1, Others).
+		Constraints, Dependent1, Dependent, Independent1, Independent).
 	
 %-----------------------------------------------------------------------------%
 
diff -u compiler/deforest.m compiler/deforest.m
--- compiler/deforest.m
+++ compiler/deforest.m
@@ -103,7 +103,9 @@
 		% become semidet.
 		list__foldl(reset_inferred_proc_determinism, Versions,
 			ModuleInfo4, ModuleInfo5),
-		determinism_pass(ModuleInfo5, ModuleInfo, IO3, IO)	
+		ReportErrors = no,
+		determinism_pass(ReportErrors,
+			ModuleInfo5, ModuleInfo, IO3, IO)	
 	;
 		IO = IO3,
 		ModuleInfo = ModuleInfo4
diff -u compiler/mercury_compile.m compiler/mercury_compile.m
--- compiler/mercury_compile.m
+++ compiler/mercury_compile.m
@@ -2168,7 +2168,7 @@
 
 mercury_compile__check_determinism(HLDS0, Verbose, Stats, HLDS, FoundError) -->
 	{ module_info_num_errors(HLDS0, NumErrors0) },
-	determinism_pass(HLDS0, HLDS),
+	determinism_pass(yes, HLDS0, HLDS),
 	{ module_info_num_errors(HLDS, NumErrors) },
 	( { NumErrors \= NumErrors0 } ->
 		{ FoundError = yes },
@@ -2567,10 +2567,21 @@
 
 mercury_compile__maybe_deforestation(HLDS0, Verbose, Stats, HLDS) -->
 	globals__io_lookup_bool_option(deforestation, Deforest),
-	globals__io_lookup_bool_option(constraint_propagation, Constraints),
+
+	% --constraint-propagation implies --local-constraint-propagation.
+	globals__io_lookup_bool_option(local_constraint_propagation,
+		Constraints),
 	( { Deforest = yes ; Constraints = yes } ->
-		maybe_write_string(Verbose,
-			"% Deforestation and/or constraint propagation...\n"),
+		{ Deforest = no, Constraints = no, 
+			error("mercury_compile__maybe_deforestation")
+		; Deforest = yes, Constraints = yes,
+			Msg = "% Deforestation and constraint propagation...\n"
+		; Deforest = yes, Constraints = no,
+			Msg = "% Deforestation...\n"
+		; Deforest = no, Constraints = yes,
+			Msg = "% Constraint propagation...\n"
+		},
+		maybe_write_string(Verbose, Msg),
 		maybe_flush_output(Verbose),
 		deforestation(HLDS0, HLDS),
 		maybe_write_string(Verbose, "% done.\n"),
diff -u compiler/pd_util.m compiler/pd_util.m
--- compiler/pd_util.m
+++ compiler/pd_util.m
@@ -159,6 +159,7 @@
 		ConstraintProp),
 	( { ConstraintProp = yes } ->
 		pd_debug__message("%% Propagating constraints\n", []),
+		pd_debug__output_goal("before constraints\n", Goal0),	
 		pd_info_get_module_info(ModuleInfo0),
 		pd_info_get_proc_info(ProcInfo0),
 		pd_info_get_instmap(InstMap),
@@ -166,6 +167,8 @@
 		{ proc_info_varset(ProcInfo0, VarSet0) },
 		{ constraint_info_init(ModuleInfo0, VarTypes0,
 			VarSet0, InstMap, CInfo0) },
+		{ Goal0 = _ - GoalInfo0 },
+		{ goal_info_get_nonlocals(GoalInfo0, NonLocals) },
 		{ constraint__propagate_constraints_in_goal(Goal0, Goal1,
 			CInfo0, CInfo) },
 		{ constraint_info_deconstruct(CInfo, ModuleInfo,
@@ -177,9 +180,7 @@
 		( { Changed = yes } ->
 			pd_debug__output_goal(
 				"after constraints, before recompute\n",
-				Goal1),	
-			{ Goal1 = _ - GoalInfo1 },
-			{ goal_info_get_nonlocals(GoalInfo1, NonLocals) },
+				Goal1),
 			pd_util__requantify_goal(Goal1, NonLocals, Goal2),
 			pd_util__recompute_instmap_delta(Goal2, Goal3),
 			pd_util__rerun_det_analysis(Goal3, Goal4),
diff -u doc/user_guide.texi doc/user_guide.texi
--- doc/user_guide.texi
+++ doc/user_guide.texi
@@ -4771,6 +4771,8 @@
 Optimization level -1 disables all optimizations,
 while optimization level 6 enables all optimizations
 except for the cross-module optimizations listed below.
+Some experimental optimizations (for example constraint
+propagation) are not be enabled at any optimization level.
 
 In general, there is a trade-off between compilation speed and the
 speed of the generated code.  When developing, you should normally use
@@ -4839,18 +4841,9 @@
 Disabling this optimization reduces the class of predicates
 that the compiler considers to be deterministic.
 
 @item --constraint-propagation
 @findex --constraint-propagation
-"--constraint-propagation",
 Enable the constraint propagation transformation,
 which attempts to transform the code so that goals
 which can fail are executed as early as possible.
diff -u constraint_order.exp constraint_order.exp
--- constraint_order.exp
+++ constraint_order.exp
@@ -1,3 +1,3 @@
-call to test
 call to q
+call to test
 succeeded: 1
only in patch2:
--- compiler/det_analysis.m	2001/04/07 14:04:34	1.150
+++ compiler/det_analysis.m	2001/08/07 10:52:08
@@ -55,13 +55,15 @@
 :- import_module prog_data.
 :- import_module hlds_goal, hlds_module, hlds_pred, hlds_data, instmap.
 :- import_module det_report, det_util, globals.
-:- import_module list, std_util, io.
+:- import_module bool, list, std_util, io.
 
+	% determinism_pass(ReportErrors, ModuleInfo0, ModuleInfo).
+	%
 	% Perform determinism inference for local predicates with no
 	% determinism declarations, and determinism checking for all other
 	% predicates.
-:- pred determinism_pass(module_info, module_info, io__state, io__state).
-:- mode determinism_pass(in, out, di, uo) is det.
+:- pred determinism_pass(bool, module_info, module_info, io__state, io__state).
+:- mode determinism_pass(in, in, out, di, uo) is det.
 
 	% Check the determinism of a single procedure
 	% (only works if the determinism of the procedures it calls
@@ -127,7 +129,7 @@
 
 %-----------------------------------------------------------------------------%
 
-determinism_pass(ModuleInfo0, ModuleInfo) -->
+determinism_pass(ReportErrors, ModuleInfo0, ModuleInfo) -->
 	{ determinism_declarations(ModuleInfo0, DeclaredProcs,
 		UndeclaredProcs, NoInferProcs) },
 	{ list__foldl(set_non_inferred_proc_determinism, NoInferProcs,
@@ -144,12 +146,13 @@
 		maybe_write_string(Verbose, "% done.\n")
 	),
 	maybe_write_string(Verbose, "% Doing determinism checking...\n"),
-	global_final_pass(ModuleInfo2, DeclaredProcs, Debug, ModuleInfo),
+	global_final_pass(ReportErrors, ModuleInfo2,
+		DeclaredProcs, Debug, ModuleInfo),
 	maybe_write_string(Verbose, "% done.\n").
 
 determinism_check_proc(ProcId, PredId, ModuleInfo0, ModuleInfo) -->
 	globals__io_lookup_bool_option(debug_det, Debug),
-	global_final_pass(ModuleInfo0, [proc(PredId, ProcId)], Debug,	
+	global_final_pass(yes, ModuleInfo0, [proc(PredId, ProcId)], Debug,	
 		ModuleInfo).
 
 %-----------------------------------------------------------------------------%
@@ -219,15 +222,19 @@
 	global_inference_single_pass(PredProcs, Debug,
 		ModuleInfo1, ModuleInfo, Msgs1, Msgs, Changed1, Changed).
 
-:- pred global_final_pass(module_info, pred_proc_list, bool,
+:- pred global_final_pass(bool, module_info, pred_proc_list, bool,
 	module_info, io__state, io__state).
-:- mode global_final_pass(in, in, in, out, di, uo) is det.
+:- mode global_final_pass(in, in, in, in, out, di, uo) is det.
 
-global_final_pass(ModuleInfo0, ProcList, Debug, ModuleInfo) -->
+global_final_pass(ReportErrors, ModuleInfo0, ProcList, Debug, ModuleInfo) -->
 	global_inference_single_pass(ProcList, Debug, ModuleInfo0, ModuleInfo1,
 		[], Msgs, unchanged, _),
-	det_report_and_handle_msgs(Msgs, ModuleInfo1, ModuleInfo2),
-	global_checking_pass(ProcList, ModuleInfo2, ModuleInfo).
+	( { ReportErrors = yes } ->
+		det_report_and_handle_msgs(Msgs, ModuleInfo1, ModuleInfo2),
+		global_checking_pass(ProcList, ModuleInfo2, ModuleInfo)
+	;
+		{ ModuleInfo = ModuleInfo1 }
+	).
 
 %-----------------------------------------------------------------------------%
 
--------------------------------------------------------------------------
mercury-reviews mailing list
post:  mercury-reviews at cs.mu.oz.au
administrative address: owner-mercury-reviews at cs.mu.oz.au
unsubscribe: Address: mercury-reviews-request at cs.mu.oz.au Message: unsubscribe
subscribe:   Address: mercury-reviews-request at cs.mu.oz.au Message: subscribe
--------------------------------------------------------------------------



More information about the reviews mailing list