forked from OERV-TOOLCHAIN/gcc-rva23
gcc/fortran/ChangeLog: * coarray.cc (check_add_new_component): Treat pure and elemental intrinsic functions the same as non-intrinsic ones. (create_caf_add_data_parameter_type): Fix front-end memleaks. * trans-intrinsic.cc (conv_caf_func_index): Likewise.
1532 lines
45 KiB
C++
1532 lines
45 KiB
C++
/* Rewrite the expression tree for coarrays.
|
|
Copyright (C) 2010-2025 Free Software Foundation, Inc.
|
|
Contributed by Andre Vehreschild.
|
|
|
|
This file is part of GCC.
|
|
|
|
GCC is free software; you can redistribute it and/or modify it under
|
|
the terms of the GNU General Public License as published by the Free
|
|
Software Foundation; either version 3, or (at your option) any later
|
|
version.
|
|
|
|
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with GCC; see the file COPYING3. If not see
|
|
<http://www.gnu.org/licenses/>. */
|
|
|
|
/* Rewrite the expression for coarrays where needed:
|
|
- coarray indexing operations need the indexing expression put into a
|
|
routine callable on the remote image
|
|
|
|
This rewriter is meant to used for non-optimisational expression tree
|
|
rewrites. When implementing early optimisation it is recommended to
|
|
do this in frontend-passes.cc.
|
|
*/
|
|
|
|
#include "config.h"
|
|
#include "system.h"
|
|
#include "coretypes.h"
|
|
#include "options.h"
|
|
#include "bitmap.h"
|
|
#include "gfortran.h"
|
|
|
|
/* The code tree element that is currently processed. */
|
|
static gfc_code **current_code;
|
|
|
|
/* Code that is inserted into the current caf_accessor at the beginning. */
|
|
static gfc_code *caf_accessor_prepend = nullptr;
|
|
|
|
static bool caf_on_lhs = false;
|
|
|
|
static int caf_sym_cnt = 0;
|
|
|
|
static gfc_array_spec *
|
|
get_arrayspec_from_expr (gfc_expr *expr)
|
|
{
|
|
gfc_array_spec *src_as, *dst_as = NULL;
|
|
gfc_ref *ref;
|
|
gfc_array_ref mod_src_ar;
|
|
int dst_rank = 0;
|
|
|
|
if (expr->rank == 0)
|
|
return NULL;
|
|
|
|
if (expr->expr_type == EXPR_FUNCTION)
|
|
return gfc_copy_array_spec (expr->symtree->n.sym->as);
|
|
|
|
/* Follow any component references. */
|
|
if (expr->expr_type == EXPR_VARIABLE || expr->expr_type == EXPR_CONSTANT)
|
|
{
|
|
if (expr->symtree)
|
|
src_as = expr->symtree->n.sym->as;
|
|
else
|
|
src_as = NULL;
|
|
|
|
for (ref = expr->ref; ref; ref = ref->next)
|
|
{
|
|
switch (ref->type)
|
|
{
|
|
case REF_COMPONENT:
|
|
src_as = ref->u.c.component->as;
|
|
continue;
|
|
|
|
case REF_SUBSTRING:
|
|
case REF_INQUIRY:
|
|
continue;
|
|
|
|
case REF_ARRAY:
|
|
switch (ref->u.ar.type)
|
|
{
|
|
case AR_ELEMENT:
|
|
src_as = NULL;
|
|
break;
|
|
case AR_SECTION:
|
|
{
|
|
if (!dst_as)
|
|
dst_as = gfc_get_array_spec ();
|
|
memset (&mod_src_ar, 0, sizeof (gfc_array_ref));
|
|
mod_src_ar = ref->u.ar;
|
|
for (int dim = 0; dim < src_as->rank; ++dim)
|
|
{
|
|
switch (ref->u.ar.dimen_type[dim])
|
|
{
|
|
case DIMEN_ELEMENT:
|
|
gfc_free_expr (mod_src_ar.start[dim]);
|
|
mod_src_ar.start[dim] = NULL;
|
|
break;
|
|
case DIMEN_RANGE:
|
|
dst_as->lower[dst_rank]
|
|
= gfc_copy_expr (ref->u.ar.start[dim]);
|
|
mod_src_ar.start[dst_rank]
|
|
= gfc_copy_expr (ref->u.ar.start[dim]);
|
|
if (ref->u.ar.end[dim])
|
|
{
|
|
dst_as->upper[dst_rank]
|
|
= gfc_copy_expr (ref->u.ar.end[dim]);
|
|
mod_src_ar.end[dst_rank] = ref->u.ar.end[dim];
|
|
mod_src_ar.stride[dst_rank]
|
|
= ref->u.ar.stride[dim];
|
|
}
|
|
else
|
|
dst_as->upper[dst_rank]
|
|
= gfc_copy_expr (ref->u.ar.as->upper[dim]);
|
|
++dst_rank;
|
|
break;
|
|
case DIMEN_STAR:
|
|
dst_as->lower[dst_rank]
|
|
= gfc_copy_expr (ref->u.ar.as->lower[dim]);
|
|
mod_src_ar.start[dst_rank]
|
|
= gfc_copy_expr (ref->u.ar.start[dim]);
|
|
if (ref->u.ar.as->upper[dim])
|
|
{
|
|
dst_as->upper[dst_rank]
|
|
= gfc_copy_expr (ref->u.ar.as->upper[dim]);
|
|
mod_src_ar.end[dst_rank] = ref->u.ar.end[dim];
|
|
mod_src_ar.stride[dst_rank]
|
|
= ref->u.ar.stride[dim];
|
|
}
|
|
++dst_rank;
|
|
break;
|
|
case DIMEN_VECTOR:
|
|
dst_as->lower[dst_rank]
|
|
= gfc_get_constant_expr (BT_INTEGER,
|
|
gfc_index_integer_kind,
|
|
&expr->where);
|
|
mpz_set_ui (dst_as->lower[dst_rank]->value.integer,
|
|
1);
|
|
mod_src_ar.start[dst_rank]
|
|
= gfc_copy_expr (ref->u.ar.start[dim]);
|
|
dst_as->upper[dst_rank]
|
|
= gfc_get_constant_expr (BT_INTEGER,
|
|
gfc_index_integer_kind,
|
|
&expr->where);
|
|
mpz_set (dst_as->upper[dst_rank]->value.integer,
|
|
ref->u.ar.start[dim]->shape[0]);
|
|
++dst_rank;
|
|
break;
|
|
case DIMEN_THIS_IMAGE:
|
|
case DIMEN_UNKNOWN:
|
|
gcc_unreachable ();
|
|
}
|
|
if (ref->u.ar.dimen_type[dim] != DIMEN_ELEMENT)
|
|
mod_src_ar.dimen_type[dst_rank]
|
|
= ref->u.ar.dimen_type[dim];
|
|
}
|
|
dst_as->rank = dst_rank;
|
|
dst_as->type = AS_EXPLICIT;
|
|
ref->u.ar = mod_src_ar;
|
|
ref->u.ar.dimen = dst_rank;
|
|
break;
|
|
|
|
case AR_UNKNOWN:
|
|
src_as = NULL;
|
|
break;
|
|
|
|
case AR_FULL:
|
|
if (dst_as)
|
|
/* Prevent memory loss. */
|
|
gfc_free_array_spec (dst_as);
|
|
dst_as = gfc_copy_array_spec (src_as);
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
src_as = NULL;
|
|
|
|
return dst_as;
|
|
}
|
|
|
|
static void
|
|
remove_coarray_from_derived_type (gfc_symbol *base, gfc_namespace *ns,
|
|
gfc_array_spec *src_as = NULL)
|
|
{
|
|
gfc_symbol *derived;
|
|
gfc_symbol *src_derived = base->ts.u.derived;
|
|
|
|
if (!src_as)
|
|
src_as = src_derived->as;
|
|
gfc_get_symbol (src_derived->name, ns, &derived);
|
|
derived->attr.flavor = FL_DERIVED;
|
|
derived->attr.alloc_comp = src_derived->attr.alloc_comp;
|
|
if (src_as && src_as->rank != 0)
|
|
{
|
|
base->attr.dimension = 1;
|
|
base->as = gfc_copy_array_spec (src_as);
|
|
base->as->corank = 0;
|
|
}
|
|
for (gfc_component *p = NULL, *c = src_derived->components; c; c = c->next)
|
|
{
|
|
gfc_component *n = gfc_get_component ();
|
|
*n = *c;
|
|
if (n->as)
|
|
n->as = gfc_copy_array_spec (c->as);
|
|
n->backend_decl = NULL;
|
|
n->initializer = NULL;
|
|
n->param_list = NULL;
|
|
if (p)
|
|
p->next = n;
|
|
else
|
|
derived->components = n;
|
|
|
|
p = n;
|
|
}
|
|
derived->declared_at = base->declared_at;
|
|
gfc_set_sym_referenced (derived);
|
|
gfc_commit_symbol (derived);
|
|
base->ts.u.derived = derived;
|
|
gfc_commit_symbol (base);
|
|
}
|
|
|
|
static void
|
|
convert_coarray_class_to_derived_type (gfc_symbol *base, gfc_namespace *ns)
|
|
{
|
|
gfc_symbol *src_derived = CLASS_DATA (base)->ts.u.derived;
|
|
gfc_array_spec *src_as = CLASS_DATA (base)->as;
|
|
const bool attr_allocatable
|
|
= src_as && src_as->rank && src_as->type == AS_DEFERRED;
|
|
|
|
base->ts.type = BT_DERIVED;
|
|
base->ts.u.derived = src_derived;
|
|
|
|
remove_coarray_from_derived_type (base, ns, src_as);
|
|
|
|
base->attr.allocatable = attr_allocatable;
|
|
base->attr.pointer = 0; // Ensure, that it is no pointer.
|
|
}
|
|
|
|
static void
|
|
move_coarray_ref (gfc_ref **from, gfc_expr *expr)
|
|
{
|
|
int i;
|
|
gfc_ref *to = expr->ref;
|
|
for (; to && to->next; to = to->next)
|
|
;
|
|
|
|
if (!to)
|
|
{
|
|
expr->ref = gfc_get_ref ();
|
|
to = expr->ref;
|
|
to->type = REF_ARRAY;
|
|
}
|
|
gcc_assert (to->type == REF_ARRAY);
|
|
to->u.ar.as = gfc_copy_array_spec ((*from)->u.ar.as);
|
|
to->u.ar.codimen = (*from)->u.ar.codimen;
|
|
to->u.ar.dimen = (*from)->u.ar.dimen;
|
|
to->u.ar.type = AR_FULL;
|
|
to->u.ar.stat = (*from)->u.ar.stat;
|
|
(*from)->u.ar.stat = nullptr;
|
|
to->u.ar.team = (*from)->u.ar.team;
|
|
(*from)->u.ar.team = nullptr;
|
|
to->u.ar.team_type = (*from)->u.ar.team_type;
|
|
(*from)->u.ar.team_type = TEAM_UNSET;
|
|
for (i = 0; i < to->u.ar.dimen; ++i)
|
|
{
|
|
to->u.ar.start[i] = nullptr;
|
|
to->u.ar.end[i] = nullptr;
|
|
to->u.ar.stride[i] = nullptr;
|
|
}
|
|
for (i = (*from)->u.ar.dimen; i < (*from)->u.ar.dimen + (*from)->u.ar.codimen;
|
|
++i)
|
|
{
|
|
to->u.ar.dimen_type[i] = (*from)->u.ar.dimen_type[i];
|
|
to->u.ar.start[i] = (*from)->u.ar.start[i];
|
|
(*from)->u.ar.start[i] = nullptr;
|
|
to->u.ar.end[i] = (*from)->u.ar.end[i];
|
|
(*from)->u.ar.end[i] = nullptr;
|
|
to->u.ar.stride[i] = (*from)->u.ar.stride[i];
|
|
(*from)->u.ar.stride[i] = nullptr;
|
|
}
|
|
(*from)->u.ar.codimen = 0;
|
|
if ((*from)->u.ar.dimen == 0)
|
|
{
|
|
gfc_ref *nref = (*from)->next;
|
|
(*from)->next = nullptr;
|
|
gfc_free_ref_list (*from);
|
|
*from = nref;
|
|
}
|
|
}
|
|
|
|
static void
|
|
fixup_comp_refs (gfc_expr *expr)
|
|
{
|
|
bool class_ref = expr->symtree->n.sym->ts.type == BT_CLASS;
|
|
gfc_symbol *type
|
|
= expr->symtree->n.sym->ts.type == BT_DERIVED
|
|
? expr->symtree->n.sym->ts.u.derived
|
|
: (class_ref ? CLASS_DATA (expr->symtree->n.sym)->ts.u.derived
|
|
: nullptr);
|
|
if (!type)
|
|
return;
|
|
gfc_ref **pref = &(expr->ref);
|
|
for (gfc_ref *ref = expr->ref; ref && type;)
|
|
{
|
|
switch (ref->type)
|
|
{
|
|
case REF_COMPONENT:
|
|
gfc_find_component (type, ref->u.c.component->name, false, true,
|
|
pref);
|
|
if (!*pref)
|
|
{
|
|
/* This happens when there were errors previously. Just don't
|
|
crash. */
|
|
ref = nullptr;
|
|
break;
|
|
}
|
|
if (class_ref)
|
|
/* Link to the class type to allow for derived type resolution. */
|
|
(*pref)->u.c.sym = ref->u.c.sym;
|
|
(*pref)->next = ref->next;
|
|
ref->next = NULL;
|
|
gfc_free_ref_list (ref);
|
|
ref = (*pref)->next;
|
|
type = (*pref)->u.c.component->ts.type == BT_DERIVED
|
|
? (*pref)->u.c.component->ts.u.derived
|
|
: ((*pref)->u.c.component->ts.type == BT_CLASS
|
|
? CLASS_DATA ((*pref)->u.c.component)->ts.u.derived
|
|
: nullptr);
|
|
pref = &(*pref)->next;
|
|
break;
|
|
case REF_ARRAY:
|
|
pref = &ref->next;
|
|
ref = ref->next;
|
|
break;
|
|
default:
|
|
gcc_unreachable ();
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
split_expr_at_caf_ref (gfc_expr *expr, gfc_namespace *ns,
|
|
gfc_expr **post_caf_ref_expr, bool for_send)
|
|
{
|
|
gfc_ref *caf_ref = NULL;
|
|
gfc_symtree *st;
|
|
gfc_symbol *base;
|
|
gfc_typespec *caf_ts;
|
|
bool created;
|
|
|
|
gcc_assert (expr->expr_type == EXPR_VARIABLE);
|
|
caf_ts = &expr->symtree->n.sym->ts;
|
|
if (!(expr->symtree->n.sym->ts.type == BT_CLASS
|
|
? CLASS_DATA (expr->symtree->n.sym)->attr.codimension
|
|
: expr->symtree->n.sym->attr.codimension))
|
|
{
|
|
/* The coarray is in some component. Find it. */
|
|
caf_ref = expr->ref;
|
|
while (caf_ref)
|
|
{
|
|
if (caf_ref->type == REF_ARRAY && caf_ref->u.ar.codimen != 0)
|
|
break;
|
|
if (caf_ref->type == REF_COMPONENT)
|
|
caf_ts = &caf_ref->u.c.component->ts;
|
|
caf_ref = caf_ref->next;
|
|
}
|
|
}
|
|
|
|
created = !gfc_get_sym_tree (!caf_ref ? expr->symtree->name : "base", ns, &st,
|
|
false);
|
|
gcc_assert (created);
|
|
st->n.sym->attr.flavor = FL_PARAMETER;
|
|
st->n.sym->attr.dummy = 1;
|
|
st->n.sym->attr.intent = INTENT_IN;
|
|
st->n.sym->ts = *caf_ts;
|
|
st->n.sym->declared_at = expr->where;
|
|
|
|
*post_caf_ref_expr = gfc_get_variable_expr (st);
|
|
(*post_caf_ref_expr)->where = expr->where;
|
|
base = (*post_caf_ref_expr)->symtree->n.sym;
|
|
|
|
if (!caf_ref)
|
|
{
|
|
(*post_caf_ref_expr)->ref = gfc_get_ref ();
|
|
*(*post_caf_ref_expr)->ref = *expr->ref;
|
|
expr->ref = nullptr;
|
|
move_coarray_ref (&(*post_caf_ref_expr)->ref, expr);
|
|
fixup_comp_refs (expr);
|
|
|
|
if (expr->symtree->n.sym->attr.dimension)
|
|
{
|
|
base->as = gfc_copy_array_spec (expr->symtree->n.sym->as);
|
|
base->as->corank = 0;
|
|
base->attr.dimension = 1;
|
|
base->attr.allocatable = expr->symtree->n.sym->attr.allocatable;
|
|
base->attr.pointer = expr->symtree->n.sym->attr.pointer
|
|
|| expr->symtree->n.sym->attr.associate_var;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
(*post_caf_ref_expr)->ref = gfc_get_ref ();
|
|
*(*post_caf_ref_expr)->ref = *caf_ref;
|
|
caf_ref->next = nullptr;
|
|
move_coarray_ref (&(*post_caf_ref_expr)->ref, expr);
|
|
fixup_comp_refs (expr);
|
|
|
|
if (caf_ref && caf_ref->u.ar.dimen)
|
|
{
|
|
base->as = gfc_copy_array_spec (caf_ref->u.ar.as);
|
|
base->as->corank = 0;
|
|
base->attr.dimension = 1;
|
|
base->attr.allocatable = caf_ref->u.ar.as->type != AS_EXPLICIT;
|
|
}
|
|
base->ts = *caf_ts;
|
|
}
|
|
(*post_caf_ref_expr)->ts = expr->ts;
|
|
if (base->ts.type == BT_CHARACTER)
|
|
{
|
|
base->ts.u.cl = gfc_get_charlen ();
|
|
*base->ts.u.cl = *(caf_ts->u.cl);
|
|
base->ts.deferred = 1;
|
|
base->ts.u.cl->length = nullptr;
|
|
}
|
|
else if (base->ts.type == BT_DERIVED)
|
|
remove_coarray_from_derived_type (base, ns);
|
|
else if (base->ts.type == BT_CLASS)
|
|
convert_coarray_class_to_derived_type (base, ns);
|
|
|
|
memset (&(*post_caf_ref_expr)->ts, 0, sizeof (gfc_typespec));
|
|
gfc_resolve_expr (*post_caf_ref_expr);
|
|
(*post_caf_ref_expr)->corank = 0;
|
|
gfc_expression_rank (*post_caf_ref_expr);
|
|
if (for_send)
|
|
gfc_expression_rank (expr);
|
|
else
|
|
expr->rank = (*post_caf_ref_expr)->rank;
|
|
}
|
|
|
|
static void add_caf_get_from_remote (gfc_expr *e);
|
|
|
|
static gfc_component *
|
|
find_comp (gfc_symbol *type, gfc_expr *e, int *cnt, const bool is_var)
|
|
{
|
|
char *temp_name = nullptr;
|
|
gfc_component *comp = type->components;
|
|
|
|
/* For variables:
|
|
- look up same name or create new
|
|
all else:
|
|
- create unique new
|
|
*/
|
|
if (is_var)
|
|
{
|
|
++(*cnt);
|
|
free (temp_name);
|
|
temp_name = xasprintf ("caf_temp_%s_%d", e->symtree->name, *cnt);
|
|
while (comp && strcmp (comp->name, temp_name) != 0)
|
|
comp = comp->next;
|
|
if (!comp)
|
|
{
|
|
const bool added = gfc_add_component (type, temp_name, &comp);
|
|
gcc_assert (added);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
int r = -1;
|
|
/* Components are always appended, i.e., when searching to add a unique
|
|
one just iterating forward is sufficient. */
|
|
do
|
|
{
|
|
++(*cnt);
|
|
free (temp_name);
|
|
temp_name = xasprintf ("caf_temp_%s_%d", e->symtree->name, *cnt);
|
|
|
|
while (comp && (r = strcmp (comp->name, temp_name)) <= 0)
|
|
comp = comp->next;
|
|
}
|
|
while (comp && r <= 0);
|
|
{
|
|
const bool added = gfc_add_component (type, temp_name, &comp);
|
|
gcc_assert (added);
|
|
}
|
|
}
|
|
|
|
comp->loc = e->where;
|
|
comp->ts = e->ts;
|
|
free (temp_name);
|
|
|
|
return comp;
|
|
}
|
|
|
|
static void
|
|
check_add_new_comp_handle_array (gfc_expr *e, gfc_symbol *type,
|
|
gfc_symbol *add_data)
|
|
{
|
|
gfc_component *comp;
|
|
static int cnt = -1;
|
|
gfc_symtree *caller_image;
|
|
gfc_code *pre_code = caf_accessor_prepend;
|
|
bool static_array_or_scalar = true;
|
|
symbol_attribute e_attr = gfc_expr_attr (e);
|
|
|
|
gfc_free_shape (&e->shape, e->rank);
|
|
|
|
/* When already code to prepend into the accessor exists, go to
|
|
the end of the chain. */
|
|
for (; pre_code && pre_code->next; pre_code = pre_code->next)
|
|
;
|
|
|
|
comp = find_comp (type, e, &cnt,
|
|
e->symtree->n.sym->attr.flavor == FL_VARIABLE
|
|
|| e->symtree->n.sym->attr.flavor == FL_PARAMETER);
|
|
|
|
if (e->expr_type == EXPR_FUNCTION
|
|
|| (e->expr_type == EXPR_VARIABLE && e_attr.dimension
|
|
&& e_attr.allocatable))
|
|
{
|
|
gfc_code *code;
|
|
gfc_symtree *st;
|
|
const bool created
|
|
= !gfc_get_sym_tree (comp->name, gfc_current_ns, &st, false, &e->where);
|
|
gcc_assert (created);
|
|
|
|
st->n.sym->ts = e->ts;
|
|
gfc_set_sym_referenced (st->n.sym);
|
|
code = gfc_get_code (EXEC_ASSIGN);
|
|
code->loc = e->where;
|
|
code->expr1 = gfc_get_variable_expr (st);
|
|
code->expr2 = XCNEW (gfc_expr);
|
|
*(code->expr2) = *e;
|
|
code->next = *current_code;
|
|
*current_code = code;
|
|
|
|
if (e_attr.dimension)
|
|
{
|
|
gfc_array_spec *as = get_arrayspec_from_expr (e);
|
|
static_array_or_scalar = gfc_is_compile_time_shape (as);
|
|
|
|
comp->attr.dimension = 1;
|
|
st->n.sym->attr.dimension = 1;
|
|
st->n.sym->as = as;
|
|
|
|
if (!static_array_or_scalar)
|
|
{
|
|
comp->attr.allocatable = 1;
|
|
st->n.sym->attr.allocatable = 1;
|
|
}
|
|
code->expr1->rank = as->rank;
|
|
gfc_add_full_array_ref (code->expr1, gfc_copy_array_spec (as));
|
|
comp->as = gfc_copy_array_spec (as);
|
|
}
|
|
|
|
gfc_expression_rank (code->expr1);
|
|
comp->initializer = gfc_get_variable_expr (st);
|
|
gfc_commit_symbol (st->n.sym);
|
|
}
|
|
else
|
|
{
|
|
comp->initializer = gfc_copy_expr (e);
|
|
if (e_attr.dimension && e->rank)
|
|
{
|
|
comp->attr.dimension = 1;
|
|
comp->as = get_arrayspec_from_expr (e);
|
|
}
|
|
}
|
|
comp->initializer->where = e->where;
|
|
comp->attr.access = ACCESS_PRIVATE;
|
|
memset (e, 0, sizeof (gfc_expr));
|
|
e->ts = comp->initializer->ts;
|
|
e->expr_type = EXPR_VARIABLE;
|
|
e->where = comp->initializer->where;
|
|
|
|
if (comp->as && comp->as->rank)
|
|
{
|
|
if (static_array_or_scalar)
|
|
{
|
|
e->ref = gfc_get_ref ();
|
|
e->ref->type = REF_ARRAY;
|
|
e->ref->u.ar.as = gfc_copy_array_spec (add_data->as);
|
|
e->ref->u.ar.codimen = 1;
|
|
e->ref->u.ar.dimen_type[0] = DIMEN_THIS_IMAGE;
|
|
}
|
|
else
|
|
{
|
|
gfc_code *c;
|
|
gfc_symtree *lv, *ad;
|
|
bool created = !gfc_get_sym_tree (comp->name, add_data->ns, &lv,
|
|
false, &e->where);
|
|
gcc_assert (created);
|
|
|
|
lv->n.sym->ts = e->ts;
|
|
lv->n.sym->attr.dimension = 1;
|
|
lv->n.sym->attr.allocatable = 1;
|
|
lv->n.sym->attr.flavor = FL_VARIABLE;
|
|
lv->n.sym->as = gfc_copy_array_spec (comp->as);
|
|
gfc_set_sym_referenced (lv->n.sym);
|
|
gfc_commit_symbol (lv->n.sym);
|
|
c = gfc_get_code (EXEC_ASSIGN);
|
|
c->loc = e->where;
|
|
c->expr1 = gfc_get_variable_expr (lv);
|
|
c->expr1->where = e->where;
|
|
|
|
created = !gfc_find_sym_tree (add_data->name, add_data->ns, 0, &ad);
|
|
gcc_assert (created);
|
|
c->expr2 = gfc_get_variable_expr (ad);
|
|
c->expr2->where = e->where;
|
|
c->expr2->ts = comp->initializer->ts;
|
|
c->expr2->ref = gfc_get_ref ();
|
|
c->expr2->ref->type = REF_ARRAY;
|
|
c->expr2->ref->u.ar.as = gfc_copy_array_spec (add_data->as);
|
|
c->expr2->ref->u.ar.codimen = 1;
|
|
c->expr2->ref->u.ar.dimen_type[0] = DIMEN_ELEMENT;
|
|
caller_image
|
|
= gfc_find_symtree_in_proc ("caller_image", add_data->ns);
|
|
gcc_assert (caller_image);
|
|
c->expr2->ref->u.ar.start[0] = gfc_get_variable_expr (caller_image);
|
|
c->expr2->ref->u.ar.start[0]->where = e->where;
|
|
created = gfc_find_component (ad->n.sym->ts.u.derived, comp->name,
|
|
false, true, &c->expr2->ref->next)
|
|
!= nullptr;
|
|
gcc_assert (created);
|
|
c->expr2->rank = comp->as->rank;
|
|
gfc_add_full_array_ref (c->expr2, gfc_copy_array_spec (comp->as));
|
|
gfc_set_sym_referenced (ad->n.sym);
|
|
gfc_commit_symbol (ad->n.sym);
|
|
if (pre_code)
|
|
pre_code->next = c;
|
|
else
|
|
caf_accessor_prepend = c;
|
|
add_caf_get_from_remote (c->expr2);
|
|
|
|
e->symtree = lv;
|
|
gfc_expression_rank (e);
|
|
gfc_add_full_array_ref (e, gfc_copy_array_spec (comp->as));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
e->ref = gfc_get_ref ();
|
|
e->ref->type = REF_ARRAY;
|
|
e->ref->u.ar.as = gfc_copy_array_spec (add_data->as);
|
|
e->ref->u.ar.codimen = 1;
|
|
e->ref->u.ar.dimen_type[0] = DIMEN_THIS_IMAGE;
|
|
}
|
|
|
|
if (static_array_or_scalar)
|
|
{
|
|
const bool created
|
|
= gfc_find_component (add_data->ts.u.derived, comp->name, false, true,
|
|
&e->ref);
|
|
gcc_assert (created);
|
|
e->symtree = gfc_find_symtree (add_data->ns->sym_root, add_data->name);
|
|
gcc_assert (e->symtree);
|
|
if (IS_CLASS_ARRAY (e->ref->u.c.component)
|
|
|| e->ref->u.c.component->attr.dimension)
|
|
{
|
|
gfc_add_full_array_ref (e, e->ref->u.c.component->ts.type == BT_CLASS
|
|
? CLASS_DATA (e->ref->u.c.component)->as
|
|
: e->ref->u.c.component->as);
|
|
e->ref->next->u.ar.dimen
|
|
= e->ref->u.c.component->ts.type == BT_CLASS
|
|
? CLASS_DATA (e->ref->u.c.component)->as->rank
|
|
: e->ref->u.c.component->as->rank;
|
|
}
|
|
gfc_expression_rank (e);
|
|
}
|
|
}
|
|
|
|
static void
|
|
check_add_new_component (gfc_symbol *type, gfc_expr *e, gfc_symbol *add_data)
|
|
{
|
|
if (e)
|
|
{
|
|
switch (e->expr_type)
|
|
{
|
|
case EXPR_CONSTANT:
|
|
case EXPR_NULL:
|
|
break;
|
|
case EXPR_OP:
|
|
check_add_new_component (type, e->value.op.op1, add_data);
|
|
if (e->value.op.op2)
|
|
check_add_new_component (type, e->value.op.op2, add_data);
|
|
break;
|
|
case EXPR_COMPCALL:
|
|
for (gfc_actual_arglist *actual = e->value.compcall.actual; actual;
|
|
actual = actual->next)
|
|
check_add_new_component (type, actual->expr, add_data);
|
|
break;
|
|
case EXPR_FUNCTION:
|
|
if (!e->symtree->n.sym->attr.pure
|
|
&& !e->symtree->n.sym->attr.elemental
|
|
&& !(e->value.function.isym
|
|
&& (e->value.function.isym->pure
|
|
|| e->value.function.isym->elemental)))
|
|
/* Treat non-pure/non-elemental functions. */
|
|
check_add_new_comp_handle_array (e, type, add_data);
|
|
else
|
|
for (gfc_actual_arglist *actual = e->value.function.actual; actual;
|
|
actual = actual->next)
|
|
check_add_new_component (type, actual->expr, add_data);
|
|
break;
|
|
case EXPR_VARIABLE:
|
|
check_add_new_comp_handle_array (e, type, add_data);
|
|
break;
|
|
case EXPR_ARRAY:
|
|
case EXPR_PPC:
|
|
case EXPR_STRUCTURE:
|
|
case EXPR_SUBSTRING:
|
|
gcc_unreachable ();
|
|
default:;
|
|
}
|
|
}
|
|
}
|
|
|
|
static gfc_symbol *
|
|
create_caf_add_data_parameter_type (gfc_expr *expr, gfc_namespace *ns,
|
|
gfc_symbol *add_data)
|
|
{
|
|
static int type_cnt = 0;
|
|
char tname[GFC_MAX_SYMBOL_LEN + 1];
|
|
char *name;
|
|
gfc_symbol *type;
|
|
|
|
gcc_assert (expr->expr_type == EXPR_VARIABLE);
|
|
|
|
strcpy (tname, expr->symtree->name);
|
|
name = xasprintf ("@_caf_add_data_t_%s_%d", tname, ++type_cnt);
|
|
gfc_get_symbol (name, ns, &type);
|
|
|
|
type->attr.flavor = FL_DERIVED;
|
|
add_data->ts.u.derived = type;
|
|
add_data->attr.codimension = 1;
|
|
add_data->as = gfc_get_array_spec ();
|
|
add_data->as->corank = 1;
|
|
add_data->as->type = AS_EXPLICIT;
|
|
add_data->as->cotype = AS_DEFERRED;
|
|
add_data->as->lower[0]
|
|
= gfc_get_constant_expr (BT_INTEGER, gfc_default_integer_kind,
|
|
&expr->where);
|
|
mpz_set_si (add_data->as->lower[0]->value.integer, 1);
|
|
|
|
for (gfc_ref *ref = expr->ref; ref; ref = ref->next)
|
|
{
|
|
if (ref->type == REF_ARRAY)
|
|
{
|
|
gfc_array_ref *ar = &ref->u.ar;
|
|
for (int i = 0; i < ar->dimen; ++i)
|
|
{
|
|
check_add_new_component (type, ar->start[i], add_data);
|
|
check_add_new_component (type, ar->end[i], add_data);
|
|
check_add_new_component (type, ar->stride[i], add_data);
|
|
}
|
|
}
|
|
}
|
|
|
|
type->declared_at = expr->where;
|
|
gfc_set_sym_referenced (type);
|
|
gfc_commit_symbol (type);
|
|
free (name);
|
|
return type;
|
|
}
|
|
|
|
static void
|
|
remove_caf_ref (gfc_expr *expr, const bool conv_to_this_image_cafref = false)
|
|
{
|
|
gfc_ref *ref = expr->ref;
|
|
while (ref && (ref->type != REF_ARRAY || ref->u.ar.codimen == 0))
|
|
{
|
|
ref = ref->next;
|
|
}
|
|
if (ref && ref->type == REF_ARRAY && ref->u.ar.codimen != 0)
|
|
{
|
|
if (ref->u.ar.dimen != 0)
|
|
{
|
|
ref->u.ar.codimen = 0;
|
|
ref = ref->next;
|
|
}
|
|
else
|
|
{
|
|
if (conv_to_this_image_cafref)
|
|
{
|
|
for (int i = ref->u.ar.dimen;
|
|
i < ref->u.ar.dimen + ref->u.ar.codimen; ++i)
|
|
ref->u.ar.dimen_type[i] = DIMEN_THIS_IMAGE;
|
|
}
|
|
else
|
|
{
|
|
expr->ref = ref->next;
|
|
ref->next = NULL;
|
|
gfc_free_ref_list (ref);
|
|
ref = expr->ref;
|
|
}
|
|
}
|
|
}
|
|
fixup_comp_refs (expr);
|
|
}
|
|
|
|
static gfc_expr *
|
|
create_get_callback (gfc_expr *expr)
|
|
{
|
|
gfc_namespace *ns;
|
|
gfc_symbol *extproc, *proc, *buffer, *free_buffer, *base, *get_data,
|
|
*old_buffer_data, *caller_image;
|
|
char tname[GFC_MAX_SYMBOL_LEN + 1];
|
|
char *name;
|
|
const char *mname;
|
|
gfc_expr *cb, *post_caf_ref_expr;
|
|
gfc_code *code;
|
|
int expr_rank = expr->rank;
|
|
gfc_code *backup_caf_accessor_prepend = caf_accessor_prepend;
|
|
caf_accessor_prepend = nullptr;
|
|
|
|
/* Find the top-level namespace. */
|
|
for (ns = gfc_current_ns; ns->parent; ns = ns->parent)
|
|
;
|
|
|
|
if (expr->expr_type == EXPR_VARIABLE)
|
|
strcpy (tname, expr->symtree->name);
|
|
else
|
|
strcpy (tname, "dummy");
|
|
if (expr->symtree->n.sym->module)
|
|
mname = expr->symtree->n.sym->module;
|
|
else
|
|
mname = "main";
|
|
name = xasprintf ("_caf_accessor_%s_%s_%d", mname, tname, ++caf_sym_cnt);
|
|
gfc_get_symbol (name, ns, &extproc);
|
|
extproc->declared_at = expr->where;
|
|
gfc_set_sym_referenced (extproc);
|
|
++extproc->refs;
|
|
gfc_commit_symbol (extproc);
|
|
|
|
/* Set up namespace. */
|
|
gfc_namespace *sub_ns = gfc_get_namespace (ns, 0);
|
|
sub_ns->sibling = ns->contained;
|
|
ns->contained = sub_ns;
|
|
sub_ns->resolved = 1;
|
|
/* Set up procedure symbol. */
|
|
gfc_find_symbol (name, sub_ns, 1, &proc);
|
|
sub_ns->proc_name = proc;
|
|
proc->attr.if_source = IFSRC_DECL;
|
|
proc->attr.access = ACCESS_PUBLIC;
|
|
gfc_add_subroutine (&proc->attr, name, NULL);
|
|
proc->attr.host_assoc = 1;
|
|
proc->attr.always_explicit = 1;
|
|
++proc->refs;
|
|
proc->declared_at = expr->where;
|
|
gfc_commit_symbol (proc);
|
|
free (name);
|
|
|
|
split_expr_at_caf_ref (expr, sub_ns, &post_caf_ref_expr, false);
|
|
|
|
if (ns->proc_name->attr.flavor == FL_MODULE)
|
|
proc->module = ns->proc_name->name;
|
|
gfc_set_sym_referenced (proc);
|
|
/* Set up formal arguments. */
|
|
gfc_formal_arglist **argptr = &proc->formal;
|
|
#define ADD_ARG(name, nsym, stype, skind, sintent) \
|
|
gfc_get_symbol (name, sub_ns, &nsym); \
|
|
nsym->ts.type = stype; \
|
|
nsym->ts.kind = skind; \
|
|
nsym->attr.flavor = FL_PARAMETER; \
|
|
nsym->attr.dummy = 1; \
|
|
nsym->attr.intent = sintent; \
|
|
nsym->declared_at = expr->where; \
|
|
gfc_set_sym_referenced (nsym); \
|
|
*argptr = gfc_get_formal_arglist (); \
|
|
(*argptr)->sym = nsym; \
|
|
argptr = &(*argptr)->next
|
|
|
|
name = xasprintf ("add_data_%s_%s_%d", mname, tname, caf_sym_cnt);
|
|
ADD_ARG (name, get_data, BT_DERIVED, 0, INTENT_IN);
|
|
gfc_commit_symbol (get_data);
|
|
free (name);
|
|
|
|
ADD_ARG ("caller_image", caller_image, BT_INTEGER, gfc_default_integer_kind,
|
|
INTENT_IN);
|
|
gfc_commit_symbol (caller_image);
|
|
|
|
ADD_ARG ("buffer", buffer, expr->ts.type, expr->ts.kind, INTENT_INOUT);
|
|
buffer->ts = expr->ts;
|
|
if (expr_rank)
|
|
{
|
|
buffer->as = gfc_get_array_spec ();
|
|
buffer->as->rank = expr_rank;
|
|
if (expr->shape)
|
|
{
|
|
buffer->as->type = AS_EXPLICIT;
|
|
for (int d = 0; d < expr_rank; ++d)
|
|
{
|
|
buffer->as->lower[d]
|
|
= gfc_get_constant_expr (BT_INTEGER, gfc_index_integer_kind,
|
|
&gfc_current_locus);
|
|
gfc_mpz_set_hwi (buffer->as->lower[d]->value.integer, 1);
|
|
buffer->as->upper[d]
|
|
= gfc_get_constant_expr (BT_INTEGER, gfc_index_integer_kind,
|
|
&gfc_current_locus);
|
|
gfc_mpz_set_hwi (buffer->as->upper[d]->value.integer,
|
|
gfc_mpz_get_hwi (expr->shape[d]));
|
|
}
|
|
buffer->attr.allocatable = 1;
|
|
}
|
|
else
|
|
{
|
|
buffer->as->type = AS_DEFERRED;
|
|
buffer->attr.allocatable = 1;
|
|
}
|
|
buffer->attr.dimension = 1;
|
|
}
|
|
else
|
|
buffer->attr.pointer = 1;
|
|
if (buffer->ts.type == BT_CHARACTER)
|
|
{
|
|
buffer->ts.u.cl = gfc_get_charlen ();
|
|
*buffer->ts.u.cl = *expr->ts.u.cl;
|
|
buffer->ts.u.cl->length = gfc_copy_expr (expr->ts.u.cl->length);
|
|
}
|
|
gfc_commit_symbol (buffer);
|
|
|
|
ADD_ARG ("free_buffer", free_buffer, BT_LOGICAL, gfc_default_logical_kind,
|
|
INTENT_OUT);
|
|
gfc_commit_symbol (free_buffer);
|
|
|
|
// ADD_ARG (expr->symtree->name, base, BT_VOID, INTENT_IN);
|
|
base = post_caf_ref_expr->symtree->n.sym;
|
|
gfc_set_sym_referenced (base);
|
|
gfc_commit_symbol (base);
|
|
*argptr = gfc_get_formal_arglist ();
|
|
(*argptr)->sym = base;
|
|
argptr = &(*argptr)->next;
|
|
gfc_commit_symbol (base);
|
|
#undef ADD_ARG
|
|
|
|
/* Set up code. */
|
|
if (expr->rank != 0)
|
|
{
|
|
/* Code: old_buffer_ptr = C_LOC (buffer); */
|
|
code = sub_ns->code = gfc_get_code (EXEC_ASSIGN);
|
|
gfc_get_symbol ("old_buffer_data", sub_ns, &old_buffer_data);
|
|
old_buffer_data->ts.type = BT_VOID;
|
|
old_buffer_data->attr.flavor = FL_VARIABLE;
|
|
old_buffer_data->declared_at = expr->where;
|
|
gfc_set_sym_referenced (old_buffer_data);
|
|
gfc_commit_symbol (old_buffer_data);
|
|
code->loc = expr->where;
|
|
code->expr1 = gfc_lval_expr_from_sym (old_buffer_data);
|
|
code->expr2 = gfc_build_intrinsic_call (ns, GFC_ISYM_C_LOC, "C_LOC",
|
|
gfc_current_locus, 1,
|
|
gfc_lval_expr_from_sym (buffer));
|
|
code->next = gfc_get_code (EXEC_ASSIGN);
|
|
code = code->next;
|
|
}
|
|
else
|
|
code = sub_ns->code = gfc_get_code (EXEC_POINTER_ASSIGN);
|
|
|
|
/* Code: buffer = expr; */
|
|
code->loc = expr->where;
|
|
code->expr1 = gfc_lval_expr_from_sym (buffer);
|
|
code->expr2 = post_caf_ref_expr;
|
|
remove_caf_ref (post_caf_ref_expr);
|
|
get_data->ts.u.derived
|
|
= create_caf_add_data_parameter_type (code->expr2, ns, get_data);
|
|
if (code->expr2->rank == 0 && code->expr2->ts.type != BT_CHARACTER)
|
|
code->expr2 = gfc_build_intrinsic_call (ns, GFC_ISYM_C_LOC, "C_LOC",
|
|
gfc_current_locus, 1, code->expr2);
|
|
|
|
/* Code: *free_buffer = old_buffer_ptr /= C_LOC (buffer); for rank != 0 or
|
|
* *free_buffer = 0; for rank == 0. */
|
|
code->next = gfc_get_code (EXEC_ASSIGN);
|
|
code = code->next;
|
|
code->loc = expr->where;
|
|
code->expr1 = gfc_lval_expr_from_sym (free_buffer);
|
|
if (expr->rank != 0)
|
|
{
|
|
code->expr2 = gfc_get_operator_expr (
|
|
&gfc_current_locus, INTRINSIC_NE_OS,
|
|
gfc_lval_expr_from_sym (old_buffer_data),
|
|
gfc_build_intrinsic_call (ns, GFC_ISYM_C_LOC, "C_LOC",
|
|
gfc_current_locus, 1,
|
|
gfc_lval_expr_from_sym (buffer)));
|
|
code->expr2->ts.type = BT_LOGICAL;
|
|
code->expr2->ts.kind = gfc_default_logical_kind;
|
|
}
|
|
else
|
|
{
|
|
code->expr2 = gfc_get_logical_expr (gfc_default_logical_kind,
|
|
&gfc_current_locus, false);
|
|
}
|
|
|
|
cb = gfc_lval_expr_from_sym (extproc);
|
|
cb->ts.interface = extproc;
|
|
|
|
if (caf_accessor_prepend)
|
|
{
|
|
gfc_code *c = caf_accessor_prepend;
|
|
/* Find last in chain. */
|
|
for (; c->next; c = c->next)
|
|
;
|
|
c->next = sub_ns->code;
|
|
sub_ns->code = caf_accessor_prepend;
|
|
}
|
|
caf_accessor_prepend = backup_caf_accessor_prepend;
|
|
return cb;
|
|
}
|
|
|
|
void
|
|
add_caf_get_from_remote (gfc_expr *e)
|
|
{
|
|
gfc_expr *wrapper, *tmp_expr, *get_from_remote_expr,
|
|
*get_from_remote_hash_expr;
|
|
gfc_ref *ref;
|
|
int n;
|
|
|
|
for (ref = e->ref; ref; ref = ref->next)
|
|
if (ref->type == REF_ARRAY && ref->u.ar.codimen > 0)
|
|
break;
|
|
if (ref == NULL)
|
|
return;
|
|
|
|
for (n = ref->u.ar.dimen; n < ref->u.ar.dimen + ref->u.ar.codimen; n++)
|
|
if (ref->u.ar.dimen_type[n] != DIMEN_ELEMENT)
|
|
return;
|
|
|
|
tmp_expr = XCNEW (gfc_expr);
|
|
*tmp_expr = *e;
|
|
get_from_remote_expr = create_get_callback (tmp_expr);
|
|
get_from_remote_hash_expr = gfc_get_expr ();
|
|
get_from_remote_hash_expr->expr_type = EXPR_CONSTANT;
|
|
get_from_remote_hash_expr->ts.type = BT_INTEGER;
|
|
get_from_remote_hash_expr->ts.kind = gfc_default_integer_kind;
|
|
get_from_remote_hash_expr->where = tmp_expr->where;
|
|
mpz_init_set_ui (get_from_remote_hash_expr->value.integer,
|
|
gfc_hash_value (get_from_remote_expr->symtree->n.sym));
|
|
wrapper = gfc_build_intrinsic_call (gfc_current_ns, GFC_ISYM_CAF_GET,
|
|
"caf_get", tmp_expr->where, 3, tmp_expr,
|
|
get_from_remote_hash_expr,
|
|
get_from_remote_expr);
|
|
gfc_add_caf_accessor (get_from_remote_hash_expr, get_from_remote_expr);
|
|
wrapper->ts = e->ts;
|
|
wrapper->rank = e->rank;
|
|
wrapper->corank = e->corank;
|
|
if (e->rank)
|
|
wrapper->shape = gfc_copy_shape (e->shape, e->rank);
|
|
*e = *wrapper;
|
|
free (wrapper);
|
|
}
|
|
|
|
static gfc_expr *
|
|
create_allocated_callback (gfc_expr *expr)
|
|
{
|
|
gfc_namespace *ns;
|
|
gfc_symbol *extproc, *proc, *result, *base, *add_data, *caller_image;
|
|
char tname[GFC_MAX_SYMBOL_LEN + 1];
|
|
char *name;
|
|
const char *mname;
|
|
gfc_expr *cb, *post_caf_ref_expr;
|
|
gfc_code *code;
|
|
gfc_code *backup_caf_accessor_prepend = caf_accessor_prepend;
|
|
caf_accessor_prepend = nullptr;
|
|
gfc_expr swp;
|
|
|
|
/* Find the top-level namespace. */
|
|
for (ns = gfc_current_ns; ns->parent; ns = ns->parent)
|
|
;
|
|
|
|
if (expr->value.function.actual->expr->expr_type == EXPR_VARIABLE)
|
|
strcpy (tname, expr->value.function.actual->expr->symtree->name);
|
|
else
|
|
strcpy (tname, "dummy");
|
|
if (expr->value.function.actual->expr->symtree->n.sym->module)
|
|
mname = expr->value.function.actual->expr->symtree->n.sym->module;
|
|
else
|
|
mname = "main";
|
|
name = xasprintf ("_caf_present_%s_%s_%d", mname, tname, ++caf_sym_cnt);
|
|
gfc_get_symbol (name, ns, &extproc);
|
|
extproc->declared_at = expr->where;
|
|
gfc_set_sym_referenced (extproc);
|
|
++extproc->refs;
|
|
gfc_commit_symbol (extproc);
|
|
|
|
/* Set up namespace. */
|
|
gfc_namespace *sub_ns = gfc_get_namespace (ns, 0);
|
|
sub_ns->sibling = ns->contained;
|
|
ns->contained = sub_ns;
|
|
sub_ns->resolved = 1;
|
|
/* Set up procedure symbol. */
|
|
gfc_find_symbol (name, sub_ns, 1, &proc);
|
|
sub_ns->proc_name = proc;
|
|
proc->attr.if_source = IFSRC_DECL;
|
|
proc->attr.access = ACCESS_PUBLIC;
|
|
gfc_add_subroutine (&proc->attr, name, NULL);
|
|
proc->attr.host_assoc = 1;
|
|
proc->attr.always_explicit = 1;
|
|
proc->declared_at = expr->where;
|
|
++proc->refs;
|
|
gfc_commit_symbol (proc);
|
|
free (name);
|
|
|
|
split_expr_at_caf_ref (expr->value.function.actual->expr, sub_ns,
|
|
&post_caf_ref_expr, true);
|
|
|
|
if (ns->proc_name->attr.flavor == FL_MODULE)
|
|
proc->module = ns->proc_name->name;
|
|
gfc_set_sym_referenced (proc);
|
|
/* Set up formal arguments. */
|
|
gfc_formal_arglist **argptr = &proc->formal;
|
|
#define ADD_ARG(name, nsym, stype, skind, sintent) \
|
|
gfc_get_symbol (name, sub_ns, &nsym); \
|
|
nsym->ts.type = stype; \
|
|
nsym->ts.kind = skind; \
|
|
nsym->attr.flavor = FL_PARAMETER; \
|
|
nsym->attr.dummy = 1; \
|
|
nsym->attr.intent = sintent; \
|
|
nsym->declared_at = expr->where; \
|
|
gfc_set_sym_referenced (nsym); \
|
|
*argptr = gfc_get_formal_arglist (); \
|
|
(*argptr)->sym = nsym; \
|
|
argptr = &(*argptr)->next
|
|
|
|
name = xasprintf ("add_data_%s_%s_%d", mname, tname, ++caf_sym_cnt);
|
|
ADD_ARG (name, add_data, BT_DERIVED, 0, INTENT_IN);
|
|
gfc_commit_symbol (add_data);
|
|
free (name);
|
|
ADD_ARG ("caller_image", caller_image, BT_INTEGER, gfc_default_integer_kind,
|
|
INTENT_IN);
|
|
gfc_commit_symbol (caller_image);
|
|
|
|
ADD_ARG ("result", result, BT_LOGICAL, gfc_default_logical_kind, INTENT_OUT);
|
|
gfc_commit_symbol (result);
|
|
|
|
// ADD_ARG (expr->symtree->name, base, BT_VOID, INTENT_IN);
|
|
base = post_caf_ref_expr->symtree->n.sym;
|
|
base->attr.pointer = !base->attr.dimension;
|
|
gfc_set_sym_referenced (base);
|
|
*argptr = gfc_get_formal_arglist ();
|
|
(*argptr)->sym = base;
|
|
argptr = &(*argptr)->next;
|
|
gfc_commit_symbol (base);
|
|
#undef ADD_ARG
|
|
|
|
/* Set up code. */
|
|
/* Code: result = post_caf_ref_expr; */
|
|
code = sub_ns->code = gfc_get_code (EXEC_ASSIGN);
|
|
code->loc = expr->where;
|
|
code->expr1 = gfc_lval_expr_from_sym (result);
|
|
swp = *expr;
|
|
*expr = *swp.value.function.actual->expr;
|
|
swp.value.function.actual->expr = nullptr;
|
|
code->expr2 = gfc_copy_expr (&swp);
|
|
code->expr2->value.function.actual->expr = post_caf_ref_expr;
|
|
|
|
remove_caf_ref (code->expr2->value.function.actual->expr, true);
|
|
add_data->ts.u.derived
|
|
= create_caf_add_data_parameter_type (post_caf_ref_expr, ns, add_data);
|
|
|
|
cb = gfc_lval_expr_from_sym (extproc);
|
|
cb->ts.interface = extproc;
|
|
|
|
if (caf_accessor_prepend)
|
|
{
|
|
gfc_code *c = caf_accessor_prepend;
|
|
/* Find last in chain. */
|
|
for (; c->next; c = c->next)
|
|
;
|
|
c->next = sub_ns->code;
|
|
sub_ns->code = caf_accessor_prepend;
|
|
}
|
|
caf_accessor_prepend = backup_caf_accessor_prepend;
|
|
return cb;
|
|
}
|
|
|
|
static void
|
|
rewrite_caf_allocated (gfc_expr **e)
|
|
{
|
|
gfc_expr *present_fn_expr, *present_hash_expr, *wrapper;
|
|
|
|
present_fn_expr = create_allocated_callback (*e);
|
|
|
|
present_hash_expr = gfc_get_expr ();
|
|
present_hash_expr->expr_type = EXPR_CONSTANT;
|
|
present_hash_expr->ts.type = BT_INTEGER;
|
|
present_hash_expr->ts.kind = gfc_default_integer_kind;
|
|
present_hash_expr->where = (*e)->where;
|
|
mpz_init_set_ui (present_hash_expr->value.integer,
|
|
gfc_hash_value (present_fn_expr->symtree->n.sym));
|
|
wrapper
|
|
= gfc_build_intrinsic_call (gfc_current_ns,
|
|
GFC_ISYM_CAF_IS_PRESENT_ON_REMOTE,
|
|
"caf_is_present_on_remote", (*e)->where, 3, *e,
|
|
present_hash_expr, present_fn_expr);
|
|
gfc_add_caf_accessor (present_hash_expr, present_fn_expr);
|
|
*e = wrapper;
|
|
}
|
|
|
|
static gfc_expr *
|
|
create_send_callback (gfc_expr *expr, gfc_expr *rhs)
|
|
{
|
|
gfc_namespace *ns;
|
|
gfc_symbol *extproc, *proc, *buffer, *base, *send_data, *caller_image;
|
|
char tname[GFC_MAX_SYMBOL_LEN + 1];
|
|
char *name;
|
|
const char *mname;
|
|
gfc_expr *cb, *post_caf_ref_expr;
|
|
gfc_code *code;
|
|
gfc_code *backup_caf_accessor_prepend = caf_accessor_prepend;
|
|
caf_accessor_prepend = nullptr;
|
|
|
|
/* Find the top-level namespace. */
|
|
for (ns = gfc_current_ns; ns->parent; ns = ns->parent)
|
|
;
|
|
|
|
if (expr->expr_type == EXPR_VARIABLE)
|
|
strcpy (tname, expr->symtree->name);
|
|
else
|
|
strcpy (tname, "dummy");
|
|
if (expr->symtree->n.sym->module)
|
|
mname = expr->symtree->n.sym->module;
|
|
else
|
|
mname = "main";
|
|
name = xasprintf ("_caf_accessor_%s_%s_%d", mname, tname, ++caf_sym_cnt);
|
|
gfc_get_symbol (name, ns, &extproc);
|
|
extproc->declared_at = expr->where;
|
|
gfc_set_sym_referenced (extproc);
|
|
++extproc->refs;
|
|
gfc_commit_symbol (extproc);
|
|
|
|
/* Set up namespace. */
|
|
gfc_namespace *sub_ns = gfc_get_namespace (ns, 0);
|
|
sub_ns->sibling = ns->contained;
|
|
ns->contained = sub_ns;
|
|
sub_ns->resolved = 1;
|
|
/* Set up procedure symbol. */
|
|
gfc_find_symbol (name, sub_ns, 1, &proc);
|
|
sub_ns->proc_name = proc;
|
|
proc->attr.if_source = IFSRC_DECL;
|
|
proc->attr.access = ACCESS_PUBLIC;
|
|
gfc_add_subroutine (&proc->attr, name, NULL);
|
|
proc->attr.host_assoc = 1;
|
|
proc->attr.always_explicit = 1;
|
|
++proc->refs;
|
|
proc->declared_at = expr->where;
|
|
gfc_commit_symbol (proc);
|
|
free (name);
|
|
|
|
split_expr_at_caf_ref (expr, sub_ns, &post_caf_ref_expr, true);
|
|
|
|
if (ns->proc_name->attr.flavor == FL_MODULE)
|
|
proc->module = ns->proc_name->name;
|
|
gfc_set_sym_referenced (proc);
|
|
/* Set up formal arguments. */
|
|
gfc_formal_arglist **argptr = &proc->formal;
|
|
#define ADD_ARG(name, nsym, stype, skind, sintent) \
|
|
gfc_get_symbol (name, sub_ns, &nsym); \
|
|
nsym->ts.type = stype; \
|
|
nsym->ts.kind = skind; \
|
|
nsym->attr.flavor = FL_PARAMETER; \
|
|
nsym->attr.dummy = 1; \
|
|
nsym->attr.intent = sintent; \
|
|
nsym->declared_at = expr->where; \
|
|
gfc_set_sym_referenced (nsym); \
|
|
*argptr = gfc_get_formal_arglist (); \
|
|
(*argptr)->sym = nsym; \
|
|
argptr = &(*argptr)->next
|
|
|
|
name = xasprintf ("add_send_data_%s_%s_%d", mname, tname, caf_sym_cnt);
|
|
ADD_ARG (name, send_data, BT_DERIVED, 0, INTENT_IN);
|
|
gfc_commit_symbol (send_data);
|
|
free (name);
|
|
|
|
ADD_ARG ("caller_image", caller_image, BT_INTEGER, gfc_default_integer_kind,
|
|
INTENT_IN);
|
|
gfc_commit_symbol (caller_image);
|
|
|
|
// ADD_ARG (expr->symtree->name, base, BT_VOID, INTENT_IN);
|
|
base = post_caf_ref_expr->symtree->n.sym;
|
|
base->attr.intent = INTENT_INOUT;
|
|
gfc_set_sym_referenced (base);
|
|
gfc_commit_symbol (base);
|
|
*argptr = gfc_get_formal_arglist ();
|
|
(*argptr)->sym = base;
|
|
argptr = &(*argptr)->next;
|
|
gfc_commit_symbol (base);
|
|
|
|
ADD_ARG ("buffer", buffer, rhs->ts.type, rhs->ts.kind, INTENT_IN);
|
|
buffer->ts = rhs->ts;
|
|
if (rhs->rank)
|
|
{
|
|
buffer->as = gfc_get_array_spec ();
|
|
buffer->as->rank = rhs->rank;
|
|
buffer->as->type = AS_DEFERRED;
|
|
buffer->attr.allocatable = 1;
|
|
buffer->attr.dimension = 1;
|
|
}
|
|
if (buffer->ts.type == BT_CHARACTER)
|
|
{
|
|
buffer->ts.u.cl = gfc_get_charlen ();
|
|
*buffer->ts.u.cl = *rhs->ts.u.cl;
|
|
buffer->ts.deferred = 1;
|
|
buffer->ts.u.cl->length = gfc_copy_expr (rhs->ts.u.cl->length);
|
|
}
|
|
gfc_commit_symbol (buffer);
|
|
#undef ADD_ARG
|
|
|
|
/* Set up code. */
|
|
/* Code: base = buffer; */
|
|
code = sub_ns->code = gfc_get_code (EXEC_ASSIGN);
|
|
code->loc = expr->where;
|
|
code->expr1 = post_caf_ref_expr;
|
|
if (code->expr1->ts.type == BT_CHARACTER
|
|
&& code->expr1->ts.kind != buffer->ts.kind)
|
|
{
|
|
bool converted;
|
|
code->expr2 = gfc_lval_expr_from_sym (buffer);
|
|
converted = gfc_convert_chartype (code->expr2, &code->expr1->ts);
|
|
gcc_assert (converted);
|
|
}
|
|
else if (code->expr1->ts.type != buffer->ts.type)
|
|
{
|
|
bool converted;
|
|
code->expr2 = gfc_lval_expr_from_sym (buffer);
|
|
converted = gfc_convert_type_warn (code->expr2, &code->expr1->ts, 0, 0,
|
|
buffer->attr.dimension);
|
|
gcc_assert (converted);
|
|
}
|
|
else
|
|
code->expr2 = gfc_lval_expr_from_sym (buffer);
|
|
remove_caf_ref (post_caf_ref_expr);
|
|
send_data->ts.u.derived
|
|
= create_caf_add_data_parameter_type (code->expr1, ns, send_data);
|
|
|
|
cb = gfc_lval_expr_from_sym (extproc);
|
|
cb->ts.interface = extproc;
|
|
|
|
if (caf_accessor_prepend)
|
|
{
|
|
gfc_code *c = caf_accessor_prepend;
|
|
/* Find last in chain. */
|
|
for (; c->next; c = c->next)
|
|
;
|
|
c->next = sub_ns->code;
|
|
sub_ns->code = caf_accessor_prepend;
|
|
}
|
|
caf_accessor_prepend = backup_caf_accessor_prepend;
|
|
return cb;
|
|
}
|
|
|
|
static void
|
|
rewrite_caf_send (gfc_code *c)
|
|
{
|
|
gfc_expr *send_to_remote_expr, *send_to_remote_hash_expr, *lhs, *rhs;
|
|
gfc_actual_arglist *arg = c->ext.actual;
|
|
|
|
lhs = arg->expr;
|
|
arg = arg->next;
|
|
rhs = arg->expr;
|
|
/* Detect an already rewritten caf_send. */
|
|
if (arg->next && arg->next->expr->expr_type == EXPR_CONSTANT
|
|
&& arg->next->next && arg->next->next->expr->expr_type == EXPR_VARIABLE)
|
|
return;
|
|
|
|
send_to_remote_expr = create_send_callback (lhs, rhs);
|
|
send_to_remote_hash_expr = gfc_get_expr ();
|
|
send_to_remote_hash_expr->expr_type = EXPR_CONSTANT;
|
|
send_to_remote_hash_expr->ts.type = BT_INTEGER;
|
|
send_to_remote_hash_expr->ts.kind = gfc_default_integer_kind;
|
|
send_to_remote_hash_expr->where = lhs->where;
|
|
mpz_init_set_ui (send_to_remote_hash_expr->value.integer,
|
|
gfc_hash_value (send_to_remote_expr->symtree->n.sym));
|
|
arg->next = gfc_get_actual_arglist ();
|
|
arg = arg->next;
|
|
arg->expr = send_to_remote_hash_expr;
|
|
arg->next = gfc_get_actual_arglist ();
|
|
arg = arg->next;
|
|
arg->expr = send_to_remote_expr;
|
|
gfc_add_caf_accessor (send_to_remote_hash_expr, send_to_remote_expr);
|
|
|
|
if (gfc_is_coindexed (rhs))
|
|
{
|
|
gfc_expr *get_from_remote_expr, *get_from_remote_hash_expr;
|
|
|
|
c->resolved_isym = gfc_intrinsic_subroutine_by_id (GFC_ISYM_CAF_SENDGET);
|
|
get_from_remote_expr = create_get_callback (rhs);
|
|
get_from_remote_hash_expr = gfc_get_expr ();
|
|
get_from_remote_hash_expr->expr_type = EXPR_CONSTANT;
|
|
get_from_remote_hash_expr->ts.type = BT_INTEGER;
|
|
get_from_remote_hash_expr->ts.kind = gfc_default_integer_kind;
|
|
get_from_remote_hash_expr->where = rhs->where;
|
|
mpz_init_set_ui (get_from_remote_hash_expr->value.integer,
|
|
gfc_hash_value (get_from_remote_expr->symtree->n.sym));
|
|
arg->next = gfc_get_actual_arglist ();
|
|
arg = arg->next;
|
|
arg->expr = get_from_remote_hash_expr;
|
|
arg->next = gfc_get_actual_arglist ();
|
|
arg = arg->next;
|
|
arg->expr = get_from_remote_expr;
|
|
gfc_add_caf_accessor (get_from_remote_hash_expr, get_from_remote_expr);
|
|
}
|
|
}
|
|
|
|
static int
|
|
coindexed_expr_callback (gfc_expr **e, int *walk_subtrees,
|
|
void *data ATTRIBUTE_UNUSED)
|
|
{
|
|
*walk_subtrees = 1;
|
|
|
|
switch ((*e)->expr_type)
|
|
{
|
|
case EXPR_VARIABLE:
|
|
if (!caf_on_lhs && gfc_is_coindexed (*e))
|
|
{
|
|
add_caf_get_from_remote (*e);
|
|
*walk_subtrees = 0;
|
|
}
|
|
/* Clear the flag to rewrite caf_gets in sub expressions of the lhs. */
|
|
caf_on_lhs = false;
|
|
break;
|
|
case EXPR_FUNCTION:
|
|
if ((*e)->value.function.isym)
|
|
switch ((*e)->value.function.isym->id)
|
|
{
|
|
case GFC_ISYM_ALLOCATED:
|
|
if ((*e)->value.function.actual->expr
|
|
&& (gfc_is_coarray ((*e)->value.function.actual->expr)
|
|
|| gfc_is_coindexed ((*e)->value.function.actual->expr)))
|
|
{
|
|
rewrite_caf_allocated (e);
|
|
*walk_subtrees = 0;
|
|
}
|
|
break;
|
|
case GFC_ISYM_CAF_GET:
|
|
case GFC_ISYM_CAF_IS_PRESENT_ON_REMOTE:
|
|
*walk_subtrees = 0;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
coindexed_code_callback (gfc_code **c, int *walk_subtrees,
|
|
void *data ATTRIBUTE_UNUSED)
|
|
{
|
|
int ws = 1;
|
|
current_code = c;
|
|
|
|
switch ((*c)->op)
|
|
{
|
|
case EXEC_ASSIGN:
|
|
case EXEC_POINTER_ASSIGN:
|
|
caf_on_lhs = true;
|
|
coindexed_expr_callback (&((*c)->expr1), &ws, NULL);
|
|
caf_on_lhs = false;
|
|
ws = 1;
|
|
coindexed_expr_callback (&((*c)->expr2), &ws, NULL);
|
|
*walk_subtrees = ws;
|
|
break;
|
|
case EXEC_LOCK:
|
|
case EXEC_UNLOCK:
|
|
case EXEC_EVENT_POST:
|
|
case EXEC_EVENT_WAIT:
|
|
*walk_subtrees = 0;
|
|
break;
|
|
case EXEC_CALL:
|
|
*walk_subtrees = 1;
|
|
if ((*c)->resolved_isym)
|
|
switch ((*c)->resolved_isym->id)
|
|
{
|
|
case GFC_ISYM_CAF_SEND:
|
|
rewrite_caf_send (*c);
|
|
*walk_subtrees = 0;
|
|
break;
|
|
case GFC_ISYM_CAF_SENDGET:
|
|
/* Seldomly this routine is called again with the symbol already
|
|
changed to CAF_SENDGET. Do not process the subtree again. The
|
|
rewrite has already been done by rewrite_caf_send (). */
|
|
*walk_subtrees = 0;
|
|
break;
|
|
case GFC_ISYM_ATOMIC_ADD:
|
|
case GFC_ISYM_ATOMIC_AND:
|
|
case GFC_ISYM_ATOMIC_CAS:
|
|
case GFC_ISYM_ATOMIC_DEF:
|
|
case GFC_ISYM_ATOMIC_FETCH_ADD:
|
|
case GFC_ISYM_ATOMIC_FETCH_AND:
|
|
case GFC_ISYM_ATOMIC_FETCH_OR:
|
|
case GFC_ISYM_ATOMIC_FETCH_XOR:
|
|
case GFC_ISYM_ATOMIC_OR:
|
|
case GFC_ISYM_ATOMIC_REF:
|
|
case GFC_ISYM_ATOMIC_XOR:
|
|
*walk_subtrees = 0;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
default:
|
|
*walk_subtrees = 1;
|
|
break;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void
|
|
gfc_coarray_rewrite (gfc_namespace *ns)
|
|
{
|
|
gfc_namespace *saved_ns = gfc_current_ns;
|
|
gfc_current_ns = ns;
|
|
|
|
if (flag_coarray == GFC_FCOARRAY_LIB)
|
|
{
|
|
gfc_code_walker (&ns->code, coindexed_code_callback,
|
|
coindexed_expr_callback, NULL);
|
|
|
|
for (gfc_namespace *cns = ns->contained; cns; cns = cns->sibling)
|
|
gfc_coarray_rewrite (cns);
|
|
}
|
|
|
|
gfc_current_ns = saved_ns;
|
|
}
|