}
-/* The EXPONENT(s) intrinsic function is translated into
+/* The EXPONENT(X) intrinsic function is translated into
int ret;
- frexp (s, &ret);
- return ret;
+ return isfinite(X) ? (frexp (X, &ret) , ret) : huge
+ so that if X is a NaN or infinity, the result is HUGE(0).
*/
static void
gfc_conv_intrinsic_exponent (gfc_se *se, gfc_expr *expr)
{
- tree arg, type, res, tmp, frexp;
+ tree arg, type, res, tmp, frexp, cond, huge;
+ int i;
frexp = gfc_builtin_decl_for_float_kind (BUILT_IN_FREXP,
expr->value.function.actual->expr->ts.kind);
gfc_conv_intrinsic_function_args (se, expr, &arg, 1);
+ arg = gfc_evaluate_now (arg, &se->pre);
+
+ i = gfc_validate_kind (BT_INTEGER, gfc_c_int_kind, false);
+ huge = gfc_conv_mpz_to_tree (gfc_integer_kinds[i].huge, gfc_c_int_kind);
+ cond = build_call_expr_loc (input_location,
+ builtin_decl_explicit (BUILT_IN_ISFINITE),
+ 1, arg);
res = gfc_create_var (integer_type_node, NULL);
tmp = build_call_expr_loc (input_location, frexp, 2, arg,
gfc_build_addr_expr (NULL_TREE, res));
- gfc_add_expr_to_block (&se->pre, tmp);
+ tmp = fold_build2_loc (input_location, COMPOUND_EXPR, integer_type_node,
+ tmp, res);
+ se->expr = fold_build3_loc (input_location, COND_EXPR, integer_type_node,
+ cond, tmp, huge);
type = gfc_typenode_for_spec (&expr->ts);
- se->expr = fold_convert (type, res);
+ se->expr = fold_convert (type, se->expr);
}
else
tmp = huge_cst;
if (HONOR_NANS (DECL_MODE (limit)))
- {
- REAL_VALUE_TYPE real;
- real_nan (&real, "", 1, DECL_MODE (limit));
- nan_cst = build_real (type, real);
- }
+ nan_cst = gfc_build_nan (type, "");
break;
case BT_INTEGER:
}
-/* FRACTION (s) is translated into frexp (s, &dummy_int). */
+/* FRACTION (s) is translated into:
+ isfinite (s) ? frexp (s, &dummy_int) : NaN */
static void
gfc_conv_intrinsic_fraction (gfc_se * se, gfc_expr * expr)
{
- tree arg, type, tmp, frexp;
+ tree arg, type, tmp, res, frexp, cond;
frexp = gfc_builtin_decl_for_float_kind (BUILT_IN_FREXP, expr->ts.kind);
type = gfc_typenode_for_spec (&expr->ts);
gfc_conv_intrinsic_function_args (se, expr, &arg, 1);
+ arg = gfc_evaluate_now (arg, &se->pre);
+
+ cond = build_call_expr_loc (input_location,
+ builtin_decl_explicit (BUILT_IN_ISFINITE),
+ 1, arg);
+
tmp = gfc_create_var (integer_type_node, NULL);
- se->expr = build_call_expr_loc (input_location, frexp, 2,
- fold_convert (type, arg),
- gfc_build_addr_expr (NULL_TREE, tmp));
- se->expr = fold_convert (type, se->expr);
+ res = build_call_expr_loc (input_location, frexp, 2,
+ fold_convert (type, arg),
+ gfc_build_addr_expr (NULL_TREE, tmp));
+ res = fold_convert (type, res);
+
+ se->expr = fold_build3_loc (input_location, COND_EXPR, type,
+ cond, res, gfc_build_nan (type, ""));
}
/* SPACING (s) is translated into
int e;
- if (s == 0)
+ if (!isfinite (s))
+ res = NaN;
+ else if (s == 0)
res = tiny;
else
{
gfc_conv_intrinsic_spacing (gfc_se * se, gfc_expr * expr)
{
tree arg, type, prec, emin, tiny, res, e;
- tree cond, tmp, frexp, scalbn;
+ tree cond, nan, tmp, frexp, scalbn;
int k;
stmtblock_t block;
build_real_from_int_cst (type, integer_one_node), e);
gfc_add_modify (&block, res, tmp);
- /* Finish by building the IF statement. */
+ /* Finish by building the IF statement for value zero. */
cond = fold_build2_loc (input_location, 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));
+ /* And deal with infinities and NaNs. */
+ cond = build_call_expr_loc (input_location,
+ builtin_decl_explicit (BUILT_IN_ISFINITE),
+ 1, arg);
+ nan = gfc_build_nan (type, "");
+ tmp = build3_v (COND_EXPR, cond, tmp, build2_v (MODIFY_EXPR, res, nan));
+
gfc_add_expr_to_block (&se->pre, tmp);
se->expr = res;
}
int e;
real x;
x = fabs (s);
- if (x != 0)
+ if (isfinite (x))
{
- frexp (s, &e);
- x = scalbn (x, precision - e);
+ if (x != 0)
+ {
+ frexp (s, &e);
+ x = scalbn (x, precision - e);
+ }
}
+ else
+ x = NaN;
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, frexp, scalbn, fabs;
+ tree arg, type, e, x, cond, nan, stmt, tmp, frexp, scalbn, fabs;
int prec, k;
stmtblock_t block;
gfc_add_modify (&block, x, tmp);
stmt = gfc_finish_block (&block);
+ /* if (x != 0) */
cond = fold_build2_loc (input_location, 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 (input_location));
- gfc_add_expr_to_block (&se->pre, tmp);
+ /* And deal with infinities and NaNs. */
+ cond = build_call_expr_loc (input_location,
+ builtin_decl_explicit (BUILT_IN_ISFINITE),
+ 1, x);
+ nan = gfc_build_nan (type, "");
+ tmp = build3_v (COND_EXPR, cond, tmp, build2_v (MODIFY_EXPR, x, nan));
+
+ gfc_add_expr_to_block (&se->pre, tmp);
se->expr = fold_convert (type, x);
}
/* SET_EXPONENT (s, i) is translated into
- scalbn (frexp (s, &dummy_int), i). */
+ isfinite(s) ? scalbn (frexp (s, &dummy_int), i) : NaN */
static void
gfc_conv_intrinsic_set_exponent (gfc_se * se, gfc_expr * expr)
{
- tree args[2], type, tmp, frexp, scalbn;
+ tree args[2], type, tmp, frexp, scalbn, cond, nan, res;
frexp = gfc_builtin_decl_for_float_kind (BUILT_IN_FREXP, expr->ts.kind);
scalbn = gfc_builtin_decl_for_float_kind (BUILT_IN_SCALBN, expr->ts.kind);
type = gfc_typenode_for_spec (&expr->ts);
gfc_conv_intrinsic_function_args (se, expr, args, 2);
+ args[0] = gfc_evaluate_now (args[0], &se->pre);
tmp = gfc_create_var (integer_type_node, NULL);
tmp = build_call_expr_loc (input_location, frexp, 2,
fold_convert (type, args[0]),
gfc_build_addr_expr (NULL_TREE, tmp));
- se->expr = build_call_expr_loc (input_location, scalbn, 2, tmp,
- fold_convert (integer_type_node, args[1]));
- se->expr = fold_convert (type, se->expr);
+ res = build_call_expr_loc (input_location, scalbn, 2, tmp,
+ fold_convert (integer_type_node, args[1]));
+ res = fold_convert (type, res);
+
+ /* Call to isfinite */
+ cond = build_call_expr_loc (input_location,
+ builtin_decl_explicit (BUILT_IN_ISFINITE),
+ 1, args[0]);
+ nan = gfc_build_nan (type, "");
+
+ se->expr = fold_build3_loc (input_location, COND_EXPR, type, cond,
+ res, nan);
}