[m-rev.] for review: mix mercury code with foreign_proc

Tyson Dowd trd at cs.mu.OZ.AU
Tue Jul 31 22:27:39 AEST 2001


On 31-Jul-2001, Fergus Henderson <fjh at cs.mu.OZ.AU> wrote:
> On 30-Jul-2001, Tyson Dowd <trd at cs.mu.OZ.AU> wrote:
> > compiler/make_hlds.m:
> > 	Set the goal type for potentially mixed mercury/foreign_proc
> > 	clauses as "clauses".
> 
> I don't think that is a good idea.  It would be much better to add a new goal
> type clauses_and_pragmas and set it to that.  Some places in our existing code
> assume that `clauses' means that there are no pragmas.
> 
> You'll also need to go through and find all the places in the compiler
> that use `pragmas' or `clauses' and see if they need to be updated to
> check for `pragmas_and_clauses'.  I had a brief look and there is at
> least one place that needs to be updated.
> 
> Those two points should be addressed before you commit this.
> 
> > compiler/hlds_pred.m:
> > 	Add a field to clauses_info to record whether we have any
> > 	foreign_proc clauses.
> 
> It would be nice to use record syntax for the clauses_info.
> 

We do.  Did you perhaps mean `clause'?

> Ideally we ought to perform semantic analysis on Mercury clauses
> even if they are overridden by foreign language pragmas.
> Your patch doesn't do that.  However, that can remain a wishlist item
> for some future patch...

Yes, this would be nice, as would error checking (e.g. unused variable
name checking) the foreign_procs even if we aren't using them.

I've submitted this as a feature request.

I've made the other changes you suggested.  There are also some cosmetic
fixes to some test cases which are on their way.

--- zzlog.merc2	Mon Jul 30 17:12:43 2001
+++ zzlog.merc4	Tue Jul 31 14:25:57 2001
@@ -1,11 +1,18 @@
 
-Estimated hours taken: 16
+Estimated hours taken: 20
 Branches: main
 
 compiler/hlds_pred.m:
 	Add a field to clauses_info to record whether we have any
 	foreign_proc clauses.
 
+	Add a new goal type clauses_and_pragmas to describe predicates
+	that have procedures implemented using both pragmas and clauses.
+
+	Add pred_info_pragma_goal_type and pred_info_clause_goal_type
+	to simplify cases where we are just interested whether the goal
+	types might contain pragmas or goals.
+
 compiler/make_hlds.m:
 	Record errors if we try to add a foreign_proc that will replace
 	a Mercury clause that is not mode-specific, or if we try to add
@@ -29,9 +36,19 @@
 compiler/clause_to_proc.m:
 compiler/higher_order.m:
 compiler/hlds_out.m:
+compiler/make_hlds.m:
+compiler/purity.m:
 compiler/polymorphism.m:
 compiler/unify_proc.m:
 	Handle have_foreign_clauses field in clauses_info.
+	Handle clauses_and_pragmas goal type.
+
+compiler/intermod.m:
+	Handle clauses_and_pragmas goal type.
+	Handle all clauses in a single pass, since we now know on a
+	clause by clause basis whether they are foreign_proc clauses
+	or Mercury clauses we can simplify the traversal of all clauses
+	down to a single pass.



 
 doc/reference_manual.texi:
 doc/user_guide.texi:

diff -u compiler/higher_order.m compiler/higher_order.m
--- compiler/higher_order.m
+++ compiler/higher_order.m
@@ -1035,7 +1035,7 @@
 			pred_info_is_pseudo_imported(CalleePredInfo),
 			hlds_pred__in_in_unification_proc_id(CalledProc)
 		;
-			pred_info_get_goal_type(CalleePredInfo, pragmas)
+			pred_info_pragma_goal_type(CalleePredInfo)
 		)
 	->
 		Info = Info0,
diff -u compiler/hlds_pred.m compiler/hlds_pred.m
--- compiler/hlds_pred.m
+++ compiler/hlds_pred.m
@@ -234,8 +234,10 @@
 
 	% The type of goals that have been given for a pred.
 
-:- type goal_type 	--->	pragmas		% pragma foreign_code(...)
+:- type goal_type 	--->	pragmas		% pragma foreign_proc(...)
 			;	clauses		
