aboutsummaryrefslogtreecommitdiff
path: root/gcc/fortran/trans-intrinsic.cc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/fortran/trans-intrinsic.cc')
-rw-r--r--gcc/fortran/trans-intrinsic.cc404
1 files changed, 203 insertions, 201 deletions
diff --git a/gcc/fortran/trans-intrinsic.cc b/gcc/fortran/trans-intrinsic.cc
index 41a1739..66da97b 100644
--- a/gcc/fortran/trans-intrinsic.cc
+++ b/gcc/fortran/trans-intrinsic.cc
@@ -42,6 +42,7 @@ along with GCC; see the file COPYING3. If not see
#include "dependency.h" /* For CAF array alias analysis. */
#include "attribs.h"
#include "realmpfr.h"
+#include "constructor.h"
/* Only for gfc_trans_assign and gfc_trans_pointer_assign. */
@@ -1667,31 +1668,59 @@ conv_expr_ref_to_caf_ref (stmtblock_t *block, gfc_expr *expr)
: NULL_TREE;
}
+static tree
+conv_shape_to_cst (gfc_expr *e)
+{
+ tree tmp = NULL;
+ for (int d = 0; d < e->rank; ++d)
+ {
+ if (!tmp)
+ tmp = gfc_conv_mpz_to_tree (e->shape[d], gfc_size_kind);
+ else
+ tmp = fold_build2 (MULT_EXPR, TREE_TYPE (tmp), tmp,
+ gfc_conv_mpz_to_tree (e->shape[d], gfc_size_kind));
+ }
+ return fold_convert (size_type_node, tmp);
+}
+
/* Get data from a remote coarray. */
static void
-gfc_conv_intrinsic_caf_get (gfc_se *se, gfc_expr *expr, tree lhs, tree lhs_kind,
- tree may_require_tmp, bool may_realloc,
- symbol_attribute *caf_attr)
+gfc_conv_intrinsic_caf_get (gfc_se *se, gfc_expr *expr, tree lhs,
+ bool may_realloc, symbol_attribute *caf_attr)
{
+ static int call_cnt = 0;
gfc_expr *array_expr, *tmp_stat;
gfc_se argse;
- tree caf_decl, token, offset, image_index, tmp;
- tree res_var, dst_var, type, kind, vec, stat;
- tree caf_reference;
+ tree caf_decl, token, image_index, tmp, res_var, type, stat, dest_size,
+ dest_data, opt_dest_desc, rget_index_tree, rget_data_tree, rget_data_size,
+ opt_src_desc, opt_src_charlen, opt_dest_charlen;
symbol_attribute caf_attr_store;
+ gfc_namespace *ns;
+ gfc_expr *rget_hash = expr->value.function.actual->next->expr,
+ *rget_fn_expr = expr->value.function.actual->next->next->expr;
+ gfc_symbol *gdata_sym
+ = rget_fn_expr->symtree->n.sym->formal->next->next->next->sym;
+ gfc_expr rget_data, rget_data_init, rget_index;
+ char *name;
+ gfc_symtree *data_st, *index_st;
+ gfc_constructor *con;
+ stmtblock_t blk;
gcc_assert (flag_coarray == GFC_FCOARRAY_LIB);
if (se->ss && se->ss->info->useflags)
{
- /* Access the previously obtained result. */
- gfc_conv_tmp_array_ref (se);
- return;
+ /* Access the previously obtained result. */
+ gfc_conv_tmp_array_ref (se);
+ return;
}
- /* If lhs is set, the CAF_GET intrinsic has already been stripped. */
- array_expr = (lhs == NULL_TREE) ? expr->value.function.actual->expr : expr;
+ array_expr = expr->value.function.actual->expr;
+ ns = array_expr->expr_type == EXPR_VARIABLE
+ && !array_expr->symtree->n.sym->attr.associate_var
+ ? array_expr->symtree->n.sym->ns
+ : gfc_current_ns;
type = gfc_typenode_for_spec (&array_expr->ts);
if (caf_attr == NULL)
@@ -1701,9 +1730,7 @@ gfc_conv_intrinsic_caf_get (gfc_se *se, gfc_expr *expr, tree lhs, tree lhs_kind,
}
res_var = lhs;
- dst_var = lhs;
- vec = null_pointer_node;
tmp_stat = gfc_find_stat_co (expr);
if (tmp_stat)
@@ -1718,198 +1745,172 @@ gfc_conv_intrinsic_caf_get (gfc_se *se, gfc_expr *expr, tree lhs, tree lhs_kind,
else
stat = null_pointer_node;
- /* Only use the new get_by_ref () where it is necessary. I.e., when the lhs
- is reallocatable or the right-hand side has allocatable components. */
- if (caf_attr->alloc_comp || caf_attr->pointer_comp || may_realloc)
- {
- /* Get using caf_get_by_ref. */
- caf_reference = conv_expr_ref_to_caf_ref (&se->pre, array_expr);
-
- if (caf_reference != NULL_TREE)
- {
- if (lhs == NULL_TREE)
- {
- if (array_expr->ts.type == BT_CHARACTER)
- gfc_init_se (&argse, NULL);
- if (array_expr->rank == 0)
- {
- symbol_attribute attr;
- gfc_clear_attr (&attr);
- if (array_expr->ts.type == BT_CHARACTER)
- {
- res_var = gfc_conv_string_tmp (se,
- build_pointer_type (type),
- array_expr->ts.u.cl->backend_decl);
- argse.string_length = array_expr->ts.u.cl->backend_decl;
- }
- else
- res_var = gfc_create_var (type, "caf_res");
- dst_var = gfc_conv_scalar_to_descriptor (se, res_var, attr);
- dst_var = gfc_build_addr_expr (NULL_TREE, dst_var);
- }
- else
- {
- /* Create temporary. */
- if (array_expr->ts.type == BT_CHARACTER)
- gfc_conv_expr_descriptor (&argse, array_expr);
- may_realloc = gfc_trans_create_temp_array (&se->pre,
- &se->post,
- se->ss, type,
- NULL_TREE, false,
- false, false,
- &array_expr->where)
- == NULL_TREE;
- res_var = se->ss->info->data.array.descriptor;
- dst_var = gfc_build_addr_expr (NULL_TREE, res_var);
- if (may_realloc)
- {
- tmp = gfc_conv_descriptor_data_get (res_var);
- tmp = gfc_deallocate_with_status (tmp, NULL_TREE,
- NULL_TREE, NULL_TREE,
- NULL_TREE, true,
- NULL,
- GFC_CAF_COARRAY_NOCOARRAY);
- gfc_add_expr_to_block (&se->post, tmp);
- }
- }
- }
-
- kind = build_int_cst (integer_type_node, expr->ts.kind);
- if (lhs_kind == NULL_TREE)
- lhs_kind = kind;
-
- caf_decl = gfc_get_tree_for_caf_expr (array_expr);
- if (TREE_CODE (TREE_TYPE (caf_decl)) == REFERENCE_TYPE)
- caf_decl = build_fold_indirect_ref_loc (input_location, caf_decl);
- image_index = gfc_caf_get_image_index (&se->pre, array_expr,
- caf_decl);
- gfc_get_caf_token_offset (se, &token, NULL, caf_decl, NULL,
- array_expr);
-
- /* No overlap possible as we have generated a temporary. */
- if (lhs == NULL_TREE)
- may_require_tmp = boolean_false_node;
-
- /* It guarantees memory consistency within the same segment. */
- tmp = gfc_build_string_const (strlen ("memory") + 1, "memory");
- tmp = build5_loc (input_location, ASM_EXPR, void_type_node,
- gfc_build_string_const (1, ""), NULL_TREE,
- NULL_TREE, tree_cons (NULL_TREE, tmp, NULL_TREE),
- NULL_TREE);
- ASM_VOLATILE_P (tmp) = 1;
- gfc_add_expr_to_block (&se->pre, tmp);
+ memset (&rget_data, 0, sizeof (gfc_expr));
+ gfc_clear_ts (&rget_data.ts);
+ rget_data.expr_type = EXPR_VARIABLE;
+ name = xasprintf ("__caf_rget_data_%d", call_cnt);
+ gcc_assert (!gfc_get_sym_tree (name, ns, &data_st, false));
+ name = xasprintf ("__caf_rget_index_%d", call_cnt);
+ ++call_cnt;
+ gcc_assert (!gfc_get_sym_tree (name, ns, &index_st, false));
+ free (name);
+ data_st->n.sym->attr.flavor = FL_VARIABLE;
+ data_st->n.sym->ts = gdata_sym->ts;
+ rget_data.symtree = data_st;
+ gfc_set_sym_referenced (rget_data.symtree->n.sym);
+ rget_data.ts = data_st->n.sym->ts;
+ gfc_commit_symbol (data_st->n.sym);
+
+ memset (&rget_data_init, 0, sizeof (gfc_expr));
+ gfc_clear_ts (&rget_data_init.ts);
+ rget_data_init.expr_type = EXPR_STRUCTURE;
+ rget_data_init.ts = rget_data.ts;
+ for (gfc_component *comp = rget_data.ts.u.derived->components; comp;
+ comp = comp->next)
+ {
+ con = gfc_constructor_get ();
+ con->expr = comp->initializer;
+ comp->initializer = NULL;
+ gfc_constructor_append (&rget_data_init.value.constructor, con);
+ }
+
+ index_st->n.sym->attr.flavor = FL_VARIABLE;
+ index_st->n.sym->attr.save = SAVE_EXPLICIT;
+ index_st->n.sym->value
+ = gfc_get_constant_expr (BT_INTEGER, gfc_default_integer_kind,
+ &gfc_current_locus);
+ mpz_init_set_si (index_st->n.sym->value->value.integer, -1);
+ index_st->n.sym->ts.type = BT_INTEGER;
+ index_st->n.sym->ts.kind = gfc_default_integer_kind;
+ gfc_set_sym_referenced (index_st->n.sym);
+ memset (&rget_index, 0, sizeof (gfc_expr));
+ gfc_clear_ts (&rget_index.ts);
+ rget_index.expr_type = EXPR_VARIABLE;
+ rget_index.symtree = index_st;
+ rget_index.ts = index_st->n.sym->ts;
+ gfc_commit_symbol (index_st->n.sym);
- tmp = build_call_expr_loc (input_location, gfor_fndecl_caf_get_by_ref,
- 10, token, image_index, dst_var,
- caf_reference, lhs_kind, kind,
- may_require_tmp,
- may_realloc ? boolean_true_node :
- boolean_false_node,
- stat, build_int_cst (integer_type_node,
- array_expr->ts.type));
+ gfc_init_se (&argse, NULL);
+ gfc_conv_expr (&argse, &rget_index);
+ gfc_add_block_to_block (&se->pre, &argse.pre);
+ rget_index_tree = argse.expr;
- gfc_add_expr_to_block (&se->pre, tmp);
+ gfc_init_se (&argse, NULL);
+ gfc_conv_expr (&argse, rget_hash);
- if (se->ss)
- gfc_advance_se_ss_chain (se);
+ gfc_init_block (&blk);
+ tmp = build_call_expr (gfor_fndecl_caf_get_remote_function_index, 1,
+ argse.expr);
- se->expr = res_var;
- if (array_expr->ts.type == BT_CHARACTER)
- se->string_length = argse.string_length;
+ gfc_add_modify (&blk, rget_index_tree, tmp);
+ gfc_add_expr_to_block (
+ &se->pre,
+ build3 (COND_EXPR, void_type_node,
+ gfc_likely (build2 (EQ_EXPR, logical_type_node, rget_index_tree,
+ build_int_cst (integer_type_node, -1)),
+ PRED_FIRST_MATCH),
+ gfc_finish_block (&blk), NULL_TREE));
- return;
- }
+ if (rget_data.ts.u.derived->components)
+ {
+ gfc_init_se (&argse, NULL);
+ gfc_conv_expr (&argse, &rget_data);
+ rget_data_tree = argse.expr;
+ gfc_add_expr_to_block (&se->pre,
+ gfc_trans_structure_assign (rget_data_tree,
+ &rget_data_init, true,
+ false));
+ gfc_constructor_free (rget_data_init.value.constructor);
+ rget_data_size = TREE_TYPE (rget_data_tree)->type_common.size_unit;
+ rget_data_tree = gfc_build_addr_expr (pvoid_type_node, rget_data_tree);
+ }
+ else
+ {
+ rget_data_tree = build_zero_cst (pvoid_type_node);
+ rget_data_size = build_zero_cst (size_type_node);
}
- gfc_init_se (&argse, NULL);
if (array_expr->rank == 0)
{
- symbol_attribute attr;
-
- gfc_clear_attr (&attr);
- gfc_conv_expr (&argse, array_expr);
-
- if (lhs == NULL_TREE)
+ res_var = gfc_create_var (type, "caf_res");
+ if (array_expr->ts.type == BT_CHARACTER)
{
- gfc_clear_attr (&attr);
- if (array_expr->ts.type == BT_CHARACTER)
- res_var = gfc_conv_string_tmp (se, build_pointer_type (type),
- argse.string_length);
- else
- res_var = gfc_create_var (type, "caf_res");
- dst_var = gfc_conv_scalar_to_descriptor (&argse, res_var, attr);
- dst_var = gfc_build_addr_expr (NULL_TREE, dst_var);
+ gfc_conv_string_length (array_expr->ts.u.cl, array_expr, &se->pre);
+ argse.string_length = array_expr->ts.u.cl->backend_decl;
+ opt_src_charlen = gfc_build_addr_expr (
+ NULL_TREE, gfc_trans_force_lval (&se->pre, argse.string_length));
+ dest_size = build_int_cstu (size_type_node, array_expr->ts.kind);
+ }
+ else
+ {
+ dest_size = res_var->typed.type->type_common.size_unit;
+ opt_src_charlen
+ = build_zero_cst (build_pointer_type (size_type_node));
}
- argse.expr = gfc_conv_scalar_to_descriptor (&argse, argse.expr, attr);
- argse.expr = gfc_build_addr_expr (NULL_TREE, argse.expr);
+ dest_data
+ = gfc_evaluate_now (gfc_build_addr_expr (NULL_TREE, res_var), &se->pre);
+ res_var = build_fold_indirect_ref (dest_data);
+ dest_data = gfc_build_addr_expr (pvoid_type_node, dest_data);
+ opt_dest_desc = build_zero_cst (pvoid_type_node);
}
else
{
- /* If has_vector, pass descriptor for whole array and the
- vector bounds separately. */
- gfc_array_ref *ar, ar2;
- bool has_vector = false;
-
- if (gfc_is_coindexed (expr) && gfc_has_vector_subscript (expr))
+ /* Create temporary. */
+ may_realloc = gfc_trans_create_temp_array (&se->pre, &se->post, se->ss,
+ type, NULL_TREE, false, false,
+ false, &array_expr->where)
+ == NULL_TREE;
+ res_var = se->ss->info->data.array.descriptor;
+ if (array_expr->ts.type == BT_CHARACTER)
{
- has_vector = true;
- ar = gfc_find_array_ref (expr);
- ar2 = *ar;
- memset (ar, '\0', sizeof (*ar));
- ar->as = ar2.as;
- ar->type = AR_FULL;
- }
- // TODO: Check whether argse.want_coarray = 1 can help with the below.
- gfc_conv_expr_descriptor (&argse, array_expr);
- /* Using gfc_conv_expr_descriptor, we only get the descriptor, but that
- has the wrong type if component references are done. */
- gfc_add_modify (&argse.pre, gfc_conv_descriptor_dtype (argse.expr),
- gfc_get_dtype_rank_type (has_vector ? ar2.dimen
- : array_expr->rank,
- type));
- if (has_vector)
- {
- vec = conv_caf_vector_subscript (&argse.pre, argse.expr, &ar2);
- *ar = ar2;
+ argse.string_length = array_expr->ts.u.cl->backend_decl;
+ opt_src_charlen = gfc_build_addr_expr (
+ NULL_TREE, gfc_trans_force_lval (&se->pre, argse.string_length));
+ dest_size = build_int_cstu (size_type_node, array_expr->ts.kind);
}
-
- if (lhs == NULL_TREE)
+ else
{
- /* Create temporary. */
- for (int n = 0; n < se->ss->loop->dimen; n++)
- if (se->loop->to[n] == NULL_TREE)
- {
- se->loop->from[n] = gfc_conv_descriptor_lbound_get (argse.expr,
- gfc_rank_cst[n]);
- se->loop->to[n] = gfc_conv_descriptor_ubound_get (argse.expr,
- gfc_rank_cst[n]);
- }
- gfc_trans_create_temp_array (&argse.pre, &argse.post, se->ss, type,
- NULL_TREE, false, true, false,
- &array_expr->where);
- res_var = se->ss->info->data.array.descriptor;
- dst_var = gfc_build_addr_expr (NULL_TREE, res_var);
- }
- argse.expr = gfc_build_addr_expr (NULL_TREE, argse.expr);
- }
-
- kind = build_int_cst (integer_type_node, expr->ts.kind);
- if (lhs_kind == NULL_TREE)
- lhs_kind = kind;
-
- gfc_add_block_to_block (&se->pre, &argse.pre);
- gfc_add_block_to_block (&se->post, &argse.post);
-
+ opt_src_charlen
+ = build_zero_cst (build_pointer_type (size_type_node));
+ dest_size = fold_build2 (
+ MULT_EXPR, size_type_node,
+ fold_convert (size_type_node,
+ array_expr->shape
+ ? conv_shape_to_cst (array_expr)
+ : gfc_conv_descriptor_size (res_var,
+ array_expr->rank)),
+ fold_convert (size_type_node,
+ gfc_conv_descriptor_span_get (res_var)));
+ }
+ opt_dest_desc = res_var;
+ dest_data = gfc_conv_descriptor_data_get (res_var);
+ opt_dest_desc = gfc_build_addr_expr (NULL_TREE, opt_dest_desc);
+ if (may_realloc)
+ {
+ tmp = gfc_conv_descriptor_data_get (res_var);
+ tmp = gfc_deallocate_with_status (tmp, NULL_TREE, NULL_TREE,
+ NULL_TREE, NULL_TREE, true, NULL,
+ GFC_CAF_COARRAY_NOCOARRAY);
+ gfc_add_expr_to_block (&se->post, tmp);
+ }
+ dest_data
+ = gfc_build_addr_expr (NULL_TREE,
+ gfc_trans_force_lval (&se->pre, dest_data));
+ }
+
+ opt_dest_charlen = opt_src_charlen;
caf_decl = gfc_get_tree_for_caf_expr (array_expr);
- if (POINTER_TYPE_P (TREE_TYPE (caf_decl)))
+ if (TREE_CODE (TREE_TYPE (caf_decl)) == REFERENCE_TYPE)
caf_decl = build_fold_indirect_ref_loc (input_location, caf_decl);
- image_index = gfc_caf_get_image_index (&se->pre, array_expr, caf_decl);
- gfc_get_caf_token_offset (se, &token, &offset, caf_decl, argse.expr,
- array_expr);
- /* No overlap possible as we have generated a temporary. */
- if (lhs == NULL_TREE)
- may_require_tmp = boolean_false_node;
+ if (!TYPE_LANG_SPECIFIC (TREE_TYPE (caf_decl))->rank
+ || GFC_ARRAY_TYPE_P (TREE_TYPE (caf_decl)))
+ opt_src_desc = build_zero_cst (pvoid_type_node);
+ else
+ opt_src_desc = gfc_build_addr_expr (pvoid_type_node, caf_decl);
+
+ image_index = gfc_caf_get_image_index (&se->pre, array_expr, caf_decl);
+ gfc_get_caf_token_offset (se, &token, NULL, caf_decl, NULL, array_expr);
/* It guarantees memory consistency within the same segment. */
tmp = gfc_build_string_const (strlen ("memory") + 1, "memory");
@@ -1919,9 +1920,12 @@ gfc_conv_intrinsic_caf_get (gfc_se *se, gfc_expr *expr, tree lhs, tree lhs_kind,
ASM_VOLATILE_P (tmp) = 1;
gfc_add_expr_to_block (&se->pre, tmp);
- tmp = build_call_expr_loc (input_location, gfor_fndecl_caf_get, 10,
- token, offset, image_index, argse.expr, vec,
- dst_var, kind, lhs_kind, may_require_tmp, stat);
+ tmp = build_call_expr_loc (
+ input_location, gfor_fndecl_caf_get_by_ct, 15, token, opt_src_desc,
+ opt_src_charlen, image_index, dest_size, dest_data, opt_dest_charlen,
+ opt_dest_desc, constant_boolean_node (may_realloc, boolean_type_node),
+ rget_index_tree, rget_data_tree, rget_data_size, stat, null_pointer_node,
+ null_pointer_node);
gfc_add_expr_to_block (&se->pre, tmp);
@@ -1931,6 +1935,8 @@ gfc_conv_intrinsic_caf_get (gfc_se *se, gfc_expr *expr, tree lhs, tree lhs_kind,
se->expr = res_var;
if (array_expr->ts.type == BT_CHARACTER)
se->string_length = argse.string_length;
+
+ return;
}
static bool
@@ -1995,8 +2001,9 @@ conv_caf_send (gfc_code *code) {
gfc_clear_attr (&attr);
gfc_conv_expr (&lhs_se, lhs_expr);
lhs_type = TREE_TYPE (lhs_se.expr);
- lhs_se.expr = gfc_conv_scalar_to_descriptor (&lhs_se, lhs_se.expr,
- attr);
+ if (lhs_is_coindexed)
+ lhs_se.expr = gfc_conv_scalar_to_descriptor (&lhs_se, lhs_se.expr,
+ attr);
lhs_se.expr = gfc_build_addr_expr (NULL_TREE, lhs_se.expr);
}
}
@@ -2174,17 +2181,13 @@ conv_caf_send (gfc_code *code) {
lhs_may_realloc = lhs_may_realloc
&& gfc_full_array_ref_p (lhs_expr->ref, NULL);
gfc_add_block_to_block (&block, &lhs_se.pre);
- gfc_conv_intrinsic_caf_get (&rhs_se, rhs_expr, lhs_se.expr, lhs_kind,
- may_require_tmp, lhs_may_realloc,
- &rhs_caf_attr);
+ gfc_conv_intrinsic_caf_get (&rhs_se, code->ext.actual->next->expr,
+ lhs_se.expr, lhs_may_realloc, &rhs_caf_attr);
gfc_add_block_to_block (&block, &rhs_se.pre);
gfc_add_block_to_block (&block, &rhs_se.post);
gfc_add_block_to_block (&block, &lhs_se.post);
return gfc_finish_block (&block);
}
- else if (rhs_expr->expr_type == EXPR_FUNCTION
- && rhs_expr->value.function.isym->id == GFC_ISYM_CAF_GET)
- rhs_expr = rhs_expr->value.function.actual->expr;
gfc_add_block_to_block (&block, &lhs_se.pre);
@@ -2301,8 +2304,8 @@ conv_caf_send (gfc_code *code) {
{
tree reference, dst_realloc;
reference = conv_expr_ref_to_caf_ref (&block, lhs_expr);
- dst_realloc = lhs_caf_attr.allocatable ? boolean_true_node
- : boolean_false_node;
+ dst_realloc
+ = lhs_caf_attr.allocatable ? boolean_true_node : boolean_false_node;
tmp = build_call_expr_loc (input_location,
gfor_fndecl_caf_send_by_ref,
10, token, image_index, rhs_se.expr,
@@ -2310,7 +2313,7 @@ conv_caf_send (gfc_code *code) {
may_require_tmp, dst_realloc, src_stat,
build_int_cst (integer_type_node,
lhs_expr->ts.type));
- }
+ }
else
tmp = build_call_expr_loc (input_location, gfor_fndecl_caf_send, 11,
token, offset, image_index, lhs_se.expr, vec,
@@ -11290,8 +11293,7 @@ gfc_conv_intrinsic_function (gfc_se * se, gfc_expr * expr)
break;
case GFC_ISYM_CAF_GET:
- gfc_conv_intrinsic_caf_get (se, expr, NULL_TREE, NULL_TREE, NULL_TREE,
- false, NULL);
+ gfc_conv_intrinsic_caf_get (se, expr, NULL_TREE, false, NULL);
break;
case GFC_ISYM_CMPLX: