for review: document pragma import & nondet pragma c_code
Fergus Henderson
fjh at cs.mu.OZ.AU
Thu Nov 5 04:33:39 AEDT 1998
Hi,
Tom and Zoltan, could you both please review this?
--------------------
Estimated hours taken: 3
doc/reference_manual.texi:
Document `pragma import' and nondet `pragma c_code'.
Also make various other minor improvements to the documentation
of the C interface, and fix a few layout errors
(e.g. the use of "..." instead of "@dots{}").
Index: doc/reference_manual.texi
===================================================================
RCS file: /home/mercury1/repository/mercury/doc/reference_manual.texi,v
retrieving revision 1.109
diff -u -r1.109 reference_manual.texi
--- reference_manual.texi 1998/11/02 02:35:28 1.109
+++ reference_manual.texi 1998/11/04 17:30:08
@@ -747,7 +747,7 @@
@noindent
where @var{N} >= 0, @var{Func} is a term of type
- at samp{func(T1, T2, ..., Tn) = T}, @var{FuncVar} is a variable
+ at samp{func(T1, T2, @dots{}, Tn) = T}, @var{FuncVar} is a variable
of that type, and
@var{Arg1}, @var{Arg2}, @dots{}, @var{ArgN} are terms of types
@samp{T1}, @samp{T2}, @dots{}, @samp{Tn}.
@@ -3222,10 +3222,98 @@
@node Calling C code from Mercury
@subsection Calling C code from Mercury
+There are two slightly different mechanisms for calling C code from Mercury:
+ at samp{pragma import} and @samp{pragma c_code}. @samp{pragma import}
+allows you to call C functions from Mercury. @samp{pragma c_code}
+allows you to implement Mercury procedures using arbitrary fragments
+of C code. @samp{pragma import} is usually simpler, but
+ at samp{pragma c_code} is a bit more flexible.
+
+ at menu
+* @samp{pragma import}:: Importing C functions
+* @samp{pragma c_code}:: Defining Mercury procedures using C code
+* Nondet @samp{pragma c_code}:: Using @samp{pragma c_code} for Mercury procedures
+ that can have more than one solution.
+* C code attributes:: Describing properties of C functions or C code.
+* Purity and side effects:: Explains when side effects are allowed.
+ at end menu
+
+ at node @samp{pragma import}
+ at subsubsection @samp{pragma import}
+
+A declaration of the form
+
+ at example
+:- pragma import(@var{Pred}(@var{Mode1}, @var{Mode2}, @dots{}),
+ @var{Attributes}, "@var{C_Name}").
+ at end example
+
+ at noindent
+or
+
+ at example
+:- pragma import(@var{Func}(@var{Mode1}, @var{Mode2}, @dots{}) = @var{Mode},
+ @var{Attributes}, "@var{C_Name}").
+ at end example
+
+ at noindent
+imports a C function for use by Mercury.
+ at var{Pred} or @var{Func} must specify the name of a previously declared
+Mercury predicate or function, and @var{Mode1}, @var{Mode2}, @dots{},
+and (for functions) @var{Mode} must specify one of the
+modes of that predicate or function. There must be no clauses
+for the specified Mercury procedure; instead, any calls to that
+procedure will be executed by calling the C function named
+ at var{C_Name}. The @var{Attributes} argument is optional; if present,
+it specifies properties of the given C function (see @pxref{C code attributes}).
+
+For example, the following code imports the C function @samp{cos()}
+as the Mercury function @samp{cos/1}:
+
+ at example
+:- func cos(float) = float.
+:- pragma import(cos(in) = out, [will_not_call_mercury], "cos").
+ at end example
+
+The interface to the C function for a given Mercury procedure is determined as follows.
+Mercury types are converted to C types according to the rules in
+ at xref{Passing data to and from C}.
+Mercury arguments declared with input modes are passed by value to the C function.
+For output arguments, the Mercury implementation will pass to the C function
+an address in which to store the result.
+If the Mercury procedure can fail, then its C function
+should return a truth value of type @samp{Integer} indicating success or failure:
+non-zero indicates success, and zero indicates failure.
+If the Mercury procedure is a Mercury function that cannot fail, and
+the function result has an output mode, then the C
+function should return the Mercury function result value.
+Otherwise the function result is appended as an extra argument.
+Arguments of type @samp{io__state} or @samp{store__store(_)}
+are not passed at all; that's because these types represent mutable state,
+and in C modifications to mutable state are done via side effects,
+rather than argument passing.
+
+If you use @samp{pragma import} for a polymorphically typed Mercury procedure,
+the compiler will prepend one @samp{type_info} argument to the parameters passed
+to the C function for each polymorphic type variable in the
+Mercury procedure's type signature. The values passed in these arguments
+will be the same as the values that would be obtained using the Mercury
+ at samp{type_of} function in the Mercury standard library module @samp{std_util}.
+These values may be useful in case the C function wishes to in turn call
+another polymorphic Mercury procedure (@pxref{Calling Mercury code from C}).
+
+You may not give a @samp{pragma import} declaration for a procedure
+with determinism @samp{nondet} or @samp{multi}.
+(It is however possible to define a @samp{nondet} or @samp{multi}
+procedure using @samp{pragma c_code} -- see @pxref{Nondet @samp{pragma c_code}}).
+
+ at node @samp{pragma c_code}
+ at subsubsection @samp{pragma c_code}
+
A declaration of the form
@example
-:- pragma c_code(@var{Pred}(@var{Var1}::@var{Mode1}, @var{Var2}::@var{Mode2}, ...),
+:- pragma c_code(@var{Pred}(@var{Var1}::@var{Mode1}, @var{Var2}::@var{Mode2}, @dots{}),
@var{Attributes}, @var{C_Code}).
@end example
@@ -3233,8 +3321,8 @@
or
@example
-:- pragma c_code(@var{Func}(@var{Var1}::@var{Mode1}, @var{Var2}::@var{Mode2}, ...) = (@var{Var}::@var{Mode}),
- may_call_mercury, @var{C_Code}).
+:- pragma c_code(@var{Func}(@var{Var1}::@var{Mode1}, @var{Var2}::@var{Mode2}, @dots{}) = (@var{Var}::@var{Mode}),
+ @var{Attributes}, @var{C_Code}).
@end example
@noindent
@@ -3242,7 +3330,9 @@
will result in execution of the C code given in @var{C_Code}.
The C code fragment may refer to the specified variables
(@var{Var1}, @var{Var2}, @dots{}, and @var{Var})
-directly by name.
+directly by name. These variables will have C types corresponding
+to their Mercury types, as determined by the rules specified in
+ at xref{Passing data to and from C}.
The C code fragment may declare local variables, but it should not
declare any static variables unless there is also a Mercury
@@ -3252,11 +3342,10 @@
which would result in the program having multiple instances of the
static variable, rather than a single shared instance.
-If there is a @code{pragma c_code} declaration for a mode of a predicate
-or function, then that mode of the predicate may not have determinism
- at samp{multi} or @samp{nondet}, there must not be any clauses for that
-predicate or function, and there must be a @code{pragma c_code} declaration
-for every mode of the predicate or function.
+If there is a @code{pragma import} or @code{pragma c_code} declaration for a
+mode of a predicate or function, then there must not be any clauses for that
+predicate or function, and there must be a @code{pragma c_code}
+or @code{pragma import} declaration for every mode of the predicate or function.
For example, the following piece of code defines a Mercury function
@samp{sin/1} which calls the C function @samp{sin()} of the same name.
@@ -3264,8 +3353,8 @@
@example
:- func sin(float) = float.
:- pragma c_code(sin(X::in) = (Sin::out),
- may_call_mercury,
- "Sin = sin(X);").
+ [may_call_mercury],
+ "Sin = sin(X);").
@end example
If the C code does not recursively invoke Mercury code,
@@ -3275,25 +3364,6 @@
(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.)
-All Mercury implementations must support the attributes described below.
-They may also support additional attributes.
-
-The attributes which must be supported by all implementations
-are as follows:
-
- at table @asis
-
- at item @samp{may_call_mercury}/@samp{will_not_call_mercury} declares
-whether or not execution inside this C code may call back into Mercury
-or not.
-
- at item @samp{thread_safe}/@samp{not_thread_safe} declares whether or not
-it is safe for multiple threads to execute this C code concurrently.
-C code that is not thread_safe has code inserted around it to obtain
-and release a mutex. All non-thread-safe C code shares a single mutex.
-
- at end table
-
The C code in a @code{pragma c_code} declaration
for any procedure whose determinism indicates that it could fail
must assign a truth value to the macro @samp{SUCCESS_INDICATOR}.
@@ -3304,7 +3374,7 @@
:- mode string__contains_char(in, in) is semidet.
:- pragma c_code(string__contains_char(Str::in, Ch::in),
- will_not_call_mercury,
+ [will_not_call_mercury],
"SUCCESS_INDICATOR = (strchr(Str, Ch) != NULL);").
@end example
@@ -3321,7 +3391,172 @@
before returning. If the procedure fails, the C code need only
set @code{SUCCESS_INDICATOR} to false (zero).
-Note that procedures implemented in C must still be ``pure'',
+ at node Nondet @samp{pragma c_code}
+ at subsubsection Nondet @samp{pragma c_code}
+
+For procedures that can return more than one result on backtracking,
+i.e. those with determinism @samp{nondet} or @samp{multi},
+the form of @samp{pragma c_code} declaration described previously
+does not suffice. Instead, you should use a declaration of the form
+shown below:
+
+ at example
+:- pragma c_code(@var{Pred}(@var{Var1}::@var{Mode1}, @var{Var2}::@var{Mode2}, @dots{}),
+ @var{Attributes}, @var{LocalVars}, @var{FirstCode}, @var{RetryCode},
+ @var{SharedCode}).
+ at end example
+
+ at noindent
+or
+
+ at example
+:- pragma c_code(@var{Func}(@var{Var1}::@var{Mode1}, @var{Var2}::@var{Mode2}, @dots{}) = (@var{Var}::@var{Mode}),
+ @var{Attributes}, local_vars(@var{LocalVars}), first_code(@var{FirstCode}),
+ retry_code(@var{RetryCode}), shared_code(@var{SharedCode})).
+ at end example
+
+ at noindent
+Here @var{FirstCode}, @var{RetryCode}, and @var{SharedCode} are all Mercury strings
+containing C code.
+ at var{FirstCode} will be executed whenever the Mercury procedure is called.
+ at var{RetryCode} will be executed whenever a given call to the procedure
+is re-entered on backtracking to find subsequent solutions.
+The shared_code(@var{SharedCode}) argument is optional; if present,
+ at var{SharedCode} willl be executed after each execution of
+ at var{FirstCode} or @var{RetryCode}.
+
+The code that is executed on each call or retry should
+finish by executing one of the three macros @samp{FAIL}, @samp{SUCCEED},
+or @samp{SUCCEED_LAST}. The @samp{FAIL} macro indicates that the call has failed;
+the call will not be retried. The @samp{SUCCEED} macro indicates
+that the call has succeeded, and that there may be more solutions;
+the call may be retried on backtracking.
+The @samp{SUCCEED_LAST} macro indicates that the call has succeeded,
+but that there are no more solutions after this one;
+the call will not be retried.
+
+ at var{LocalVars} is a sequence of struct member declarations which are
+used to hold any state which needs to be preserved in case of backtracking
+or passed between the different C code fragments.
+The code fragments @var{FirstCode}, @var{RetryCode}, and @var{SharedCode}
+may use the macro @samp{LOCALS}, which is defined to be a pointer to a struct
+containing the fields specified by @var{LocalVars}, to access this saved state.
+
+Note @var{RetryCode} and @var{SharedCode} may not access the input variables --
+only @var{FirstCode} should access the input variables.
+if @var{RetryCode} or @var{SharedCode} need to access any of the input variables,
+then @var{FirstCode} should copy the values needed to the @var{LocalVars}.
+
+The following example shows how you can use a state variable to
+keep track of next alternative to return.
+
+ at example
+%
+% This example implements the equivalent of
+% foo(X) :- X = 20 ; X = 10 ; X = 42 ; X = 99 ; fail.
+%
+:- pred foo(int).
+:- mode foo(out) is multi.
+:- pragma c_code(foo(X::out), [will_not_call_mercury, thread_safe],
+ local_vars("
+ int state;
+ "),
+ first_code("
+ LOCALS->state = 0;
+ "),
+ common_code("
+ switch (++LOCALS->state) {
+ case 1: X = 20; SUCCEED; break;
+ case 2: X = 10; SUCCEED; break;
+ case 3: X = 42; SUCCEED; break;
+ case 4: X = 99; SUCCEED; break;
+ case 5: FAIL; break;
+ }
+ ")
+).
+ at end example
+
+ at noindent
+The next example is a more realistic example;
+it shows how you could implement the reverse
+mode of @samp{string__append}, which returns
+all possible ways of splitting a string into
+two pieces, using @samp{pragma c_code}.
+
+ at example
+:- pred string__append(string, string, string).
+:- mode string__append(out, out, in) is multi.
+:- pragma c_code(string__append(S1::out, S2::out, S3::in),
+ [will_not_call_mercury, thread_safe],
+ local_vars("
+ String s;
+ size_t len;
+ size_t count;
+ "),
+ first_code("
+ LOCALS->s = S3;
+ LOCALS->len = strlen(S3);
+ LOCALS->count = 0;
+ "),
+ retry_code("
+ LOCALS->count++;
+ "),
+ common_code("
+ S1 = copy_substring(LOCALS->s, 0, LOCALS->count);
+ S2 = copy_substring(LOCALS->s, LOCALS->count + 1, LOCALS->len);
+ if (LOCALS->count < LOCALS->len) {
+ SUCCEED;
+ } else {
+ SUCCEED_LAST;
+ }
+ ")
+).
+ at end example
+
+ at node C code attributes
+ at subsubsection C code attributes
+
+As described above, @samp{pragma import} and @samp{pragma c_code}
+declarations may include a list of attributes describing properties
+of the given C function or C code.
+All Mercury implementations must support the attributes listed below.
+They may also support additional attributes.
+
+The attributes which must be supported by all implementations
+are as follows:
+
+ at table @asis
+
+ at item @samp{may_call_mercury}/@samp{will_not_call_mercury}
+This attribute declares whether or not execution inside this C code may
+call back into Mercury or not. If you specify @samp{will_not_call_mercury},
+but the C code @emph{does} invoke Mercury code, then the behaviour is
+undefined.
+
+ at item @samp{thread_safe}/@samp{not_thread_safe}
+This attribute declares whether or not it is safe for multiple threads
+to execute this C code concurrently.
+If the C code is declared @samp{thread_safe}, then the Mercury implementation
+is permitted to execute the code concurrently from multiple threads without
+taking any special precautions. If the C code is declared @samp{not_thread_safe},
+then the Mercury implementation must not invoke the code concurrently from
+multiple threads. If the Mercury implementation does use multithreading,
+then it must take appropriate steps to prevent this.
+[The (experimental) multithreaded version of the current University of Melbourne Mercury
+implementation protects @samp{not_thread_safe} code using a mutex:
+C code that is not thread-safe has code inserted around it to obtain
+and release a mutex. All non-thread-safe C code shares a single mutex.]
+ at c XXX this can cause deadlocks if not_thread_safe C code calls Mercury which calls C
+
+ at c XXX document the default values
+
+ at end table
+
+ at node Purity and side effects
+ at subsubsection Purity and side effects
+
+Note that procedures implemented in C using either
+ at samp{pragma import} or @samp{pragma c_code} must still be ``pure'',
unless declared otherwise (@pxref{Impurity}), and they must
be type-correct and mode-correct. (Determinism-correctness
is also required, but it follows from the rules already stated
@@ -3347,7 +3582,7 @@
:- mode c_write_string(in, di, uo) is det.
:- pragma c_code(c_write_string(S::in, IO0::di, IO::uo),
- may_call_mercury,
+ [may_call_mercury],
"puts(S); IO = IO0;").
@end example
@@ -3437,14 +3672,14 @@
A declaration of the form
@example
-:- pragma export(@var{Pred}(@var{Mode1}, @var{Mode2}, ...), "@var{C_Name_1}").
+:- pragma export(@var{Pred}(@var{Mode1}, @var{Mode2}, @dots{}), "@var{C_Name_1}").
@end example
@noindent
or
@example
-:- pragma export(@var{Func}(@var{Mode1}, @var{Mode2}, ...) = @var{Mode}, "@var{C_Name_2}").
+:- pragma export(@var{Func}(@var{Mode1}, @var{Mode2}, @dots{}) = @var{Mode}, "@var{C_Name_2}").
@end example
@noindent
@@ -3458,6 +3693,9 @@
the specified Mercury predicate or function.
The interface to a Mercury procedure is determined as follows.
+(The rules here are just the converse of the rules for @samp{pragma export}).
+Mercury types are converted to C types according to the rules in
+ at xref{Passing data to and from C}.
Input arguments are passed by value. For output arguments, the
caller must pass the address in which to store the result.
If the Mercury procedure can fail, then its C interface function
@@ -3537,6 +3775,13 @@
given by the corresponding typedef. Mercury variables of any other
type are passed as a @samp{Word}, which in the current implementation
is a typedef for an unsigned type whose size is the same size as a pointer.
+(Note: it would in fact be better for each Mercury type to map to a distinct
+abstract type in C, since that would be more type-safe, and thus we may
+change this in a future release. We advise programmers who are manipulating
+Mercury types in C code to use typedefs for each user-defined Mercury type,
+and to treat each such type as an abstract data type. This is good style
+and it will also minimize any compatibility problems if and when we do change
+this.)
Mercury lists can be manipulated by C code using the following macros,
which are defined by the Mercury implementation.
@@ -3583,11 +3828,11 @@
");
:- pragma c_code(initialise_complicated_structure(Structure::uo),
- may_call_mercury,
+ [may_call_mercury],
"Structure = init_struct();").
:- pragma c_code(do_calculation(Value::in, Structure0::di, Structure::uo,
- may_call_mercury,
+ [may_call_mercury],
"Structure = perform_calculation(Value, Structure0);").
@end example
@@ -3834,7 +4079,7 @@
@itemx @bullet{} @code{MR_null_choicepoint_id()}
Prototypes:
@example
-typedef ... MR_ChoicepointId;
+typedef @dots{} MR_ChoicepointId;
MR_ChoicepointId MR_current_choicepoint_id(void);
MR_ChoicepointId MR_null_choicepoint_id(void);
@end example
@@ -4020,14 +4265,14 @@
or @code{semipure}, respectively. That is, a declaration of the form:
@example
-:- impure pred @var{Pred}(@var{Arguments...}).
+:- impure pred @var{Pred}(@var{Arguments}@dots{}).
@end example
@noindent
or
@example
-:- semipure pred @var{Pred}(@var{Arguments...}).
+:- semipure pred @var{Pred}(@var{Arguments}@dots{}).
@end example
@noindent
@@ -4084,17 +4329,17 @@
:- impure pred init_max is det.
:- pragma c_code(init_max,
- will_not_call_mercury,
+ [will_not_call_mercury],
"max = INT_MIN;").
:- impure pred set_max(int::in) is det.
:- pragma c_code(set_max(X::in),
- will_not_call_mercury,
+ [will_not_call_mercury],
"if (X > max) max = X;").
:- semipure pred get_max(int::out) is det.
:- pragma c_code(get_max(X::out),
- will_not_call_mercury,
+ [will_not_call_mercury],
"X = max;").
:- pragma promise_pure(max_solution/2).
@@ -4223,7 +4468,7 @@
additional pragmas:
@menu
-* Fact tables:: Support for very large tables of facts.
+* Fact tables:: Support for very large tables of facts.
* Tabled evaluation:: Support for automatically recording previously
calculated results and detecting or avoiding
certain kinds of infinite loops.
--
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