+			;	clauses_and_pragmas 
+						% both clauses and pragmas
 			;	(assertion)
 			;	none.
 
@@ -676,6 +678,18 @@
 :- pred pred_info_get_goal_type(pred_info, goal_type).
 :- mode pred_info_get_goal_type(in, out) is det.
 
+	% Do we have a clause goal type?
+	% (this means either "clauses" or "clauses_and_pragmas")
+	
+:- pred pred_info_clause_goal_type(pred_info).
+:- mode pred_info_clause_goal_type(in) is semidet.
+
+	% Do we have a pragma goal type?
+	% (this means either "pragmas" or "clauses_and_pragmas")
+
+:- pred pred_info_pragma_goal_type(pred_info).
+:- mode pred_info_pragma_goal_type(in) is semidet.
+
 :- pred pred_info_set_goal_type(pred_info, goal_type, pred_info).
 :- mode pred_info_set_goal_type(in, in, out) is det.
 
@@ -1135,6 +1149,16 @@
 pred_info_set_typevarset(PredInfo, X, PredInfo^typevarset := X).
 
 pred_info_get_goal_type(PredInfo, PredInfo^goal_type).
+
+pred_info_clause_goal_type(PredInfo) :- 
+	( PredInfo ^ goal_type = clauses 
+	; PredInfo ^ goal_type = clauses_and_pragmas
+	).
+
+pred_info_pragma_goal_type(PredInfo) :- 
+	( PredInfo ^ goal_type = pragmas 
+	; PredInfo ^ goal_type = clauses_and_pragmas
+	).
 
 pred_info_set_goal_type(PredInfo, X, PredInfo^goal_type := X).
 
diff -u compiler/make_hlds.m compiler/make_hlds.m
--- compiler/make_hlds.m
+++ compiler/make_hlds.m
@@ -3583,7 +3583,7 @@
 		PredInfo1 = PredInfo0
 	},
 	(
-		{ pred_info_get_goal_type(PredInfo1, pragmas) },
+		{ pred_info_pragma_goal_type(PredInfo1) },
 		{ get_mode_annotations(Args, _, empty, ModeAnnotations) },
 		{ ModeAnnotations = empty ; ModeAnnotations = none }
 	->
@@ -4014,7 +4014,7 @@
 		io__write_string(".\n"),
 		{ Info = Info0 }
 	;	
-		{ pred_info_get_goal_type(PredInfo1, clauses) }
+		{ pred_info_clause_goal_type(PredInfo1) }
 	->
 		{ module_info_incr_errors(ModuleInfo1, ModuleInfo) },
 		prog_out__write_context(Context),
@@ -4172,7 +4172,7 @@
 		io__write_string(".\n"),
 		{ Info = Info0 }
 	;	
-		{ pred_info_get_goal_type(PredInfo1, clauses) },
+		{ pred_info_clause_goal_type(PredInfo1) },
 		{ pred_info_clauses_info(PredInfo1, CInfo) },
 		{ clauses_info_clauses(CInfo, ClauseList) },
 		{ list__member(clause([], _, mercury, _), ClauseList) }
@@ -4216,11 +4216,9 @@
 				ModuleInfo2, Info0, Info),
 			{ pred_info_set_clauses_info(PredInfo1, Clauses, 
 				PredInfo2) },
