[m-dev.] for review: recognise associativity assertions

Peter Ross petdr at cs.mu.OZ.AU
Fri Dec 24 14:16:46 AEDT 1999


On 20-Dec-1999, Fergus Henderson <fjh at cs.mu.OZ.AU> wrote:
> On 20-Dec-1999, Peter Ross <petdr at cs.mu.OZ.AU> wrote:
> > 
> > Is it alright to check this code in?
> 
> I'd like to see a diff for your updated changes first
> (preferably both a relative diff and complete diff).
> 

Here is the relative diff of my changes followed by the full diff (the
changes to the test directory are at the end).

--- accumulator.m.old	Thu Dec 23 17:24:19 1999
+++ accumulator.m	Fri Dec 24 13:15:41 1999
@@ -242,7 +242,7 @@
 			{ pred_info_context(PredInfo, Context) },
 
 			error_util__write_error_pieces(Context, 0,
-					[words("In the"), words(PredName)]),
+					[words("The"), words(PredName)]),
 
 			{ proc_info_varset(ProcInfo, VarSet) },
 			accumulator__warnings(Warnings, VarSet, ModuleInfo1),
@@ -254,15 +254,50 @@
 					words("do not introduce"),
 					words("performance problems."),
 					words("These warnings can"),
-					words("be supressed by"),
-					words("--inhibit-accumulator-warnings.")
+					words("be suppressed by"),
+					words("`--inhibit-accumulator-warnings'.")
 					]),
 
+			globals__io_lookup_bool_option(verbose_errors,
+					VerboseErrors),
+			(
+				{ VerboseErrors = yes }
+			->
+				error_util__write_error_pieces(Context, 2, 
+					[
+					words("If a predicate has been"),
+					words("declared associative via"),
+					words("a promise declaration,"),
+					words("the compiler will"),
+					words("rearrange the order"),
+					words("of the arguments"),
+					words("in calls to that"),
+					words("predicate, if by so doing"),
+					words("it makes the containing"),
+					words("predicate tail recursive."),
+					words("In such situations, the"),
+					words("compiler will issue"),
+					words("this warning."),
+					words("If this reordering changes the"),
+					words("performance characteristics"),
+					words("of the call to the"),
+					words("predicate, use"),
+					words("`--no-accumulator-introduction'"),
+					words("to turn the optimization"),
+					words("off, or"),
+					words("`--inhibit-accumulator-warnings'"),
+					words("to turn off the warnings.")
+					])
+			;
+				[]
+			),
+
 			globals__io_lookup_bool_option(halt_at_warn,
 					HaltAtWarn),
 			(
 				{ HaltAtWarn = yes }
 			->
+				io__set_exit_status(1),
 				{ module_info_incr_errors(ModuleInfo1,
 						ModuleInfo) }
 			;
@@ -327,7 +362,7 @@
 	error_util__describe_one_pred_name(ModuleInfo, PredId, PredStr),
 	varset__lookup_name(VarSet, VarA, VarAStr),
 	varset__lookup_name(VarSet, VarB, VarBStr),
-	Formats = [words("warning: The"), words(PredStr),
+	Formats = [words("warning: the call to"), words(PredStr),
 			words("has had the location of the variables"),
 			words(VarAStr), words("and"), words(VarBStr),
 			words("swapped to allow accumulator introduction.")
--- assertion.m.old	Thu Dec 23 17:24:19 1999
+++ assertion.m	Thu Dec 23 17:20:15 1999
@@ -189,7 +189,9 @@
 		% If you read the predicate documentation, you will note
 		% that for each pair of variables on the left hand side
 		% their is an equivalent pair of variables on the right
-		% hand side.
+		% hand side.  As the pairs of variables are not
+		% symmetric, the call to list__perm will only succeed
+		% once, if at all.
 	assoc_list__from_corresponding_lists(PairsL, PairsR, Pairs),
 	list__perm(Pairs, [(A - AB) - (B - A), (B - C) - (C - BC),
 			(AB - ABC) - (BC - ABC)]),


===================================================================


Estimated hours taken: 35

Recognise associativity assertions, and use them to introduce
accumulators.

mercury/compiler/assertion.m:
    Add assertion__is_associativity_assertion, which for an assert_id
    determines whether the assertion is associative.
    
mercury/compiler/accumulator.m:
    Call assertion__is_associativity_assertion to determine whether a
    call is associative.
    Rather than failing if a call is associative and nothing is known
    about the effect of rearranging the argument order, report a
    suppressible warning.
    Fix a bug where the mode of the introduced pred wasn't correct.
    
mercury/compiler/mercury_compile.m:
    Move accumulator introduction before inlining and unused_args, as
    inlining can inline an associative call making it unrecognisable and
    unused_args eliminates arguments which make it difficult to relate
    the assertion with the actual call.

mercury/compiler/notes/compiler_design.html:
    Document the constraints on when the module accumulator.m can be
    called for it to be effective.

mercury/compiler/options.m:
    Add the new option "--inhibit-accumulator-warnings".

mercury/doc/user_guide.texi:
    Document "--inhibit-accumulator-warnings".

mercury/library/list.m:
    Declare list__append to be associative.

tests/general/accumulator/runtests:
    Turn the tests back on, they *should* work under different
    optimization levels now.

tests/warnings/Mmakefile:
tests/warnings/arg_order_rearrangment.exp:
tests/warnings/arg_order_rearrangment.m:
    Test that a warning is output when accumulator introduction reorders
    the arguments to a call without knowing the performance
    implications.

Index: promise/compiler/accumulator.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/accumulator.m,v
retrieving revision 1.7
diff -u -r1.7 accumulator.m
--- promise/compiler/accumulator.m	1999/09/12 04:26:36	1.7
+++ promise/compiler/accumulator.m	1999/12/24 02:15:41
@@ -95,8 +95,8 @@
 
 :- implementation.
 
-:- import_module (assertion), goal_util, globals.
-:- import_module hlds_data, hlds_goal, hlds_out.
+:- import_module (assertion), error_util, goal_util, globals.
+:- import_module hlds_data, hlds_goal, hlds_out, (inst).
 :- import_module inst_match, instmap, mode_util, options, prog_data, prog_util.
 
 :- import_module assoc_list, bool, list, map, multi_map.
@@ -163,9 +163,17 @@
 			orig_dynvar_map,
 			subst,		% Y0s -> As
 			subst,		% Hs -> As
-			set(prog_var)	% Ys
+			set(prog_var),	% Ys
+			warnings
 		).
 
+:- type warning 
+			% warn that two prog_vars in call to pred_id
+			% at prog_context were swapped.
+	--->	w(prog_context, pred_id, prog_var, prog_var).
+
+:- type warnings == list(warning).
+
 	% is the pred commutative?
 :- type commutative == bool.
 
@@ -209,7 +217,7 @@
 		{ module_info_pred_info(ModuleInfo0, PredId, PredInfo) },
 		{ accumulator__attempt_transform(ProcId, ProcInfo0, PredId,
 				PredInfo, DoLCO, FullyStrict, ModuleInfo0,
-				ProcInfo1, ModuleInfo1) }
+				Warnings, ProcInfo1, ModuleInfo1) }
 	->
 		globals__io_lookup_bool_option(very_verbose, VeryVerbose),
 		( 
@@ -222,8 +230,81 @@
 			[]
 		),
 
-		{ ProcInfo   = ProcInfo1 },
-		{ ModuleInfo = ModuleInfo1 }
+		globals__io_lookup_bool_option(inhibit_accumulator_warnings,
+				InhibitWarnings),
+		(
+			( { Warnings = [] } ; { InhibitWarnings = yes } )
+		->
+			{ ModuleInfo = ModuleInfo1 }
+		;
+			{ error_util__describe_one_pred_name(ModuleInfo1,
+					PredId, PredName) },
+			{ pred_info_context(PredInfo, Context) },
+
+			error_util__write_error_pieces(Context, 0,
+					[words("The"), words(PredName)]),
+
+			{ proc_info_varset(ProcInfo, VarSet) },
+			accumulator__warnings(Warnings, VarSet, ModuleInfo1),
+
+			error_util__write_error_pieces(Context, 2, 
+					[
+					words("Please ensure that these"),
+					words("argument rearrangements"),
+					words("do not introduce"),
+					words("performance problems."),
+					words("These warnings can"),
+					words("be suppressed by"),
+					words("`--inhibit-accumulator-warnings'.")
+					]),
+
+			globals__io_lookup_bool_option(verbose_errors,
+					VerboseErrors),
+			(
+				{ VerboseErrors = yes }
+			->
+				error_util__write_error_pieces(Context, 2, 
+					[
+					words("If a predicate has been"),
+					words("declared associative via"),
+					words("a promise declaration,"),
+					words("the compiler will"),
+					words("rearrange the order"),
+					words("of the arguments"),
+					words("in calls to that"),
+					words("predicate, if by so doing"),
+					words("it makes the containing"),
+					words("predicate tail recursive."),
+					words("In such situations, the"),
+					words("compiler will issue"),
+					words("this warning."),
+					words("If this reordering changes the"),
+					words("performance characteristics"),
+					words("of the call to the"),
+					words("predicate, use"),
+					words("`--no-accumulator-introduction'"),
+					words("to turn the optimization"),
+					words("off, or"),
+					words("`--inhibit-accumulator-warnings'"),
+					words("to turn off the warnings.")
+					])
+			;
+				[]
+			),
+
+			globals__io_lookup_bool_option(halt_at_warn,
+					HaltAtWarn),
+			(
+				{ HaltAtWarn = yes }
+			->
+				io__set_exit_status(1),
+				{ module_info_incr_errors(ModuleInfo1,
+						ModuleInfo) }
+			;
+				{ ModuleInfo = ModuleInfo1 }
+			)
+		),
+		{ ProcInfo   = ProcInfo1 }
 	;
 		{ ProcInfo   = ProcInfo0 },
 		{ ModuleInfo = ModuleInfo0 }
@@ -236,10 +317,10 @@
 	%
 :- pred accumulator__attempt_transform(proc_id::in, proc_info::in,
 		pred_id::in, pred_info::in, bool::in, bool::in, module_info::in,
-		proc_info::out, module_info::out) is semidet.
+		warnings::out, proc_info::out, module_info::out) is semidet.
 
 accumulator__attempt_transform(ProcId, ProcInfo0, PredId, PredInfo0, DoLCO,
-		FullyStrict, ModuleInfo0, ProcInfo, ModuleInfo) :-
+		FullyStrict, ModuleInfo0, Warnings, ProcInfo, ModuleInfo) :-
 	proc_info_goal(ProcInfo0, Goal0),
 	proc_info_headvars(ProcInfo0, HeadVars),
 	proc_info_get_initial_instmap(ProcInfo0, ModuleInfo0, InitialInstMap),
@@ -254,7 +335,7 @@
 
 	accumulator__transform(GoalType, Base, Rec, Goal, DoLCO, FullyStrict,
 			ModuleInfo1, HeadVars, HstoAs_Subst, NewPredId,
-			NewProcId, NewPredName, OrigGoal, AccGoal),
+			NewProcId, NewPredName, OrigGoal, Warnings, AccGoal),
 
 	accumulator__update_accumulator_pred(NewPredId, NewProcId, AccGoal,
 			ModuleInfo1, ModuleInfo),
@@ -264,6 +345,33 @@
 %-----------------------------------------------------------------------------%
 %-----------------------------------------------------------------------------%
 
+:- pred accumulator__warnings(list(warning)::in, prog_varset::in,
+		module_info::in, io__state::di, io__state::uo) is det.
+
+accumulator__warnings([], _, _) --> [].
+accumulator__warnings([W | Ws], VarSet, ModuleInfo) -->
+	{ accumulator__warning(W, VarSet, ModuleInfo, Context, Format) },
+	error_util__write_error_pieces(Context, 2, Format),
+	accumulator__warnings(Ws, VarSet, ModuleInfo).
+
+:- pred accumulator__warning(warning::in, prog_varset::in, module_info::in,
+		prog_context::out, list(format_component)::out) is det.
+
+accumulator__warning(w(Context, PredId, VarA, VarB), VarSet, ModuleInfo,
+		Context, Formats) :-
+	error_util__describe_one_pred_name(ModuleInfo, PredId, PredStr),
+	varset__lookup_name(VarSet, VarA, VarAStr),
+	varset__lookup_name(VarSet, VarB, VarBStr),
+	Formats = [words("warning: the call to"), words(PredStr),
+			words("has had the location of the variables"),
+			words(VarAStr), words("and"), words(VarBStr),
+			words("swapped to allow accumulator introduction.")
+			].
+
+
+%-----------------------------------------------------------------------------%
+%-----------------------------------------------------------------------------%
+
 	%
 	% accumulator__simplify
 	%
@@ -549,7 +657,13 @@
 	map__lookup(VarTypes0, Var, Type),
 	map__det_insert(VarTypes1, NewVar, Type, VarTypes),
 
-	instmap__lookup_var(InstMap, Var, Inst),
+		% XXX we don't want to use the inst of the var as it can
+		% be more specific than it should be. ie int_const(1)
+		% when it should be any integer.
+		% However this will no longer handle partially
+		% instantiated data structures.
+	% instmap__lookup_var(InstMap, Var, Inst),
+	Inst = ground(shared, no),
 	inst_lists_to_mode_list([Inst], [Inst], Mode),
 	list__append(Mode, Modes0, Modes).
 
@@ -605,11 +719,12 @@
 		hlds_goal::in, bool::in, bool::in, module_info::in,
 		prog_vars::in, subst::in, pred_id::in,
 		proc_id::in, sym_name::in,
-		hlds_goal::out, hlds_goal::out) is semidet.
+		hlds_goal::out, warnings::out, hlds_goal::out) is semidet.
 
 accumulator__transform(TopLevel, base(BaseGoalList), recursive(PreDP, DP, R, C),
-		Goal, DoLCO, FullyStrict, ModuleInfo, HeadVars, HstoAs_Subst,
-		NewPredId, NewProcId, NewPredName, OrigGoal, NewGoal) :-
+		Goal, DoLCO, FullyStrict, ModuleInfo, HeadVars,
+		HstoAs_Subst, NewPredId, NewProcId, NewPredName,
+		OrigGoal, Warnings, NewGoal) :-
 
 	accumulator__Ys_descended_from_Y0s(HeadVars, DP, ModuleInfo),
 
