This is the mail archive of the
fortran@gcc.gnu.org
mailing list for the GNU Fortran project.
Re: How to add intrinsic functions to gfortran?
- From: Paul Brook <paul at codesourcery dot com>
- To: fortran at gcc dot gnu dot org
- Cc: Steve Kargl <sgk at troutmask dot apl dot washington dot edu>
- Date: Sat, 29 May 2004 01:47:07 +0100
- Subject: Re: How to add intrinsic functions to gfortran?
- Organization: CodeSourcery
- References: <20040528190837.GA14769@troutmask.apl.washington.edu>
On Friday 28 May 2004 20:08, Steve Kargl wrote:
> Is there a document that describes how to add an
> intrinsic function to gfortran?
No, but there's plenty of examples :)
> I've implemented G77's irand(), srand(), and rand()
> procedures. srand() is an intrinsic subroutine and
> as far as I can tell it is seen, works, and is used by
> gfortran. On the other hand, irand() and rand() are
> not working and I suspect some name mangling is need.
This is a good thing, however we need a way for the user to disable these
additional intrinsics.
Actually the whole registering/checking/resolution of intrinsics needs a
rewrite to make it easy to add and maintain new intrinsics.
Me and Steven Bosscher discussed this some time ago, and came up with ideas
for autogenerating 90% of intrinsic.c, check.c and iresolve.c. I don't think
we ever got any working code though.
> I'll restrict the discussion to irand() where the Fortran
> prototypes is
>
> integer function irand(integer flag)
>
> In my C code, I have tried the following declarations
>
> GFC_INTEGER_4 prefix(irand) (GFC_INTEGER_4 flag)
You should use this one.
> GFC_INTEGER_4 __irand (GFC_INTEGER_4 flag)
> GFC_INTEGER_4 _irand (GFC_INTEGER_4 flag)
> GFC_INTEGER_4 irand (GFC_INTEGER_4 flag)
>
> In all cases, gfortran compiles
>
> program cc
> integer i
> i = irand(0)
> end program cc
>
> to the following tree
>
> troutmask:sgk[286] more cc.f90.t03.original
> MAIN__ ()
> {
> int4 i;
>
> i = 0;
> }
The frontend is replacing the intrinsic with the "known" value (see below).
> In intrinsic.c, I have
>
> add_sym_1 ("irand", 0, 1, BT_INTEGER, di,
> gfc_check_irand, gfc_simplify_irand, NULL,
> i, BT_INTEGER, di, 0);
>
> make_generic ("irand", GFC_ISYM_IRAND);
>
> where GFC_ISYM_IRAND is added to "enum gfc_generic_isym_id" in
> gfortran.h. gfc_simplify_irand is required or gfortran yields
> an ICE. It looks like
>
> gfc_expr *
> gfc_simplify_irand (gfc_expr * e)
> {
> gfc_expr *result;
>
> if (e->expr_type != EXPR_CONSTANT) return NULL;
>
> result = gfc_constant_result (BT_INTEGER, gfc_default_integer_kind(),
> &e->where);
>
> mpz_set (result->value.integer, e->value.integer);
>
> return range_check (result, "IRAND");
> }
The simplify functions basically perform constant folding. The above routine
effectively says that the function will return its argument unmodified, and
makes the substitution if the value if known at compile time.
I'd guess that irand doesn't need/want a simplify function.
> I've tried various version of a gfc_resolve_irand function to
> set the function name to each of the above 4 prototype function
> names without much luck.
I assume you modified the call to add_sym_1 so it was actually used ;)
> Any hints would be appreciated.
The code generation for intrinsic functions is in trans-intrinsic.c. The best
starting point is probably gfc_conv_intrinsic_function.
a) Generate inline code, possibly including calls to helper functions. In this
case this probably means the libc rand() and srand() functions.
The resolved name is usually ignored, although you may still need the
resolution function.
b) let it drop through to gfc_conv_intrinsic_funcall (Like MATMUL and
DOT_PRODUCT). This uses the resolved name, and it will be called exactly like
and external function.
Note that gfc_is_intrinsic_libcall is only for functions that return arrays
(as the comment says), and gfc_conv_intrinsic_lib_function contains magic you
almost certainly don't want.
HTH
Paul