aboutsummaryrefslogtreecommitdiff
path: root/gcc/fortran/trans-array.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/fortran/trans-array.c')
-rw-r--r--gcc/fortran/trans-array.c184
1 files changed, 117 insertions, 67 deletions
diff --git a/gcc/fortran/trans-array.c b/gcc/fortran/trans-array.c
index 87e37ea6308..2060fa1787d 100644
--- a/gcc/fortran/trans-array.c
+++ b/gcc/fortran/trans-array.c
@@ -134,22 +134,60 @@ gfc_array_dataptr_type (tree desc)
#define LBOUND_SUBFIELD 1
#define UBOUND_SUBFIELD 2
+/* This provides READ-ONLY access to the data field. The field itself
+ doesn't have the proper type. */
+
tree
-gfc_conv_descriptor_data (tree desc)
+gfc_conv_descriptor_data_get (tree desc)
{
- tree field;
- tree type;
+ tree field, type, t;
type = TREE_TYPE (desc);
gcc_assert (GFC_DESCRIPTOR_TYPE_P (type));
field = TYPE_FIELDS (type);
gcc_assert (DATA_FIELD == 0);
- gcc_assert (field != NULL_TREE
- && TREE_CODE (TREE_TYPE (field)) == POINTER_TYPE
- && TREE_CODE (TREE_TYPE (TREE_TYPE (field))) == ARRAY_TYPE);
- return build3 (COMPONENT_REF, TREE_TYPE (field), desc, field, NULL_TREE);
+ t = build3 (COMPONENT_REF, TREE_TYPE (field), desc, field, NULL_TREE);
+ t = fold_convert (GFC_TYPE_ARRAY_DATAPTR_TYPE (type), t);
+
+ return t;
+}
+
+/* This provides WRITE access to the data field. */
+
+void
+gfc_conv_descriptor_data_set (stmtblock_t *block, tree desc, tree value)
+{
+ tree field, type, t;
+
+ type = TREE_TYPE (desc);
+ gcc_assert (GFC_DESCRIPTOR_TYPE_P (type));
+
+ field = TYPE_FIELDS (type);
+ gcc_assert (DATA_FIELD == 0);
+
+ t = build3 (COMPONENT_REF, TREE_TYPE (field), desc, field, NULL_TREE);
+ gfc_add_modify_expr (block, t, fold_convert (TREE_TYPE (field), value));
+}
+
+
+/* This provides address access to the data field. This should only be
+ used by array allocation, passing this on to the runtime. */
+
+tree
+gfc_conv_descriptor_data_addr (tree desc)
+{
+ tree field, type, t;
+
+ type = TREE_TYPE (desc);
+ gcc_assert (GFC_DESCRIPTOR_TYPE_P (type));
+
+ field = TYPE_FIELDS (type);
+ gcc_assert (DATA_FIELD == 0);
+
+ t = build3 (COMPONENT_REF, TREE_TYPE (field), desc, field, NULL_TREE);
+ return gfc_build_addr_expr (NULL, t);
}
tree
@@ -407,18 +445,14 @@ gfc_trans_allocate_array_storage (gfc_loopinfo * loop, gfc_ss_info * info,
tree tmp;
tree args;
tree desc;
- tree data;
bool onstack;
desc = info->descriptor;
- data = gfc_conv_descriptor_data (desc);
+ info->offset = gfc_index_zero_node;
if (size == NULL_TREE)
{
/* A callee allocated array. */
- gfc_add_modify_expr (&loop->pre, data, convert (TREE_TYPE (data),
- gfc_index_zero_node));
- info->data = data;
- info->offset = gfc_index_zero_node;
+ gfc_conv_descriptor_data_set (&loop->pre, desc, null_pointer_node);
onstack = FALSE;
}
else
@@ -436,11 +470,8 @@ gfc_trans_allocate_array_storage (gfc_loopinfo * loop, gfc_ss_info * info,
tmp = build_array_type (gfc_get_element_type (TREE_TYPE (desc)),
tmp);
tmp = gfc_create_var (tmp, "A");
- tmp = gfc_build_addr_expr (TREE_TYPE (data), tmp);
- gfc_add_modify_expr (&loop->pre, data, tmp);
- info->data = data;
- info->offset = gfc_index_zero_node;
-
+ tmp = gfc_build_addr_expr (NULL, tmp);
+ gfc_conv_descriptor_data_set (&loop->pre, desc, tmp);
}
else
{
@@ -454,13 +485,11 @@ gfc_trans_allocate_array_storage (gfc_loopinfo * loop, gfc_ss_info * info,
else
gcc_unreachable ();
tmp = gfc_build_function_call (tmp, args);
- tmp = convert (TREE_TYPE (data), tmp);
- gfc_add_modify_expr (&loop->pre, data, tmp);
-
- info->data = data;
- info->offset = gfc_index_zero_node;
+ tmp = gfc_evaluate_now (tmp, &loop->pre);
+ gfc_conv_descriptor_data_set (&loop->pre, desc, tmp);
}
}
+ info->data = gfc_conv_descriptor_data_get (desc);
/* The offset is zero because we create temporaries with a zero
lower bound. */
@@ -470,7 +499,8 @@ gfc_trans_allocate_array_storage (gfc_loopinfo * loop, gfc_ss_info * info,
if (!onstack)
{
/* Free the temporary. */
- tmp = convert (pvoid_type_node, info->data);
+ tmp = gfc_conv_descriptor_data_get (desc);
+ tmp = fold_convert (pvoid_type_node, tmp);
tmp = gfc_chainon_list (NULL_TREE, tmp);
tmp = gfc_build_function_call (gfor_fndecl_internal_free, tmp);
gfc_add_expr_to_block (&loop->post, tmp);
@@ -721,7 +751,6 @@ gfc_trans_array_constructor_value (stmtblock_t * pblock, tree type,
{
tree tmp;
stmtblock_t body;
- tree loopbody;
gfc_se se;
for (; c; c = c->next)
@@ -842,13 +871,23 @@ gfc_trans_array_constructor_value (stmtblock_t * pblock, tree type,
}
}
- /* The frontend should already have done any expansions. */
- if (c->iterator)
+ /* The frontend should already have done any expansions possible
+ at compile-time. */
+ if (!c->iterator)
{
+ /* Pass the code as is. */
+ tmp = gfc_finish_block (&body);
+ gfc_add_expr_to_block (pblock, tmp);
+ }
+ else
+ {
+ /* Build the implied do-loop. */
+ tree cond;
tree end;
tree step;
tree loopvar;
tree exit_label;
+ tree loopbody;
loopbody = gfc_finish_block (&body);
@@ -877,17 +916,25 @@ gfc_trans_array_constructor_value (stmtblock_t * pblock, tree type,
exit_label = gfc_build_label_decl (NULL_TREE);
gfc_start_block (&body);
- /* Generate the exit condition. */
- end = build2 (GT_EXPR, boolean_type_node, loopvar, end);
+ /* Generate the exit condition. Depending on the sign of
+ the step variable we have to generate the correct
+ comparison. */
+ tmp = fold_build2 (GT_EXPR, boolean_type_node, step,
+ build_int_cst (TREE_TYPE (step), 0));
+ cond = fold_build3 (COND_EXPR, boolean_type_node, tmp,
+ build2 (GT_EXPR, boolean_type_node,
+ loopvar, end),
+ build2 (LT_EXPR, boolean_type_node,
+ loopvar, end));
tmp = build1_v (GOTO_EXPR, exit_label);
TREE_USED (exit_label) = 1;
- tmp = build3_v (COND_EXPR, end, tmp, build_empty_stmt ());
+ tmp = build3_v (COND_EXPR, cond, tmp, build_empty_stmt ());
gfc_add_expr_to_block (&body, tmp);
/* The main loop body. */
gfc_add_expr_to_block (&body, loopbody);
- /* Increment the loop variable. */
+ /* Increase loop variable by step. */
tmp = build2 (PLUS_EXPR, TREE_TYPE (loopvar), loopvar, step);
gfc_add_modify_expr (&body, loopvar, tmp);
@@ -900,12 +947,6 @@ gfc_trans_array_constructor_value (stmtblock_t * pblock, tree type,
tmp = build1_v (LABEL_EXPR, exit_label);
gfc_add_expr_to_block (pblock, tmp);
}
- else
- {
- /* Pass the code as is. */
- tmp = gfc_finish_block (&body);
- gfc_add_expr_to_block (pblock, tmp);
- }
}
}
@@ -1297,7 +1338,7 @@ gfc_conv_array_data (tree descriptor)
}
}
else
- return gfc_conv_descriptor_data (descriptor);
+ return gfc_conv_descriptor_data_get (descriptor);
}
@@ -2342,7 +2383,7 @@ gfc_conv_resolve_dependencies (gfc_loopinfo * loop, gfc_ss * dest,
loop->temp_ss->type = GFC_SS_TEMP;
loop->temp_ss->data.temp.type =
gfc_get_element_type (TREE_TYPE (dest->data.info.descriptor));
- loop->temp_ss->string_length = NULL_TREE;
+ loop->temp_ss->string_length = dest->string_length;
loop->temp_ss->data.temp.dimen = loop->dimen;
loop->temp_ss->next = gfc_ss_terminator;
gfc_add_ss_to_loop (loop, loop->temp_ss);
@@ -2738,9 +2779,8 @@ gfc_array_allocate (gfc_se * se, gfc_ref * ref, tree pstat)
lower, upper, &se->pre);
/* Allocate memory to store the data. */
- tmp = gfc_conv_descriptor_data (se->expr);
- pointer = gfc_build_addr_expr (NULL, tmp);
- pointer = gfc_evaluate_now (pointer, &se->pre);
+ tmp = gfc_conv_descriptor_data_addr (se->expr);
+ pointer = gfc_evaluate_now (tmp, &se->pre);
if (TYPE_PRECISION (gfc_array_index_type) == 32)
allocate = gfor_fndecl_allocate;
@@ -2755,8 +2795,6 @@ gfc_array_allocate (gfc_se * se, gfc_ref * ref, tree pstat)
tmp = gfc_build_function_call (allocate, tmp);
gfc_add_expr_to_block (&se->pre, tmp);
- pointer = gfc_conv_descriptor_data (se->expr);
-
tmp = gfc_conv_descriptor_offset (se->expr);
gfc_add_modify_expr (&se->pre, tmp, offset);
}
@@ -2767,7 +2805,7 @@ gfc_array_allocate (gfc_se * se, gfc_ref * ref, tree pstat)
/*GCC ARRAYS*/
tree
-gfc_array_deallocate (tree descriptor)
+gfc_array_deallocate (tree descriptor, tree pstat)
{
tree var;
tree tmp;
@@ -2775,14 +2813,12 @@ gfc_array_deallocate (tree descriptor)
gfc_start_block (&block);
/* Get a pointer to the data. */
- tmp = gfc_conv_descriptor_data (descriptor);
- tmp = gfc_build_addr_expr (NULL, tmp);
- var = gfc_create_var (TREE_TYPE (tmp), "ptr");
- gfc_add_modify_expr (&block, var, tmp);
+ tmp = gfc_conv_descriptor_data_addr (descriptor);
+ var = gfc_evaluate_now (tmp, &block);
/* Parameter is the address of the data component. */
tmp = gfc_chainon_list (NULL_TREE, var);
- tmp = gfc_chainon_list (tmp, integer_zero_node);
+ tmp = gfc_chainon_list (tmp, pstat);
tmp = gfc_build_function_call (gfor_fndecl_deallocate, tmp);
gfc_add_expr_to_block (&block, tmp);
@@ -3242,7 +3278,7 @@ gfc_trans_dummy_array_bias (gfc_symbol * sym, tree tmpdesc, tree body)
/* This is for the case where the array data is used directly without
calling the repack function. */
if (no_repack || partial != NULL_TREE)
- stmt_packed = gfc_conv_descriptor_data (dumdesc);
+ stmt_packed = gfc_conv_descriptor_data_get (dumdesc);
else
stmt_packed = NULL_TREE;
@@ -3409,7 +3445,7 @@ gfc_trans_dummy_array_bias (gfc_symbol * sym, tree tmpdesc, tree body)
/* Only do the cleanup if the array was repacked. */
tmp = gfc_build_indirect_ref (dumdesc);
- tmp = gfc_conv_descriptor_data (tmp);
+ tmp = gfc_conv_descriptor_data_get (tmp);
tmp = build2 (NE_EXPR, boolean_type_node, tmp, tmpdesc);
stmt = build3_v (COND_EXPR, tmp, stmt, build_empty_stmt ());
@@ -3616,11 +3652,23 @@ gfc_conv_expr_descriptor (gfc_se * se, gfc_expr * expr, gfc_ss * ss)
loop.temp_ss = gfc_get_ss ();
loop.temp_ss->type = GFC_SS_TEMP;
loop.temp_ss->next = gfc_ss_terminator;
- loop.temp_ss->data.temp.type = gfc_typenode_for_spec (&expr->ts);
+ if (expr->ts.type == BT_CHARACTER)
+ {
+ gcc_assert (expr->ts.cl && expr->ts.cl->length
+ && expr->ts.cl->length->expr_type == EXPR_CONSTANT);
+ loop.temp_ss->string_length = gfc_conv_mpz_to_tree
+ (expr->ts.cl->length->value.integer,
+ expr->ts.cl->length->ts.kind);
+ expr->ts.cl->backend_decl = loop.temp_ss->string_length;
+ }
+ loop.temp_ss->data.temp.type = gfc_typenode_for_spec (&expr->ts);
+
/* ... which can hold our string, if present. */
if (expr->ts.type == BT_CHARACTER)
- se->string_length = loop.temp_ss->string_length
- = TYPE_SIZE_UNIT (loop.temp_ss->data.temp.type);
+ {
+ loop.temp_ss->string_length = TYPE_SIZE_UNIT (loop.temp_ss->data.temp.type);
+ se->string_length = loop.temp_ss->string_length;
+ }
else
loop.temp_ss->string_length = NULL;
loop.temp_ss->data.temp.dimen = loop.dimen;
@@ -3652,7 +3700,13 @@ gfc_conv_expr_descriptor (gfc_se * se, gfc_expr * expr, gfc_ss * ss)
rse.ss = ss;
gfc_conv_scalarized_array_ref (&lse, NULL);
- gfc_conv_expr_val (&rse, expr);
+ if (expr->ts.type == BT_CHARACTER)
+ {
+ gfc_conv_expr (&rse, expr);
+ rse.expr = gfc_build_indirect_ref (rse.expr);
+ }
+ else
+ gfc_conv_expr_val (&rse, expr);
gfc_add_block_to_block (&block, &rse.pre);
gfc_add_block_to_block (&block, &lse.pre);
@@ -3814,10 +3868,7 @@ gfc_conv_expr_descriptor (gfc_se * se, gfc_expr * expr, gfc_ss * ss)
tmp = gfc_build_indirect_ref (tmp);
tmp = gfc_build_array_ref (tmp, offset);
offset = gfc_build_addr_expr (gfc_array_dataptr_type (desc), tmp);
-
- tmp = gfc_conv_descriptor_data (parm);
- gfc_add_modify_expr (&loop.pre, tmp,
- fold_convert (TREE_TYPE (tmp), offset));
+ gfc_conv_descriptor_data_set (&loop.pre, parm, offset);
if (se->direct_byref)
{
@@ -3984,9 +4035,7 @@ gfc_trans_deferred_array (gfc_symbol * sym, tree body)
gcc_assert (GFC_DESCRIPTOR_TYPE_P (type));
/* NULLIFY the data pointer. */
- tmp = gfc_conv_descriptor_data (descriptor);
- gfc_add_modify_expr (&fnblock, tmp,
- convert (TREE_TYPE (tmp), integer_zero_node));
+ gfc_conv_descriptor_data_set (&fnblock, descriptor, null_pointer_node);
gfc_add_expr_to_block (&fnblock, body);
@@ -3997,10 +4046,11 @@ gfc_trans_deferred_array (gfc_symbol * sym, tree body)
gfc_start_block (&block);
/* Deallocate if still allocated at the end of the procedure. */
- deallocate = gfc_array_deallocate (descriptor);
+ deallocate = gfc_array_deallocate (descriptor, null_pointer_node);
- tmp = gfc_conv_descriptor_data (descriptor);
- tmp = build2 (NE_EXPR, boolean_type_node, tmp, integer_zero_node);
+ tmp = gfc_conv_descriptor_data_get (descriptor);
+ tmp = build2 (NE_EXPR, boolean_type_node, tmp,
+ build_int_cst (TREE_TYPE (tmp), 0));
tmp = build3_v (COND_EXPR, tmp, deallocate, build_empty_stmt ());
gfc_add_expr_to_block (&block, tmp);
@@ -4349,7 +4399,7 @@ gfc_walk_array_constructor (gfc_ss * ss, gfc_expr * expr)
/* Walk an expression. Add walked expressions to the head of the SS chain.
- A wholy scalar expression will not be added. */
+ A wholly scalar expression will not be added. */
static gfc_ss *
gfc_walk_subexpr (gfc_ss * ss, gfc_expr * expr)