@@ -623,8 +738,8 @@
 			Y0stoYs_Subst, HstoAs_Subst, NewBaseGoal),
 	accumulator__new_recursive_case(DP, C, R, DoLCO, FullyStrict,
 			ModuleInfo, NewPredId, NewProcId, NewPredName,
-			Vars, HeadVars,
-			Y0stoYs_Subst, HstoAs_Subst, NewRecGoal),
+			Vars, HeadVars, Y0stoYs_Subst, HstoAs_Subst,
+			Warnings, NewRecGoal),
 
 	accumulator__top_level(TopLevel, Goal, OrigBaseGoal, OrigRecGoal,
 			NewBaseGoal, NewRecGoal, OrigGoal, NewGoal).
@@ -1073,11 +1188,11 @@
 		a_goal::in, bool::in, bool::in,
 		module_info::in, pred_id::in, proc_id::in,
 		sym_name::in, prog_vars::in, prog_vars::in, subst::in,
-		subst::in, hlds_goal::out) is semidet.
+		subst::in, warnings::out, hlds_goal::out) is semidet.
 
 accumulator__new_recursive_case(DP, C, R0, DoLCO, FullyStrict,
 		ModuleInfo, PredId, ProcId, Name, Hs, HeadVars,
-		Y0stoYs_Subst, HstoAs_Subst, Goal) :-
+		Y0stoYs_Subst, HstoAs_Subst, Warnings, Goal) :-
 	DP = goal(DecomposeProcess, _InstMapBeforeDecomposeProcess),
 	C  = goal(Compose, InstMapBeforeCompose),
 	R0 = goal(Recursive0, _InstMapBeforeRecursive0),
@@ -1107,6 +1222,7 @@
 	),
 
 	assoc_info_Y0stoAs(Y0stoAs_Subst, AssocInfo, _),
+	assoc_info_warnings(Warnings, AssocInfo, _),
 
 	accumulator__rename_prerec_goals(PreRecGoal0, Y0stoAs_Subst,
 			Y0stoYs_Subst, LCO_Subst, HstoAs_Subst, PreRecGoal),
@@ -1347,21 +1463,10 @@
 	assoc_info_module_info(ModuleInfo),
 	accumulator__call_dynamic_var(Arg0s, DynamicCallVar),
 
-	{ accumulator__is_associative(PredId, ProcId, ModuleInfo, Arg0s, Args,
-		PossibleStaticVars, Commutative) },
+	{ goal_info_get_context(GoalInfo, ProgContext) },
+	accumulator__is_associative(PredId, ProcId, ProgContext, ModuleInfo,
+			Arg0s, Args, PossibleStaticVars, Commutative),
 
-	(
-			% Make sure that after rearrangement of the
-			% arguments the new proc will be at least as
-			% efficient as the old pred.
-		{ Commutative = no },
-		assoc_info_static_set(StaticSet),
-		{ accumulator__obey_heuristic(PredId, ModuleInfo,
-				Args, StaticSet) }
-	;
-		{ Commutative = yes }
-	),
-
 	accumulator__check_previous_calls(DynamicCallVar,
 			PredId, ProcId, Commutative),
 	accumulator__new_dynamic_var(Arg0s, DynamicCallVar, NewDynamicVar),
@@ -1630,12 +1735,14 @@
 	% and an indicator of whether or not the predicate is
 	% commutative.
 	%
-:- pred accumulator__is_associative(pred_id::in, proc_id::in, module_info::in,
-		prog_vars::in, prog_vars::out, set(prog_var)::out,
-		commutative::out) is semidet.
+:- pred accumulator__is_associative(pred_id::in, proc_id::in, prog_context::in,
+		module_info::in, prog_vars::in, prog_vars::out,
+		set(prog_var)::out, commutative::out,
+		assoc_info::in, assoc_info::out) is semidet.
 
-accumulator__is_associative(PredId, ProcId, ModuleInfo,
-		Args0, Args, PossibleStaticVars, Commutative):-
+accumulator__is_associative(PredId, ProcId, Context, ModuleInfo,
+		Args0, Args, PossibleStaticVars, Commutative,
+		AssocInfo0, AssocInfo):-
 	module_info_pred_proc_info(ModuleInfo, PredId, ProcId, 
 			PredInfo, ProcInfo),
 
@@ -1649,19 +1756,85 @@
 		check_modes(Args0, PossibleStaticVars0, Modes, ModuleInfo),
 		Args = Args0,
 		PossibleStaticVars = PossibleStaticVars0,
+		AssocInfo = AssocInfo0,
 		Commutative = yes
 	;
+		associativity_assertion(set__to_sorted_list(Assertions),
+				ModuleInfo, Args0, VarA - VarB),
+
+		PossibleStaticVars = set__list_to_set([VarA, VarB]),
+
+			% Swap the order of the arguments
+		list__map((pred(V0::in, V::out) is det :-
+				(
+					V0 = VarA
+				->
+					V = VarB
+				;
+					V0 = VarB
+				->
+					V = VarA
+				;
+					V = V0
+				)
+			), Args0, Args),
 
-			% Check if it is associative
+		check_modes(Args, PossibleStaticVars, Modes, ModuleInfo),
+
+			% Determine what variables can be static
 		pred_info_module(PredInfo, ModuleName),
 		pred_info_name(PredInfo, PredName),
 		pred_info_arity(PredInfo, Arity),
-
-		assoc_fact(ModuleName, PredName, Arity, Modes,
-				ModuleInfo, Args0, Args, PossibleStaticVars),
+		(
+			has_heuristic(ModuleName, PredName, Arity)
+		->
+				% If there is a heuristic for that call
+				% then ensure that the call obeys
+				% the heuristic that the static
+				% variables are in certain positions.
+				%
+				% For example, a call to append in the
+				% forward mode will have the following
+				% types of variables: (static, dynamic,
+				% dynamic).  After rearrangment that
+				% order will be (dynamic, static,
+				% dynamic).  Having a dynamic variable
+				% in the first position will probably
+				% take O(N) time to process while having
+				% a static variable will probably take
+				% O(1) time.  Therefore the complexity
+				% of the predicate as a whole will
+				% change, we must ensure that it changes
+				% for the better.
+				%
+			heuristic(ModuleName, PredName, Arity, Args,
+					MustBeStaticVars),
+			assoc_info_static_set(StaticSet, AssocInfo0,
+					AssocInfo),
+			(StaticSet `intersect` MustBeStaticVars) `equal`
+					MustBeStaticVars
+		;
+				% If no heuristic is known, then record
+				% which variables were swapped and warn
+				% the user.
+			assoc_info_add_warning(w(Context, PredId, VarA, VarB),
+					AssocInfo0, AssocInfo)
+		),
 		Commutative = no
 	).
 
