gcc/fortran/ChangeLog: * dump-parse-tree.cc (show_code_node): Updated to use c->ext.concur.forall_iterator instead of c->ext.forall_iterator. Added support for dumping DO CONCURRENT locality specifiers. * frontend-passes.cc (index_interchange, gfc_code_walker): Updated to use c->ext.concur.forall_iterator instead of c->ext.forall_iterator. * gfortran.h (enum locality_type): Added new enum for locality types in DO CONCURRENT constructs. * match.cc (match_simple_forall, gfc_match_forall): Updated to use new_st.ext.concur.forall_iterator instead of new_st.ext.forall_iterator. (gfc_match_do): Implemented support for matching DO CONCURRENT locality specifiers (LOCAL, LOCAL_INIT, SHARED, DEFAULT(NONE), and REDUCE). * parse.cc (parse_do_block): Updated to use new_st.ext.concur.forall_iterator instead of new_st.ext.forall_iterator. * resolve.cc: Added struct check_default_none_data. (do_concur_locality_specs_f2023): New function to check compliance with F2023's C1133 constraint for DO CONCURRENT. (check_default_none_expr): New function to check DEFAULT(NONE) compliance. (resolve_locality_spec): New function to resolve locality specs. (gfc_count_forall_iterators): Updated to use code->ext.concur.forall_iterator. (gfc_resolve_forall): Updated to use code->ext.concur.forall_iterator. * st.cc (gfc_free_statement): Updated to free locality specifications and use p->ext.concur.forall_iterator. * trans-stmt.cc (gfc_trans_forall_1): Updated to use code->ext.concur.forall_iterator.
gcc/testsuite/ChangeLog: * gfortran.dg/do_concurrent_10.f90: New test for parsing DO CONCURRENT with 'concurrent' as a variable name. * gfortran.dg/do_concurrent_8_f2018.f90: New test for F2018 DO CONCURRENT with nested loops and REDUCE clauses. * gfortran.dg/do_concurrent_8_f2023.f90: New test for F2023 DO CONCURRENT with nested loops and REDUCE clauses. * gfortran.dg/do_concurrent_9.f90: New test for DO CONCURRENT with DEFAULT(NONE) and locality specs. * gfortran.dg/do_concurrent_all_clauses.f90: New test covering all DO CONCURRENT clauses and their interactions. * gfortran.dg/do_concurrent_basic.f90: New basic test for DO CONCURRENT functionality. * gfortran.dg/do_concurrent_constraints.f90: New test for constraints on DO CONCURRENT locality specs. * gfortran.dg/do_concurrent_local_init.f90: New test for LOCAL_INIT clause in DO CONCURRENT. * gfortran.dg/do_concurrent_locality_specs.f90: New test for DO CONCURRENT with locality specs. * gfortran.dg/do_concurrent_multiple_reduce.f90: New test for multiple REDUCE clauses in DO CONCURRENT. * gfortran.dg/do_concurrent_nested.f90: New test for nested DO CONCURRENT loops. * gfortran.dg/do_concurrent_parser.f90: New test for DO CONCURRENT parser error handling. * gfortran.dg/do_concurrent_reduce_max.f90: New test for REDUCE with MAX operation in DO CONCURRENT. * gfortran.dg/do_concurrent_reduce_sum.f90: New test for REDUCE with sum operation in DO CONCURRENT. * gfortran.dg/do_concurrent_shared.f90: New test for SHARED clause in DO CONCURRENT. Signed-off-by: Anuj <anujmohite...@gmail.com> --- gcc/fortran/dump-parse-tree.cc | 113 +++++- gcc/fortran/frontend-passes.cc | 8 +- gcc/fortran/gfortran.h | 20 +- gcc/fortran/match.cc | 286 +++++++++++++- gcc/fortran/parse.cc | 2 +- gcc/fortran/resolve.cc | 354 +++++++++++++++++- gcc/fortran/st.cc | 5 +- gcc/fortran/trans-stmt.cc | 6 +- .../gfortran.dg/do_concurrent_10.f90 | 11 + .../gfortran.dg/do_concurrent_8_f2018.f90 | 19 + .../gfortran.dg/do_concurrent_8_f2023.f90 | 23 ++ gcc/testsuite/gfortran.dg/do_concurrent_9.f90 | 15 + .../gfortran.dg/do_concurrent_all_clauses.f90 | 26 ++ .../gfortran.dg/do_concurrent_basic.f90 | 11 + .../gfortran.dg/do_concurrent_constraints.f90 | 126 +++++++ .../gfortran.dg/do_concurrent_local_init.f90 | 11 + .../do_concurrent_locality_specs.f90 | 14 + .../do_concurrent_multiple_reduce.f90 | 17 + .../gfortran.dg/do_concurrent_nested.f90 | 26 ++ .../gfortran.dg/do_concurrent_parser.f90 | 20 + .../gfortran.dg/do_concurrent_reduce_max.f90 | 14 + .../gfortran.dg/do_concurrent_reduce_sum.f90 | 14 + .../gfortran.dg/do_concurrent_shared.f90 | 14 + 23 files changed, 1134 insertions(+), 21 deletions(-) create mode 100644 gcc/testsuite/gfortran.dg/do_concurrent_10.f90 create mode 100644 gcc/testsuite/gfortran.dg/do_concurrent_8_f2018.f90 create mode 100644 gcc/testsuite/gfortran.dg/do_concurrent_8_f2023.f90 create mode 100644 gcc/testsuite/gfortran.dg/do_concurrent_9.f90 create mode 100644 gcc/testsuite/gfortran.dg/do_concurrent_all_clauses.f90 create mode 100644 gcc/testsuite/gfortran.dg/do_concurrent_basic.f90 create mode 100644 gcc/testsuite/gfortran.dg/do_concurrent_constraints.f90 create mode 100644 gcc/testsuite/gfortran.dg/do_concurrent_local_init.f90 create mode 100644 gcc/testsuite/gfortran.dg/do_concurrent_locality_specs.f90 create mode 100644 gcc/testsuite/gfortran.dg/do_concurrent_multiple_reduce.f90 create mode 100644 gcc/testsuite/gfortran.dg/do_concurrent_nested.f90 create mode 100644 gcc/testsuite/gfortran.dg/do_concurrent_parser.f90 create mode 100644 gcc/testsuite/gfortran.dg/do_concurrent_reduce_max.f90 create mode 100644 gcc/testsuite/gfortran.dg/do_concurrent_reduce_sum.f90 create mode 100644 gcc/testsuite/gfortran.dg/do_concurrent_shared.f90 diff --git a/gcc/fortran/dump-parse-tree.cc b/gcc/fortran/dump-parse-tree.cc index 80aa8ef84e7..4cbd61c349e 100644 --- a/gcc/fortran/dump-parse-tree.cc +++ b/gcc/fortran/dump-parse-tree.cc @@ -2830,7 +2830,7 @@ show_code_node (int level, gfc_code *c) case EXEC_FORALL: fputs ("FORALL ", dumpfile); - for (fa = c->ext.forall_iterator; fa; fa = fa->next) + for (fa = c->ext.concur.forall_iterator; fa; fa = fa->next) { show_expr (fa->var); fputc (' ', dumpfile); @@ -2890,7 +2890,7 @@ show_code_node (int level, gfc_code *c) case EXEC_DO_CONCURRENT: fputs ("DO CONCURRENT ", dumpfile); - for (fa = c->ext.forall_iterator; fa; fa = fa->next) + for (fa = c->ext.concur.forall_iterator; fa; fa = fa->next) { show_expr (fa->var); fputc (' ', dumpfile); @@ -2903,7 +2903,114 @@ show_code_node (int level, gfc_code *c) if (fa->next != NULL) fputc (',', dumpfile); } - show_expr (c->expr1); + + if (c->expr1 != NULL) + { + fputc (',', dumpfile); + show_expr (c->expr1); + } + + if (c->ext.concur.locality[LOCALITY_LOCAL]) + { + fputs (" LOCAL(", dumpfile); + + for (gfc_expr_list *el = c->ext.concur.locality[LOCALITY_LOCAL]; + el; el = el->next) + { + show_expr (el->expr); + if (el->next) + fputc (',', dumpfile); + } + fputc (')', dumpfile); + } + + if (c->ext.concur.locality[LOCALITY_LOCAL_INIT]) + { + fputs (" LOCAL_INIT(", dumpfile); + for (gfc_expr_list *el = c->ext.concur.locality[LOCALITY_LOCAL_INIT]; + el; el = el->next) + { + show_expr (el->expr); + if (el->next) + fputc (',', dumpfile); + } + fputc (')', dumpfile); + } + + if (c->ext.concur.locality[LOCALITY_SHARED]) + { + fputs (" SHARED(", dumpfile); + for (gfc_expr_list *el = c->ext.concur.locality[LOCALITY_SHARED]; + el; el = el->next) + { + show_expr (el->expr); + if (el->next) + fputc (',', dumpfile); + } + fputc (')', dumpfile); + } + + if (c->ext.concur.default_none) + { + fputs (" DEFAULT(NONE)", dumpfile); + } + + if (c->ext.concur.locality[LOCALITY_REDUCE]) + { + gfc_expr_list *el = c->ext.concur.locality[LOCALITY_REDUCE]; + while (el) + { + fputs (" REDUCE(", dumpfile); + if (el->expr) + { + if (el->expr->expr_type == EXPR_FUNCTION) + { + const char *name; + switch (el->expr->value.function.isym->id) + { + case GFC_ISYM_MIN: + name = "MIN"; + break; + case GFC_ISYM_MAX: + name = "MAX"; + break; + case GFC_ISYM_IAND: + name = "IAND"; + break; + case GFC_ISYM_IOR: + name = "IOR"; + break; + case GFC_ISYM_IEOR: + name = "IEOR"; + break; + default: + gcc_unreachable (); + } + fputs (name, dumpfile); + } + else + show_expr (el->expr); + } + else + { + fputs ("(NULL)", dumpfile); + } + + fputc (':', dumpfile); + el = el->next; + + while (el && el->expr && el->expr->expr_type == EXPR_VARIABLE) + { + show_expr (el->expr); + el = el->next; + if (el && el->expr && el->expr->expr_type == EXPR_VARIABLE) + fputc (',', dumpfile); + } + + fputc (')', dumpfile); + } + } + ++show_level; show_code (level + 1, c->block->next); diff --git a/gcc/fortran/frontend-passes.cc b/gcc/fortran/frontend-passes.cc index 3c06018fdbb..372fa8a8c76 100644 --- a/gcc/fortran/frontend-passes.cc +++ b/gcc/fortran/frontend-passes.cc @@ -5171,7 +5171,7 @@ index_interchange (gfc_code **c, int *walk_subtrees ATTRIBUTE_UNUSED, return 0; n_iter = 0; - for (fa = co->ext.forall_iterator; fa; fa = fa->next) + for (fa = co->ext.concur.forall_iterator; fa; fa = fa->next) n_iter ++; /* Nothing to reorder. */ @@ -5181,7 +5181,7 @@ index_interchange (gfc_code **c, int *walk_subtrees ATTRIBUTE_UNUSED, ind = XALLOCAVEC (ind_type, n_iter + 1); i = 0; - for (fa = co->ext.forall_iterator; fa; fa = fa->next) + for (fa = co->ext.concur.forall_iterator; fa; fa = fa->next) { ind[i].sym = fa->var->symtree->n.sym; ind[i].fa = fa; @@ -5197,7 +5197,7 @@ index_interchange (gfc_code **c, int *walk_subtrees ATTRIBUTE_UNUSED, qsort ((void *) ind, n_iter, sizeof (ind_type), loop_comp); /* Do the actual index interchange. */ - co->ext.forall_iterator = fa = ind[0].fa; + co->ext.concur.forall_iterator = fa = ind[0].fa; for (i=1; i<n_iter; i++) { fa->next = ind[i].fa; @@ -5449,7 +5449,7 @@ gfc_code_walker (gfc_code **c, walk_code_fn_t codefn, walk_expr_fn_t exprfn, case EXEC_DO_CONCURRENT: { gfc_forall_iterator *fa; - for (fa = co->ext.forall_iterator; fa; fa = fa->next) + for (fa = co->ext.concur.forall_iterator; fa; fa = fa->next) { WALK_SUBEXPR (fa->var); WALK_SUBEXPR (fa->start); diff --git a/gcc/fortran/gfortran.h b/gcc/fortran/gfortran.h index 36ed8eeac2d..c6aefb81a73 100644 --- a/gcc/fortran/gfortran.h +++ b/gcc/fortran/gfortran.h @@ -3042,6 +3042,16 @@ enum gfc_exec_op EXEC_OMP_ERROR, EXEC_OMP_ALLOCATE, EXEC_OMP_ALLOCATORS }; +/* Enum Definition for locality types. */ +enum locality_type +{ + LOCALITY_LOCAL = 0, + LOCALITY_LOCAL_INIT, + LOCALITY_SHARED, + LOCALITY_REDUCE, + LOCALITY_NUM +}; + typedef struct gfc_code { gfc_exec_op op; @@ -3089,7 +3099,15 @@ typedef struct gfc_code gfc_inquire *inquire; gfc_wait *wait; gfc_dt *dt; - gfc_forall_iterator *forall_iterator; + + struct + { + gfc_forall_iterator *forall_iterator; + gfc_expr_list *locality[LOCALITY_NUM]; + bool default_none; + } + concur; + struct gfc_code *which_construct; int stop_code; gfc_entry_list *entry; diff --git a/gcc/fortran/match.cc b/gcc/fortran/match.cc index 1851a8f94a5..8263b337df0 100644 --- a/gcc/fortran/match.cc +++ b/gcc/fortran/match.cc @@ -2504,7 +2504,7 @@ match_simple_forall (void) gfc_clear_new_st (); new_st.op = EXEC_FORALL; new_st.expr1 = mask; - new_st.ext.forall_iterator = head; + new_st.ext.concur.forall_iterator = head; new_st.block = gfc_get_code (EXEC_FORALL); new_st.block->next = c; @@ -2554,7 +2554,7 @@ gfc_match_forall (gfc_statement *st) *st = ST_FORALL_BLOCK; new_st.op = EXEC_FORALL; new_st.expr1 = mask; - new_st.ext.forall_iterator = head; + new_st.ext.concur.forall_iterator = head; return MATCH_YES; } @@ -2577,7 +2577,7 @@ gfc_match_forall (gfc_statement *st) gfc_clear_new_st (); new_st.op = EXEC_FORALL; new_st.expr1 = mask; - new_st.ext.forall_iterator = head; + new_st.ext.concur.forall_iterator = head; new_st.block = gfc_get_code (EXEC_FORALL); new_st.block->next = c; @@ -2639,9 +2639,20 @@ gfc_match_do (void) if (gfc_match_parens () == MATCH_ERROR) return MATCH_ERROR; + /* Handle DO CONCURRENT construct. */ + if (gfc_match (" concurrent") == MATCH_YES) { gfc_forall_iterator *head; + gfc_expr_list *local = NULL; + gfc_expr_list *local_tail = NULL; + gfc_expr_list *local_init = NULL; + gfc_expr_list *local_init_tail = NULL; + gfc_expr_list *shared = NULL; + gfc_expr_list *shared_tail = NULL; + gfc_expr_list *reduce = NULL; + gfc_expr_list *reduce_tail = NULL; + bool default_none = false; gfc_expr *mask; if (!gfc_notify_std (GFC_STD_F2008, "DO CONCURRENT construct at %C")) @@ -2652,6 +2663,258 @@ gfc_match_do (void) head = NULL; m = match_forall_header (&head, &mask); + if (m == MATCH_NO) + goto match_do_loop; + if (m == MATCH_ERROR) + goto concurr_cleanup; + + while (true) + { + gfc_gobble_whitespace (); + locus where = gfc_current_locus; + + if (gfc_match_eos () == MATCH_YES) + break; + + else if (gfc_match ("local ( ") == MATCH_YES) + { + gfc_expr *e; + while (true) + { + if (gfc_match_variable (&e, 0) != MATCH_YES) + goto concurr_cleanup; + + if (local == NULL) + local = local_tail = gfc_get_expr_list (); + + else + { + local_tail->next = gfc_get_expr_list (); + local_tail = local_tail->next; + } + local_tail->expr = e; + + if (gfc_match_char (',') == MATCH_YES) + continue; + if (gfc_match_char (')') == MATCH_YES) + break; + goto concurr_cleanup; + } + } + + else if (gfc_match ("local_init ( ") == MATCH_YES) + { + gfc_expr *e; + + while (true) + { + if (gfc_match_variable (&e, 0) != MATCH_YES) + goto concurr_cleanup; + + if (local_init == NULL) + local_init = local_init_tail = gfc_get_expr_list (); + + else + { + local_init_tail->next = gfc_get_expr_list (); + local_init_tail = local_init_tail->next; + } + local_init_tail->expr = e; + + if (gfc_match_char (',') == MATCH_YES) + continue; + if (gfc_match_char (')') == MATCH_YES) + break; + goto concurr_cleanup; + } + } + + else if (gfc_match ("shared ( ") == MATCH_YES) + { + gfc_expr *e; + while (true) + { + if (gfc_match_variable (&e, 0) != MATCH_YES) + goto concurr_cleanup; + + if (shared == NULL) + shared = shared_tail = gfc_get_expr_list (); + + else + { + shared_tail->next = gfc_get_expr_list (); + shared_tail = shared_tail->next; + } + shared_tail->expr = e; + + if (gfc_match_char (',') == MATCH_YES) + continue; + if (gfc_match_char (')') == MATCH_YES) + break; + goto concurr_cleanup; + } + } + + else if (gfc_match ("default ( none )") == MATCH_YES) + { + if (default_none) + { + gfc_error ("DEFAULT(NONE) specified more than once in DO " + "CONCURRENT at %C"); + goto concurr_cleanup; + } + default_none = true; + } + + else if (gfc_match ("reduce ( ") == MATCH_YES) + { + gfc_expr *reduction_expr; + where = gfc_current_locus; + + if (gfc_match_char ('+') == MATCH_YES) + reduction_expr = gfc_get_operator_expr (&where, + INTRINSIC_PLUS, + NULL, NULL); + + else if (gfc_match_char ('*') == MATCH_YES) + reduction_expr = gfc_get_operator_expr (&where, + INTRINSIC_TIMES, + NULL, NULL); + + else if (gfc_match (".and.") == MATCH_YES) + reduction_expr = gfc_get_operator_expr (&where, + INTRINSIC_AND, + NULL, NULL); + + else if (gfc_match (".or.") == MATCH_YES) + reduction_expr = gfc_get_operator_expr (&where, + INTRINSIC_OR, + NULL, NULL); + + else if (gfc_match (".eqv.") == MATCH_YES) + reduction_expr = gfc_get_operator_expr (&where, + INTRINSIC_EQV, + NULL, NULL); + + else if (gfc_match (".neqv.") == MATCH_YES) + reduction_expr = gfc_get_operator_expr (&where, + INTRINSIC_NEQV, + NULL, NULL); + + else if (gfc_match ("min") == MATCH_YES) + { + reduction_expr = gfc_get_expr (); + reduction_expr->expr_type = EXPR_FUNCTION; + reduction_expr->value.function.isym + = gfc_intrinsic_function_by_id (GFC_ISYM_MIN); + reduction_expr->where = where; + } + + else if (gfc_match ("max") == MATCH_YES) + { + reduction_expr = gfc_get_expr (); + reduction_expr->expr_type = EXPR_FUNCTION; + reduction_expr->value.function.isym + = gfc_intrinsic_function_by_id (GFC_ISYM_MAX); + reduction_expr->where = where; + } + + else if (gfc_match ("iand") == MATCH_YES) + { + reduction_expr = gfc_get_expr (); + reduction_expr->expr_type = EXPR_FUNCTION; + reduction_expr->value.function.isym + = gfc_intrinsic_function_by_id (GFC_ISYM_IAND); + reduction_expr->where = where; + } + + else if (gfc_match ("ior") == MATCH_YES) + { + reduction_expr = gfc_get_expr (); + reduction_expr->expr_type = EXPR_FUNCTION; + reduction_expr->value.function.isym + = gfc_intrinsic_function_by_id (GFC_ISYM_IOR); + reduction_expr->where = where; + } + + else if (gfc_match ("ieor") == MATCH_YES) + { + reduction_expr = gfc_get_expr (); + reduction_expr->expr_type = EXPR_FUNCTION; + reduction_expr->value.function.isym + = gfc_intrinsic_function_by_id (GFC_ISYM_IEOR); + reduction_expr->where = where; + } + + else + { + gfc_error ("Expected reduction operator or function name " + "at %C"); + goto concurr_cleanup; + } + + if (!reduce) + { + reduce = reduce_tail = gfc_get_expr_list (); + } + else + { + reduce_tail->next = gfc_get_expr_list (); + reduce_tail = reduce_tail->next; + } + reduce_tail->expr = reduction_expr; + + gfc_gobble_whitespace (); + + if (gfc_match_char (':') != MATCH_YES) + { + gfc_error ("Expected %<:%> at %C"); + goto concurr_cleanup; + } + + while (true) + { + gfc_expr *reduction_expr; + + if (gfc_match_variable (&reduction_expr, 0) != MATCH_YES) + { + gfc_error ("Expected variable name in reduction list " + "at %C"); + goto concurr_cleanup; + } + + if (reduce == NULL) + reduce = reduce_tail = gfc_get_expr_list (); + else + { + reduce_tail = reduce_tail->next = gfc_get_expr_list (); + reduce_tail->expr = reduction_expr; + } + + if (gfc_match_char (',') == MATCH_YES) + continue; + else if (gfc_match_char (')') == MATCH_YES) + break; + else + { + gfc_error ("Expected ',' or ')' in reduction list " + "at %C"); + goto concurr_cleanup; + } + } + + if (!gfc_notify_std (GFC_STD_F2023, "REDUCE locality spec at " + "%L", &where)) + goto concurr_cleanup; + } + else + goto concurr_cleanup; + + if (!gfc_notify_std (GFC_STD_F2018, "Locality spec at %L", + &gfc_current_locus)) + goto concurr_cleanup; + } + if (m == MATCH_NO) return m; if (m == MATCH_ERROR) @@ -2667,14 +2930,26 @@ gfc_match_do (void) new_st.label1 = label; new_st.op = EXEC_DO_CONCURRENT; new_st.expr1 = mask; - new_st.ext.forall_iterator = head; + new_st.ext.concur.forall_iterator = head; + new_st.ext.concur.locality[LOCALITY_LOCAL] = local; + new_st.ext.concur.locality[LOCALITY_LOCAL_INIT] = local_init; + new_st.ext.concur.locality[LOCALITY_SHARED] = shared; + new_st.ext.concur.locality[LOCALITY_REDUCE] = reduce; + new_st.ext.concur.default_none = default_none; return MATCH_YES; concurr_cleanup: - gfc_syntax_error (ST_DO); gfc_free_expr (mask); gfc_free_forall_iterator (head); + gfc_free_expr_list (local); + gfc_free_expr_list (local_init); + gfc_free_expr_list (shared); + gfc_free_expr_list (reduce); + + if (!gfc_error_check ()) + gfc_syntax_error (ST_DO); + return MATCH_ERROR; } @@ -2685,6 +2960,7 @@ concurr_cleanup: goto done; } +match_do_loop: /* The abortive DO WHILE may have done something to the symbol table, so we start over. */ gfc_undo_symbols (); diff --git a/gcc/fortran/parse.cc b/gcc/fortran/parse.cc index b28c8a94547..739d824e831 100644 --- a/gcc/fortran/parse.cc +++ b/gcc/fortran/parse.cc @@ -5358,7 +5358,7 @@ parse_do_block (void) if (do_op == EXEC_DO_CONCURRENT) { gfc_forall_iterator *fa; - for (fa = new_st.ext.forall_iterator; fa; fa = fa->next) + for (fa = new_st.ext.concur.forall_iterator; fa; fa = fa->next) { /* Apply unroll only to innermost loop (first control variable). */ diff --git a/gcc/fortran/resolve.cc b/gcc/fortran/resolve.cc index 4f4fafa4217..b0eed12afed 100644 --- a/gcc/fortran/resolve.cc +++ b/gcc/fortran/resolve.cc @@ -54,6 +54,13 @@ code_stack; static code_stack *cs_base = NULL; +struct check_default_none_data +{ + gfc_code *code; + hash_set<gfc_symbol *> *sym_hash; + gfc_namespace *ns; + bool default_none; +}; /* Nonzero if we're inside a FORALL or DO CONCURRENT block. */ @@ -7794,6 +7801,344 @@ find_forall_index (gfc_expr *expr, gfc_symbol *sym, int f) return false; } +/* Check compliance with Fortran 2023's C1133 constraint for DO CONCURRENT + This constraint specifies rules for variables in locality-specs. */ + +static int +do_concur_locality_specs_f2023 (gfc_expr **expr, int *walk_subtrees, void *data) +{ + struct check_default_none_data *dt = (struct check_default_none_data *) data; + + if ((*expr)->expr_type == EXPR_VARIABLE) + { + gfc_symbol *sym = (*expr)->symtree->n.sym; + for (gfc_expr_list *list = dt->code->ext.concur.locality[LOCALITY_LOCAL]; + list; list = list->next) + { + if (list->expr->symtree->n.sym == sym) + { + gfc_error ("Variable %qs referenced in concurrent-header at %L " + "must not appear in LOCAL locality-spec at %L", + sym->name, &(*expr)->where, &list->expr->where); + *walk_subtrees = 0; + return 1; + } + } + } + + *walk_subtrees = 1; + return 0; +} + +static int +check_default_none_expr (gfc_expr **e, int *, void *data) +{ + struct check_default_none_data *d = (struct check_default_none_data*) data; + + if ((*e)->expr_type == EXPR_VARIABLE) + { + gfc_symbol *sym = (*e)->symtree->n.sym; + + if (d->sym_hash->contains (sym)) + sym->mark = 1; + + else if (d->default_none) + { + gfc_namespace *ns2 = d->ns; + while (ns2) + { + if (ns2 == sym->ns) + break; + ns2 = ns2->parent; + } + if (ns2 != NULL) + { + gfc_error ("Variable %qs at %L not specified in a locality spec " + "of DO CONCURRENT at %L but required due to " + "DEFAULT(NONE)", + sym->name, &(*e)->where, &d->code->loc); + d->sym_hash->add (sym); + } + } + } + return 0; +} + +static void +resolve_locality_spec (gfc_code *code, gfc_namespace *ns) +{ + struct check_default_none_data data; + data.code = code; + data.sym_hash = new hash_set<gfc_symbol *>; + data.ns = ns; + data.default_none = code->ext.concur.default_none; + + for (int locality = 0; locality < LOCALITY_NUM; locality++) + { + const char *name; + switch (locality) + { + case LOCALITY_LOCAL: name = "LOCAL"; break; + case LOCALITY_LOCAL_INIT: name = "LOCAL_INIT"; break; + case LOCALITY_SHARED: name = "SHARED"; break; + case LOCALITY_REDUCE: name = "REDUCE"; break; + default: gcc_unreachable (); + } + + for (gfc_expr_list *list = code->ext.concur.locality[locality]; list; + list = list->next) + { + gfc_expr *expr = list->expr; + + if (locality == LOCALITY_REDUCE + && (expr->expr_type == EXPR_FUNCTION + || expr->expr_type == EXPR_OP)) + continue; + + if (!gfc_resolve_expr (expr)) + continue; + + if (expr->expr_type != EXPR_VARIABLE + || expr->symtree->n.sym->attr.flavor != FL_VARIABLE + || (expr->ref + && (expr->ref->type != REF_ARRAY + || expr->ref->u.ar.type != AR_FULL + || expr->ref->next))) + { + gfc_error ("Expected variable name in %s locality spec at %L", + name, &expr->where); + continue; + } + + gfc_symbol *sym = expr->symtree->n.sym; + + if (data.sym_hash->contains (sym)) + { + gfc_error ("Variable %qs at %L has already been specified in a " + "locality-spec", sym->name, &expr->where); + continue; + } + + for (gfc_forall_iterator *iter = code->ext.concur.forall_iterator; + iter; iter = iter->next) + { + if (iter->var->symtree->n.sym == sym) + { + gfc_error ("Index variable %qs at %L cannot be specified in a" + "locality-spec", sym->name, &expr->where); + continue; + } + + data.sym_hash->add (iter->var->symtree->n.sym); + } + + if (locality == LOCALITY_LOCAL + || locality == LOCALITY_LOCAL_INIT + || locality == LOCALITY_REDUCE) + { + if (sym->attr.optional) + gfc_error ("OPTIONAL attribute not permitted for %qs in %s " + "locality-spec at %L", + sym->name, name, &expr->where); + + if (sym->attr.dimension + && sym->as + && sym->as->type == AS_ASSUMED_SIZE) + gfc_error ("Assumed-size array not permitted for %qs in %s " + "locality-spec at %L", + sym->name, name, &expr->where); + + gfc_check_vardef_context (expr, false, false, false, name); + } + + if (locality == LOCALITY_LOCAL + || locality == LOCALITY_LOCAL_INIT) + { + symbol_attribute attr = gfc_expr_attr (expr); + + if (attr.allocatable) + gfc_error ("ALLOCATABLE attribute not permitted for %qs in %s " + "locality-spec at %L", + sym->name, name, &expr->where); + + else if (expr->ts.type == BT_CLASS && attr.dummy && !attr.pointer) + gfc_error ("Nonpointer polymorphic dummy argument not permitted" + " for %qs in %s locality-spec at %L", + sym->name, name, &expr->where); + + else if (attr.codimension) + gfc_error ("Coarray not permitted for %qs in %s locality-spec " + "at %L", + sym->name, name, &expr->where); + + else if (expr->ts.type == BT_DERIVED + && gfc_is_finalizable (expr->ts.u.derived, NULL)) + gfc_error ("Finalizable type not permitted for %qs in %s " + "locality-spec at %L", + sym->name, name, &expr->where); + + else if (gfc_has_ultimate_allocatable (expr)) + gfc_error ("Type with ultimate allocatable component not " + "permitted for %qs in %s locality-spec at %L", + sym->name, name, &expr->where); + } + + else if (locality == LOCALITY_REDUCE) + { + if (sym->attr.asynchronous) + gfc_error ("ASYNCHRONOUS attribute not permitted for %qs in " + "REDUCE locality-spec at %L", + sym->name, &expr->where); + if (sym->attr.volatile_) + gfc_error ("VOLATILE attribute not permitted for %qs in REDUCE " + "locality-spec at %L", sym->name, &expr->where); + } + + data.sym_hash->add (sym); + } + + if (locality == LOCALITY_LOCAL) + { + gcc_assert (locality == 0); + + for (gfc_forall_iterator *iter = code->ext.concur.forall_iterator; + iter; iter = iter->next) + { + gfc_expr_walker (&iter->start, + do_concur_locality_specs_f2023, + &data); + + gfc_expr_walker (&iter->end, + do_concur_locality_specs_f2023, + &data); + + gfc_expr_walker (&iter->stride, + do_concur_locality_specs_f2023, + &data); + } + + if (code->expr1) + gfc_expr_walker (&code->expr1, + do_concur_locality_specs_f2023, + &data); + } + } + + gfc_expr *reduce_op = NULL; + + for (gfc_expr_list *list = code->ext.concur.locality[LOCALITY_REDUCE]; + list; list = list->next) + { + gfc_expr *expr = list->expr; + + if (expr->expr_type != EXPR_VARIABLE) + { + reduce_op = expr; + continue; + } + + if (reduce_op->expr_type == EXPR_OP) + { + switch (reduce_op->value.op.op) + { + case INTRINSIC_PLUS: + case INTRINSIC_TIMES: + if (!gfc_numeric_ts (&expr->ts)) + gfc_error ("Expected numeric type for %qs in REDUCE at %L, " + "got %s", expr->symtree->n.sym->name, + &expr->where, gfc_basic_typename (expr->ts.type)); + break; + case INTRINSIC_AND: + case INTRINSIC_OR: + case INTRINSIC_EQV: + case INTRINSIC_NEQV: + if (expr->ts.type != BT_LOGICAL) + gfc_error ("Expected logical type for %qs in REDUCE at %L, " + "got %qs", expr->symtree->n.sym->name, + &expr->where, gfc_basic_typename (expr->ts.type)); + break; + default: + gcc_unreachable (); + } + } + + else if (reduce_op->expr_type == EXPR_FUNCTION) + { + switch (reduce_op->value.function.isym->id) + { + case GFC_ISYM_MIN: + case GFC_ISYM_MAX: + if (expr->ts.type != BT_INTEGER + && expr->ts.type != BT_REAL + && expr->ts.type != BT_CHARACTER) + gfc_error ("Expected INTEGER, REAL or CHARACTER type for %qs " + "in REDUCE with MIN/MAX at %L, got %s", + expr->symtree->n.sym->name, &expr->where, + gfc_basic_typename (expr->ts.type)); + break; + case GFC_ISYM_IAND: + case GFC_ISYM_IOR: + case GFC_ISYM_IEOR: + if (expr->ts.type != BT_INTEGER) + gfc_error ("Expected integer type for %qs in REDUCE with " + "IAND/IOR/IEOR at %L, got %s", + expr->symtree->n.sym->name, &expr->where, + gfc_basic_typename (expr->ts.type)); + break; + default: + gcc_unreachable (); + } + } + + else + gcc_unreachable (); + } + + for (int locality = 0; locality < LOCALITY_NUM; locality++) + { + for (gfc_expr_list *list = code->ext.concur.locality[locality]; list; + list = list->next) + { + if (list->expr->expr_type == EXPR_VARIABLE) + list->expr->symtree->n.sym->mark = 0; + } + } + + gfc_code_walker (&code->block->next, gfc_dummy_code_callback, + check_default_none_expr, &data); + + for (int locality = 0; locality < LOCALITY_NUM; locality++) + { + gfc_expr_list **plist = &code->ext.concur.locality[locality]; + while (*plist) + { + gfc_expr *expr = (*plist)->expr; + if (expr->expr_type == EXPR_VARIABLE) + { + gfc_symbol *sym = expr->symtree->n.sym; + if (sym->mark == 0) + { + gfc_warning (OPT_Wunused_variable, "Variable %qs in " + "locality-spec at %L is not used", + sym->name, &expr->where); + gfc_expr_list *tmp = *plist; + *plist = (*plist)->next; + gfc_free_expr (tmp->expr); + free (tmp); + continue; + } + } + plist = &((*plist)->next); + } + } + + if (code->ext.concur.locality[LOCALITY_LOCAL] + || code->ext.concur.locality[LOCALITY_LOCAL_INIT]) + { + gfc_error ("Sorry, LOCAL and LOCAL_INIT are not yet supported for " + "%<do concurrent%> constructs at %L", &code->loc); + } +} /* Resolve a list of FORALL iterators. The FORALL index-name is constrained to be a scalar INTEGER variable. The subscripts and stride are scalar @@ -11181,7 +11526,7 @@ gfc_count_forall_iterators (gfc_code *code) max_iters = 0; current_iters = 0; - for (fa = code->ext.forall_iterator; fa; fa = fa->next) + for (fa = code->ext.concur.forall_iterator; fa; fa = fa->next) current_iters ++; code = code->block->next; @@ -11231,7 +11576,7 @@ gfc_resolve_forall (gfc_code *code, gfc_namespace *ns, int forall_save) /* The information about FORALL iterator, including FORALL indices start, end and stride. An outer FORALL indice cannot appear in start, end or stride. */ - for (fa = code->ext.forall_iterator; fa; fa = fa->next) + for (fa = code->ext.concur.forall_iterator; fa; fa = fa->next) { /* Fortran 20008: C738 (R753). */ if (fa->var->ref && fa->var->ref->type == REF_ARRAY) @@ -13021,12 +13366,15 @@ start: case EXEC_DO_CONCURRENT: case EXEC_FORALL: - resolve_forall_iterators (code->ext.forall_iterator); + resolve_forall_iterators (code->ext.concur.forall_iterator); if (code->expr1 != NULL && (code->expr1->ts.type != BT_LOGICAL || code->expr1->rank)) gfc_error ("FORALL mask clause at %L requires a scalar LOGICAL " "expression", &code->expr1->where); + + if (code->op == EXEC_DO_CONCURRENT) + resolve_locality_spec (code, ns); break; case EXEC_OACC_PARALLEL_LOOP: diff --git a/gcc/fortran/st.cc b/gcc/fortran/st.cc index 0218d290782..63ef5ccb9d0 100644 --- a/gcc/fortran/st.cc +++ b/gcc/fortran/st.cc @@ -189,8 +189,11 @@ gfc_free_statement (gfc_code *p) break; case EXEC_DO_CONCURRENT: + for (int i = 0; i < LOCALITY_NUM; i++) + gfc_free_expr_list (p->ext.concur.locality[i]); + gcc_fallthrough (); case EXEC_FORALL: - gfc_free_forall_iterator (p->ext.forall_iterator); + gfc_free_forall_iterator (p->ext.concur.forall_iterator); break; case EXEC_OACC_DECLARE: diff --git a/gcc/fortran/trans-stmt.cc b/gcc/fortran/trans-stmt.cc index 93b633e212e..d5cef554a1e 100644 --- a/gcc/fortran/trans-stmt.cc +++ b/gcc/fortran/trans-stmt.cc @@ -5063,7 +5063,7 @@ gfc_trans_forall_1 (gfc_code * code, forall_info * nested_forall_info) n = 0; /* Count the FORALL index number. */ - for (fa = code->ext.forall_iterator; fa; fa = fa->next) + for (fa = code->ext.concur.forall_iterator; fa; fa = fa->next) n++; nvar = n; @@ -5083,7 +5083,7 @@ gfc_trans_forall_1 (gfc_code * code, forall_info * nested_forall_info) gfc_init_block (&block); n = 0; - for (fa = code->ext.forall_iterator; fa; fa = fa->next) + for (fa = code->ext.concur.forall_iterator; fa; fa = fa->next) { gfc_symbol *sym = fa->var->symtree->n.sym; @@ -5344,7 +5344,7 @@ gfc_trans_forall_1 (gfc_code * code, forall_info * nested_forall_info) done: /* Restore the original index variables. */ - for (fa = code->ext.forall_iterator, n = 0; fa; fa = fa->next, n++) + for (fa = code->ext.concur.forall_iterator, n = 0; fa; fa = fa->next, n++) gfc_restore_sym (fa->var->symtree->n.sym, &saved_vars[n]); /* Free the space for var, start, end, step, varexpr. */ diff --git a/gcc/testsuite/gfortran.dg/do_concurrent_10.f90 b/gcc/testsuite/gfortran.dg/do_concurrent_10.f90 new file mode 100644 index 00000000000..6bbeb3bc990 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/do_concurrent_10.f90 @@ -0,0 +1,11 @@ +! { dg-do compile } +! { dg-options "-std=f2018" } + +program do_concurrent_parsing + implicit none + integer :: concurrent, do + do concurrent = 1, 5 + end do + do concurrent = 1, 5 + end do +end program do_concurrent_parsing diff --git a/gcc/testsuite/gfortran.dg/do_concurrent_8_f2018.f90 b/gcc/testsuite/gfortran.dg/do_concurrent_8_f2018.f90 new file mode 100644 index 00000000000..7449026dea8 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/do_concurrent_8_f2018.f90 @@ -0,0 +1,19 @@ +! { dg-do compile } +! { dg-options "-std=f2018" } +program do_concurrent_complex + implicit none + integer :: i, j, k, sum, product + integer, dimension(10,10,10) :: array + sum = 0 + product = 1 + do concurrent (i = 1:10) local(j) shared(sum) reduce(+:sum) ! { dg-error "Fortran 2023: REDUCE locality spec" } + do concurrent (j = 1:10) local(k) shared(product) reduce(*:product) ! { dg-error "Fortran 2023: REDUCE locality spec" } + do concurrent (k = 1:10) + array(i,j,k) = i * j * k + sum = sum + array(i,j,k) + product = product * array(i,j,k) + end do + end do ! { dg-error "Expecting END PROGRAM statement" } + end do ! { dg-error "Expecting END PROGRAM statement" } + print *, sum, product +end program do_concurrent_complex \ No newline at end of file diff --git a/gcc/testsuite/gfortran.dg/do_concurrent_8_f2023.f90 b/gcc/testsuite/gfortran.dg/do_concurrent_8_f2023.f90 new file mode 100644 index 00000000000..a99d81e4a5c --- /dev/null +++ b/gcc/testsuite/gfortran.dg/do_concurrent_8_f2023.f90 @@ -0,0 +1,23 @@ +! { dg-do compile } +! { dg-options "-std=gnu" } +program do_concurrent_complex + implicit none + integer :: i, j, k, sum, product + integer, dimension(10,10,10) :: array + sum = 0 + product = 1 + do concurrent (i = 1:10) local(j) shared(sum) reduce(+:sum) + ! { dg-error "Variable .sum. at .1. has already been specified in a locality-spec" "" { target *-*-* } .-1 } + ! { dg-error "Sorry, LOCAL and LOCAL_INIT are not yet supported for 'do concurrent' constructs" "" { target *-*-* } .-2 } + do concurrent (j = 1:10) local(k) shared(product) reduce(*:product) + ! { dg-error "Variable .product. at .1. has already been specified in a locality-spec" "" { target *-*-* } .-1 } + ! { dg-error "Sorry, LOCAL and LOCAL_INIT are not yet supported for 'do concurrent' constructs" "" { target *-*-* } .-2 } + do concurrent (k = 1:10) + array(i,j,k) = i * j * k + sum = sum + array(i,j,k) + product = product * array(i,j,k) + end do + end do + end do + print *, sum, product +end program do_concurrent_complex \ No newline at end of file diff --git a/gcc/testsuite/gfortran.dg/do_concurrent_9.f90 b/gcc/testsuite/gfortran.dg/do_concurrent_9.f90 new file mode 100644 index 00000000000..86bc2b3ea0b --- /dev/null +++ b/gcc/testsuite/gfortran.dg/do_concurrent_9.f90 @@ -0,0 +1,15 @@ +! { dg-do compile } +! { dg-options "-std=f2018" } +program do_concurrent_default_none + implicit none + integer :: i, x, y, z + x = 0 + y = 0 + z = 0 + do concurrent (i = 1:10) default(none) shared(x) local(y) ! { dg-error "Sorry, LOCAL and LOCAL_INIT are not yet supported" } + ! { dg-error "Variable 'z' .* not specified in a locality spec .* but required due to DEFAULT\\(NONE\\)" "" { target *-*-* } .-1 } + x = x + i + y = i * 2 + z = z + 1 ! { dg-error "Variable 'z' .* not specified in a locality spec .* but required due to DEFAULT\\(NONE\\)" } + end do +end program do_concurrent_default_none \ No newline at end of file diff --git a/gcc/testsuite/gfortran.dg/do_concurrent_all_clauses.f90 b/gcc/testsuite/gfortran.dg/do_concurrent_all_clauses.f90 new file mode 100644 index 00000000000..98e4b872839 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/do_concurrent_all_clauses.f90 @@ -0,0 +1,26 @@ +! { dg-do compile } +program do_concurrent_all_clauses + implicit none + integer :: i, arr(10), sum, max_val, temp, squared + sum = 0 + max_val = 0 + + do concurrent (i = 1:10, i <= 8) & + default(none) & + local(temp) & + shared(arr, squared, sum, max_val) & + reduce(+:sum) & ! { dg-error "Variable 'sum' at \\(1\\) has already been specified in a locality-spec" } + reduce(max:max_val) ! { dg-error "Variable 'max_val' at \\(1\\) has already been specified in a locality-spec" } + ! { dg-error "Sorry, LOCAL and LOCAL_INIT are not yet supported" "" { target *-*-* } .-1 } + block + integer :: temp2 + temp = i * 2 + temp2 = temp * 2 + squared = i * i + arr(i) = temp2 + squared + sum = sum + arr(i) + max_val = max(max_val, arr(i)) + end block + end do + print *, arr, sum, max_val +end program do_concurrent_all_clauses \ No newline at end of file diff --git a/gcc/testsuite/gfortran.dg/do_concurrent_basic.f90 b/gcc/testsuite/gfortran.dg/do_concurrent_basic.f90 new file mode 100644 index 00000000000..fe8723d48b4 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/do_concurrent_basic.f90 @@ -0,0 +1,11 @@ +! { dg-do run } +program basic_do_concurrent + implicit none + integer :: i, arr(10) + + do concurrent (i = 1:10) + arr(i) = i + end do + + print *, arr +end program basic_do_concurrent \ No newline at end of file diff --git a/gcc/testsuite/gfortran.dg/do_concurrent_constraints.f90 b/gcc/testsuite/gfortran.dg/do_concurrent_constraints.f90 new file mode 100644 index 00000000000..5716fc30b86 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/do_concurrent_constraints.f90 @@ -0,0 +1,126 @@ +! { dg-do compile } +! { dg-options "-fcoarray=single" } + +module m + type t1 + integer, allocatable :: x + end type t1 + + type t2 + type(t1), allocatable :: y + end type t2 + + type, abstract :: abstract_type + end type abstract_type + +contains + subroutine test_c1130(a, b, c, d, e, f, g, h, j) + integer, allocatable :: a + integer, intent(in) :: b + integer, optional :: c + type(t1) :: d + real :: e[*] + integer :: f(*) + type(t2) :: g + class(abstract_type), pointer :: h + class(abstract_type) :: j + integer :: i + + ! C1130 tests + do concurrent (i=1:5) local(a) ! { dg-error "ALLOCATABLE attribute not permitted for 'a' in LOCAL locality-spec" } + end do + do concurrent (i=1:5) local(b) ! { dg-error "Dummy argument 'b' with INTENT\\(IN\\) in variable definition context \\(LOCAL\\) at" } + end do + do concurrent (i=1:5) local(c) ! { dg-error "OPTIONAL attribute not permitted for 'c' in LOCAL locality-spec" } + end do + do concurrent (i=1:5) local(d) ! { dg-error "Type with ultimate allocatable component not permitted for 'd' in LOCAL locality-spec" } + end do + do concurrent (i=1:5) local(e) ! { dg-error "Expected variable name in LOCAL locality spec" } + end do + do concurrent (i=1:5) local(f) ! { dg-error "The upper bound in the last dimension must appear in the reference to the assumed size array 'f'" } + end do + do concurrent (i=1:5) local(g) ! { dg-error "Type with ultimate allocatable component not permitted for 'g' in LOCAL locality-spec" } + end do + do concurrent (i=1:5) local(h) + end do + do concurrent (i=1:5) local(j) ! { dg-error "Nonpointer polymorphic dummy argument not permitted for 'j' in LOCAL locality-spec" } + end do + + ! LOCAL_INIT tests + do concurrent (i=1:5) local_init(a) ! { dg-error "ALLOCATABLE attribute not permitted for 'a' in LOCAL_INIT locality-spec" } + end do + do concurrent (i=1:5) local_init(b) ! { dg-error "Dummy argument 'b' with INTENT\\(IN\\) in variable definition context \\(LOCAL_INIT\\) at" } + end do + do concurrent (i=1:5) local_init(c) ! { dg-error "OPTIONAL attribute not permitted for 'c' in LOCAL_INIT locality-spec" } + end do + do concurrent (i=1:5) local_init(d) ! { dg-error "Type with ultimate allocatable component not permitted for 'd' in LOCAL_INIT locality-spec" } + end do + do concurrent (i=1:5) local_init(e) ! { dg-error "Expected variable name in LOCAL_INIT locality spec" } + end do + do concurrent (i=1:5) local_init(f) ! { dg-error "The upper bound in the last dimension must appear in the reference to the assumed size array 'f'" } + end do + do concurrent (i=1:5) local_init(g) ! { dg-error "Type with ultimate allocatable component not permitted for 'g' in LOCAL_INIT locality-spec" } + end do + do concurrent (i=1:5) local_init(h) + end do + do concurrent (i=1:5) local_init(j) ! { dg-error "Nonpointer polymorphic dummy argument not permitted for 'j' in LOCAL_INIT locality-spec" } + end do + end subroutine test_c1130 + + subroutine test_c1131(a, b, c, d, e, f, g) + integer, asynchronous :: a + integer, intent(in) :: b + integer, optional :: c + integer, volatile :: d + real :: e[*] + integer :: f(*) + real :: g(3)[*] + integer :: i + + ! C1131 tests + do concurrent (i=1:5) reduce(+:a) ! { dg-error "ASYNCHRONOUS attribute not permitted for 'a' in REDUCE locality-spec" } + end do + do concurrent (i=1:5) reduce(+:b) + ! { dg-error "Dummy argument 'b' with INTENT\\(IN\\) in variable definition context \\(REDUCE\\)" "" { target *-*-* } .-1 } + end do + do concurrent (i=1:5) reduce(+:c) ! { dg-error "OPTIONAL attribute not permitted for 'c' in REDUCE locality-spec" } + end do + do concurrent (i=1:5) reduce(+:d) ! { dg-error "VOLATILE attribute not permitted for 'd' in REDUCE locality-spec" } + end do + do concurrent (i=1:5) reduce(+:e) ! { dg-error "Expected variable name in REDUCE locality spec" } + end do + do concurrent (i=1:5) reduce(+:f) ! { dg-error "The upper bound in the last dimension must appear in the reference to the assumed size array 'f'" } + end do + do concurrent (i=1:5) reduce(+:g(2)[1]) ! { dg-error "Expected variable name in REDUCE locality spec" } + end do + end subroutine test_c1131 + + subroutine test_c1132() + logical :: l1, l2, l3, l4 + integer :: i, int1 + real :: r1 + complex :: c1, c2, c3 + character(len=10) :: str1, str2, str3, str4 + + ! C1132 tests + do concurrent (i=1:5) & + reduce(+:l1) & ! { dg-error "Expected numeric type for 'l1' in REDUCE at \\(1\\), got LOGICAL" } + reduce(*:l2) & ! { dg-error "Expected numeric type for 'l2' in REDUCE at \\(1\\), got LOGICAL" } + reduce(max:l3) & ! { dg-error "Expected INTEGER, REAL or CHARACTER type for 'l3' in REDUCE with MIN/MAX at \\(1\\), got LOGICAL" } + reduce(iand:l4) ! { dg-error "Expected integer type for 'l4' in REDUCE with IAND/IOR/IEOR at \\(1\\), got LOGICAL" } + end do + + do concurrent (i=1:5) & + reduce(*:str2) & ! { dg-error "Expected numeric type for 'str2' in REDUCE at \\(1\\), got CHARACTER" } + reduce(min:str3) & ! OK + reduce(max:str4) ! OK + end do + + do concurrent (i=1:5) & + reduce(*:c2) & ! OK + reduce(max:c3) ! { dg-error "Expected INTEGER, REAL or CHARACTER type for 'c3' in REDUCE with MIN/MAX at \\(1\\), got COMPLEX" } + end do + + end subroutine test_c1132 + +end module m \ No newline at end of file diff --git a/gcc/testsuite/gfortran.dg/do_concurrent_local_init.f90 b/gcc/testsuite/gfortran.dg/do_concurrent_local_init.f90 new file mode 100644 index 00000000000..08e1fb92e64 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/do_concurrent_local_init.f90 @@ -0,0 +1,11 @@ +! { dg-do compile } +! { dg-options "-fmax-errors=1" } +program do_concurrent_local_init + implicit none + integer :: i, arr(10), temp + do concurrent (i = 1:10) local_init(temp) ! { dg-error "LOCAL and LOCAL_INIT are not yet supported for 'do concurrent' constructs" } + temp = i + arr(i) = temp + end do + print *, arr +end program do_concurrent_local_init \ No newline at end of file diff --git a/gcc/testsuite/gfortran.dg/do_concurrent_locality_specs.f90 b/gcc/testsuite/gfortran.dg/do_concurrent_locality_specs.f90 new file mode 100644 index 00000000000..0ee7a7e53b7 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/do_concurrent_locality_specs.f90 @@ -0,0 +1,14 @@ +! { dg-additional-options "-Wunused-variable" } +implicit none +integer :: i, j, k, ll +integer :: jj, kk, lll +do , concurrent (i = 1:5) shared(j,jj) local(k,kk) local_init(ll,lll) + ! { dg-warning "Variable 'kk' in locality-spec at \\(1\\) is not used \\\[-Wunused-variable\\\]" "" { target *-*-* } .-1 } + ! { dg-warning "Variable 'll' in locality-spec at \\(1\\) is not used \\\[-Wunused-variable\\\]" "" { target *-*-* } .-2 } + ! { dg-warning "Variable 'jj' in locality-spec at \\(1\\) is not used \\\[-Wunused-variable\\\]" "" { target *-*-* } .-3 } + ! { dg-error "Sorry, LOCAL and LOCAL_INIT are not yet supported for 'do concurrent' constructs" "" { target *-*-* } .-4 } + j = 5 + k = 7 + lll = 8 +end do +end \ No newline at end of file diff --git a/gcc/testsuite/gfortran.dg/do_concurrent_multiple_reduce.f90 b/gcc/testsuite/gfortran.dg/do_concurrent_multiple_reduce.f90 new file mode 100644 index 00000000000..47c71492107 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/do_concurrent_multiple_reduce.f90 @@ -0,0 +1,17 @@ +! { dg-do compile } +program do_concurrent_multiple_reduce + implicit none + integer :: i, arr(10), sum, product + sum = 0 + product = 1 + + do concurrent (i = 1:10) reduce(+:sum) reduce(*:product) + arr(i) = i + sum = sum + i + product = product * i + end do + + print *, arr + print *, "Sum:", sum + print *, "Product:", product +end program do_concurrent_multiple_reduce \ No newline at end of file diff --git a/gcc/testsuite/gfortran.dg/do_concurrent_nested.f90 b/gcc/testsuite/gfortran.dg/do_concurrent_nested.f90 new file mode 100644 index 00000000000..83b9cdbc04f --- /dev/null +++ b/gcc/testsuite/gfortran.dg/do_concurrent_nested.f90 @@ -0,0 +1,26 @@ +! { dg-do compile } +program nested_do_concurrent + implicit none + integer :: i, j, x(10, 10) + integer :: total_sum + + total_sum = 0 + + ! Outer loop remains DO CONCURRENT + do concurrent (i = 1:10) + ! Inner loop changed to regular DO loop + do j = 1, 10 + x(i, j) = i * j + end do + end do + + ! Separate loops for summation + do i = 1, 10 + do j = 1, 10 + total_sum = total_sum + x(i, j) + end do + end do + + print *, "Total sum:", total_sum + print *, "Array:", x +end program nested_do_concurrent \ No newline at end of file diff --git a/gcc/testsuite/gfortran.dg/do_concurrent_parser.f90 b/gcc/testsuite/gfortran.dg/do_concurrent_parser.f90 new file mode 100644 index 00000000000..ec4ec6a7d0d --- /dev/null +++ b/gcc/testsuite/gfortran.dg/do_concurrent_parser.f90 @@ -0,0 +1,20 @@ +! { dg-do compile } +program do_concurrent_parser_errors + implicit none + integer :: i, x, b + do, concurrent (i=-3:4:2) default(none) shared(b) default(none) ! { dg-error "DEFAULT\\(NONE\\) specified more than once in DO CONCURRENT" } + b = i + end do ! { dg-error "Expecting END PROGRAM statement" } + do concurrent(i = 2 : 4) reduce(-:x) ! { dg-error "Expected reduction operator or function name" } + x = x - i + end do ! { dg-error "Expecting END PROGRAM statement" } + do concurrent(i = 2 : 4) reduce(+ x) ! { dg-error "Expected ':'" } + x = x + i + end do ! { dg-error "Expecting END PROGRAM statement" } + do concurrent(i = 2 : 4) reduce(+ , x) ! { dg-error "Expected ':'" } + x = x + i + end do ! { dg-error "Expecting END PROGRAM statement" } + do concurrent(i = 2 : 4) reduction(+: x) ! { dg-error "Syntax error in DO statement" } + x = x + i + end do ! { dg-error "Expecting END PROGRAM statement" } +end program do_concurrent_parser_errors \ No newline at end of file diff --git a/gcc/testsuite/gfortran.dg/do_concurrent_reduce_max.f90 b/gcc/testsuite/gfortran.dg/do_concurrent_reduce_max.f90 new file mode 100644 index 00000000000..ddf9626da7b --- /dev/null +++ b/gcc/testsuite/gfortran.dg/do_concurrent_reduce_max.f90 @@ -0,0 +1,14 @@ +! { dg-do compile } +program do_concurrent_reduce_max + implicit none + integer :: i, arr(10), max_val + max_val = 0 + + do concurrent (i = 1:10) reduce(max:max_val) + arr(i) = i * i + max_val = max(max_val, arr(i)) + end do + + print *, arr + print *, "Max value:", max_val +end program do_concurrent_reduce_max \ No newline at end of file diff --git a/gcc/testsuite/gfortran.dg/do_concurrent_reduce_sum.f90 b/gcc/testsuite/gfortran.dg/do_concurrent_reduce_sum.f90 new file mode 100644 index 00000000000..1165e0c5243 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/do_concurrent_reduce_sum.f90 @@ -0,0 +1,14 @@ +! { dg-do compile } +program do_concurrent_reduce_sum + implicit none + integer :: i, arr(10), sum + sum = 0 + + do concurrent (i = 1:10) reduce(+:sum) + arr(i) = i + sum = sum + i + end do + + print *, arr + print *, "Sum:", sum +end program do_concurrent_reduce_sum \ No newline at end of file diff --git a/gcc/testsuite/gfortran.dg/do_concurrent_shared.f90 b/gcc/testsuite/gfortran.dg/do_concurrent_shared.f90 new file mode 100644 index 00000000000..6e3dd1c883d --- /dev/null +++ b/gcc/testsuite/gfortran.dg/do_concurrent_shared.f90 @@ -0,0 +1,14 @@ +! { dg-do compile } +program do_concurrent_shared + implicit none + integer :: i, arr(10), sum + sum = 0 + + do concurrent (i = 1:10) shared(sum) + arr(i) = i + sum = sum + i + end do + + print *, arr + print *, "Sum:", sum +end program do_concurrent_shared \ No newline at end of file -- 2.43.0