summaryrefslogtreecommitdiff
path: root/gnu/usr.bin/gcc/f/intrin.c
diff options
context:
space:
mode:
authorJason Downs <downsj@cvs.openbsd.org>1996-07-27 02:52:39 +0000
committerJason Downs <downsj@cvs.openbsd.org>1996-07-27 02:52:39 +0000
commit978f1b8e18efed5647513070f53f269049feb83c (patch)
treece00da25c18405cf3e6847ad3d72d14d363e98b9 /gnu/usr.bin/gcc/f/intrin.c
parente2ce9843b6a157aadf0700edefbe6d916cb98c57 (diff)
Initial integration of G77.
Please do a make cleandir before rebuilding gcc!
Diffstat (limited to 'gnu/usr.bin/gcc/f/intrin.c')
-rw-r--r--gnu/usr.bin/gcc/f/intrin.c1773
1 files changed, 1773 insertions, 0 deletions
diff --git a/gnu/usr.bin/gcc/f/intrin.c b/gnu/usr.bin/gcc/f/intrin.c
new file mode 100644
index 00000000000..dac8d6a912a
--- /dev/null
+++ b/gnu/usr.bin/gcc/f/intrin.c
@@ -0,0 +1,1773 @@
+/* intrin.c -- Recognize references to intrinsics
+ Copyright (C) 1995 Free Software Foundation, Inc.
+ Contributed by James Craig Burley (burley@gnu.ai.mit.edu).
+
+This file is part of GNU Fortran.
+
+GNU Fortran is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Fortran is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Fortran; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.
+
+*/
+
+#include "proj.h"
+#include <ctype.h>
+#include "intrin.h"
+#include "expr.h"
+#include "info.h"
+#include "src.h"
+#include "target.h"
+#include "top.h"
+
+struct _ffeintrin_name_
+ {
+ char *name_uc;
+ char *name_lc;
+ char *name_ic;
+ ffeintrinGen generic;
+ ffeintrinSpec specific;
+ };
+
+struct _ffeintrin_gen_
+ {
+ char *name; /* Name as seen in program. */
+ ffeintrinSpec specs[2];
+ };
+
+struct _ffeintrin_spec_
+ {
+ char *name; /* Uppercase name as seen in source code,
+ lowercase if no source name, "none" if no
+ name at all (NONE case). */
+ bool is_actualarg; /* Ok to pass as actual arg if -pedantic. */
+ ffeintrinFamily family;
+ ffeintrinImp implementation;
+ };
+
+struct _ffeintrin_imp_
+ {
+ char *name; /* Name of implementation. */
+ ffeintrinImp cg_imp; /* Unique code-generation code. */
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+ ffecomGfrt gfrt; /* gfrt index in library. */
+#endif /* FFECOM_targetCURRENT == FFECOM_targetGCC */
+ char *control;
+ };
+
+static ffebad ffeintrin_check_ (ffeintrinImp imp, ffebldOp op,
+ ffebld args, ffeinfoBasictype *xbt,
+ ffeinfoKindtype *xkt,
+ ffetargetCharacterSize *xsz,
+ ffelexToken t,
+ bool commit);
+static bool ffeintrin_check_any_ (ffebld arglist);
+static int ffeintrin_cmp_name_ (const void *name, const void *intrinsic);
+
+static struct _ffeintrin_name_ ffeintrin_names_[]
+=
+{ /* Alpha order. */
+#define DEFNAME(UPPER,LOWER,MIXED,GEN,SPEC) \
+ { UPPER, LOWER, MIXED, FFEINTRIN_ ## GEN, FFEINTRIN_ ## SPEC },
+#define DEFGEN(CODE,NAME,SPEC1,SPEC2)
+#define DEFSPEC(CODE,NAME,CALLABLE,FAMILY,IMP)
+#define DEFIMP(CODE,NAME,GFRT,CONTROL)
+#define DEFIMQ(CODE,NAME,GFRT,CONTROL,CGIMP)
+#include "intrin.def"
+#undef DEFNAME
+#undef DEFGEN
+#undef DEFSPEC
+#undef DEFIMP
+#undef DEFIMQ
+};
+
+static struct _ffeintrin_gen_ ffeintrin_gens_[]
+=
+{
+#define DEFNAME(UPPER,LOWER,MIXED,GEN,SPEC)
+#define DEFGEN(CODE,NAME,SPEC1,SPEC2) \
+ { NAME, { SPEC1, SPEC2, }, },
+#define DEFSPEC(CODE,NAME,CALLABLE,FAMILY,IMP)
+#define DEFIMP(CODE,NAME,GFRT,CONTROL)
+#define DEFIMQ(CODE,NAME,GFRT,CONTROL,CGIMP)
+#include "intrin.def"
+#undef DEFNAME
+#undef DEFGEN
+#undef DEFSPEC
+#undef DEFIMP
+#undef DEFIMQ
+};
+
+static struct _ffeintrin_imp_ ffeintrin_imps_[]
+=
+{
+#define DEFNAME(UPPER,LOWER,MIXED,GEN,SPEC)
+#define DEFGEN(CODE,NAME,SPEC1,SPEC2)
+#define DEFSPEC(CODE,NAME,CALLABLE,FAMILY,IMP)
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+#define DEFIMP(CODE,NAME,GFRT,CONTROL) \
+ { NAME, FFEINTRIN_imp ## CODE, FFECOM_gfrt ## GFRT, CONTROL },
+#define DEFIMQ(CODE,NAME,GFRT,CONTROL,CGIMP) \
+ { NAME, FFEINTRIN_imp ## CGIMP, FFECOM_gfrt ## GFRT, CONTROL },
+#elif FFECOM_targetCURRENT == FFECOM_targetFFE
+#define DEFIMP(CODE,NAME,GFRT,CONTROL) \
+ { NAME, CODE, CONTROL },
+#define DEFIMQ(CODE,NAME,GFRT,CONTROL,CGIMP) \
+ { NAME, CGIMP, CONTROL },
+#else
+#error
+#endif
+#include "intrin.def"
+#undef DEFNAME
+#undef DEFGEN
+#undef DEFSPEC
+#undef DEFIMP
+#undef DEFIMQ
+};
+
+static struct _ffeintrin_spec_ ffeintrin_specs_[]
+=
+{
+#define DEFNAME(UPPER,LOWER,MIXED,GEN,SPEC)
+#define DEFGEN(CODE,NAME,SPEC1,SPEC2)
+#define DEFSPEC(CODE,NAME,CALLABLE,FAMILY,IMP) \
+ { NAME, CALLABLE, FAMILY, IMP, },
+#define DEFIMP(CODE,NAME,GFRT,CONTROL)
+#define DEFIMQ(CODE,NAME,GFRT,CONTROL,CGIMP)
+#include "intrin.def"
+#undef DEFGEN
+#undef DEFSPEC
+#undef DEFIMP
+#undef DEFIMQ
+};
+
+
+static ffebad
+ffeintrin_check_ (ffeintrinImp imp, ffebldOp op,
+ ffebld args, ffeinfoBasictype *xbt,
+ ffeinfoKindtype *xkt,
+ ffetargetCharacterSize *xsz,
+ ffelexToken t,
+ bool commit)
+{
+ char *c = ffeintrin_imps_[imp].control;
+ bool subr = (c[0] == '-');
+ char *argc;
+ ffebld arg;
+ ffeinfoBasictype bt;
+ ffeinfoKindtype kt;
+ ffetargetCharacterSize sz = FFETARGET_charactersizeNONE;
+ ffeinfoKindtype firstarg_kt;
+ bool need_col;
+ ffeinfoBasictype col_bt = FFEINFO_basictypeNONE;
+ ffeinfoKindtype col_kt = FFEINFO_kindtypeNONE;
+
+ /* Check procedure type (function vs. subroutine) against
+ invocation. */
+
+ if (op == FFEBLD_opSUBRREF)
+ {
+ if (!subr)
+ return FFEBAD_INTRINSIC_IS_FUNC;
+ }
+ else if (op == FFEBLD_opFUNCREF)
+ {
+ if (subr)
+ return FFEBAD_INTRINSIC_IS_SUBR;
+ }
+ else
+ return FFEBAD_INTRINSIC_REF;
+
+ /* Check the arglist for validity. */
+
+ if ((args != NULL)
+ && (ffebld_head (args) != NULL))
+ firstarg_kt = ffeinfo_kindtype (ffebld_info (ffebld_head (args)));
+ else
+ firstarg_kt = FFEINFO_kindtype;
+
+ for (argc = &c[5],
+ arg = args;
+ *argc != '\0';
+ )
+ {
+ char optional = '\0';
+ char required = '\0';
+ char extra = '\0';
+ char basic;
+ char kind;
+ bool lastarg_complex = FALSE;
+
+ /* We don't do anything with keywords yet. */
+ do
+ {
+ } while (*(++argc) != '=');
+
+ ++argc;
+ if ((*argc == '?')
+ || (*argc == '!')
+ || (*argc == '*'))
+ optional = *(argc++);
+ if ((*argc == '+')
+ || (*argc == 'n')
+ || (*argc == 'p'))
+ required = *(argc++);
+ basic = *(argc++);
+ kind = *(argc++);
+ if ((*argc == '&')
+ || (*argc == 'w')
+ || (*argc == 'x'))
+ extra = *(argc++);
+ if (*argc == ',')
+ ++argc;
+
+ /* Break out of this loop only when current arg spec completely
+ processed. */
+
+ do
+ {
+ bool okay;
+ ffebld a;
+ ffeinfo i;
+ bool anynum;
+ ffeinfoBasictype abt = FFEINFO_basictypeNONE;
+ ffeinfoKindtype akt = FFEINFO_kindtypeNONE;
+
+ if ((arg == NULL)
+ || (ffebld_head (arg) == NULL))
+ {
+ if (required != '\0')
+ return FFEBAD_INTRINSIC_TOOFEW;
+ if (optional == '\0')
+ return FFEBAD_INTRINSIC_TOOFEW;
+ if (arg != NULL)
+ arg = ffebld_trail (arg);
+ break; /* Try next argspec. */
+ }
+
+ a = ffebld_head (arg);
+ i = ffebld_info (a);
+ anynum = (ffeinfo_basictype (i) == FFEINFO_basictypeHOLLERITH)
+ || (ffeinfo_basictype (i) == FFEINFO_basictypeTYPELESS);
+
+ /* See how well the arg matches up to the spec. */
+
+ switch (basic)
+ {
+ case 'A':
+ okay = ffeinfo_basictype (i) == FFEINFO_basictypeCHARACTER;
+ break;
+
+ case 'C':
+ okay = anynum
+ || (ffeinfo_basictype (i) == FFEINFO_basictypeCOMPLEX);
+ abt = FFEINFO_basictypeCOMPLEX;
+ break;
+
+ case 'I':
+ okay = anynum
+ || (ffeinfo_basictype (i) == FFEINFO_basictypeINTEGER);
+ abt = FFEINFO_basictypeINTEGER;
+ break;
+
+ case 'L':
+ okay = anynum
+ || (ffeinfo_basictype (i) == FFEINFO_basictypeLOGICAL);
+ abt = FFEINFO_basictypeLOGICAL;
+ break;
+
+ case 'R':
+ okay = anynum
+ || (ffeinfo_basictype (i) == FFEINFO_basictypeREAL);
+ abt = FFEINFO_basictypeREAL;
+ break;
+
+ case 'B':
+ okay = anynum
+ || (ffeinfo_basictype (i) == FFEINFO_basictypeINTEGER)
+ || (ffeinfo_basictype (i) == FFEINFO_basictypeLOGICAL);
+ break;
+
+ case 'F':
+ okay = anynum
+ || (ffeinfo_basictype (i) == FFEINFO_basictypeCOMPLEX)
+ || (ffeinfo_basictype (i) == FFEINFO_basictypeREAL);
+ break;
+
+ case 'N':
+ okay = anynum
+ || (ffeinfo_basictype (i) == FFEINFO_basictypeCOMPLEX)
+ || (ffeinfo_basictype (i) == FFEINFO_basictypeINTEGER)
+ || (ffeinfo_basictype (i) == FFEINFO_basictypeREAL);
+ break;
+
+ case 'S':
+ okay = anynum
+ || (ffeinfo_basictype (i) == FFEINFO_basictypeINTEGER)
+ || (ffeinfo_basictype (i) == FFEINFO_basictypeREAL);
+ break;
+
+ case '-':
+ default:
+ okay = TRUE;
+ break;
+ }
+
+ switch (kind)
+ {
+ case '1':
+ okay &= anynum || (ffeinfo_kindtype (i) == 1);
+ akt = 1;
+ break;
+
+ case '2':
+ okay &= anynum || (ffeinfo_kindtype (i) == 2);
+ akt = 2;
+ break;
+
+ case '3':
+ okay &= anynum || (ffeinfo_kindtype (i) == 3);
+ akt = 3;
+ break;
+
+ case 'A':
+ okay &= anynum || (ffeinfo_kindtype (i) == firstarg_kt);
+ akt = (firstarg_kt == FFEINFO_kindtype) ? FFEINFO_kindtypeNONE
+ : firstarg_kt;
+ break;
+
+ case 's':
+ if (((((ffeinfo_basictype (i) != FFEINFO_basictypeNONE)
+ || (ffeinfo_kindtype (i) != FFEINFO_kindtypeNONE)
+ || (ffeinfo_kind (i) != FFEINFO_kindSUBROUTINE))
+ && ((ffeinfo_basictype (i) != FFEINFO_basictypeINTEGER)
+ || (ffeinfo_kindtype (i) != FFEINFO_kindtypeINTEGERDEFAULT)
+ || (ffeinfo_kind (i) != FFEINFO_kindFUNCTION))
+ && (ffeinfo_kind (i) != FFEINFO_kindNONE))
+ || ((ffeinfo_where (i) != FFEINFO_whereDUMMY)
+ && (ffeinfo_where (i) != FFEINFO_whereGLOBAL)))
+ && ((ffeinfo_basictype (i) != FFEINFO_basictypeINTEGER)
+ || (ffeinfo_kind (i) != FFEINFO_kindENTITY)))
+ okay = FALSE;
+ break;
+
+ case '0':
+ default:
+ break;
+ }
+
+ switch (extra)
+ {
+ case '&':
+ if ((ffeinfo_kind (i) != FFEINFO_kindENTITY)
+ || ((ffebld_op (a) != FFEBLD_opSYMTER)
+ && (ffebld_op (a) != FFEBLD_opSUBSTR)
+ && (ffebld_op (a) != FFEBLD_opARRAYREF)))
+ okay = FALSE;
+ break;
+
+ case 'w':
+ case 'x':
+ if ((ffeinfo_kind (i) != FFEINFO_kindENTITY)
+ || (ffeinfo_rank (i) != 0)
+ || ((ffebld_op (a) != FFEBLD_opSYMTER)
+ && (ffebld_op (a) != FFEBLD_opARRAYREF)
+ && (ffebld_op (a) != FFEBLD_opSUBSTR)))
+ okay = FALSE;
+ break;
+
+ default:
+ if ((ffeinfo_kind (i) != FFEINFO_kindENTITY)
+ || (ffeinfo_rank (i) != 0))
+ okay = FALSE;
+ break;
+ }
+
+ if ((optional == '!')
+ && lastarg_complex)
+ okay = FALSE;
+
+ if (!okay)
+ {
+ /* If it wasn't optional, it's an error,
+ else maybe it could match a later argspec. */
+ if (optional == '\0')
+ return FFEBAD_INTRINSIC_REF;
+ break; /* Try next argspec. */
+ }
+
+ lastarg_complex
+ = (ffeinfo_basictype (i) == FFEINFO_basictypeCOMPLEX);
+
+ if (anynum)
+ {
+ /* If we know dummy arg type, convert to that now. */
+
+ if ((abt != FFEINFO_basictypeNONE)
+ && (akt != FFEINFO_kindtypeNONE)
+ && commit)
+ {
+ /* We have a known type, convert hollerith/typeless
+ to it. */
+
+ a = ffeexpr_convert (a, t, NULL,
+ abt, akt, 0,
+ FFETARGET_charactersizeNONE,
+ FFEEXPR_contextLET);
+ ffebld_set_head (arg, a);
+ }
+ }
+
+ arg = ffebld_trail (arg); /* Arg accepted, now move on. */
+
+ if (optional == '*')
+ continue; /* Go ahead and try another arg. */
+ if (required == '\0')
+ break;
+ if ((required == 'n')
+ || (required == '+'))
+ {
+ optional = '*';
+ required = '\0';
+ }
+ else if (required == 'p')
+ required = 'n';
+ } while (TRUE);
+ }
+
+ /* Ignore explicit trailing omitted args. */
+
+ while ((arg != NULL) && (ffebld_head (arg) == NULL))
+ arg = ffebld_trail (arg);
+
+ if (arg != NULL)
+ return FFEBAD_INTRINSIC_TOOMANY;
+
+ /* Set up the initial type for the return value of the function. */
+
+ need_col = FALSE;
+ switch (c[0])
+ {
+ case 'A':
+ bt = FFEINFO_basictypeCHARACTER;
+ sz = 1;
+ break;
+
+ case 'C':
+ bt = FFEINFO_basictypeCOMPLEX;
+ break;
+
+ case 'I':
+ bt = FFEINFO_basictypeINTEGER;
+ break;
+
+ case 'L':
+ bt = FFEINFO_basictypeLOGICAL;
+ break;
+
+ case 'R':
+ bt = FFEINFO_basictypeREAL;
+ break;
+
+ case 'B':
+ case 'F':
+ case 'N':
+ case 'S':
+ need_col = TRUE;
+ /* Fall through. */
+ case '-':
+ default:
+ bt = FFEINFO_basictypeNONE;
+ break;
+ }
+
+ switch (c[1])
+ {
+ case '1':
+ kt = 1;
+ break;
+
+ case '2':
+ kt = 2;
+ break;
+
+ case '3':
+ kt = 3;
+ break;
+
+ case 'C':
+ if (ffe_is_90 ())
+ need_col = TRUE;
+ kt = 1;
+ break;
+
+ case '0':
+ need_col = TRUE;
+ /* Fall through. */
+ case '-':
+ default:
+ kt = FFEINFO_kindtypeNONE;
+ break;
+ }
+
+ /* Determine collective type of COL, if there is one. */
+
+ if (need_col || c[3] != '-')
+ {
+ bool okay = TRUE;
+ bool have_anynum = FALSE;
+
+ for (arg = args;
+ arg != NULL;
+ arg = (c[3] == '*') ? ffebld_trail (arg) : NULL)
+ {
+ ffebld a = ffebld_head (arg);
+ ffeinfo i;
+ bool anynum;
+
+ if (a == NULL)
+ continue;
+ i = ffebld_info (a);
+
+ anynum = (ffeinfo_basictype (i) == FFEINFO_basictypeHOLLERITH)
+ || (ffeinfo_basictype (i) == FFEINFO_basictypeTYPELESS);
+ if (anynum)
+ {
+ have_anynum = TRUE;
+ continue;
+ }
+
+ if ((col_bt == FFEINFO_basictypeNONE)
+ && (col_kt == FFEINFO_kindtypeNONE))
+ {
+ col_bt = ffeinfo_basictype (i);
+ col_kt = ffeinfo_kindtype (i);
+ }
+ else
+ {
+ ffeexpr_type_combine (&col_bt, &col_kt,
+ col_bt, col_kt,
+ ffeinfo_basictype (i),
+ ffeinfo_kindtype (i),
+ NULL);
+ if ((col_bt == FFEINFO_basictypeNONE)
+ || (col_kt == FFEINFO_kindtypeNONE))
+ return FFEBAD_INTRINSIC_REF;
+ }
+ }
+
+ if (have_anynum
+ && ((col_bt == FFEINFO_basictypeNONE)
+ || (col_kt == FFEINFO_kindtypeNONE)))
+ {
+ /* No type, but have hollerith/typeless. Use type of return
+ value to determine type of COL. */
+
+ switch (c[0])
+ {
+ case 'A':
+ return FFEBAD_INTRINSIC_REF;
+
+ case 'B':
+ case 'I':
+ case 'L':
+ if ((col_bt != FFEINFO_basictypeNONE)
+ && (col_bt != FFEINFO_basictypeINTEGER))
+ return FFEBAD_INTRINSIC_REF;
+ /* Fall through. */
+ case 'N':
+ case 'S':
+ case '-':
+ default:
+ col_bt = FFEINFO_basictypeINTEGER;
+ col_kt = FFEINFO_kindtypeINTEGER1;
+ break;
+
+ case 'C':
+ if ((col_bt != FFEINFO_basictypeNONE)
+ && (col_bt != FFEINFO_basictypeCOMPLEX))
+ return FFEBAD_INTRINSIC_REF;
+ col_bt = FFEINFO_basictypeCOMPLEX;
+ col_kt = FFEINFO_kindtypeREAL1;
+ break;
+
+ case 'R':
+ if ((col_bt != FFEINFO_basictypeNONE)
+ && (col_bt != FFEINFO_basictypeREAL))
+ return FFEBAD_INTRINSIC_REF;
+ /* Fall through. */
+ case 'F':
+ col_bt = FFEINFO_basictypeREAL;
+ col_kt = FFEINFO_kindtypeREAL1;
+ break;
+ }
+ }
+
+ switch (c[0])
+ {
+ case 'B':
+ okay = (col_bt == FFEINFO_basictypeINTEGER)
+ || (col_bt == FFEINFO_basictypeLOGICAL);
+ if (need_col)
+ bt = col_bt;
+ break;
+
+ case 'F':
+ okay = (col_bt == FFEINFO_basictypeCOMPLEX)
+ || (col_bt == FFEINFO_basictypeREAL);
+ if (need_col)
+ bt = col_bt;
+ break;
+
+ case 'N':
+ okay = (col_bt == FFEINFO_basictypeCOMPLEX)
+ || (col_bt == FFEINFO_basictypeINTEGER)
+ || (col_bt == FFEINFO_basictypeREAL);
+ if (need_col)
+ bt = col_bt;
+ break;
+
+ case 'S':
+ okay = (col_bt == FFEINFO_basictypeINTEGER)
+ || (col_bt == FFEINFO_basictypeREAL)
+ || (col_bt == FFEINFO_basictypeCOMPLEX);
+ if (need_col)
+ bt = ((col_bt != FFEINFO_basictypeCOMPLEX) ? col_bt
+ : FFEINFO_basictypeREAL);
+ break;
+ }
+
+ switch (c[1])
+ {
+ case '0':
+ if (need_col)
+ kt = col_kt;
+ break;
+
+ case 'C':
+ if (need_col && (col_bt == FFEINFO_basictypeCOMPLEX))
+ kt = col_kt;
+ break;
+ }
+
+ if (!okay)
+ return FFEBAD_INTRINSIC_REF;
+ }
+
+ /* Now, convert args in the arglist to the final type of the COL. */
+
+ for (argc = &c[5],
+ arg = args;
+ *argc != '\0';
+ )
+ {
+ char optional = '\0';
+ char required = '\0';
+ char extra = '\0';
+ char basic;
+ char kind;
+ bool lastarg_complex = FALSE;
+
+ /* We don't do anything with keywords yet. */
+ do
+ {
+ } while (*(++argc) != '=');
+
+ ++argc;
+ if ((*argc == '?')
+ || (*argc == '!')
+ || (*argc == '*'))
+ optional = *(argc++);
+ if ((*argc == '+')
+ || (*argc == 'n')
+ || (*argc == 'p'))
+ required = *(argc++);
+ basic = *(argc++);
+ kind = *(argc++);
+ if ((*argc == '&')
+ || (*argc == 'w')
+ || (*argc == 'x'))
+ extra = *(argc++);
+ if (*argc == ',')
+ ++argc;
+
+ /* Break out of this loop only when current arg spec completely
+ processed. */
+
+ do
+ {
+ bool okay;
+ ffebld a;
+ ffeinfo i;
+ bool anynum;
+ ffeinfoBasictype abt;
+ ffeinfoKindtype akt;
+
+ if ((arg == NULL)
+ || (ffebld_head (arg) == NULL))
+ {
+ if (arg != NULL)
+ arg = ffebld_trail (arg);
+ break; /* Try next argspec. */
+ }
+
+ a = ffebld_head (arg);
+ i = ffebld_info (a);
+ anynum = (ffeinfo_basictype (i) == FFEINFO_basictypeHOLLERITH)
+ || (ffeinfo_basictype (i) == FFEINFO_basictypeTYPELESS);
+
+ /* Determine what the default type for anynum would be. */
+
+ abt = FFEINFO_basictypeNONE;
+ akt = FFEINFO_kindtypeNONE;
+ if (anynum)
+ {
+ switch (c[3])
+ {
+ case '-':
+ break;
+ case '1':
+ if (arg != args)
+ break;
+ case '*':
+ abt = col_bt;
+ akt = col_kt;
+ break;
+ }
+ }
+
+ /* Again, match arg up to the spec. We go through all of
+ this again to properly follow the contour of optional
+ arguments. Probably this level of flexibility is not
+ needed, perhaps it's even downright naughty. */
+
+ switch (basic)
+ {
+ case 'A':
+ okay = ffeinfo_basictype (i) == FFEINFO_basictypeCHARACTER;
+ break;
+
+ case 'C':
+ okay = anynum
+ || (ffeinfo_basictype (i) == FFEINFO_basictypeCOMPLEX);
+ abt = FFEINFO_basictypeCOMPLEX;
+ break;
+
+ case 'I':
+ okay = anynum
+ || (ffeinfo_basictype (i) == FFEINFO_basictypeINTEGER);
+ abt = FFEINFO_basictypeINTEGER;
+ break;
+
+ case 'L':
+ okay = anynum
+ || (ffeinfo_basictype (i) == FFEINFO_basictypeLOGICAL);
+ abt = FFEINFO_basictypeLOGICAL;
+ break;
+
+ case 'R':
+ okay = anynum
+ || (ffeinfo_basictype (i) == FFEINFO_basictypeREAL);
+ abt = FFEINFO_basictypeREAL;
+ break;
+
+ case 'B':
+ okay = anynum
+ || (ffeinfo_basictype (i) == FFEINFO_basictypeINTEGER)
+ || (ffeinfo_basictype (i) == FFEINFO_basictypeLOGICAL);
+ break;
+
+ case 'F':
+ okay = anynum
+ || (ffeinfo_basictype (i) == FFEINFO_basictypeCOMPLEX)
+ || (ffeinfo_basictype (i) == FFEINFO_basictypeREAL);
+ break;
+
+ case 'N':
+ okay = anynum
+ || (ffeinfo_basictype (i) == FFEINFO_basictypeCOMPLEX)
+ || (ffeinfo_basictype (i) == FFEINFO_basictypeINTEGER)
+ || (ffeinfo_basictype (i) == FFEINFO_basictypeREAL);
+ break;
+
+ case 'S':
+ okay = anynum
+ || (ffeinfo_basictype (i) == FFEINFO_basictypeINTEGER)
+ || (ffeinfo_basictype (i) == FFEINFO_basictypeREAL);
+ break;
+
+ case '-':
+ default:
+ okay = TRUE;
+ break;
+ }
+
+ switch (kind)
+ {
+ case '1':
+ okay &= anynum || (ffeinfo_kindtype (i) == 1);
+ akt = 1;
+ break;
+
+ case '2':
+ okay &= anynum || (ffeinfo_kindtype (i) == 2);
+ akt = 2;
+ break;
+
+ case '3':
+ okay &= anynum || (ffeinfo_kindtype (i) == 3);
+ akt = 3;
+ break;
+
+ case 'A':
+ okay &= anynum || (ffeinfo_kindtype (i) == firstarg_kt);
+ akt = (firstarg_kt == FFEINFO_kindtype) ? FFEINFO_kindtypeNONE
+ : firstarg_kt;
+ break;
+
+ case 's':
+ if (((((ffeinfo_basictype (i) != FFEINFO_basictypeNONE)
+ || (ffeinfo_kindtype (i) != FFEINFO_kindtypeNONE)
+ || (ffeinfo_kind (i) != FFEINFO_kindSUBROUTINE))
+ && ((ffeinfo_basictype (i) != FFEINFO_basictypeINTEGER)
+ || (ffeinfo_kindtype (i) != FFEINFO_kindtypeINTEGERDEFAULT)
+ || (ffeinfo_kind (i) != FFEINFO_kindFUNCTION))
+ && (ffeinfo_kind (i) != FFEINFO_kindNONE))
+ || ((ffeinfo_where (i) != FFEINFO_whereDUMMY)
+ && (ffeinfo_where (i) != FFEINFO_whereGLOBAL)))
+ && ((ffeinfo_basictype (i) != FFEINFO_basictypeINTEGER)
+ || (ffeinfo_kind (i) != FFEINFO_kindENTITY)))
+ okay = FALSE;
+ break;
+
+ case '0':
+ default:
+ break;
+ }
+
+ switch (extra)
+ {
+ case '&':
+ if ((ffeinfo_kind (i) != FFEINFO_kindENTITY)
+ || ((ffebld_op (a) != FFEBLD_opSYMTER)
+ && (ffebld_op (a) != FFEBLD_opSUBSTR)
+ && (ffebld_op (a) != FFEBLD_opARRAYREF)))
+ okay = FALSE;
+ break;
+
+ case 'w':
+ case 'x':
+ if ((ffeinfo_kind (i) != FFEINFO_kindENTITY)
+ || (ffeinfo_rank (i) != 0)
+ || ((ffebld_op (a) != FFEBLD_opSYMTER)
+ && (ffebld_op (a) != FFEBLD_opARRAYREF)
+ && (ffebld_op (a) != FFEBLD_opSUBSTR)))
+ okay = FALSE;
+ break;
+
+ default:
+ if ((ffeinfo_kind (i) != FFEINFO_kindENTITY)
+ || (ffeinfo_rank (i) != 0))
+ okay = FALSE;
+ break;
+ }
+
+ if ((optional == '!')
+ && lastarg_complex)
+ okay = FALSE;
+
+ if (!okay)
+ {
+ /* If it wasn't optional, it's an error,
+ else maybe it could match a later argspec. */
+ if (optional == '\0')
+ return FFEBAD_INTRINSIC_REF;
+ break; /* Try next argspec. */
+ }
+
+ lastarg_complex
+ = (ffeinfo_basictype (i) == FFEINFO_basictypeCOMPLEX);
+
+ if (anynum && commit)
+ {
+ /* If we know dummy arg type, convert to that now. */
+
+ if (abt == FFEINFO_basictypeNONE)
+ abt = FFEINFO_basictypeINTEGER;
+ if (akt == FFEINFO_kindtypeNONE)
+ akt = FFEINFO_kindtypeINTEGER1;
+
+ /* We have a known type, convert hollerith/typeless to it. */
+
+ a = ffeexpr_convert (a, t, NULL,
+ abt, akt, 0,
+ FFETARGET_charactersizeNONE,
+ FFEEXPR_contextLET);
+ ffebld_set_head (arg, a);
+ }
+ else if ((c[3] == '*') && commit)
+ {
+ /* This is where we promote types to the consensus
+ type for the COL. Maybe this is where -fpedantic
+ should issue a warning as well. */
+
+ a = ffeexpr_convert (a, t, NULL,
+ col_bt, col_kt, 0,
+ ffeinfo_size (i),
+ FFEEXPR_contextLET);
+ ffebld_set_head (arg, a);
+ }
+
+ arg = ffebld_trail (arg); /* Arg accepted, now move on. */
+
+ if (optional == '*')
+ continue; /* Go ahead and try another arg. */
+ if (required == '\0')
+ break;
+ if ((required == 'n')
+ || (required == '+'))
+ {
+ optional = '*';
+ required = '\0';
+ }
+ else if (required == 'p')
+ required = 'n';
+ } while (TRUE);
+ }
+
+ *xbt = bt;
+ *xkt = kt;
+ *xsz = sz;
+ return FFEBAD;
+}
+
+static bool
+ffeintrin_check_any_ (ffebld arglist)
+{
+ ffebld item;
+
+ for (; arglist != NULL; arglist = ffebld_trail (arglist))
+ {
+ item = ffebld_head (arglist);
+ if ((item != NULL)
+ && (ffebld_op (item) == FFEBLD_opANY))
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/* Compare name to intrinsic's name. Uses strcmp on arguments' names. */
+
+static int
+ffeintrin_cmp_name_ (const void *name, const void *intrinsic)
+{
+ char *uc = (char *) ((struct _ffeintrin_name_ *) intrinsic)->name_uc;
+ char *lc = (char *) ((struct _ffeintrin_name_ *) intrinsic)->name_lc;
+ char *ic = (char *) ((struct _ffeintrin_name_ *) intrinsic)->name_ic;
+
+ return ffesrc_strcmp_2c (ffe_case_intrin (), name, uc, lc, ic);
+}
+
+/* Return basic type of intrinsic implementation. */
+
+ffeinfoBasictype
+ffeintrin_basictype (ffeintrinSpec spec)
+{
+ assert (spec < FFEINTRIN_spec);
+ return FFEINTRIN_specNONE;
+}
+
+/* Return code-generation implementation of intrinsic.
+
+ The idea is that an intrinsic might have its own implementation
+ (defined by the DEFIMP macro) or might defer to the implementation
+ of another intrinsic (defined by the DEFIMQ macro), and this is
+ what points to that other implementation.
+
+ The reason for this extra level of indirection, rather than
+ just adding "case" statements to the big switch in com.c's
+ ffecom_expr_intrinsic_ function, is so that generic disambiguation
+ can ensure that it doesn't have an ambiguity on its hands.
+ E.g. Both ABS and DABS might cope with a DOUBLE PRECISION,
+ etc. Previously, the implementation itself was used to allow
+ multiple specific intrinsics to "accept" the argument list
+ if they all agreed on implementation. But, since implementation
+ includes type signature and run-time-library function, another
+ level was needed to say "maybe two intrinsics would be handled
+ as two _different_ library references or involve different types
+ in general, but the specific code involved to implement them is
+ the same, so it is okay if a generic function reference can be
+ satisfied by either intrinsic". */
+
+ffeintrinImp
+ffeintrin_codegen_imp (ffeintrinImp imp)
+{
+ assert (imp < FFEINTRIN_imp);
+ return ffeintrin_imps_[imp].cg_imp;
+}
+
+/* Return family to which specific intrinsic belongs. */
+
+ffeintrinFamily
+ffeintrin_family (ffeintrinSpec spec)
+{
+ if (spec >= FFEINTRIN_spec)
+ return FALSE;
+ return ffeintrin_specs_[spec].family;
+}
+
+/* Check and fill in info on func/subr ref node.
+
+ ffebld expr; // FUNCREF or SUBRREF with no info (caller
+ // gets it from the modified info structure).
+ ffeinfo info; // Already filled in, will be overwritten.
+ ffelexToken token; // Used for error message.
+ ffeintrin_fulfill_generic (&expr, &info, token);
+
+ Based on the generic id, figure out which specific procedure is meant and
+ pick that one. Else return an error, a la _specific. */
+
+void
+ffeintrin_fulfill_generic (ffebld *expr, ffeinfo *info, ffelexToken t)
+{
+ ffebld symter;
+ ffebldOp op;
+ ffeintrinGen gen;
+ ffeintrinSpec spec = FFEINTRIN_specNONE;
+ ffeinfoBasictype bt = FFEINFO_basictypeNONE;
+ ffeinfoKindtype kt = FFEINFO_kindtypeNONE;
+ ffetargetCharacterSize sz = FFETARGET_charactersizeNONE;
+ ffeintrinImp imp;
+ ffeintrinSpec tspec;
+ ffeintrinImp nimp = FFEINTRIN_impNONE;
+ ffebad error;
+ bool any = FALSE;
+ bool highly_specific = FALSE;
+ char *name = NULL;
+ int i;
+
+ op = ffebld_op (*expr);
+ assert ((op == FFEBLD_opFUNCREF) || (op == FFEBLD_opSUBRREF));
+ assert (ffebld_op (ffebld_left (*expr)) == FFEBLD_opSYMTER);
+
+ gen = ffebld_symter_generic (ffebld_left (*expr));
+ assert (gen != FFEINTRIN_genNONE);
+
+ imp = FFEINTRIN_impNONE;
+ error = FFEBAD;
+
+ any = ffeintrin_check_any_ (ffebld_right (*expr));
+
+ for (i = 0;
+ (((size_t) i) < ARRAY_SIZE (ffeintrin_gens_[gen].specs))
+ && ((tspec = ffeintrin_gens_[gen].specs[i]) != FFEINTRIN_specNONE)
+ && !any;
+ ++i)
+ {
+ ffeintrinImp timp = ffeintrin_specs_[tspec].implementation;
+ ffeinfoBasictype tbt;
+ ffeinfoKindtype tkt;
+ ffetargetCharacterSize tsz;
+ ffeIntrinsicState state
+ = ffeintrin_state_family (ffeintrin_specs_[tspec].family);
+ ffebad terror;
+ char *tname;
+
+ if (state == FFE_intrinsicstateDELETED)
+ continue;
+
+ if (timp == FFEINTRIN_impNONE)
+ tname = ffeintrin_specs_[tspec].name;
+ else
+ tname = ffeintrin_imps_[timp].name;
+
+ if (state == FFE_intrinsicstateDISABLED)
+ terror = FFEBAD_INTRINSIC_DISABLED;
+ else if (timp == FFEINTRIN_impNONE)
+ terror = FFEBAD_INTRINSIC_UNIMPL;
+ else
+ {
+ terror = ffeintrin_check_ (timp, ffebld_op (*expr),
+ ffebld_right (*expr),
+ &tbt, &tkt, &tsz, t, FALSE);
+ if (terror == FFEBAD)
+ {
+ if (imp != FFEINTRIN_impNONE)
+ {
+ if (ffeintrin_imps_[timp].cg_imp
+ == ffeintrin_imps_[imp].cg_imp)
+ {
+ if (ffebld_symter_specific (ffebld_left (*expr))
+ == tspec)
+ {
+ highly_specific = TRUE;
+ imp = timp;
+ spec = tspec;
+ bt = tbt;
+ kt = tkt;
+ sz = tkt;
+ error = terror;
+ }
+ else if (nimp == FFEINTRIN_impNONE)
+ nimp = timp;
+ }
+ else
+ {
+ ffebad_start (FFEBAD_INTRINSIC_AMBIG);
+ ffebad_here (0, ffelex_token_where_line (t),
+ ffelex_token_where_column (t));
+ ffebad_string (ffeintrin_gens_[gen].name);
+ ffebad_string (ffeintrin_specs_[spec].name);
+ ffebad_string (ffeintrin_specs_[tspec].name);
+ ffebad_finish ();
+ }
+ }
+ else
+ {
+ if (ffebld_symter_specific (ffebld_left (*expr))
+ == tspec)
+ highly_specific = TRUE;
+ imp = timp;
+ spec = tspec;
+ bt = tbt;
+ kt = tkt;
+ sz = tkt;
+ error = terror;
+ }
+ }
+ else if (terror != FFEBAD)
+ { /* This error has precedence over others. */
+ if ((error == FFEBAD_INTRINSIC_DISABLED)
+ || (error == FFEBAD_INTRINSIC_UNIMPL))
+ error = FFEBAD;
+ }
+ }
+
+ if (error == FFEBAD)
+ {
+ error = terror;
+ name = tname;
+ }
+ }
+
+ if (any || (imp == FFEINTRIN_impNONE))
+ {
+ if (!any)
+ {
+ if (error == FFEBAD)
+ error = FFEBAD_INTRINSIC_REF;
+ if (name == NULL)
+ name = ffeintrin_gens_[gen].name;
+ ffebad_start (error);
+ ffebad_here (0, ffelex_token_where_line (t),
+ ffelex_token_where_column (t));
+ ffebad_string (name);
+ ffebad_finish ();
+ }
+
+ *expr = ffebld_new_any ();
+ *info = ffeinfo_new_any ();
+ }
+ else
+ {
+ if (!highly_specific && (nimp != FFEINTRIN_impNONE))
+ {
+ fprintf (stderr, "lineno=%ld, gen=%s, imp=%s, timp=%s\n",
+ (long) lineno,
+ ffeintrin_gens_[gen].name,
+ ffeintrin_imps_[imp].name,
+ ffeintrin_imps_[nimp].name);
+ assert ("Ambiguous generic reference" == NULL);
+ abort ();
+ }
+ error = ffeintrin_check_ (imp, ffebld_op (*expr),
+ ffebld_right (*expr),
+ &bt, &kt, &sz, t, TRUE);
+ assert (error == FFEBAD);
+ *info = ffeinfo_new (bt,
+ kt,
+ 0,
+ FFEINFO_kindENTITY,
+ FFEINFO_whereFLEETING,
+ sz);
+ symter = ffebld_left (*expr);
+ ffebld_symter_set_specific (symter, spec);
+ ffebld_symter_set_implementation (symter, imp);
+ ffebld_set_info (symter,
+ ffeinfo_new (bt,
+ kt,
+ 0,
+ (bt == FFEINFO_basictypeNONE)
+ ? FFEINFO_kindSUBROUTINE
+ : FFEINFO_kindFUNCTION,
+ FFEINFO_whereINTRINSIC,
+ sz));
+ }
+}
+
+/* Check and fill in info on func/subr ref node.
+
+ ffebld expr; // FUNCREF or SUBRREF with no info (caller
+ // gets it from the modified info structure).
+ ffeinfo info; // Already filled in, will be overwritten.
+ ffelexToken token; // Used for error message.
+ ffeintrin_fulfill_specific (&expr, &info, token);
+
+ Based on the specific id, determine whether the arg list is valid
+ (number, type, rank, and kind of args) and fill in the info structure
+ accordingly. Currently don't rewrite the expression, but perhaps
+ someday do so for constant collapsing, except when an error occurs,
+ in which case it is overwritten with ANY and info is also overwritten
+ accordingly. */
+
+void
+ffeintrin_fulfill_specific (ffebld *expr, ffeinfo *info, ffelexToken t)
+{
+ ffebld symter;
+ ffebldOp op;
+ ffeintrinSpec spec;
+ ffeintrinImp imp;
+ ffeinfoBasictype bt = FFEINFO_basictypeNONE;
+ ffeinfoKindtype kt = FFEINFO_kindtypeNONE;
+ ffetargetCharacterSize sz = FFETARGET_charactersizeNONE;
+ ffeIntrinsicState state;
+ ffebad error;
+ bool any = FALSE;
+
+ op = ffebld_op (*expr);
+ assert ((op == FFEBLD_opFUNCREF) || (op == FFEBLD_opSUBRREF));
+ assert (ffebld_op (ffebld_left (*expr)) == FFEBLD_opSYMTER);
+
+ spec = ffebld_symter_specific (ffebld_left (*expr));
+ assert (spec != FFEINTRIN_specNONE);
+
+ state = ffeintrin_state_family (ffeintrin_specs_[spec].family);
+
+ imp = ffeintrin_specs_[spec].implementation;
+
+ any = ffeintrin_check_any_ (ffebld_right (*expr));
+
+ if (state == FFE_intrinsicstateDISABLED)
+ error = FFEBAD_INTRINSIC_DISABLED;
+ else if (imp == FFEINTRIN_impNONE)
+ error = FFEBAD_INTRINSIC_UNIMPL;
+ else if (!any)
+ {
+ error = ffeintrin_check_ (imp, ffebld_op (*expr),
+ ffebld_right (*expr),
+ &bt, &kt, &sz, t, TRUE);
+ }
+
+ if (any || (error != FFEBAD))
+ {
+ if (!any)
+ {
+ char *name;
+
+ ffebad_start (error);
+ ffebad_here (0, ffelex_token_where_line (t),
+ ffelex_token_where_column (t));
+ if (imp == FFEINTRIN_impNONE)
+ name = ffeintrin_specs_[spec].name;
+ else
+ name = ffeintrin_imps_[imp].name;
+ ffebad_string (name);
+ ffebad_finish ();
+ }
+
+ *expr = ffebld_new_any ();
+ *info = ffeinfo_new_any ();
+ }
+ else
+ {
+ *info = ffeinfo_new (bt,
+ kt,
+ 0,
+ FFEINFO_kindENTITY,
+ FFEINFO_whereFLEETING,
+ sz);
+ symter = ffebld_left (*expr);
+ ffebld_set_info (symter,
+ ffeinfo_new (bt,
+ kt,
+ 0,
+ (bt == FFEINFO_basictypeNONE)
+ ? FFEINFO_kindSUBROUTINE
+ : FFEINFO_kindFUNCTION,
+ FFEINFO_whereINTRINSIC,
+ sz));
+ }
+}
+
+/* Return run-time index of intrinsic implementation as arg. */
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+ffecomGfrt
+ffeintrin_gfrt (ffeintrinImp imp)
+{
+ assert (imp < FFEINTRIN_imp);
+ return ffeintrin_imps_[imp].gfrt;
+}
+
+#endif
+void
+ffeintrin_init_0 ()
+{
+ int i;
+ char *p1;
+ char *p2;
+ char *p3;
+
+ if (!ffe_is_do_internal_checks())
+ return;
+
+ assert (FFEINTRIN_gen == ARRAY_SIZE (ffeintrin_gens_));
+ assert (FFEINTRIN_imp == ARRAY_SIZE (ffeintrin_imps_));
+ assert (FFEINTRIN_spec == ARRAY_SIZE (ffeintrin_specs_));
+
+ for (i = 1; ((size_t) i) < ARRAY_SIZE (ffeintrin_names_); ++i)
+ { /* Make sure binary-searched list is in alpha
+ order. */
+ if (strcmp (ffeintrin_names_[i - 1].name_uc,
+ ffeintrin_names_[i].name_uc) >= 0)
+ assert ("name list out of order" == NULL);
+ }
+
+ for (i = 0; ((size_t) i) < ARRAY_SIZE (ffeintrin_names_); ++i)
+ {
+ p1 = ffeintrin_names_[i].name_uc;
+ p2 = ffeintrin_names_[i].name_lc;
+ p3 = ffeintrin_names_[i].name_ic;
+ for (; *p1 != '\0' && *p2 != '\0' && *p3 != '\0'; ++p1, ++p2, ++p3)
+ {
+ if (!isascii (*p1) || !isascii (*p2) || !isascii (*p3))
+ break;
+ if ((isdigit (*p1) || (*p1 == '_')) && (*p1 == *p2) && (*p1 == *p3))
+ continue;
+ if (!isupper (*p1) || !islower (*p2)
+ || (*p1 != toupper (*p2)) || ((*p3 != *p1) && (*p3 != *p2)))
+ break;
+ }
+ assert ((*p1 == *p2) && (*p1 == *p3) && (*p1 == '\0'));
+ }
+
+ for (i = 0; ((size_t) i) < ARRAY_SIZE (ffeintrin_imps_); ++i)
+ {
+ char *c = ffeintrin_imps_[i].control;
+
+ if (c[0] == '\0')
+ continue;
+
+ if ((c[0] != '-')
+ && (c[0] != 'A')
+ && (c[0] != 'C')
+ && (c[0] != 'I')
+ && (c[0] != 'L')
+ && (c[0] != 'R')
+ && (c[0] != 'B')
+ && (c[0] != 'F')
+ && (c[0] != 'N')
+ && (c[0] != 'S'))
+ {
+ fprintf (stderr, "%s: bad return-base-type\n",
+ ffeintrin_imps_[i].name);
+ continue;
+ }
+ if ((c[1] != '-')
+ && (c[1] != '0')
+ && (c[1] != '1')
+ && (c[1] != '2')
+ && (c[1] != '3')
+ && (c[1] != 'C'))
+ {
+ fprintf (stderr, "%s: bad return-kind-type\n",
+ ffeintrin_imps_[i].name);
+ continue;
+ }
+ if ((c[2] != ':') || (c[4] != ':'))
+ {
+ fprintf (stderr, "%s: bad control\n",
+ ffeintrin_imps_[i].name);
+ continue;
+ }
+ if ((c[3] != '-')
+ && (c[3] != '*')
+ && (c[3] != '1'))
+ {
+ fprintf (stderr, "%s: bad COL-spec\n",
+ ffeintrin_imps_[i].name);
+ continue;
+ }
+ c += 5;
+ while (c[0] != '\0')
+ {
+ while ((c[0] != '=')
+ && (c[0] != ',')
+ && (c[0] != '\0'))
+ ++c;
+ if (c[0] != '=')
+ {
+ fprintf (stderr, "%s: bad keyword\n",
+ ffeintrin_imps_[i].name);
+ break;
+ }
+ if ((c[1] == '?')
+ || (c[1] == '!')
+ || (c[1] == '!')
+ || (c[1] == '+')
+ || (c[1] == '*')
+ || (c[1] == 'n')
+ || (c[1] == 'p'))
+ ++c;
+ if (((c[1] != '-')
+ && (c[1] != 'A')
+ && (c[1] != 'C')
+ && (c[1] != 'I')
+ && (c[1] != 'L')
+ && (c[1] != 'R')
+ && (c[1] != 'B')
+ && (c[1] != 'F')
+ && (c[1] != 'N')
+ && (c[1] != 'S'))
+ || ((c[2] != '0')
+ && (c[2] != '1')
+ && (c[2] != '2')
+ && (c[2] != '3')
+ && (c[2] != 'A')
+ && (c[2] != 's')))
+ {
+ fprintf (stderr, "%s: bad arg-type\n",
+ ffeintrin_imps_[i].name);
+ break;
+ }
+ if ((c[3] == '&')
+ || (c[3] == 'w')
+ || (c[3] == 'x'))
+ ++c;
+ if (c[3] == ',')
+ {
+ c += 4;
+ break;
+ }
+ if (c[3] != '\0')
+ {
+ fprintf (stderr, "%s: bad arg-list\n",
+ ffeintrin_imps_[i].name);
+ }
+ break;
+ }
+ }
+}
+
+/* Determine whether intrinsic ok as actual arg. */
+
+bool
+ffeintrin_is_actualarg (ffeintrinSpec spec)
+{
+ ffeIntrinsicState state;
+
+ if (spec >= FFEINTRIN_spec)
+ return FALSE;
+
+ state = ffeintrin_state_family (ffeintrin_specs_[spec].family);
+
+ return (!ffe_is_pedantic () || ffeintrin_specs_[spec].is_actualarg)
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+ && (ffeintrin_imps_[ffeintrin_specs_[spec].implementation].gfrt
+ != FFECOM_gfrt)
+#endif
+ && ((state == FFE_intrinsicstateENABLED)
+ || (state == FFE_intrinsicstateHIDDEN));
+}
+
+/* Determine if name is intrinsic, return info.
+
+ char *name; // C-string name of possible intrinsic.
+ ffelexToken t; // NULL if no diagnostic to be given.
+ bool explicit; // TRUE if INTRINSIC name.
+ ffeintrinGen gen; // (TRUE only) Generic id of intrinsic.
+ ffeintrinSpec spec; // (TRUE only) Specific id of intrinsic.
+ ffeintrinImp imp; // (TRUE only) Implementation id of intrinsic.
+ ffeinfoKind kind; // (TRUE:) kindFUNCTION, kindSUBROUTINE,
+ // or kindNONE; (FALSE:) kindANY, kindNONE.
+ if (ffeintrin_is_intrinsic (name, t, &gen, &spec, &imp, &kind))
+ // is an intrinsic, use gen, spec, imp, and
+ // kind accordingly.
+
+ If FALSE is returned, kindANY says that the intrinsic exists but is
+ not valid for some reason (disabled or unimplemented), in which case a
+ diagnostic was generated (assuming t == NULL). */
+
+bool
+ffeintrin_is_intrinsic (char *name, ffelexToken t, bool explicit,
+ ffeintrinGen *xgen, ffeintrinSpec *xspec,
+ ffeintrinImp *ximp, ffeinfoKind *xkind)
+{
+ struct _ffeintrin_name_ *intrinsic;
+ ffeintrinGen gen;
+ ffeintrinSpec spec;
+ ffeintrinImp imp;
+ ffeinfoKind kind;
+ ffeIntrinsicState state;
+ bool disabled = FALSE;
+ bool unimpl = FALSE;
+
+ intrinsic = bsearch (name, &ffeintrin_names_[0],
+ ARRAY_SIZE (ffeintrin_names_),
+ sizeof (struct _ffeintrin_name_),
+ (void *) ffeintrin_cmp_name_);
+
+ if (intrinsic == NULL)
+ return FALSE;
+
+ gen = intrinsic->generic;
+ spec = intrinsic->specific;
+ imp = ffeintrin_specs_[spec].implementation;
+
+ /* Generic is okay only if at least one of its specifics is okay. */
+
+ if (gen != FFEINTRIN_genNONE)
+ {
+ int i;
+ ffeintrinSpec tspec;
+ bool ok = FALSE;
+
+ for (i = 0;
+ (((size_t) i) < ARRAY_SIZE (ffeintrin_gens_[gen].specs))
+ && ((tspec
+ = ffeintrin_gens_[gen].specs[i]) != FFEINTRIN_specNONE);
+ ++i)
+ {
+ state = ffeintrin_state_family (ffeintrin_specs_[tspec].family);
+
+ if (state == FFE_intrinsicstateDELETED)
+ continue;
+
+ if (state == FFE_intrinsicstateDISABLED)
+ {
+ disabled = TRUE;
+ continue;
+ }
+
+ if (ffeintrin_specs_[tspec].implementation == FFEINTRIN_impNONE)
+ {
+ unimpl = TRUE;
+ continue;
+ }
+
+ if ((state == FFE_intrinsicstateENABLED)
+ || (explicit
+ && (state == FFE_intrinsicstateHIDDEN)))
+ {
+ ok = TRUE;
+ break;
+ }
+ }
+ if (!ok)
+ gen = FFEINTRIN_genNONE;
+ }
+
+ /* Specific is okay only if not: unimplemented, disabled, deleted, or
+ hidden and not explicit. */
+
+ if (spec != FFEINTRIN_specNONE)
+ {
+ if (((state = ffeintrin_state_family (ffeintrin_specs_[spec].family))
+ == FFE_intrinsicstateDELETED)
+ || (!explicit
+ && (state == FFE_intrinsicstateHIDDEN)))
+ spec = FFEINTRIN_specNONE;
+ else if (state == FFE_intrinsicstateDISABLED)
+ {
+ disabled = TRUE;
+ spec = FFEINTRIN_specNONE;
+ }
+ else if (imp == FFEINTRIN_impNONE)
+ {
+ unimpl = TRUE;
+ spec = FFEINTRIN_specNONE;
+ }
+ }
+
+ /* If neither is okay, not an intrinsic. */
+
+ if ((gen == FFEINTRIN_genNONE) && (spec == FFEINTRIN_specNONE))
+ {
+ /* Here is where we produce a diagnostic about a reference to a
+ disabled or unimplemented intrinsic, if the diagnostic is desired. */
+
+ if ((disabled || unimpl)
+ && (t != NULL))
+ {
+ ffebad_start (disabled
+ ? FFEBAD_INTRINSIC_DISABLED
+ : FFEBAD_INTRINSIC_UNIMPL);
+ ffebad_here (0, ffelex_token_where_line (t), ffelex_token_where_column (t));
+ ffebad_string (name);
+ ffebad_finish ();
+ }
+
+ if (disabled || unimpl)
+ *xkind = FFEINFO_kindANY;
+ else
+ *xkind = FFEINFO_kindNONE;
+ return FALSE;
+ }
+
+ /* Determine whether intrinsic is function or subroutine. If no specific
+ id, scan list of possible specifics for generic to get consensus. Must
+ be unanimous, at least for now. */
+
+ if (spec == FFEINTRIN_specNONE)
+ {
+ int i;
+ ffeintrinSpec tspec;
+ ffeintrinImp timp;
+ ffeinfoKind tkind;
+
+ kind = FFEINFO_kindNONE;
+
+ for (i = 0;
+ (((size_t) i) < ARRAY_SIZE (ffeintrin_gens_[gen].specs))
+ && ((tspec
+ = ffeintrin_gens_[gen].specs[i]) != FFEINTRIN_specNONE);
+ ++i)
+ {
+ if ((timp = ffeintrin_specs_[tspec].implementation)
+ == FFEINTRIN_impNONE)
+ continue;
+
+ if (ffeintrin_imps_[timp].control[0] == '-')
+ tkind = FFEINFO_kindSUBROUTINE;
+ else
+ tkind = FFEINFO_kindFUNCTION;
+
+ if ((kind == tkind) || (kind == FFEINFO_kindNONE))
+ kind = tkind;
+ else
+ assert ("what kind of proc am i?" == NULL);
+ }
+ }
+ else /* Have specific, use that. */
+ kind
+ = (ffeintrin_imps_[imp].control[0] == '-')
+ ? FFEINFO_kindSUBROUTINE
+ : FFEINFO_kindFUNCTION;
+
+ *xgen = gen;
+ *xspec = spec;
+ *ximp = imp;
+ *xkind = kind;
+ return TRUE;
+}
+
+/* Return kind type of intrinsic implementation. */
+
+ffeinfoKindtype
+ffeintrin_kindtype (ffeintrinSpec spec)
+{
+ assert (spec < FFEINTRIN_spec);
+ return FFEINFO_kindtypeNONE;
+}
+
+/* Return name of generic intrinsic. */
+
+char *
+ffeintrin_name_generic (ffeintrinGen gen)
+{
+ assert (gen < FFEINTRIN_gen);
+ return ffeintrin_gens_[gen].name;
+}
+
+/* Return name of intrinsic implementation. */
+
+char *
+ffeintrin_name_implementation (ffeintrinImp imp)
+{
+ assert (imp < FFEINTRIN_imp);
+ return ffeintrin_imps_[imp].name;
+}
+
+/* Return external/internal name of specific intrinsic. */
+
+char *
+ffeintrin_name_specific (ffeintrinSpec spec)
+{
+ assert (spec < FFEINTRIN_spec);
+ return ffeintrin_specs_[spec].name;
+}
+
+/* Return state of family. */
+
+ffeIntrinsicState
+ffeintrin_state_family (ffeintrinFamily family)
+{
+ ffeIntrinsicState state;
+
+ switch (family)
+ {
+ case FFEINTRIN_familyNONE:
+ return FFE_intrinsicstateDELETED;
+
+ case FFEINTRIN_familyF77:
+ return FFE_intrinsicstateENABLED;
+
+ case FFEINTRIN_familyASC:
+ state = ffe_intrinsic_state_f2c ();
+ state = ffe_state_max (state, ffe_intrinsic_state_f90 ());
+ return state;
+
+ case FFEINTRIN_familyMIL:
+ state = ffe_intrinsic_state_vxt ();
+ state = ffe_state_max (state, ffe_intrinsic_state_f90 ());
+ state = ffe_state_max (state, ffe_intrinsic_state_mil ());
+ return state;
+
+ case FFEINTRIN_familyDCP:
+ state = ffe_intrinsic_state_vxt ();
+ state = ffe_state_max (state, ffe_intrinsic_state_f90 ());
+ state = ffe_state_max (state, ffe_intrinsic_state_dcp ());
+ return state;
+
+ case FFEINTRIN_familyF90:
+ state = ffe_intrinsic_state_f90 ();
+ return state;
+
+ case FFEINTRIN_familyVXT:
+ state = ffe_intrinsic_state_vxt ();
+ return state;
+
+ case FFEINTRIN_familyFVZ:
+ state = ffe_intrinsic_state_f2c ();
+ state = ffe_state_max (state, ffe_intrinsic_state_vxt ());
+ state = ffe_state_max (state, ffe_intrinsic_state_dcp ());
+ return state;
+
+ case FFEINTRIN_familyF2C:
+ state = ffe_intrinsic_state_f2c ();
+ return state;
+
+ case FFEINTRIN_familyF2Z:
+ state = ffe_intrinsic_state_f2c ();
+ return state;
+
+ case FFEINTRIN_familyF2U:
+ state = ffe_intrinsic_state_unix ();
+ return state;
+
+ default:
+ assert ("bad family" == NULL);
+ return FFE_intrinsicstateDELETED;
+ }
+}