+
+:- pred has_heuristic(module_name::in, string::in, arity::in) is semidet.
+
+has_heuristic(unqualified("list"), "append", 3).
+
+:- pred heuristic(module_name::in, string::in, arity::in, prog_vars::in,
+		set(prog_var)::out) is semidet.
+
+heuristic(unqualified("list"), "append", 3, [_Typeinfo, A, _B, _C], Set) :-
+	set__list_to_set([A], Set).
+
+
 	%
 	% commutativity_assertion
 	%
@@ -1690,6 +1863,31 @@
 	
 
 	%
+	% associativity_assertion
+	%
+	% Does there exist one (and only one) associativity assertion for the 
+	% current predicate.
+	% The 'and only one condition' is required because we currently
+	% don't handle the case of predicates which have individual
+	% parts which are associative, because then we don't know which
+	% variable is descended from which.
+	%
+:- pred associativity_assertion(list(assert_id)::in, module_info::in,
+		prog_vars::in, pair(prog_var)::out) is semidet.
+
+associativity_assertion([AssertId | AssertIds], ModuleInfo, Args0, VarAB) :-
+	(
+		assertion__is_associativity_assertion(AssertId, ModuleInfo,
+				Args0, VarAB0)
+	->
+		\+ associativity_assertion(AssertIds, ModuleInfo, Args0, _),
+		VarAB = VarAB0
+	;
+		associativity_assertion(AssertIds, ModuleInfo, Args0, VarAB)
+	).
+	
+
+	%
 	% check_modes(Vs, CVs, Ms, MI)
 	%
 	% Given a list of variables, Vs, and associated modes, Ms, make
@@ -1713,106 +1911,9 @@
 	check_modes(Vs, PossibleStaticVars, Ms, ModuleInfo).
 
 
-	%
-	% XXX this fact table is only a temporary solution to whether or
-	% not a particular procedure is associative.  In the long term
-	% the user should be able to annotate their code to indicate
-	% which predicates are associative.
-	%
-	% The set is simply the set of vars that must be static.  It is
-	% a simple heuristic to ensure that the O() behaviour only
-	% improves.  ie for append after swapping the arguments the
-	% static variable must be in the first location.
-	%
-:- pred assoc_fact(module_name::in, string::in, arity::in,
-		list(mode)::in, module_info::in, prog_vars::in,
-		prog_vars::out, set(prog_var)::out) is semidet.
-
-assoc_fact(unqualified("list"), "append", 3, [TypeInfoIn, In, In, Out], 
-		ModuleInfo, [TypeInfo, A, B, C], 
-		[TypeInfo, B, A, C], PossibleStaticVars) :-
-	set__list_to_set([A, B], PossibleStaticVars),
-	mode_is_input(ModuleInfo, TypeInfoIn),
-	mode_is_input(ModuleInfo, In),
-	mode_is_output(ModuleInfo, Out).
-
-
-
-/* XXX introducing accumulators for floating point numbers can be bad.
-assoc_fact(unqualified("float"), "+", 3, [In, In, Out], ModuleInfo, 
-		[A, B, C], [A, B, C], PossibleStaticVars, no) :-
-	set__list_to_set([A, B], PossibleStaticVars),
-	mode_is_input(ModuleInfo, In),
-	mode_is_output(ModuleInfo, Out).
-
-assoc_fact(unqualified("float"), "*", 3, [In, In, Out], ModuleInfo, 
-		[A, B, C], [A, B, C], PossibleStaticVars, no) :-
-	set__list_to_set([A, B], PossibleStaticVars),
-	mode_is_input(ModuleInfo, In),
-	mode_is_output(ModuleInfo, Out).
-*/
-/*
-	XXX this no longer works, because set__insert isn't associative.
-
-	However set__insert obeys the following axiom, providing that you 
-	use user-defined equality (set__equals), not structural equality 
-	for S.
-
-		some [SA] (p(A, S0, SA), p(B, SA, S)) <=>
-			some [SB] (p(B, S0, SB), p(A, SB, S))
-
-	My previous attempt at this transformation handled this case 
-	and I thought the current one did as well.  I was wrong.  I need
-	to reintegrate my old code.
-
-assoc_fact(unqualified("set"), "insert", 3, [TypeInfoIn, In, In, Out], 
-		Moduleinfo, [TypeInfo, A, B, C], 
-		[TypeInfo, A, B, C], PossibleStaticVars, no) :-
-	set__list_to_set([A, B], PossibleStaticVars),
-	mode_is_input(Moduleinfo, TypeInfoIn),
-	mode_is_input(Moduleinfo, In),
-	mode_is_output(Moduleinfo, Out).
-*/
-
 %-----------------------------------------------------------------------------%
 %-----------------------------------------------------------------------------%
 
-	% 
-	% accumulator__obey_heuristic
-	%
-	% for calls which rearrange the order of variables ensure that
-	% the call obeys the heuristic that the static variables are in 
-	% certain positions.
-	%
-	% For example, a call to append in the forward mode will have
-	% the following types of variables: (static, dynamic, dynamic).
-	% After rearrangment that order will be (dynamic, static, dynamic).
-	% Having a dynamic variable in the first position will probably
-	% take O(N) time to process while having a static variable will 
-	% probably take O(1) time.  Therefore the complexity of the
-	% predicate as a whole will change, we must ensure that it
-	% changes for the better.
-	%
-:- pred accumulator__obey_heuristic(pred_id::in, module_info::in,
-		prog_vars::in, set(prog_var)::in) is semidet.
-
-accumulator__obey_heuristic(Predid, ModuleInfo, Args, StaticSet) :-
-	module_info_pred_info(ModuleInfo, Predid, PredInfo),
-	pred_info_module(PredInfo, ModuleName),
-	pred_info_name(PredInfo, PredName),
-	pred_info_arity(PredInfo, Arity),
-	heuristic(ModuleName, PredName, Arity, Args, MustBeStaticVars),
-	set__intersect(StaticSet, MustBeStaticVars, Intersection),
-	set__equal(MustBeStaticVars, Intersection).
-
-:- pred heuristic(module_name::in, string::in, arity::in, prog_vars::in,
-		set(prog_var)::out) is semidet.
-
-heuristic(unqualified("list"), "append", 3, [_Typeinfo, A, _B, _C], Set) :-
-	set__list_to_set([A], Set).
-
-%-----------------------------------------------------------------------------%
-
 :- pred assoc_info_init(module_info::in, prog_vars::in, a_goals::in,
 		a_goals::in, a_goal::in,
 		subst::in, subst::in, assoc_info::out) is det.
@@ -1864,76 +1965,91 @@
 		%
 	set__list_to_set(Ys, YsSet),
 
+	ErrorMessages = [],
+
 	AssocInfo = assoc_info(StaticSet, DynamicSet,
 			ModuleInfo, PrevCallMap, OrigDynVarMap,
-			Y0stoAs_Subst, HstoAs_Subst, YsSet).
+			Y0stoAs_Subst, HstoAs_Subst, YsSet,
+			ErrorMessages).
 
 :- pred assoc_info_static_set(set(prog_var)::out,
 		assoc_info::in, assoc_info::out) is det.
 assoc_info_static_set(StaticSet, AssocInfo, AssocInfo) :-
-	AssocInfo = assoc_info(StaticSet, _, _, _, _, _, _, _).
+	AssocInfo = assoc_info(StaticSet, _, _, _, _, _, _, _, _).
 
 :- pred assoc_info_dynamic_set(set(prog_var)::out,
 		assoc_info::in, assoc_info::out) is det.
 assoc_info_dynamic_set(DynamicSet, AssocInfo, AssocInfo) :-
-	AssocInfo = assoc_info(_, DynamicSet, _, _, _, _, _, _).
+	AssocInfo = assoc_info(_, DynamicSet, _, _, _, _, _, _, _).
 
 :- pred assoc_info_module_info(module_info::out,
 		assoc_info::in, assoc_info::out) is det.
 assoc_info_module_info(ModuleInfo, AssocInfo, AssocInfo) :-
-	AssocInfo = assoc_info(_, _, ModuleInfo, _, _, _, _, _).
+	AssocInfo = assoc_info(_, _, ModuleInfo, _, _, _, _, _, _).
 
 :- pred assoc_info_prev_call_map(prev_call_map::out,
 		assoc_info::in, assoc_info::out) is det.
 assoc_info_prev_call_map(PrevCallMap, AssocInfo, AssocInfo) :-
-	AssocInfo = assoc_info(_, _, _, PrevCallMap, _, _, _, _).
+	AssocInfo = assoc_info(_, _, _, PrevCallMap, _, _, _, _, _).
 
 :- pred assoc_info_orig_dynvar_map(orig_dynvar_map::out,
 		assoc_info::in, assoc_info::out) is det.
 assoc_info_orig_dynvar_map(OrigDynVarMap, AssocInfo, AssocInfo) :-
-	AssocInfo = assoc_info(_, _, _, _, OrigDynVarMap, _, _, _).
+	AssocInfo = assoc_info(_, _, _, _, OrigDynVarMap, _, _, _, _).
 
 :- pred assoc_info_Y0stoAs(subst::out,
 		assoc_info::in, assoc_info::out) is det.
 assoc_info_Y0stoAs(Y0stoAs_Subst, AssocInfo, AssocInfo) :-
-	AssocInfo = assoc_info(_, _, _, _, _, Y0stoAs_Subst, _, _).
+	AssocInfo = assoc_info(_, _, _, _, _, Y0stoAs_Subst, _, _, _).
 
 :- pred assoc_info_HstoAs(subst::out,
 		assoc_info::in, assoc_info::out) is det.
 assoc_info_HstoAs(HstoAs_Subst, AssocInfo, AssocInfo) :-
-	AssocInfo = assoc_info(_, _, _, _, _, _, HstoAs_Subst, _).
+	AssocInfo = assoc_info(_, _, _, _, _, _, HstoAs_Subst, _, _).
 
 :- pred assoc_info_Ys(set(prog_var)::out,
 		assoc_info::in, assoc_info::out) is det.
 assoc_info_Ys(Ys, AssocInfo, AssocInfo) :-
-	AssocInfo = assoc_info(_, _, _, _, _, _, _, Ys).
+	AssocInfo = assoc_info(_, _, _, _, _, _, _, Ys, _).
 
+:- pred assoc_info_warnings(warnings::out,
+		assoc_info::in, assoc_info::out) is det.
+assoc_info_warnings(Warnings, AssocInfo, AssocInfo) :-
+	AssocInfo = assoc_info(_, _, _, _, _, _, _, _, Warnings).
+
 /*
 :- pred assoc_info_set_static_set(set(prog_var)::in, assoc_info::in,
 		assoc_info::out) is det.
-assoc_info_set_static_set(StaticSet, assoc_info(_, B, C, D, E, F, G, H),
-		assoc_info(StaticSet, B, C, D, E, F, G, H)).
+assoc_info_set_static_set(StaticSet, assoc_info(_, B, C, D, E, F, G, H, I),
+		assoc_info(StaticSet, B, C, D, E, F, G, H, I)).
 */
 
 :- pred assoc_info_set_dynamic_set(set(prog_var)::in, assoc_info::in,
 		assoc_info::out) is det.
-assoc_info_set_dynamic_set(DynamicSet, assoc_info(A, _, C, D, E, F, G, H),
-		assoc_info(A, DynamicSet, C, D, E, F, G, H)).
+assoc_info_set_dynamic_set(DynamicSet, assoc_info(A, _, C, D, E, F, G, H, I),
+		assoc_info(A, DynamicSet, C, D, E, F, G, H, I)).
 
 :- pred assoc_info_set_prev_call_map(prev_call_map::in, assoc_info::in,
 		assoc_info::out) is det.
-assoc_info_set_prev_call_map(PrevCallMap, assoc_info(A, B, C, _, E, F, G, H),
-		assoc_info(A, B, C, PrevCallMap, E, F, G, H)).
+assoc_info_set_prev_call_map(PrevCallMap, assoc_info(A, B, C, _, E, F, G, H, I),
+		assoc_info(A, B, C, PrevCallMap, E, F, G, H, I)).
 
 :- pred assoc_info_set_orig_dynvar_map(orig_dynvar_map::in, assoc_info::in,
 		assoc_info::out) is det.
-assoc_info_set_orig_dynvar_map(OrigDynMap, assoc_info(A, B, C, D, _, F, G, H),
-		assoc_info(A, B, C, D, OrigDynMap, F, G, H)).
+assoc_info_set_orig_dynvar_map(OrigDynMap,
+		assoc_info(A, B, C, D, _, F, G, H, I),
+		assoc_info(A, B, C, D, OrigDynMap, F, G, H, I)).
 
 :- pred assoc_info_set_Y0stoAs(subst::in, assoc_info::in,
+		assoc_info::out) is det.
+assoc_info_set_Y0stoAs(Y0stoAs_Subst, assoc_info(A, B, C, D, E, _, G, H, I),
+		assoc_info(A, B, C, D, E, Y0stoAs_Subst, G, H, I)).
+
+:- pred assoc_info_add_warning(warning::in, assoc_info::in,
 		assoc_info::out) is det.
-assoc_info_set_Y0stoAs(Y0stoAs_Subst, assoc_info(A, B, C, D, E, _, G, H),
-		assoc_info(A, B, C, D, E, Y0stoAs_Subst, G, H)).
+assoc_info_add_warning(Warning,
+		assoc_info(A, B, C, D, E, F, G, H, Warnings),
+		assoc_info(A, B, C, D, E, F, G, H, [Warning | Warnings])).
 
 %-----------------------------------------------------------------------------%
 %-----------------------------------------------------------------------------%
Index: promise/compiler/assertion.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/assertion.m,v
retrieving revision 1.5
diff -u -r1.5 assertion.m
--- promise/compiler/assertion.m	1999/11/12 09:08:12	1.5
+++ promise/compiler/assertion.m	1999/12/23 06:20:15
@@ -58,6 +58,31 @@
 		prog_vars::in, pair(prog_var)::out) is semidet.
 
 	%
