diff: allow mixing cc and non-cc modes

Fergus Henderson fjh at cs.mu.OZ.AU
Sun May 31 01:21:10 AEST 1998


Estimated hours taken: 3

Allow a predicate to have matching `cc' and `non-cc' modes.

compiler/det_analysis.m:
	If there is a call to a cc procedure in a non-cc context,
	then search for a mode of that predicate which is
	identical to the called mode except that it is not cc.
	If such a mode is found, use it, rather than reporting
	an error.

compiler/modecheck_call.m:
	Add predicate modes_are_identical_bar_cc, for use by
	det_analysis.m.

NEWS:
LIMITATIONS:
doc/reference_manual.texi:
	Document the new feature and delete documentation about the
	lack of this feature.

tests/hard_coded/Mmakefile:
tests/hard_coded/cc_and_non_cc_test.m:
tests/hard_coded/cc_and_non_cc_test.exp:
	Add a test case for the new feature.

Index: LIMITATIONS
===================================================================
RCS file: /home/mercury1/repository/mercury/LIMITATIONS,v
retrieving revision 1.12
diff -u -r1.12 LIMITATIONS
--- LIMITATIONS	1997/10/15 07:39:27	1.12
+++ LIMITATIONS	1998/05/30 15:00:28
@@ -10,9 +10,6 @@
 * The compiler does not yet use structure reuse or compile-time
   garbage collection to exploit unique modes :-(
 
-* It is not possible to give both `cc_multi' and `multi' (or `cc_nondet'
-  and `nondet') determinisms for the same mode of a predicate.
-
 * Type inference and mode inference are a bit imperfect.
 
 We are working on eliminating all of these problems. 
Index: NEWS
===================================================================
RCS file: /home/mercury1/repository/mercury/NEWS,v
retrieving revision 1.103
diff -u -r1.103 NEWS
--- NEWS	1998/05/29 21:41:55	1.103
+++ NEWS	1998/05/30 15:09:58
@@ -246,6 +246,12 @@
 * Mode inference can now infer "mostly-unique" modes as well as
   "unique" modes.
 
+* You can now declare both committed-choice ("cc") and backtracking (non-cc)
+  modes for the same predicate.
+  
+  Determinism analysis will pick the appropriate one to use for each
+  call based on the context.
+
 * The module system now includes support for sub-modules.
 
   The aim of this extension is twofold.  One aim is to provide more
Index: compiler/det_analysis.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/det_analysis.m,v
retrieving revision 1.131
diff -u -r1.131 det_analysis.m
--- det_analysis.m	1998/05/15 07:07:03	1.131
+++ det_analysis.m	1998/05/30 14:56:14
@@ -103,9 +103,9 @@
 :- implementation.
 
 :- import_module hlds_goal, prog_data, det_report, det_util.
-:- import_module type_util, mode_util, options, passes_aux.
+:- import_module type_util, modecheck_call, mode_util, options, passes_aux.
 :- import_module hlds_out, mercury_to_mercury, instmap.
-:- import_module bool, map, set, require, term.
+:- import_module assoc_list, bool, map, set, require, term.
 
 %-----------------------------------------------------------------------------%
 
@@ -425,10 +425,10 @@
 	% This is the point at which annotations start changing
 	% when we iterate to fixpoint for global determinism inference.
 
-det_infer_goal_2(call(PredId, ModeId, A, B, C, N), GoalInfo, _, SolnContext,
+det_infer_goal_2(call(PredId, ModeId0, A, B, C, N), GoalInfo, _, SolnContext,
 		DetInfo, _, _,
 		call(PredId, ModeId, A, B, C, N), Detism, Msgs) :-
-	det_lookup_detism(DetInfo, PredId, ModeId, Detism0),
+	det_lookup_detism(DetInfo, PredId, ModeId0, Detism0),
 	%
 	% Make sure we don't try to call a committed-choice pred
 	% from a non-committed-choice context.
@@ -438,14 +438,26 @@
 		NumSolns = at_most_many_cc,
 		SolnContext \= first_soln
 	->
-		Msgs = [cc_pred_in_wrong_context(GoalInfo, Detism0,
-				PredId, ModeId)],
-		% Code elsewhere relies on the assumption that
-		% SolnContext \= first_soln => NumSolns \= at_most_many_cc,
-		% so we need to enforce that here.
-		determinism_components(Detism, CanFail, at_most_many)
+		(
+			det_find_matching_non_cc_mode(DetInfo, PredId, ModeId0,
+				ModeId1)
+		->
+			ModeId = ModeId1,
+			Msgs = [],
+			Detism = Detism0
+		;
+			Msgs = [cc_pred_in_wrong_context(GoalInfo, Detism0,
+					PredId, ModeId0)],
+			ModeId = ModeId0,
+			% Code elsewhere relies on the assumption that
+			%	SolnContext \= first_soln =>
+			%		NumSolns \= at_most_many_cc,
+			% so we need to enforce that here.
+			determinism_components(Detism, CanFail, at_most_many)
+		)
 	;
 		Msgs = [],
+		ModeId = ModeId0,
 		Detism = Detism0
 	).
 
@@ -752,6 +764,46 @@
 	det_infer_switch(Cases0, InstMap0, SolnContext, DetInfo, CanFail2,
 		MaxSolns2, Cases, Detism, Msgs2),
 	list__append(Msgs1, Msgs2, Msgs).
+
+%-----------------------------------------------------------------------------%
+
+	% det_find_matching_non_cc_mode(DetInfo, PredId, ProcId0, ProcId):
+	%	Search for a mode of the given predicate that
+	% 	is identical to the mode ProcId0, except that its
+	%	determinism is non-cc whereas ProcId0's detism is cc.
+	%	Let ProcId be the first such mode.
+
+:- pred det_find_matching_non_cc_mode(det_info, pred_id, proc_id, proc_id).
+:- mode det_find_matching_non_cc_mode(in, in, in, out) is semidet.
+
+det_find_matching_non_cc_mode(DetInfo, PredId, ProcId0, ProcId) :-
+	det_info_get_module_info(DetInfo, ModuleInfo),
+        module_info_preds(ModuleInfo, PredTable),
+	map__lookup(PredTable, PredId, PredInfo),
+	pred_info_procedures(PredInfo, ProcTable),
+	map__to_assoc_list(ProcTable, ProcList),
+	det_find_matching_non_cc_mode_2(ProcList, ModuleInfo, PredInfo,
+		ProcId0, ProcId).
+
+:- pred det_find_matching_non_cc_mode_2(assoc_list(proc_id, proc_info),
+		module_info, pred_info, proc_id, proc_id).
+:- mode det_find_matching_non_cc_mode_2(in, in, in, in, out) is semidet.
+
+det_find_matching_non_cc_mode_2([ProcId1 - ProcInfo | Rest],
+		ModuleInfo, PredInfo, ProcId0, ProcId) :-
+	(
+		ProcId1 \= ProcId0,
+		proc_info_interface_determinism(ProcInfo, Detism),
+		determinism_components(Detism, _CanFail, MaxSoln),
+		MaxSoln = at_most_many,
+		modes_are_identical_bar_cc(ProcId0, ProcId1, PredInfo,
+			ModuleInfo)
+	->
+		ProcId = ProcId1
+	;
+		det_find_matching_non_cc_mode_2(Rest, ModuleInfo, PredInfo,
+				ProcId0, ProcId)
+	).
 
 %-----------------------------------------------------------------------------%
 
Index: compiler/modecheck_call.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/modecheck_call.m,v
retrieving revision 1.24
diff -u -r1.24 modecheck_call.m
--- modecheck_call.m	1998/03/03 17:35:17	1.24
+++ modecheck_call.m	1998/05/30 15:20:21
@@ -52,10 +52,23 @@
 	% they are indistinguishable; that is, whether any valid call to
 	% one mode would also be a valid call to the other.
 	% (If so, it is a mode error.)
+	% Note that mode declarations which only have different final insts
+	% do not count as distinguishable.
 	%
 :- pred modes_are_indistinguishable(proc_id, proc_id, pred_info, module_info).
 :- mode modes_are_indistinguishable(in, in, in, in) is semidet.
 
+	%
+	% Given two modes of a predicate, figure out whether
+	% they are identical, except that one is cc_nondet/cc_multi
+	% and the other is nondet/multi.
+	% This is used by determinism analysis to substitute
+	% a multi mode for a cc_multi one if the call occurs in a
+	% non-cc context.
+	%
+:- pred modes_are_identical_bar_cc(proc_id, proc_id, pred_info, module_info).
+:- mode modes_are_identical_bar_cc(in, in, in, in) is semidet.
+
 %-----------------------------------------------------------------------------%
 %-----------------------------------------------------------------------------%
 
@@ -444,8 +457,11 @@
 	% they are indistinguishable; that is, whether any valid call to
 	% one mode would also be a valid call to the other.
 	% (If so, it is a mode error.)
+	% Note that mode declarations which only have different final insts
+	% do not count as distinguishable.
 	%
-	% The code for this is similar to the code for compare_procs/5 below.
+	% The code for this is similar to the code for
+	% modes_are_indentical/4 and compare_proc/5 below.
 	%
 modes_are_indistinguishable(ProcId, OtherProcId, PredInfo, ModuleInfo) :-
 	pred_info_procedures(PredInfo, Procs),
@@ -487,6 +503,64 @@
 
 %-----------------------------------------------------------------------------%
 
+	%
+	% Given two modes of a predicate, figure out whether
+	% they are identical, except that one is cc_nondet/cc_multi
+	% and the other is nondet/multi.
+	%
+	% The code for this is similar to the code for compare_proc/5 below
+	% and modes_are_indistinguishable/4 above.
+	%
+modes_are_identical_bar_cc(ProcId, OtherProcId, PredInfo, ModuleInfo) :-
+	pred_info_procedures(PredInfo, Procs),
+	map__lookup(Procs, ProcId, ProcInfo),
+	map__lookup(Procs, OtherProcId, OtherProcInfo),
+
+	%
+	% Compare the initial insts of the arguments
+	%
+	proc_info_argmodes(ProcInfo, ProcArgModes),
+	proc_info_argmodes(OtherProcInfo, OtherProcArgModes),
+	mode_list_get_initial_insts(ProcArgModes, ModuleInfo, InitialInsts),
+	mode_list_get_initial_insts(OtherProcArgModes, ModuleInfo,
+							OtherInitialInsts),
+	compare_inst_list(InitialInsts, OtherInitialInsts, no,
+		CompareInitialInsts, ModuleInfo),
+	CompareInitialInsts = same,
+
+	%
+	% Compare the final insts of the arguments
+	%
+	mode_list_get_final_insts(ProcArgModes, ModuleInfo, FinalInsts),
+	mode_list_get_final_insts(OtherProcArgModes, ModuleInfo,
+							OtherFinalInsts),
+	compare_inst_list(FinalInsts, OtherFinalInsts, no,
+		CompareFinalInsts, ModuleInfo),
+	CompareFinalInsts = same,
+
+	%
+	% Compare the expected livenesses of the arguments
+	%
+	get_arg_lives(ProcArgModes, ModuleInfo, ProcArgLives),
+	get_arg_lives(OtherProcArgModes, ModuleInfo, OtherProcArgLives),
+	compare_liveness_list(ProcArgLives, OtherProcArgLives, CompareLives),
+	CompareLives = same,
+
+	%
+	% Compare the determinisms, ignoring the cc part.
+	%
+	proc_info_interface_determinism(ProcInfo, Detism),
+	proc_info_interface_determinism(OtherProcInfo, OtherDetism),
+	determinism_components(Detism, CanFail, Solns),
+	determinism_components(OtherDetism, OtherCanFail, OtherSolns),
+	CanFail = OtherCanFail,
+	( Solns = OtherSolns
+	; Solns = at_most_many_cc, OtherSolns = at_most_many
+	; Solns = at_most_many, OtherSolns = at_most_many_cc
+	).
+
+%-----------------------------------------------------------------------------%
+
 /*
 The algorithm for choose_best_match is supposed to be equivalent
 to the following specification:
@@ -556,7 +630,8 @@
 	% for calls which could match either mode.
 	%
 	% The code for this is similar to the code for
-	% modes_are_indistiguisable/4 above.
+	% modes_are_indistinguishable/4 and
+	% modes_are_identical_bar_cc/4 above.
 	%
 :- pred compare_proc(proc_id, proc_id, list(var), match, proc_table, mode_info).
 :- mode compare_proc(in, in, in, out, in, mode_info_ui) is det.
Index: doc/reference_manual.texi
===================================================================
RCS file: /home/mercury1/repository/mercury/doc/reference_manual.texi,v
retrieving revision 1.94
diff -u -r1.94 reference_manual.texi
--- reference_manual.texi	1998/05/29 19:29:09	1.94
+++ reference_manual.texi	1998/05/30 15:19:51
@@ -1947,6 +1947,15 @@
 The compiler will check that all calls to a committed-choice
 mode of a predicate do indeed occur in a single-solution context.
 
+You can declare two different modes of a predicate which differ
+only in ``cc-ness'' (i.e. one being @samp{multi} and the other
+ at samp{cc_multi}, or one being @samp{nondet} and the other {cc_nondet}).
+In that case, the compiler will select the appropriate one for each
+call depending on whether the call comes from a single-solution context
+or not.  Calls from single-solution contexts will call the committed
+choice version, while calls which are not from single-solution contexts
+will call the backtracking version.
+
 There are several reasons to use committed choice determinism annotations.
 One reason is for efficiency: committed choice annotations allow
 the compiler to generate much more efficient code.
@@ -1955,12 +1964,6 @@
 Another is for dealing with types that use non-canonical representations
 (@pxref{Equality preds}).
 And there are a variety of other applications.
-
-It would be nice to be able to declare a mode of a predicate as
-both @samp{multi} and @samp{cc_multi}, and have the compiler call
-the appropriate one depending on whether the call comes from a
-single-solution context or not.  However, the current implementation
-does not yet support this.
 
 @node Equality preds
 @chapter User-defined equality predicates
Index: tests/hard_coded/Mmakefile
===================================================================
RCS file: /home/mercury1/repository/tests/hard_coded/Mmakefile,v
retrieving revision 1.30
diff -u -r1.30 Mmakefile
--- Mmakefile	1998/05/27 04:00:51	1.30
+++ Mmakefile	1998/05/30 15:15:29
@@ -13,6 +13,7 @@
 	boyer \
 	c_write_string \
 	cc_nondet_disj \
+	cc_and_non_cc_test \
 	common_type_cast \
 	construct \
 	curry \
cvs diff: tests/hard_coded/cc_and_non_cc_test.exp is a new entry, no comparison available
cvs diff: tests/hard_coded/cc_and_non_cc_test.m is a new entry, no comparison available

-- 
Fergus Henderson <fjh at cs.mu.oz.au>  |  "I have always known that the pursuit
WWW: <http://www.cs.mu.oz.au/~fjh>  |  of excellence is a lethal habit"
PGP: finger fjh at 128.250.37.3        |     -- the last words of T. S. Garp.



More information about the developers mailing list