-					% If we have already seen Mercury
-					% clauses for this, use Mercury clauses
-					% as an appoximation for the goal type.
-			{ pred_info_get_goal_type(PredInfo2, clauses) ->
-				PredInfo = PredInfo2
+			{ pred_info_clause_goal_type(PredInfo2) ->
+				pred_info_set_goal_type(PredInfo2,
+					clauses_and_pragmas, PredInfo)
 			;
 				pred_info_set_goal_type(PredInfo2, pragmas,
 					PredInfo)
@@ -5341,13 +5339,14 @@
 				ClauseLang = foreign_language(OldLang),
 				list__member(ProcId, ProcIds)
 			->
-				PreferNewLang = 
-					foreign__prefer_foreign_language(
+				(
+					yes = foreign__prefer_foreign_language(
 						Globals, Target, OldLang,
-						NewLang),
+						NewLang)
+				->
+
 					% This language is preferred to the old
 					% language, so we should replace it
-				( PreferNewLang = yes ->
 					Action = replace(N0)
 				;
 					% Just ignore it.
@@ -5363,12 +5362,12 @@
 		( FinalAction = ignore,
 			Cs = ClauseList
 		; FinalAction = add,
-			Cs = [NewCl|ClauseList]
+			Cs = [NewCl | ClauseList]
 		; FinalAction = replace(X),
 			list__replace_nth_det(ClauseList, X, NewCl, Cs)
 		; FinalAction = split_add(X, Clause),
 			list__replace_nth_det(ClauseList, X, Clause, Cs1),
-			Cs = [NewCl|Cs1]
+			Cs = [NewCl | Cs1]
 		)
 	) },
 
diff -u doc/reference_manual.texi doc/reference_manual.texi
--- doc/reference_manual.texi
+++ doc/reference_manual.texi
@@ -4785,13 +4785,15 @@
 (If you use this form, and the C code @emph{does} invoke Mercury code,
 then the behaviour is undefined --- your program may misbehave or crash.)
 
-It is possible to provide both a Mercury definition, and
-a foreign_proc definition for a procedure.
+If there are both Mercury definitions and foreign_proc defintions for 
+a procedures, it is implementation defined which definition is used.
 All such Mercury definitions must use mode-specific clauses (even if
 there is only a single mode for the predicate).
-Suitable foreign_proc definitions will be used first, but
-if no suitable foreign_proc definition is found, the Mercury definition
-will be used instead.
+
+For pure and semipure procedures, the declarative semantics of the
+foreign_proc definitions must be the same as that of the Mercury code.
+The only thing that is allowed to differ is the efficiency (including
+the possibility of nondeterminism) and the order of solutions.
 
 @node Foreign code attributes
 @subsection Foreign code attributes
diff -u doc/user_guide.texi doc/user_guide.texi
--- doc/user_guide.texi
+++ doc/user_guide.texi
@@ -5697,15 +5697,19 @@
 @node Foreign language interface
 @chapter Foreign language interface
 
-If the compiler generates code for a particular target for which 
+The Mercury foreign language interfaces allows pragma foreign_proc to
+specify multiple implementations (in different foreign programming
+languages) for a procedure.
+
+If the compiler generates code for a procedure using a back-end for which 
 there are multiple applicable foreign languages, it will choose the
-foreign languages according to a builtin ordering. 
+foreign language to use for each procedure according to a builtin ordering. 
 
-If the language is not available for a particular backend, it will be
-ignored. 
+If the language specified in a foreign_proc is not available for a
+particular backend, it will be ignored. 
 
-Mercury clauses will be used if there are no suitable foreign_proc
-clauses for a particular procedure.
+If there are no suitable foreign_proc clauses for a particular
+procedure but there are Mercury clauses, they will be used instead.
 
 @table @asis
 
only in patch2:
--- compiler/purity.m	2001/07/20 14:14:23	1.35
+++ compiler/purity.m	2001/07/31 12:24:18
@@ -424,7 +424,7 @@
 	( { pred_info_get_goal_type(PredInfo0, pragmas) } ->
 		{ WorstPurity = (impure) },
 		{ IsPragmaCCode = yes },
-			% This is where we assume pragma C code is
+			% This is where we assume pragma foreign_proc is
 			% pure.
 		{ Purity = pure },
 		{ PredInfo = PredInfo0 },
only in patch2:
--- compiler/intermod.m	2001/07/20 14:13:34	1.103
+++ compiler/intermod.m	2001/07/31 12:24:11
@@ -252,7 +252,7 @@
 			{ module_info_set_preds(ModuleInfo0, PredTable,
 					ModuleInfo) },
 			intermod_info_get_preds(Preds0),
-			( { pred_info_get_goal_type(PredInfo, pragmas) } ->
+			( { pred_info_clause_goal_type(PredInfo) } ->
 				% The header code must be written since
 				% it could be used by the pragma_foreign_code.
 				intermod_info_set_write_header
@@ -1304,6 +1304,11 @@
 		% if `T' is written as `T_1' in the pred declaration.
 		AppendVarNums = no
 	;
+		GoalType = clauses_and_pragmas,
+		% Because pragmas may be present, we treat this case like
+		% pragmas above.
+		AppendVarNums = no
+	;
 		GoalType = clauses,
 		AppendVarNums = yes
 	;
@@ -1393,12 +1398,7 @@
 	{ clauses_info_headvars(ClausesInfo, HeadVars) },
 	{ clauses_info_clauses(ClausesInfo, Clauses) },
 
-		% handle pragma foreign_code(...) separately
-	( { pred_info_get_goal_type(PredInfo, pragmas) } ->
-		{ pred_info_procedures(PredInfo, Procs) },
-		intermod__write_foreign_code(SymName, PredOrFunc, HeadVars,
-			VarSet, Clauses, Procs)
-	;
+	(
 		{ pred_info_get_goal_type(PredInfo, assertion) }
 	->
 		(
@@ -1410,19 +1410,19 @@
 		;
 			{ error("intermod__write_preds: assertion not a single clause.") }
 		)
-	;
-		% { pred_info_typevarset(PredInfo, TVarSet) },
+	;	
 		list__foldl(intermod__write_clause(ModuleInfo, PredId, VarSet,
-			HeadVars, PredOrFunc), Clauses)
+			HeadVars, PredOrFunc, SymName), Clauses)
 	),
 	intermod__write_preds(ModuleInfo, PredIds).
 
 :- pred intermod__write_clause(module_info::in, pred_id::in, prog_varset::in,
-		list(prog_var)::in, pred_or_func::in, clause::in,
+		list(prog_var)::in, pred_or_func::in, sym_name::in, clause::in,
 		io__state::di, io__state::uo) is det.
 
 intermod__write_clause(ModuleInfo, PredId, VarSet, HeadVars,
-		PredOrFunc, Clause0) -->
+		PredOrFunc, _SymName, Clause0) -->
+	{ Clause0 = clause(_, _, mercury, _) },
 	{ strip_headvar_unifications(HeadVars, Clause0,
 		ClauseHeadVars, Clause) },
 	% Variable numbers need to be appended for the case
@@ -1432,6 +1432,54 @@
 	hlds_out__write_clause(1, ModuleInfo, PredId, VarSet, AppendVarNums,
 		ClauseHeadVars, PredOrFunc, Clause, no).
 
+intermod__write_clause(ModuleInfo, PredId, VarSet, _HeadVars,
+		PredOrFunc, SymName, Clause) -->
+	{ Clause = clause(ProcIds, Goal, foreign_language(_), _) },
+	{ module_info_pred_info(ModuleInfo, PredId, PredInfo) },
+	{ pred_info_procedures(PredInfo, Procs) },
+	(
+		(
+			% Pull the foreign code out of the goal.
+			{ Goal = conj(Goals) - _ },
+			{ list__filter(
+				lambda([X::in] is semidet, (
+				    X = foreign_proc(_,_,_,_,_,_,_) - _
+				)),
+				Goals, [ForeignCodeGoal]) },
+			{ ForeignCodeGoal = foreign_proc(Attributes,
+				_, _, Vars, Names, _, PragmaCode) - _ }
+		;
+			{ Goal = foreign_proc(Attributes,
+				_, _, Vars, Names, _, PragmaCode) - _ }
+		)
+	->	
+		list__foldl(intermod__write_foreign_clause(Procs,
+			PredOrFunc, PragmaCode, Attributes, Vars, 
+			VarSet, Names, SymName), ProcIds)
+	;
+		{ error("foreign_proc expected within this goal") }
+	).
+
+
+:- pred intermod__write_foreign_clause(proc_table::in, 
+		pred_or_func::in, pragma_foreign_code_impl::in,
+		pragma_foreign_proc_attributes::in, list(prog_var)::in,
+		prog_varset::in, list(maybe(pair(string, mode)))::in,
+		sym_name::in, proc_id::in, io__state::di, io__state::uo) is det.
+intermod__write_foreign_clause(Procs, PredOrFunc, PragmaImpl,
+		Attributes, Vars, VarSet0, Names, SymName, ProcId) -->
+	{ map__lookup(Procs, ProcId, ProcInfo) },
+	{ proc_info_maybe_declared_argmodes(ProcInfo, MaybeArgModes) },
+	( { MaybeArgModes = yes(ArgModes) } ->
+		{ get_pragma_foreign_code_vars(Vars, Names, VarSet0,
+			ArgModes, VarSet, PragmaVars) },
+		mercury_output_pragma_foreign_code(Attributes, SymName,
+			PredOrFunc, PragmaVars, VarSet, PragmaImpl)
+	;
+		{ error("intermod__write_clause: no mode declaration") }
+	).
+
+
 	% Strip the `Headvar__n = Term' unifications from each clause,
 	% except if the `Term' is a lambda expression.
 	%
@@ -1613,64 +1661,6 @@
 intermod__should_output_marker(generate_inline, _) :-
 	% This marker should only occur after the magic sets transformation.
 	error("intermod__should_output_marker: generate_inline").
-
-	% Some pretty kludgy stuff to get foreign code written correctly.
-:- pred intermod__write_foreign_code(sym_name::in, pred_or_func::in, 
-	list(prog_var)::in, prog_varset::in,
-	list(clause)::in, proc_table::in, io__state::di, io__state::uo) is det.
-
-intermod__write_foreign_code(_, _, _, _, [], _) --> [].
-intermod__write_foreign_code(SymName, PredOrFunc, HeadVars, Varset, 
-		[Clause | Clauses], Procs) -->
-	{ Clause = clause(ProcIds, Goal, _, _) },
-	(
-		(
-			% Pull the foreign code out of the goal.
-			{ Goal = conj(Goals) - _ },
-			{ list__filter(
-				lambda([X::in] is semidet, (
-				    X = foreign_proc(_,_,_,_,_,_,_) - _
-				)),
-				Goals, [ForeignCodeGoal]) },
-			{ ForeignCodeGoal = foreign_proc(Attributes,
-				_, _, Vars, Names, _, PragmaCode) - _ }
-		;
-			{ Goal = foreign_proc(Attributes,
-				_, _, Vars, Names, _, PragmaCode) - _ }
-		)
-	->	
-		intermod__write_foreign_clauses(Procs, ProcIds, PredOrFunc,
-			PragmaCode, Attributes, Vars, Varset, Names,
-			SymName)
-	;
-		{ error("intermod__write_foreign_code called with non foreign_code goal") }
-	),
-	intermod__write_foreign_code(SymName, PredOrFunc, HeadVars, Varset, 
-				Clauses, Procs).
-
-:- pred intermod__write_foreign_clauses(proc_table::in, list(proc_id)::in, 
-		pred_or_func::in, pragma_foreign_code_impl::in,
-		pragma_foreign_proc_attributes::in, list(prog_var)::in,
-		prog_varset::in, list(maybe(pair(string, mode)))::in,
-		sym_name::in, io__state::di, io__state::uo) is det.
-
-intermod__write_foreign_clauses(_, [], _, _, _, _, _, _, _) --> [].
-intermod__write_foreign_clauses(Procs, [ProcId | ProcIds], PredOrFunc,
-		PragmaImpl, Attributes, Vars, Varset0, Names, SymName) -->
-	{ map__lookup(Procs, ProcId, ProcInfo) },
-	{ proc_info_maybe_declared_argmodes(ProcInfo, MaybeArgModes) },
-	( { MaybeArgModes = yes(ArgModes) } ->
-		{ get_pragma_foreign_code_vars(Vars, Names, Varset0, ArgModes,
-			Varset, PragmaVars) },
-		mercury_output_pragma_foreign_code(Attributes, SymName,
-			PredOrFunc, PragmaVars, Varset, PragmaImpl),
-		intermod__write_foreign_clauses(Procs, ProcIds, PredOrFunc,
-			PragmaImpl, Attributes, Vars, Varset, Names,
-			SymName)
-	;
-		{ error(
-			"intermod__write_foreign_clauses: no mode declaration") }
-	).
 
 :- pred get_pragma_foreign_code_vars(list(prog_var)::in,
 		list(maybe(pair(string, mode)))::in, prog_varset::in,

--------------------------------------------------------------------------
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