diff --git a/gcc/c-family/c-omp.c b/gcc/c-family/c-omp.c index 1f07a0a454b..2849fdabc3d 100644 --- a/gcc/c-family/c-omp.c +++ b/gcc/c-family/c-omp.c @@ -2128,6 +2128,8 @@ c_omp_split_clauses (location_t loc, enum tree_code code, OMP_CLAUSE_ORDER); OMP_CLAUSE_ORDER_UNCONSTRAINED (c) = OMP_CLAUSE_ORDER_UNCONSTRAINED (clauses); + OMP_CLAUSE_ORDER_REPRODUCIBLE (c) + = OMP_CLAUSE_ORDER_REPRODUCIBLE (clauses); OMP_CLAUSE_CHAIN (c) = cclauses[C_OMP_CLAUSE_SPLIT_DISTRIBUTE]; cclauses[C_OMP_CLAUSE_SPLIT_DISTRIBUTE] = c; } @@ -2139,6 +2141,8 @@ c_omp_split_clauses (location_t loc, enum tree_code code, OMP_CLAUSE_ORDER); OMP_CLAUSE_ORDER_UNCONSTRAINED (c) = OMP_CLAUSE_ORDER_UNCONSTRAINED (clauses); + OMP_CLAUSE_ORDER_REPRODUCIBLE (c) + = OMP_CLAUSE_ORDER_REPRODUCIBLE (clauses); OMP_CLAUSE_CHAIN (c) = cclauses[C_OMP_CLAUSE_SPLIT_FOR]; cclauses[C_OMP_CLAUSE_SPLIT_FOR] = c; s = C_OMP_CLAUSE_SPLIT_SIMD; diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c index 21ff25d3b2c..a66f43f6dc2 100644 --- a/gcc/c/c-parser.c +++ b/gcc/c/c-parser.c @@ -14626,6 +14626,7 @@ c_parser_omp_clause_order (c_parser *parser, tree list) tree c; const char *p; bool unconstrained = false; + bool reproducible = false; matching_parens parens; if (!parens.require_open (parser)) @@ -14636,7 +14637,9 @@ c_parser_omp_clause_order (c_parser *parser, tree list) p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); if (strcmp (p, "unconstrained") == 0) unconstrained = true; - else if (strcmp (p, "reproducible") != 0) + else if (strcmp (p, "reproducible") == 0) + reproducible = true; + else { c_parser_error (parser, "expected % or " "%"); @@ -14661,6 +14664,7 @@ c_parser_omp_clause_order (c_parser *parser, tree list) check_no_duplicate_clause (list, OMP_CLAUSE_ORDER, "order"); c = build_omp_clause (loc, OMP_CLAUSE_ORDER); OMP_CLAUSE_ORDER_UNCONSTRAINED (c) = unconstrained; + OMP_CLAUSE_ORDER_REPRODUCIBLE (c) = reproducible; OMP_CLAUSE_CHAIN (c) = list; return c; diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 04f5a24cc03..c6f1a9796c5 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -37735,6 +37735,7 @@ cp_parser_omp_clause_order (cp_parser *parser, tree list, location_t location) tree c, id; const char *p; bool unconstrained = false; + bool reproducible = false; matching_parens parens; if (!parens.require_open (parser)) @@ -37747,7 +37748,9 @@ cp_parser_omp_clause_order (cp_parser *parser, tree list, location_t location) p = IDENTIFIER_POINTER (id); if (strcmp (p, "unconstrained") == 0) unconstrained = true; - else if (strcmp (p, "reproducible") != 0) + else if (strcmp (p, "reproducible") == 0) + reproducible = true; + else { cp_parser_error (parser, "expected % or " "%"); @@ -37778,6 +37781,7 @@ cp_parser_omp_clause_order (cp_parser *parser, tree list, location_t location) check_no_duplicate_clause (list, OMP_CLAUSE_ORDER, "order", location); c = build_omp_clause (location, OMP_CLAUSE_ORDER); OMP_CLAUSE_ORDER_UNCONSTRAINED (c) = unconstrained; + OMP_CLAUSE_ORDER_REPRODUCIBLE (c) = reproducible; OMP_CLAUSE_CHAIN (c) = list; return c; diff --git a/gcc/fortran/dump-parse-tree.c b/gcc/fortran/dump-parse-tree.c index 28eb09e261d..64e04c043f6 100644 --- a/gcc/fortran/dump-parse-tree.c +++ b/gcc/fortran/dump-parse-tree.c @@ -1634,6 +1634,8 @@ show_omp_clauses (gfc_omp_clauses *omp_clauses) fputs (" ORDER(", dumpfile); if (omp_clauses->order_unconstrained) fputs ("UNCONSTRAINED:", dumpfile); + else if (omp_clauses->order_reproducible) + fputs ("REPRODUCIBLE:", dumpfile); fputs ("CONCURRENT)", dumpfile); } if (omp_clauses->ordered) diff --git a/gcc/fortran/gfortran.h b/gcc/fortran/gfortran.h index 7ef835b211a..c25d1cca3a8 100644 --- a/gcc/fortran/gfortran.h +++ b/gcc/fortran/gfortran.h @@ -1491,8 +1491,8 @@ typedef struct gfc_omp_clauses unsigned inbranch:1, notinbranch:1, nogroup:1; unsigned sched_simd:1, sched_monotonic:1, sched_nonmonotonic:1; unsigned simd:1, threads:1, depend_source:1, destroy:1, order_concurrent:1; - unsigned order_unconstrained:1, capture:1, grainsize_strict:1; - unsigned num_tasks_strict:1; + unsigned order_unconstrained:1, order_reproducible:1, capture:1; + unsigned grainsize_strict:1, num_tasks_strict:1; ENUM_BITFIELD (gfc_omp_sched_kind) sched_kind:3; ENUM_BITFIELD (gfc_omp_device_type) device_type:2; ENUM_BITFIELD (gfc_omp_memorder) memorder:3; diff --git a/gcc/fortran/openmp.c b/gcc/fortran/openmp.c index 9ee52d6b0ea..6a4ca2868f8 100644 --- a/gcc/fortran/openmp.c +++ b/gcc/fortran/openmp.c @@ -2374,8 +2374,9 @@ gfc_match_omp_clauses (gfc_omp_clauses **cp, const omp_mask mask, { if (m == MATCH_ERROR) goto error; - if (gfc_match (" reproducible : concurrent )") == MATCH_YES - || gfc_match (" concurrent )") == MATCH_YES) + if (gfc_match (" reproducible : concurrent )") == MATCH_YES) + c->order_reproducible = true; + else if (gfc_match (" concurrent )") == MATCH_YES) ; else if (gfc_match (" unconstrained : concurrent )") == MATCH_YES) c->order_unconstrained = true; diff --git a/gcc/fortran/trans-openmp.c b/gcc/fortran/trans-openmp.c index 4ca2c3f9e7f..d234d1b070f 100644 --- a/gcc/fortran/trans-openmp.c +++ b/gcc/fortran/trans-openmp.c @@ -3804,6 +3804,7 @@ gfc_trans_omp_clauses (stmtblock_t *block, gfc_omp_clauses *clauses, { c = build_omp_clause (gfc_get_location (&where), OMP_CLAUSE_ORDER); OMP_CLAUSE_ORDER_UNCONSTRAINED (c) = clauses->order_unconstrained; + OMP_CLAUSE_ORDER_REPRODUCIBLE (c) = clauses->order_reproducible; omp_clauses = gfc_trans_add_clause (c, omp_clauses); } @@ -5895,6 +5896,8 @@ gfc_split_omp_clauses (gfc_code *code, = code->ext.omp_clauses->order_concurrent; clausesa[GFC_OMP_SPLIT_DISTRIBUTE].order_unconstrained = code->ext.omp_clauses->order_unconstrained; + clausesa[GFC_OMP_SPLIT_DISTRIBUTE].order_reproducible + = code->ext.omp_clauses->order_reproducible; } if (mask & GFC_OMP_MASK_PARALLEL) { @@ -5951,6 +5954,8 @@ gfc_split_omp_clauses (gfc_code *code, = code->ext.omp_clauses->order_concurrent; clausesa[GFC_OMP_SPLIT_DO].order_unconstrained = code->ext.omp_clauses->order_unconstrained; + clausesa[GFC_OMP_SPLIT_DO].order_reproducible + = code->ext.omp_clauses->order_reproducible; } if (mask & GFC_OMP_MASK_SIMD) { @@ -5969,6 +5974,8 @@ gfc_split_omp_clauses (gfc_code *code, = code->ext.omp_clauses->order_concurrent; clausesa[GFC_OMP_SPLIT_SIMD].order_unconstrained = code->ext.omp_clauses->order_unconstrained; + clausesa[GFC_OMP_SPLIT_SIMD].order_reproducible + = code->ext.omp_clauses->order_reproducible; /* And this is copied to all. */ clausesa[GFC_OMP_SPLIT_SIMD].if_expr = code->ext.omp_clauses->if_expr; diff --git a/gcc/omp-general.c b/gcc/omp-general.c index cc6aecb1d66..1e4c0b25531 100644 --- a/gcc/omp-general.c +++ b/gcc/omp-general.c @@ -193,6 +193,7 @@ omp_extract_for_data (gomp_for *for_stmt, struct omp_for_data *fd, == GF_OMP_FOR_KIND_DISTRIBUTE; bool taskloop = gimple_omp_for_kind (for_stmt) == GF_OMP_FOR_KIND_TASKLOOP; + bool order_reproducible = false; tree iterv, countv; fd->for_stmt = for_stmt; @@ -277,10 +278,25 @@ omp_extract_for_data (gomp_for *for_stmt, struct omp_for_data *fd, && !OMP_CLAUSE__SCANTEMP__CONTROL (t)) fd->have_nonctrl_scantemp = true; break; + case OMP_CLAUSE_ORDER: + /* FIXME: For OpenMP 5.2 this should change to + if (OMP_CLAUSE_ORDER_REPRODUCIBLE (t)) + (with the exception of loop construct but that lowers to + no schedule/dist_schedule clauses currently). */ + if (!OMP_CLAUSE_ORDER_UNCONSTRAINED (t)) + order_reproducible = true; default: break; } + /* For order(reproducible:concurrent) schedule ({dynamic,guided,runtime}) + we have either the option to expensively remember at runtime how we've + distributed work from first loop and reuse that in following loops with + the same number of iterations and schedule, or just force static schedule. + OpenMP API calls etc. aren't allowed in order(concurrent) bodies so + users can't observe it easily anyway. */ + if (order_reproducible) + fd->sched_kind = OMP_CLAUSE_SCHEDULE_STATIC; if (fd->collapse > 1 || fd->tiling) fd->loops = loops; else diff --git a/gcc/testsuite/gfortran.dg/gomp/order-5.f90 b/gcc/testsuite/gfortran.dg/gomp/order-5.f90 index 4d9e33642af..0dddb968cb4 100644 --- a/gcc/testsuite/gfortran.dg/gomp/order-5.f90 +++ b/gcc/testsuite/gfortran.dg/gomp/order-5.f90 @@ -116,14 +116,14 @@ subroutine f4 (a) end do end -! { dg-final { scan-tree-dump-times "#pragma omp distribute order\\(concurrent\\)" 6 "original"} } +! { dg-final { scan-tree-dump-times "#pragma omp distribute order\\(reproducible:concurrent\\)" 6 "original"} } ! { dg-final { scan-tree-dump-times "#pragma omp distribute order\\(unconstrained:concurrent\\)" 6 "original"} } -! { dg-final { scan-tree-dump-times "#pragma omp for nowait order\\(concurrent\\)" 6 "original"} } +! { dg-final { scan-tree-dump-times "#pragma omp for nowait order\\(reproducible:concurrent\\)" 6 "original"} } ! { dg-final { scan-tree-dump-times "#pragma omp for nowait order\\(unconstrained:concurrent\\)" 6 "original"} } -! { dg-final { scan-tree-dump-times "#pragma omp for order\\(concurrent\\)" 2 "original"} } +! { dg-final { scan-tree-dump-times "#pragma omp for order\\(reproducible:concurrent\\)" 2 "original"} } ! { dg-final { scan-tree-dump-times "#pragma omp for order\\(unconstrained:concurrent\\)" 2 "original"} } ! { dg-final { scan-tree-dump-times "#pragma omp parallel" 12 "original"} } -! { dg-final { scan-tree-dump-times "#pragma omp simd linear\\(i:1\\) order\\(concurrent\\)" 6 "original"} } +! { dg-final { scan-tree-dump-times "#pragma omp simd linear\\(i:1\\) order\\(reproducible:concurrent\\)" 6 "original"} } ! { dg-final { scan-tree-dump-times "#pragma omp simd linear\\(i:1\\) order\\(unconstrained:concurrent\\)" 6 "original"} } ! { dg-final { scan-tree-dump-times "#pragma omp taskloop" 2 "original"} } ! { dg-final { scan-tree-dump-times "#pragma omp teams" 8 "original"} } diff --git a/gcc/tree-pretty-print.c b/gcc/tree-pretty-print.c index 35e567cbfaf..0b5bdd78f06 100644 --- a/gcc/tree-pretty-print.c +++ b/gcc/tree-pretty-print.c @@ -1165,6 +1165,8 @@ dump_omp_clause (pretty_printer *pp, tree clause, int spc, dump_flags_t flags) pp_string (pp, "order("); if (OMP_CLAUSE_ORDER_UNCONSTRAINED (clause)) pp_string (pp, "unconstrained:"); + else if (OMP_CLAUSE_ORDER_REPRODUCIBLE (clause)) + pp_string (pp, "reproducible:"); pp_string (pp, "concurrent)"); break; diff --git a/gcc/tree.h b/gcc/tree.h index 7d1257b7a75..7542d97ce12 100644 --- a/gcc/tree.h +++ b/gcc/tree.h @@ -1718,6 +1718,9 @@ class auto_suppress_location_wrappers /* True for unconstrained modifier on order(concurrent) clause. */ #define OMP_CLAUSE_ORDER_UNCONSTRAINED(NODE) \ (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_ORDER)->base.public_flag) +/* True for reproducible modifier on order(concurrent) clause. */ +#define OMP_CLAUSE_ORDER_REPRODUCIBLE(NODE) \ + TREE_PROTECTED (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_ORDER)) #define OMP_CLAUSE_REDUCTION_CODE(NODE) \ (OMP_CLAUSE_RANGE_CHECK (NODE, OMP_CLAUSE_REDUCTION, \ diff --git a/libgomp/testsuite/libgomp.c-c++-common/order-reproducible-1.c b/libgomp/testsuite/libgomp.c-c++-common/order-reproducible-1.c new file mode 100644 index 00000000000..7e6968fe980 --- /dev/null +++ b/libgomp/testsuite/libgomp.c-c++-common/order-reproducible-1.c @@ -0,0 +1,63 @@ +#include +#include + +int +main () +{ + int a[128]; + #pragma omp teams num_teams(5) + { + #pragma omp loop bind(teams) + for (int i = 0; i < 128; i++) + { + a[i] = i; + if (i == 0) + usleep (20); + else if (i == 17) + usleep (40); + } + #pragma omp loop bind(teams) + for (int i = 0; i < 128; i++) + a[i] += i; + } + for (int i = 0; i < 128; i++) + if (a[i] != 2 * i) + abort (); + #pragma omp teams num_teams(5) + { + #pragma omp loop bind(teams) order(concurrent) + for (int i = 0; i < 128; i++) + { + a[i] *= 2; + if (i == 1) + usleep (20); + else if (i == 13) + usleep (40); + } + #pragma omp loop bind(teams) order(concurrent) + for (int i = 0; i < 128; i++) + a[i] += i; + } + for (int i = 0; i < 128; i++) + if (a[i] != 5 * i) + abort (); + #pragma omp teams num_teams(5) + { + #pragma omp loop bind(teams) order(reproducible:concurrent) + for (int i = 0; i < 128; i++) + { + a[i] *= 2; + if (i == 2) + usleep (20); + else if (i == 105) + usleep (40); + } + #pragma omp loop bind(teams) order(reproducible:concurrent) + for (int i = 0; i < 128; i++) + a[i] += i; + } + for (int i = 0; i < 128; i++) + if (a[i] != 11 * i) + abort (); + return 0; +} diff --git a/libgomp/testsuite/libgomp.c-c++-common/order-reproducible-2.c b/libgomp/testsuite/libgomp.c-c++-common/order-reproducible-2.c new file mode 100644 index 00000000000..c8ba658cf5e --- /dev/null +++ b/libgomp/testsuite/libgomp.c-c++-common/order-reproducible-2.c @@ -0,0 +1,28 @@ +#include +#include + +int +main () +{ + int a[128]; + #pragma omp parallel num_threads(8) + { + #pragma omp barrier + #pragma omp for nowait schedule (dynamic, 2) order(reproducible:concurrent) + for (int i = 0; i < 128; i++) + { + a[i] = i; + if (i == 0) + usleep (20); + else if (i == 17) + usleep (40); + } + #pragma omp for nowait schedule (dynamic, 2) order(reproducible:concurrent) + for (int i = 0; i < 128; i++) + a[i] += i; + } + for (int i = 0; i < 128; i++) + if (a[i] != 2 * i) + abort (); + return 0; +}