re PR fortran/33387 (Fortran front-end should translate intrinsics by calling C99 function instead of libgfortran functions)
PR fortran/33387 * trans.h: Remove prototypes for gfor_fndecl_math_exponent4, gfor_fndecl_math_exponent8, gfor_fndecl_math_exponent10 and gfor_fndecl_math_exponent16. * f95-lang.c (build_builtin_fntypes): Add new function types. (gfc_init_builtin_functions): Add new builtins for nextafter, frexp, ldexp, fabs, scalbn and inf. * iresolve.c (gfc_resolve_rrspacing): Don't add hidden arguments. (gfc_resolve_scale): Don't convert type of second argument. (gfc_resolve_set_exponent): Likewise. (gfc_resolve_size): Don't add hidden arguments. * trans-decl.c: Remove gfor_fndecl_math_exponent4, gfor_fndecl_math_exponent8, gfor_fndecl_math_exponent10 and gfor_fndecl_math_exponent16. * trans-intrinsic.c (gfc_intrinsic_map): Remove intrinsics for scalbn, fraction, nearest, rrspacing, set_exponent and spacing. (gfc_conv_intrinsic_exponent): Directly call frexp. (gfc_conv_intrinsic_fraction, gfc_conv_intrinsic_nearest, gfc_conv_intrinsic_spacing, gfc_conv_intrinsic_rrspacing, gfc_conv_intrinsic_scale, gfc_conv_intrinsic_set_exponent): New functions. (gfc_conv_intrinsic_function): Use the new functions above. From-SVN: r132713
This commit is contained in:
parent
8bf6e27028
commit
b5a4419cde
@ -1,3 +1,29 @@
|
||||
2008-02-27 Francois-Xavier Coudert <fxcoudert@gcc.gnu.org>
|
||||
|
||||
PR fortran/33387
|
||||
* trans.h: Remove prototypes for gfor_fndecl_math_exponent4,
|
||||
gfor_fndecl_math_exponent8, gfor_fndecl_math_exponent10 and
|
||||
gfor_fndecl_math_exponent16.
|
||||
* f95-lang.c (build_builtin_fntypes): Add new function types.
|
||||
(gfc_init_builtin_functions): Add new builtins for nextafter,
|
||||
frexp, ldexp, fabs, scalbn and inf.
|
||||
* iresolve.c (gfc_resolve_rrspacing): Don't add hidden arguments.
|
||||
(gfc_resolve_scale): Don't convert type of second argument.
|
||||
(gfc_resolve_set_exponent): Likewise.
|
||||
(gfc_resolve_size): Don't add hidden arguments.
|
||||
* trans-decl.c: Remove gfor_fndecl_math_exponent4,
|
||||
gfor_fndecl_math_exponent8, gfor_fndecl_math_exponent10 and
|
||||
gfor_fndecl_math_exponent16.
|
||||
* trans-intrinsic.c (gfc_intrinsic_map): Remove intrinsics
|
||||
for scalbn, fraction, nearest, rrspacing, set_exponent and
|
||||
spacing.
|
||||
(gfc_conv_intrinsic_exponent): Directly call frexp.
|
||||
(gfc_conv_intrinsic_fraction, gfc_conv_intrinsic_nearest,
|
||||
gfc_conv_intrinsic_spacing, gfc_conv_intrinsic_rrspacing,
|
||||
gfc_conv_intrinsic_scale, gfc_conv_intrinsic_set_exponent): New
|
||||
functions.
|
||||
(gfc_conv_intrinsic_function): Use the new functions above.
|
||||
|
||||
2008-02-26 Tobias Burnus <burnus@net-b.de>
|
||||
|
||||
PR fortran/35033
|
||||
|
@ -756,6 +756,16 @@ build_builtin_fntypes (tree *fntype, tree type)
|
||||
tmp = tree_cons (NULL_TREE, integer_type_node, void_list_node);
|
||||
tmp = tree_cons (NULL_TREE, type, tmp);
|
||||
fntype[2] = build_function_type (type, tmp);
|
||||
/* type (*) (void) */
|
||||
fntype[3] = build_function_type (type, void_list_node);
|
||||
/* type (*) (type, &int) */
|
||||
tmp = tree_cons (NULL_TREE, type, void_list_node);
|
||||
tmp = tree_cons (NULL_TREE, build_pointer_type (integer_type_node), tmp);
|
||||
fntype[4] = build_function_type (type, tmp);
|
||||
/* type (*) (type, int) */
|
||||
tmp = tree_cons (NULL_TREE, type, void_list_node);
|
||||
tmp = tree_cons (NULL_TREE, integer_type_node, tmp);
|
||||
fntype[5] = build_function_type (type, tmp);
|
||||
}
|
||||
|
||||
|
||||
@ -806,12 +816,12 @@ gfc_init_builtin_functions (void)
|
||||
ATTR_CONST_NOTHROW_LIST
|
||||
};
|
||||
|
||||
tree mfunc_float[3];
|
||||
tree mfunc_double[3];
|
||||
tree mfunc_longdouble[3];
|
||||
tree mfunc_cfloat[3];
|
||||
tree mfunc_cdouble[3];
|
||||
tree mfunc_clongdouble[3];
|
||||
tree mfunc_float[6];
|
||||
tree mfunc_double[6];
|
||||
tree mfunc_longdouble[6];
|
||||
tree mfunc_cfloat[6];
|
||||
tree mfunc_cdouble[6];
|
||||
tree mfunc_clongdouble[6];
|
||||
tree func_cfloat_float, func_float_cfloat;
|
||||
tree func_cdouble_double, func_double_cdouble;
|
||||
tree func_clongdouble_longdouble, func_longdouble_clongdouble;
|
||||
@ -902,6 +912,34 @@ gfc_init_builtin_functions (void)
|
||||
gfc_define_builtin ("__builtin_copysignf", mfunc_float[1],
|
||||
BUILT_IN_COPYSIGNF, "copysignf", true);
|
||||
|
||||
gfc_define_builtin ("__builtin_nextafterl", mfunc_longdouble[1],
|
||||
BUILT_IN_NEXTAFTERL, "nextafterl", true);
|
||||
gfc_define_builtin ("__builtin_nextafter", mfunc_double[1],
|
||||
BUILT_IN_NEXTAFTER, "nextafter", true);
|
||||
gfc_define_builtin ("__builtin_nextafterf", mfunc_float[1],
|
||||
BUILT_IN_NEXTAFTERF, "nextafterf", true);
|
||||
|
||||
gfc_define_builtin ("__builtin_frexpl", mfunc_longdouble[4],
|
||||
BUILT_IN_FREXPL, "frexpl", false);
|
||||
gfc_define_builtin ("__builtin_frexp", mfunc_double[4],
|
||||
BUILT_IN_FREXP, "frexp", false);
|
||||
gfc_define_builtin ("__builtin_frexpf", mfunc_float[4],
|
||||
BUILT_IN_FREXPF, "frexpf", false);
|
||||
|
||||
gfc_define_builtin ("__builtin_fabsl", mfunc_longdouble[0],
|
||||
BUILT_IN_FABSL, "fabsl", true);
|
||||
gfc_define_builtin ("__builtin_fabs", mfunc_double[0],
|
||||
BUILT_IN_FABS, "fabs", true);
|
||||
gfc_define_builtin ("__builtin_fabsf", mfunc_float[0],
|
||||
BUILT_IN_FABSF, "fabsf", true);
|
||||
|
||||
gfc_define_builtin ("__builtin_scalbnl", mfunc_longdouble[5],
|
||||
BUILT_IN_SCALBNL, "scalbnl", true);
|
||||
gfc_define_builtin ("__builtin_scalbn", mfunc_double[5],
|
||||
BUILT_IN_SCALBN, "scalbn", true);
|
||||
gfc_define_builtin ("__builtin_scalbnf", mfunc_float[5],
|
||||
BUILT_IN_SCALBNF, "scalbnf", true);
|
||||
|
||||
gfc_define_builtin ("__builtin_fmodl", mfunc_longdouble[1],
|
||||
BUILT_IN_FMODL, "fmodl", true);
|
||||
gfc_define_builtin ("__builtin_fmod", mfunc_double[1],
|
||||
@ -909,6 +947,13 @@ gfc_init_builtin_functions (void)
|
||||
gfc_define_builtin ("__builtin_fmodf", mfunc_float[1],
|
||||
BUILT_IN_FMODF, "fmodf", true);
|
||||
|
||||
gfc_define_builtin ("__builtin_infl", mfunc_longdouble[3],
|
||||
BUILT_IN_INFL, "__builtin_infl", true);
|
||||
gfc_define_builtin ("__builtin_inf", mfunc_double[3],
|
||||
BUILT_IN_INF, "__builtin_inf", true);
|
||||
gfc_define_builtin ("__builtin_inff", mfunc_float[3],
|
||||
BUILT_IN_INFF, "__builtin_inff", true);
|
||||
|
||||
/* lround{f,,l} and llround{f,,l} */
|
||||
type = tree_cons (NULL_TREE, float_type_node, void_list_node);
|
||||
tmp = build_function_type (long_integer_type_node, type);
|
||||
|
@ -1853,47 +1853,15 @@ gfc_resolve_reshape (gfc_expr *f, gfc_expr *source, gfc_expr *shape,
|
||||
void
|
||||
gfc_resolve_rrspacing (gfc_expr *f, gfc_expr *x)
|
||||
{
|
||||
int k;
|
||||
gfc_actual_arglist *prec;
|
||||
|
||||
f->ts = x->ts;
|
||||
f->value.function.name = gfc_get_string ("__rrspacing_%d", x->ts.kind);
|
||||
|
||||
/* Create a hidden argument to the library routines for rrspacing. This
|
||||
hidden argument is the precision of x. */
|
||||
k = gfc_validate_kind (BT_REAL, x->ts.kind, false);
|
||||
prec = gfc_get_actual_arglist ();
|
||||
prec->name = "p";
|
||||
prec->expr = gfc_int_expr (gfc_real_kinds[k].digits);
|
||||
/* The library routine expects INTEGER(4). */
|
||||
if (prec->expr->ts.kind != gfc_c_int_kind)
|
||||
{
|
||||
gfc_typespec ts;
|
||||
gfc_clear_ts (&ts);
|
||||
ts.type = BT_INTEGER;
|
||||
ts.kind = gfc_c_int_kind;
|
||||
gfc_convert_type (prec->expr, &ts, 2);
|
||||
}
|
||||
f->value.function.actual->next = prec;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
gfc_resolve_scale (gfc_expr *f, gfc_expr *x, gfc_expr *i)
|
||||
gfc_resolve_scale (gfc_expr *f, gfc_expr *x, gfc_expr *i ATTRIBUTE_UNUSED)
|
||||
{
|
||||
f->ts = x->ts;
|
||||
|
||||
/* The implementation calls scalbn which takes an int as the
|
||||
second argument. */
|
||||
if (i->ts.kind != gfc_c_int_kind)
|
||||
{
|
||||
gfc_typespec ts;
|
||||
gfc_clear_ts (&ts);
|
||||
ts.type = BT_INTEGER;
|
||||
ts.kind = gfc_c_int_kind;
|
||||
gfc_convert_type_warn (i, &ts, 2, 0);
|
||||
}
|
||||
|
||||
f->value.function.name = gfc_get_string ("__scale_%d", x->ts.kind);
|
||||
}
|
||||
|
||||
@ -1921,22 +1889,10 @@ gfc_resolve_secnds (gfc_expr *t1, gfc_expr *t0)
|
||||
|
||||
|
||||
void
|
||||
gfc_resolve_set_exponent (gfc_expr *f, gfc_expr *x, gfc_expr *i)
|
||||
gfc_resolve_set_exponent (gfc_expr *f, gfc_expr *x,
|
||||
gfc_expr *i ATTRIBUTE_UNUSED)
|
||||
{
|
||||
f->ts = x->ts;
|
||||
|
||||
/* The library implementation uses GFC_INTEGER_4 unconditionally,
|
||||
convert type so we don't have to implement all possible
|
||||
permutations. */
|
||||
if (i->ts.kind != gfc_c_int_kind)
|
||||
{
|
||||
gfc_typespec ts;
|
||||
gfc_clear_ts (&ts);
|
||||
ts.type = BT_INTEGER;
|
||||
ts.kind = gfc_c_int_kind;
|
||||
gfc_convert_type_warn (i, &ts, 2, 0);
|
||||
}
|
||||
|
||||
f->value.function.name = gfc_get_string ("__set_exponent_%d", x->ts.kind);
|
||||
}
|
||||
|
||||
@ -2016,59 +1972,8 @@ gfc_resolve_size (gfc_expr *f, gfc_expr *array ATTRIBUTE_UNUSED,
|
||||
void
|
||||
gfc_resolve_spacing (gfc_expr *f, gfc_expr *x)
|
||||
{
|
||||
int k;
|
||||
gfc_actual_arglist *prec, *tiny, *emin_1;
|
||||
|
||||
f->ts = x->ts;
|
||||
f->value.function.name = gfc_get_string ("__spacing_%d", x->ts.kind);
|
||||
|
||||
/* Create hidden arguments to the library routine for spacing. These
|
||||
hidden arguments are tiny(x), min_exponent - 1, and the precision
|
||||
of x. */
|
||||
|
||||
k = gfc_validate_kind (BT_REAL, x->ts.kind, false);
|
||||
|
||||
tiny = gfc_get_actual_arglist ();
|
||||
tiny->name = "tiny";
|
||||
tiny->expr = gfc_get_expr ();
|
||||
tiny->expr->expr_type = EXPR_CONSTANT;
|
||||
tiny->expr->where = gfc_current_locus;
|
||||
tiny->expr->ts.type = x->ts.type;
|
||||
tiny->expr->ts.kind = x->ts.kind;
|
||||
mpfr_init (tiny->expr->value.real);
|
||||
mpfr_set (tiny->expr->value.real, gfc_real_kinds[k].tiny, GFC_RND_MODE);
|
||||
|
||||
emin_1 = gfc_get_actual_arglist ();
|
||||
emin_1->name = "emin";
|
||||
emin_1->expr = gfc_int_expr (gfc_real_kinds[k].min_exponent - 1);
|
||||
|
||||
/* The library routine expects INTEGER(4). */
|
||||
if (emin_1->expr->ts.kind != gfc_c_int_kind)
|
||||
{
|
||||
gfc_typespec ts;
|
||||
gfc_clear_ts (&ts);
|
||||
ts.type = BT_INTEGER;
|
||||
ts.kind = gfc_c_int_kind;
|
||||
gfc_convert_type (emin_1->expr, &ts, 2);
|
||||
}
|
||||
emin_1->next = tiny;
|
||||
|
||||
prec = gfc_get_actual_arglist ();
|
||||
prec->name = "prec";
|
||||
prec->expr = gfc_int_expr (gfc_real_kinds[k].digits);
|
||||
|
||||
/* The library routine expects INTEGER(4). */
|
||||
if (prec->expr->ts.kind != gfc_c_int_kind)
|
||||
{
|
||||
gfc_typespec ts;
|
||||
gfc_clear_ts (&ts);
|
||||
ts.type = BT_INTEGER;
|
||||
ts.kind = gfc_c_int_kind;
|
||||
gfc_convert_type (prec->expr, &ts, 2);
|
||||
}
|
||||
prec->next = emin_1;
|
||||
|
||||
f->value.function.actual->next = prec;
|
||||
}
|
||||
|
||||
|
||||
|
@ -102,10 +102,6 @@ gfc_powdecl_list gfor_fndecl_math_powi[4][3];
|
||||
tree gfor_fndecl_math_ishftc4;
|
||||
tree gfor_fndecl_math_ishftc8;
|
||||
tree gfor_fndecl_math_ishftc16;
|
||||
tree gfor_fndecl_math_exponent4;
|
||||
tree gfor_fndecl_math_exponent8;
|
||||
tree gfor_fndecl_math_exponent10;
|
||||
tree gfor_fndecl_math_exponent16;
|
||||
|
||||
|
||||
/* String functions. */
|
||||
@ -2010,10 +2006,6 @@ gfc_build_intrinsic_function_decls (void)
|
||||
tree gfc_int8_type_node = gfc_get_int_type (8);
|
||||
tree gfc_int16_type_node = gfc_get_int_type (16);
|
||||
tree gfc_logical4_type_node = gfc_get_logical_type (4);
|
||||
tree gfc_real4_type_node = gfc_get_real_type (4);
|
||||
tree gfc_real8_type_node = gfc_get_real_type (8);
|
||||
tree gfc_real10_type_node = gfc_get_real_type (10);
|
||||
tree gfc_real16_type_node = gfc_get_real_type (16);
|
||||
|
||||
/* String functions. */
|
||||
gfor_fndecl_compare_string =
|
||||
@ -2199,25 +2191,6 @@ gfc_build_intrinsic_function_decls (void)
|
||||
gfc_int4_type_node,
|
||||
gfc_int4_type_node);
|
||||
|
||||
gfor_fndecl_math_exponent4 =
|
||||
gfc_build_library_function_decl (get_identifier (PREFIX("exponent_r4")),
|
||||
gfc_int4_type_node,
|
||||
1, gfc_real4_type_node);
|
||||
gfor_fndecl_math_exponent8 =
|
||||
gfc_build_library_function_decl (get_identifier (PREFIX("exponent_r8")),
|
||||
gfc_int4_type_node,
|
||||
1, gfc_real8_type_node);
|
||||
if (gfc_real10_type_node)
|
||||
gfor_fndecl_math_exponent10 =
|
||||
gfc_build_library_function_decl (get_identifier (PREFIX("exponent_r10")),
|
||||
gfc_int4_type_node, 1,
|
||||
gfc_real10_type_node);
|
||||
if (gfc_real16_type_node)
|
||||
gfor_fndecl_math_exponent16 =
|
||||
gfc_build_library_function_decl (get_identifier (PREFIX("exponent_r16")),
|
||||
gfc_int4_type_node, 1,
|
||||
gfc_real16_type_node);
|
||||
|
||||
/* BLAS functions. */
|
||||
{
|
||||
tree pint = build_pointer_type (integer_type_node);
|
||||
|
@ -104,43 +104,19 @@ gfc_intrinsic_map_t;
|
||||
true, true, NAME, NULL_TREE, NULL_TREE, NULL_TREE, NULL_TREE, \
|
||||
NULL_TREE, NULL_TREE, NULL_TREE, NULL_TREE},
|
||||
|
||||
#define LIBM_FUNCTION(ID, NAME, HAVE_COMPLEX) \
|
||||
{ GFC_ISYM_ ## ID, END_BUILTINS, END_BUILTINS, END_BUILTINS, END_BUILTINS, \
|
||||
END_BUILTINS, END_BUILTINS, END_BUILTINS, END_BUILTINS, \
|
||||
true, HAVE_COMPLEX, true, NAME, NULL_TREE, NULL_TREE, NULL_TREE, \
|
||||
NULL_TREE, NULL_TREE, NULL_TREE, NULL_TREE, NULL_TREE }
|
||||
|
||||
#define LIBF_FUNCTION(ID, NAME, HAVE_COMPLEX) \
|
||||
{ GFC_ISYM_ ## ID, END_BUILTINS, END_BUILTINS, END_BUILTINS, END_BUILTINS, \
|
||||
END_BUILTINS, END_BUILTINS, END_BUILTINS, END_BUILTINS, \
|
||||
false, HAVE_COMPLEX, true, NAME, NULL_TREE, NULL_TREE, NULL_TREE, \
|
||||
NULL_TREE, NULL_TREE, NULL_TREE, NULL_TREE, NULL_TREE }
|
||||
|
||||
static GTY(()) gfc_intrinsic_map_t gfc_intrinsic_map[] =
|
||||
{
|
||||
/* Functions built into gcc itself. */
|
||||
#include "mathbuiltins.def"
|
||||
|
||||
/* Functions in libm. */
|
||||
/* ??? This does exist as BUILT_IN_SCALBN, but doesn't quite fit the
|
||||
pattern for other mathbuiltins.def entries. At present we have no
|
||||
optimizations for this in the common sources. */
|
||||
LIBM_FUNCTION (SCALE, "scalbn", false),
|
||||
|
||||
/* Functions in libgfortran. */
|
||||
LIBF_FUNCTION (FRACTION, "fraction", false),
|
||||
LIBF_FUNCTION (NEAREST, "nearest", false),
|
||||
LIBF_FUNCTION (RRSPACING, "rrspacing", false),
|
||||
LIBF_FUNCTION (SET_EXPONENT, "set_exponent", false),
|
||||
LIBF_FUNCTION (SPACING, "spacing", false),
|
||||
|
||||
/* End the list. */
|
||||
LIBF_FUNCTION (NONE, NULL, false)
|
||||
{ GFC_ISYM_NONE, END_BUILTINS, END_BUILTINS, END_BUILTINS, END_BUILTINS,
|
||||
END_BUILTINS, END_BUILTINS, END_BUILTINS, END_BUILTINS,
|
||||
true, false, true, NULL, NULL_TREE, NULL_TREE, NULL_TREE,
|
||||
NULL_TREE, NULL_TREE, NULL_TREE, NULL_TREE, NULL_TREE }
|
||||
};
|
||||
#undef DEFINE_MATH_BUILTIN
|
||||
#undef DEFINE_MATH_BUILTIN_C
|
||||
#undef LIBM_FUNCTION
|
||||
#undef LIBF_FUNCTION
|
||||
|
||||
/* Structure for storing components of a floating number to be used by
|
||||
elemental functions to manipulate reals. */
|
||||
@ -727,38 +703,43 @@ gfc_conv_intrinsic_lib_function (gfc_se * se, gfc_expr * expr)
|
||||
se->expr = build_call_array (rettype, fndecl, num_args, args);
|
||||
}
|
||||
|
||||
/* Generate code for EXPONENT(X) intrinsic function. */
|
||||
/* The EXPONENT(s) intrinsic function is translated into
|
||||
int ret;
|
||||
frexp (s, &ret);
|
||||
return ret;
|
||||
*/
|
||||
|
||||
static void
|
||||
gfc_conv_intrinsic_exponent (gfc_se *se, gfc_expr *expr)
|
||||
{
|
||||
tree arg, fndecl, type;
|
||||
gfc_expr *a1;
|
||||
tree arg, type, res, tmp;
|
||||
int frexp;
|
||||
|
||||
gfc_conv_intrinsic_function_args (se, expr, &arg, 1);
|
||||
|
||||
a1 = expr->value.function.actual->expr;
|
||||
switch (a1->ts.kind)
|
||||
switch (expr->value.function.actual->expr->ts.kind)
|
||||
{
|
||||
case 4:
|
||||
fndecl = gfor_fndecl_math_exponent4;
|
||||
frexp = BUILT_IN_FREXPF;
|
||||
break;
|
||||
case 8:
|
||||
fndecl = gfor_fndecl_math_exponent8;
|
||||
frexp = BUILT_IN_FREXP;
|
||||
break;
|
||||
case 10:
|
||||
fndecl = gfor_fndecl_math_exponent10;
|
||||
break;
|
||||
case 16:
|
||||
fndecl = gfor_fndecl_math_exponent16;
|
||||
frexp = BUILT_IN_FREXPL;
|
||||
break;
|
||||
default:
|
||||
gcc_unreachable ();
|
||||
}
|
||||
|
||||
/* Convert it to the required type. */
|
||||
gfc_conv_intrinsic_function_args (se, expr, &arg, 1);
|
||||
|
||||
res = gfc_create_var (integer_type_node, NULL);
|
||||
tmp = build_call_expr (built_in_decls[frexp], 2, arg,
|
||||
build_fold_addr_expr (res));
|
||||
gfc_add_expr_to_block (&se->pre, tmp);
|
||||
|
||||
type = gfc_typenode_for_spec (&expr->ts);
|
||||
se->expr = fold_convert (type, build_call_expr (fndecl, 1, arg));
|
||||
se->expr = fold_convert (type, res);
|
||||
}
|
||||
|
||||
/* Evaluate a single upper or lower bound. */
|
||||
@ -2823,6 +2804,310 @@ gfc_conv_intrinsic_merge (gfc_se * se, gfc_expr * expr)
|
||||
}
|
||||
|
||||
|
||||
/* FRACTION (s) is translated into frexp (s, &dummy_int). */
|
||||
static void
|
||||
gfc_conv_intrinsic_fraction (gfc_se * se, gfc_expr * expr)
|
||||
{
|
||||
tree arg, type, tmp;
|
||||
int frexp;
|
||||
|
||||
switch (expr->ts.kind)
|
||||
{
|
||||
case 4:
|
||||
frexp = BUILT_IN_FREXPF;
|
||||
break;
|
||||
case 8:
|
||||
frexp = BUILT_IN_FREXP;
|
||||
break;
|
||||
case 10:
|
||||
case 16:
|
||||
frexp = BUILT_IN_FREXPL;
|
||||
break;
|
||||
default:
|
||||
gcc_unreachable ();
|
||||
}
|
||||
|
||||
type = gfc_typenode_for_spec (&expr->ts);
|
||||
gfc_conv_intrinsic_function_args (se, expr, &arg, 1);
|
||||
tmp = gfc_create_var (integer_type_node, NULL);
|
||||
se->expr = build_call_expr (built_in_decls[frexp], 2,
|
||||
fold_convert (type, arg),
|
||||
build_fold_addr_expr (tmp));
|
||||
se->expr = fold_convert (type, se->expr);
|
||||
}
|
||||
|
||||
|
||||
/* NEAREST (s, dir) is translated into
|
||||
tmp = copysign (INF, dir);
|
||||
return nextafter (s, tmp);
|
||||
*/
|
||||
static void
|
||||
gfc_conv_intrinsic_nearest (gfc_se * se, gfc_expr * expr)
|
||||
{
|
||||
tree args[2], type, tmp;
|
||||
int nextafter, copysign, inf;
|
||||
|
||||
switch (expr->ts.kind)
|
||||
{
|
||||
case 4:
|
||||
nextafter = BUILT_IN_NEXTAFTERF;
|
||||
copysign = BUILT_IN_COPYSIGNF;
|
||||
inf = BUILT_IN_INFF;
|
||||
break;
|
||||
case 8:
|
||||
nextafter = BUILT_IN_NEXTAFTER;
|
||||
copysign = BUILT_IN_COPYSIGN;
|
||||
inf = BUILT_IN_INF;
|
||||
break;
|
||||
case 10:
|
||||
case 16:
|
||||
nextafter = BUILT_IN_NEXTAFTERL;
|
||||
copysign = BUILT_IN_COPYSIGNL;
|
||||
inf = BUILT_IN_INFL;
|
||||
break;
|
||||
default:
|
||||
gcc_unreachable ();
|
||||
}
|
||||
|
||||
type = gfc_typenode_for_spec (&expr->ts);
|
||||
gfc_conv_intrinsic_function_args (se, expr, args, 2);
|
||||
tmp = build_call_expr (built_in_decls[copysign], 2,
|
||||
build_call_expr (built_in_decls[inf], 0),
|
||||
fold_convert (type, args[1]));
|
||||
se->expr = build_call_expr (built_in_decls[nextafter], 2,
|
||||
fold_convert (type, args[0]), tmp);
|
||||
se->expr = fold_convert (type, se->expr);
|
||||
}
|
||||
|
||||
|
||||
/* SPACING (s) is translated into
|
||||
int e;
|
||||
if (s == 0)
|
||||
res = tiny;
|
||||
else
|
||||
{
|
||||
frexp (s, &e);
|
||||
e = e - prec;
|
||||
e = MAX_EXPR (e, emin);
|
||||
res = scalbn (1., e);
|
||||
}
|
||||
return res;
|
||||
|
||||
where prec is the precision of s, gfc_real_kinds[k].digits,
|
||||
emin is min_exponent - 1, gfc_real_kinds[k].min_exponent - 1,
|
||||
and tiny is tiny(s), gfc_real_kinds[k].tiny. */
|
||||
|
||||
static void
|
||||
gfc_conv_intrinsic_spacing (gfc_se * se, gfc_expr * expr)
|
||||
{
|
||||
tree arg, type, prec, emin, tiny, res, e;
|
||||
tree cond, tmp;
|
||||
int frexp, scalbn, k;
|
||||
stmtblock_t block;
|
||||
|
||||
k = gfc_validate_kind (BT_REAL, expr->ts.kind, false);
|
||||
prec = build_int_cst (NULL_TREE, gfc_real_kinds[k].digits);
|
||||
emin = build_int_cst (NULL_TREE, gfc_real_kinds[k].min_exponent - 1);
|
||||
tiny = gfc_conv_mpfr_to_tree (gfc_real_kinds[k].tiny, expr->ts.kind);
|
||||
|
||||
switch (expr->ts.kind)
|
||||
{
|
||||
case 4:
|
||||
frexp = BUILT_IN_FREXPF;
|
||||
scalbn = BUILT_IN_SCALBNF;
|
||||
break;
|
||||
case 8:
|
||||
frexp = BUILT_IN_FREXP;
|
||||
scalbn = BUILT_IN_SCALBN;
|
||||
break;
|
||||
case 10:
|
||||
case 16:
|
||||
frexp = BUILT_IN_FREXPL;
|
||||
scalbn = BUILT_IN_SCALBNL;
|
||||
break;
|
||||
default:
|
||||
gcc_unreachable ();
|
||||
}
|
||||
|
||||
gfc_conv_intrinsic_function_args (se, expr, &arg, 1);
|
||||
arg = gfc_evaluate_now (arg, &se->pre);
|
||||
|
||||
type = gfc_typenode_for_spec (&expr->ts);
|
||||
e = gfc_create_var (integer_type_node, NULL);
|
||||
res = gfc_create_var (type, NULL);
|
||||
|
||||
|
||||
/* Build the block for s /= 0. */
|
||||
gfc_start_block (&block);
|
||||
tmp = build_call_expr (built_in_decls[frexp], 2, arg,
|
||||
build_fold_addr_expr (e));
|
||||
gfc_add_expr_to_block (&block, tmp);
|
||||
|
||||
tmp = fold_build2 (MINUS_EXPR, integer_type_node, e, prec);
|
||||
gfc_add_modify_expr (&block, e, fold_build2 (MAX_EXPR, integer_type_node,
|
||||
tmp, emin));
|
||||
|
||||
tmp = build_call_expr (built_in_decls[scalbn], 2,
|
||||
build_real_from_int_cst (type, integer_one_node), e);
|
||||
gfc_add_modify_expr (&block, res, tmp);
|
||||
|
||||
/* Finish by building the IF statement. */
|
||||
cond = fold_build2 (EQ_EXPR, boolean_type_node, arg,
|
||||
build_real_from_int_cst (type, integer_zero_node));
|
||||
tmp = build3_v (COND_EXPR, cond, build2_v (MODIFY_EXPR, res, tiny),
|
||||
gfc_finish_block (&block));
|
||||
|
||||
gfc_add_expr_to_block (&se->pre, tmp);
|
||||
se->expr = res;
|
||||
}
|
||||
|
||||
|
||||
/* RRSPACING (s) is translated into
|
||||
int e;
|
||||
real x;
|
||||
x = fabs (s);
|
||||
if (x != 0)
|
||||
{
|
||||
frexp (s, &e);
|
||||
x = scalbn (x, precision - e);
|
||||
}
|
||||
return x;
|
||||
|
||||
where precision is gfc_real_kinds[k].digits. */
|
||||
|
||||
static void
|
||||
gfc_conv_intrinsic_rrspacing (gfc_se * se, gfc_expr * expr)
|
||||
{
|
||||
tree arg, type, e, x, cond, stmt, tmp;
|
||||
int frexp, scalbn, fabs, prec, k;
|
||||
stmtblock_t block;
|
||||
|
||||
k = gfc_validate_kind (BT_REAL, expr->ts.kind, false);
|
||||
prec = gfc_real_kinds[k].digits;
|
||||
switch (expr->ts.kind)
|
||||
{
|
||||
case 4:
|
||||
frexp = BUILT_IN_FREXPF;
|
||||
scalbn = BUILT_IN_SCALBNF;
|
||||
fabs = BUILT_IN_FABSF;
|
||||
break;
|
||||
case 8:
|
||||
frexp = BUILT_IN_FREXP;
|
||||
scalbn = BUILT_IN_SCALBN;
|
||||
fabs = BUILT_IN_FABS;
|
||||
break;
|
||||
case 10:
|
||||
case 16:
|
||||
frexp = BUILT_IN_FREXPL;
|
||||
scalbn = BUILT_IN_SCALBNL;
|
||||
fabs = BUILT_IN_FABSL;
|
||||
break;
|
||||
default:
|
||||
gcc_unreachable ();
|
||||
}
|
||||
|
||||
type = gfc_typenode_for_spec (&expr->ts);
|
||||
gfc_conv_intrinsic_function_args (se, expr, &arg, 1);
|
||||
arg = gfc_evaluate_now (arg, &se->pre);
|
||||
|
||||
e = gfc_create_var (integer_type_node, NULL);
|
||||
x = gfc_create_var (type, NULL);
|
||||
gfc_add_modify_expr (&se->pre, x,
|
||||
build_call_expr (built_in_decls[fabs], 1, arg));
|
||||
|
||||
|
||||
gfc_start_block (&block);
|
||||
tmp = build_call_expr (built_in_decls[frexp], 2, arg,
|
||||
build_fold_addr_expr (e));
|
||||
gfc_add_expr_to_block (&block, tmp);
|
||||
|
||||
tmp = fold_build2 (MINUS_EXPR, integer_type_node,
|
||||
build_int_cst (NULL_TREE, prec), e);
|
||||
tmp = build_call_expr (built_in_decls[scalbn], 2, x, tmp);
|
||||
gfc_add_modify_expr (&block, x, tmp);
|
||||
stmt = gfc_finish_block (&block);
|
||||
|
||||
cond = fold_build2 (NE_EXPR, boolean_type_node, x,
|
||||
build_real_from_int_cst (type, integer_zero_node));
|
||||
tmp = build3_v (COND_EXPR, cond, stmt, build_empty_stmt ());
|
||||
gfc_add_expr_to_block (&se->pre, tmp);
|
||||
|
||||
se->expr = fold_convert (type, x);
|
||||
}
|
||||
|
||||
|
||||
/* SCALE (s, i) is translated into scalbn (s, i). */
|
||||
static void
|
||||
gfc_conv_intrinsic_scale (gfc_se * se, gfc_expr * expr)
|
||||
{
|
||||
tree args[2], type;
|
||||
int scalbn;
|
||||
|
||||
switch (expr->ts.kind)
|
||||
{
|
||||
case 4:
|
||||
scalbn = BUILT_IN_SCALBNF;
|
||||
break;
|
||||
case 8:
|
||||
scalbn = BUILT_IN_SCALBN;
|
||||
break;
|
||||
case 10:
|
||||
case 16:
|
||||
scalbn = BUILT_IN_SCALBNL;
|
||||
break;
|
||||
default:
|
||||
gcc_unreachable ();
|
||||
}
|
||||
|
||||
type = gfc_typenode_for_spec (&expr->ts);
|
||||
gfc_conv_intrinsic_function_args (se, expr, args, 2);
|
||||
se->expr = build_call_expr (built_in_decls[scalbn], 2,
|
||||
fold_convert (type, args[0]),
|
||||
fold_convert (integer_type_node, args[1]));
|
||||
se->expr = fold_convert (type, se->expr);
|
||||
}
|
||||
|
||||
|
||||
/* SET_EXPONENT (s, i) is translated into
|
||||
scalbn (frexp (s, &dummy_int), i). */
|
||||
static void
|
||||
gfc_conv_intrinsic_set_exponent (gfc_se * se, gfc_expr * expr)
|
||||
{
|
||||
tree args[2], type, tmp;
|
||||
int frexp, scalbn;
|
||||
|
||||
switch (expr->ts.kind)
|
||||
{
|
||||
case 4:
|
||||
frexp = BUILT_IN_FREXPF;
|
||||
scalbn = BUILT_IN_SCALBNF;
|
||||
break;
|
||||
case 8:
|
||||
frexp = BUILT_IN_FREXP;
|
||||
scalbn = BUILT_IN_SCALBN;
|
||||
break;
|
||||
case 10:
|
||||
case 16:
|
||||
frexp = BUILT_IN_FREXPL;
|
||||
scalbn = BUILT_IN_SCALBNL;
|
||||
break;
|
||||
default:
|
||||
gcc_unreachable ();
|
||||
}
|
||||
|
||||
type = gfc_typenode_for_spec (&expr->ts);
|
||||
gfc_conv_intrinsic_function_args (se, expr, args, 2);
|
||||
|
||||
tmp = gfc_create_var (integer_type_node, NULL);
|
||||
tmp = build_call_expr (built_in_decls[frexp], 2,
|
||||
fold_convert (type, args[0]),
|
||||
build_fold_addr_expr (tmp));
|
||||
se->expr = build_call_expr (built_in_decls[scalbn], 2, tmp,
|
||||
fold_convert (integer_type_node, args[1]));
|
||||
se->expr = fold_convert (type, se->expr);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
gfc_conv_intrinsic_size (gfc_se * se, gfc_expr * expr)
|
||||
{
|
||||
@ -3899,6 +4184,10 @@ gfc_conv_intrinsic_function (gfc_se * se, gfc_expr * expr)
|
||||
gfc_conv_intrinsic_fdate (se, expr);
|
||||
break;
|
||||
|
||||
case GFC_ISYM_FRACTION:
|
||||
gfc_conv_intrinsic_fraction (se, expr);
|
||||
break;
|
||||
|
||||
case GFC_ISYM_IAND:
|
||||
gfc_conv_intrinsic_bitop (se, expr, BIT_AND_EXPR);
|
||||
break;
|
||||
@ -4037,6 +4326,10 @@ gfc_conv_intrinsic_function (gfc_se * se, gfc_expr * expr)
|
||||
gfc_conv_intrinsic_minmaxval (se, expr, LT_EXPR);
|
||||
break;
|
||||
|
||||
case GFC_ISYM_NEAREST:
|
||||
gfc_conv_intrinsic_nearest (se, expr);
|
||||
break;
|
||||
|
||||
case GFC_ISYM_NOT:
|
||||
gfc_conv_intrinsic_not (se, expr);
|
||||
break;
|
||||
@ -4053,6 +4346,18 @@ gfc_conv_intrinsic_function (gfc_se * se, gfc_expr * expr)
|
||||
gfc_conv_intrinsic_arith (se, expr, MULT_EXPR);
|
||||
break;
|
||||
|
||||
case GFC_ISYM_RRSPACING:
|
||||
gfc_conv_intrinsic_rrspacing (se, expr);
|
||||
break;
|
||||
|
||||
case GFC_ISYM_SET_EXPONENT:
|
||||
gfc_conv_intrinsic_set_exponent (se, expr);
|
||||
break;
|
||||
|
||||
case GFC_ISYM_SCALE:
|
||||
gfc_conv_intrinsic_scale (se, expr);
|
||||
break;
|
||||
|
||||
case GFC_ISYM_SIGN:
|
||||
gfc_conv_intrinsic_sign (se, expr);
|
||||
break;
|
||||
@ -4065,6 +4370,10 @@ gfc_conv_intrinsic_function (gfc_se * se, gfc_expr * expr)
|
||||
gfc_conv_intrinsic_sizeof (se, expr);
|
||||
break;
|
||||
|
||||
case GFC_ISYM_SPACING:
|
||||
gfc_conv_intrinsic_spacing (se, expr);
|
||||
break;
|
||||
|
||||
case GFC_ISYM_SUM:
|
||||
gfc_conv_intrinsic_arith (se, expr, PLUS_EXPR);
|
||||
break;
|
||||
|
@ -529,10 +529,6 @@ extern GTY(()) gfc_powdecl_list gfor_fndecl_math_powi[4][3];
|
||||
extern GTY(()) tree gfor_fndecl_math_ishftc4;
|
||||
extern GTY(()) tree gfor_fndecl_math_ishftc8;
|
||||
extern GTY(()) tree gfor_fndecl_math_ishftc16;
|
||||
extern GTY(()) tree gfor_fndecl_math_exponent4;
|
||||
extern GTY(()) tree gfor_fndecl_math_exponent8;
|
||||
extern GTY(()) tree gfor_fndecl_math_exponent10;
|
||||
extern GTY(()) tree gfor_fndecl_math_exponent16;
|
||||
|
||||
/* BLAS functions. */
|
||||
extern GTY(()) tree gfor_fndecl_sgemm;
|
||||
|
Loading…
Reference in New Issue
Block a user