mirror of git://gcc.gnu.org/git/gcc.git
re PR fortran/12840 ([4.0 only] Unable to find scalarization loop specifier)
PR fortran/12840 * trans.h (gfor_fndecl_internal_realloc): Declare. (gfor_fndecl_internal_realloc64): Declare. * trans-decl.c (gfor_fndecl_internal_realloc): New variable. (gfor_fndecl_internal_realloc64): New variable. (gfc_build_builtin_function_decls): Initialize them. * trans-array.h (gfc_trans_allocate_temp_array): Add a fourth argument. * trans-array.c (gfc_trans_allocate_array_storage): Add an argument to say whether the array can grow later. Don't allocate the array on the stack if so. Don't call malloc for zero-sized arrays. (gfc_trans_allocate_temp_array): Add a similar argument here. Pass it along to gfc_trans_allocate_array_storage. (gfc_get_iteration_count, gfc_grow_array): New functions. (gfc_iterator_has_dynamic_bounds): New function. (gfc_get_array_constructor_element_size): New function. (gfc_get_array_constructor_size): New function. (gfc_trans_array_ctor_element): Replace pointer argument with a descriptor tree. (gfc_trans_array_constructor_subarray): Likewise. Take an extra argument to say whether the variable-sized part of the constructor must be allocated using realloc. Grow the array when this argument is true. (gfc_trans_array_constructor_value): Likewise. (gfc_get_array_cons_size): Delete. (gfc_trans_array_constructor): If the loop bound has not been set, split the allocation into a static part and a dynamic part. Set loop->to to the bounds for static part before allocating the temporary. Adjust call to gfc_trans_array_constructor_value. (gfc_conv_loop_setup): Allow any constructor to determine the loop bounds. Check whether the constructor has a dynamic size and prefer to use something else if so. Expect the loop bound to be set later. Adjust call to gfc_trans_allocate_temp_array. * trans-expr.c (gfc_conv_function_call): Adjust another call here. From-SVN: r104073
This commit is contained in:
parent
84bb243df1
commit
ec25720ba3
|
@ -1,3 +1,39 @@
|
||||||
|
2005-09-09 Richard Sandiford <richard@codesourcery.com>
|
||||||
|
|
||||||
|
PR fortran/12840
|
||||||
|
* trans.h (gfor_fndecl_internal_realloc): Declare.
|
||||||
|
(gfor_fndecl_internal_realloc64): Declare.
|
||||||
|
* trans-decl.c (gfor_fndecl_internal_realloc): New variable.
|
||||||
|
(gfor_fndecl_internal_realloc64): New variable.
|
||||||
|
(gfc_build_builtin_function_decls): Initialize them.
|
||||||
|
* trans-array.h (gfc_trans_allocate_temp_array): Add a fourth argument.
|
||||||
|
* trans-array.c (gfc_trans_allocate_array_storage): Add an argument
|
||||||
|
to say whether the array can grow later. Don't allocate the array
|
||||||
|
on the stack if so. Don't call malloc for zero-sized arrays.
|
||||||
|
(gfc_trans_allocate_temp_array): Add a similar argument here.
|
||||||
|
Pass it along to gfc_trans_allocate_array_storage.
|
||||||
|
(gfc_get_iteration_count, gfc_grow_array): New functions.
|
||||||
|
(gfc_iterator_has_dynamic_bounds): New function.
|
||||||
|
(gfc_get_array_constructor_element_size): New function.
|
||||||
|
(gfc_get_array_constructor_size): New function.
|
||||||
|
(gfc_trans_array_ctor_element): Replace pointer argument with
|
||||||
|
a descriptor tree.
|
||||||
|
(gfc_trans_array_constructor_subarray): Likewise. Take an extra
|
||||||
|
argument to say whether the variable-sized part of the constructor
|
||||||
|
must be allocated using realloc. Grow the array when this
|
||||||
|
argument is true.
|
||||||
|
(gfc_trans_array_constructor_value): Likewise.
|
||||||
|
(gfc_get_array_cons_size): Delete.
|
||||||
|
(gfc_trans_array_constructor): If the loop bound has not been set,
|
||||||
|
split the allocation into a static part and a dynamic part. Set
|
||||||
|
loop->to to the bounds for static part before allocating the
|
||||||
|
temporary. Adjust call to gfc_trans_array_constructor_value.
|
||||||
|
(gfc_conv_loop_setup): Allow any constructor to determine the
|
||||||
|
loop bounds. Check whether the constructor has a dynamic size
|
||||||
|
and prefer to use something else if so. Expect the loop bound
|
||||||
|
to be set later. Adjust call to gfc_trans_allocate_temp_array.
|
||||||
|
* trans-expr.c (gfc_conv_function_call): Adjust another call here.
|
||||||
|
|
||||||
2005-09-09 Paul Thomas <pault@gcc.gnu.org>
|
2005-09-09 Paul Thomas <pault@gcc.gnu.org>
|
||||||
|
|
||||||
PR fortran/18878
|
PR fortran/18878
|
||||||
|
|
|
@ -94,6 +94,7 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
|
||||||
#include "dependency.h"
|
#include "dependency.h"
|
||||||
|
|
||||||
static gfc_ss *gfc_walk_subexpr (gfc_ss *, gfc_expr *);
|
static gfc_ss *gfc_walk_subexpr (gfc_ss *, gfc_expr *);
|
||||||
|
static bool gfc_get_array_constructor_size (mpz_t *, gfc_constructor *);
|
||||||
|
|
||||||
/* The contents of this structure aren't actually used, just the address. */
|
/* The contents of this structure aren't actually used, just the address. */
|
||||||
static gfc_ss gfc_ss_terminator_var;
|
static gfc_ss gfc_ss_terminator_var;
|
||||||
|
@ -435,11 +436,14 @@ gfc_trans_static_array_pointer (gfc_symbol * sym)
|
||||||
/* Generate code to allocate an array temporary, or create a variable to
|
/* Generate code to allocate an array temporary, or create a variable to
|
||||||
hold the data. If size is NULL zero the descriptor so that so that the
|
hold the data. If size is NULL zero the descriptor so that so that the
|
||||||
callee will allocate the array. Also generates code to free the array
|
callee will allocate the array. Also generates code to free the array
|
||||||
afterwards. */
|
afterwards.
|
||||||
|
|
||||||
|
DYNAMIC is true if the caller may want to extend the array later
|
||||||
|
using realloc. This prevents us from putting the array on the stack. */
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gfc_trans_allocate_array_storage (gfc_loopinfo * loop, gfc_ss_info * info,
|
gfc_trans_allocate_array_storage (gfc_loopinfo * loop, gfc_ss_info * info,
|
||||||
tree size, tree nelem)
|
tree size, tree nelem, bool dynamic)
|
||||||
{
|
{
|
||||||
tree tmp;
|
tree tmp;
|
||||||
tree args;
|
tree args;
|
||||||
|
@ -448,7 +452,7 @@ gfc_trans_allocate_array_storage (gfc_loopinfo * loop, gfc_ss_info * info,
|
||||||
|
|
||||||
desc = info->descriptor;
|
desc = info->descriptor;
|
||||||
info->offset = gfc_index_zero_node;
|
info->offset = gfc_index_zero_node;
|
||||||
if (size == NULL_TREE)
|
if (size == NULL_TREE || integer_zerop (size))
|
||||||
{
|
{
|
||||||
/* A callee allocated array. */
|
/* A callee allocated array. */
|
||||||
gfc_conv_descriptor_data_set (&loop->pre, desc, null_pointer_node);
|
gfc_conv_descriptor_data_set (&loop->pre, desc, null_pointer_node);
|
||||||
|
@ -457,7 +461,7 @@ gfc_trans_allocate_array_storage (gfc_loopinfo * loop, gfc_ss_info * info,
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* Allocate the temporary. */
|
/* Allocate the temporary. */
|
||||||
onstack = gfc_can_put_var_on_stack (size);
|
onstack = !dynamic && gfc_can_put_var_on_stack (size);
|
||||||
|
|
||||||
if (onstack)
|
if (onstack)
|
||||||
{
|
{
|
||||||
|
@ -512,11 +516,13 @@ gfc_trans_allocate_array_storage (gfc_loopinfo * loop, gfc_ss_info * info,
|
||||||
functions returning arrays. Adjusts the loop variables to be zero-based,
|
functions returning arrays. Adjusts the loop variables to be zero-based,
|
||||||
and calculates the loop bounds for callee allocated arrays.
|
and calculates the loop bounds for callee allocated arrays.
|
||||||
Also fills in the descriptor, data and offset fields of info if known.
|
Also fills in the descriptor, data and offset fields of info if known.
|
||||||
Returns the size of the array, or NULL for a callee allocated array. */
|
Returns the size of the array, or NULL for a callee allocated array.
|
||||||
|
|
||||||
|
DYNAMIC is as for gfc_trans_allocate_array_storage. */
|
||||||
|
|
||||||
tree
|
tree
|
||||||
gfc_trans_allocate_temp_array (gfc_loopinfo * loop, gfc_ss_info * info,
|
gfc_trans_allocate_temp_array (gfc_loopinfo * loop, gfc_ss_info * info,
|
||||||
tree eltype)
|
tree eltype, bool dynamic)
|
||||||
{
|
{
|
||||||
tree type;
|
tree type;
|
||||||
tree desc;
|
tree desc;
|
||||||
|
@ -611,7 +617,7 @@ gfc_trans_allocate_temp_array (gfc_loopinfo * loop, gfc_ss_info * info,
|
||||||
size = fold_build2 (MULT_EXPR, gfc_array_index_type, size,
|
size = fold_build2 (MULT_EXPR, gfc_array_index_type, size,
|
||||||
TYPE_SIZE_UNIT (gfc_get_element_type (type)));
|
TYPE_SIZE_UNIT (gfc_get_element_type (type)));
|
||||||
|
|
||||||
gfc_trans_allocate_array_storage (loop, info, size, nelem);
|
gfc_trans_allocate_array_storage (loop, info, size, nelem, dynamic);
|
||||||
|
|
||||||
if (info->dimen > loop->temp_dim)
|
if (info->dimen > loop->temp_dim)
|
||||||
loop->temp_dim = info->dimen;
|
loop->temp_dim = info->dimen;
|
||||||
|
@ -620,6 +626,149 @@ gfc_trans_allocate_temp_array (gfc_loopinfo * loop, gfc_ss_info * info,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Return the number of iterations in a loop that starts at START,
|
||||||
|
ends at END, and has step STEP. */
|
||||||
|
|
||||||
|
static tree
|
||||||
|
gfc_get_iteration_count (tree start, tree end, tree step)
|
||||||
|
{
|
||||||
|
tree tmp;
|
||||||
|
tree type;
|
||||||
|
|
||||||
|
type = TREE_TYPE (step);
|
||||||
|
tmp = fold_build2 (MINUS_EXPR, type, end, start);
|
||||||
|
tmp = fold_build2 (FLOOR_DIV_EXPR, type, tmp, step);
|
||||||
|
tmp = fold_build2 (PLUS_EXPR, type, tmp, build_int_cst (type, 1));
|
||||||
|
tmp = fold_build2 (MAX_EXPR, type, tmp, build_int_cst (type, 0));
|
||||||
|
return fold_convert (gfc_array_index_type, tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Extend the data in array DESC by EXTRA elements. */
|
||||||
|
|
||||||
|
static void
|
||||||
|
gfc_grow_array (stmtblock_t * pblock, tree desc, tree extra)
|
||||||
|
{
|
||||||
|
tree args;
|
||||||
|
tree tmp;
|
||||||
|
tree size;
|
||||||
|
tree ubound;
|
||||||
|
|
||||||
|
if (integer_zerop (extra))
|
||||||
|
return;
|
||||||
|
|
||||||
|
ubound = gfc_conv_descriptor_ubound (desc, gfc_rank_cst[0]);
|
||||||
|
|
||||||
|
/* Add EXTRA to the upper bound. */
|
||||||
|
tmp = build2 (PLUS_EXPR, gfc_array_index_type, ubound, extra);
|
||||||
|
gfc_add_modify_expr (pblock, ubound, tmp);
|
||||||
|
|
||||||
|
/* Get the value of the current data pointer. */
|
||||||
|
tmp = gfc_conv_descriptor_data_get (desc);
|
||||||
|
args = gfc_chainon_list (NULL_TREE, tmp);
|
||||||
|
|
||||||
|
/* Calculate the new array size. */
|
||||||
|
size = TYPE_SIZE_UNIT (gfc_get_element_type (TREE_TYPE (desc)));
|
||||||
|
tmp = build2 (PLUS_EXPR, gfc_array_index_type, ubound, gfc_index_one_node);
|
||||||
|
tmp = build2 (MULT_EXPR, gfc_array_index_type, tmp, size);
|
||||||
|
args = gfc_chainon_list (args, tmp);
|
||||||
|
|
||||||
|
/* Pick the appropriate realloc function. */
|
||||||
|
if (gfc_index_integer_kind == 4)
|
||||||
|
tmp = gfor_fndecl_internal_realloc;
|
||||||
|
else if (gfc_index_integer_kind == 8)
|
||||||
|
tmp = gfor_fndecl_internal_realloc64;
|
||||||
|
else
|
||||||
|
gcc_unreachable ();
|
||||||
|
|
||||||
|
/* Set the new data pointer. */
|
||||||
|
tmp = gfc_build_function_call (tmp, args);
|
||||||
|
gfc_conv_descriptor_data_set (pblock, desc, tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Return true if the bounds of iterator I can only be determined
|
||||||
|
at run time. */
|
||||||
|
|
||||||
|
static inline bool
|
||||||
|
gfc_iterator_has_dynamic_bounds (gfc_iterator * i)
|
||||||
|
{
|
||||||
|
return (i->start->expr_type != EXPR_CONSTANT
|
||||||
|
|| i->end->expr_type != EXPR_CONSTANT
|
||||||
|
|| i->step->expr_type != EXPR_CONSTANT);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Split the size of constructor element EXPR into the sum of two terms,
|
||||||
|
one of which can be determined at compile time and one of which must
|
||||||
|
be calculated at run time. Set *SIZE to the former and return true
|
||||||
|
if the latter might be nonzero. */
|
||||||
|
|
||||||
|
static bool
|
||||||
|
gfc_get_array_constructor_element_size (mpz_t * size, gfc_expr * expr)
|
||||||
|
{
|
||||||
|
if (expr->expr_type == EXPR_ARRAY)
|
||||||
|
return gfc_get_array_constructor_size (size, expr->value.constructor);
|
||||||
|
else if (expr->rank > 0)
|
||||||
|
{
|
||||||
|
/* Calculate everything at run time. */
|
||||||
|
mpz_set_ui (*size, 0);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* A single element. */
|
||||||
|
mpz_set_ui (*size, 1);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Like gfc_get_array_constructor_element_size, but applied to the whole
|
||||||
|
of array constructor C. */
|
||||||
|
|
||||||
|
static bool
|
||||||
|
gfc_get_array_constructor_size (mpz_t * size, gfc_constructor * c)
|
||||||
|
{
|
||||||
|
gfc_iterator *i;
|
||||||
|
mpz_t val;
|
||||||
|
mpz_t len;
|
||||||
|
bool dynamic;
|
||||||
|
|
||||||
|
mpz_set_ui (*size, 0);
|
||||||
|
mpz_init (len);
|
||||||
|
mpz_init (val);
|
||||||
|
|
||||||
|
dynamic = false;
|
||||||
|
for (; c; c = c->next)
|
||||||
|
{
|
||||||
|
i = c->iterator;
|
||||||
|
if (i && gfc_iterator_has_dynamic_bounds (i))
|
||||||
|
dynamic = true;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
dynamic |= gfc_get_array_constructor_element_size (&len, c->expr);
|
||||||
|
if (i)
|
||||||
|
{
|
||||||
|
/* Multiply the static part of the element size by the
|
||||||
|
number of iterations. */
|
||||||
|
mpz_sub (val, i->end->value.integer, i->start->value.integer);
|
||||||
|
mpz_fdiv_q (val, val, i->step->value.integer);
|
||||||
|
mpz_add_ui (val, val, 1);
|
||||||
|
if (mpz_sgn (val) > 0)
|
||||||
|
mpz_mul (len, len, val);
|
||||||
|
else
|
||||||
|
mpz_set_ui (len, 0);
|
||||||
|
}
|
||||||
|
mpz_add (*size, *size, len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mpz_clear (len);
|
||||||
|
mpz_clear (val);
|
||||||
|
return dynamic;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Make sure offset is a variable. */
|
/* Make sure offset is a variable. */
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -638,7 +787,7 @@ gfc_put_offset_into_var (stmtblock_t * pblock, tree * poffset,
|
||||||
/* Assign an element of an array constructor. */
|
/* Assign an element of an array constructor. */
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gfc_trans_array_ctor_element (stmtblock_t * pblock, tree pointer,
|
gfc_trans_array_ctor_element (stmtblock_t * pblock, tree desc,
|
||||||
tree offset, gfc_se * se, gfc_expr * expr)
|
tree offset, gfc_se * se, gfc_expr * expr)
|
||||||
{
|
{
|
||||||
tree tmp;
|
tree tmp;
|
||||||
|
@ -647,7 +796,7 @@ gfc_trans_array_ctor_element (stmtblock_t * pblock, tree pointer,
|
||||||
gfc_conv_expr (se, expr);
|
gfc_conv_expr (se, expr);
|
||||||
|
|
||||||
/* Store the value. */
|
/* Store the value. */
|
||||||
tmp = gfc_build_indirect_ref (pointer);
|
tmp = gfc_build_indirect_ref (gfc_conv_descriptor_data_get (desc));
|
||||||
tmp = gfc_build_array_ref (tmp, offset);
|
tmp = gfc_build_array_ref (tmp, offset);
|
||||||
if (expr->ts.type == BT_CHARACTER)
|
if (expr->ts.type == BT_CHARACTER)
|
||||||
{
|
{
|
||||||
|
@ -684,19 +833,23 @@ gfc_trans_array_ctor_element (stmtblock_t * pblock, tree pointer,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Add the contents of an array to the constructor. */
|
/* Add the contents of an array to the constructor. DYNAMIC is as for
|
||||||
|
gfc_trans_array_constructor_value. */
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gfc_trans_array_constructor_subarray (stmtblock_t * pblock,
|
gfc_trans_array_constructor_subarray (stmtblock_t * pblock,
|
||||||
tree type ATTRIBUTE_UNUSED,
|
tree type ATTRIBUTE_UNUSED,
|
||||||
tree pointer, gfc_expr * expr,
|
tree desc, gfc_expr * expr,
|
||||||
tree * poffset, tree * offsetvar)
|
tree * poffset, tree * offsetvar,
|
||||||
|
bool dynamic)
|
||||||
{
|
{
|
||||||
gfc_se se;
|
gfc_se se;
|
||||||
gfc_ss *ss;
|
gfc_ss *ss;
|
||||||
gfc_loopinfo loop;
|
gfc_loopinfo loop;
|
||||||
stmtblock_t body;
|
stmtblock_t body;
|
||||||
tree tmp;
|
tree tmp;
|
||||||
|
tree size;
|
||||||
|
int n;
|
||||||
|
|
||||||
/* We need this to be a variable so we can increment it. */
|
/* We need this to be a variable so we can increment it. */
|
||||||
gfc_put_offset_into_var (pblock, poffset, offsetvar);
|
gfc_put_offset_into_var (pblock, poffset, offsetvar);
|
||||||
|
@ -715,6 +868,22 @@ gfc_trans_array_constructor_subarray (stmtblock_t * pblock,
|
||||||
gfc_conv_ss_startstride (&loop);
|
gfc_conv_ss_startstride (&loop);
|
||||||
gfc_conv_loop_setup (&loop);
|
gfc_conv_loop_setup (&loop);
|
||||||
|
|
||||||
|
/* Make sure the constructed array has room for the new data. */
|
||||||
|
if (dynamic)
|
||||||
|
{
|
||||||
|
/* Set SIZE to the total number of elements in the subarray. */
|
||||||
|
size = gfc_index_one_node;
|
||||||
|
for (n = 0; n < loop.dimen; n++)
|
||||||
|
{
|
||||||
|
tmp = gfc_get_iteration_count (loop.from[n], loop.to[n],
|
||||||
|
gfc_index_one_node);
|
||||||
|
size = fold_build2 (MULT_EXPR, gfc_array_index_type, size, tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Grow the constructed array by SIZE elements. */
|
||||||
|
gfc_grow_array (&loop.pre, desc, size);
|
||||||
|
}
|
||||||
|
|
||||||
/* Make the loop body. */
|
/* Make the loop body. */
|
||||||
gfc_mark_ss_chain_used (ss, 1);
|
gfc_mark_ss_chain_used (ss, 1);
|
||||||
gfc_start_scalarized_body (&loop, &body);
|
gfc_start_scalarized_body (&loop, &body);
|
||||||
|
@ -724,7 +893,7 @@ gfc_trans_array_constructor_subarray (stmtblock_t * pblock,
|
||||||
if (expr->ts.type == BT_CHARACTER)
|
if (expr->ts.type == BT_CHARACTER)
|
||||||
gfc_todo_error ("character arrays in constructors");
|
gfc_todo_error ("character arrays in constructors");
|
||||||
|
|
||||||
gfc_trans_array_ctor_element (&body, pointer, *poffset, &se, expr);
|
gfc_trans_array_ctor_element (&body, desc, *poffset, &se, expr);
|
||||||
gcc_assert (se.ss == gfc_ss_terminator);
|
gcc_assert (se.ss == gfc_ss_terminator);
|
||||||
|
|
||||||
/* Increment the offset. */
|
/* Increment the offset. */
|
||||||
|
@ -741,17 +910,23 @@ gfc_trans_array_constructor_subarray (stmtblock_t * pblock,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Assign the values to the elements of an array constructor. */
|
/* Assign the values to the elements of an array constructor. DYNAMIC
|
||||||
|
is true if descriptor DESC only contains enough data for the static
|
||||||
|
size calculated by gfc_get_array_constructor_size. When true, memory
|
||||||
|
for the dynamic parts must be allocated using realloc. */
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gfc_trans_array_constructor_value (stmtblock_t * pblock, tree type,
|
gfc_trans_array_constructor_value (stmtblock_t * pblock, tree type,
|
||||||
tree pointer, gfc_constructor * c,
|
tree desc, gfc_constructor * c,
|
||||||
tree * poffset, tree * offsetvar)
|
tree * poffset, tree * offsetvar,
|
||||||
|
bool dynamic)
|
||||||
{
|
{
|
||||||
tree tmp;
|
tree tmp;
|
||||||
stmtblock_t body;
|
stmtblock_t body;
|
||||||
gfc_se se;
|
gfc_se se;
|
||||||
|
mpz_t size;
|
||||||
|
|
||||||
|
mpz_init (size);
|
||||||
for (; c; c = c->next)
|
for (; c; c = c->next)
|
||||||
{
|
{
|
||||||
/* If this is an iterator or an array, the offset must be a variable. */
|
/* If this is an iterator or an array, the offset must be a variable. */
|
||||||
|
@ -763,14 +938,14 @@ gfc_trans_array_constructor_value (stmtblock_t * pblock, tree type,
|
||||||
if (c->expr->expr_type == EXPR_ARRAY)
|
if (c->expr->expr_type == EXPR_ARRAY)
|
||||||
{
|
{
|
||||||
/* Array constructors can be nested. */
|
/* Array constructors can be nested. */
|
||||||
gfc_trans_array_constructor_value (&body, type, pointer,
|
gfc_trans_array_constructor_value (&body, type, desc,
|
||||||
c->expr->value.constructor,
|
c->expr->value.constructor,
|
||||||
poffset, offsetvar);
|
poffset, offsetvar, dynamic);
|
||||||
}
|
}
|
||||||
else if (c->expr->rank > 0)
|
else if (c->expr->rank > 0)
|
||||||
{
|
{
|
||||||
gfc_trans_array_constructor_subarray (&body, type, pointer,
|
gfc_trans_array_constructor_subarray (&body, type, desc, c->expr,
|
||||||
c->expr, poffset, offsetvar);
|
poffset, offsetvar, dynamic);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -790,8 +965,8 @@ gfc_trans_array_constructor_value (stmtblock_t * pblock, tree type,
|
||||||
{
|
{
|
||||||
/* Scalar values. */
|
/* Scalar values. */
|
||||||
gfc_init_se (&se, NULL);
|
gfc_init_se (&se, NULL);
|
||||||
gfc_trans_array_ctor_element (&body, pointer, *poffset, &se,
|
gfc_trans_array_ctor_element (&body, desc, *poffset,
|
||||||
c->expr);
|
&se, c->expr);
|
||||||
|
|
||||||
*poffset = fold_build2 (PLUS_EXPR, gfc_array_index_type,
|
*poffset = fold_build2 (PLUS_EXPR, gfc_array_index_type,
|
||||||
*poffset, gfc_index_one_node);
|
*poffset, gfc_index_one_node);
|
||||||
|
@ -813,13 +988,12 @@ gfc_trans_array_constructor_value (stmtblock_t * pblock, tree type,
|
||||||
gfc_init_se (&se, NULL);
|
gfc_init_se (&se, NULL);
|
||||||
gfc_conv_constant (&se, p->expr);
|
gfc_conv_constant (&se, p->expr);
|
||||||
if (p->expr->ts.type == BT_CHARACTER
|
if (p->expr->ts.type == BT_CHARACTER
|
||||||
&& POINTER_TYPE_P (TREE_TYPE (TREE_TYPE
|
&& POINTER_TYPE_P (type))
|
||||||
(TREE_TYPE (pointer)))))
|
|
||||||
{
|
{
|
||||||
/* For constant character array constructors we build
|
/* For constant character array constructors we build
|
||||||
an array of pointers. */
|
an array of pointers. */
|
||||||
se.expr = gfc_build_addr_expr (pchar_type_node,
|
se.expr = gfc_build_addr_expr (pchar_type_node,
|
||||||
se.expr);
|
se.expr);
|
||||||
}
|
}
|
||||||
|
|
||||||
list = tree_cons (NULL_TREE, se.expr, list);
|
list = tree_cons (NULL_TREE, se.expr, list);
|
||||||
|
@ -846,7 +1020,8 @@ gfc_trans_array_constructor_value (stmtblock_t * pblock, tree type,
|
||||||
init = tmp;
|
init = tmp;
|
||||||
|
|
||||||
/* Use BUILTIN_MEMCPY to assign the values. */
|
/* Use BUILTIN_MEMCPY to assign the values. */
|
||||||
tmp = gfc_build_indirect_ref (pointer);
|
tmp = gfc_conv_descriptor_data_get (desc);
|
||||||
|
tmp = gfc_build_indirect_ref (tmp);
|
||||||
tmp = gfc_build_array_ref (tmp, *poffset);
|
tmp = gfc_build_array_ref (tmp, *poffset);
|
||||||
tmp = gfc_build_addr_expr (NULL, tmp);
|
tmp = gfc_build_addr_expr (NULL, tmp);
|
||||||
init = gfc_build_addr_expr (NULL, init);
|
init = gfc_build_addr_expr (NULL, init);
|
||||||
|
@ -887,6 +1062,7 @@ gfc_trans_array_constructor_value (stmtblock_t * pblock, tree type,
|
||||||
tree loopvar;
|
tree loopvar;
|
||||||
tree exit_label;
|
tree exit_label;
|
||||||
tree loopbody;
|
tree loopbody;
|
||||||
|
tree tmp2;
|
||||||
|
|
||||||
loopbody = gfc_finish_block (&body);
|
loopbody = gfc_finish_block (&body);
|
||||||
|
|
||||||
|
@ -911,6 +1087,23 @@ gfc_trans_array_constructor_value (stmtblock_t * pblock, tree type,
|
||||||
gfc_add_block_to_block (pblock, &se.pre);
|
gfc_add_block_to_block (pblock, &se.pre);
|
||||||
step = gfc_evaluate_now (se.expr, pblock);
|
step = gfc_evaluate_now (se.expr, pblock);
|
||||||
|
|
||||||
|
/* If this array expands dynamically, and the number of iterations
|
||||||
|
is not constant, we won't have allocated space for the static
|
||||||
|
part of C->EXPR's size. Do that now. */
|
||||||
|
if (dynamic && gfc_iterator_has_dynamic_bounds (c->iterator))
|
||||||
|
{
|
||||||
|
/* Get the number of iterations. */
|
||||||
|
tmp = gfc_get_iteration_count (loopvar, end, step);
|
||||||
|
|
||||||
|
/* Get the static part of C->EXPR's size. */
|
||||||
|
gfc_get_array_constructor_element_size (&size, c->expr);
|
||||||
|
tmp2 = gfc_conv_mpz_to_tree (size, gfc_index_integer_kind);
|
||||||
|
|
||||||
|
/* Grow the array by TMP * TMP2 elements. */
|
||||||
|
tmp = fold_build2 (MULT_EXPR, gfc_array_index_type, tmp, tmp2);
|
||||||
|
gfc_grow_array (pblock, desc, tmp);
|
||||||
|
}
|
||||||
|
|
||||||
/* Generate the loop body. */
|
/* Generate the loop body. */
|
||||||
exit_label = gfc_build_label_decl (NULL_TREE);
|
exit_label = gfc_build_label_decl (NULL_TREE);
|
||||||
gfc_start_block (&body);
|
gfc_start_block (&body);
|
||||||
|
@ -947,73 +1140,7 @@ gfc_trans_array_constructor_value (stmtblock_t * pblock, tree type,
|
||||||
gfc_add_expr_to_block (pblock, tmp);
|
gfc_add_expr_to_block (pblock, tmp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
mpz_clear (size);
|
||||||
|
|
||||||
|
|
||||||
/* Get the size of an expression. Returns -1 if the size isn't constant.
|
|
||||||
Implied do loops with non-constant bounds are tricky because we must only
|
|
||||||
evaluate the bounds once. */
|
|
||||||
|
|
||||||
static void
|
|
||||||
gfc_get_array_cons_size (mpz_t * size, gfc_constructor * c)
|
|
||||||
{
|
|
||||||
gfc_iterator *i;
|
|
||||||
mpz_t val;
|
|
||||||
mpz_t len;
|
|
||||||
|
|
||||||
mpz_set_ui (*size, 0);
|
|
||||||
mpz_init (len);
|
|
||||||
mpz_init (val);
|
|
||||||
|
|
||||||
for (; c; c = c->next)
|
|
||||||
{
|
|
||||||
if (c->expr->expr_type == EXPR_ARRAY)
|
|
||||||
{
|
|
||||||
/* A nested array constructor. */
|
|
||||||
gfc_get_array_cons_size (&len, c->expr->value.constructor);
|
|
||||||
if (mpz_sgn (len) < 0)
|
|
||||||
{
|
|
||||||
mpz_set (*size, len);
|
|
||||||
mpz_clear (len);
|
|
||||||
mpz_clear (val);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (c->expr->rank > 0)
|
|
||||||
{
|
|
||||||
mpz_set_si (*size, -1);
|
|
||||||
mpz_clear (len);
|
|
||||||
mpz_clear (val);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
mpz_set_ui (len, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (c->iterator)
|
|
||||||
{
|
|
||||||
i = c->iterator;
|
|
||||||
|
|
||||||
if (i->start->expr_type != EXPR_CONSTANT
|
|
||||||
|| i->end->expr_type != EXPR_CONSTANT
|
|
||||||
|| i->step->expr_type != EXPR_CONSTANT)
|
|
||||||
{
|
|
||||||
mpz_set_si (*size, -1);
|
|
||||||
mpz_clear (len);
|
|
||||||
mpz_clear (val);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
mpz_add (val, i->end->value.integer, i->start->value.integer);
|
|
||||||
mpz_tdiv_q (val, val, i->step->value.integer);
|
|
||||||
mpz_add_ui (val, val, 1);
|
|
||||||
mpz_mul (len, len, val);
|
|
||||||
}
|
|
||||||
mpz_add (*size, *size, len);
|
|
||||||
}
|
|
||||||
mpz_clear (len);
|
|
||||||
mpz_clear (val);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1104,19 +1231,20 @@ get_array_ctor_strlen (gfc_constructor * c, tree * len)
|
||||||
static void
|
static void
|
||||||
gfc_trans_array_constructor (gfc_loopinfo * loop, gfc_ss * ss)
|
gfc_trans_array_constructor (gfc_loopinfo * loop, gfc_ss * ss)
|
||||||
{
|
{
|
||||||
|
gfc_constructor *c;
|
||||||
tree offset;
|
tree offset;
|
||||||
tree offsetvar;
|
tree offsetvar;
|
||||||
tree desc;
|
tree desc;
|
||||||
tree size;
|
|
||||||
tree type;
|
tree type;
|
||||||
bool const_string;
|
bool const_string;
|
||||||
|
bool dynamic;
|
||||||
|
|
||||||
ss->data.info.dimen = loop->dimen;
|
ss->data.info.dimen = loop->dimen;
|
||||||
|
|
||||||
|
c = ss->expr->value.constructor;
|
||||||
if (ss->expr->ts.type == BT_CHARACTER)
|
if (ss->expr->ts.type == BT_CHARACTER)
|
||||||
{
|
{
|
||||||
const_string = get_array_ctor_strlen (ss->expr->value.constructor,
|
const_string = get_array_ctor_strlen (c, &ss->string_length);
|
||||||
&ss->string_length);
|
|
||||||
if (!ss->string_length)
|
if (!ss->string_length)
|
||||||
gfc_todo_error ("complex character array constructors");
|
gfc_todo_error ("complex character array constructors");
|
||||||
|
|
||||||
|
@ -1130,16 +1258,39 @@ gfc_trans_array_constructor (gfc_loopinfo * loop, gfc_ss * ss)
|
||||||
type = gfc_typenode_for_spec (&ss->expr->ts);
|
type = gfc_typenode_for_spec (&ss->expr->ts);
|
||||||
}
|
}
|
||||||
|
|
||||||
size = gfc_trans_allocate_temp_array (loop, &ss->data.info, type);
|
/* See if the constructor determines the loop bounds. */
|
||||||
|
dynamic = false;
|
||||||
|
if (loop->to[0] == NULL_TREE)
|
||||||
|
{
|
||||||
|
mpz_t size;
|
||||||
|
|
||||||
|
/* We should have a 1-dimensional, zero-based loop. */
|
||||||
|
gcc_assert (loop->dimen == 1);
|
||||||
|
gcc_assert (integer_zerop (loop->from[0]));
|
||||||
|
|
||||||
|
/* Split the constructor size into a static part and a dynamic part.
|
||||||
|
Allocate the static size up-front and record whether the dynamic
|
||||||
|
size might be nonzero. */
|
||||||
|
mpz_init (size);
|
||||||
|
dynamic = gfc_get_array_constructor_size (&size, c);
|
||||||
|
mpz_sub_ui (size, size, 1);
|
||||||
|
loop->to[0] = gfc_conv_mpz_to_tree (size, gfc_index_integer_kind);
|
||||||
|
mpz_clear (size);
|
||||||
|
}
|
||||||
|
|
||||||
|
gfc_trans_allocate_temp_array (loop, &ss->data.info, type, dynamic);
|
||||||
|
|
||||||
desc = ss->data.info.descriptor;
|
desc = ss->data.info.descriptor;
|
||||||
offset = gfc_index_zero_node;
|
offset = gfc_index_zero_node;
|
||||||
offsetvar = gfc_create_var_np (gfc_array_index_type, "offset");
|
offsetvar = gfc_create_var_np (gfc_array_index_type, "offset");
|
||||||
TREE_USED (offsetvar) = 0;
|
TREE_USED (offsetvar) = 0;
|
||||||
gfc_trans_array_constructor_value (&loop->pre, type,
|
gfc_trans_array_constructor_value (&loop->pre, type, desc, c,
|
||||||
ss->data.info.data,
|
&offset, &offsetvar, dynamic);
|
||||||
ss->expr->value.constructor, &offset,
|
|
||||||
&offsetvar);
|
/* If the array grows dynamically, the upper bound of the loop variable
|
||||||
|
is determined by the array's final upper bound. */
|
||||||
|
if (dynamic)
|
||||||
|
loop->to[0] = gfc_conv_descriptor_ubound (desc, gfc_rank_cst[0]);
|
||||||
|
|
||||||
if (TREE_USED (offsetvar))
|
if (TREE_USED (offsetvar))
|
||||||
pushdecl (offsetvar);
|
pushdecl (offsetvar);
|
||||||
|
@ -2411,6 +2562,8 @@ gfc_conv_loop_setup (gfc_loopinfo * loop)
|
||||||
tree tmp;
|
tree tmp;
|
||||||
tree len;
|
tree len;
|
||||||
gfc_ss *loopspec[GFC_MAX_DIMENSIONS];
|
gfc_ss *loopspec[GFC_MAX_DIMENSIONS];
|
||||||
|
bool dynamic[GFC_MAX_DIMENSIONS];
|
||||||
|
gfc_constructor *c;
|
||||||
mpz_t *cshape;
|
mpz_t *cshape;
|
||||||
mpz_t i;
|
mpz_t i;
|
||||||
|
|
||||||
|
@ -2418,6 +2571,7 @@ gfc_conv_loop_setup (gfc_loopinfo * loop)
|
||||||
for (n = 0; n < loop->dimen; n++)
|
for (n = 0; n < loop->dimen; n++)
|
||||||
{
|
{
|
||||||
loopspec[n] = NULL;
|
loopspec[n] = NULL;
|
||||||
|
dynamic[n] = false;
|
||||||
/* We use one SS term, and use that to determine the bounds of the
|
/* We use one SS term, and use that to determine the bounds of the
|
||||||
loop for this dimension. We try to pick the simplest term. */
|
loop for this dimension. We try to pick the simplest term. */
|
||||||
for (ss = loop->ss; ss != gfc_ss_terminator; ss = ss->loop_chain)
|
for (ss = loop->ss; ss != gfc_ss_terminator; ss = ss->loop_chain)
|
||||||
|
@ -2435,17 +2589,15 @@ gfc_conv_loop_setup (gfc_loopinfo * loop)
|
||||||
Higher rank constructors will either have known shape,
|
Higher rank constructors will either have known shape,
|
||||||
or still be wrapped in a call to reshape. */
|
or still be wrapped in a call to reshape. */
|
||||||
gcc_assert (loop->dimen == 1);
|
gcc_assert (loop->dimen == 1);
|
||||||
/* Try to figure out the size of the constructor. */
|
|
||||||
/* TODO: avoid this by making the frontend set the shape. */
|
/* Always prefer to use the constructor bounds if the size
|
||||||
gfc_get_array_cons_size (&i, ss->expr->value.constructor);
|
can be determined at compile time. Prefer not to otherwise,
|
||||||
/* A negative value means we failed. */
|
since the general case involves realloc, and it's better to
|
||||||
if (mpz_sgn (i) > 0)
|
avoid that overhead if possible. */
|
||||||
{
|
c = ss->expr->value.constructor;
|
||||||
mpz_sub_ui (i, i, 1);
|
dynamic[n] = gfc_get_array_constructor_size (&i, c);
|
||||||
loop->to[n] =
|
if (!dynamic[n] || !loopspec[n])
|
||||||
gfc_conv_mpz_to_tree (i, gfc_index_integer_kind);
|
loopspec[n] = ss;
|
||||||
loopspec[n] = ss;
|
|
||||||
}
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2466,31 +2618,30 @@ gfc_conv_loop_setup (gfc_loopinfo * loop)
|
||||||
specinfo = NULL;
|
specinfo = NULL;
|
||||||
info = &ss->data.info;
|
info = &ss->data.info;
|
||||||
|
|
||||||
|
if (!specinfo)
|
||||||
|
loopspec[n] = ss;
|
||||||
/* Criteria for choosing a loop specifier (most important first):
|
/* Criteria for choosing a loop specifier (most important first):
|
||||||
|
doesn't need realloc
|
||||||
stride of one
|
stride of one
|
||||||
known stride
|
known stride
|
||||||
known lower bound
|
known lower bound
|
||||||
known upper bound
|
known upper bound
|
||||||
*/
|
*/
|
||||||
if (!specinfo)
|
else if (loopspec[n]->type == GFC_SS_CONSTRUCTOR && dynamic[n])
|
||||||
loopspec[n] = ss;
|
loopspec[n] = ss;
|
||||||
/* TODO: Is != constructor correct? */
|
else if (integer_onep (info->stride[n])
|
||||||
else if (loopspec[n]->type != GFC_SS_CONSTRUCTOR)
|
&& !integer_onep (specinfo->stride[n]))
|
||||||
{
|
loopspec[n] = ss;
|
||||||
if (integer_onep (info->stride[n])
|
else if (INTEGER_CST_P (info->stride[n])
|
||||||
&& !integer_onep (specinfo->stride[n]))
|
&& !INTEGER_CST_P (specinfo->stride[n]))
|
||||||
loopspec[n] = ss;
|
loopspec[n] = ss;
|
||||||
else if (INTEGER_CST_P (info->stride[n])
|
else if (INTEGER_CST_P (info->start[n])
|
||||||
&& !INTEGER_CST_P (specinfo->stride[n]))
|
&& !INTEGER_CST_P (specinfo->start[n]))
|
||||||
loopspec[n] = ss;
|
loopspec[n] = ss;
|
||||||
else if (INTEGER_CST_P (info->start[n])
|
/* We don't work out the upper bound.
|
||||||
&& !INTEGER_CST_P (specinfo->start[n]))
|
else if (INTEGER_CST_P (info->finish[n])
|
||||||
loopspec[n] = ss;
|
&& ! INTEGER_CST_P (specinfo->finish[n]))
|
||||||
/* We don't work out the upper bound.
|
loopspec[n] = ss; */
|
||||||
else if (INTEGER_CST_P (info->finish[n])
|
|
||||||
&& ! INTEGER_CST_P (specinfo->finish[n]))
|
|
||||||
loopspec[n] = ss; */
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!loopspec[n])
|
if (!loopspec[n])
|
||||||
|
@ -2520,8 +2671,9 @@ gfc_conv_loop_setup (gfc_loopinfo * loop)
|
||||||
switch (loopspec[n]->type)
|
switch (loopspec[n]->type)
|
||||||
{
|
{
|
||||||
case GFC_SS_CONSTRUCTOR:
|
case GFC_SS_CONSTRUCTOR:
|
||||||
gcc_assert (info->dimen == 1);
|
/* The upper bound is calculated when we expand the
|
||||||
gcc_assert (loop->to[n]);
|
constructor. */
|
||||||
|
gcc_assert (loop->to[n] == NULL_TREE);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case GFC_SS_SECTION:
|
case GFC_SS_SECTION:
|
||||||
|
@ -2575,7 +2727,8 @@ gfc_conv_loop_setup (gfc_loopinfo * loop)
|
||||||
memset (&loop->temp_ss->data.info, 0, sizeof (gfc_ss_info));
|
memset (&loop->temp_ss->data.info, 0, sizeof (gfc_ss_info));
|
||||||
loop->temp_ss->type = GFC_SS_SECTION;
|
loop->temp_ss->type = GFC_SS_SECTION;
|
||||||
loop->temp_ss->data.info.dimen = n;
|
loop->temp_ss->data.info.dimen = n;
|
||||||
gfc_trans_allocate_temp_array (loop, &loop->temp_ss->data.info, tmp);
|
gfc_trans_allocate_temp_array (loop, &loop->temp_ss->data.info,
|
||||||
|
tmp, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (n = 0; n < loop->temp_dim; n++)
|
for (n = 0; n < loop->temp_dim; n++)
|
||||||
|
|
|
@ -27,7 +27,7 @@ tree gfc_array_deallocate (tree, tree);
|
||||||
void gfc_array_allocate (gfc_se *, gfc_ref *, tree);
|
void gfc_array_allocate (gfc_se *, gfc_ref *, tree);
|
||||||
|
|
||||||
/* Generate code to allocate a temporary array. */
|
/* Generate code to allocate a temporary array. */
|
||||||
tree gfc_trans_allocate_temp_array (gfc_loopinfo *, gfc_ss_info *, tree);
|
tree gfc_trans_allocate_temp_array (gfc_loopinfo *, gfc_ss_info *, tree, bool);
|
||||||
|
|
||||||
/* Generate function entry code for allocation of compiler allocated array
|
/* Generate function entry code for allocation of compiler allocated array
|
||||||
variables. */
|
variables. */
|
||||||
|
|
|
@ -73,6 +73,8 @@ tree gfc_static_ctors;
|
||||||
|
|
||||||
tree gfor_fndecl_internal_malloc;
|
tree gfor_fndecl_internal_malloc;
|
||||||
tree gfor_fndecl_internal_malloc64;
|
tree gfor_fndecl_internal_malloc64;
|
||||||
|
tree gfor_fndecl_internal_realloc;
|
||||||
|
tree gfor_fndecl_internal_realloc64;
|
||||||
tree gfor_fndecl_internal_free;
|
tree gfor_fndecl_internal_free;
|
||||||
tree gfor_fndecl_allocate;
|
tree gfor_fndecl_allocate;
|
||||||
tree gfor_fndecl_allocate64;
|
tree gfor_fndecl_allocate64;
|
||||||
|
@ -1891,6 +1893,18 @@ gfc_build_builtin_function_decls (void)
|
||||||
pvoid_type_node, 1, gfc_int8_type_node);
|
pvoid_type_node, 1, gfc_int8_type_node);
|
||||||
DECL_IS_MALLOC (gfor_fndecl_internal_malloc64) = 1;
|
DECL_IS_MALLOC (gfor_fndecl_internal_malloc64) = 1;
|
||||||
|
|
||||||
|
gfor_fndecl_internal_realloc =
|
||||||
|
gfc_build_library_function_decl (get_identifier
|
||||||
|
(PREFIX("internal_realloc")),
|
||||||
|
pvoid_type_node, 2, pvoid_type_node,
|
||||||
|
gfc_int4_type_node);
|
||||||
|
|
||||||
|
gfor_fndecl_internal_realloc64 =
|
||||||
|
gfc_build_library_function_decl (get_identifier
|
||||||
|
(PREFIX("internal_realloc64")),
|
||||||
|
pvoid_type_node, 2, pvoid_type_node,
|
||||||
|
gfc_int8_type_node);
|
||||||
|
|
||||||
gfor_fndecl_internal_free =
|
gfor_fndecl_internal_free =
|
||||||
gfc_build_library_function_decl (get_identifier (PREFIX("internal_free")),
|
gfc_build_library_function_decl (get_identifier (PREFIX("internal_free")),
|
||||||
void_type_node, 1, pvoid_type_node);
|
void_type_node, 1, pvoid_type_node);
|
||||||
|
|
|
@ -1694,7 +1694,7 @@ gfc_conv_function_call (gfc_se * se, gfc_symbol * sym,
|
||||||
info->dimen = se->loop->dimen;
|
info->dimen = se->loop->dimen;
|
||||||
|
|
||||||
/* Allocate a temporary to store the result. */
|
/* Allocate a temporary to store the result. */
|
||||||
gfc_trans_allocate_temp_array (se->loop, info, tmp);
|
gfc_trans_allocate_temp_array (se->loop, info, tmp, false);
|
||||||
|
|
||||||
/* Zero the first stride to indicate a temporary. */
|
/* Zero the first stride to indicate a temporary. */
|
||||||
tmp = gfc_conv_descriptor_stride (info->descriptor, gfc_rank_cst[0]);
|
tmp = gfc_conv_descriptor_stride (info->descriptor, gfc_rank_cst[0]);
|
||||||
|
|
|
@ -443,6 +443,8 @@ tree builtin_function (const char *, tree, int, enum built_in_class,
|
||||||
/* Runtime library function decls. */
|
/* Runtime library function decls. */
|
||||||
extern GTY(()) tree gfor_fndecl_internal_malloc;
|
extern GTY(()) tree gfor_fndecl_internal_malloc;
|
||||||
extern GTY(()) tree gfor_fndecl_internal_malloc64;
|
extern GTY(()) tree gfor_fndecl_internal_malloc64;
|
||||||
|
extern GTY(()) tree gfor_fndecl_internal_realloc;
|
||||||
|
extern GTY(()) tree gfor_fndecl_internal_realloc64;
|
||||||
extern GTY(()) tree gfor_fndecl_internal_free;
|
extern GTY(()) tree gfor_fndecl_internal_free;
|
||||||
extern GTY(()) tree gfor_fndecl_allocate;
|
extern GTY(()) tree gfor_fndecl_allocate;
|
||||||
extern GTY(()) tree gfor_fndecl_allocate64;
|
extern GTY(()) tree gfor_fndecl_allocate64;
|
||||||
|
|
|
@ -1,3 +1,14 @@
|
||||||
|
2005-09-09 Richard Sandiford <richard@codesourcery.com>
|
||||||
|
|
||||||
|
PR fortran/12840
|
||||||
|
* gfortran.dg/array_constructor_6.f90
|
||||||
|
* gfortran.dg/array_constructor_7.f90
|
||||||
|
* gfortran.dg/array_constructor_8.f90
|
||||||
|
* gfortran.dg/array_constructor_9.f90
|
||||||
|
* gfortran.dg/array_constructor_10.f90
|
||||||
|
* gfortran.dg/array_constructor_11.f90
|
||||||
|
* gfortran.dg/array_constructor_12.f90: New tests.
|
||||||
|
|
||||||
2005-09-08 Josh Conner <jconner@apple.com>
|
2005-09-08 Josh Conner <jconner@apple.com>
|
||||||
|
|
||||||
PR c++/23180
|
PR c++/23180
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
! Like array_constructor_6.f90, but check constructors that apply
|
||||||
|
! an elemental function to an array.
|
||||||
|
! { dg-do run }
|
||||||
|
program main
|
||||||
|
implicit none
|
||||||
|
call build (200)
|
||||||
|
contains
|
||||||
|
subroutine build (order)
|
||||||
|
integer :: order, i
|
||||||
|
|
||||||
|
call test (order, (/ (abs ((/ i, -i, -i * 2 /)), i = 1, order) /))
|
||||||
|
call test (order, abs ((/ ((/ -i, -i, i * 2 /), i = 1, order) /)))
|
||||||
|
call test (order, (/ abs ((/ ((/ i, i, -i * 2 /), i = 1, order) /)) /))
|
||||||
|
end subroutine build
|
||||||
|
|
||||||
|
subroutine test (order, values)
|
||||||
|
integer, dimension (3:) :: values
|
||||||
|
integer :: order, i
|
||||||
|
|
||||||
|
if (size (values, dim = 1) .ne. order * 3) call abort
|
||||||
|
do i = 1, order
|
||||||
|
if (values (i * 3) .ne. i) call abort
|
||||||
|
if (values (i * 3 + 1) .ne. i) call abort
|
||||||
|
if (values (i * 3 + 2) .ne. i * 2) call abort
|
||||||
|
end do
|
||||||
|
end subroutine test
|
||||||
|
end program main
|
|
@ -0,0 +1,47 @@
|
||||||
|
! Like array_constructor_6.f90, but check iterators with non-default stride,
|
||||||
|
! including combinations which lead to zero-length vectors.
|
||||||
|
! { dg-do run }
|
||||||
|
program main
|
||||||
|
implicit none
|
||||||
|
call build (77)
|
||||||
|
contains
|
||||||
|
subroutine build (order)
|
||||||
|
integer :: order, i, j
|
||||||
|
|
||||||
|
call test (1, 11, 3, (/ (i, i = 1, 11, 3) /))
|
||||||
|
call test (3, 20, 2, (/ (i, i = 3, 20, 2) /))
|
||||||
|
call test (4, 0, 11, (/ (i, i = 4, 0, 11) /))
|
||||||
|
|
||||||
|
call test (110, 10, -3, (/ (i, i = 110, 10, -3) /))
|
||||||
|
call test (200, 20, -12, (/ (i, i = 200, 20, -12) /))
|
||||||
|
call test (29, 30, -6, (/ (i, i = 29, 30, -6) /))
|
||||||
|
|
||||||
|
call test (1, order, 3, (/ (i, i = 1, order, 3) /))
|
||||||
|
call test (order, 1, -3, (/ (i, i = order, 1, -3) /))
|
||||||
|
|
||||||
|
! Triggers compile-time iterator calculations in trans-array.c
|
||||||
|
call test (1, 1000, 2, (/ (i, i = 1, 1000, 2), (i, i = order, 0, 1) /))
|
||||||
|
call test (1, 0, 3, (/ (i, i = 1, 0, 3), (i, i = order, 0, 1) /))
|
||||||
|
call test (1, 2000, -5, (/ (i, i = 1, 2000, -5), (i, i = order, 0, 1) /))
|
||||||
|
call test (3000, 99, 4, (/ (i, i = 3000, 99, 4), (i, i = order, 0, 1) /))
|
||||||
|
call test (400, 77, -39, (/ (i, i = 400, 77, -39), (i, i = order, 0, 1) /))
|
||||||
|
|
||||||
|
do j = -10, 10
|
||||||
|
call test (order + j, order, 5, (/ (i, i = order + j, order, 5) /))
|
||||||
|
call test (order + j, order, -5, (/ (i, i = order + j, order, -5) /))
|
||||||
|
end do
|
||||||
|
|
||||||
|
end subroutine build
|
||||||
|
|
||||||
|
subroutine test (from, to, step, values)
|
||||||
|
integer, dimension (:) :: values
|
||||||
|
integer :: from, to, step, last, i
|
||||||
|
|
||||||
|
last = 0
|
||||||
|
do i = from, to, step
|
||||||
|
last = last + 1
|
||||||
|
if (values (last) .ne. i) call abort
|
||||||
|
end do
|
||||||
|
if (size (values, dim = 1) .ne. last) call abort
|
||||||
|
end subroutine test
|
||||||
|
end program main
|
|
@ -0,0 +1,51 @@
|
||||||
|
! Like array_constructor_6.f90, but check integer(8) iterators.
|
||||||
|
! { dg-do run }
|
||||||
|
program main
|
||||||
|
integer (kind = 8) :: i, l8, u8, step8
|
||||||
|
integer (kind = 4) :: l4, step4
|
||||||
|
integer (kind = 8), parameter :: big = 10000000000_8
|
||||||
|
|
||||||
|
l4 = huge (1)
|
||||||
|
u8 = l4 + 10_8
|
||||||
|
step4 = 2
|
||||||
|
call test ((/ (i, i = l4, u8, step4) /), l4 + 0_8, u8, step4 + 0_8)
|
||||||
|
|
||||||
|
l8 = big
|
||||||
|
u8 = big * 20
|
||||||
|
step8 = big
|
||||||
|
call test ((/ (i, i = l8, u8, step8) /), l8, u8, step8)
|
||||||
|
|
||||||
|
u8 = big + 100
|
||||||
|
l8 = big
|
||||||
|
step4 = -20
|
||||||
|
call test ((/ (i, i = u8, l8, step4) /), u8, l8, step4 + 0_8)
|
||||||
|
|
||||||
|
u8 = big * 40
|
||||||
|
l8 = big * 20
|
||||||
|
step8 = -big * 2
|
||||||
|
call test ((/ (i, i = u8, l8, step8) /), u8, l8, step8)
|
||||||
|
|
||||||
|
u8 = big
|
||||||
|
l4 = big / 100
|
||||||
|
step4 = -big / 500
|
||||||
|
call test ((/ (i, i = u8, l4, step4) /), u8, l4 + 0_8, step4 + 0_8)
|
||||||
|
|
||||||
|
u8 = big * 40 + 200
|
||||||
|
l4 = 200
|
||||||
|
step8 = -big
|
||||||
|
call test ((/ (i, i = u8, l4, step8) /), u8, l4 + 0_8, step8)
|
||||||
|
contains
|
||||||
|
subroutine test (a, l, u, step)
|
||||||
|
integer (kind = 8), dimension (:), intent (in) :: a
|
||||||
|
integer (kind = 8), intent (in) :: l, u, step
|
||||||
|
integer (kind = 8) :: i
|
||||||
|
integer :: j
|
||||||
|
|
||||||
|
j = 1
|
||||||
|
do i = l, u, step
|
||||||
|
if (a (j) .ne. i) call abort
|
||||||
|
j = j + 1
|
||||||
|
end do
|
||||||
|
if (size (a, 1) .ne. j - 1) call abort
|
||||||
|
end subroutine test
|
||||||
|
end program main
|
|
@ -0,0 +1,25 @@
|
||||||
|
! PR 12840. Make sure that array constructors can be used to determine
|
||||||
|
! the bounds of a scalarization loop.
|
||||||
|
! { dg-do run }
|
||||||
|
program main
|
||||||
|
implicit none
|
||||||
|
call build (11)
|
||||||
|
contains
|
||||||
|
subroutine build (order)
|
||||||
|
integer :: order, i
|
||||||
|
|
||||||
|
call test (order, (/ (i * 2, i = 1, order) /))
|
||||||
|
call test (17, (/ (i * 2, i = 1, 17) /))
|
||||||
|
call test (5, (/ 2, 4, 6, 8, 10 /))
|
||||||
|
end subroutine build
|
||||||
|
|
||||||
|
subroutine test (order, values)
|
||||||
|
integer, dimension (:) :: values
|
||||||
|
integer :: order, i
|
||||||
|
|
||||||
|
if (size (values, dim = 1) .ne. order) call abort
|
||||||
|
do i = 1, order
|
||||||
|
if (values (i) .ne. i * 2) call abort
|
||||||
|
end do
|
||||||
|
end subroutine test
|
||||||
|
end program main
|
|
@ -0,0 +1,26 @@
|
||||||
|
! Like array_constructor_6.f90, but test for nested iterators.
|
||||||
|
! { dg-do run }
|
||||||
|
program main
|
||||||
|
implicit none
|
||||||
|
call build (17)
|
||||||
|
contains
|
||||||
|
subroutine build (order)
|
||||||
|
integer :: order, i, j
|
||||||
|
|
||||||
|
call test (order, (/ (((j + 100) * i, j = 1, i), i = 1, order) /))
|
||||||
|
call test (9, (/ (((j + 100) * i, j = 1, i), i = 1, 9) /))
|
||||||
|
call test (3, (/ 101, 202, 204, 303, 306, 309 /))
|
||||||
|
end subroutine build
|
||||||
|
|
||||||
|
subroutine test (order, values)
|
||||||
|
integer, dimension (:) :: values
|
||||||
|
integer :: order, i, j
|
||||||
|
|
||||||
|
if (size (values, dim = 1) .ne. order * (order + 1) / 2) call abort
|
||||||
|
do i = 1, order
|
||||||
|
do j = 1, i
|
||||||
|
if (values (i * (i - 1) / 2 + j) .ne. (j + 100) * i) call abort
|
||||||
|
end do
|
||||||
|
end do
|
||||||
|
end subroutine test
|
||||||
|
end program main
|
|
@ -0,0 +1,46 @@
|
||||||
|
! Like array_constructor_6.f90, but check constructors that mix iterators
|
||||||
|
! and individual scalar elements.
|
||||||
|
! { dg-do run }
|
||||||
|
program main
|
||||||
|
implicit none
|
||||||
|
call build (42)
|
||||||
|
contains
|
||||||
|
subroutine build (order)
|
||||||
|
integer :: order, i
|
||||||
|
|
||||||
|
call test (order, 8, 5, (/ ((/ 1, 2, 3, 4, 5, 6, 7, 8 /), i = 1, order), &
|
||||||
|
100, 200, 300, 400, 500 /))
|
||||||
|
|
||||||
|
call test (order, 2, 3, (/ ((/ 1, 2 /), i = 1, order), &
|
||||||
|
100, 200, 300 /))
|
||||||
|
|
||||||
|
call test (order, 3, 5, (/ ((/ 1, 2, 3 /), i = 1, order), &
|
||||||
|
100, 200, 300, 400, 500 /))
|
||||||
|
|
||||||
|
call test (order, 6, 1, (/ ((/ 1, 2, 3, 4, 5, 6 /), i = 1, order), &
|
||||||
|
100 /))
|
||||||
|
|
||||||
|
call test (order, 5, 0, (/ ((/ 1, 2, 3, 4, 5 /), i = 1, order) /))
|
||||||
|
|
||||||
|
call test (order, 0, 4, (/ 100, 200, 300, 400 /))
|
||||||
|
|
||||||
|
call test (11, 5, 2, (/ ((/ 1, 2, 3, 4, 5 /), i = 1, 11), &
|
||||||
|
100, 200 /))
|
||||||
|
|
||||||
|
call test (6, 2, order, (/ ((/ 1, 2 /), i = 1, 6), &
|
||||||
|
(i * 100, i = 1, order) /))
|
||||||
|
end subroutine build
|
||||||
|
|
||||||
|
subroutine test (order, repeat, trail, values)
|
||||||
|
integer, dimension (:) :: values
|
||||||
|
integer :: order, repeat, trail, i
|
||||||
|
|
||||||
|
if (size (values, dim = 1) .ne. order * repeat + trail) call abort
|
||||||
|
do i = 1, order * repeat
|
||||||
|
if (values (i) .ne. mod (i - 1, repeat) + 1) call abort
|
||||||
|
end do
|
||||||
|
do i = 1, trail
|
||||||
|
if (values (i + order * repeat) .ne. i * 100) call abort
|
||||||
|
end do
|
||||||
|
end subroutine test
|
||||||
|
end program main
|
|
@ -0,0 +1,43 @@
|
||||||
|
! Like array_constructor_6.f90, but check constructors in which the length
|
||||||
|
! of each subarray can only be determined at run time.
|
||||||
|
! { dg-do run }
|
||||||
|
program main
|
||||||
|
implicit none
|
||||||
|
call build (9)
|
||||||
|
contains
|
||||||
|
function gen (order)
|
||||||
|
real, dimension (:, :), pointer :: gen
|
||||||
|
integer :: order, i, j
|
||||||
|
|
||||||
|
allocate (gen (order, order + 1))
|
||||||
|
forall (i = 1 : order, j = 1 : order + 1) gen (i, j) = i * i + j
|
||||||
|
end function gen
|
||||||
|
|
||||||
|
! Deliberately leaky!
|
||||||
|
subroutine build (order)
|
||||||
|
integer :: order, i
|
||||||
|
|
||||||
|
call test (order, 0, (/ (gen (i), i = 1, order) /))
|
||||||
|
call test (3, 2, (/ ((/ 1.5, 1.5, gen (i) /), i = 1, 3) /))
|
||||||
|
end subroutine build
|
||||||
|
|
||||||
|
subroutine test (order, prefix, values)
|
||||||
|
real, dimension (:) :: values
|
||||||
|
integer :: order, prefix, last, i, j, k
|
||||||
|
|
||||||
|
last = 0
|
||||||
|
do i = 1, order
|
||||||
|
do j = 1, prefix
|
||||||
|
last = last + 1
|
||||||
|
if (values (last) .ne. 1.5) call abort
|
||||||
|
end do
|
||||||
|
do j = 1, i + 1
|
||||||
|
do k = 1, i
|
||||||
|
last = last + 1
|
||||||
|
if (values (last) .ne. j + k * k) call abort
|
||||||
|
end do
|
||||||
|
end do
|
||||||
|
end do
|
||||||
|
if (size (values, dim = 1) .ne. last) call abort
|
||||||
|
end subroutine test
|
||||||
|
end program main
|
|
@ -1,3 +1,11 @@
|
||||||
|
2005-09-09 Richard Sandiford <richard@codesourcery.com>
|
||||||
|
|
||||||
|
PR fortran/12840
|
||||||
|
* runtime/memory.c (internal_malloc_size): Return a null pointer
|
||||||
|
if the size is zero.
|
||||||
|
(internal_free): Do nothing if the pointer is null.
|
||||||
|
(internal_realloc_size, internal_realloc, internal_realloc64): New.
|
||||||
|
|
||||||
2005-09-07 Francois-Xavier Coudert <coudert@clipper.ens.fr>
|
2005-09-07 Francois-Xavier Coudert <coudert@clipper.ens.fr>
|
||||||
|
|
||||||
PR libfortran/23262
|
PR libfortran/23262
|
||||||
|
|
|
@ -141,6 +141,9 @@ internal_malloc_size (size_t size)
|
||||||
{
|
{
|
||||||
malloc_t *newmem;
|
malloc_t *newmem;
|
||||||
|
|
||||||
|
if (size == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
newmem = malloc_with_header (size);
|
newmem = malloc_with_header (size);
|
||||||
|
|
||||||
if (!newmem)
|
if (!newmem)
|
||||||
|
@ -195,7 +198,7 @@ internal_free (void *mem)
|
||||||
malloc_t *m;
|
malloc_t *m;
|
||||||
|
|
||||||
if (!mem)
|
if (!mem)
|
||||||
runtime_error ("Internal: Possible double free of temporary.");
|
return;
|
||||||
|
|
||||||
m = DATA_HEADER (mem);
|
m = DATA_HEADER (mem);
|
||||||
|
|
||||||
|
@ -213,6 +216,67 @@ internal_free (void *mem)
|
||||||
}
|
}
|
||||||
iexport(internal_free);
|
iexport(internal_free);
|
||||||
|
|
||||||
|
/* Reallocate internal memory MEM so it has SIZE bytes of data.
|
||||||
|
Allocate a new block if MEM is zero, and free the block if
|
||||||
|
SIZE is 0. */
|
||||||
|
|
||||||
|
static void *
|
||||||
|
internal_realloc_size (void *mem, size_t size)
|
||||||
|
{
|
||||||
|
malloc_t *m;
|
||||||
|
|
||||||
|
if (size == 0)
|
||||||
|
{
|
||||||
|
if (mem)
|
||||||
|
internal_free (mem);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mem == 0)
|
||||||
|
return internal_malloc (size);
|
||||||
|
|
||||||
|
m = DATA_HEADER (mem);
|
||||||
|
if (m->magic != GFC_MALLOC_MAGIC)
|
||||||
|
runtime_error ("Internal: No magic memblock marker. "
|
||||||
|
"Possible memory corruption");
|
||||||
|
|
||||||
|
m = realloc (m, size + HEADER_SIZE);
|
||||||
|
if (!m)
|
||||||
|
os_error ("Out of memory.");
|
||||||
|
|
||||||
|
m->prev->next = m;
|
||||||
|
m->next->prev = m;
|
||||||
|
return DATA_POINTER (m);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern void *internal_realloc (void *, GFC_INTEGER_4);
|
||||||
|
export_proto(internal_realloc);
|
||||||
|
|
||||||
|
void *
|
||||||
|
internal_realloc (void *mem, GFC_INTEGER_4 size)
|
||||||
|
{
|
||||||
|
#ifdef GFC_CHECK_MEMORY
|
||||||
|
/* Under normal circumstances, this is _never_ going to happen! */
|
||||||
|
if (size < 0)
|
||||||
|
runtime_error ("Attempt to allocate a negative amount of memory.");
|
||||||
|
#endif
|
||||||
|
return internal_realloc_size (mem, (size_t) size);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern void *internal_realloc64 (void *, GFC_INTEGER_8);
|
||||||
|
export_proto(internal_realloc64);
|
||||||
|
|
||||||
|
void *
|
||||||
|
internal_realloc64 (void *mem, GFC_INTEGER_8 size)
|
||||||
|
{
|
||||||
|
#ifdef GFC_CHECK_MEMORY
|
||||||
|
/* Under normal circumstances, this is _never_ going to happen! */
|
||||||
|
if (size < 0)
|
||||||
|
runtime_error ("Attempt to allocate a negative amount of memory.");
|
||||||
|
#endif
|
||||||
|
return internal_realloc_size (mem, (size_t) size);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* User-allocate, one call for each member of the alloc-list of an
|
/* User-allocate, one call for each member of the alloc-list of an
|
||||||
ALLOCATE statement. */
|
ALLOCATE statement. */
|
||||||
|
|
Loading…
Reference in New Issue