+	% assertion__is_associativity_assertion(Id, MI, Vs, CVs)
+	%
+	% Does the assertion represented by the assertion id, Id,
+	% state the associativity of a pred/func?
+	% We extend the usual definition of associativity to apply to
+	% predicates or functions with more than two arguments as
+	% follows by allowing extra arguments which must be invariant.
+	% If so, this predicate returns (in CVs) the two variables which
+	% can be swapped in order if it was a call to Vs.
+	%
+	% The assertion must be in a form similar to this
+	% 	all [Is,A,B,C,ABC] 
+	% 	(
+	% 	  some [AB] p(Is,A,B,AB), p(Is,AB,C,ABC)
+	% 	<=>
+	% 	  some [BC] p(Is,B,C,BC), p(Is,A,BC,ABC)
+	% 	)
+	% for the predicate to return true (note that the invariant
+	% arguments, Is, can be any where providing they are in
+	% identical locations on both sides of the equivalence).
+	%
+:- pred assertion__is_associativity_assertion(assert_id::in, module_info::in,
+		prog_vars::in, pair(prog_var)::out) is semidet.
+
+	%
 	% assertion__in_interface_check
 	%
 	% Ensure that an assertion which is defined in an interface
@@ -73,7 +98,7 @@
 :- implementation.
 
 :- import_module globals, goal_util, hlds_out, options, prog_out, type_util.
-:- import_module bool, list, map, require, set, std_util.
+:- import_module assoc_list, bool, list, map, require, set, std_util.
 
 :- type subst == map(prog_var, prog_var).
 
@@ -124,6 +149,107 @@
 		Q = VarP,
 		Ps = Qs
 	).
+
+%-----------------------------------------------------------------------------%
+%-----------------------------------------------------------------------------%
+
+assertion__is_associativity_assertion(AssertId, Module, CallVars,
+		AssociativeVars) :-
+	assertion__goal(AssertId, Module, Goal - GoalInfo),
+	equivalent(Goal - GoalInfo, P, Q),
+
+	goal_info_get_nonlocals(GoalInfo, UniversiallyQuantifiedVars),
+
+	P = some(_, _, conj(PCalls) - _) - _PGoalInfo,
+	Q = some(_, _, conj(QCalls) - _) - _QGoalInfo,
+
+	AssociativeVars = promise_only_solution(associative(PCalls, QCalls,
+				UniversiallyQuantifiedVars, CallVars)).
+
+
+	% associative(Ps, Qs, Us, R)
+	%
+	% If the assertion was in the form
+	% 	all [Us] (some [] (Ps)) <=> (some [] (Qs))
+	% try and rearrange the order of Ps and Qs so that the assertion
+	% is in the standard from
+	%
+	% 	compose( A, B,  AB),		compose(B,  C,  BC),
+	% 	compose(AB, C, ABC) 	<=>	compose(A, BC, ABC)
+
+:- pred associative(hlds_goals::in, hlds_goals::in, set(prog_var)::in,
+		prog_vars::in, pair(prog_var)::out) is cc_nondet.
+
+associative(PCalls, QCalls, UniversiallyQuantifiedVars, CallVars,
+		CallVarA - CallVarB) :-
+	reorder(PCalls, QCalls, LHSCalls, RHSCalls),
+	process_one_side(LHSCalls, UniversiallyQuantifiedVars, AB, PairsL, Vs),
+	process_one_side(RHSCalls, UniversiallyQuantifiedVars, BC, PairsR, _),
+
+		% If you read the predicate documentation, you will note
+		% that for each pair of variables on the left hand side
+		% their is an equivalent pair of variables on the right
+		% hand side.  As the pairs of variables are not
+		% symmetric, the call to list__perm will only succeed
+		% once, if at all.
+	assoc_list__from_corresponding_lists(PairsL, PairsR, Pairs),
+	list__perm(Pairs, [(A - AB) - (B - A), (B - C) - (C - BC),
+			(AB - ABC) - (BC - ABC)]),
+
+	assoc_list__from_corresponding_lists(Vs, CallVars, AssocList),
+	list__filter((pred(X-_Y::in) is semidet :- X = A),
+			AssocList, [_A - CallVarA]),
+	list__filter((pred(X-_Y::in) is semidet :- X = B),
+			AssocList, [_B - CallVarB]).
+
+	% reorder(Ps, Qs, Ls, Rs)
+	%
+	% Given both sides of the equivalence return another possible
+	% ordering.
+
+:- pred reorder(hlds_goals::in, hlds_goals::in,
+		hlds_goals::out, hlds_goals::out) is nondet.
+
+reorder(PCalls, QCalls, LHSCalls, RHSCalls) :-
+	list__perm(PCalls, LHSCalls),
+	list__perm(QCalls, RHSCalls).
+reorder(PCalls, QCalls, LHSCalls, RHSCalls) :-
+	list__perm(PCalls, RHSCalls),
+	list__perm(QCalls, LHSCalls).
+
+	% process_one_side(Gs, Us, L, Ps)
+	% 
+	% Given the list of goals, Gs, which are one side of a possible
+	% associative equivalence, and the universally quantified
+	% variables, Us, of the goals return L the existentially
+	% quantified variable that links the two calls and Ps the list
+	% of variables which are not invariants.
+	%
+	% ie for app(TypeInfo, X, Y, XY), app(TypeInfo, XY, Z, XYZ)
+	% L <= XY and Ps <= [X - XY, Y - Z, XY - XYZ]
+
+:- pred process_one_side(hlds_goals::in, set(prog_var)::in, prog_var::out,
+		assoc_list(prog_var)::out, prog_vars::out) is semidet.
+
+process_one_side(Goals, UniversiallyQuantifiedVars, LinkingVar, Vars, VarsA) :-
+	Goals = [call(PredId, _, VarsA, _, _, _) - _,
+			call(PredId, _, VarsB, _, _, _) - _],
+
+		% Determine the linking variable, L.
+		% By definition it must be existentially quantified and
+		% a member of both variable lists.
+	CommonVars = list_to_set(VarsA) `intersect` list_to_set(VarsB),
+	set__singleton_set(CommonVars `difference` UniversiallyQuantifiedVars,
+			LinkingVar),
+
+		% Filter out all the invariant arguments, and then make
+		% sure that their is only 3 arguments left.
+	assoc_list__from_corresponding_lists(VarsA, VarsB, Vars0),
+	list__filter((pred(X-Y::in) is semidet :- not X = Y), Vars0, Vars),
+	list__length(Vars, number_of_associative_vars).
+
+:- func number_of_associative_vars = int.
+number_of_associative_vars = 3.
 
 %-----------------------------------------------------------------------------%
 %-----------------------------------------------------------------------------%
Index: promise/compiler/mercury_compile.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/mercury_compile.m,v
retrieving revision 1.145
diff -u -r1.145 mercury_compile.m
--- promise/compiler/mercury_compile.m	1999/12/21 09:56:36	1.145
+++ promise/compiler/mercury_compile.m	1999/12/23 06:41:55
@@ -36,9 +36,9 @@
 :- import_module stratify, check_typeclass, simplify, intermod, trans_opt.
 :- import_module table_gen.
 :- import_module bytecode_gen, bytecode.
