[m-rev.] for review: fix purity problems

Simon Taylor stayl at cs.mu.OZ.AU
Sat Dec 15 01:54:47 AEDT 2001


Estimated hours taken: 2
Branches: main

Fix bugs in the handling of impurity which broke `solutions/2'
in grade asm_fast when compiled with `--optimize-duplicate-calls'.

compiler/purity.m:
	Fix the handling of `foreign_proc' goals. Previously they
	were always assumed to be pure. Now they have the purity
	of the predicate they implement.

compiler/inlining.m:
	Compare the purity of the old and new goals when
	checking whether purity checking needs to be rerun,
	rather than just checking for `promise_pure' markers.

compiler/options.m:
	Re-enable `--optimize-duplicate-calls'.
	
tests/hard_coded/Mmakefile:
tests/hard_coded/impure_foreign.{m,exp}:
	Test case.

Index: compiler/inlining.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/inlining.m,v
retrieving revision 1.103
diff -u -u -r1.103 inlining.m
--- compiler/inlining.m	10 Aug 2001 14:51:58 -0000	1.103
+++ compiler/inlining.m	13 Dec 2001 13:49:24 -0000
@@ -584,11 +584,9 @@
 			Requantify = yes
 		),
 
-		pred_info_get_markers(PredInfo, CalleeMarkers),
 		(
-			( check_marker(CalleeMarkers, promised_pure)
-			; check_marker(CalleeMarkers, promised_semipure)
-			)
+			infer_goal_info_purity(GoalInfo0, Purity),
+			infer_goal_info_purity(GoalInfo, Purity)
 		->
 			PurityChanged = yes
 		;
Index: compiler/options.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/options.m,v
retrieving revision 1.349
diff -u -u -r1.349 options.m
--- compiler/options.m	14 Dec 2001 01:29:07 -0000	1.349
+++ compiler/options.m	14 Dec 2001 01:42:35 -0000
@@ -1732,11 +1732,7 @@
 	common_struct		-	bool(yes),
 	user_guided_type_specialization
 				-	bool(yes),
-% XXX optimize_duplicate_calls is broken -- it ignores impurity.
-% It currently screws up builtin_aggregate, which leads to failures
-% of most test cases using solutions/2 (e.g. general/commit_bug)
-% in grade asm_fast. It should be reenabled when we have fixed that bug.
-%	optimize_duplicate_calls -	bool(yes),
+	optimize_duplicate_calls -	bool(yes),
 	simple_neg		-	bool(yes),
 
 	optimize_rl		-	bool(yes),
Index: compiler/purity.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/purity.m,v
retrieving revision 1.39
diff -u -u -r1.39 purity.m
--- compiler/purity.m	13 Dec 2001 09:06:05 -0000	1.39
+++ compiler/purity.m	14 Dec 2001 14:39:08 -0000
@@ -431,44 +431,30 @@
 puritycheck_pred(PredId, PredInfo0, PredInfo, ModuleInfo, NumErrors) -->
 	{ pred_info_get_purity(PredInfo0, DeclPurity) } ,
 	{ pred_info_get_promised_purity(PredInfo0, PromisedPurity) },
-		% XXX we should remove this test when we have bootstrapped
-		% the changes requires to make foreign_proc impure by default
-	( { pred_info_get_goal_type(PredInfo0, pragmas) } ->
-		{ WorstPurity = (impure) },
-			% This is where we assume pragma foreign_proc is
-			% pure.
-		{ Purity = (pure) },
-		{ PredInfo = PredInfo0 },
-		{ NumErrors0 = 0 }
-	;   
-		{ pred_info_clauses_info(PredInfo0, ClausesInfo0) },
-		{ pred_info_procids(PredInfo0, ProcIds) },
-		{ clauses_info_clauses(ClausesInfo0, Clauses0) },
-		{ clauses_info_vartypes(ClausesInfo0, VarTypes0) },
-		{ clauses_info_varset(ClausesInfo0, VarSet0) },
-		{ RunPostTypecheck = yes },
-		{ PurityInfo0 = purity_info(ModuleInfo, RunPostTypecheck,
-			PredInfo0, VarTypes0, VarSet0, []) },
-		{ compute_purity(Clauses0, Clauses, ProcIds, pure, Purity,
-			PurityInfo0, PurityInfo) },
-		{ PurityInfo = purity_info(_, _, PredInfo1,
-			VarTypes, VarSet, RevMessages) },
-		{ clauses_info_set_vartypes(ClausesInfo0,
-			VarTypes, ClausesInfo1) },
-		{ clauses_info_set_varset(ClausesInfo1,
-			VarSet, ClausesInfo2) },
-		{ Messages = list__reverse(RevMessages) },
-		list__foldl(report_post_typecheck_message(ModuleInfo),
-			Messages),
-		{ NumErrors0 = list__length(
-				list__filter((pred(error(_)::in) is semidet),
-				Messages)) },
-		{ clauses_info_set_clauses(ClausesInfo2, Clauses,
-				ClausesInfo) },
-		{ pred_info_set_clauses_info(PredInfo1, ClausesInfo,
-				PredInfo) },
-		{ WorstPurity = Purity }
-	),
+  
+	{ pred_info_clauses_info(PredInfo0, ClausesInfo0) },
+	{ pred_info_procids(PredInfo0, ProcIds) },
+	{ clauses_info_clauses(ClausesInfo0, Clauses0) },
+	{ clauses_info_vartypes(ClausesInfo0, VarTypes0) },
+	{ clauses_info_varset(ClausesInfo0, VarSet0) },
+	{ RunPostTypecheck = yes },
+	{ PurityInfo0 = purity_info(ModuleInfo, RunPostTypecheck,
+		PredInfo0, VarTypes0, VarSet0, []) },
+	{ pred_info_get_goal_type(PredInfo0, GoalType) },
+	{ compute_purity(GoalType, Clauses0, Clauses, ProcIds, pure, Purity,
+		PurityInfo0, PurityInfo) },
+	{ PurityInfo = purity_info(_, _, PredInfo1,
+		VarTypes, VarSet, RevMessages) },
+	{ clauses_info_set_vartypes(ClausesInfo0, VarTypes, ClausesInfo1) },
+	{ clauses_info_set_varset(ClausesInfo1, VarSet, ClausesInfo2) },
+	{ Messages = list__reverse(RevMessages) },
+	list__foldl(report_post_typecheck_message(ModuleInfo), Messages),
+	{ NumErrors0 = list__length(
+			list__filter((pred(error(_)::in) is semidet),
+			Messages)) },
+	{ clauses_info_set_clauses(ClausesInfo2, Clauses, ClausesInfo) },
+	{ pred_info_set_clauses_info(PredInfo1, ClausesInfo, PredInfo) },
+	{ WorstPurity = Purity },
 	{ perform_pred_purity_checks(PredInfo, Purity, DeclPurity,
 		PromisedPurity, PurityCheckResult) },
 	( { PurityCheckResult = inconsistent_promise },
@@ -565,20 +551,24 @@
 
 % Infer the purity of a single (non-pragma c_code) predicate
 
-:- pred compute_purity(list(clause), list(clause), list(proc_id),
+:- pred compute_purity(goal_type, list(clause), list(clause), list(proc_id),
 	purity, purity, purity_info, purity_info).
-:- mode compute_purity(in, out, in, in, out, in, out) is det.
+:- mode compute_purity(in, in, out, in, in, out, in, out) is det.
 
-compute_purity([], [], _, Purity, Purity) --> [].
-compute_purity([Clause0|Clauses0], [Clause|Clauses], ProcIds,
+compute_purity(_, [], [], _, Purity, Purity) --> [].
+compute_purity(GoalType, [Clause0|Clauses0], [Clause|Clauses], ProcIds,
 		Purity0, Purity) -->
 	{ Clause0 = clause(Ids, Body0 - Info0, Lang, Context) },
 	compute_expr_purity(Body0, Body, Info0, no, Bodypurity0),
 	% If this clause doesn't apply to all modes of this procedure,
 	% i.e. the procedure has different clauses for different modes,
 	% then we must treat it as impure.
+	% XXX Currently `:- pragma foreign_proc' procedures are
+	% assumed to be pure. This will change.
 	{
-		applies_to_all_modes(Clause0, ProcIds)
+		( applies_to_all_modes(Clause0, ProcIds)
+		; GoalType = pragmas
+		)
 	->
 		Clausepurity = (pure)
 	;
@@ -588,7 +578,7 @@
 	{ add_goal_info_purity_feature(Info0, Bodypurity, Info) },
 	{ worst_purity(Purity0, Bodypurity, Purity1) },
 	{ Clause = clause(Ids, Body - Info, Lang, Context) },
-	compute_purity(Clauses0, Clauses, ProcIds, Purity1, Purity).
+	compute_purity(GoalType, Clauses0, Clauses, ProcIds, Purity1, Purity).
 
 :- pred applies_to_all_modes(clause::in, list(proc_id)::in) is semidet.
 
@@ -785,8 +775,24 @@
 	{ worst_purity(Purity1, Purity2, Purity12) },
 	{ worst_purity(Purity12, Purity3, Purity) }.
 compute_expr_purity(Ccode, Ccode, _, _, Purity) -->
-	{ Ccode = foreign_proc(Attributes,_,_,_,_,_,_) },
-	{ purity(Attributes, Purity) }.
+	{ Ccode = foreign_proc(Attributes, PredId, _,_,_,_,_) },
+	{ purity(Attributes, AttributesPurity) },
+
+	%
+	% If there were no purity attributes, the purity of the goal
+	% is the purity of the predicate.
+	% XXX Currently the default purity is `pure'. Eventually it
+	% should default to `impure', and require promises for any
+	% other purity levels, i.e. Purity = AttributesPurity.
+	%
+	ModuleInfo =^ module_info,
+	{ AttributesPurity = (pure) ->
+		module_info_pred_info(ModuleInfo, PredId, PredInfo),
+		pred_info_get_purity(PredInfo, Purity)
+	;
+		Purity = AttributesPurity
+	}.
+
 compute_expr_purity(shorthand(_), _, _, _, _) -->
 	% these should have been expanded out by now
 	{ error("compute_expr_purity: unexpected shorthand") }.
Index: tests/hard_coded/Mmakefile
===================================================================
RCS file: /home/mercury1/repository/tests/hard_coded/Mmakefile,v
retrieving revision 1.136
diff -u -u -r1.136 Mmakefile
--- tests/hard_coded/Mmakefile	6 Dec 2001 10:16:43 -0000	1.136
+++ tests/hard_coded/Mmakefile	12 Dec 2001 15:52:20 -0000
@@ -73,6 +73,7 @@
 	ho_solns \
 	ho_univ_to_type \
 	impossible_unify \
+	impure_foreign \
 	impure_prune \
 	integer_test \
 	intermod_c_code \
@@ -229,6 +230,7 @@
 MCFLAGS-ho_order	=	--optimize-higher-order
 MCFLAGS-ho_order2	=	--optimize-higher-order
 MCFLAGS-no_fully_strict	=	--no-fully-strict
+MCFLAGS-impure_foreign	=	--optimize-duplicate-calls
 MCFLAGS-intermod_c_code =	--intermodule-optimization
 MCFLAGS-intermod_c_code2 =	--intermodule-optimization
 MCFLAGS-intermod_multimode =	--intermodule-optimization
Index: tests/hard_coded/impure_foreign.exp
===================================================================
RCS file: tests/hard_coded/impure_foreign.exp
diff -N tests/hard_coded/impure_foreign.exp
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tests/hard_coded/impure_foreign.exp	13 Dec 2001 15:16:19 -0000
@@ -0,0 +1,2 @@
+1
+4
Index: tests/hard_coded/impure_foreign.m
===================================================================
RCS file: tests/hard_coded/impure_foreign.m
diff -N tests/hard_coded/impure_foreign.m
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tests/hard_coded/impure_foreign.m	13 Dec 2001 15:15:23 -0000
@@ -0,0 +1,62 @@
+:- module impure_foreign.
+
+:- interface.
+
+:- import_module io.
+
+:- impure pred main(io__state::di, io__state::uo) is det.
+
+:- implementation.
+
+:- import_module require.
+
+main -->
+		% Inlining this call forces recomputation
+		% of purity for main/2 (because of the
+		% `:- pragma promise_pure').
+		% In some versions of this compiler, this
+		% recomputation would erroneously infer
+		% that the inlined calls to incr/1 below
+		% were `pure'. Duplicate call elimination
+		% would then remove all but one of them.
+	{ unsafe_get(Val0) },
+
+	io__write_int(Val0),
+	io__nl,
+
+	{ impure incr(_) },
+	{ impure incr(_) },
+	{ impure incr(_) },
+	{ semipure get(Val) },
+	io__write_int(Val),
+	io__nl.
+
+:- pragma foreign_decl("C",
+"
+	int counter;
+").
+
+:- pragma foreign_code("C",
+"
+	int counter = 1;
+").
+
+:- impure pred incr(int::out) is det.
+
+incr(_::out) :- error("incr/1 called for language other than C").
+
+:- pragma foreign_proc("C", incr(Val::out), [will_not_call_mercury],
+			"counter++; Val = counter;").
+
+:- semipure pred get(int::out) is det.
+
+get(_::out) :- error("get/1 called for language other than C").
+
+:- pragma foreign_proc("C", get(Val::out),
+		[will_not_call_mercury, promise_semipure],
+		"Val = counter").
+	
+:- pred unsafe_get(int::out) is det.
+:- pragma promise_pure(unsafe_get/1).
+
+unsafe_get(X) :- semipure get(X).
--------------------------------------------------------------------------
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