[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