-:- import_module (lambda), termination, higher_order, inlining.
-:- import_module deforest, dnf, unused_args, magic, dead_proc_elim.
-:- import_module accumulator, lco, saved_vars, liveness.
+:- import_module (lambda), termination, higher_order, accumulator, inlining.
+:- import_module deforest, dnf, magic, dead_proc_elim.
+:- import_module unused_args, lco, saved_vars, liveness.
 :- import_module follow_code, live_vars, arg_info, store_alloc, goal_path.
 :- import_module code_gen, optimize, export, base_type_info, base_type_layout.
 :- import_module rl_gen, rl_opt, rl_out.
@@ -1009,19 +1009,19 @@
 	mercury_compile__maybe_higher_order(HLDS30, Verbose, Stats, HLDS32), !,
 	mercury_compile__maybe_dump_hlds(HLDS32, "32", "higher_order"), !,
 
-	mercury_compile__maybe_do_inlining(HLDS32, Verbose, Stats, HLDS34), !,
+	mercury_compile__maybe_introduce_accumulators(HLDS32,
+			Verbose, Stats, HLDS33), !,
+	mercury_compile__maybe_dump_hlds(HLDS33, "33", "accum"), !,
+
+	mercury_compile__maybe_do_inlining(HLDS33, Verbose, Stats, HLDS34), !,
 	mercury_compile__maybe_dump_hlds(HLDS34, "34", "inlining"), !,
 
 	mercury_compile__maybe_deforestation(HLDS34, 
 			Verbose, Stats, HLDS36), !,
 	mercury_compile__maybe_dump_hlds(HLDS36, "36", "deforestation"), !,
-
-	mercury_compile__maybe_unused_args(HLDS36, Verbose, Stats, HLDS38), !,
-	mercury_compile__maybe_dump_hlds(HLDS38, "38", "unused_args"), !,
 
-	mercury_compile__maybe_introduce_accumulators(HLDS38,
-			Verbose, Stats, HLDS39), !,
-	mercury_compile__maybe_dump_hlds(HLDS39, "39", "accum"), !,
+	mercury_compile__maybe_unused_args(HLDS36, Verbose, Stats, HLDS39), !,
+	mercury_compile__maybe_dump_hlds(HLDS39, "39", "unused_args"), !,
 
 	mercury_compile__maybe_lco(HLDS39, Verbose, Stats, HLDS40), !,
 	mercury_compile__maybe_dump_hlds(HLDS40, "40", "lco"), !,
Index: promise/compiler/options.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/options.m,v
retrieving revision 1.276
diff -u -r1.276 options.m
--- promise/compiler/options.m	1999/12/21 09:56:38	1.276
+++ promise/compiler/options.m	1999/12/23 06:41:58
@@ -46,6 +46,7 @@
 :- type option	
 	% Warning options
 		--->	inhibit_warnings
+		;	inhibit_accumulator_warnings
 		;	halt_at_warn
 		;	halt_at_syntax_errors
 		;	warn_singleton_vars
@@ -404,6 +405,7 @@
 option_defaults_2(warning_option, [
 		% Warning Options
 	inhibit_warnings	-	bool_special,
+	inhibit_accumulator_warnings -	bool(no),
 	halt_at_warn		-	bool(no),
 	halt_at_syntax_errors	-	bool(no),
 	%
@@ -763,6 +765,7 @@
 
 % warning options
 long_option("inhibit-warnings",		inhibit_warnings).
+long_option("inhibit-accumulator-warnings",	inhibit_accumulator_warnings).
 long_option("halt-at-warn",		halt_at_warn).
 long_option("halt-at-syntax-errors",	halt_at_syntax_errors).
 long_option("warn-singleton-variables",	warn_singleton_vars).
@@ -1177,6 +1180,7 @@
 		:-
 	bool__not(Inhibit, Enable),
 	override_options([
+			inhibit_accumulator_warnings	-	bool(Inhibit),
 			warn_singleton_vars	-	bool(Enable),
 			warn_overlapping_scopes	-	bool(Enable),
 			warn_det_decls_too_lax	-	bool(Enable),
@@ -1420,6 +1424,9 @@
 		"\tThis option causes the compiler to halt immediately",
 		"\tafter syntax checking and not do any semantic checking",
 		"\tif it finds any syntax errors in the program.",
+		"--inhibit-accumulator-warnings",
+		"\tDon't warn about argument order rearrangement caused",
+		"\tby --introduce-accumulators.",
 		"--no-warn-singleton-variables",
 		"\tDon't warn about variables which only occur once.",
 		"--no-warn-overlapping-scopes",
Index: promise/compiler/notes/compiler_design.html
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/notes/compiler_design.html,v
retrieving revision 1.43
diff -u -r1.43 compiler_design.html
--- promise/compiler/notes/compiler_design.html	1999/12/20 18:08:39	1.43
+++ promise/compiler/notes/compiler_design.html	1999/12/23 06:42:06
@@ -534,6 +534,16 @@
   value of the higher-order/type_info/typeclass_info arguments are known
   (higher_order.m)
 
+<li> attempt to introduce accumulators (accumulator.m).  This optimizes
+  procedures whose tail consists of independent associative computations
+  or independant chains of commutative computations into a tail
+  recursive form by the introduction of accumulators.  If lco is turned
+  on it can also transform some procedures so that only construction
+  unifications are after the recursive call.  This pass must come before
+  lco, unused_args (eliminating arguments makes it hard to relate the
+  code back to the assertion) and inlining (can make the associative
+  call disappear).
+
 <li> inlining (i.e. unfolding) of simple procedures (inlining.m)
 
 <li> pushing constraints as far left as possible (constraint.m);
@@ -563,14 +573,6 @@
 <li> issue warnings about unused arguments from predicates, and create
   specialized versions without them (unused_args.m); type_infos are
   often unused.
-
-<li> attempt to introduce accumulators (accumulator.m).  This optimizes
-  procedures whose tail consists of independent associative computations
-  or independant chains of commutative computations into a tail
-  recursive form by the introduction of accumulators.  If lco is turned
-  on it can also transform some procedures so that only construction
-  unifications are after the recursive call.  This pass must come before
-  lco.
 
 <li> elimination of dead procedures (dead_proc_elim.m). Inlining, higher-order
   specialization and the elimination of unused args can make procedures dead
Index: promise/doc/user_guide.texi
===================================================================
RCS file: /home/staff/zs/imp/mercury/doc/user_guide.texi,v
retrieving revision 1.198
diff -u -r1.198 user_guide.texi
--- promise/doc/user_guide.texi	1999/12/14 04:53:37	1.198
+++ promise/doc/user_guide.texi	1999/12/16 05:50:01
@@ -2737,6 +2737,11 @@
 if it finds any syntax errors in the program.
 
 @sp 1
+ at item --inhibit-accumulator-warnings
+Don't warn about argument order rearrangement caused by
+ at samp{--introduce-accumulators}.
+
+ at sp 1
 @item --no-warn-singleton-variables
 Don't warn about variables which only occur once.
 
Index: promise/library/list.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/library/list.m,v
retrieving revision 1.88
diff -u -r1.88 list.m
--- promise/library/list.m	1999/07/07 15:19:40	1.88
+++ promise/library/list.m	1999/12/09 00:47:22
@@ -72,6 +72,16 @@
 %	that it is semidet.  Use list__remove_suffix instead.
 % :- mode list__append(out, in, in) is semidet.
 
+	% associativity of append
+:- promise all [A, B, C, ABC]
+	(
+		( some [AB]
+			(list__append(A, B, AB), list__append(AB, C, ABC)) )
+	<=>
+		( some [BC]
+			(list__append(B, C, BC), list__append(A, BC, ABC)) )
+	).
+
 	% list__remove_suffix(List, Suffix, Prefix):
 	%	The same as list__append(Prefix, Suffix, List) except that
 	%	this is semidet whereas list__append(out, in, in) is nondet.
Index: tests/general/accumulator/Mmakefile
===================================================================
RCS file: /home/staff/zs/imp/tests/general/accumulator/Mmakefile,v
retrieving revision 1.5
diff -u -r1.5 Mmakefile
--- tests/general/accumulator/Mmakefile	1999/10/26 06:11:53	1.5
+++ tests/general/accumulator/Mmakefile	1999/11/17 13:12:44
@@ -33,10 +33,6 @@
 		split		\
 		swap
 
-	# XXX
-	# Accumulators aren't introduced for -O5
-	# this is just a temp workaround
-override EXTRA_MCFLAGS =
 MCFLAGS = -d accum --introduce-accumulators --optimize-constructor-last-call \
 		--intermodule-optimization
 
Index: tests/general/accumulator/runtests
===================================================================
RCS file: /home/staff/zs/imp/tests/general/accumulator/runtests,v
retrieving revision 1.5
diff -u -r1.5 runtests
--- tests/general/accumulator/runtests	1999/11/02 05:27:21	1.5
+++ tests/general/accumulator/runtests	1999/11/16 07:56:05
@@ -22,10 +22,6 @@
 cat *.res > .allres
 if test ! -s .allres -a "$checkstatus" = 0
 then
-    # XXX disable these checks until we pass them
-    echo "the tests in the general/accumulator directory are not fully enabled"
-    exit 0
-
     grep -h "% mode.*AccFrom" *hlds*acc* | sed -e 's/number//' \
         | sed -e 's/ of predicate//g' > I.$$
     diff -u INTRODUCED I.$$ > INTRODUCED.diff
Index: tests/warnings/Mmakefile
===================================================================
RCS file: /home/staff/zs/imp/tests/warnings/Mmakefile,v
retrieving revision 1.7
diff -u -r1.7 Mmakefile
--- tests/warnings/Mmakefile	1999/10/26 08:47:46	1.7
+++ tests/warnings/Mmakefile	1999/12/24 02:34:01
@@ -4,7 +4,7 @@
 
 #-----------------------------------------------------------------------------#
 
-PROGS=	\
+ERRORCHECKONLY_PROGS=	\
 	det_infer_warning \
 	double_underscore \
 	duplicate_call \
@@ -18,10 +18,16 @@
 	unused_args_test \
 	unused_import
 
+COMPILE_PROGS=			\
+	arg_order_rearrangment
+
+PROGS=$(ERRORCHECKONLY_PROGS) $(COMPILE_PROGS)
+
 #-----------------------------------------------------------------------------#
 
 # some files need to be compiled with special options
 
+MCFLAGS-arg_order_rearrangment	= --introduce-accumulators
 MCFLAGS-duplicate_call		= --warn-duplicate-calls
 MCFLAGS-unused_args_test	= --warn-unused-args
 MCFLAGS-unused_import		= --warn-interface-imports
@@ -36,14 +42,15 @@
 #-----------------------------------------------------------------------------#
 
 DEPENDS=$(PROGS:%=%.depend)
-ERRS=	$(PROGS:%=%.err)
+ERRS=	$(ERRORCHECKONLY_PROGS:%=%.err)
+CS=	$(COMPILE_PROGS:%=%.c)
 RESS=	$(PROGS:%=%.res)
 
 #-----------------------------------------------------------------------------#
 
 depend:	$(DEPENDS)
 
-check:	$(ERRS) $(RESS)
+check:	$(ERRS) $(CS) $(RESS)
 
 all:	$(PROGS)
 
Index: tests/warnings/arg_order_rearrangment.exp
===================================================================
RCS file: arg_order_rearrangment.exp
diff -N arg_order_rearrangment.exp
--- /dev/null	Thu Mar  4 04:20:11 1999
+++ arg_order_rearrangment.exp	Fri Dec 24 13:02:09 1999
@@ -0,0 +1,9 @@
+arg_order_rearrangment.m:004: The predicate `arg_order_rearrangment:r/2'
+arg_order_rearrangment.m:010:   warning: the call to predicate
+arg_order_rearrangment.m:010:     `arg_order_rearrangment:app/3' has had the
+arg_order_rearrangment.m:010:     location of the variables R0 and V_7 swapped
+arg_order_rearrangment.m:010:     to allow accumulator introduction.
+arg_order_rearrangment.m:004:   Please ensure that these argument
+arg_order_rearrangment.m:004:     rearrangements do not introduce performance
+arg_order_rearrangment.m:004:     problems. These warnings can be suppressed by
+arg_order_rearrangment.m:004:     `--inhibit-accumulator-warnings'.
Index: tests/warnings/arg_order_rearrangment.m
===================================================================
RCS file: arg_order_rearrangment.m
diff -N arg_order_rearrangment.m
--- /dev/null	Thu Mar  4 04:20:11 1999
+++ arg_order_rearrangment.m	Fri Dec 24 13:47:21 1999
@@ -0,0 +1,26 @@
+# For accumulators to be introduced into r, R0 and [H] must have their
+# order swapped.  The compiler should warn the user that this may have
+# performance implications (a good one in this case).
+:- module arg_order_rearrangment.
+:- interface.
+:- import_module list.
+:- pred r(list(T)::in, list(T)::out) is det.
+:- implementation.
+
+r([], []).
+r([H|T], R) :-
+	r(T, R0),
+	app(R0, [H], R).
+
+:- promise all [A, B, C, ABC]
+	(
+		(some [AB] (app(A, B, AB), app(AB, C, ABC)))
+	<=>
+		(some [BC] (app(B, C, BC), app(A, BC, ABC)))
+	).
+
+:- pred app(list(T)::in, list(T)::in, list(T)::out) is det.
+
+app([], Ys, Ys).
+app([X|Xs], Ys, [X|Zs]) :-
+	app(Xs, Ys, Zs).

--------------------------------------------------------------------------
mercury-developers mailing list
Post messages to:       mercury-developers at cs.mu.oz.au
Administrative Queries: owner-mercury-developers at cs.mu.oz.au
Subscriptions:          mercury-developers-request at cs.mu.oz.au
--------------------------------------------------------------------------



More information about the developers mailing list