From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from esa1.mentor.iphmx.com (esa1.mentor.iphmx.com [68.232.129.153]) by sourceware.org (Postfix) with ESMTPS id 8A7AE3858291 for ; Fri, 24 Mar 2023 15:33:02 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 8A7AE3858291 Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=codesourcery.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=mentor.com X-IronPort-AV: E=Sophos;i="5.98,288,1673942400"; d="scan'208";a="324687" Received: from orw-gwy-02-in.mentorg.com ([192.94.38.167]) by esa1.mentor.iphmx.com with ESMTP; 24 Mar 2023 07:31:09 -0800 IronPort-SDR: lsb2wNYMdtH0XpBBY3uUbFl9IQG5kWvXclcPgp7V1k8yHR493GLOXyAdyGeJj1i7yXe6nJ032b +NX/2LgLqXyCuzaXCyBLRZp0vUZ7WsL2KYZMrL7YTreXykND+BhNYO6AvNOb01Cm8CLmPq5aSy teaQL1XYlZF2EziKZKSXz7a8RIrV0Jgx+fHlaub4/emMaG05NVqFno9tSCfmf3UlIz/nQkmgKU bDZ0xp3/tq1z+SGUfHr0etKa4vkGz0+xWjiNf3OyCF49+AXU4wxfFzX01C40VjVTnq0fXN08/6 ewc= From: Frederik Harwath To: , , , , Subject: [PATCH 2/7] openmp: Add C/C++ support for "omp unroll" directive Date: Fri, 24 Mar 2023 16:30:40 +0100 Message-ID: <20230324153046.3996092-3-frederik@codesourcery.com> X-Mailer: git-send-email 2.36.1 In-Reply-To: <20230324153046.3996092-1-frederik@codesourcery.com> References: <20230324153046.3996092-1-frederik@codesourcery.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain X-Originating-IP: [137.202.0.90] X-ClientProxiedBy: svr-ies-mbx-10.mgc.mentorg.com (139.181.222.10) To svr-ies-mbx-10.mgc.mentorg.com (139.181.222.10) X-Spam-Status: No, score=-12.5 required=5.0 tests=BAYES_00,GIT_PATCH_0,HEADER_FROM_DIFFERENT_DOMAINS,KAM_DMARC_STATUS,SPF_HELO_PASS,SPF_PASS,TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org List-Id: This commit implements the C and the C++ front end changes to support the "omp unroll" directive. The execution of the loop transformation relies on the pass that has been added as a part of the earlier Fortran patch. gcc/c-family/ChangeLog: * c-gimplify.cc (c_genericize_control_stmt): Handle OMP_UNROLL. * c-omp.cc: Add "unroll" to omp_directives[]. * c-pragma.cc: Add "unroll" to omp_pragmas_simd[]. * c-pragma.h (enum pragma_kind): Add PRAGMA_OMP_UNROLL to pragma_kind and adjust PRAGMA_OMP__LAST_. (enum pragma_omp_clause): Add PRAGMA_OMP_CLAUSE_FULL and PRAGMA_OMP_CLAUSE_PARTIAL. gcc/c/ChangeLog: * c-parser.cc (c_parser_omp_clause_name): Handle "full" and "partial" clauses. (check_no_duplicate_clause): Change return type to bool and return check result. (c_parser_omp_clause_unroll_full): New function for parsing the "unroll clause". (c_parser_omp_clause_unroll_partial): New function for parsing the "partial" clause. (c_parser_omp_all_clauses): Handle PRAGMA_OMP_CLAUSE_FULL and PRAGMA_OMP_CLAUSE_PARTIAL. (c_parser_nested_omp_unroll_clauses): New function for parsing "omp unroll" directives following another directive. (OMP_UNROLL_CLAUSE_MASK): New definition. (c_parser_omp_unroll): New function for parsing "omp unroll" loops that are not associated with another directive. (c_parser_omp_construct): Handle PRAGMA_OMP_UNROLL. * c-typeck.cc (c_finish_omp_clauses): Handle OMP_CLAUSE_UNROLL_FULL, OMP_CLAUSE_UNROLL_PARTIAL, and OMP_CLAUSE_UNROLL_NONE. gcc/cp/ChangeLog: * cp-gimplify.cc (cp_gimplify_expr): Handle OMP_UNROLL. (cp_fold_r): Likewise. (cp_genericize_r): Likewise. * parser.cc (cp_parser_omp_clause_name): Handle "full" clause. (check_no_duplicate_clause): Change return type to bool and return check result. (cp_parser_omp_clause_unroll_full): New function for parsing the "unroll clause". (cp_parser_omp_clause_unroll_partial): New function for parsing the "partial" clause. (cp_parser_omp_all_clauses): Handle OMP_CLAUSE_UNROLL and OMP_CLAUSE_FULL. (cp_parser_nested_omp_unroll_clauses): New function for parsing "omp unroll" directives following another directive. (cp_parser_omp_for_loop): Handle "omp unroll" directives between directive and loop. (OMP_UNROLL_CLAUSE_MASK): New definition. (cp_parser_omp_unroll): New function for parsing "omp unroll" loops that are not associated with another directive. (cp_parser_omp_construct): Handle PRAGMA_OMP_UNROLL. (cp_parser_pragma): Handle PRAGMA_OMP_UNROLL. * pt.cc (tsubst_omp_clauses): Handle OMP_CLAUSE_UNROLL_PARTIAL, OMP_CLAUSE_UNROLL_FULL, and OMP_CLAUSE_UNROLL_NONE. (tsubst_expr): Handle OMP_UNROLL. * semantics.cc (finish_omp_clauses): Handle OMP_CLAUSE_UNROLL_FULL, OMP_CLAUSE_UNROLL_PARTIAL, and OMP_CLAUSE_UNROLL_NONE. libgomp/ChangeLog: * testsuite/libgomp.c++/loop-transforms/unroll-1.C: New test. * testsuite/libgomp.c++/loop-transforms/unroll-2.C: New test. * testsuite/libgomp.c-c++-common/loop-transforms/unroll-1.c: New te= st. gcc/testsuite/ChangeLog: * c-c++-common/gomp/loop-transforms/unroll-1.c: New test. * c-c++-common/gomp/loop-transforms/unroll-2.c: New test. * c-c++-common/gomp/loop-transforms/unroll-3.c: New test. * c-c++-common/gomp/loop-transforms/unroll-4.c: New test. * c-c++-common/gomp/loop-transforms/unroll-5.c: New test. * c-c++-common/gomp/loop-transforms/unroll-6.c: New test. * g++.dg/gomp/loop-transforms/unroll-1.C: New test. * g++.dg/gomp/loop-transforms/unroll-2.C: New test. * g++.dg/gomp/loop-transforms/unroll-3.C: New test. --- gcc/c-family/c-gimplify.cc | 1 + gcc/c-family/c-omp.cc | 6 +- gcc/c-family/c-pragma.cc | 1 + gcc/c-family/c-pragma.h | 5 +- gcc/c/c-parser.cc | 161 ++++++++++++++++- gcc/c/c-typeck.cc | 8 + gcc/cp/cp-gimplify.cc | 3 + gcc/cp/parser.cc | 164 +++++++++++++++++- gcc/cp/pt.cc | 4 + gcc/cp/semantics.cc | 56 ++++++ .../gomp/loop-transforms/unroll-1.c | 133 ++++++++++++++ .../gomp/loop-transforms/unroll-2.c | 99 +++++++++++ .../gomp/loop-transforms/unroll-3.c | 18 ++ .../gomp/loop-transforms/unroll-4.c | 19 ++ .../gomp/loop-transforms/unroll-5.c | 19 ++ .../gomp/loop-transforms/unroll-6.c | 20 +++ .../gomp/loop-transforms/unroll-7.c | 144 +++++++++++++++ .../gomp/loop-transforms/unroll-simd-1.c | 84 +++++++++ .../g++.dg/gomp/loop-transforms/unroll-1.C | 42 +++++ .../g++.dg/gomp/loop-transforms/unroll-2.C | 47 +++++ .../g++.dg/gomp/loop-transforms/unroll-3.C | 37 ++++ .../libgomp.c++/loop-transforms/unroll-1.C | 73 ++++++++ .../libgomp.c++/loop-transforms/unroll-2.C | 34 ++++ .../loop-transforms/unroll-1.c | 76 ++++++++ 24 files changed, 1246 insertions(+), 8 deletions(-) create mode 100644 gcc/testsuite/c-c++-common/gomp/loop-transforms/unroll-= 1.c create mode 100644 gcc/testsuite/c-c++-common/gomp/loop-transforms/unroll-= 2.c create mode 100644 gcc/testsuite/c-c++-common/gomp/loop-transforms/unroll-= 3.c create mode 100644 gcc/testsuite/c-c++-common/gomp/loop-transforms/unroll-= 4.c create mode 100644 gcc/testsuite/c-c++-common/gomp/loop-transforms/unroll-= 5.c create mode 100644 gcc/testsuite/c-c++-common/gomp/loop-transforms/unroll-= 6.c create mode 100644 gcc/testsuite/c-c++-common/gomp/loop-transforms/unroll-= 7.c create mode 100644 gcc/testsuite/c-c++-common/gomp/loop-transforms/unroll-= simd-1.c create mode 100644 gcc/testsuite/g++.dg/gomp/loop-transforms/unroll-1.C create mode 100644 gcc/testsuite/g++.dg/gomp/loop-transforms/unroll-2.C create mode 100644 gcc/testsuite/g++.dg/gomp/loop-transforms/unroll-3.C create mode 100644 libgomp/testsuite/libgomp.c++/loop-transforms/unroll-1.= C create mode 100644 libgomp/testsuite/libgomp.c++/loop-transforms/unroll-2.= C create mode 100644 libgomp/testsuite/libgomp.c-c++-common/loop-transforms/= unroll-1.c diff --git a/gcc/c-family/c-gimplify.cc b/gcc/c-family/c-gimplify.cc index ef5c7d919fc..82c88bd70e1 100644 --- a/gcc/c-family/c-gimplify.cc +++ b/gcc/c-family/c-gimplify.cc @@ -506,6 +506,7 @@ c_genericize_control_stmt (tree *stmt_p, int *walk_subt= rees, void *data, case OMP_DISTRIBUTE: case OMP_LOOP: case OMP_TASKLOOP: + case OMP_LOOP_TRANS: case OACC_LOOP: genericize_omp_for_stmt (stmt_p, walk_subtrees, data, func, lh); break; diff --git a/gcc/c-family/c-omp.cc b/gcc/c-family/c-omp.cc index f72ca4c6acd..85ba9c528c8 100644 --- a/gcc/c-family/c-omp.cc +++ b/gcc/c-family/c-omp.cc @@ -3212,9 +3212,9 @@ const struct c_omp_directive c_omp_directives[] =3D { { "teams", nullptr, nullptr, PRAGMA_OMP_TEAMS, C_OMP_DIR_CONSTRUCT, true }, { "threadprivate", nullptr, nullptr, PRAGMA_OMP_THREADPRIVATE, - C_OMP_DIR_DECLARATIVE, false } - /* { "unroll", nullptr, nullptr, PRAGMA_OMP_UNROLL, - C_OMP_DIR_CONSTRUCT, false }, */ + C_OMP_DIR_DECLARATIVE, false }, + { "unroll", nullptr, nullptr, PRAGMA_OMP_UNROLL, + C_OMP_DIR_CONSTRUCT, false }, }; /* Find (non-combined/composite) OpenMP directive (if any) which starts diff --git a/gcc/c-family/c-pragma.cc b/gcc/c-family/c-pragma.cc index 0d2b333cebb..96a28ac1b0c 100644 --- a/gcc/c-family/c-pragma.cc +++ b/gcc/c-family/c-pragma.cc @@ -1593,6 +1593,7 @@ static const struct omp_pragma_def omp_pragmas_simd[]= =3D { { "target", PRAGMA_OMP_TARGET }, { "taskloop", PRAGMA_OMP_TASKLOOP }, { "teams", PRAGMA_OMP_TEAMS }, + { "unroll", PRAGMA_OMP_UNROLL }, }; void diff --git a/gcc/c-family/c-pragma.h b/gcc/c-family/c-pragma.h index 9cc95ab3ee3..6686abdc94d 100644 --- a/gcc/c-family/c-pragma.h +++ b/gcc/c-family/c-pragma.h @@ -81,8 +81,9 @@ enum pragma_kind { PRAGMA_OMP_TASKYIELD, PRAGMA_OMP_THREADPRIVATE, PRAGMA_OMP_TEAMS, + PRAGMA_OMP_UNROLL, /* PRAGMA_OMP__LAST_ should be equal to the last PRAGMA_OMP_* code. */ - PRAGMA_OMP__LAST_ =3D PRAGMA_OMP_TEAMS, + PRAGMA_OMP__LAST_ =3D PRAGMA_OMP_UNROLL, PRAGMA_GCC_PCH_PREPROCESS, PRAGMA_IVDEP, @@ -118,6 +119,7 @@ enum pragma_omp_clause { PRAGMA_OMP_CLAUSE_FIRSTPRIVATE, PRAGMA_OMP_CLAUSE_FOR, PRAGMA_OMP_CLAUSE_FROM, + PRAGMA_OMP_CLAUSE_FULL, PRAGMA_OMP_CLAUSE_GRAINSIZE, PRAGMA_OMP_CLAUSE_HAS_DEVICE_ADDR, PRAGMA_OMP_CLAUSE_HINT, @@ -140,6 +142,7 @@ enum pragma_omp_clause { PRAGMA_OMP_CLAUSE_ORDER, PRAGMA_OMP_CLAUSE_ORDERED, PRAGMA_OMP_CLAUSE_PARALLEL, + PRAGMA_OMP_CLAUSE_PARTIAL, PRAGMA_OMP_CLAUSE_PRIORITY, PRAGMA_OMP_CLAUSE_PRIVATE, PRAGMA_OMP_CLAUSE_PROC_BIND, diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc index 21bc3167ce2..9d875befccc 100644 --- a/gcc/c/c-parser.cc +++ b/gcc/c/c-parser.cc @@ -13471,6 +13471,8 @@ c_parser_omp_clause_name (c_parser *parser) result =3D PRAGMA_OMP_CLAUSE_FIRSTPRIVATE; else if (!strcmp ("from", p)) result =3D PRAGMA_OMP_CLAUSE_FROM; + else if (!strcmp ("full", p)) + result =3D PRAGMA_OMP_CLAUSE_FULL; break; case 'g': if (!strcmp ("gang", p)) @@ -13545,6 +13547,8 @@ c_parser_omp_clause_name (c_parser *parser) case 'p': if (!strcmp ("parallel", p)) result =3D PRAGMA_OMP_CLAUSE_PARALLEL; + else if (!strcmp ("partial", p)) + result =3D PRAGMA_OMP_CLAUSE_PARTIAL; else if (!strcmp ("present", p)) result =3D PRAGMA_OACC_CLAUSE_PRESENT; /* As of OpenACC 2.5, these are now aliases of the non-present_or @@ -13639,12 +13643,15 @@ c_parser_omp_clause_name (c_parser *parser) /* Validate that a clause of the given type does not already exist. */ -static void +static bool check_no_duplicate_clause (tree clauses, enum omp_clause_code code, const char *name) { - if (tree c =3D omp_find_clause (clauses, code)) + tree c =3D omp_find_clause (clauses, code); + if (c) error_at (OMP_CLAUSE_LOCATION (c), "too many %qs clauses", name); + + return c =3D=3D NULL_TREE; } /* OpenACC 2.0 @@ -17448,6 +17455,65 @@ c_parser_omp_clause_uniform (c_parser *parser, tre= e list) return list; } +/* OpenMP 5.1 + full */ + +static tree +c_parser_omp_clause_unroll_full (c_parser *parser, tree list) +{ + if (!check_no_duplicate_clause (list, OMP_CLAUSE_UNROLL_FULL, "full")) + return list; + + location_t loc =3D c_parser_peek_token (parser)->location; + tree c =3D build_omp_clause (loc, OMP_CLAUSE_UNROLL_FULL); + OMP_CLAUSE_CHAIN (c) =3D list; + return c; +} + +/* OpenMP 5.1 + partial ( constant-expression ) */ + +static tree +c_parser_omp_clause_unroll_partial (c_parser *parser, tree list) +{ + if (!check_no_duplicate_clause (list, OMP_CLAUSE_UNROLL_PARTIAL, "partia= l")) + return list; + + tree c, num =3D error_mark_node; + HOST_WIDE_INT n; + location_t loc; + + loc =3D c_parser_peek_token (parser)->location; + c =3D build_omp_clause (loc, OMP_CLAUSE_UNROLL_PARTIAL); + OMP_CLAUSE_UNROLL_PARTIAL_EXPR (c) =3D NULL_TREE; + OMP_CLAUSE_CHAIN (c) =3D list; + + if (!c_parser_next_token_is (parser, CPP_OPEN_PAREN)) + return c; + + matching_parens parens; + parens.consume_open (parser); + num =3D c_parser_expr_no_commas (parser, NULL).value; + parens.skip_until_found_close (parser); + + if (num =3D=3D error_mark_node) + return list; + + mark_exp_read (num); + num =3D c_fully_fold (num, false, NULL); + if (!INTEGRAL_TYPE_P (TREE_TYPE (num)) || !tree_fits_shwi_p (num) + || (n =3D tree_to_shwi (num)) <=3D 0 || (int)n !=3D n) + { + error_at (loc, + "partial argument needs positive constant integer expressio= n"); + return list; + } + + OMP_CLAUSE_UNROLL_PARTIAL_EXPR (c) =3D num; + + return c; +} + /* OpenMP 5.0: detach ( event-handle ) */ @@ -18042,6 +18108,14 @@ c_parser_omp_all_clauses (c_parser *parser, omp_cl= ause_mask mask, clauses); c_name =3D "enter"; break; + case PRAGMA_OMP_CLAUSE_FULL: + c_name =3D "full"; + clauses =3D c_parser_omp_clause_unroll_full (parser, clauses); + break; + case PRAGMA_OMP_CLAUSE_PARTIAL: + c_name =3D "partial"; + clauses =3D c_parser_omp_clause_unroll_partial (parser, clauses); + break; default: c_parser_error (parser, "expected %<#pragma omp%> clause"); goto saw_error; @@ -20169,6 +20243,8 @@ c_parser_omp_scan_loop_body (c_parser *parser, bool= open_brace_parsed) "expected %<}%>"); } +static bool c_parser_nested_omp_unroll_clauses (c_parser *, tree &); + /* Parse the restricted form of loop statements allowed by OpenACC and Ope= nMP. The real trick here is to determine the loop control variable early so that we can push a new decl if necessary to make it private. @@ -20227,6 +20303,13 @@ c_parser_omp_for_loop (location_t loc, c_parser *p= arser, enum tree_code code, condv =3D make_tree_vec (count); incrv =3D make_tree_vec (count); + if (c_parser_nested_omp_unroll_clauses (parser, clauses) + && count > 1) + { + error_at (loc, "collapse cannot be larger than 1 on an unrolled loop= "); + return NULL; + } + if (!c_parser_next_token_is_keyword (parser, RID_FOR)) { c_parser_error (parser, "for statement expected"); @@ -23858,6 +23941,76 @@ c_parser_omp_taskloop (location_t loc, c_parser *p= arser, return ret; } +#define OMP_UNROLL_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PARTIAL) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FULL) ) + +/* Parse zero or more '#pragma omp unroll' that follow + another directive that requires a canonical loop nest. */ + +static bool +c_parser_nested_omp_unroll_clauses (c_parser *parser, tree &clauses) +{ + static const char *p_name =3D "#pragma omp unroll"; + c_token *tok; + bool found_unroll =3D false; + while (c_parser_next_token_is (parser, CPP_PRAGMA) + && (tok =3D c_parser_peek_token (parser), + tok->pragma_kind =3D=3D PRAGMA_OMP_UNROLL)) + { + c_parser_consume_pragma (parser); + tree c =3D c_parser_omp_all_clauses (parser, OMP_UNROLL_CLAUSE_MASK, + p_name, true); + if (c) + { + gcc_assert (!TREE_CHAIN (c)); + found_unroll =3D true; + if (OMP_CLAUSE_CODE (c) =3D=3D OMP_CLAUSE_UNROLL_FULL) + { + error_at (tok->location, "% clause is invalid here; " + "turns loop into non-loop"); + continue; + } + } + else + { + error_at (tok->location, "%<#pragma omp unroll%> without " + "% clause is invalid here; " + "turns loop into non-loop"); + continue; + } + + clauses =3D chainon (clauses, c); + } + + return found_unroll; +} + +static tree +c_parser_omp_unroll (location_t loc, c_parser *parser, bool *if_p) +{ + tree block, ret; + static const char *p_name =3D "#pragma omp unroll"; + omp_clause_mask mask =3D OMP_UNROLL_CLAUSE_MASK; + + tree clauses =3D c_parser_omp_all_clauses (parser, mask, p_name, false); + c_parser_nested_omp_unroll_clauses (parser, clauses); + + if (!clauses) + { + tree c =3D build_omp_clause (loc, OMP_CLAUSE_UNROLL_NONE); + OMP_CLAUSE_CHAIN (c) =3D clauses; + clauses =3D c; + } + + block =3D c_begin_compound_stmt (true); + ret =3D c_parser_omp_for_loop (loc, parser, OMP_LOOP_TRANS, clauses, NUL= L, if_p); + block =3D c_end_compound_stmt (loc, block, true); + add_stmt (block); + + return ret; +} + /* OpenMP 5.1 #pragma omp nothing new-line */ @@ -24249,6 +24402,7 @@ c_parser_omp_construct (c_parser *parser, bool *if_= p) p_kind =3D c_parser_peek_token (parser)->pragma_kind; c_parser_consume_pragma (parser); + gcc_assert (parser->in_pragma); switch (p_kind) { case PRAGMA_OACC_ATOMIC: @@ -24342,6 +24496,9 @@ c_parser_omp_construct (c_parser *parser, bool *if_= p) case PRAGMA_OMP_ASSUME: c_parser_omp_assume (parser, if_p); return; + case PRAGMA_OMP_UNROLL: + stmt =3D c_parser_omp_unroll (loc, parser, if_p); + break; default: gcc_unreachable (); } diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc index 45bacc06c47..bffea79b441 100644 --- a/gcc/c/c-typeck.cc +++ b/gcc/c/c-typeck.cc @@ -15916,6 +15916,14 @@ c_finish_omp_clauses (tree clauses, enum c_omp_reg= ion_type ort) pc =3D &OMP_CLAUSE_CHAIN (c); continue; + case OMP_CLAUSE_UNROLL_FULL: + pc =3D &OMP_CLAUSE_CHAIN (c); + continue; + + case OMP_CLAUSE_UNROLL_PARTIAL: + pc =3D &OMP_CLAUSE_CHAIN (c); + continue; + case OMP_CLAUSE_INBRANCH: case OMP_CLAUSE_NOTINBRANCH: if (branch_seen) diff --git a/gcc/cp/cp-gimplify.cc b/gcc/cp/cp-gimplify.cc index 4fecd5616bd..bf81097d780 100644 --- a/gcc/cp/cp-gimplify.cc +++ b/gcc/cp/cp-gimplify.cc @@ -638,6 +638,7 @@ cp_gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimp= le_seq *post_p) case OMP_DISTRIBUTE: case OMP_LOOP: case OMP_TASKLOOP: + case OMP_LOOP_TRANS: ret =3D cp_gimplify_omp_for (expr_p, pre_p); break; @@ -1097,6 +1098,7 @@ cp_fold_r (tree *stmt_p, int *walk_subtrees, void *da= ta_) case OMP_DISTRIBUTE: case OMP_LOOP: case OMP_TASKLOOP: + case OMP_LOOP_TRANS: case OACC_LOOP: cp_walk_tree (&OMP_FOR_BODY (stmt), cp_fold_r, data, NULL); cp_walk_tree (&OMP_FOR_CLAUSES (stmt), cp_fold_r, data, NULL); @@ -1855,6 +1857,7 @@ cp_genericize_r (tree *stmt_p, int *walk_subtrees, vo= id *data) case OMP_FOR: case OMP_SIMD: case OMP_LOOP: + case OMP_LOOP_TRANS: case OACC_LOOP: case STATEMENT_LIST: /* These cases are handled by shared code. */ diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc index a277003ea58..7034fdf49a4 100644 --- a/gcc/cp/parser.cc +++ b/gcc/cp/parser.cc @@ -37204,6 +37204,8 @@ cp_parser_omp_clause_name (cp_parser *parser) result =3D PRAGMA_OMP_CLAUSE_FIRSTPRIVATE; else if (!strcmp ("from", p)) result =3D PRAGMA_OMP_CLAUSE_FROM; + else if (!strcmp ("full", p)) + result =3D PRAGMA_OMP_CLAUSE_FULL; break; case 'g': if (!strcmp ("gang", p)) @@ -37278,6 +37280,8 @@ cp_parser_omp_clause_name (cp_parser *parser) case 'p': if (!strcmp ("parallel", p)) result =3D PRAGMA_OMP_CLAUSE_PARALLEL; + if (!strcmp ("partial", p)) + result =3D PRAGMA_OMP_CLAUSE_PARTIAL; else if (!strcmp ("present", p)) result =3D PRAGMA_OACC_CLAUSE_PRESENT; else if (!strcmp ("present_or_copy", p) @@ -37368,12 +37372,15 @@ cp_parser_omp_clause_name (cp_parser *parser) /* Validate that a clause of the given type does not already exist. */ -static void +static bool check_no_duplicate_clause (tree clauses, enum omp_clause_code code, const char *name, location_t location) { - if (omp_find_clause (clauses, code)) + bool found =3D omp_find_clause (clauses, code); + if (found) error_at (location, "too many %qs clauses", name); + + return !found; } /* OpenMP 2.5: @@ -39459,6 +39466,56 @@ cp_parser_omp_clause_thread_limit (cp_parser *pars= er, tree list, return c; } +/* OpenMP 5.1 + full */ + +static tree +cp_parser_omp_clause_unroll_full (tree list, location_t loc) +{ + if (!check_no_duplicate_clause (list, OMP_CLAUSE_UNROLL_FULL, "full", lo= c)) + return list; + + tree c =3D build_omp_clause (loc, OMP_CLAUSE_UNROLL_FULL); + OMP_CLAUSE_CHAIN (c) =3D list; + return c; +} + +/* OpenMP 5.1 + partial ( constant-expression ) */ + +static tree +cp_parser_omp_clause_unroll_partial (cp_parser *parser, tree list, + location_t loc) +{ + if (!check_no_duplicate_clause (list, OMP_CLAUSE_UNROLL_PARTIAL, "partia= l", + loc)) + return list; + + tree c, num =3D error_mark_node; + c =3D build_omp_clause (loc, OMP_CLAUSE_UNROLL_PARTIAL); + OMP_CLAUSE_UNROLL_PARTIAL_EXPR (c) =3D NULL_TREE; + OMP_CLAUSE_CHAIN (c) =3D list; + + if (!cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN)) + return c; + + matching_parens parens; + parens.consume_open (parser); + num =3D cp_parser_constant_expression (parser); + cp_parser_skip_to_closing_parenthesis (parser, /*recovering=3D*/true, + /*or_comma=3D*/false, + /*consume_paren=3D*/true); + + if (num =3D=3D error_mark_node) + return list; + + mark_exp_read (num); + num =3D fold_non_dependent_expr (num); + + OMP_CLAUSE_UNROLL_PARTIAL_EXPR (c) =3D num; + return c; +} + /* OpenMP 4.0: aligned ( variable-list ) aligned ( variable-list : constant-expression ) */ @@ -41441,6 +41498,15 @@ cp_parser_omp_all_clauses (cp_parser *parser, omp_= clause_mask mask, clauses); c_name =3D "enter"; break; + case PRAGMA_OMP_CLAUSE_PARTIAL: + clauses =3D cp_parser_omp_clause_unroll_partial (parser, clauses, + token->location); + c_name =3D "partial"; + break; + case PRAGMA_OMP_CLAUSE_FULL: + clauses =3D cp_parser_omp_clause_unroll_full(clauses, token->loca= tion); + c_name =3D "full"; + break; default: cp_parser_error (parser, "expected %<#pragma omp%> clause"); goto saw_error; @@ -43565,6 +43631,8 @@ cp_parser_omp_scan_loop_body (cp_parser *parser) braces.require_close (parser); } +static bool cp_parser_nested_omp_unroll_clauses (cp_parser *, tree &); + /* Parse the restricted form of the for statement allowed by OpenMP. */ static tree @@ -43622,6 +43690,15 @@ cp_parser_omp_for_loop (cp_parser *parser, enum tr= ee_code code, tree clauses, loc_first =3D cp_lexer_peek_token (parser->lexer)->location; + if (cp_parser_nested_omp_unroll_clauses (parser, clauses) + && count > 1) + { + error_at (loc_first, + "collapse cannot be larger than 1 on an unrolled loop"); + return NULL; + } + + for (i =3D 0; i < count; i++) { int bracecount =3D 0; @@ -45657,6 +45734,79 @@ cp_parser_omp_target (cp_parser *parser, cp_token = *pragma_tok, return true; } +#define OMP_UNROLL_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PARTIAL) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FULL) ) + +/* Parse zero or more '#pragma omp unroll' that follow + another directive that requires a canonical loop nest. */ + +static bool +cp_parser_nested_omp_unroll_clauses (cp_parser *parser, tree &clauses) +{ + static const char *p_name =3D "#pragma omp unroll"; + cp_token *tok; + bool unroll_found =3D false; + while (cp_lexer_next_token_is (parser->lexer, CPP_PRAGMA) + && (tok =3D cp_lexer_peek_token (parser->lexer), + cp_parser_pragma_kind (tok) =3D=3D PRAGMA_OMP_UNROLL)) + { + cp_lexer_consume_token (parser->lexer); + gcc_assert (tok->type =3D=3D CPP_PRAGMA); + parser->lexer->in_pragma =3D true; + tree c =3D cp_parser_omp_all_clauses (parser, OMP_UNROLL_CLAUSE_MASK= , + p_name, tok); + if (c) + { + gcc_assert (!TREE_CHAIN (c)); + unroll_found =3D true; + if (OMP_CLAUSE_CODE (c) =3D=3D OMP_CLAUSE_UNROLL_FULL) + { + error_at (tok->location, "% clause is invalid here; " + "turns loop into non-loop"); + continue; + } + + c =3D finish_omp_clauses (c, C_ORT_OMP); + } + else + { + error_at (tok->location, "%<#pragma omp unroll%> without " + "% clause is invalid here; " + "turns loop into non-loop"); + continue; + } + clauses =3D chainon (clauses, c); + } + return unroll_found; +} + +static tree +cp_parser_omp_unroll (cp_parser *parser, cp_token *tok, bool *if_p) +{ + tree block, ret; + static const char *p_name =3D "#pragma omp unroll"; + omp_clause_mask mask =3D OMP_UNROLL_CLAUSE_MASK; + + tree clauses =3D cp_parser_omp_all_clauses (parser, mask, p_name, tok, f= alse); + + if (!clauses) + { + tree c =3D build_omp_clause (tok->location, OMP_CLAUSE_UNROLL_NONE); + OMP_CLAUSE_CHAIN (c) =3D clauses; + clauses =3D c; + } + + cp_parser_nested_omp_unroll_clauses (parser, clauses); + + block =3D begin_omp_structured_block (); + ret =3D cp_parser_omp_for_loop (parser, OMP_LOOP_TRANS, clauses, NULL, i= f_p); + block =3D finish_omp_structured_block (block); + add_stmt (block); + + return ret; +} + /* OpenACC 2.0: # pragma acc cache (variable-list) new-line */ @@ -48750,6 +48900,9 @@ cp_parser_omp_construct (cp_parser *parser, cp_toke= n *pragma_tok, bool *if_p) case PRAGMA_OMP_ASSUME: cp_parser_omp_assume (parser, pragma_tok, if_p); return; + case PRAGMA_OMP_UNROLL: + stmt =3D cp_parser_omp_unroll (parser, pragma_tok, if_p); + break; default: gcc_unreachable (); } @@ -49376,6 +49529,13 @@ cp_parser_pragma (cp_parser *parser, enum pragma_c= ontext context, bool *if_p) cp_parser_omp_construct (parser, pragma_tok, if_p); pop_omp_privatization_clauses (stmt); return true; + case PRAGMA_OMP_UNROLL: + if (context !=3D pragma_stmt && context !=3D pragma_compound) + goto bad_stmt; + stmt =3D push_omp_privatization_clauses (false); + cp_parser_omp_construct (parser, pragma_tok, if_p); + pop_omp_privatization_clauses (stmt); + return true; case PRAGMA_OMP_REQUIRES: if (context !=3D pragma_external) diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index 40deedc9ba9..63b2d1f7a45 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -18086,6 +18086,7 @@ tsubst_omp_clauses (tree clauses, enum c_omp_region= _type ort, case OMP_CLAUSE_ASYNC: case OMP_CLAUSE_WAIT: case OMP_CLAUSE_DETACH: + case OMP_CLAUSE_UNROLL_PARTIAL: OMP_CLAUSE_OPERAND (nc, 0) =3D tsubst_expr (OMP_CLAUSE_OPERAND (oc, 0), args, complain, in= _decl); break; @@ -18169,6 +18170,8 @@ tsubst_omp_clauses (tree clauses, enum c_omp_region= _type ort, case OMP_CLAUSE_IF_PRESENT: case OMP_CLAUSE_FINALIZE: case OMP_CLAUSE_NOHOST: + case OMP_CLAUSE_UNROLL_FULL: + case OMP_CLAUSE_UNROLL_NONE: break; default: gcc_unreachable (); @@ -19437,6 +19440,7 @@ tsubst_expr (tree t, tree args, tsubst_flags_t comp= lain, tree in_decl) case OMP_SIMD: case OMP_DISTRIBUTE: case OMP_TASKLOOP: + case OMP_LOOP_TRANS: case OACC_LOOP: { tree clauses, body, pre_body; diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc index 99a76e3ed65..ac49502eea4 100644 --- a/gcc/cp/semantics.cc +++ b/gcc/cp/semantics.cc @@ -6779,6 +6779,7 @@ finish_omp_clauses (tree clauses, enum c_omp_region_t= ype ort) bool mergeable_seen =3D false; bool implicit_moved =3D false; bool target_in_reduction_seen =3D false; + bool unroll_full_seen =3D false; bitmap_obstack_initialize (NULL); bitmap_initialize (&generic_head, &bitmap_default_obstack); @@ -8822,6 +8823,61 @@ finish_omp_clauses (tree clauses, enum c_omp_region_= type ort) } break; + case OMP_CLAUSE_UNROLL_FULL: + if (unroll_full_seen) + { + error_at (OMP_CLAUSE_LOCATION (c), + "% appears more than once"); + remove =3D true; + } + unroll_full_seen =3D true; + break; + + case OMP_CLAUSE_UNROLL_PARTIAL: + { + + tree t =3D OMP_CLAUSE_UNROLL_PARTIAL_EXPR (c); + + if (!t) + break; + + if (t =3D=3D error_mark_node) + remove =3D true; + else if (!type_dependent_expression_p (t) + && !INTEGRAL_TYPE_P (TREE_TYPE (t))) + { + error_at (OMP_CLAUSE_LOCATION (c), + "partial argument needs integral type"); + remove =3D true; + } + else + { + t =3D mark_rvalue_use (t); + if (!processing_template_decl) + { + t =3D maybe_constant_value (t); + + int n; + if (!INTEGRAL_TYPE_P (TREE_TYPE (t)) + || !tree_fits_shwi_p (t) + || (n =3D tree_to_shwi (t)) <=3D 0 || (int)n !=3D n= ) + { + error_at (OMP_CLAUSE_LOCATION (c), + "partial argument needs positive constant= " + "integer expression"); + remove =3D true; + } + t =3D fold_build_cleanup_point_expr (TREE_TYPE (t), t); + } + } + + OMP_CLAUSE_UNROLL_PARTIAL_EXPR (c) =3D t; + } + break; + + case OMP_CLAUSE_UNROLL_NONE: + break; + default: gcc_unreachable (); } diff --git a/gcc/testsuite/c-c++-common/gomp/loop-transforms/unroll-1.c b/g= cc/testsuite/c-c++-common/gomp/loop-transforms/unroll-1.c new file mode 100644 index 00000000000..d496dc29053 --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/loop-transforms/unroll-1.c @@ -0,0 +1,133 @@ +extern void dummy (int); + +void +test1 () +{ +#pragma omp unroll partial + for (int i =3D 0; i < 100; ++i) + dummy (i); +} + +void +test2 () +{ +#pragma omp unroll partial(10) + for (int i =3D 0; i < 100; ++i) + dummy (i); +} + +void +test3 () +{ +#pragma omp unroll full + for (int i =3D 0; i < 100; ++i) + dummy (i); +} + +void +test4 () +{ +#pragma omp unroll full + for (int i =3D 0; i > 100; ++i) + dummy (i); +} + +void +test5 () +{ +#pragma omp unroll full + for (int i =3D 1; i <=3D 100; ++i) + dummy (i); +} + +void +test6 () +{ +#pragma omp unroll full + for (int i =3D 200; i >=3D 100; i--) + dummy (i); +} + +void +test7 () +{ +#pragma omp unroll full + for (int i =3D -100; i > 100; ++i) + dummy (i); +} + +void +test8 () +{ +#pragma omp unroll full + for (int i =3D 100; i > -200; --i) + dummy (i); +} + +void +test9 () +{ +#pragma omp unroll full + for (int i =3D -300; i !=3D 100; ++i) + dummy (i); +} + +void +test10 () +{ +#pragma omp unroll full + for (int i =3D -300; i !=3D 100; ++i) + dummy (i); +} + +void +test12 () +{ +#pragma omp unroll full +#pragma omp unroll partial +#pragma omp unroll partial + for (int i =3D -300; i !=3D 100; ++i) + dummy (i); +} + +void +test13 () +{ + for (int i =3D 0; i < 100; ++i) +#pragma omp unroll full +#pragma omp unroll partial +#pragma omp unroll partial + for (int j =3D -300; j !=3D 100; ++j) + dummy (i); +} + +void +test14 () +{ + #pragma omp for + for (int i =3D 0; i < 100; ++i) +#pragma omp unroll full +#pragma omp unroll partial +#pragma omp unroll partial + for (int j =3D -300; j !=3D 100; ++j) + dummy (i); +} + +void +test15 () +{ + #pragma omp for + for (int i =3D 0; i < 100; ++i) + { + + dummy (i); + +#pragma omp unroll full +#pragma omp unroll partial +#pragma omp unroll partial + for (int j =3D -300; j !=3D 100; ++j) + dummy (j); + + dummy (i); + } + } diff --git a/gcc/testsuite/c-c++-common/gomp/loop-transforms/unroll-2.c b/g= cc/testsuite/c-c++-common/gomp/loop-transforms/unroll-2.c new file mode 100644 index 00000000000..8f7c3088a2e --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/loop-transforms/unroll-2.c @@ -0,0 +1,99 @@ +/* { dg-prune-output "error: invalid controlling predicate" } */ +/* { dg-additional-options "-std=3Dc++11" { target c++} } */ + +extern void dummy (int); + +void +test () +{ +#pragma omp unroll partial +#pragma omp unroll full /* { dg-error {'full' clause is invalid here; turn= s loop into non-loop} } */ + for (int i =3D -300; i !=3D 100; ++i) + dummy (i); + +#pragma omp for +#pragma omp unroll full /* { dg-error {'full' clause is invalid here; turn= s loop into non-loop} } */ +#pragma omp unroll partial + for (int i =3D -300; i !=3D 100; ++i) + dummy (i); + +#pragma omp for +#pragma omp unroll full /* { dg-error {'full' clause is invalid here; turn= s loop into non-loop} } */ +#pragma omp unroll full /* { dg-error {'full' clause is invalid here; turn= s loop into non-loop} } */ + for (int i =3D -300; i !=3D 100; ++i) + dummy (i); + +#pragma omp for +#pragma omp unroll partial partial /* { dg-error {too many 'partial' claus= es} } */ + for (int i =3D -300; i !=3D 100; ++i) + dummy (i); + +#pragma omp unroll full full /* { dg-error {too many 'full' clauses} } */ + for (int i =3D -300; i !=3D 100; ++i) + dummy (i); + +#pragma omp unroll partial +#pragma omp unroll /* { dg-error {'#pragma omp unroll' without 'partial' c= lause is invalid here; turns loop into non-loop} } */ + for (int i =3D -300; i !=3D 100; ++i) + dummy (i); + +#pragma omp for +#pragma omp unroll /* { dg-error {'#pragma omp unroll' without 'partial' c= lause is invalid here; turns loop into non-loop} } */ + for (int i =3D -300; i !=3D 100; ++i) + dummy (i); + + int i; +#pragma omp for +#pragma omp unroll( /* { dg-error {expected '#pragma omp' clause before '\= (' token} } */ + /* { dg-error {'#pragma omp unroll' without 'partial' clause is invalid = here; turns loop into non-loop} "" { target *-*-* } .-1 } */ + for (int i =3D -300; i !=3D 100; ++i) + dummy (i); + +#pragma omp for +#pragma omp unroll foo /* { dg-error {expected '#pragma omp' clause before= 'foo'} } */ + /* { dg-error {'#pragma omp unroll' without 'partial' clause is invalid = here; turns loop into non-loop} "" { target *-*-* } .-1 } */ + for (int i =3D -300; i !=3D 100; ++i) + dummy (i); + +#pragma omp unroll partial( /* { dg-error {expected expression before end = of line} "" { target c } } */ + /* { dg-error {expected primary-expression before end of line} "" { targ= et c++ } .-1 } */ + for (int i =3D -300; i !=3D 100; ++i) + dummy (i); + +#pragma omp unroll partial() /* { dg-error {expected expression before '\)= ' token} "" { target c } } */ + /* { dg-error {expected primary-expression before '\)' token} "" { targe= t c++ } .-1 } */ + for (int i =3D -300; i !=3D 100; ++i) + dummy (i); + +#pragma omp unroll partial(i) + /* { dg-error {the value of 'i' is not usable in a constant expression} "= " { target c++ } .-1 } */ + /* { dg-error {partial argument needs positive constant integer expressio= n} "" { target c } .-2 } */ + for (int i =3D -300; i !=3D 100; ++i) + dummy (i); + +#pragma omp unroll parti /* { dg-error {expected '#pragma omp' clause befo= re 'parti'} } */ + for (int i =3D -300; i !=3D 100; ++i) + dummy (i); + +#pragma omp for +#pragma omp unroll partial(1) +#pragma omp unroll parti /* { dg-error {expected '#pragma omp' clause befo= re 'parti'} } */ + /* { dg-error {'#pragma omp unroll' without 'partial' clause is invalid = here; turns loop into non-loop} "" { target *-*-* } .-1 } */ + for (int i =3D -300; i !=3D 100; ++i) + dummy (i); + +#pragma omp for +#pragma omp unroll partial(1) +#pragma omp unroll parti /* { dg-error {expected '#pragma omp' clause befo= re 'parti'} } */ + /* { dg-error {'#pragma omp unroll' without 'partial' clause is invalid = here; turns loop into non-loop} "" { target *-*-* } .-1 } */ + for (int i =3D -300; i !=3D 100; ++i) + dummy (i); + +int sum =3D 0; +#pragma omp parallel for reduction(+ : sum) collapse(2) /* { dg-error {col= lapse cannot be larger than 1 on an unrolled loop} "" { target c } } */ +#pragma omp unroll partial(1) /* { dg-error {collapse cannot be larger tha= n 1 on an unrolled loop} "" { target c++ } } */ + for (int i =3D 3; i < 10; ++i) + for (int j =3D -2; j < 7; ++j) + sum++; +} + diff --git a/gcc/testsuite/c-c++-common/gomp/loop-transforms/unroll-3.c b/g= cc/testsuite/c-c++-common/gomp/loop-transforms/unroll-3.c new file mode 100644 index 00000000000..7ace5657b26 --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/loop-transforms/unroll-3.c @@ -0,0 +1,18 @@ +/* { dg-additional-options "-fdump-tree-omp_transform_loops" } + * { dg-additional-options "-fdump-tree-original" } */ + +extern void dummy (int); + +void +test1 () +{ + int i; +#pragma omp unroll full + for (int i =3D 0; i < 10; i++) + dummy (i); +} + + /* Loop should be removed with 10 copies of the body remaining + * { dg-final { scan-tree-dump-times "dummy" 10 "omp_transform_loops" } } + * { dg-final { scan-tree-dump "#pragma omp loop_transform" "original" } = } + * { dg-final { scan-tree-dump-not "#pragma omp" "omp_transform_loops" } = } */ diff --git a/gcc/testsuite/c-c++-common/gomp/loop-transforms/unroll-4.c b/g= cc/testsuite/c-c++-common/gomp/loop-transforms/unroll-4.c new file mode 100644 index 00000000000..5e473a099d3 --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/loop-transforms/unroll-4.c @@ -0,0 +1,19 @@ +/* { dg-additional-options "-fdump-tree-omp_transform_loops" } + * { dg-additional-options "-fdump-tree-original" } */ + +extern void dummy (int); + +void +test1 () +{ + int i; +#pragma omp unroll + for (int i =3D 0; i < 100; i++) + dummy (i); +} + +/* Loop should not be unrolled, but the internal representation should be = lowered + * { dg-final { scan-tree-dump "#pragma omp loop_transform" "original" } } + * { dg-final { scan-tree-dump-not "#pragma omp" "omp_transform_loops" } } + * { dg-final { scan-tree-dump-times "dummy" 1 "omp_transform_loops" } } + * { dg-final { scan-tree-dump-times {if \(i < .+?.+goto.+else goto.*?$} 1= "omp_transform_loops" } } */ diff --git a/gcc/testsuite/c-c++-common/gomp/loop-transforms/unroll-5.c b/g= cc/testsuite/c-c++-common/gomp/loop-transforms/unroll-5.c new file mode 100644 index 00000000000..9d5101bdc60 --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/loop-transforms/unroll-5.c @@ -0,0 +1,19 @@ +/* { dg-additional-options "-fdump-tree-omp_transform_loops -fopt-info-omp= -optimized-missed" } + * { dg-additional-options "-fdump-tree-original" } */ + +extern void dummy (int); + +void +test1 () +{ + int i; +#pragma omp unroll partial /* { dg-optimized {'partial' clause without un= rolling factor turned into 'partial\(5\)' clause} } */ + for (int i =3D 0; i < 100; i++) + dummy (i); +} + +/* Loop should be unrolled 5 times and the internal representation should = be lowered + * { dg-final { scan-tree-dump "#pragma omp loop_transform" "original" } } + * { dg-final { scan-tree-dump-not "#pragma omp" "omp_transform_loops" } } + * { dg-final { scan-tree-dump-times "dummy" 5 "omp_transform_loops" } } + * { dg-final { scan-tree-dump-times {if \(i < .+?.+goto.+else goto.*?$} 1= "omp_transform_loops" } } */ diff --git a/gcc/testsuite/c-c++-common/gomp/loop-transforms/unroll-6.c b/g= cc/testsuite/c-c++-common/gomp/loop-transforms/unroll-6.c new file mode 100644 index 00000000000..ee2d000239d --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/loop-transforms/unroll-6.c @@ -0,0 +1,20 @@ +/* { dg-additional-options "--param=3Domp-unroll-default-factor=3D100" } + * { dg-additional-options "-fdump-tree-omp_transform_loops -fopt-info-omp= -optimized-missed" } + * { dg-additional-options "-fdump-tree-original" } */ + +extern void dummy (int); + +void +test1 () +{ + int i; +#pragma omp unroll /* { dg-optimized {added 'partial\(100\)' clause to 'om= p unroll' directive} } */ + for (int i =3D 0; i < 100; i++) + dummy (i); +} + +/* Loop should be unrolled 5 times and the internal representation should = be lowered + * { dg-final { scan-tree-dump "#pragma omp loop_transform unroll_none" "o= riginal" } } + * { dg-final { scan-tree-dump-not "#pragma omp" "omp_transform_loops" } } + * { dg-final { scan-tree-dump-times "dummy" 100 "omp_transform_loops" } } + * { dg-final { scan-tree-dump-times {if \(i < .+?.+goto.+else goto.*?$} 1= "omp_transform_loops" } } */ diff --git a/gcc/testsuite/c-c++-common/gomp/loop-transforms/unroll-7.c b/g= cc/testsuite/c-c++-common/gomp/loop-transforms/unroll-7.c new file mode 100644 index 00000000000..0458cb030a9 --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/loop-transforms/unroll-7.c @@ -0,0 +1,144 @@ +/* { dg-do run } */ +/* { dg-options "-O0 -fopenmp-simd" } */ + +#include + +#define ASSERT_EQ(var, val) if (var !=3D val) { fprintf (stderr, "%s:%d: U= nexpected value %d\n", __FILE__, __LINE__, var); \ + __builtin_abort (); } + +#define ASSERT_EQ_PTR(var, ptr) if (var !=3D ptr) { fprintf (stderr, "%s:%= d: Unexpected value %p\n", __FILE__, __LINE__, var); \ + __builtin_abort (); } + +int +test1 (int data[10]) +{ + int iter =3D 0; + int *i; + #pragma omp unroll partial(8) + for (i =3D data; i < data + 10 ; i++) + { + ASSERT_EQ (*i, data[iter]); + ASSERT_EQ_PTR (i, data + iter); + iter++; + } + + return iter; +} + +int +test2 (int data[10]) +{ + int iter =3D 0; + int *i; + #pragma omp unroll partial(8) + for (i =3D data; i < data + 10 ; i=3Di+2) + { + ASSERT_EQ_PTR (i, data + 2 * iter); + ASSERT_EQ (*i, data[2 * iter]); + iter++; + } + + return iter; +} + +int +test3 (int data[10]) +{ + int iter =3D 0; + int *i; + #pragma omp unroll partial(8) + for (i =3D data; i <=3D data + 9 ; i=3Di+2) + { + ASSERT_EQ (*i, data[2 * iter]); + iter++; + } + + return iter; +} + +int +test4 (int data[10]) +{ + int iter =3D 0; + int *i; + #pragma omp unroll partial(8) + for (i =3D data; i !=3D data + 10 ; i=3Di+1) + { + ASSERT_EQ (*i, data[iter]); + iter++; + } + + return iter; +} + +int +test5 (int data[10]) +{ + int iter =3D 0; + int *i; + #pragma omp unroll partial(7) + for (i =3D data + 9; i >=3D data ; i--) + { + ASSERT_EQ (*i, data[9 - iter]); + iter++; + } + + return iter; +} + +int +test6 (int data[10]) +{ + int iter =3D 0; + int *i; + #pragma omp unroll partial(7) + for (i =3D data + 9; i > data - 1 ; i--) + { + ASSERT_EQ (*i, data[9 - iter]); + iter++; + } + + return iter; +} + +int +test7 (int data[10]) +{ + int iter =3D 0; + #pragma omp unroll partial(7) + for (int *i =3D data + 9; i !=3D data - 1 ; i--) + { + ASSERT_EQ (*i, data[9 - iter]); + iter++; + } + + return iter; +} + +int +main () +{ + int iter_count; + int data[10] =3D { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + + iter_count =3D test1 (data); + ASSERT_EQ (iter_count, 10); + + iter_count =3D test2 (data); + ASSERT_EQ (iter_count, 5); + + iter_count =3D test3 (data); + ASSERT_EQ (iter_count, 5); + + iter_count =3D test4 (data); + ASSERT_EQ (iter_count, 10); + + iter_count =3D test5 (data); + ASSERT_EQ (iter_count, 10); + + iter_count =3D test6 (data); + ASSERT_EQ (iter_count, 10); + + iter_count =3D test7 (data); + ASSERT_EQ (iter_count, 10); +} diff --git a/gcc/testsuite/c-c++-common/gomp/loop-transforms/unroll-simd-1.= c b/gcc/testsuite/c-c++-common/gomp/loop-transforms/unroll-simd-1.c new file mode 100644 index 00000000000..1cd4d6e7322 --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/loop-transforms/unroll-simd-1.c @@ -0,0 +1,84 @@ +/* { dg-options "-fno-openmp -fopenmp-simd" } */ +/* { dg-do run } */ +/* { dg-additional-options "-fdump-tree-original" } */ +/* { dg-additional-options "-fdump-tree-omp_transform_loops" } */ + +#include + +int compute_sum1 () +{ + int sum =3D 0; + int i,j; + +#pragma omp simd reduction(+:sum) + for (i =3D 3; i < 10; ++i) + #pragma omp unroll full + for (j =3D -2; j < 7; ++j) + sum++; + + if (j !=3D 7) + __builtin_abort; + + return sum; +} + +int compute_sum2() +{ + int sum =3D 0; + int i,j; +#pragma omp simd reduction(+:sum) +#pragma omp unroll partial(5) + for (i =3D 3; i < 10; ++i) + for (j =3D -2; j < 7; ++j) + sum++; + + if (j !=3D 7) + __builtin_abort; + + return sum; +} + +int compute_sum3() +{ + int sum =3D 0; + int i,j; +#pragma omp simd reduction(+:sum) +#pragma omp unroll partial(1) + for (i =3D 3; i < 10; ++i) + for (j =3D -2; j < 7; ++j) + sum++; + + if (j !=3D 7) + __builtin_abort; + + return sum; +} + +int main () +{ + int result =3D compute_sum1 (); + if (result !=3D 7 * 9) + { + fprintf (stderr, "%d: Wrong result %d\n", __LINE__, result); + __builtin_abort (); + } + + result =3D compute_sum1 (); + if (result !=3D 7 * 9) + { + fprintf (stderr, "%d: Wrong result %d\n", __LINE__, result); + __builtin_abort (); + } + + result =3D compute_sum3 (); + if (result !=3D 7 * 9) + { + fprintf (stderr, "%d: Wrong result %d\n", __LINE__, result); + __builtin_abort (); + } + + return 0; +} + +/* { dg-final { scan-tree-dump {omp loop_transform} "original" } } */ +/* { dg-final { scan-tree-dump-not {omp loop_transform} "omp_transform_loo= ps" } } */ diff --git a/gcc/testsuite/g++.dg/gomp/loop-transforms/unroll-1.C b/gcc/tes= tsuite/g++.dg/gomp/loop-transforms/unroll-1.C new file mode 100644 index 00000000000..cba37c88ebe --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/loop-transforms/unroll-1.C @@ -0,0 +1,42 @@ +// { dg-do compile } +// { dg-additional-options "-std=3Dc++11" } +#include + +extern void dummy (int); + +void +test1 () +{ + std::vector v; + + for (unsigned i =3D 0; i < 1000; i++) + v.push_back (i); + +#pragma omp for + for (int i : v) + dummy (i); + +#pragma omp unroll partial(5) + for (int i : v) + dummy (i); +} + +void +test2 () +{ + std::vector> v; + + for (unsigned i =3D 0; i < 10; i++) + { + std::vector u; + for (unsigned j =3D 0; j < 10; j++) + u.push_back (j); + v.push_back (u); + } + +#pragma omp for +#pragma omp unroll partial(5) + for (auto u : v) + for (int i : u) + dummy (i); +} diff --git a/gcc/testsuite/g++.dg/gomp/loop-transforms/unroll-2.C b/gcc/tes= tsuite/g++.dg/gomp/loop-transforms/unroll-2.C new file mode 100644 index 00000000000..f606f3de757 --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/loop-transforms/unroll-2.C @@ -0,0 +1,47 @@ +// { dg-do link } +// { dg-additional-options "-std=3Dc++11" } +#include + +extern void dummy (int); + +template void +test_template () +{ + std::vector v; + + for (unsigned i =3D 0; i < 1000; i++) + v.push_back (i); + +#pragma omp for + for (int i : v) + dummy (i); + +#pragma omp unroll partial(U1) + for (T i : v) + dummy (i); + +#pragma omp unroll partial(U2) // { dg-error {partial argument needs posit= ive constant integer expression} } + for (T i : v) + dummy (i); + +#pragma omp unroll partial(U3) // { dg-error {partial argument needs posit= ive constant integer expression} } + for (T i : v) + dummy (i); + +#pragma omp for +#pragma omp unroll partial(U1) + for (T i : v) + dummy (i); + +#pragma omp for +#pragma omp unroll partial(U2) // { dg-error {partial argument needs posit= ive constant integer expression} } + for (T i : v) + dummy (i); + +#pragma omp for +#pragma omp unroll partial(U3) // { dg-error {partial argument needs posit= ive constant integer expression} } + for (T i : v) + dummy (i); +} + +void test () { test_template (); }; diff --git a/gcc/testsuite/g++.dg/gomp/loop-transforms/unroll-3.C b/gcc/tes= tsuite/g++.dg/gomp/loop-transforms/unroll-3.C new file mode 100644 index 00000000000..ae9f5500360 --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/loop-transforms/unroll-3.C @@ -0,0 +1,37 @@ +// { dg-do compile } +// { dg-additional-options "-std=3Dc++11" } +// { dg-additional-options "-fdump-tree-omp_transform_loops -fopt-info-omp= -optimized-missed" } +// { dg-additional-options "-fdump-tree-original" } +#include + +extern void dummy (int); + +constexpr unsigned fib (unsigned n) +{ + return n <=3D 2 ? 1 : fib (n-1) + fib (n-2); +} + +void +test1 () +{ + std::vector v; + + for (unsigned i =3D 0; i < 1000; i++) + v.push_back (i); + +#pragma omp unroll partial(fib(10)) + for (int i : v) + dummy (i); +} + + +// Loop should be unrolled fib(10) =3D 55 times +// ! { dg-final { scan-tree-dump {#pragma omp loop_transform unroll_partia= l\(55\)} "original" } } +// ! { dg-final { scan-tree-dump-not "#pragma omp" "omp_transform_loops" }= } +// ! { dg-final { scan-tree-dump-times "dummy" 55 "omp_transform_loops" } = } + +// There should be one loop that fills the vector ... +// ! { dg-final { scan-tree-dump-times {if \(i.*? <=3D .+?.+goto.+else got= o.*?$} 1 "omp_transform_loops" } } + +// ... and one resulting from the lowering of the unrolled loop +// ! { dg-final { scan-tree-dump-times {if \(D\.[0-9]+ < retval.+?.+goto.+= else goto.*?$} 1 "omp_transform_loops" } } diff --git a/libgomp/testsuite/libgomp.c++/loop-transforms/unroll-1.C b/lib= gomp/testsuite/libgomp.c++/loop-transforms/unroll-1.C new file mode 100644 index 00000000000..004eef91649 --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/loop-transforms/unroll-1.C @@ -0,0 +1,73 @@ +// { dg-additional-options "-std=3Dc++11" } +// { dg-additional-options "-O0" } + +#include +#include + +constexpr unsigned fib (unsigned n) +{ + return n <=3D 2 ? 1 : fib (n-1) + fib (n-2); +} + +int +test1 () +{ + std::vector v; + + for (unsigned i =3D 0; i <=3D 9; i++) + v.push_back (1); + + int sum =3D 0; + for (int k =3D 0; k < 10; k++) +#pragma omp unroll partial(fib(3)) + for (int i : v) { + for (int j =3D 8; j !=3D -2; --j) + sum =3D sum + i; + } + + return sum; +} + +int +test2 () +{ + std::vector v; + + for (unsigned i =3D 0; i <=3D 10; i++) + v.push_back (i); + + int sum =3D 0; +#pragma omp parallel for reduction(+:sum) + for (int k =3D 0; k < 10; k++) +#pragma omp unroll +#pragma omp unroll partial(fib(4)) + for (int i : v) + { + #pragma omp unroll full + for (int j =3D 8; j !=3D -2; --j) + sum =3D sum + i; + } + + return sum; +} + +int +main () +{ + int result =3D test1 (); + + if (result !=3D 1000) + { + fprintf (stderr, "Wrong result: %d\n", result); + __builtin_abort (); + } + + result =3D test2 (); + if (result !=3D 5500) + { + fprintf (stderr, "Wrong result: %d\n", result); + __builtin_abort (); + } + + return 0; +} diff --git a/libgomp/testsuite/libgomp.c++/loop-transforms/unroll-2.C b/lib= gomp/testsuite/libgomp.c++/loop-transforms/unroll-2.C new file mode 100644 index 00000000000..90d2775c95b --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/loop-transforms/unroll-2.C @@ -0,0 +1,34 @@ +// { dg-do run } +// { dg-additional-options "-std=3Dc++11" } +#include +#include + +int +main () +{ + std::vector> v; + std::vector w; + + for (unsigned i =3D 0; i < 10; i++) + { + std::vector u; + for (unsigned j =3D 0; j < 10; j++) + u.push_back (j); + v.push_back (u); + } + +#pragma omp for +#pragma omp unroll partial(7) + for (auto u : v) + for (int x : u) + w.push_back (x); + + std::size_t l =3D w.size (); + for (std::size_t i =3D 0; i < l; i++) + { + if (w[i] !=3D i % 10) + __builtin_abort (); + } + + return 0; +} diff --git a/libgomp/testsuite/libgomp.c-c++-common/loop-transforms/unroll-= 1.c b/libgomp/testsuite/libgomp.c-c++-common/loop-transforms/unroll-1.c new file mode 100644 index 00000000000..2ac0fff16af --- /dev/null +++ b/libgomp/testsuite/libgomp.c-c++-common/loop-transforms/unroll-1.c @@ -0,0 +1,76 @@ +#include + +int compute_sum1 () +{ + int sum =3D 0; + int i,j; +#pragma omp parallel for reduction(+:sum) lastprivate(j) +#pragma omp unroll partial + for (i =3D 3; i < 10; ++i) + for (j =3D -2; j < 7; ++j) + sum++; + + if (j !=3D 7) + __builtin_abort; + + return sum; +} + +int compute_sum2() +{ + int sum =3D 0; + int i,j; +#pragma omp parallel for reduction(+:sum) lastprivate(j) +#pragma omp unroll partial(5) + for (i =3D 3; i < 10; ++i) + for (j =3D -2; j < 7; ++j) + sum++; + + if (j !=3D 7) + __builtin_abort; + + return sum; +} + +int compute_sum3() +{ + int sum =3D 0; + int i,j; +#pragma omp parallel for reduction(+:sum) +#pragma omp unroll partial(1) + for (i =3D 3; i < 10; ++i) + for (j =3D -2; j < 7; ++j) + sum++; + + if (j !=3D 7) + __builtin_abort; + + return sum; +} + +int main () +{ + int result; + result =3D compute_sum1 (); + if (result !=3D 7 * 9) + { + fprintf (stderr, "%d: Wrong result %d\n", __LINE__, result); + __builtin_abort (); + } + + result =3D compute_sum2 (); + if (result !=3D 7 * 9) + { + fprintf (stderr, "%d: Wrong result %d\n", __LINE__, result); + __builtin_abort (); + } + + result =3D compute_sum3 (); + if (result !=3D 7 * 9) + { + fprintf (stderr, "%d: Wrong result %d\n", __LINE__, result); + __builtin_abort (); + } + + return 0; +} -- 2.36.1 ----------------- Siemens Electronic Design Automation GmbH; Anschrift: Arnulfstra=DFe 201, 8= 0634 M=FCnchen; Gesellschaft mit beschr=E4nkter Haftung; Gesch=E4ftsf=FChre= r: Thomas Heurung, Frank Th=FCrauf; Sitz der Gesellschaft: M=FCnchen; Regis= tergericht M=FCnchen, HRB 106955