/* Intrinsic translation
- Copyright (C) 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
+ Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007
+ Free Software Foundation, Inc.
Contributed by Paul Brook <paul@nowt.org>
and Steven Bosscher <s.bosscher@student.tudelft.nl>
{
/* The explicit enum is required to work around inadequacies in the
garbage collection/gengtype parsing mechanism. */
- enum gfc_generic_isym_id id;
+ enum gfc_isym_id id;
/* Enum value from the "language-independent", aka C-centric, part
of gcc, or END_BUILTINS of no such value set. */
}
real_compnt_info;
+enum rounding_mode { RND_ROUND, RND_TRUNC, RND_CEIL, RND_FLOOR };
/* Evaluate the arguments to an intrinsic function. */
+/* FIXME: This function and its callers should be rewritten so that it's
+ not necessary to cons up a list to hold the arguments. */
static tree
gfc_conv_intrinsic_function_args (gfc_se * se, gfc_expr * expr)
static tree
build_fix_expr (stmtblock_t * pblock, tree arg, tree type,
- enum tree_code op)
+ enum rounding_mode op)
{
switch (op)
{
- case FIX_FLOOR_EXPR:
+ case RND_FLOOR:
return build_fixbound_expr (pblock, arg, type, 0);
break;
- case FIX_CEIL_EXPR:
+ case RND_CEIL:
return build_fixbound_expr (pblock, arg, type, 1);
break;
- case FIX_ROUND_EXPR:
+ case RND_ROUND:
return build_round_expr (pblock, arg, type);
default:
- return build1 (op, type, arg);
+ gcc_assert (op == RND_TRUNC);
+ return build1 (FIX_TRUNC_EXPR, type, arg);
}
}
*/
static void
-gfc_conv_intrinsic_aint (gfc_se * se, gfc_expr * expr, enum tree_code op)
+gfc_conv_intrinsic_aint (gfc_se * se, gfc_expr * expr, enum rounding_mode op)
{
tree type;
tree itype;
/* We have builtin functions for some cases. */
switch (op)
{
- case FIX_ROUND_EXPR:
+ case RND_ROUND:
switch (kind)
{
case 4:
}
break;
- case FIX_TRUNC_EXPR:
+ case RND_TRUNC:
switch (kind)
{
case 4:
/* Convert to an integer using the specified rounding mode. */
static void
-gfc_conv_intrinsic_int (gfc_se * se, gfc_expr * expr, int op)
+gfc_conv_intrinsic_int (gfc_se * se, gfc_expr * expr, enum rounding_mode op)
{
tree type;
tree arg;
gfc_intrinsic_map_t *m;
tree args;
tree fndecl;
- gfc_generic_isym_id id;
+ gfc_isym_id id;
- id = expr->value.function.isym->generic_id;
+ id = expr->value.function.isym->id;
/* Find the entry for this function. */
for (m = gfc_intrinsic_map; m->id != GFC_ISYM_NONE; m++)
{
tree type;
tree bound;
tree tmp;
- tree cond;
+ tree cond, cond1, cond2, cond3, cond4, size;
+ tree ubound;
+ tree lbound;
gfc_se argse;
gfc_ss *ss;
- int i;
+ gfc_array_spec * as;
+ gfc_ref *ref;
arg = expr->value.function.actual;
arg2 = arg->next;
if (INTEGER_CST_P (bound))
{
- gcc_assert (TREE_INT_CST_HIGH (bound) == 0);
- i = TREE_INT_CST_LOW (bound);
- gcc_assert (i >= 0 && i < GFC_TYPE_ARRAY_RANK (TREE_TYPE (desc)));
+ int hi, low;
+
+ hi = TREE_INT_CST_HIGH (bound);
+ low = TREE_INT_CST_LOW (bound);
+ if (hi || low < 0 || low >= GFC_TYPE_ARRAY_RANK (TREE_TYPE (desc)))
+ gfc_error ("'dim' argument of %s intrinsic at %L is not a valid "
+ "dimension index", upper ? "UBOUND" : "LBOUND",
+ &expr->where);
}
else
{
tmp = gfc_rank_cst[GFC_TYPE_ARRAY_RANK (TREE_TYPE (desc))];
tmp = fold_build2 (GE_EXPR, boolean_type_node, bound, tmp);
cond = fold_build2 (TRUTH_ORIF_EXPR, boolean_type_node, cond, tmp);
- gfc_trans_runtime_check (cond, gfc_msg_fault, &se->pre, NULL);
+ gfc_trans_runtime_check (cond, gfc_msg_fault, &se->pre, &expr->where);
}
}
- if (upper)
- se->expr = gfc_conv_descriptor_ubound(desc, bound);
+ ubound = gfc_conv_descriptor_ubound (desc, bound);
+ lbound = gfc_conv_descriptor_lbound (desc, bound);
+
+ /* Follow any component references. */
+ if (arg->expr->expr_type == EXPR_VARIABLE
+ || arg->expr->expr_type == EXPR_CONSTANT)
+ {
+ as = arg->expr->symtree->n.sym->as;
+ for (ref = arg->expr->ref; ref; ref = ref->next)
+ {
+ switch (ref->type)
+ {
+ case REF_COMPONENT:
+ as = ref->u.c.component->as;
+ continue;
+
+ case REF_SUBSTRING:
+ continue;
+
+ case REF_ARRAY:
+ {
+ switch (ref->u.ar.type)
+ {
+ case AR_ELEMENT:
+ case AR_SECTION:
+ case AR_UNKNOWN:
+ as = NULL;
+ continue;
+
+ case AR_FULL:
+ break;
+ }
+ }
+ }
+ }
+ }
+ else
+ as = NULL;
+
+ /* 13.14.53: Result value for LBOUND
+
+ Case (i): For an array section or for an array expression other than a
+ whole array or array structure component, LBOUND(ARRAY, DIM)
+ has the value 1. For a whole array or array structure
+ component, LBOUND(ARRAY, DIM) has the value:
+ (a) equal to the lower bound for subscript DIM of ARRAY if
+ dimension DIM of ARRAY does not have extent zero
+ or if ARRAY is an assumed-size array of rank DIM,
+ or (b) 1 otherwise.
+
+ 13.14.113: Result value for UBOUND
+
+ Case (i): For an array section or for an array expression other than a
+ whole array or array structure component, UBOUND(ARRAY, DIM)
+ has the value equal to the number of elements in the given
+ dimension; otherwise, it has a value equal to the upper bound
+ for subscript DIM of ARRAY if dimension DIM of ARRAY does
+ not have size zero and has value zero if dimension DIM has
+ size zero. */
+
+ if (as)
+ {
+ tree stride = gfc_conv_descriptor_stride (desc, bound);
+
+ cond1 = fold_build2 (GE_EXPR, boolean_type_node, ubound, lbound);
+ cond2 = fold_build2 (LE_EXPR, boolean_type_node, ubound, lbound);
+
+ cond3 = fold_build2 (GE_EXPR, boolean_type_node, stride,
+ gfc_index_zero_node);
+ cond3 = fold_build2 (TRUTH_AND_EXPR, boolean_type_node, cond3, cond1);
+
+ cond4 = fold_build2 (LT_EXPR, boolean_type_node, stride,
+ gfc_index_zero_node);
+ cond4 = fold_build2 (TRUTH_AND_EXPR, boolean_type_node, cond4, cond2);
+
+ if (upper)
+ {
+ cond = fold_build2 (TRUTH_OR_EXPR, boolean_type_node, cond3, cond4);
+
+ se->expr = fold_build3 (COND_EXPR, gfc_array_index_type, cond,
+ ubound, gfc_index_zero_node);
+ }
+ else
+ {
+ if (as->type == AS_ASSUMED_SIZE)
+ cond = fold_build2 (EQ_EXPR, boolean_type_node, bound,
+ build_int_cst (TREE_TYPE (bound),
+ arg->expr->rank - 1));
+ else
+ cond = boolean_false_node;
+
+ cond1 = fold_build2 (TRUTH_OR_EXPR, boolean_type_node, cond3, cond4);
+ cond = fold_build2 (TRUTH_OR_EXPR, boolean_type_node, cond, cond1);
+
+ se->expr = fold_build3 (COND_EXPR, gfc_array_index_type, cond,
+ lbound, gfc_index_one_node);
+ }
+ }
else
- se->expr = gfc_conv_descriptor_lbound(desc, bound);
+ {
+ if (upper)
+ {
+ size = fold_build2 (MINUS_EXPR, gfc_array_index_type, ubound, lbound);
+ se->expr = fold_build2 (PLUS_EXPR, gfc_array_index_type, size,
+ gfc_index_one_node);
+ }
+ else
+ se->expr = gfc_index_one_node;
+ }
type = gfc_typenode_for_spec (&expr->ts);
se->expr = convert (type, se->expr);
int n, ikind;
arg = gfc_conv_intrinsic_function_args (se, expr);
- arg2 = TREE_VALUE (TREE_CHAIN (arg));
- arg = TREE_VALUE (arg);
- type = TREE_TYPE (arg);
switch (expr->ts.type)
{
case BT_INTEGER:
/* Integer case is easy, we've got a builtin op. */
+ arg2 = TREE_VALUE (TREE_CHAIN (arg));
+ arg = TREE_VALUE (arg);
+ type = TREE_TYPE (arg);
+
if (modulo)
se->expr = build2 (FLOOR_MOD_EXPR, type, arg, arg2);
else
break;
case BT_REAL:
- /* Real values we have to do the hard way. */
+ n = END_BUILTINS;
+ /* Check if we have a builtin fmod. */
+ switch (expr->ts.kind)
+ {
+ case 4:
+ n = BUILT_IN_FMODF;
+ break;
+
+ case 8:
+ n = BUILT_IN_FMOD;
+ break;
+
+ case 10:
+ case 16:
+ n = BUILT_IN_FMODL;
+ break;
+
+ default:
+ break;
+ }
+
+ /* Use it if it exists. */
+ if (n != END_BUILTINS)
+ {
+ tmp = built_in_decls[n];
+ se->expr = build_function_call_expr (tmp, arg);
+ if (modulo == 0)
+ return;
+ }
+
+ arg2 = TREE_VALUE (TREE_CHAIN (arg));
+ arg = TREE_VALUE (arg);
+ type = TREE_TYPE (arg);
+
arg = gfc_evaluate_now (arg, &se->pre);
arg2 = gfc_evaluate_now (arg2, &se->pre);
+ /* Definition:
+ modulo = arg - floor (arg/arg2) * arg2, so
+ = test ? fmod (arg, arg2) : fmod (arg, arg2) + arg2,
+ where
+ test = (fmod (arg, arg2) != 0) && ((arg < 0) xor (arg2 < 0))
+ thereby avoiding another division and retaining the accuracy
+ of the builtin function. */
+ if (n != END_BUILTINS && modulo)
+ {
+ tree zero = gfc_build_const (type, integer_zero_node);
+ tmp = gfc_evaluate_now (se->expr, &se->pre);
+ test = build2 (LT_EXPR, boolean_type_node, arg, zero);
+ test2 = build2 (LT_EXPR, boolean_type_node, arg2, zero);
+ test2 = build2 (TRUTH_XOR_EXPR, boolean_type_node, test, test2);
+ test = build2 (NE_EXPR, boolean_type_node, tmp, zero);
+ test = build2 (TRUTH_AND_EXPR, boolean_type_node, test, test2);
+ test = gfc_evaluate_now (test, &se->pre);
+ se->expr = build3 (COND_EXPR, type, test,
+ build2 (PLUS_EXPR, type, tmp, arg2), tmp);
+ return;
+ }
+
+ /* If we do not have a built_in fmod, the calculation is going to
+ have to be done longhand. */
tmp = build2 (RDIV_EXPR, type, arg, arg2);
+
/* Test if the value is too large to handle sensibly. */
gfc_set_model_kind (expr->ts.kind);
mpfr_init (huge);
itype = gfc_get_int_type (ikind);
if (modulo)
- tmp = build_fix_expr (&se->pre, tmp, itype, FIX_FLOOR_EXPR);
+ tmp = build_fix_expr (&se->pre, tmp, itype, RND_FLOOR);
else
- tmp = build_fix_expr (&se->pre, tmp, itype, FIX_TRUNC_EXPR);
+ tmp = build_fix_expr (&se->pre, tmp, itype, RND_TRUNC);
tmp = convert (type, tmp);
tmp = build3 (COND_EXPR, type, test2, tmp, arg);
tmp = build2 (MULT_EXPR, type, tmp, arg2);
/* SIGN(A, B) is absolute value of A times sign of B.
The real value versions use library functions to ensure the correct
handling of negative zero. Integer case implemented as:
- SIGN(A, B) = ((a >= 0) .xor. (b >= 0)) ? a : -a
+ SIGN(A, B) = { tmp = (A ^ B) >> C; (A + tmp) ^ tmp }
*/
static void
tree arg;
tree arg2;
tree type;
- tree zero;
- tree testa;
- tree testb;
-
arg = gfc_conv_intrinsic_function_args (se, expr);
if (expr->ts.type == BT_REAL)
return;
}
+ /* Having excluded floating point types, we know we are now dealing
+ with signed integer types. */
arg2 = TREE_VALUE (TREE_CHAIN (arg));
arg = TREE_VALUE (arg);
type = TREE_TYPE (arg);
- zero = gfc_build_const (type, integer_zero_node);
- testa = fold_build2 (GE_EXPR, boolean_type_node, arg, zero);
- testb = fold_build2 (GE_EXPR, boolean_type_node, arg2, zero);
- tmp = fold_build2 (TRUTH_XOR_EXPR, boolean_type_node, testa, testb);
- se->expr = fold_build3 (COND_EXPR, type, tmp,
- build1 (NEGATE_EXPR, type, arg), arg);
+ /* Arg is used multiple times below. */
+ arg = gfc_evaluate_now (arg, &se->pre);
+
+ /* Construct (A ^ B) >> 31, which generates a bit mask of all zeros if
+ the signs of A and B are the same, and of all ones if they differ. */
+ tmp = fold_build2 (BIT_XOR_EXPR, type, arg, arg2);
+ tmp = fold_build2 (RSHIFT_EXPR, type, tmp,
+ build_int_cst (type, TYPE_PRECISION (type) - 1));
+ tmp = gfc_evaluate_now (tmp, &se->pre);
+
+ /* Construct (A + tmp) ^ tmp, which is A if tmp is zero, and -A if tmp]
+ is all ones (i.e. -1). */
+ se->expr = fold_build2 (BIT_XOR_EXPR, type,
+ fold_build2 (PLUS_EXPR, type, arg, tmp),
+ tmp);
}
/* Free the temporary afterwards, if necessary. */
cond = build2 (GT_EXPR, boolean_type_node, len,
build_int_cst (TREE_TYPE (len), 0));
- arglist = gfc_chainon_list (NULL_TREE, var);
- tmp = build_function_call_expr (gfor_fndecl_internal_free, arglist);
+ tmp = gfc_call_free (var);
tmp = build3_v (COND_EXPR, cond, tmp, build_empty_stmt ());
gfc_add_expr_to_block (&se->post, tmp);
/* Free the temporary afterwards, if necessary. */
cond = build2 (GT_EXPR, boolean_type_node, len,
build_int_cst (TREE_TYPE (len), 0));
- arglist = gfc_chainon_list (NULL_TREE, var);
- tmp = build_function_call_expr (gfor_fndecl_internal_free, arglist);
+ tmp = gfc_call_free (var);
tmp = build3_v (COND_EXPR, cond, tmp, build_empty_stmt ());
gfc_add_expr_to_block (&se->post, tmp);
/* Free the temporary afterwards, if necessary. */
cond = build2 (GT_EXPR, boolean_type_node, len,
build_int_cst (TREE_TYPE (len), 0));
- arglist = gfc_chainon_list (NULL_TREE, var);
- tmp = build_function_call_expr (gfor_fndecl_internal_free, arglist);
+ tmp = gfc_call_free (var);
tmp = build3_v (COND_EXPR, cond, tmp, build_empty_stmt ());
gfc_add_expr_to_block (&se->post, tmp);
limit = convert (type, limit);
/* Only evaluate the argument once. */
if (TREE_CODE (limit) != VAR_DECL && !TREE_CONSTANT (limit))
- limit = gfc_evaluate_now(limit, &se->pre);
+ limit = gfc_evaluate_now (limit, &se->pre);
mvar = gfc_create_var (type, "M");
elsecase = build2_v (MODIFY_EXPR, mvar, limit);
/* Only evaluate the argument once. */
if (TREE_CODE (val) != VAR_DECL && !TREE_CONSTANT (val))
- val = gfc_evaluate_now(val, &se->pre);
+ val = gfc_evaluate_now (val, &se->pre);
thencase = build2_v (MODIFY_EXPR, mvar, convert (type, val));
gfc_conv_intrinsic_funcall (gfc_se * se, gfc_expr * expr)
{
gfc_symbol *sym;
+ tree append_args;
gcc_assert (!se->ss || se->ss->expr == expr);
gcc_assert (expr->rank == 0);
sym = gfc_get_symbol_for_expr (expr);
- gfc_conv_function_call (se, sym, expr->value.function.actual);
+
+ /* Calls to libgfortran_matmul need to be appended special arguments,
+ to be able to call the BLAS ?gemm functions if required and possible. */
+ append_args = NULL_TREE;
+ if (expr->value.function.isym->id == GFC_ISYM_MATMUL
+ && sym->ts.type != BT_LOGICAL)
+ {
+ tree cint = gfc_get_int_type (gfc_c_int_kind);
+
+ if (gfc_option.flag_external_blas
+ && (sym->ts.type == BT_REAL || sym->ts.type == BT_COMPLEX)
+ && (sym->ts.kind == gfc_default_real_kind
+ || sym->ts.kind == gfc_default_double_kind))
+ {
+ tree gemm_fndecl;
+
+ if (sym->ts.type == BT_REAL)
+ {
+ if (sym->ts.kind == gfc_default_real_kind)
+ gemm_fndecl = gfor_fndecl_sgemm;
+ else
+ gemm_fndecl = gfor_fndecl_dgemm;
+ }
+ else
+ {
+ if (sym->ts.kind == gfc_default_real_kind)
+ gemm_fndecl = gfor_fndecl_cgemm;
+ else
+ gemm_fndecl = gfor_fndecl_zgemm;
+ }
+
+ append_args = gfc_chainon_list (NULL_TREE, build_int_cst (cint, 1));
+ append_args = gfc_chainon_list
+ (append_args, build_int_cst
+ (cint, gfc_option.blas_matmul_limit));
+ append_args = gfc_chainon_list (append_args,
+ gfc_build_addr_expr (NULL_TREE,
+ gemm_fndecl));
+ }
+ else
+ {
+ append_args = gfc_chainon_list (NULL_TREE, build_int_cst (cint, 0));
+ append_args = gfc_chainon_list (append_args, build_int_cst (cint, 0));
+ append_args = gfc_chainon_list (append_args, null_pointer_node);
+ }
+ }
+
+ gfc_conv_function_call (se, sym, expr->value.function.actual, append_args);
gfc_free (sym);
}
gfc_conv_expr_val (&arrayse, actual->expr);
gfc_add_block_to_block (&body, &arrayse.pre);
- tmp = build2 (op, boolean_type_node, arrayse.expr,
- build_int_cst (TREE_TYPE (arrayse.expr), 0));
+ tmp = fold_build2 (op, boolean_type_node, arrayse.expr,
+ build_int_cst (TREE_TYPE (arrayse.expr), 0));
tmp = build3_v (COND_EXPR, tmp, found, build_empty_stmt ());
gfc_add_expr_to_block (&body, tmp);
gfc_add_block_to_block (&body, &arrayse.post);
/* Initialize the result. */
resvar = gfc_create_var (type, "val");
if (expr->ts.type == BT_LOGICAL)
- tmp = convert (type, integer_zero_node);
+ tmp = build_int_cst (type, 0);
else
tmp = gfc_build_const (type, integer_zero_node);
gcc_unreachable ();
}
- /* Most negative(+HUGE) for maxval, most negative (-HUGE) for minval. */
+ /* We start with the most negative possible value for MAXLOC, and the most
+ positive possible value for MINLOC. The most negative possible value is
+ -HUGE for BT_REAL and (-HUGE - 1) for BT_INTEGER; the most positive
+ possible value is HUGE in both cases. */
if (op == GT_EXPR)
tmp = fold_build1 (NEGATE_EXPR, TREE_TYPE (tmp), tmp);
gfc_add_modify_expr (&se->pre, limit, tmp);
+ if (op == GT_EXPR && expr->ts.type == BT_INTEGER)
+ tmp = build2 (MINUS_EXPR, TREE_TYPE (tmp), tmp,
+ build_int_cst (type, 1));
+
/* Initialize the scalarizer. */
gfc_init_loopinfo (&loop);
gfc_add_ss_to_loop (&loop, arrayss);
gcc_unreachable ();
}
- /* Most negative(-HUGE) for maxval, most positive (-HUGE) for minval. */
+ /* We start with the most negative possible value for MAXVAL, and the most
+ positive possible value for MINVAL. The most negative possible value is
+ -HUGE for BT_REAL and (-HUGE - 1) for BT_INTEGER; the most positive
+ possible value is HUGE in both cases. */
if (op == GT_EXPR)
tmp = fold_build1 (NEGATE_EXPR, TREE_TYPE (tmp), tmp);
+
+ if (op == GT_EXPR && expr->ts.type == BT_INTEGER)
+ tmp = build2 (MINUS_EXPR, TREE_TYPE (tmp), tmp,
+ build_int_cst (type, 1));
+
gfc_add_modify_expr (&se->pre, limit, tmp);
/* Walk the arguments. */
arg2 = TREE_VALUE (arg2);
type = TREE_TYPE (arg);
- mask = build_int_cst (NULL_TREE, -1);
+ mask = build_int_cst (type, -1);
mask = build2 (LSHIFT_EXPR, type, mask, arg3);
mask = build1 (BIT_NOT_EXPR, type, mask);
arg2 = TREE_VALUE (TREE_CHAIN (arg));
arg = TREE_VALUE (arg);
type = TREE_TYPE (arg);
- utype = gfc_unsigned_type (type);
+ utype = unsigned_type_for (type);
width = fold_build1 (ABS_EXPR, TREE_TYPE (arg2), arg2);
gfc_symbol *sym;
gfc_se argse;
gfc_expr *arg;
+ gfc_ss *ss;
gcc_assert (!se->ss);
/* Obtain the string length from the function used by
trans-array.c(gfc_trans_array_constructor). */
len = NULL_TREE;
- get_array_ctor_strlen (arg->value.constructor, &len);
+ get_array_ctor_strlen (&se->pre, arg->value.constructor, &len);
break;
- default:
- if (arg->expr_type == EXPR_VARIABLE
- && (arg->ref == NULL || (arg->ref->next == NULL
- && arg->ref->type == REF_ARRAY)))
- {
- /* This doesn't catch all cases.
- See http://gcc.gnu.org/ml/fortran/2004-06/msg00165.html
- and the surrounding thread. */
- sym = arg->symtree->n.sym;
- decl = gfc_get_symbol_decl (sym);
- if (decl == current_function_decl && sym->attr.function
+ case EXPR_VARIABLE:
+ if (arg->ref == NULL
+ || (arg->ref->next == NULL && arg->ref->type == REF_ARRAY))
+ {
+ /* This doesn't catch all cases.
+ See http://gcc.gnu.org/ml/fortran/2004-06/msg00165.html
+ and the surrounding thread. */
+ sym = arg->symtree->n.sym;
+ decl = gfc_get_symbol_decl (sym);
+ if (decl == current_function_decl && sym->attr.function
&& (sym->result == sym))
- decl = gfc_get_fake_result_decl (sym, 0);
-
- len = sym->ts.cl->backend_decl;
- gcc_assert (len);
- }
- else
- {
- /* Anybody stupid enough to do this deserves inefficient code. */
- gfc_init_se (&argse, se);
- gfc_conv_expr (&argse, arg);
- gfc_add_block_to_block (&se->pre, &argse.pre);
- gfc_add_block_to_block (&se->post, &argse.post);
- len = argse.string_length;
+ decl = gfc_get_fake_result_decl (sym, 0);
+
+ len = sym->ts.cl->backend_decl;
+ gcc_assert (len);
+ break;
}
+
+ /* Otherwise fall through. */
+
+ default:
+ /* Anybody stupid enough to do this deserves inefficient code. */
+ ss = gfc_walk_expr (arg);
+ gfc_init_se (&argse, se);
+ if (ss == gfc_ss_terminator)
+ gfc_conv_expr (&argse, arg);
+ else
+ gfc_conv_expr_descriptor (&argse, arg, ss);
+ gfc_add_block_to_block (&se->pre, &argse.pre);
+ gfc_add_block_to_block (&se->post, &argse.post);
+ len = argse.string_length;
break;
}
se->expr = convert (type, len);
gfc_conv_intrinsic_size (gfc_se * se, gfc_expr * expr)
{
gfc_actual_arglist *actual;
- tree args;
+ tree arg1;
tree type;
- tree fndecl;
+ tree fncall0;
+ tree fncall1;
gfc_se argse;
gfc_ss *ss;
gfc_conv_expr_descriptor (&argse, actual->expr, ss);
gfc_add_block_to_block (&se->pre, &argse.pre);
gfc_add_block_to_block (&se->post, &argse.post);
- args = gfc_chainon_list (NULL_TREE, argse.expr);
+ arg1 = gfc_evaluate_now (argse.expr, &se->pre);
+
+ /* Build the call to size0. */
+ fncall0 = build_call_expr (gfor_fndecl_size0, 1, arg1);
actual = actual->next;
+
if (actual->expr)
{
gfc_init_se (&argse, NULL);
- gfc_conv_expr_type (&argse, actual->expr, gfc_array_index_type);
+ gfc_conv_expr_type (&argse, actual->expr,
+ gfc_array_index_type);
gfc_add_block_to_block (&se->pre, &argse.pre);
- args = gfc_chainon_list (args, argse.expr);
- fndecl = gfor_fndecl_size1;
+
+ /* Build the call to size1. */
+ fncall1 = build_call_expr (gfor_fndecl_size1, 2,
+ arg1, argse.expr);
+
+ /* Unusually, for an intrinsic, size does not exclude
+ an optional arg2, so we must test for it. */
+ if (actual->expr->expr_type == EXPR_VARIABLE
+ && actual->expr->symtree->n.sym->attr.dummy
+ && actual->expr->symtree->n.sym->attr.optional)
+ {
+ tree tmp;
+ gfc_init_se (&argse, NULL);
+ argse.want_pointer = 1;
+ argse.data_not_needed = 1;
+ gfc_conv_expr (&argse, actual->expr);
+ gfc_add_block_to_block (&se->pre, &argse.pre);
+ tmp = build2 (NE_EXPR, boolean_type_node, argse.expr,
+ null_pointer_node);
+ tmp = gfc_evaluate_now (tmp, &se->pre);
+ se->expr = build3 (COND_EXPR, pvoid_type_node,
+ tmp, fncall1, fncall0);
+ }
+ else
+ se->expr = fncall1;
}
else
- fndecl = gfor_fndecl_size0;
+ se->expr = fncall0;
- se->expr = build_function_call_expr (fndecl, args);
type = gfc_typenode_for_spec (&expr->ts);
se->expr = convert (type, se->expr);
}
+static void
+gfc_conv_intrinsic_sizeof (gfc_se *se, gfc_expr *expr)
+{
+ gfc_expr *arg;
+ gfc_ss *ss;
+ gfc_se argse;
+ tree source;
+ tree source_bytes;
+ tree type;
+ tree tmp;
+ tree lower;
+ tree upper;
+ /*tree stride;*/
+ int n;
+
+ arg = expr->value.function.actual->expr;
+
+ gfc_init_se (&argse, NULL);
+ ss = gfc_walk_expr (arg);
+
+ source_bytes = gfc_create_var (gfc_array_index_type, "bytes");
+
+ if (ss == gfc_ss_terminator)
+ {
+ gfc_conv_expr_reference (&argse, arg);
+ source = argse.expr;
+
+ type = TREE_TYPE (build_fold_indirect_ref (argse.expr));
+
+ /* Obtain the source word length. */
+ if (arg->ts.type == BT_CHARACTER)
+ source_bytes = fold_convert (gfc_array_index_type,
+ argse.string_length);
+ else
+ source_bytes = fold_convert (gfc_array_index_type,
+ size_in_bytes (type));
+ }
+ else
+ {
+ argse.want_pointer = 0;
+ gfc_conv_expr_descriptor (&argse, arg, ss);
+ source = gfc_conv_descriptor_data_get (argse.expr);
+ type = gfc_get_element_type (TREE_TYPE (argse.expr));
+
+ /* Obtain the argument's word length. */
+ if (arg->ts.type == BT_CHARACTER)
+ tmp = fold_convert (gfc_array_index_type, argse.string_length);
+ else
+ tmp = fold_convert (gfc_array_index_type,
+ size_in_bytes (type));
+ gfc_add_modify_expr (&argse.pre, source_bytes, tmp);
+
+ /* Obtain the size of the array in bytes. */
+ for (n = 0; n < arg->rank; n++)
+ {
+ tree idx;
+ idx = gfc_rank_cst[n];
+ lower = gfc_conv_descriptor_lbound (argse.expr, idx);
+ upper = gfc_conv_descriptor_ubound (argse.expr, idx);
+ tmp = fold_build2 (MINUS_EXPR, gfc_array_index_type,
+ upper, lower);
+ tmp = fold_build2 (PLUS_EXPR, gfc_array_index_type,
+ tmp, gfc_index_one_node);
+ tmp = fold_build2 (MULT_EXPR, gfc_array_index_type,
+ tmp, source_bytes);
+ gfc_add_modify_expr (&argse.pre, source_bytes, tmp);
+ }
+ }
+
+ gfc_add_block_to_block (&se->pre, &argse.pre);
+ se->expr = source_bytes;
+}
+
+
/* Intrinsic string comparison functions. */
- static void
+static void
gfc_conv_intrinsic_strcmp (gfc_se * se, gfc_expr * expr, int op)
{
tree type;
}
-/* A helper function for gfc_conv_intrinsic_array_transfer to compute
- the size of tree expressions in bytes. */
-static tree
-gfc_size_in_bytes (gfc_se *se, gfc_expr *e)
-{
- tree tmp;
-
- if (e->ts.type == BT_CHARACTER)
- tmp = se->string_length;
- else
- {
- if (e->rank)
- {
- tmp = gfc_get_element_type (TREE_TYPE (se->expr));
- tmp = size_in_bytes (tmp);
- }
- else
- tmp = size_in_bytes (TREE_TYPE (TREE_TYPE (se->expr)));
- }
-
- return fold_convert (gfc_array_index_type, tmp);
-}
-
-
/* Array transfer statement.
DEST(1:N) = TRANSFER (SOURCE, MOLD[, SIZE])
where:
tree tmp;
tree extent;
tree source;
+ tree source_type;
tree source_bytes;
+ tree mold_type;
tree dest_word_len;
tree size_words;
tree size_bytes;
tree lower;
tree stride;
tree stmt;
- tree args;
gfc_actual_arglist *arg;
gfc_se argse;
gfc_ss *ss;
gfc_conv_expr_reference (&argse, arg->expr);
source = argse.expr;
+ source_type = TREE_TYPE (build_fold_indirect_ref (argse.expr));
+
/* Obtain the source word length. */
- tmp = gfc_size_in_bytes (&argse, arg->expr);
+ if (arg->expr->ts.type == BT_CHARACTER)
+ tmp = fold_convert (gfc_array_index_type, argse.string_length);
+ else
+ tmp = fold_convert (gfc_array_index_type,
+ size_in_bytes (source_type));
}
else
{
- gfc_init_se (&argse, NULL);
argse.want_pointer = 0;
gfc_conv_expr_descriptor (&argse, arg->expr, ss);
source = gfc_conv_descriptor_data_get (argse.expr);
+ source_type = gfc_get_element_type (TREE_TYPE (argse.expr));
/* Repack the source if not a full variable array. */
if (!(arg->expr->expr_type == EXPR_VARIABLE
&& arg->expr->ref->u.ar.type == AR_FULL))
{
tmp = build_fold_addr_expr (argse.expr);
- tmp = gfc_chainon_list (NULL_TREE, tmp);
- source = build_function_call_expr (gfor_fndecl_in_pack, tmp);
+ source = build_call_expr (gfor_fndecl_in_pack, 1, tmp);
source = gfc_evaluate_now (source, &argse.pre);
/* Free the temporary. */
gfc_start_block (&block);
- tmp = convert (pvoid_type_node, source);
- tmp = gfc_chainon_list (NULL_TREE, tmp);
- tmp = build_function_call_expr (gfor_fndecl_internal_free, tmp);
+ tmp = gfc_call_free (convert (pvoid_type_node, source));
gfc_add_expr_to_block (&block, tmp);
stmt = gfc_finish_block (&block);
}
/* Obtain the source word length. */
- tmp = gfc_size_in_bytes (&argse, arg->expr);
+ if (arg->expr->ts.type == BT_CHARACTER)
+ tmp = fold_convert (gfc_array_index_type, argse.string_length);
+ else
+ tmp = fold_convert (gfc_array_index_type,
+ size_in_bytes (source_type));
/* Obtain the size of the array in bytes. */
extent = gfc_create_var (gfc_array_index_type, NULL);
stride = gfc_conv_descriptor_stride (argse.expr, idx);
lower = gfc_conv_descriptor_lbound (argse.expr, idx);
upper = gfc_conv_descriptor_ubound (argse.expr, idx);
- tmp = build2 (MINUS_EXPR, gfc_array_index_type,
- upper, lower);
+ tmp = fold_build2 (MINUS_EXPR, gfc_array_index_type,
+ upper, lower);
gfc_add_modify_expr (&argse.pre, extent, tmp);
- tmp = build2 (PLUS_EXPR, gfc_array_index_type,
- extent, gfc_index_one_node);
- tmp = build2 (MULT_EXPR, gfc_array_index_type,
- tmp, source_bytes);
+ tmp = fold_build2 (PLUS_EXPR, gfc_array_index_type,
+ extent, gfc_index_one_node);
+ tmp = fold_build2 (MULT_EXPR, gfc_array_index_type,
+ tmp, source_bytes);
}
}
gfc_add_block_to_block (&se->pre, &argse.pre);
gfc_add_block_to_block (&se->post, &argse.post);
- /* Now convert MOLD. The sole output is:
+ /* Now convert MOLD. The outputs are:
+ mold_type = the TREE type of MOLD
dest_word_len = destination word length in bytes. */
arg = arg->next;
if (ss == gfc_ss_terminator)
{
gfc_conv_expr_reference (&argse, arg->expr);
-
- /* Obtain the source word length. */
- tmp = gfc_size_in_bytes (&argse, arg->expr);
+ mold_type = TREE_TYPE (build_fold_indirect_ref (argse.expr));
}
else
{
gfc_init_se (&argse, NULL);
argse.want_pointer = 0;
gfc_conv_expr_descriptor (&argse, arg->expr, ss);
-
- /* Obtain the source word length. */
- tmp = gfc_size_in_bytes (&argse, arg->expr);
+ mold_type = gfc_get_element_type (TREE_TYPE (argse.expr));
}
+ if (arg->expr->ts.type == BT_CHARACTER)
+ {
+ tmp = fold_convert (gfc_array_index_type, argse.string_length);
+ mold_type = gfc_get_character_type_len (arg->expr->ts.kind, tmp);
+ }
+ else
+ tmp = fold_convert (gfc_array_index_type,
+ size_in_bytes (mold_type));
+
dest_word_len = gfc_create_var (gfc_array_index_type, NULL);
gfc_add_modify_expr (&se->pre, dest_word_len, tmp);
size_bytes = gfc_create_var (gfc_array_index_type, NULL);
if (tmp != NULL_TREE)
{
- tmp = build2 (MULT_EXPR, gfc_array_index_type,
- tmp, dest_word_len);
- tmp = build2 (MIN_EXPR, gfc_array_index_type, tmp, source_bytes);
+ tmp = fold_build2 (MULT_EXPR, gfc_array_index_type,
+ tmp, dest_word_len);
+ tmp = fold_build2 (MIN_EXPR, gfc_array_index_type,
+ tmp, source_bytes);
}
else
tmp = source_bytes;
gfc_add_modify_expr (&se->pre, size_bytes, tmp);
gfc_add_modify_expr (&se->pre, size_words,
- build2 (CEIL_DIV_EXPR, gfc_array_index_type,
- size_bytes, dest_word_len));
+ fold_build2 (CEIL_DIV_EXPR, gfc_array_index_type,
+ size_bytes, dest_word_len));
/* Evaluate the bounds of the result. If the loop range exists, we have
to check if it is too large. If so, we modify loop->to be consistent
{
tmp = fold_build2 (MINUS_EXPR, gfc_array_index_type,
se->loop->to[n], se->loop->from[n]);
- tmp = build2 (PLUS_EXPR, gfc_array_index_type,
- tmp, gfc_index_one_node);
- tmp = build2 (MIN_EXPR, gfc_array_index_type,
- tmp, size_words);
+ tmp = fold_build2 (PLUS_EXPR, gfc_array_index_type,
+ tmp, gfc_index_one_node);
+ tmp = fold_build2 (MIN_EXPR, gfc_array_index_type,
+ tmp, size_words);
gfc_add_modify_expr (&se->pre, size_words, tmp);
gfc_add_modify_expr (&se->pre, size_bytes,
- build2 (MULT_EXPR, gfc_array_index_type,
- size_words, dest_word_len));
- upper = build2 (PLUS_EXPR, gfc_array_index_type,
- size_words, se->loop->from[n]);
- upper = build2 (MINUS_EXPR, gfc_array_index_type,
- upper, gfc_index_one_node);
+ fold_build2 (MULT_EXPR, gfc_array_index_type,
+ size_words, dest_word_len));
+ upper = fold_build2 (PLUS_EXPR, gfc_array_index_type,
+ size_words, se->loop->from[n]);
+ upper = fold_build2 (MINUS_EXPR, gfc_array_index_type,
+ upper, gfc_index_one_node);
}
else
{
- upper = build2 (MINUS_EXPR, gfc_array_index_type,
- size_words, gfc_index_one_node);
+ upper = fold_build2 (MINUS_EXPR, gfc_array_index_type,
+ size_words, gfc_index_one_node);
se->loop->from[n] = gfc_index_zero_node;
}
se->loop->to[n] = upper;
/* Build a destination descriptor, using the pointer, source, as the
- data field. This is already allocated so set callee_alloc. */
- tmp = gfc_typenode_for_spec (&expr->ts);
+ data field. This is already allocated so set callee_alloc.
+ FIXME callee_alloc is not set! */
+
gfc_trans_create_temp_array (&se->pre, &se->post, se->loop,
- info, tmp, false, true, false, false);
+ info, mold_type, false, true, false);
- /* Use memcpy to do the transfer. */
+ /* Cast the pointer to the result. */
tmp = gfc_conv_descriptor_data_get (info->descriptor);
- args = gfc_chainon_list (NULL_TREE, tmp);
- tmp = fold_convert (pvoid_type_node, source);
- args = gfc_chainon_list (args, source);
- args = gfc_chainon_list (args, size_bytes);
- tmp = built_in_decls[BUILT_IN_MEMCPY];
- tmp = build_function_call_expr (tmp, args);
+ tmp = fold_convert (pvoid_type_node, tmp);
+
+ /* Use memcpy to do the transfer. */
+ tmp = build_call_expr (built_in_decls[BUILT_IN_MEMCPY],
+ 3,
+ tmp,
+ fold_convert (pvoid_type_node, source),
+ size_bytes);
gfc_add_expr_to_block (&se->pre, tmp);
se->expr = info->descriptor;
/* Scalar transfer statement.
- TRANSFER (source, mold) = *(typeof<mold> *)&source. */
+ TRANSFER (source, mold) = memcpy(&tmpdecl, &source, size), tmpdecl. */
static void
gfc_conv_intrinsic_transfer (gfc_se * se, gfc_expr * expr)
tree type;
tree ptr;
gfc_ss *ss;
+ tree tmpdecl, tmp;
/* Get a pointer to the source. */
arg = expr->value.function.actual;
arg = arg->next;
type = gfc_typenode_for_spec (&expr->ts);
- ptr = convert (build_pointer_type (type), ptr);
+
if (expr->ts.type == BT_CHARACTER)
{
+ ptr = convert (build_pointer_type (type), ptr);
gfc_init_se (&argse, NULL);
gfc_conv_expr (&argse, arg->expr);
gfc_add_block_to_block (&se->pre, &argse.pre);
}
else
{
- se->expr = build_fold_indirect_ref (ptr);
+ tree moldsize;
+ tmpdecl = gfc_create_var (type, "transfer");
+ moldsize = size_in_bytes (type);
+
+ /* Use memcpy to do the transfer. */
+ tmp = build1 (ADDR_EXPR, build_pointer_type (type), tmpdecl);
+ tmp = build_call_expr (built_in_decls[BUILT_IN_MEMCPY], 3,
+ fold_convert (pvoid_type_node, tmp),
+ fold_convert (pvoid_type_node, ptr),
+ moldsize);
+ gfc_add_expr_to_block (&se->pre, tmp);
+
+ se->expr = tmpdecl;
}
}
gfc_se arg2se;
tree tmp2;
tree tmp;
- tree args, fndecl;
+ tree fndecl;
tree nonzero_charlen;
tree nonzero_arraylen;
gfc_ss *ss1, *ss2;
else
{
/* A pointer to an array. */
- arg1se.descriptor_only = 1;
- gfc_conv_expr_lhs (&arg1se, arg1->expr);
+ gfc_conv_expr_descriptor (&arg1se, arg1->expr, ss1);
tmp2 = gfc_conv_descriptor_data_get (arg1se.expr);
}
gfc_add_block_to_block (&se->pre, &arg1se.pre);
gfc_add_block_to_block (&se->pre, &arg1se.pre);
gfc_add_block_to_block (&se->post, &arg1se.post);
tmp = build2 (EQ_EXPR, boolean_type_node, arg1se.expr, arg2se.expr);
- se->expr = tmp;
+ tmp2 = build2 (NE_EXPR, boolean_type_node, arg1se.expr,
+ null_pointer_node);
+ se->expr = build2 (TRUTH_AND_EXPR, boolean_type_node, tmp, tmp2);
}
else
{
/* A pointer to an array, call library function _gfor_associated. */
gcc_assert (ss2 != gfc_ss_terminator);
- args = NULL_TREE;
arg1se.want_pointer = 1;
gfc_conv_expr_descriptor (&arg1se, arg1->expr, ss1);
- args = gfc_chainon_list (args, arg1se.expr);
arg2se.want_pointer = 1;
gfc_conv_expr_descriptor (&arg2se, arg2->expr, ss2);
gfc_add_block_to_block (&se->pre, &arg2se.pre);
gfc_add_block_to_block (&se->post, &arg2se.post);
- args = gfc_chainon_list (args, arg2se.expr);
fndecl = gfor_fndecl_associated;
- se->expr = build_function_call_expr (fndecl, args);
+ se->expr = build_call_expr (fndecl, 2, arg1se.expr, arg2se.expr);
se->expr = build2 (TRUTH_AND_EXPR, boolean_type_node,
se->expr, nonzero_arraylen);
args = gfc_conv_intrinsic_function_args (se, expr);
args = TREE_VALUE (args);
args = build_fold_addr_expr (args);
- args = tree_cons (NULL_TREE, args, NULL_TREE);
- se->expr = build_function_call_expr (gfor_fndecl_si_kind, args);
+ se->expr = build_call_expr (gfor_fndecl_si_kind, 1, args);
}
/* Generate code for SELECTED_REAL_KIND (P, R) intrinsic function. */
/* Free the temporary afterwards, if necessary. */
cond = build2 (GT_EXPR, boolean_type_node, len,
build_int_cst (TREE_TYPE (len), 0));
- arglist = gfc_chainon_list (NULL_TREE, var);
- tmp = build_function_call_expr (gfor_fndecl_internal_free, arglist);
+ tmp = gfc_call_free (var);
tmp = build3_v (COND_EXPR, cond, tmp, build_empty_stmt ());
gfc_add_expr_to_block (&se->post, tmp);
static void
gfc_conv_intrinsic_repeat (gfc_se * se, gfc_expr * expr)
{
- tree gfc_int4_type_node = gfc_get_int_type (4);
- tree tmp;
- tree len;
- tree args;
- tree arglist;
- tree ncopies;
- tree var;
- tree type;
+ tree args, ncopies, dest, dlen, src, slen, ncopies_type;
+ tree type, cond, tmp, count, exit_label, n, max, largest;
+ stmtblock_t block, body;
+ int i;
+ /* Get the arguments. */
args = gfc_conv_intrinsic_function_args (se, expr);
- len = TREE_VALUE (args);
- tmp = gfc_advance_chain (args, 2);
- ncopies = TREE_VALUE (tmp);
- len = fold_build2 (MULT_EXPR, gfc_int4_type_node, len, ncopies);
+ slen = fold_convert (size_type_node, gfc_evaluate_now (TREE_VALUE (args),
+ &se->pre));
+ src = TREE_VALUE (TREE_CHAIN (args));
+ ncopies = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (args)));
+ ncopies = gfc_evaluate_now (ncopies, &se->pre);
+ ncopies_type = TREE_TYPE (ncopies);
+
+ /* Check that NCOPIES is not negative. */
+ cond = fold_build2 (LT_EXPR, boolean_type_node, ncopies,
+ build_int_cst (ncopies_type, 0));
+ gfc_trans_runtime_check (cond,
+ "Argument NCOPIES of REPEAT intrinsic is negative",
+ &se->pre, &expr->where);
+
+ /* If the source length is zero, any non negative value of NCOPIES
+ is valid, and nothing happens. */
+ n = gfc_create_var (ncopies_type, "ncopies");
+ cond = fold_build2 (EQ_EXPR, boolean_type_node, slen,
+ build_int_cst (size_type_node, 0));
+ tmp = fold_build3 (COND_EXPR, ncopies_type, cond,
+ build_int_cst (ncopies_type, 0), ncopies);
+ gfc_add_modify_expr (&se->pre, n, tmp);
+ ncopies = n;
+
+ /* Check that ncopies is not too large: ncopies should be less than
+ (or equal to) MAX / slen, where MAX is the maximal integer of
+ the gfc_charlen_type_node type. If slen == 0, we need a special
+ case to avoid the division by zero. */
+ i = gfc_validate_kind (BT_INTEGER, gfc_charlen_int_kind, false);
+ max = gfc_conv_mpz_to_tree (gfc_integer_kinds[i].huge, gfc_charlen_int_kind);
+ max = fold_build2 (TRUNC_DIV_EXPR, size_type_node,
+ fold_convert (size_type_node, max), slen);
+ largest = TYPE_PRECISION (size_type_node) > TYPE_PRECISION (ncopies_type)
+ ? size_type_node : ncopies_type;
+ cond = fold_build2 (GT_EXPR, boolean_type_node,
+ fold_convert (largest, ncopies),
+ fold_convert (largest, max));
+ tmp = fold_build2 (EQ_EXPR, boolean_type_node, slen,
+ build_int_cst (size_type_node, 0));
+ cond = fold_build3 (COND_EXPR, boolean_type_node, tmp, boolean_false_node,
+ cond);
+ gfc_trans_runtime_check (cond,
+ "Argument NCOPIES of REPEAT intrinsic is too large",
+ &se->pre, &expr->where);
+
+ /* Compute the destination length. */
+ dlen = fold_build2 (MULT_EXPR, gfc_charlen_type_node, slen, ncopies);
type = gfc_get_character_type (expr->ts.kind, expr->ts.cl);
- var = gfc_conv_string_tmp (se, build_pointer_type (type), len);
+ dest = gfc_conv_string_tmp (se, build_pointer_type (type), dlen);
- arglist = NULL_TREE;
- arglist = gfc_chainon_list (arglist, var);
- arglist = chainon (arglist, args);
- tmp = build_function_call_expr (gfor_fndecl_string_repeat, arglist);
+ /* Generate the code to do the repeat operation:
+ for (i = 0; i < ncopies; i++)
+ memmove (dest + (i * slen), src, slen); */
+ gfc_start_block (&block);
+ count = gfc_create_var (ncopies_type, "count");
+ gfc_add_modify_expr (&block, count, build_int_cst (ncopies_type, 0));
+ exit_label = gfc_build_label_decl (NULL_TREE);
+
+ /* Start the loop body. */
+ gfc_start_block (&body);
+
+ /* Exit the loop if count >= ncopies. */
+ cond = fold_build2 (GE_EXPR, boolean_type_node, count, ncopies);
+ tmp = build1_v (GOTO_EXPR, exit_label);
+ TREE_USED (exit_label) = 1;
+ tmp = fold_build3 (COND_EXPR, void_type_node, cond, tmp,
+ build_empty_stmt ());
+ gfc_add_expr_to_block (&body, tmp);
+
+ /* Call memmove (dest + (i*slen), src, slen). */
+ tmp = fold_build2 (MULT_EXPR, gfc_charlen_type_node, slen,
+ fold_convert (gfc_charlen_type_node, count));
+ tmp = fold_build2 (PLUS_EXPR, pchar_type_node, dest,
+ fold_convert (pchar_type_node, tmp));
+ tmp = build_call_expr (built_in_decls[BUILT_IN_MEMMOVE], 3,
+ tmp, src, slen);
+ gfc_add_expr_to_block (&body, tmp);
+
+ /* Increment count. */
+ tmp = build2 (PLUS_EXPR, ncopies_type, count,
+ build_int_cst (TREE_TYPE (count), 1));
+ gfc_add_modify_expr (&body, count, tmp);
+
+ /* Build the loop. */
+ tmp = build1_v (LOOP_EXPR, gfc_finish_block (&body));
+ gfc_add_expr_to_block (&block, tmp);
+
+ /* Add the exit label. */
+ tmp = build1_v (LABEL_EXPR, exit_label);
+ gfc_add_expr_to_block (&block, tmp);
+
+ /* Finish the block. */
+ tmp = gfc_finish_block (&block);
gfc_add_expr_to_block (&se->pre, tmp);
- se->expr = var;
- se->string_length = len;
+ /* Set the result value. */
+ se->expr = dest;
+ se->string_length = dlen;
}
/* Call the library function. This always returns an INTEGER(4). */
fndecl = gfor_fndecl_iargc;
- tmp = build_function_call_expr (fndecl, NULL_TREE);
+ tmp = build_call_expr (fndecl, 0);
/* Convert it to the required type. */
type = gfc_typenode_for_spec (&expr->ts);
gfc_index_integer_kind integer. */
static void
-gfc_conv_intrinsic_loc(gfc_se * se, gfc_expr * expr)
+gfc_conv_intrinsic_loc (gfc_se * se, gfc_expr * expr)
{
tree temp_var;
gfc_expr *arg_expr;
gfc_conv_expr_reference (se, arg_expr);
else
gfc_conv_array_parameter (se, arg_expr, ss, 1);
- se->expr= convert (gfc_unsigned_type (long_integer_type_node),
- se->expr);
+ se->expr= convert (gfc_get_int_type (gfc_index_integer_kind), se->expr);
/* Create a temporary variable for loc return value. Without this,
we get an error an ICE in gcc/expr.c(expand_expr_addr_expr_1). */
- temp_var = gfc_create_var (gfc_unsigned_type (long_integer_type_node),
- NULL);
+ temp_var = gfc_create_var (gfc_get_int_type (gfc_index_integer_kind), NULL);
gfc_add_modify_expr (&se->pre, temp_var, se->expr);
se->expr = temp_var;
}
}
}
- switch (expr->value.function.isym->generic_id)
+ switch (expr->value.function.isym->id)
{
case GFC_ISYM_NONE:
gcc_unreachable ();
break;
case GFC_ISYM_AINT:
- gfc_conv_intrinsic_aint (se, expr, FIX_TRUNC_EXPR);
+ gfc_conv_intrinsic_aint (se, expr, RND_TRUNC);
break;
case GFC_ISYM_ALL:
break;
case GFC_ISYM_ANINT:
- gfc_conv_intrinsic_aint (se, expr, FIX_ROUND_EXPR);
+ gfc_conv_intrinsic_aint (se, expr, RND_ROUND);
break;
case GFC_ISYM_AND:
case GFC_ISYM_INT2:
case GFC_ISYM_INT8:
case GFC_ISYM_LONG:
- gfc_conv_intrinsic_int (se, expr, FIX_TRUNC_EXPR);
+ gfc_conv_intrinsic_int (se, expr, RND_TRUNC);
break;
case GFC_ISYM_NINT:
- gfc_conv_intrinsic_int (se, expr, FIX_ROUND_EXPR);
+ gfc_conv_intrinsic_int (se, expr, RND_ROUND);
break;
case GFC_ISYM_CEILING:
- gfc_conv_intrinsic_int (se, expr, FIX_CEIL_EXPR);
+ gfc_conv_intrinsic_int (se, expr, RND_CEIL);
break;
case GFC_ISYM_FLOOR:
- gfc_conv_intrinsic_int (se, expr, FIX_FLOOR_EXPR);
+ gfc_conv_intrinsic_int (se, expr, RND_FLOOR);
break;
case GFC_ISYM_MOD:
gfc_conv_intrinsic_size (se, expr);
break;
+ case GFC_ISYM_SIZEOF:
+ gfc_conv_intrinsic_sizeof (se, expr);
+ break;
+
case GFC_ISYM_SUM:
gfc_conv_intrinsic_arith (se, expr, PLUS_EXPR);
break;
void
gfc_add_intrinsic_ss_code (gfc_loopinfo * loop ATTRIBUTE_UNUSED, gfc_ss * ss)
{
- switch (ss->expr->value.function.isym->generic_id)
+ switch (ss->expr->value.function.isym->id)
{
case GFC_ISYM_UBOUND:
case GFC_ISYM_LBOUND:
gcc_assert (expr->expr_type == EXPR_FUNCTION && expr->value.function.isym);
gcc_assert (expr->rank > 0);
- switch (expr->value.function.isym->generic_id)
+ switch (expr->value.function.isym->id)
{
case GFC_ISYM_ALL:
case GFC_ISYM_ANY:
return gfc_walk_intrinsic_libfunc (ss, expr);
/* Special cases. */
- switch (isym->generic_id)
+ switch (isym->id)
{
case GFC_ISYM_LBOUND:
case GFC_ISYM_UBOUND: