aboutsummaryrefslogtreecommitdiff
path: root/gcc/fortran/trans-expr.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/fortran/trans-expr.c')
-rw-r--r--gcc/fortran/trans-expr.c625
1 files changed, 472 insertions, 153 deletions
diff --git a/gcc/fortran/trans-expr.c b/gcc/fortran/trans-expr.c
index afca3a6..0138937 100644
--- a/gcc/fortran/trans-expr.c
+++ b/gcc/fortran/trans-expr.c
@@ -2866,6 +2866,9 @@ tree
gfc_maybe_dereference_var (gfc_symbol *sym, tree var, bool descriptor_only_p,
bool is_classarray)
{
+ if (is_CFI_desc (sym, NULL))
+ return build_fold_indirect_ref_loc (input_location, var);
+
/* Characters are entirely different from other types, they are treated
separately. */
if (sym->ts.type == BT_CHARACTER)
@@ -4922,7 +4925,7 @@ gfc_conv_subref_array_arg (gfc_se *se, gfc_expr * expr, int g77,
if (fsym && proc_name)
msg = xasprintf ("An array temporary was created for argument "
- "'%s' of procedure '%s'", fsym->name, proc_name);
+ "'%s' of procedure '%s'", fsym->name, proc_name);
else
msg = xasprintf ("An array temporary was created");
@@ -5220,6 +5223,8 @@ class_array_fcn:
tree post_cond;
type = TREE_TYPE (parmse->expr);
+ if (POINTER_TYPE_P (type) && GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (type)))
+ type = TREE_TYPE (type);
pointer = gfc_create_var (type, "arg_ptr");
if (check_contiguous)
@@ -5263,17 +5268,25 @@ class_array_fcn:
gfc_add_block_to_block (&se->pre, &(&array_se)->pre);
gfc_add_block_to_block (&se->pre, &(&array_se)->post);
- /* if_stmt = { pointer = &a[0]; } . */
+ /* if_stmt = { descriptor ? pointer = a : pointer = &a[0]; } . */
gfc_init_block (&if_block);
- tmp = gfc_conv_array_data (array_se.expr);
- tmp = fold_convert (type, tmp);
- gfc_add_modify (&if_block, pointer, tmp);
+ if (GFC_DESCRIPTOR_TYPE_P (type))
+ gfc_add_modify (&if_block, pointer, array_se.expr);
+ else
+ {
+ tmp = gfc_conv_array_data (array_se.expr);
+ tmp = fold_convert (type, tmp);
+ gfc_add_modify (&if_block, pointer, tmp);
+ }
if_stmt = gfc_finish_block (&if_block);
/* else_stmt = { parmse->pre(); pointer = parmse->expr; } . */
gfc_init_block (&else_block);
gfc_add_block_to_block (&else_block, &parmse->pre);
- gfc_add_modify (&else_block, pointer, parmse->expr);
+ tmp = (GFC_DESCRIPTOR_TYPE_P (type)
+ ? build_fold_indirect_ref_loc (input_location, parmse->expr)
+ : parmse->expr);
+ gfc_add_modify (&else_block, pointer, tmp);
else_stmt = gfc_finish_block (&else_block);
/* And put the above into an if statement. */
@@ -5300,7 +5313,11 @@ class_array_fcn:
/* else_stmt = { pointer = NULL; } . */
gfc_init_block (&else_block);
- gfc_add_modify (&else_block, pointer, build_int_cst (type, 0));
+ if (GFC_DESCRIPTOR_TYPE_P (type))
+ gfc_conv_descriptor_data_set (&else_block, pointer,
+ null_pointer_node);
+ else
+ gfc_add_modify (&else_block, pointer, build_int_cst (type, 0));
else_stmt = gfc_finish_block (&else_block);
tmp = fold_build3_loc (input_location, COND_EXPR, void_type_node,
@@ -5344,6 +5361,24 @@ class_array_fcn:
tmp = fold_build3_loc (input_location, COND_EXPR, void_type_node, post_cond,
post_stmts, build_empty_stmt (input_location));
gfc_add_expr_to_block (&se->post, tmp);
+ if (GFC_DESCRIPTOR_TYPE_P (type))
+ {
+ type = TREE_TYPE (parmse->expr);
+ if (POINTER_TYPE_P (type))
+ {
+ pointer = gfc_build_addr_expr (type, pointer);
+ if (pass_optional)
+ {
+ tmp = gfc_likely (present_var, PRED_FORTRAN_ABSENT_DUMMY);
+ pointer = fold_build3_loc (input_location, COND_EXPR, type,
+ tmp, pointer,
+ fold_convert (type,
+ null_pointer_node));
+ }
+ }
+ else
+ gcc_assert (!pass_optional);
+ }
se->expr = pointer;
}
@@ -5484,168 +5519,457 @@ set_dtype_for_unallocated (gfc_se *parmse, gfc_expr *e)
static void
gfc_conv_gfc_desc_to_cfi_desc (gfc_se *parmse, gfc_expr *e, gfc_symbol *fsym)
{
- tree tmp;
- tree cfi_desc_ptr;
- tree gfc_desc_ptr;
- tree type;
- tree cond;
- tree desc_attr;
- int attribute;
- int cfi_attribute;
- symbol_attribute attr = gfc_expr_attr (e);
+ stmtblock_t block, block2;
+ tree cfi, gfc, tmp, tmp2;
+ tree present = NULL;
+ tree gfc_strlen = NULL;
+ tree rank;
+ gfc_se se;
+
+ if (fsym->attr.optional
+ && e->expr_type == EXPR_VARIABLE
+ && e->symtree->n.sym->attr.optional)
+ present = gfc_conv_expr_present (e->symtree->n.sym);
+
+ gfc_init_block (&block);
- /* If this is a full array or a scalar, the allocatable and pointer
- attributes can be passed. Otherwise it is 'CFI_attribute_other'*/
- attribute = 2;
- if (!e->rank || gfc_get_full_arrayspec_from_expr (e))
+ /* Convert original argument to a tree. */
+ gfc_init_se (&se, NULL);
+ if (e->rank == 0)
{
- if (attr.pointer)
- attribute = 0;
- else if (attr.allocatable)
- attribute = 1;
+ se.want_pointer = 1;
+ gfc_conv_expr (&se, e);
+ gfc = se.expr;
+ /* gfc_conv_constant ignores se.want_poiner, e.g. for string_cst. */
+ if (!POINTER_TYPE_P (TREE_TYPE (gfc)))
+ gfc = gfc_build_addr_expr (NULL, gfc);
+ }
+ else
+ {
+ /* If the actual argument can be noncontiguous, copy-in/out is required,
+ if the dummy has either the CONTIGUOUS attribute or is an assumed-
+ length assumed-length/assumed-size CHARACTER array. */
+ se.force_no_tmp = 1;
+ if ((fsym->attr.contiguous
+ || (fsym->ts.type == BT_CHARACTER && !fsym->ts.u.cl->length
+ && (fsym->as->type == AS_ASSUMED_SIZE
+ || fsym->as->type == AS_EXPLICIT)))
+ && !gfc_is_simply_contiguous (e, false, true))
+ {
+ bool optional = fsym->attr.optional;
+ fsym->attr.optional = 0;
+ gfc_conv_subref_array_arg (&se, e, false, fsym->attr.intent,
+ fsym->attr.pointer, fsym,
+ fsym->ns->proc_name->name, NULL,
+ /* check_contiguous= */ true);
+ fsym->attr.optional = optional;
+ }
+ else
+ gfc_conv_expr_descriptor (&se, e);
+ gfc = se.expr;
+ /* For dt(:)%var the elem_len*stride != sm, hence, GFC uses
+ elem_len = sizeof(dt) and base_addr = dt(lb) instead.
+ gfc_get_dataptr_offset fixes the base_addr; for elem_len, see below.
+ While sm is fine as it uses span*stride and not elem_len. */
+ if (POINTER_TYPE_P (TREE_TYPE (gfc)))
+ gfc = build_fold_indirect_ref_loc (input_location, gfc);
+ else if (is_subref_array (e) && e->ts.type != BT_CHARACTER)
+ gfc_get_dataptr_offset (&se.pre, gfc, gfc, NULL, true, e);
+ }
+ if (e->ts.type == BT_CHARACTER)
+ {
+ if (se.string_length)
+ gfc_strlen = se.string_length;
+ else if (e->ts.u.cl->backend_decl)
+ gfc_strlen = e->ts.u.cl->backend_decl;
+ else
+ gcc_unreachable ();
}
+ gfc_add_block_to_block (&block, &se.pre);
+
+ /* Create array decriptor and set version, rank, attribute, type. */
+ cfi = gfc_create_var (gfc_get_cfi_type (e->rank < 0
+ ? GFC_MAX_DIMENSIONS : e->rank,
+ false), "cfi");
+ /* Convert to CFI_cdesc_t, which has dim[] to avoid TBAA issues,*/
+ if (fsym->attr.dimension && fsym->as->type == AS_ASSUMED_RANK)
+ {
+ tmp = gfc_get_cfi_type (-1, !fsym->attr.pointer && !fsym->attr.target);
+ tmp = build_pointer_type (tmp);
+ parmse->expr = cfi = gfc_build_addr_expr (tmp, cfi);
+ cfi = build_fold_indirect_ref_loc (input_location, cfi);
+ }
+ else
+ parmse->expr = gfc_build_addr_expr (NULL, cfi);
+
+ tmp = gfc_get_cfi_desc_version (cfi);
+ gfc_add_modify (&block, tmp,
+ build_int_cst (TREE_TYPE (tmp), CFI_VERSION));
+ if (e->rank < 0)
+ rank = fold_convert (signed_char_type_node, gfc_conv_descriptor_rank (gfc));
+ else
+ rank = build_int_cst (signed_char_type_node, e->rank);
+ tmp = gfc_get_cfi_desc_rank (cfi);
+ gfc_add_modify (&block, tmp, rank);
+ int itype = CFI_type_other;
+ if (e->ts.f90_type == BT_VOID)
+ itype = (e->ts.u.derived->intmod_sym_id == ISOCBINDING_FUNPTR
+ ? CFI_type_cfunptr : CFI_type_cptr);
+ else
+ switch (e->ts.type)
+ {
+ case BT_INTEGER:
+ case BT_LOGICAL:
+ case BT_REAL:
+ case BT_COMPLEX:
+ itype = CFI_type_from_type_kind (e->ts.type, e->ts.kind);
+ break;
+ case BT_CHARACTER:
+ itype = CFI_type_from_type_kind (CFI_type_Character, e->ts.kind);
+ break;
+ case BT_DERIVED:
+ itype = CFI_type_struct;
+ break;
+ case BT_VOID:
+ itype = (e->ts.u.derived->intmod_sym_id == ISOCBINDING_FUNPTR
+ ? CFI_type_cfunptr : CFI_type_cptr);
+ break;
+ case BT_ASSUMED:
+ itype = CFI_type_other; // FIXME: Or CFI_type_cptr ?
+ break;
+ case BT_CLASS:
+ case BT_PROCEDURE:
+ case BT_HOLLERITH:
+ case BT_UNION:
+ case BT_BOZ:
+ case BT_UNKNOWN:
+ // FIXME: Really unreachable? Or reachable for type(*) ? If so, CFI_type_other?
+ gcc_unreachable ();
+ }
+
+ tmp = gfc_get_cfi_desc_type (cfi);
+ gfc_add_modify (&block, tmp,
+ build_int_cst (TREE_TYPE (tmp), itype));
+ int attr = CFI_attribute_other;
if (fsym->attr.pointer)
- cfi_attribute = 0;
+ attr = CFI_attribute_pointer;
else if (fsym->attr.allocatable)
- cfi_attribute = 1;
- else
- cfi_attribute = 2;
+ attr = CFI_attribute_allocatable;
+ tmp = gfc_get_cfi_desc_attribute (cfi);
+ gfc_add_modify (&block, tmp,
+ build_int_cst (TREE_TYPE (tmp), attr));
- if (e->rank != 0)
+ if (e->rank == 0)
{
- parmse->force_no_tmp = 1;
- if (fsym->attr.contiguous
- && !gfc_is_simply_contiguous (e, false, true))
- gfc_conv_subref_array_arg (parmse, e, false, fsym->attr.intent,
- fsym->attr.pointer);
- else
- gfc_conv_expr_descriptor (parmse, e);
-
- if (POINTER_TYPE_P (TREE_TYPE (parmse->expr)))
- parmse->expr = build_fold_indirect_ref_loc (input_location,
- parmse->expr);
- bool is_artificial = (INDIRECT_REF_P (parmse->expr)
- ? DECL_ARTIFICIAL (TREE_OPERAND (parmse->expr, 0))
- : DECL_ARTIFICIAL (parmse->expr));
-
- /* Unallocated allocatable arrays and unassociated pointer arrays
- need their dtype setting if they are argument associated with
- assumed rank dummies. */
- if (fsym && fsym->as
- && (gfc_expr_attr (e).pointer
- || gfc_expr_attr (e).allocatable))
- set_dtype_for_unallocated (parmse, e);
-
- /* All the temporary descriptors are marked as DECL_ARTIFICIAL. If
- the expression type is different from the descriptor type, then
- the offset must be found (eg. to a component ref or substring)
- and the dtype updated. Assumed type entities are only allowed
- to be dummies in Fortran. They therefore lack the decl specific
- appendiges and so must be treated differently from other fortran
- entities passed to CFI descriptors in the interface decl. */
- type = e->ts.type != BT_ASSUMED ? gfc_typenode_for_spec (&e->ts) :
- NULL_TREE;
-
- if (type && is_artificial
- && type != gfc_get_element_type (TREE_TYPE (parmse->expr)))
- {
- /* Obtain the offset to the data. */
- gfc_get_dataptr_offset (&parmse->pre, parmse->expr, parmse->expr,
- gfc_index_zero_node, true, e);
-
- /* Update the dtype. */
- gfc_add_modify (&parmse->pre,
- gfc_conv_descriptor_dtype (parmse->expr),
- gfc_get_dtype_rank_type (e->rank, type));
- }
- else if (type == NULL_TREE
- || (!is_subref_array (e) && !is_artificial))
- {
- /* Make sure that the span is set for expressions where it
- might not have been done already. */
- tmp = gfc_conv_descriptor_elem_len (parmse->expr);
- tmp = fold_convert (gfc_array_index_type, tmp);
- gfc_conv_descriptor_span_set (&parmse->pre, parmse->expr, tmp);
- }
+ tmp = gfc_get_cfi_desc_base_addr (cfi);
+ gfc_add_modify (&block, tmp, fold_convert (TREE_TYPE (tmp), gfc));
}
else
{
- gfc_conv_expr (parmse, e);
-
- if (POINTER_TYPE_P (TREE_TYPE (parmse->expr)))
- parmse->expr = build_fold_indirect_ref_loc (input_location,
- parmse->expr);
+ tmp = gfc_get_cfi_desc_base_addr (cfi);
+ tmp2 = gfc_conv_descriptor_data_get (gfc);
+ gfc_add_modify (&block, tmp, fold_convert (TREE_TYPE (tmp), tmp2));
+ }
- parmse->expr = gfc_conv_scalar_to_descriptor (parmse,
- parmse->expr, attr);
+ /* Set elem_len if known - must be before the next if block.
+ Note that allocatable implies 'len=:'. */
+ if (e->ts.type != BT_ASSUMED && e->ts.type != BT_CHARACTER )
+ {
+ /* Length is known at compile time; use use 'block' for it. */
+ tmp = size_in_bytes (gfc_typenode_for_spec (&e->ts));
+ tmp2 = gfc_get_cfi_desc_elem_len (cfi);
+ gfc_add_modify (&block, tmp2, fold_convert (TREE_TYPE (tmp2), tmp));
}
- /* Set the CFI attribute field through a temporary value for the
- gfc attribute. */
- desc_attr = gfc_conv_descriptor_attribute (parmse->expr);
- tmp = fold_build2_loc (input_location, MODIFY_EXPR,
- void_type_node, desc_attr,
- build_int_cst (TREE_TYPE (desc_attr), cfi_attribute));
- gfc_add_expr_to_block (&parmse->pre, tmp);
+ /* When allocatable + intent out, free the cfi descriptor. */
+ if (fsym->attr.allocatable && fsym->attr.intent == INTENT_OUT)
+ {
+ tmp = gfc_get_cfi_desc_base_addr (cfi);
+ tree call = builtin_decl_explicit (BUILT_IN_FREE);
+ call = build_call_expr_loc (input_location, call, 1, tmp);
+ gfc_add_expr_to_block (&block, fold_convert (void_type_node, call));
+ gfc_add_modify (&block, tmp,
+ fold_convert (TREE_TYPE (tmp), null_pointer_node));
+ goto done;
+ }
- /* Now pass the gfc_descriptor by reference. */
- parmse->expr = gfc_build_addr_expr (NULL_TREE, parmse->expr);
+ /* If not unallocated/unassociated. */
+ gfc_init_block (&block2);
- /* Variables to point to the gfc and CFI descriptors; cfi = NULL implies
- that the CFI descriptor is allocated by the gfor_fndecl_gfc_to_cfi call. */
- gfc_desc_ptr = parmse->expr;
- cfi_desc_ptr = gfc_create_var (pvoid_type_node, "cfi");
- gfc_add_modify (&parmse->pre, cfi_desc_ptr, null_pointer_node);
+ /* Set elem_len, which may be only known at run time. */
+ if (e->ts.type == BT_CHARACTER)
+ {
+ gcc_assert (gfc_strlen);
+ tmp = gfc_strlen;
+ if (e->ts.kind != 1)
+ tmp = fold_build2_loc (input_location, MULT_EXPR,
+ gfc_charlen_type_node, tmp,
+ build_int_cst (gfc_charlen_type_node,
+ e->ts.kind));
+ tmp2 = gfc_get_cfi_desc_elem_len (cfi);
+ gfc_add_modify (&block2, tmp2, fold_convert (TREE_TYPE (tmp2), tmp));
+ }
+ else if (e->ts.type == BT_ASSUMED)
+ {
+ tmp = gfc_conv_descriptor_elem_len (gfc);
+ tmp2 = gfc_get_cfi_desc_elem_len (cfi);
+ gfc_add_modify (&block2, tmp2, fold_convert (TREE_TYPE (tmp2), tmp));
+ }
- /* Allocate the CFI descriptor itself and fill the fields. */
- tmp = gfc_build_addr_expr (NULL_TREE, cfi_desc_ptr);
- tmp = build_call_expr_loc (input_location,
- gfor_fndecl_gfc_to_cfi, 2, tmp, gfc_desc_ptr);
- gfc_add_expr_to_block (&parmse->pre, tmp);
+ if (e->ts.type == BT_ASSUMED)
+ {
+ /* Note: type(*) implies assumed-shape/assumed-rank if fsym requires
+ an CFI descriptor. Use the type in the descritor as it provide
+ mode information. (Quality of implementation feature.) */
+ tree cond;
+ tree ctype = gfc_get_cfi_desc_type (cfi);
+ tree type = fold_convert (TREE_TYPE (ctype),
+ gfc_conv_descriptor_type (gfc));
+ tree kind = fold_convert (TREE_TYPE (ctype),
+ gfc_conv_descriptor_elem_len (gfc));
+ kind = fold_build2_loc (input_location, LSHIFT_EXPR, TREE_TYPE (type),
+ kind, build_int_cst (TREE_TYPE (type),
+ CFI_type_kind_shift));
+
+ /* if (BT_VOID) CFI_type_cptr else CFI_type_other */
+ /* Note: BT_VOID is could also be CFI_type_funcptr, but assume c_ptr. */
+ cond = fold_build2_loc (input_location, EQ_EXPR, boolean_type_node, type,
+ build_int_cst (TREE_TYPE (type), BT_VOID));
+ tmp = fold_build2_loc (input_location, MODIFY_EXPR, void_type_node, ctype,
+ build_int_cst (TREE_TYPE (type), CFI_type_cptr));
+ tmp2 = fold_build2_loc (input_location, MODIFY_EXPR, void_type_node,
+ ctype,
+ build_int_cst (TREE_TYPE (type), CFI_type_other));
+ tmp2 = fold_build3_loc (input_location, COND_EXPR, void_type_node, cond,
+ tmp, tmp2);
+ /* if (BT_DERIVED) CFI_type_struct else < tmp2 > */
+ cond = fold_build2_loc (input_location, EQ_EXPR, boolean_type_node, type,
+ build_int_cst (TREE_TYPE (type), BT_DERIVED));
+ tmp = fold_build2_loc (input_location, MODIFY_EXPR, void_type_node, ctype,
+ build_int_cst (TREE_TYPE (type), CFI_type_struct));
+ tmp2 = fold_build3_loc (input_location, COND_EXPR, void_type_node, cond,
+ tmp, tmp2);
+ /* if (BT_CHARACTER) CFI_type_Character + kind=1 else < tmp2 > */
+ /* Note: could also be kind=4, with cfi->elem_len = gfc->elem_len*4. */
+ cond = fold_build2_loc (input_location, EQ_EXPR, boolean_type_node, type,
+ build_int_cst (TREE_TYPE (type), BT_CHARACTER));
+ tmp = build_int_cst (TREE_TYPE (type),
+ CFI_type_from_type_kind (CFI_type_Character, 1));
+ tmp = fold_build2_loc (input_location, MODIFY_EXPR, void_type_node,
+ ctype, tmp);
+ tmp2 = fold_build3_loc (input_location, COND_EXPR, void_type_node, cond,
+ tmp, tmp2);
+ /* if (BT_COMPLEX) CFI_type_Complex + kind/2 else < tmp2 > */
+ cond = fold_build2_loc (input_location, EQ_EXPR, boolean_type_node, type,
+ build_int_cst (TREE_TYPE (type), BT_COMPLEX));
+ tmp = fold_build2_loc (input_location, TRUNC_DIV_EXPR, TREE_TYPE (type),
+ kind, build_int_cst (TREE_TYPE (type), 2));
+ tmp = fold_build2_loc (input_location, PLUS_EXPR, TREE_TYPE (type), tmp,
+ build_int_cst (TREE_TYPE (type),
+ CFI_type_Complex));
+ tmp = fold_build2_loc (input_location, MODIFY_EXPR, void_type_node,
+ ctype, tmp);
+ tmp2 = fold_build3_loc (input_location, COND_EXPR, void_type_node, cond,
+ tmp, tmp2);
+ /* if (BT_INTEGER || BT_LOGICAL || BT_REAL) type + kind else <tmp2> */
+ cond = fold_build2_loc (input_location, EQ_EXPR, boolean_type_node, type,
+ build_int_cst (TREE_TYPE (type), BT_INTEGER));
+ tmp = fold_build2_loc (input_location, EQ_EXPR, boolean_type_node, type,
+ build_int_cst (TREE_TYPE (type), BT_LOGICAL));
+ cond = fold_build2_loc (input_location, TRUTH_OR_EXPR, boolean_type_node,
+ cond, tmp);
+ tmp = fold_build2_loc (input_location, EQ_EXPR, boolean_type_node, type,
+ build_int_cst (TREE_TYPE (type), BT_REAL));
+ cond = fold_build2_loc (input_location, TRUTH_OR_EXPR, boolean_type_node,
+ cond, tmp);
+ tmp = fold_build2_loc (input_location, PLUS_EXPR, TREE_TYPE (type),
+ type, kind);
+ tmp = fold_build2_loc (input_location, MODIFY_EXPR, void_type_node,
+ ctype, tmp);
+ tmp2 = fold_build3_loc (input_location, COND_EXPR, void_type_node, cond,
+ tmp, tmp2);
+ gfc_add_expr_to_block (&block2, tmp2);
+ }
- /* Now set the gfc descriptor attribute. */
- tmp = fold_build2_loc (input_location, MODIFY_EXPR,
- void_type_node, desc_attr,
- build_int_cst (TREE_TYPE (desc_attr), attribute));
- gfc_add_expr_to_block (&parmse->pre, tmp);
+ if (e->rank != 0)
+ {
+ /* Loop: for (i = 0; i < rank; ++i). */
+ tree idx = gfc_create_var (TREE_TYPE (rank), "idx");
+ /* Loop body. */
+ stmtblock_t loop_body;
+ gfc_init_block (&loop_body);
+ /* cfi->dim[i].lower_bound = (allocatable/pointer)
+ ? gfc->dim[i].lbound : 0 */
+ if (fsym->attr.pointer || fsym->attr.allocatable)
+ tmp = gfc_conv_descriptor_lbound_get (gfc, idx);
+ else
+ tmp = gfc_index_zero_node;
+ gfc_add_modify (&loop_body, gfc_get_cfi_dim_lbound (cfi, idx), tmp);
+ /* cfi->dim[i].extent = gfc->dim[i].ubound - gfc->dim[i].lbound + 1. */
+ tmp = fold_build2_loc (input_location, MINUS_EXPR, gfc_array_index_type,
+ gfc_conv_descriptor_ubound_get (gfc, idx),
+ gfc_conv_descriptor_lbound_get (gfc, idx));
+ tmp = fold_build2_loc (input_location, PLUS_EXPR, gfc_array_index_type,
+ tmp, gfc_index_one_node);
+ gfc_add_modify (&loop_body, gfc_get_cfi_dim_extent (cfi, idx), tmp);
+ /* d->dim[n].sm = gfc->dim[i].stride * gfc->span); */
+ tmp = fold_build2_loc (input_location, MULT_EXPR, gfc_array_index_type,
+ gfc_conv_descriptor_stride_get (gfc, idx),
+ gfc_conv_descriptor_span_get (gfc));
+ gfc_add_modify (&loop_body, gfc_get_cfi_dim_sm (cfi, idx), tmp);
- /* The CFI descriptor is passed to the bind_C procedure. */
- parmse->expr = cfi_desc_ptr;
+ /* Generate loop. */
+ gfc_simple_for_loop (&block2, idx, build_int_cst (TREE_TYPE (idx), 0),
+ rank, LT_EXPR, build_int_cst (TREE_TYPE (idx), 1),
+ gfc_finish_block (&loop_body));
- /* Free the CFI descriptor. */
- tmp = gfc_call_free (cfi_desc_ptr);
- gfc_prepend_expr_to_block (&parmse->post, tmp);
+ if (e->expr_type == EXPR_VARIABLE
+ && e->ref
+ && e->ref->u.ar.type == AR_FULL
+ && e->symtree->n.sym->attr.dummy
+ && e->symtree->n.sym->as
+ && e->symtree->n.sym->as->type == AS_ASSUMED_SIZE)
+ {
+ tmp = gfc_get_cfi_dim_extent (cfi, gfc_rank_cst[e->rank-1]),
+ gfc_add_modify (&block2, tmp, build_int_cst (TREE_TYPE (tmp), -1));
+ }
+ }
- /* Transfer values back to gfc descriptor. */
- if (cfi_attribute != 2 /* CFI_attribute_other. */
- && !fsym->attr.value
- && fsym->attr.intent != INTENT_IN)
+ if (fsym->attr.allocatable || fsym->attr.pointer)
{
- tmp = gfc_build_addr_expr (NULL_TREE, parmse->expr);
- tmp = build_call_expr_loc (input_location,
- gfor_fndecl_cfi_to_gfc, 2, gfc_desc_ptr, tmp);
- gfc_prepend_expr_to_block (&parmse->post, tmp);
+ tmp = gfc_get_cfi_desc_base_addr (cfi),
+ tmp = fold_build2_loc (input_location, NE_EXPR, boolean_type_node,
+ tmp, null_pointer_node);
+ tmp = build3_v (COND_EXPR, tmp, gfc_finish_block (&block2),
+ build_empty_stmt (input_location));
+ gfc_add_expr_to_block (&block, tmp);
}
+ else
+ gfc_add_block_to_block (&block, &block2);
- /* Deal with an optional dummy being passed to an optional formal arg
- by finishing the pre and post blocks and making their execution
- conditional on the dummy being present. */
- if (fsym->attr.optional && e->expr_type == EXPR_VARIABLE
- && e->symtree->n.sym->attr.optional)
+
+done:
+ if (present)
{
- cond = gfc_conv_expr_present (e->symtree->n.sym);
- tmp = fold_build2 (MODIFY_EXPR, void_type_node,
- cfi_desc_ptr,
- build_int_cst (pvoid_type_node, 0));
- tmp = build3_v (COND_EXPR, cond,
- gfc_finish_block (&parmse->pre), tmp);
+ parmse->expr = build3_loc (input_location, COND_EXPR,
+ TREE_TYPE (parmse->expr),
+ present, parmse->expr, null_pointer_node);
+ tmp = build3_v (COND_EXPR, present, gfc_finish_block (&block),
+ build_empty_stmt (input_location));
gfc_add_expr_to_block (&parmse->pre, tmp);
- tmp = build3_v (COND_EXPR, cond,
- gfc_finish_block (&parmse->post),
+ }
+ else
+ gfc_add_block_to_block (&parmse->pre, &block);
+
+ gfc_init_block (&block);
+
+ if ((!fsym->attr.allocatable && !fsym->attr.pointer)
+ || fsym->attr.intent == INTENT_IN)
+ goto post_call;
+
+ gfc_init_block (&block2);
+ if (e->rank == 0)
+ {
+ tmp = gfc_get_cfi_desc_base_addr (cfi);
+ gfc_add_modify (&block, gfc, fold_convert (TREE_TYPE (gfc), tmp));
+ }
+ else
+ {
+ tmp = gfc_get_cfi_desc_base_addr (cfi);
+ gfc_conv_descriptor_data_set (&block, gfc, tmp);
+
+ if (fsym->attr.allocatable)
+ {
+ /* gfc->span = cfi->elem_len. */
+ tmp = fold_convert (gfc_array_index_type,
+ gfc_get_cfi_dim_sm (cfi, gfc_rank_cst[0]));
+ }
+ else
+ {
+ /* gfc->span = ((cfi->dim[0].sm % cfi->elem_len)
+ ? cfi->dim[0].sm : cfi->elem_len). */
+ tmp = gfc_get_cfi_dim_sm (cfi, gfc_rank_cst[0]);
+ tmp2 = fold_convert (gfc_array_index_type,
+ gfc_get_cfi_desc_elem_len (cfi));
+ tmp = fold_build2_loc (input_location, TRUNC_MOD_EXPR,
+ gfc_array_index_type, tmp, tmp2);
+ tmp = fold_build2_loc (input_location, NE_EXPR, boolean_type_node,
+ tmp, gfc_index_zero_node);
+ tmp = build3_loc (input_location, COND_EXPR, gfc_array_index_type, tmp,
+ gfc_get_cfi_dim_sm (cfi, gfc_rank_cst[0]), tmp2);
+ }
+ gfc_conv_descriptor_span_set (&block2, gfc, tmp);
+
+ /* Calculate offset + set lbound, ubound and stride. */
+ gfc_conv_descriptor_offset_set (&block2, gfc, gfc_index_zero_node);
+ /* Loop: for (i = 0; i < rank; ++i). */
+ tree idx = gfc_create_var (TREE_TYPE (rank), "idx");
+ /* Loop body. */
+ stmtblock_t loop_body;
+ gfc_init_block (&loop_body);
+ /* gfc->dim[i].lbound = ... */
+ tmp = gfc_get_cfi_dim_lbound (cfi, idx);
+ gfc_conv_descriptor_lbound_set (&loop_body, gfc, idx, tmp);
+
+ /* gfc->dim[i].ubound = gfc->dim[i].lbound + cfi->dim[i].extent - 1. */
+ tmp = fold_build2_loc (input_location, MINUS_EXPR, gfc_array_index_type,
+ gfc_conv_descriptor_lbound_get (gfc, idx),
+ gfc_index_one_node);
+ tmp = fold_build2_loc (input_location, PLUS_EXPR, gfc_array_index_type,
+ gfc_get_cfi_dim_extent (cfi, idx), tmp);
+ gfc_conv_descriptor_ubound_set (&loop_body, gfc, idx, tmp);
+
+ /* gfc->dim[i].stride = cfi->dim[i].sm / cfi>elem_len */
+ tmp = gfc_get_cfi_dim_sm (cfi, idx);
+ tmp = fold_build2_loc (input_location, TRUNC_DIV_EXPR,
+ gfc_array_index_type, tmp,
+ fold_convert (gfc_array_index_type,
+ gfc_get_cfi_desc_elem_len (cfi)));
+ gfc_conv_descriptor_stride_set (&loop_body, gfc, idx, tmp);
+
+ /* gfc->offset -= gfc->dim[i].stride * gfc->dim[i].lbound. */
+ tmp = fold_build2_loc (input_location, MULT_EXPR, gfc_array_index_type,
+ gfc_conv_descriptor_stride_get (gfc, idx),
+ gfc_conv_descriptor_lbound_get (gfc, idx));
+ tmp = fold_build2_loc (input_location, MINUS_EXPR, gfc_array_index_type,
+ gfc_conv_descriptor_offset_get (gfc), tmp);
+ gfc_conv_descriptor_offset_set (&loop_body, gfc, tmp);
+ /* Generate loop. */
+ gfc_simple_for_loop (&block2, idx, build_int_cst (TREE_TYPE (idx), 0),
+ rank, LT_EXPR, build_int_cst (TREE_TYPE (idx), 1),
+ gfc_finish_block (&loop_body));
+ }
+
+ if (e->ts.type == BT_CHARACTER && !e->ts.u.cl->length)
+ {
+ tmp = fold_convert (gfc_charlen_type_node,
+ gfc_get_cfi_desc_elem_len (cfi));
+ if (e->ts.kind != 1)
+ tmp = fold_build2_loc (input_location, TRUNC_DIV_EXPR,
+ gfc_charlen_type_node, tmp,
+ build_int_cst (gfc_charlen_type_node,
+ e->ts.kind));
+ gfc_add_modify (&block2, gfc_strlen, tmp);
+ }
+
+ tmp = gfc_get_cfi_desc_base_addr (cfi),
+ tmp = fold_build2_loc (input_location, NE_EXPR, boolean_type_node,
+ tmp, null_pointer_node);
+ tmp = build3_v (COND_EXPR, tmp, gfc_finish_block (&block2),
+ build_empty_stmt (input_location));
+ gfc_add_expr_to_block (&block, tmp);
+
+post_call:
+ gfc_add_block_to_block (&block, &se.post);
+ if (present && block.head)
+ {
+ tmp = build3_v (COND_EXPR, present, gfc_finish_block (&block),
build_empty_stmt (input_location));
gfc_add_expr_to_block (&parmse->post, tmp);
}
+ else if (block.head)
+ gfc_add_block_to_block (&parmse->post, &block);
}
@@ -5764,17 +6088,12 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym,
arg = arg->next, formal = formal ? formal->next : NULL, ++argc)
{
bool finalized = false;
- bool assumed_length_string = false;
tree derived_array = NULL_TREE;
e = arg->expr;
fsym = formal ? formal->sym : NULL;
parm_kind = MISSING;
- if (fsym && fsym->ts.type == BT_CHARACTER
- && (!fsym->ts.u.cl || !fsym->ts.u.cl->length))
- assumed_length_string = true;
-
/* If the procedure requires an explicit interface, the actual
argument is passed according to the corresponding formal
argument. If the corresponding formal argument is a POINTER,
@@ -6005,9 +6324,7 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym,
parmse.expr = convert (type, tmp);
}
- else if (sym->attr.is_bind_c && e
- && (is_CFI_desc (fsym, NULL)
- || assumed_length_string))
+ else if (sym->attr.is_bind_c && e && is_CFI_desc (fsym, NULL))
/* Implement F2018, 18.3.6, list item (5), bullet point 2. */
gfc_conv_gfc_desc_to_cfi_desc (&parmse, e, fsym);
@@ -6217,7 +6534,8 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym,
if (fsym && fsym->attr.intent == INTENT_OUT
&& (fsym->attr.allocatable
|| (fsym->ts.type == BT_CLASS
- && CLASS_DATA (fsym)->attr.allocatable)))
+ && CLASS_DATA (fsym)->attr.allocatable))
+ && !is_CFI_desc (fsym, NULL))
{
stmtblock_t block;
tree ptr;
@@ -6474,8 +6792,7 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym,
ref->u.ar.type = AR_SECTION;
}
- if (sym->attr.is_bind_c && e
- && (is_CFI_desc (fsym, NULL) || assumed_length_string))
+ if (sym->attr.is_bind_c && e && is_CFI_desc (fsym, NULL))
/* Implement F2018, 18.3.6, list item (5), bullet point 2. */
gfc_conv_gfc_desc_to_cfi_desc (&parmse, e, fsym);
@@ -6535,9 +6852,11 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym,
sym->name, NULL);
/* If an ALLOCATABLE dummy argument has INTENT(OUT) and is
- allocated on entry, it must be deallocated. */
+ allocated on entry, it must be deallocated.
+ CFI descriptors are handled elsewhere. */
if (fsym && fsym->attr.allocatable
- && fsym->attr.intent == INTENT_OUT)
+ && fsym->attr.intent == INTENT_OUT
+ && !is_CFI_desc (fsym, NULL))
{
if (fsym->ts.type == BT_DERIVED
&& fsym->ts.u.derived->attr.alloc_comp)