| /* 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; |
| } |