From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from esa3.mentor.iphmx.com (esa3.mentor.iphmx.com [68.232.137.180]) by sourceware.org (Postfix) with ESMTPS id BDA973858C78 for ; Fri, 24 Mar 2023 15:51:49 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org BDA973858C78 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="274542" Received: from orw-gwy-02-in.mentorg.com ([192.94.38.167]) by esa3.mentor.iphmx.com with ESMTP; 24 Mar 2023 07:31:24 -0800 IronPort-SDR: nMWqhwbwIHSPXJ7tn7tJU828gsnQk8l9lgH9EylWOO5SOzXj8FfMeMWyl/1ZkhoMvxyBoGDa/r DKPcnjHZqfU/a4yKPZRObGZK85hVodkyCFsxyrNKAC2U8/EtLJo0wqt1bRvsP6pEa/kSeKyAoW sbULNIXWgDQsKAZ8PdfZc8pKu7lX9JiefYl2oyd7ZgVFvqUQEWlZZznXH+414+AJbpGxHc5T/m x+i2+9/CP4eFuQQbBL2qw1k7KPHiQJnWoh6LN59ZTdzltTBFFGllsNczWmmJ7tW/YqovjZXjkB bu4= From: Frederik Harwath To: , , , , Subject: [PATCH 5/7] openmp: Add C/C++ support for "omp tile" Date: Fri, 24 Mar 2023 16:30:43 +0100 Message-ID: <20230324153046.3996092-6-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-14.mgc.mentorg.com (139.181.222.14) 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 adds the C and C++ front end support for the "omp tile" directive. gcc/c-family/ChangeLog: * c-omp.cc (c_omp_directives): Add PRAGMA_OMP_TILE. * c-pragma.cc (omp_pragmas_simd): Likewise. * c-pragma.h (enum pragma_kind): Add PRAGMA_OMP_TILE. (enum pragma_omp_clause): Add PRAGMA_OMP_CLAUSE_TILE gcc/c/ChangeLog: * c-parser.cc (c_parser_nested_omp_unroll_clauses): Rename and generalize ... (c_parser_omp_nested_loop_transform_clauses): ... to this. (c_parser_omp_for_loop): Handle "omp tile" parsing in loop nests. (c_parser_omp_tile_sizes): Parse single "sizes" clause. (c_parser_omp_loop_transform_clause): New function. (c_parser_omp_tile): New function for parsing "omp tile" (c_parser_omp_unroll): Adjust to renaming. (c_parser_omp_construct): Handle PRAGMA_OMP_TILE. gcc/cp/ChangeLog: * parser.cc (cp_parser_omp_clause_unroll_partial): Adjust. (cp_parser_nested_omp_unroll_clauses): Rename ... (cp_parser_omp_nested_loop_transform_clauses): ... to this. (cp_parser_omp_for_loop): Handle "omp tile" parsing in loop nests. (cp_parser_omp_tile_sizes): New function, parses single "sizes" cla= use (cp_parser_omp_tile): New function for parsing "omp tile". (cp_parser_omp_loop_transform_clause): New function. (cp_parser_omp_unroll): Adjust to renaming. (cp_parser_omp_construct): Handle PRAGMA_OMP_TILE. (cp_parser_pragma): Likewise. * pt.cc (tsubst_omp_clauses): Handle OMP_CLAUSE_TILE. * semantics.cc (finish_omp_clauses): Likewise. gcc/ChangeLog: * gimplify.cc (omp_for_drop_tile_clauses): New function, ... (gimplify_omp_for): ... used here. libgomp/ChangeLog: * testsuite/libgomp.c++/loop-transforms/tile-1.C: New test. * testsuite/libgomp.c++/loop-transforms/tile-2.C: New test. * testsuite/libgomp.c++/loop-transforms/tile-3.C: New test. gcc/testsuite/ChangeLog: * c-c++-common/gomp/loop-transforms/tile-1.c: New test. * c-c++-common/gomp/loop-transforms/tile-2.c: New test. * c-c++-common/gomp/loop-transforms/tile-3.c: New test. * c-c++-common/gomp/loop-transforms/tile-4.c: New test. * c-c++-common/gomp/loop-transforms/tile-5.c: New test. * c-c++-common/gomp/loop-transforms/tile-6.c: New test. * c-c++-common/gomp/loop-transforms/tile-7.c: New test. * c-c++-common/gomp/loop-transforms/tile-8.c: New test. * c-c++-common/gomp/loop-transforms/unroll-2.c: Adapt. * g++.dg/gomp/loop-transforms/tile-1.h: New test. * g++.dg/gomp/loop-transforms/tile-1a.C: New test. * g++.dg/gomp/loop-transforms/tile-1b.C: New test. --- gcc/c-family/c-omp.cc | 4 +- gcc/c-family/c-pragma.cc | 1 + gcc/c-family/c-pragma.h | 2 + gcc/c/c-parser.cc | 277 ++++++++++++--- gcc/cp/parser.cc | 289 +++++++++++++--- gcc/cp/pt.cc | 1 + gcc/cp/semantics.cc | 40 +++ gcc/gimplify.cc | 28 ++ .../gomp/loop-transforms/tile-1.c | 164 +++++++++ .../gomp/loop-transforms/tile-2.c | 183 ++++++++++ .../gomp/loop-transforms/tile-3.c | 117 +++++++ .../gomp/loop-transforms/tile-4.c | 322 ++++++++++++++++++ .../gomp/loop-transforms/tile-5.c | 150 ++++++++ .../gomp/loop-transforms/tile-6.c | 34 ++ .../gomp/loop-transforms/tile-7.c | 31 ++ .../gomp/loop-transforms/tile-8.c | 40 +++ .../gomp/loop-transforms/unroll-2.c | 12 +- .../g++.dg/gomp/loop-transforms/tile-1.h | 27 ++ .../g++.dg/gomp/loop-transforms/tile-1a.C | 27 ++ .../g++.dg/gomp/loop-transforms/tile-1b.C | 27 ++ .../libgomp.c++/loop-transforms/tile-1.C | 52 +++ .../libgomp.c++/loop-transforms/tile-2.C | 69 ++++ .../libgomp.c++/loop-transforms/tile-3.C | 28 ++ 23 files changed, 1823 insertions(+), 102 deletions(-) create mode 100644 gcc/testsuite/c-c++-common/gomp/loop-transforms/tile-1.= c create mode 100644 gcc/testsuite/c-c++-common/gomp/loop-transforms/tile-2.= c create mode 100644 gcc/testsuite/c-c++-common/gomp/loop-transforms/tile-3.= c create mode 100644 gcc/testsuite/c-c++-common/gomp/loop-transforms/tile-4.= c create mode 100644 gcc/testsuite/c-c++-common/gomp/loop-transforms/tile-5.= c create mode 100644 gcc/testsuite/c-c++-common/gomp/loop-transforms/tile-6.= c create mode 100644 gcc/testsuite/c-c++-common/gomp/loop-transforms/tile-7.= c create mode 100644 gcc/testsuite/c-c++-common/gomp/loop-transforms/tile-8.= c create mode 100644 gcc/testsuite/g++.dg/gomp/loop-transforms/tile-1.h create mode 100644 gcc/testsuite/g++.dg/gomp/loop-transforms/tile-1a.C create mode 100644 gcc/testsuite/g++.dg/gomp/loop-transforms/tile-1b.C create mode 100644 libgomp/testsuite/libgomp.c++/loop-transforms/tile-1.C create mode 100644 libgomp/testsuite/libgomp.c++/loop-transforms/tile-2.C create mode 100644 libgomp/testsuite/libgomp.c++/loop-transforms/tile-3.C diff --git a/gcc/c-family/c-omp.cc b/gcc/c-family/c-omp.cc index fec7f337772..2ab7faea2cc 100644 --- a/gcc/c-family/c-omp.cc +++ b/gcc/c-family/c-omp.cc @@ -3207,8 +3207,8 @@ const struct c_omp_directive c_omp_directives[] =3D { C_OMP_DIR_STANDALONE, false }, { "taskyield", nullptr, nullptr, PRAGMA_OMP_TASKYIELD, C_OMP_DIR_STANDALONE, false }, - /* { "tile", nullptr, nullptr, PRAGMA_OMP_TILE, - C_OMP_DIR_CONSTRUCT, false }, */ + { "tile", nullptr, nullptr, PRAGMA_OMP_TILE, + C_OMP_DIR_CONSTRUCT, false }, { "teams", nullptr, nullptr, PRAGMA_OMP_TEAMS, C_OMP_DIR_CONSTRUCT, true }, { "threadprivate", nullptr, nullptr, PRAGMA_OMP_THREADPRIVATE, diff --git a/gcc/c-family/c-pragma.cc b/gcc/c-family/c-pragma.cc index 96a28ac1b0c..75d5cabbafd 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 }, + { "tile", PRAGMA_OMP_TILE }, { "unroll", PRAGMA_OMP_UNROLL }, }; diff --git a/gcc/c-family/c-pragma.h b/gcc/c-family/c-pragma.h index 6686abdc94d..c0476f74441 100644 --- a/gcc/c-family/c-pragma.h +++ b/gcc/c-family/c-pragma.h @@ -81,6 +81,7 @@ enum pragma_kind { PRAGMA_OMP_TASKYIELD, PRAGMA_OMP_THREADPRIVATE, PRAGMA_OMP_TEAMS, + PRAGMA_OMP_TILE, PRAGMA_OMP_UNROLL, /* PRAGMA_OMP__LAST_ should be equal to the last PRAGMA_OMP_* code. */ PRAGMA_OMP__LAST_ =3D PRAGMA_OMP_UNROLL, @@ -157,6 +158,7 @@ enum pragma_omp_clause { PRAGMA_OMP_CLAUSE_TASKGROUP, PRAGMA_OMP_CLAUSE_THREAD_LIMIT, PRAGMA_OMP_CLAUSE_THREADS, + PRAGMA_OMP_CLAUSE_TILE, PRAGMA_OMP_CLAUSE_TO, PRAGMA_OMP_CLAUSE_UNIFORM, PRAGMA_OMP_CLAUSE_UNTIED, diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc index e7c9da99552..aac23dec9c0 100644 --- a/gcc/c/c-parser.cc +++ b/gcc/c/c-parser.cc @@ -20243,7 +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 &); +static int c_parser_omp_nested_loop_transform_clauses (c_parser *, tree &,= int, + const char *); /* 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 @@ -20263,16 +20264,18 @@ c_parser_omp_for_loop (location_t loc, c_parser *= parser, enum tree_code code, bool fail =3D false, open_brace_parsed =3D false; int i, collapse =3D 1, ordered =3D 0, count, nbraces =3D 0; location_t for_loc; - bool tiling =3D false; + bool oacc_tiling =3D false; bool inscan =3D false; vec *for_block =3D make_tree_vector (); for (cl =3D clauses; cl; cl =3D OMP_CLAUSE_CHAIN (cl)) if (OMP_CLAUSE_CODE (cl) =3D=3D OMP_CLAUSE_COLLAPSE) - collapse =3D tree_to_shwi (OMP_CLAUSE_COLLAPSE_EXPR (cl)); + { + collapse =3D tree_to_shwi (OMP_CLAUSE_COLLAPSE_EXPR (cl)); + } else if (OMP_CLAUSE_CODE (cl) =3D=3D OMP_CLAUSE_OACC_TILE) { - tiling =3D true; + oacc_tiling =3D true; collapse =3D list_length (OMP_CLAUSE_OACC_TILE_LIST (cl)); } else if (OMP_CLAUSE_CODE (cl) =3D=3D OMP_CLAUSE_ORDERED @@ -20295,21 +20298,31 @@ c_parser_omp_for_loop (location_t loc, c_parser *= parser, enum tree_code code, ordered =3D collapse; } - gcc_assert (tiling || (collapse >=3D 1 && ordered >=3D 0)); + c_parser_omp_nested_loop_transform_clauses (parser, clauses, collapse, + "loop collapse"); + + /* Find the depth of the loop nest affected by "omp tile" + directives. There can be several such directives, but the tiling + depth of the outer ones may not be larger than the depth of the + innermost directive. */ + int omp_tile_depth =3D 0; + for (tree c =3D clauses; c; c =3D TREE_CHAIN (c)) + { + if (OMP_CLAUSE_CODE (c) !=3D OMP_CLAUSE_TILE) + continue; + + omp_tile_depth =3D list_length (OMP_CLAUSE_TILE_SIZES (c)); + } + + gcc_assert (oacc_tiling || (collapse >=3D 1 && ordered >=3D 0)); count =3D ordered ? ordered : collapse; + count =3D MAX (count, omp_tile_depth); declv =3D make_tree_vec (count); initv =3D make_tree_vec (count); 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"); @@ -23945,47 +23958,224 @@ c_parser_omp_taskloop (location_t loc, c_parser = *parser, ( (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. */ +/* OpenMP 5.1: Parse sizes list for "omp tile sizes" + sizes ( size-expr-list ) */ +static tree +c_parser_omp_tile_sizes (c_parser *parser, location_t loc) +{ + tree sizes =3D NULL_TREE; -static bool -c_parser_nested_omp_unroll_clauses (c_parser *parser, tree &clauses) + c_token *tok =3D c_parser_peek_token (parser); + if (tok->type !=3D CPP_NAME + || strcmp ("sizes", IDENTIFIER_POINTER (tok->value))) + { + c_parser_error (parser, "expected %"); + return error_mark_node; + } + c_parser_consume_token (parser); + + if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) + return error_mark_node; + + do + { + if (sizes && !c_parser_require (parser, CPP_COMMA, "expected %<,%>")= ) + return error_mark_node; + + location_t expr_loc =3D c_parser_peek_token (parser)->location; + c_expr cexpr =3D c_parser_expr_no_commas (parser, NULL); + cexpr =3D convert_lvalue_to_rvalue (expr_loc, cexpr, false, true); + tree expr =3D cexpr.value; + + if (expr =3D=3D error_mark_node) + { + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, + "expected %<)%>"); + return error_mark_node; + } + + expr =3D c_fully_fold (expr, false, NULL); + + if (!INTEGRAL_TYPE_P (TREE_TYPE (expr)) || !tree_fits_shwi_p (expr) + || tree_to_shwi (expr) <=3D 0) + { + c_parser_error (parser, "% argument needs positive" + " integral constant"); + expr =3D integer_zero_node; + } + + sizes =3D tree_cons (NULL_TREE, expr, sizes); + } + while (c_parser_next_token_is_not (parser, CPP_CLOSE_PAREN)); + c_parser_consume_token (parser); + + gcc_assert (sizes); + tree c =3D build_omp_clause (loc, OMP_CLAUSE_TILE); + OMP_CLAUSE_TILE_SIZES (c) =3D sizes; + + return c; +} + +/* Parse a single OpenMP loop transformation directive and return the + clause that is used internally to represent the directive. */ + +static tree +c_parser_omp_loop_transform_clause (c_parser *parser) { - 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_token *tok =3D c_parser_peek_token (parser); + if (tok->type !=3D CPP_PRAGMA) + return NULL_TREE; + + tree c; + switch (tok->pragma_kind) { + case 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) + c =3D c_parser_omp_all_clauses (parser, OMP_UNROLL_CLAUSE_MASK, + "#pragma omp unroll", false, 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; - } + if (c_parser_next_token_is (parser, CPP_PRAGMA_EOL)) + c =3D build_omp_clause (tok->location, OMP_CLAUSE_UNROLL_NONE); + else + c =3D error_mark_node; } - else + c_parser_skip_to_pragma_eol (parser); + break; + + case PRAGMA_OMP_TILE: + c_parser_consume_pragma (parser); + c =3D c_parser_omp_tile_sizes (parser, tok->location); + c_parser_skip_to_pragma_eol (parser); + break; + + default: + c =3D NULL_TREE; + break; + } + + gcc_assert (!c || !TREE_CHAIN (c)); + return c; +} + +/* Parse zero or more OpenMP loop transformation directives that + follow another directive that requires a canonical loop nest and + append all to CLAUSES. Return the nesting depth + of the transformed loop nest. + + REQUIRED_DEPTH is the nesting depth of the loop nest required by + the preceding directive. OUTER_DESCR is a description of the + language construct that requires the loop nest depth (e.g. "loop + collpase", "outer transformation") that is used for error + messages. */ + +static int +c_parser_omp_nested_loop_transform_clauses (c_parser *parser, tree &clause= s, + int required_depth, + const char *outer_descr) +{ + tree c =3D NULL_TREE; + tree last_c =3D tree_last (clauses); + + /* The depth of the loop nest, counting from LEVEL, after the + transformations. That is, the nesting depth left by the outermost + transformation which is the first to be parsed, but the last to be + executed. */ + int transformed_depth =3D 0; + + /* The minimum nesting depth required by the last parsed transformation.= */ + int last_depth =3D required_depth; + while ((c =3D c_parser_omp_loop_transform_clause (parser))) + { + /* The nesting depth left after the current transformation */ + int depth =3D 1; + if (TREE_CODE (c) =3D=3D ERROR_MARK) + goto error; + + gcc_assert (!TREE_CHAIN (c)); + switch (OMP_CLAUSE_CODE (c)) { - error_at (tok->location, "%<#pragma omp unroll%> without " - "% clause is invalid here; " - "turns loop into non-loop"); - continue; + case OMP_CLAUSE_UNROLL_FULL: + error_at (OMP_CLAUSE_LOCATION (c), + "% clause is invalid here; " + "turns loop into non-loop"); + goto error; + case OMP_CLAUSE_UNROLL_NONE: + error_at (OMP_CLAUSE_LOCATION (c), + "%<#pragma omp unroll%> without " + "% clause is invalid here; " + "turns loop into non-loop"); + goto error; + case OMP_CLAUSE_UNROLL_PARTIAL: + depth =3D 1; + break; + case OMP_CLAUSE_TILE: + depth =3D list_length (OMP_CLAUSE_TILE_SIZES (c)); + break; + default: + gcc_unreachable (); + } + + if (depth < last_depth) + { + bool is_outermost_clause =3D !transformed_depth; + error_at (OMP_CLAUSE_LOCATION (c), + "nesting depth left after this transformation too low " + "for %s", + is_outermost_clause ? outer_descr + : "outer transformation"); + goto error; } - clauses =3D chainon (clauses, c); + last_depth =3D depth; + + if (!transformed_depth) + transformed_depth =3D last_depth; + + if (!clauses) + clauses =3D c; + else if (last_c) + TREE_CHAIN (last_c) =3D c; + + last_c =3D c; } - return found_unroll; + return transformed_depth; + +error: + while (c_parser_omp_loop_transform_clause (parser)) + ; + clauses =3D NULL_TREE; + return -1; } +/* OpenMP 5.1: + tile sizes ( size-expr-list ) */ + +static tree +c_parser_omp_tile (location_t loc, c_parser *parser, bool *if_p) +{ + tree block; + tree ret =3D error_mark_node; + + tree clauses =3D c_parser_omp_tile_sizes (parser, loc); + c_parser_skip_to_pragma_eol (parser); + + if (!clauses || clauses =3D=3D error_mark_node) + return error_mark_node; + + int required_depth =3D list_length (OMP_CLAUSE_TILE_SIZES (clauses)); + c_parser_omp_nested_loop_transform_clauses (parser, clauses, required_de= pth, + "outer transformation"); + + 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; + } + static tree c_parser_omp_unroll (location_t loc, c_parser *parser, bool *if_p) { @@ -23994,7 +24184,9 @@ c_parser_omp_unroll (location_t loc, c_parser *pars= er, bool *if_p) 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); + int required_depth =3D 1; + c_parser_omp_nested_loop_transform_clauses (parser, clauses, required_de= pth, + "outer transformation"); if (!clauses) { @@ -24496,6 +24688,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_TILE: + stmt =3D c_parser_omp_tile (loc, parser, if_p); + break; case PRAGMA_OMP_UNROLL: stmt =3D c_parser_omp_unroll (loc, parser, if_p); break; diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc index 90af40c4dbc..084ecd3ada5 100644 --- a/gcc/cp/parser.cc +++ b/gcc/cp/parser.cc @@ -43631,7 +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 &); +static int cp_parser_omp_nested_loop_transform_clauses (cp_parser *, tree = &, + int, const char *); /* Parse the restricted form of the for statement allowed by OpenMP. */ @@ -43643,20 +43644,20 @@ cp_parser_omp_for_loop (cp_parser *parser, enum t= ree_code code, tree clauses, tree orig_decl; tree real_decl, initv, condv, incrv, declv, orig_declv; tree this_pre_body, cl, ordered_cl =3D NULL_TREE; - location_t loc_first; bool collapse_err =3D false; int i, collapse =3D 1, ordered =3D 0, count, nbraces =3D 0; releasing_vec for_block; auto_vec orig_inits; - bool tiling =3D false; + bool oacc_tiling =3D false; bool inscan =3D false; + location_t loc_first =3D cp_lexer_peek_token (parser->lexer)->location; for (cl =3D clauses; cl; cl =3D OMP_CLAUSE_CHAIN (cl)) if (OMP_CLAUSE_CODE (cl) =3D=3D OMP_CLAUSE_COLLAPSE) collapse =3D tree_to_shwi (OMP_CLAUSE_COLLAPSE_EXPR (cl)); else if (OMP_CLAUSE_CODE (cl) =3D=3D OMP_CLAUSE_OACC_TILE) { - tiling =3D true; + oacc_tiling =3D true; collapse =3D list_length (OMP_CLAUSE_OACC_TILE_LIST (cl)); } else if (OMP_CLAUSE_CODE (cl) =3D=3D OMP_CLAUSE_ORDERED @@ -43679,26 +43680,33 @@ cp_parser_omp_for_loop (cp_parser *parser, enum t= ree_code code, tree clauses, ordered =3D collapse; } - gcc_assert (tiling || (collapse >=3D 1 && ordered >=3D 0)); + + gcc_assert (oacc_tiling || (collapse >=3D 1 && ordered >=3D 0)); count =3D ordered ? ordered : collapse; + cp_parser_omp_nested_loop_transform_clauses (parser, clauses, count, + "loop collapse"); + + /* Find the depth of the loop nest affected by "omp tile" + directives. There can be several such directives, but the tiling + depth of the outer ones may not be larger than the depth of the + innermost directive. */ + int omp_tile_depth =3D 0; + for (tree c =3D clauses; c; c =3D TREE_CHAIN (c)) + { + if (OMP_CLAUSE_CODE (c) !=3D OMP_CLAUSE_TILE) + continue; + + omp_tile_depth =3D list_length (OMP_CLAUSE_TILE_SIZES (c)); + } + count =3D MAX (count, omp_tile_depth); + declv =3D make_tree_vec (count); initv =3D make_tree_vec (count); condv =3D make_tree_vec (count); incrv =3D make_tree_vec (count); orig_declv =3D NULL_TREE; - 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; @@ -45734,51 +45742,224 @@ cp_parser_omp_target (cp_parser *parser, cp_toke= n *pragma_tok, return true; } +/* OpenMP 5.1: Parse sizes list for "omp tile sizes" + sizes ( size-expr-list ) */ +static tree +cp_parser_omp_tile_sizes (cp_parser *parser, location_t loc) +{ + tree sizes =3D NULL_TREE; + cp_lexer *lexer =3D parser->lexer; + + cp_token *tok =3D cp_lexer_peek_token (lexer); + if (tok->type !=3D CPP_NAME + || strcmp ("sizes", IDENTIFIER_POINTER (tok->u.value))) + { + cp_parser_error (parser, "expected %"); + return error_mark_node; + } + cp_lexer_consume_token (lexer); + + if (!cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN)) + return error_mark_node; + + do + { + if (sizes && !cp_parser_require (parser, CPP_COMMA, RT_COMMA)) + return error_mark_node; + + tree expr =3D cp_parser_constant_expression (parser); + if (expr =3D=3D error_mark_node) + { + cp_parser_skip_to_closing_parenthesis (parser, + /*recovering=3D*/true, + /*or_comma=3D*/false, + /*consume_paren=3D*/ + true); + return error_mark_node; + } + + sizes =3D tree_cons (NULL_TREE, expr, sizes); + } + while (cp_lexer_next_token_is_not (lexer, CPP_CLOSE_PAREN)); + cp_lexer_consume_token (lexer); + + gcc_assert (sizes); + tree c =3D build_omp_clause (loc, OMP_CLAUSE_TILE); + OMP_CLAUSE_TILE_SIZES (c) =3D sizes; + + return c; +} + +/* OpenMP 5.1: + tile sizes ( size-expr-list ) */ + +static tree +cp_parser_omp_tile (cp_parser *parser, cp_token *tok, bool *if_p) +{ + tree block; + tree ret =3D error_mark_node; + + tree clauses =3D cp_parser_omp_tile_sizes (parser, tok->location); + cp_parser_require_pragma_eol (parser, tok); + + if (!clauses || clauses =3D=3D error_mark_node) + return error_mark_node; + + int required_depth =3D list_length (OMP_CLAUSE_TILE_SIZES (clauses)); + cp_parser_omp_nested_loop_transform_clauses ( + parser, clauses, required_depth, "outer transformation"); + + block =3D begin_omp_structured_block (); + clauses =3D finish_omp_clauses (clauses, C_ORT_OMP); + + 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; +} + #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. */ +/* Parse a single OpenMP loop transformation directive and return the + clause that is used internally to represent the directive. */ -static bool -cp_parser_nested_omp_unroll_clauses (cp_parser *parser, tree &clauses) +static tree +cp_parser_omp_loop_transform_clause (cp_parser *parser) { - 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 *lexer =3D parser->lexer; + cp_token *tok =3D cp_lexer_peek_token (lexer); + if (tok->type !=3D CPP_PRAGMA) + return NULL_TREE; + + tree c; + switch (cp_parser_pragma_kind (tok)) { - 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; - } + case PRAGMA_OMP_UNROLL: + cp_lexer_consume_token (lexer); + lexer->in_pragma =3D true; + c =3D cp_parser_omp_all_clauses (parser, OMP_UNROLL_CLAUSE_MASK, + "#pragma omp unroll", tok, + false, true); + if (!c) + { + if (cp_lexer_next_token_is (lexer, CPP_PRAGMA_EOL)) + c =3D build_omp_clause (tok->location, OMP_CLAUSE_UNROLL_NONE); + else + c =3D error_mark_node; + } + cp_parser_skip_to_pragma_eol (parser, tok); + break; - c =3D finish_omp_clauses (c, C_ORT_OMP); + case PRAGMA_OMP_TILE: + cp_lexer_consume_token (lexer); + lexer->in_pragma =3D true; + c =3D cp_parser_omp_tile_sizes (parser, tok->location); + cp_parser_require_pragma_eol (parser, tok); + break; + + default: + c =3D NULL_TREE; + break; + } + + gcc_assert (!c || !TREE_CHAIN (c)); + return c; +} + +/* Parse zero or more OpenMP loop transformation directives that + follow another directive that requires a canonical loop nest and + append all to CLAUSES. Return the nesting depth + of the transformed loop nest. + + REQUIRED_DEPTH is the nesting depth of the loop nest required by + the preceding directive. OUTER_DESCR is a description of the + language construct that requires the loop nest depth (e.g. "loop + collpase", "outer transformation") that is used for error + messages. */ + +static int +cp_parser_omp_nested_loop_transform_clauses (cp_parser *parser, tree &clau= ses, + int required_depth, + const char *outer_descr) +{ + tree c =3D NULL_TREE; + tree last_c =3D tree_last (clauses); + + /* The depth of the loop nest after the transformations. That is, + the nesting depth left by the outermost transformation which is + the first to be parsed, but the last to be executed. */ + int transformed_depth =3D 0; + + /* The minimum nesting depth required by the last parsed transformation.= */ + int last_depth =3D required_depth; + + while ((c =3D cp_parser_omp_loop_transform_clause (parser))) + { + /* The nesting depth left after the current transformation */ + int depth =3D 1; + if (TREE_CODE (c) =3D=3D ERROR_MARK) + goto error; + + gcc_assert (!TREE_CHAIN (c)); + switch (OMP_CLAUSE_CODE (c)) + { + case OMP_CLAUSE_UNROLL_FULL: + error_at (OMP_CLAUSE_LOCATION (c), + "% clause is invalid here; " + "turns loop into non-loop"); + goto error; + case OMP_CLAUSE_UNROLL_NONE: + error_at (OMP_CLAUSE_LOCATION (c), + "%<#pragma omp unroll%> without " + "% clause is invalid here; " + "turns loop into non-loop"); + goto error; + case OMP_CLAUSE_UNROLL_PARTIAL: + depth =3D 1; + break; + case OMP_CLAUSE_TILE: + depth =3D list_length (OMP_CLAUSE_TILE_SIZES (c)); + break; + default: + gcc_unreachable (); } - else + + if (depth < last_depth) { - error_at (tok->location, "%<#pragma omp unroll%> without " - "% clause is invalid here; " - "turns loop into non-loop"); - continue; + bool is_outermost_clause =3D !transformed_depth; + error_at (OMP_CLAUSE_LOCATION (c), + "nesting depth left after this transformation too low " + "for %s", + is_outermost_clause ? outer_descr + : "outer transformation"); + goto error; } - clauses =3D chainon (clauses, c); + + last_depth =3D depth; + + if (!transformed_depth) + transformed_depth =3D last_depth; + + c =3D finish_omp_clauses (c, C_ORT_OMP); + + if (!clauses) + clauses =3D c; + else if (last_c) + TREE_CHAIN (last_c) =3D c; + + last_c =3D c; } - return unroll_found; + + return transformed_depth; + +error: + while (cp_parser_omp_loop_transform_clause (parser)) + ; + clauses =3D NULL_TREE; + return -1; } static tree @@ -45788,7 +45969,7 @@ cp_parser_omp_unroll (cp_parser *parser, cp_token *= tok, bool *if_p) 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); + tree clauses =3D cp_parser_omp_all_clauses (parser, mask, p_name, tok, t= rue); if (!clauses) { @@ -45797,7 +45978,9 @@ cp_parser_omp_unroll (cp_parser *parser, cp_token *= tok, bool *if_p) clauses =3D c; } - cp_parser_nested_omp_unroll_clauses (parser, clauses); + int required_depth =3D 1; + cp_parser_omp_nested_loop_transform_clauses ( + parser, clauses, required_depth, "outer transformation"); block =3D begin_omp_structured_block (); ret =3D cp_parser_omp_for_loop (parser, OMP_LOOP_TRANS, clauses, NULL, i= f_p); @@ -48900,6 +49083,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_TILE: + stmt =3D cp_parser_omp_tile (parser, pragma_tok, if_p); + break; case PRAGMA_OMP_UNROLL: stmt =3D cp_parser_omp_unroll (parser, pragma_tok, if_p); break; @@ -49529,6 +49715,7 @@ cp_parser_pragma (cp_parser *parser, enum pragma_co= ntext context, bool *if_p) cp_parser_omp_construct (parser, pragma_tok, if_p); pop_omp_privatization_clauses (stmt); return true; + case PRAGMA_OMP_TILE: case PRAGMA_OMP_UNROLL: if (context !=3D pragma_stmt && context !=3D pragma_compound) goto bad_stmt; diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index 16197b17e5a..a9d36d66caf 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -18087,6 +18087,7 @@ tsubst_omp_clauses (tree clauses, enum c_omp_region= _type ort, case OMP_CLAUSE_WAIT: case OMP_CLAUSE_DETACH: case OMP_CLAUSE_UNROLL_PARTIAL: + case OMP_CLAUSE_TILE: OMP_CLAUSE_OPERAND (nc, 0) =3D tsubst_expr (OMP_CLAUSE_OPERAND (oc, 0), args, complain, in= _decl); break; diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc index c87e252ff06..15f7c7e6dc4 100644 --- a/gcc/cp/semantics.cc +++ b/gcc/cp/semantics.cc @@ -8769,6 +8769,46 @@ finish_omp_clauses (tree clauses, enum c_omp_region_= type ort) } break; + case OMP_CLAUSE_TILE: + for (tree list =3D OMP_CLAUSE_TILE_SIZES (c); !remove && list; + list =3D TREE_CHAIN (list)) + { + t =3D TREE_VALUE (list); + + 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), + "% 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 (!tree_fits_shwi_p (t) + || !INTEGRAL_TYPE_P (TREE_TYPE (t)) + || (n =3D tree_to_shwi (t)) <=3D 0 || (int)n !=3D= n) + { + error_at (OMP_CLAUSE_LOCATION (c), + "% argument needs positive= " + "integral constant"); + remove =3D true; + } + t =3D fold_build_cleanup_point_expr (TREE_TYPE (t), t= ); + } + } + + /* Update list item. */ + TREE_VALUE (list) =3D t; + } + break; + case OMP_CLAUSE_ORDERED: ordered_seen =3D true; break; diff --git a/gcc/gimplify.cc b/gcc/gimplify.cc index 4d504a12451..365897afb61 100644 --- a/gcc/gimplify.cc +++ b/gcc/gimplify.cc @@ -13572,6 +13572,29 @@ find_standalone_omp_ordered (tree *tp, int *walk_s= ubtrees, void *) return NULL_TREE; } +static void omp_for_drop_tile_clauses (tree for_stmt) +{ + /* Drop erroneous loop transformation clauses to avoid follow up errors + in pass-omp_transform_loops. */ + tree last_c =3D NULL_TREE; + for (tree c =3D OMP_FOR_CLAUSES (for_stmt); c; + c =3D OMP_CLAUSE_CHAIN (c)) + { + + if (OMP_CLAUSE_CODE (c) !=3D OMP_CLAUSE_TILE) + continue; + + if (last_c) + TREE_CHAIN (last_c) =3D TREE_CHAIN (c); + else + OMP_FOR_CLAUSES (for_stmt) =3D TREE_CHAIN (c); + + error_at (OMP_CLAUSE_LOCATION (c), + "'tile' loop transformation may not appear on " + "non-rectangular for"); + } +} + /* Gimplify the gross structure of an OMP_FOR statement. */ static enum gimplify_status @@ -13763,6 +13786,8 @@ gimplify_omp_for (tree *expr_p, gimple_seq *pre_p) case OMP_FOR: if (OMP_FOR_NON_RECTANGULAR (inner_for_stmt ? inner_for_stmt : for_s= tmt)) { + omp_for_drop_tile_clauses (for_stmt); + if (omp_find_clause (OMP_FOR_CLAUSES (for_stmt), OMP_CLAUSE_SCHEDULE)) error_at (EXPR_LOCATION (for_stmt), @@ -13808,6 +13833,8 @@ gimplify_omp_for (tree *expr_p, gimple_seq *pre_p) ort =3D ORT_SIMD; break; case OMP_LOOP_TRANS: + if (OMP_FOR_NON_RECTANGULAR (inner_for_stmt ? inner_for_stmt : for_s= tmt)) + omp_for_drop_tile_clauses (for_stmt); break; default: gcc_unreachable (); @@ -14693,6 +14720,7 @@ gimplify_omp_for (tree *expr_p, gimple_seq *pre_p) case OMP_CLAUSE_UNROLL_FULL: case OMP_CLAUSE_UNROLL_NONE: case OMP_CLAUSE_UNROLL_PARTIAL: + case OMP_CLAUSE_TILE: *gfor_clauses_ptr =3D c; gfor_clauses_ptr =3D &OMP_CLAUSE_CHAIN (c); break; diff --git a/gcc/testsuite/c-c++-common/gomp/loop-transforms/tile-1.c b/gcc= /testsuite/c-c++-common/gomp/loop-transforms/tile-1.c new file mode 100644 index 00000000000..8a2f2126af4 --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/loop-transforms/tile-1.c @@ -0,0 +1,164 @@ +extern void dummy (int); + +void +test () +{ + #pragma omp tile sizes(1) + for (int i =3D 0; i < 100; ++i) + dummy (i); + + #pragma omp tile sizes(0) /* { dg-error {'tile sizes' argument needs p= ositive integral constant} } */ + for (int i =3D 0; i < 100; ++i) + dummy (i); + + #pragma omp tile sizes(-1) /* { dg-error {'tile sizes' argument needs = positive integral constant} } */ + for (int i =3D 0; i < 100; ++i) + dummy (i); + + #pragma omp tile sizes() /* { dg-error {expected expression before} ""= { target c} } */ + /* { dg-error {expected primary-expression before} "" { target c++ } .= -1 } */ + for (int i =3D 0; i < 100; ++i) + dummy (i); + + #pragma omp tile sizes(,) /* { dg-error {expected expression before} "= " { target c } } */ + /* { dg-error {expected primary-expression before} "" { target c++ } .= -1 } */ + for (int i =3D 0; i < 100; ++i) + dummy (i); + + #pragma omp tile sizes(1,2 /* { dg-error {expected '\,' before end of = line} } */ + for (int i =3D 0; i < 100; ++i) + dummy (i); + + #pragma omp tile sizes /* { dg-error {expected '\(' before end of line= } } */ + for (int i =3D 0; i < 100; ++i) + dummy (i); + + #pragma omp tile sizes(1) sizes(1) /* { dg-error {expected end of line= before 'sizes'} } */ + for (int i =3D 0; i < 100; ++i) + dummy (i); + + #pragma omp tile sizes(1) + #pragma omp tile sizes(1) + for (int i =3D 0; i < 100; ++i) + dummy (i); + + #pragma omp tile sizes(1, 2) + #pragma omp tile sizes(1) /* { dg-error {nesting depth left after this= transformation too low for outer transformation} } */ + for (int i =3D 0; i < 100; ++i) + for (int j =3D 0; j < 100; ++j) + dummy (i); + + #pragma omp tile sizes(1, 2) + #pragma omp tile sizes(1, 2) + for (int i =3D 0; i < 100; ++i) + for (int j =3D 0; j < 100; ++j) + dummy (i); + + #pragma omp tile sizes(5, 6) + #pragma omp tile sizes(1, 2, 3) + for (int i =3D 0; i < 100; ++i) + for (int j =3D 0; j < 100; ++j) + for (int k =3D 0; k < 100; ++k) + dummy (i); + + #pragma omp tile sizes(1) + #pragma omp unroll partia /* { dg-error {expected '#pragma omp' clause= before 'partia'} } */ + #pragma omp tile sizes(1) + for (int i =3D 0; i < 100; ++i) + dummy (i); + + #pragma omp tile sizes(1) + #pragma omp unroll /* { dg-error {'#pragma omp unroll' without 'partia= l' clause is invalid here; turns loop into non-loop} } */ + for (int i =3D 0; i < 100; ++i) + dummy (i); + + #pragma omp tile sizes(1) + #pragma omp unroll full /* { dg-error {'full' clause is invalid here; = turns loop into non-loop} } */ + for (int i =3D 0; i < 100; ++i) + dummy (i); + + #pragma omp tile sizes(1) + #pragma omp unroll partial + #pragma omp tile sizes(1) + for (int i =3D 0; i < 100; ++i) + dummy (i); + + #pragma omp tile sizes(8,8) + #pragma omp unroll partial /* { dg-error {nesting depth left after thi= s transformation too low for outer transformation} } */ + #pragma omp tile sizes(1) + for (int i =3D 0; i < 100; ++i) + dummy (i); + + #pragma omp tile sizes(8,8) + #pragma omp unroll partial /* { dg-error {nesting depth left after thi= s transformation too low for outer transformation} } */ + for (int i =3D 0; i < 100; ++i) + dummy (i); + + #pragma omp tile sizes(1, 2) + for (int i =3D 0; i < 100; ++i) + for (int j =3D 0; j < 100; ++j) + dummy (i); + + #pragma omp tile sizes(1, 2) /* { dg-error {'tile' loop transformation= may not appear on non-rectangular for} } */ + for (int i =3D 0; i < 100; ++i) + for (int j =3D i; j < 100; ++j) + dummy (i); + + #pragma omp tile sizes(1, 2) /* { dg-error {'tile' loop transformation= may not appear on non-rectangular for} } */ + for (int i =3D 0; i < 100; ++i) + for (int j =3D 2; j < i; ++j) + dummy (i); + + #pragma omp tile sizes(1, 2, 3) + for (int i =3D 0; i < 100; ++i) + for (int j =3D 0; j < 100; ++j) + dummy (i); /* { dg-error {not enough perfectly nested loops before= 'dummy'} "" { target c } } */ + /* { dg-error {not enough for loops to collapse} "" { target c++ } .-1= } */ + /* { dg-error {'i' was not declared in this scope} "" { target c++ } .= -2 } */ + + #pragma omp tile sizes(1) + for (int i =3D 0; i < 100; ++i) + { + dummy (i); + for (int j =3D 0; j < 100; ++j) + dummy (i); + } + + #pragma omp tile sizes(1) + for (int i =3D 0; i < 100; ++i) + { + for (int j =3D 0; j < 100; ++j) + dummy (j); + dummy (i); + } + + #pragma omp tile sizes(1, 2) + for (int i =3D 0; i < 100; ++i) + { + dummy (i); /* { dg-error {not enough perfectly nested loops before= 'dummy'} "" { target c } } */ + /* { dg-error {not enough for loops to collapse} "" { target c++ } = .-1 } */ + for (int j =3D 0; j < 100; ++j) + dummy (j); + } + + #pragma omp tile sizes(1, 2) + for (int i =3D 0; i < 100; ++i) + { + for (int j =3D 0; j < 100; ++j) + dummy (j); + dummy (i); /* { dg-error {collapsed loops not perfectly nested befo= re 'dummy'} "" { target c} } */ + /* { dg-error {collapsed loops not perfectly nested} "" { target c+= + } .-1 } */ + } + + int s; + #pragma omp tile sizes(s) /* { dg-error {'tile sizes' argument needs p= ositive integral constant} "" { target { ! c++98_only } } } */ + /* { dg-error {the value of 's' is not usable in a constant expression= } "" { target { c++ && { ! c++98_only } } } .-1 } */ + /* { dg-error {'s' cannot appear in a constant-expression} "" { target= c++98_only } .-2 } */ + for (int i =3D 0; i < 100; ++i) + dummy (i); + + #pragma omp tile sizes(42.0) /* { dg-error {'tile sizes' argument need= s positive integral constant} "" { target c } } */ + /* { dg-error {'tile sizes' argument needs integral type} "" { target = c++ } .-1 } */ + for (int i =3D 0; i < 100; ++i) + dummy (i); +} diff --git a/gcc/testsuite/c-c++-common/gomp/loop-transforms/tile-2.c b/gcc= /testsuite/c-c++-common/gomp/loop-transforms/tile-2.c new file mode 100644 index 00000000000..51d62552945 --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/loop-transforms/tile-2.c @@ -0,0 +1,183 @@ +extern void dummy (int); + +void +test () +{ + #pragma omp parallel for + #pragma omp tile sizes(1) + for (int i =3D 0; i < 100; ++i) + dummy (i); + + #pragma omp parallel for + #pragma omp tile sizes(0) /* { dg-error {'tile sizes' argument needs p= ositive integral constant} } */ + for (int i =3D 0; i < 100; ++i) + dummy (i); + + #pragma omp parallel for + #pragma omp tile sizes(-1) /* { dg-error {'tile sizes' argument needs = positive integral constant} } */ + for (int i =3D 0; i < 100; ++i) + dummy (i); + + #pragma omp parallel for + #pragma omp tile sizes() /* { dg-error {expected expression before} ""= { target c} } */ + /* { dg-error {expected primary-expression before} "" { target c++ } .= -1 } */ + for (int i =3D 0; i < 100; ++i) + dummy (i); + + #pragma omp parallel for + #pragma omp tile sizes(,) /* { dg-error {expected expression before} "= " { target c } } */ + /* { dg-error {expected primary-expression before} "" { target c++ } .= -1 } */ + for (int i =3D 0; i < 100; ++i) + dummy (i); + + #pragma omp parallel for + #pragma omp tile sizes(1,2 /* { dg-error {expected '\,' before end of = line} } */ + for (int i =3D 0; i < 100; ++i) + dummy (i); + + #pragma omp parallel for + #pragma omp tile sizes /* { dg-error {expected '\(' before end of line= } } */ + for (int i =3D 0; i < 100; ++i) + dummy (i); + + #pragma omp parallel for + #pragma omp tile sizes(1) sizes(1) /* { dg-error {expected end of line= before 'sizes'} } */ + for (int i =3D 0; i < 100; ++i) + dummy (i); + + #pragma omp parallel for + #pragma omp tile sizes(1) + #pragma omp tile sizes(1) + for (int i =3D 0; i < 100; ++i) + dummy (i); + + #pragma omp parallel for + #pragma omp tile sizes(1, 2) + #pragma omp tile sizes(1) /* { dg-error {nesting depth left after this= transformation too low for outer transformation} } */ + for (int i =3D 0; i < 100; ++i) + for (int j =3D 0; j < 100; ++j) + dummy (i); + + #pragma omp parallel for + #pragma omp tile sizes(1, 2) + #pragma omp tile sizes(1, 2) + for (int i =3D 0; i < 100; ++i) + for (int j =3D 0; j < 100; ++j) + dummy (i); + + #pragma omp parallel for + #pragma omp tile sizes(5, 6) + #pragma omp tile sizes(1, 2, 3) + for (int i =3D 0; i < 100; ++i) + for (int j =3D 0; j < 100; ++j) + for (int k =3D 0; k < 100; ++k) + dummy (i); + + #pragma omp parallel for + #pragma omp tile sizes(1) + #pragma omp unroll partia /* { dg-error {expected '#pragma omp' clause= before 'partia'} } */ + #pragma omp tile sizes(1) + for (int i =3D 0; i < 100; ++i) + dummy (i); + + #pragma omp parallel for + #pragma omp tile sizes(1) + #pragma omp unroll /* { dg-error {'#pragma omp unroll' without 'partia= l' clause is invalid here; turns loop into non-loop} } */ + for (int i =3D 0; i < 100; ++i) + dummy (i); + + #pragma omp parallel for + #pragma omp tile sizes(1) + #pragma omp unroll full /* { dg-error {'full' clause is invalid here; = turns loop into non-loop} } */ + for (int i =3D 0; i < 100; ++i) + dummy (i); + + #pragma omp parallel for + #pragma omp tile sizes(1) + #pragma omp unroll partial + #pragma omp tile sizes(1) + for (int i =3D 0; i < 100; ++i) + dummy (i); + + #pragma omp parallel for + #pragma omp tile sizes(8,8) + #pragma omp unroll partial /* { dg-error {nesting depth left after thi= s transformation too low for outer transformation} } */ + #pragma omp tile sizes(1) + for (int i =3D 0; i < 100; ++i) + dummy (i); + + #pragma omp parallel for + #pragma omp tile sizes(8,8) + #pragma omp unroll partial /* { dg-error {nesting depth left after thi= s transformation too low for outer transformation} } */ + for (int i =3D 0; i < 100; ++i) + dummy (i); + + #pragma omp parallel for + #pragma omp tile sizes(1, 2) + for (int i =3D 0; i < 100; ++i) + for (int j =3D 0; j < 100; ++j) + dummy (i); + + #pragma omp parallel for + #pragma omp tile sizes(1, 2) /* { dg-error {'tile' loop transformation= may not appear on non-rectangular for} } */ + for (int i =3D 0; i < 100; ++i) + for (int j =3D i; j < 100; ++j) + dummy (i); + + #pragma omp parallel for + #pragma omp tile sizes(1, 2) /* { dg-error {'tile' loop transformation= may not appear on non-rectangular for} } */ + for (int i =3D 0; i < 100; ++i) + for (int j =3D 2; j < i; ++j) + dummy (i); + + #pragma omp parallel for + #pragma omp tile sizes(1, 2, 3) + for (int i =3D 0; i < 100; ++i) + for (int j =3D 0; j < 100; ++j) + dummy (i); /* { dg-error {not enough perfectly nested loops before= 'dummy'} "" { target c } } */ + /* { dg-error {not enough for loops to collapse} "" { target c++ } .-1= } */ + /* { dg-error {'i' was not declared in this scope} "" { target c++ } .= -2 } */ + + #pragma omp parallel for + #pragma omp tile sizes(1) + for (int i =3D 0; i < 100; ++i) + { + dummy (i); + for (int j =3D 0; j < 100; ++j) + dummy (i); + } + + #pragma omp parallel for + #pragma omp tile sizes(1) + for (int i =3D 0; i < 100; ++i) + { + for (int j =3D 0; j < 100; ++j) + dummy (j); + dummy (i); + } + + #pragma omp parallel for + #pragma omp tile sizes(1, 2) + for (int i =3D 0; i < 100; ++i) + { + dummy (i); /* { dg-error {not enough perfectly nested loops before= 'dummy'} "" { target c } } */ + /* { dg-error {not enough for loops to collapse} "" { target c++ } = .-1 } */ + for (int j =3D 0; j < 100; ++j) + dummy (j); + } + + #pragma omp parallel for + #pragma omp tile sizes(1, 2) + for (int i =3D 0; i < 100; ++i) + { + for (int j =3D 0; j < 100; ++j) + dummy (j); + dummy (i); /* { dg-error {collapsed loops not perfectly nested befo= re 'dummy'} "" { target c} } */ + /* { dg-error {collapsed loops not perfectly nested} "" { target c+= + } .-1 } */ + } + + #pragma omp parallel for + #pragma omp tile sizes(1) + for (int i =3D 0; i < 100; ++i) + dummy (i); +} diff --git a/gcc/testsuite/c-c++-common/gomp/loop-transforms/tile-3.c b/gcc= /testsuite/c-c++-common/gomp/loop-transforms/tile-3.c new file mode 100644 index 00000000000..7fffc72b335 --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/loop-transforms/tile-3.c @@ -0,0 +1,117 @@ +extern void dummy (int); + +void +test () +{ + #pragma omp for + #pragma omp tile sizes(1, 2) /* { dg-error {'tile' loop transformation= may not appear on non-rectangular for} } */ + for (int i =3D 0; i < 100; ++i) + for (int j =3D i; j < 100; ++j) + dummy (i); + + #pragma omp for + #pragma omp tile sizes(1, 2) /* { dg-error {'tile' loop transformation= may not appear on non-rectangular for} } */ + for (int i =3D 0; i < 100; ++i) + for (int j =3D 0; j < i; ++j) + dummy (i); + + +#pragma omp for collapse(1) + #pragma omp tile sizes(1) + for (int i =3D 0; i < 100; ++i) + for (int j =3D 0; j < 100; ++j) + dummy (i); + +#pragma omp for collapse(2) + #pragma omp tile sizes(1) /* { dg-error {nesting depth left after this= transformation too low for loop collapse} } */ + for (int i =3D 0; i < 100; ++i) + for (int j =3D 0; j < 100; ++j) + dummy (i); + +#pragma omp for collapse(2) + #pragma omp tile sizes(1, 2) + for (int i =3D 0; i < 100; ++i) + for (int j =3D 0; j < 100; ++j) + dummy (i); + +#pragma omp for collapse(3) + #pragma omp tile sizes(1, 2) /* { dg-error {nesting depth left after t= his transformation too low for loop collapse} } */ + for (int i =3D 0; i < 100; ++i) + for (int j =3D 0; j < 100; ++j) + dummy (i); + /* { dg-error {not enough perfectly nested loops before 'dummy'} "" { = target c } .-1 } */ + /* { dg-error {not enough for loops to collapse} "" { target c++ } .-2= } */ + /* { dg-error {'i' was not declared in this scope} "" { target c++ } .= -3 } */ + +#pragma omp for collapse(1) +#pragma omp tile sizes(1) +#pragma omp tile sizes(1) + for (int i =3D 0; i < 100; ++i) + dummy (i); + +#pragma omp for collapse(2) +#pragma omp tile sizes(1, 2) +#pragma omp tile sizes(1) /* { dg-error {nesting depth left after this tra= nsformation too low for outer transformation} } */ + for (int i =3D 0; i < 100; ++i) + dummy (i); /* { dg-error {not enough perfectly nested loops before = 'dummy'} "" { target c } } */ + /* { dg-error {not enough for loops to collapse} "" { target c++ } .-1= } */ + +#pragma omp for collapse(2) +#pragma omp tile sizes(1, 2) +#pragma omp tile sizes(1, 2) + for (int i =3D 0; i < 100; ++i) + dummy (i); /* { dg-error {not enough perfectly nested loops before = 'dummy'} "" { target c } } */ + /* { dg-error {not enough for loops to collapse} "" { target c++ } .-1= } */ + +#pragma omp for collapse(2) +#pragma omp tile sizes(5, 6) +#pragma omp tile sizes(1, 2, 3) + for (int i =3D 0; i < 100; ++i) + dummy (i); /* { dg-error {not enough perfectly nested loops before = 'dummy'} "" { target c } } */ + /* { dg-error {not enough for loops to collapse} "" { target c++ } .-1= } */ + + +#pragma omp for collapse(1) +#pragma omp tile sizes(1) +#pragma omp tile sizes(1) + for (int i =3D 0; i < 100; ++i) + dummy (i); + +#pragma omp for collapse(2) +#pragma omp tile sizes(1, 2) +#pragma omp tile sizes(1) /* { dg-error {nesting depth left after this tra= nsformation too low for outer transformation} } */ + for (int i =3D 0; i < 100; ++i) + for (int j =3D 0; j < 100; ++j) + dummy (i); + +#pragma omp for collapse(2) +#pragma omp tile sizes(1, 2) +#pragma omp tile sizes(1, 2) + for (int i =3D 0; i < 100; ++i) + for (int j =3D 0; j < 100; ++j) + dummy (i); + +#pragma omp for collapse(2) +#pragma omp tile sizes(5, 6) +#pragma omp tile sizes(1, 2, 3) + for (int i =3D 0; i < 100; ++i) + for (int j =3D 0; j < 100; ++j) + for (int k =3D 0; k < 100; ++k) + dummy (i); + +#pragma omp for collapse(3) +#pragma omp tile sizes(1, 2) /* { dg-error {nesting depth left after this = transformation too low for loop collapse} } */ +#pragma omp tile sizes(1, 2) + for (int i =3D 0; i < 100; ++i) + for (int j =3D 0; j < 100; ++j) + dummy (i); /* { dg-error {not enough perfectly nested loops before = 'dummy'} "" { target c } } */ + /* { dg-error {not enough for loops to collapse} "" { target c++ } .-1= } */ + +#pragma omp for collapse(3) +#pragma omp tile sizes(5, 6) /* { dg-error {nesting depth left after this = transformation too low for loop collapse} } */ +#pragma omp tile sizes(1, 2, 3) + for (int i =3D 0; i < 100; ++i) + for (int j =3D 0; j < 100; ++j) + for (int k =3D 0; k < 100; ++k) + dummy (i); +} diff --git a/gcc/testsuite/c-c++-common/gomp/loop-transforms/tile-4.c b/gcc= /testsuite/c-c++-common/gomp/loop-transforms/tile-4.c new file mode 100644 index 00000000000..d46bb0cb642 --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/loop-transforms/tile-4.c @@ -0,0 +1,322 @@ +/* { 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, expected %d\n", __FILE__, __LINE__, var, val); \ + __builtin_abort (); } + +int +test1 () +{ + int iter =3D 0; + int i; +#pragma omp tile sizes(3) + for (i =3D 0; i < 10; i=3Di+2) + { + ASSERT_EQ (i, iter) + iter =3D iter + 2; + } + + ASSERT_EQ (i, 10) + return iter; +} + +int +test2 () +{ + int iter =3D 0; + int i; +#pragma omp tile sizes(3) + for (i =3D 0; i < 10; i=3Di+2) + { + ASSERT_EQ (i, iter) + iter =3D iter + 2; + } + + ASSERT_EQ (i, 10) + return iter; +} + +int +test3 () +{ + int iter =3D 0; + int i; +#pragma omp tile sizes(8) + for (i =3D 0; i < 10; i=3Di+2) + { + ASSERT_EQ (i, iter) + iter =3D iter + 2; + } + + ASSERT_EQ (i, 10) + return iter; +} + +int +test4 () +{ + int iter =3D 10; + int i; +#pragma omp tile sizes(8) + for (i =3D 10; i > 0; i=3Di-2) + { + ASSERT_EQ (i, iter) + iter =3D iter - 2; + } + ASSERT_EQ (i, 0) + return iter; +} + +int +test5 () +{ + int iter =3D 10; + int i; +#pragma omp tile sizes(71) + for (i =3D 10; i > 0; i=3Di-2) + { + ASSERT_EQ (i, iter) + iter =3D iter - 2; + } + + ASSERT_EQ (i, 0) + return iter; +} + +int +test6 () +{ + int iter =3D 10; + int i; +#pragma omp tile sizes(1) + for (i =3D 10; i > 0; i=3Di-2) + { + ASSERT_EQ (i, iter) + iter =3D iter - 2; + } + ASSERT_EQ (i, 0) + return iter; +} + +int +test7 () +{ + int iter =3D 5; + int i; +#pragma omp tile sizes(2) + for (i =3D 5; i < -5; i=3Di-3) + { + fprintf (stderr, "%d\n", i); + __builtin_abort (); + iter =3D iter - 3; + } + + ASSERT_EQ (i, 5) + + /* No iteration expected */ + return iter; +} + +int +test8 () +{ + int iter =3D 5; + int i; +#pragma omp tile sizes(2) + for (i =3D 5; i > -5; i=3Di-3) + { + ASSERT_EQ (i, iter) + /* Expect only first iteration of the last tile to execute */ + if (iter !=3D -4) + iter =3D iter - 3; + } + + ASSERT_EQ (i, -7) + return iter; +} + + +int +test9 () +{ + int iter =3D 5; + int i; +#pragma omp tile sizes(5) + for (i =3D 5; i >=3D -5; i=3Di-4) + { + ASSERT_EQ (i, iter) + /* Expect only first iteration of the last tile to execute */ + if (iter !=3D - 3) + iter =3D iter - 4; + } + + ASSERT_EQ (i, -7) + return iter; +} + +int +test10 () +{ + int iter =3D 5; + int i; +#pragma omp tile sizes(5) + for (i =3D 5; i >=3D -5; i--) + { + ASSERT_EQ (i, iter) + iter--; + } + + ASSERT_EQ (i, -6) + return iter; +} + +int +test11 () +{ + int iter =3D 5; + int i; +#pragma omp tile sizes(15) + for (i =3D 5; i !=3D -5; i--) + { + ASSERT_EQ (i, iter) + iter--; + } + ASSERT_EQ (i, -5) + return iter; +} + +int +test12 () +{ + int iter =3D 0; + unsigned i; +#pragma omp tile sizes(3) + for (i =3D 0; i !=3D 5; i++) + { + ASSERT_EQ (i, iter) + iter++; + } + + ASSERT_EQ (i, 5) + return iter; +} + +int +test13 () +{ + int iter =3D -5; + long long unsigned int i; +#pragma omp tile sizes(15) + for (int i =3D -5; i < 5; i=3Di+3) + { + ASSERT_EQ (i, iter) + iter++; + } + + ASSERT_EQ (i, 5) + return iter; +} + +int +test14 (unsigned init, int step) +{ + int iter =3D init; + long long unsigned int i; +#pragma omp tile sizes(8) + for (i =3D init; i < 2*init; i=3Di+step) + iter++; + + ASSERT_EQ (i, 2*init) + return iter; +} + +int +test15 (unsigned init, int step) +{ + int iter =3D init; + int i; +#pragma omp tile sizes(8) + for (unsigned i =3D init; i > 2* init; i=3Di+step) + iter++; + + return iter; +} + +int +main () +{ + int last_iter; + + last_iter =3D test1 (); + ASSERT_EQ (last_iter, 10); + + last_iter =3D test2 (); + ASSERT_EQ (last_iter, 10); + + last_iter =3D test3 (); + ASSERT_EQ (last_iter, 10); + + last_iter =3D test4 (); + ASSERT_EQ (last_iter, 0); + + last_iter =3D test5 (); + ASSERT_EQ (last_iter, 0); + + last_iter =3D test6 (); + ASSERT_EQ (last_iter, 0); + + last_iter =3D test7 (); + ASSERT_EQ (last_iter, 5); + + last_iter =3D test8 (); + ASSERT_EQ (last_iter, -4); + + last_iter =3D test9 (); + ASSERT_EQ (last_iter, -3); + + last_iter =3D test10 (); + ASSERT_EQ (last_iter, -6); + return 0; + + last_iter =3D test11 (); + ASSERT_EQ (last_iter, -4); + return 0; + + last_iter =3D test12 (); + ASSERT_EQ (last_iter, 5); + return 0; + + last_iter =3D test13 (); + ASSERT_EQ (last_iter, 4); + return 0; + + last_iter =3D test14 (0, 1); + ASSERT_EQ (last_iter, 0); + return 0; + + last_iter =3D test14 (0, -1); + ASSERT_EQ (last_iter, 0); + return 0; + + last_iter =3D test14 (8, 2); + ASSERT_EQ (last_iter, 16); + return 0; + + last_iter =3D test14 (5, 3); + ASSERT_EQ (last_iter, 9); + return 0; + + last_iter =3D test15 (8, -1); + ASSERT_EQ (last_iter, 9); + return 0; + + last_iter =3D test15 (8, -2); + ASSERT_EQ (last_iter, 10); + return 0; + + last_iter =3D test15 (5, -3); + ASSERT_EQ (last_iter, 6); + return 0; +} diff --git a/gcc/testsuite/c-c++-common/gomp/loop-transforms/tile-5.c b/gcc= /testsuite/c-c++-common/gomp/loop-transforms/tile-5.c new file mode 100644 index 00000000000..815318ab27a --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/loop-transforms/tile-5.c @@ -0,0 +1,150 @@ +/* { 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 tile sizes(5) + for (i =3D data; i < data + 10 ; i++) + { + ASSERT_EQ (*i, data[iter]); + ASSERT_EQ_PTR (i, data + iter); + iter++; + } + + ASSERT_EQ_PTR (i, data + 10) + return iter; +} + +int +test2 (int data[10]) +{ + int iter =3D 0; + int *i; + #pragma omp tile sizes(5) + for (i =3D data; i < data + 10 ; i=3Di+2) + { + ASSERT_EQ_PTR (i, data + 2 * iter); + ASSERT_EQ (*i, data[2 * iter]); + iter++; + } + + ASSERT_EQ_PTR (i, data + 10) + return iter; +} + +int +test3 (int data[10]) +{ + int iter =3D 0; + int *i; + #pragma omp tile sizes(5) + for (i =3D data; i <=3D data + 9 ; i=3Di+2) + { + ASSERT_EQ (*i, data[2 * iter]); + iter++; + } + + ASSERT_EQ_PTR (i, data + 10) + return iter; +} + +int +test4 (int data[10]) +{ + int iter =3D 0; + int *i; + #pragma omp tile sizes(5) + for (i =3D data; i !=3D data + 10 ; i=3Di+1) + { + ASSERT_EQ (*i, data[iter]); + iter++; + } + + ASSERT_EQ_PTR (i, data + 10) + return iter; +} + +int +test5 (int data[10]) +{ + int iter =3D 0; + int *i; + #pragma omp tile sizes(3) + for (i =3D data + 9; i >=3D data ; i--) + { + ASSERT_EQ (*i, data[9 - iter]); + iter++; + } + + ASSERT_EQ_PTR (i, data - 1) + return iter; +} + +int +test6 (int data[10]) +{ + int iter =3D 0; + int *i; + #pragma omp tile sizes(3) + for (i =3D data + 9; i > data - 1 ; i--) + { + ASSERT_EQ (*i, data[9 - iter]); + iter++; + } + + ASSERT_EQ_PTR (i, data - 1) + return iter; +} + +int +test7 (int data[10]) +{ + int iter =3D 0; + #pragma omp tile sizes(1) + 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/tile-6.c b/gcc= /testsuite/c-c++-common/gomp/loop-transforms/tile-6.c new file mode 100644 index 00000000000..8132128a5a8 --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/loop-transforms/tile-6.c @@ -0,0 +1,34 @@ +/* { dg-do run } */ +/* { dg-options "-O0 -fopenmp-simd" } */ + +#include + +int +test1 () +{ + int sum =3D 0; +for (int k =3D 0; k < 10; k++) + { +#pragma omp tile sizes(5,7) + for (int i =3D 0; i < 10; i++) + for (int j =3D 0; j < 10; j=3Dj+2) + { + sum =3D sum + 1; + } + } + + return sum; +} + +int +main () +{ + int result =3D test1 (); + + if (result !=3D 500) + { + fprintf (stderr, "Wrong result: %d\n", result); + __builtin_abort (); + } + return 0; +} diff --git a/gcc/testsuite/c-c++-common/gomp/loop-transforms/tile-7.c b/gcc= /testsuite/c-c++-common/gomp/loop-transforms/tile-7.c new file mode 100644 index 00000000000..cd25a62c5c0 --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/loop-transforms/tile-7.c @@ -0,0 +1,31 @@ +/* { 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 +main () +{ + int iter_count; + int data[10] =3D { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + + int iter =3D 0; + int *i; + #pragma omp tile sizes(1) + for (i =3D data; i < data + 10; i=3Di+2) + { + ASSERT_EQ_PTR (i, data + 2 * iter); + ASSERT_EQ (*i, data[2 * iter]); + iter++; + } + + unsigned long real_iter_count =3D ((unsigned long)i - (unsigned long)dat= a) / (sizeof (int) * 2); + ASSERT_EQ (real_iter_count, 5); + + return 0; +} diff --git a/gcc/testsuite/c-c++-common/gomp/loop-transforms/tile-8.c b/gcc= /testsuite/c-c++-common/gomp/loop-transforms/tile-8.c new file mode 100644 index 00000000000..c26e03d7e74 --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/loop-transforms/tile-8.c @@ -0,0 +1,40 @@ +/* { 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, expected %d\n", __FILE__, __LINE__, var, val); \ + __builtin_abort (); } + +int +main () +{ + int iter_j =3D 0, iter_k =3D 0; + unsigned i, j, k; +#pragma omp tile sizes(3,5,8) + for (i =3D 0; i < 2; i=3Di+2) + for (j =3D 0; j < 3; j=3Dj+1) + for (k =3D 0; k < 5; k=3Dk+3) + { + /* fprintf (stderr, "i=3D%d j=3D%d k=3D%d\n", i, j, k); + * fprintf (stderr, "iter_j=3D%d iter_k=3D%d\n", iter_j, iter_k);= */ + ASSERT_EQ (i, 0); + if (k =3D=3D 0) + { + ASSERT_EQ (j, iter_j); + iter_k =3D 0; + } + + ASSERT_EQ (k, iter_k); + + iter_k =3D iter_k + 3; + if (k =3D=3D 3) + iter_j++; + } + + ASSERT_EQ (i, 2); + ASSERT_EQ (j, 3); + ASSERT_EQ (k, 6); + + return 0; +} 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 index 8f7c3088a2e..e4fee72c04d 100644 --- a/gcc/testsuite/c-c++-common/gomp/loop-transforms/unroll-2.c +++ b/gcc/testsuite/c-c++-common/gomp/loop-transforms/unroll-2.c @@ -19,7 +19,7 @@ test () #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} } */ +#pragma omp unroll full for (int i =3D -300; i !=3D 100; ++i) dummy (i); @@ -45,13 +45,11 @@ test () 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); @@ -67,7 +65,7 @@ test () #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 } */ + /* { dg-error {partial argument needs positive constant integer expressio= n} "" { target *-*-* } .-2 } */ for (int i =3D -300; i !=3D 100; ++i) dummy (i); @@ -78,20 +76,18 @@ test () #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++ } } */ +#pragma omp parallel for reduction(+ : sum) collapse(2) +#pragma omp unroll partial(1) /* { dg-error {nesting depth left after this= transformation too low for loop collapse} } */ for (int i =3D 3; i < 10; ++i) for (int j =3D -2; j < 7; ++j) sum++; diff --git a/gcc/testsuite/g++.dg/gomp/loop-transforms/tile-1.h b/gcc/tests= uite/g++.dg/gomp/loop-transforms/tile-1.h new file mode 100644 index 00000000000..166d1d48677 --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/loop-transforms/tile-1.h @@ -0,0 +1,27 @@ +// { dg-do compile } +// { dg-additional-options "-std=3Dc++11" } + +#include + +extern void dummy (int); + +template void +test1_template () +{ + std::vector v; + + for (unsigned i =3D 0; i < 10; i++) + v.push_back (i); + +#pragma omp for + for (int i : v) + dummy (i); + +#pragma omp tile sizes (U, 10, V) + for (T i : v) + for (T j : v) + for (T k : v) + dummy (i); +} + +void test () { test1_template (); }; diff --git a/gcc/testsuite/g++.dg/gomp/loop-transforms/tile-1a.C b/gcc/test= suite/g++.dg/gomp/loop-transforms/tile-1a.C new file mode 100644 index 00000000000..1ee76da3d4a --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/loop-transforms/tile-1a.C @@ -0,0 +1,27 @@ +// { dg-do compile } +// { dg-additional-options "-std=3Dc++11" } + +#include + +extern void dummy (int); + +template void +test1_template () +{ + std::vector v; + + for (unsigned i =3D 0; i < 10; i++) + v.push_back (i); + +#pragma omp teams distribute parallel for num_teams(V) + for (int i : v) + dummy (i); + +#pragma omp tile sizes (V, U) + for (T i : v) + for (T j : v) + for (T k : v) + dummy (i); +} + +void test () { test1_template (); }; diff --git a/gcc/testsuite/g++.dg/gomp/loop-transforms/tile-1b.C b/gcc/test= suite/g++.dg/gomp/loop-transforms/tile-1b.C new file mode 100644 index 00000000000..263c9b301c6 --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/loop-transforms/tile-1b.C @@ -0,0 +1,27 @@ +// { dg-do compile } +// { dg-additional-options "-std=3Dc++11" } + +#include + +extern void dummy (int); + +template void +test1_template () +{ + std::vector v; + + for (unsigned i =3D 0; i < 10; i++) + v.push_back (i); + +#pragma omp for + for (int i : v) + dummy (i); + +#pragma omp tile sizes (U, 10, V) // { dg-error {'tile sizes' argument nee= ds positive integral constant} } + for (T i : v) + for (T j : v) + for (T k : v) + dummy (i); +} + +void test () { test1_template (); }; diff --git a/libgomp/testsuite/libgomp.c++/loop-transforms/tile-1.C b/libgo= mp/testsuite/libgomp.c++/loop-transforms/tile-1.C new file mode 100644 index 00000000000..2a4d760720d --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/loop-transforms/tile-1.C @@ -0,0 +1,52 @@ +#include +#include +#include + +void +mult (float *matrix1, float *matrix2, float *result, unsigned dim0, + unsigned dim1) +{ + memset (result, 0, sizeof (float) * dim0 * dim1); +#pragma omp target parallel for collapse(3) map(tofrom:result[0:dim0*dim1]= ) map(to:matrix1[0:dim0*dim1], matrix2[0:dim0*dim1]) +#pragma omp tile sizes(8, 16, 4) + for (unsigned i =3D 0; i < dim0; i++) + for (unsigned j =3D 0; j < dim1; j++) + for (unsigned k =3D 0; k < dim1; k++) + result[i * dim1 + j] +=3D matrix1[i * dim1 + k] * matrix2[k * dim0 = + j]; +} + +int +main () +{ + unsigned dim0 =3D 20; + unsigned dim1 =3D 20; + + float *result =3D (float *)malloc (sizeof (float) * dim0 * dim1); + float *matrix1 =3D (float *)malloc (sizeof (float) * dim0 * dim1); + float *matrix2 =3D (float *)malloc (sizeof (float) * dim0 * dim1); + + for (unsigned i =3D 0; i < dim0; i++) + for (unsigned j =3D 0; j < dim1; j++) + matrix1[i * dim1 + j] =3D j; + + for (unsigned i =3D 0; i < dim1; i++) + for (unsigned j =3D 0; j < dim0; j++) + if (i =3D=3D j) + matrix2[i * dim0 + j] =3D 1; + else + matrix2[i * dim0 + j] =3D 0; + + mult (matrix1, matrix2, result, dim0, dim1); + + for (unsigned i =3D 0; i < dim0; i++) + for (unsigned j =3D 0; j < dim1; j++) + { + if (matrix1[i * dim1 + j] !=3D result[i * dim1 + j]) + { + printf ("ERROR at %d, %d\n", i, j); + __builtin_abort (); + } + } + + return 0; +} diff --git a/libgomp/testsuite/libgomp.c++/loop-transforms/tile-2.C b/libgo= mp/testsuite/libgomp.c++/loop-transforms/tile-2.C new file mode 100644 index 00000000000..780421fa4c7 --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/loop-transforms/tile-2.C @@ -0,0 +1,69 @@ +// { 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 tile sizes(fib(4)) + 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; + for (int k =3D 0; k < 10; k++) +#pragma omp parallel for collapse(2) reduction(+:sum) +#pragma omp tile sizes(fib(4), 1) + for (int i : v) + for (int j =3D 8; j > -2; --j) + sum =3D sum + i; + + return sum; +} + +int +main () +{ + int result =3D test1 (); + + if (result !=3D 1000) + { + fprintf (stderr, "%d: Wrong result: %d\n", __LINE__, result); + __builtin_abort (); + } + + result =3D test2 (); + if (result !=3D 5500) + { + fprintf (stderr, "%d: Wrong result: %d\n", __LINE__, result); + __builtin_abort (); + } + + return 0; +} diff --git a/libgomp/testsuite/libgomp.c++/loop-transforms/tile-3.C b/libgo= mp/testsuite/libgomp.c++/loop-transforms/tile-3.C new file mode 100644 index 00000000000..91ec8f5c137 --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/loop-transforms/tile-3.C @@ -0,0 +1,28 @@ +// { dg-additional-options "-std=3Dc++11" } +// { dg-additional-options "-O0" } + +#include + +int +main () +{ + std::vector v; + std::vector w; + + for (unsigned i =3D 0; i <=3D 9; i++) + v.push_back (i); + + int iter =3D 0; +#pragma omp for +#pragma omp tile sizes(5) + for (int i : v) + { + w.push_back (iter); + iter++; + } + + for (int i =3D 0; i < w.size (); i++) + if (w[i] !=3D i) + __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