From patchwork Sun Oct 1 20:10:21 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sandra Loosemore X-Patchwork-Id: 147155 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a05:612c:2a8e:b0:403:3b70:6f57 with SMTP id in14csp1038821vqb; Sun, 1 Oct 2023 13:14:55 -0700 (PDT) X-Google-Smtp-Source: AGHT+IGEI7BFELPw486MX6MZFa2P9LrgddjXOmt9v2x2eTMNVgnqLlYn7Y8Yh+wfc0wVAmBvB1aq X-Received: by 2002:a05:6402:354:b0:532:c046:9e01 with SMTP id r20-20020a056402035400b00532c0469e01mr8467028edw.7.1696191295624; Sun, 01 Oct 2023 13:14:55 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1696191295; cv=none; d=google.com; s=arc-20160816; b=c5bWDmjqGBuladgQHc/2YQqVO5VNxn53r159EDRrEg0zKO91lz7QnsMK1VC166tuWx ChXx7Pw9KsyaGDn7SeYLgxFubdG1E4w77U78bZM4SQidwtgybmHSjVbEfbTDEyMYANxb 3LAkemVe+2qJcTjTKFE/uCynO4Er1R/7ab3VakVYFS1AFqS+X/ev/dlYDIjsQYY4XL2m +hWU//EHMBMPJj94impe968Ra9qRWb227HsPutA34NEUmuYi+GP2f7SIN3eus8UTIpfS nHHyWQ3v70JhLStIC7VM2VxT0PePSWgFFX92zeJNbsUIdTyL+VZBAIB52WlxwnOtwVLS vSPw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=errors-to:list-subscribe:list-help:list-post:list-archive :list-unsubscribe:list-id:precedence:content-transfer-encoding :mime-version:references:in-reply-to:message-id:date:subject:cc:to :from:ironport-sdr:dmarc-filter:delivered-to; bh=CHe0NeKTawvXCeQIRl52pAwSGoehXRBJbmGJ0nj1yJM=; fh=OCleZEGPw6EXwGK7DgwfSjSqRFJqj4InDXFwXNGe58Y=; b=Av0/cQ53jRyRMv12eQZA79zF8J6NrNJ+IJWUiG/SwqJZBimVfKYLIz4qtPDD6bBUY7 CnodZ1E3TAdUBVEiUt2UzbubgLZHtBvq5UtB27rVvBxdtssY3y7bLEtlLiybwnElA8uv BId0NAqe/B+LFfw+X9evVWkvikxVeIGA5WCUMSQhieFKe8LVP43cUqzZTAE0aU767Km8 GCI3Zmo4rQnFFG2uDGcMF9T3An0Bku8rMfB/hblHrgI6q3fCFUrJBPoUTxZOtbKX3EeW aObmnItozuQLAjUUbqu4OmboIzrMCE0LqMhXqHSrT2pzWV/rlt2NWC2OiedOZFN5vsF8 V4dQ== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: domain of gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org designates 8.43.85.97 as permitted sender) smtp.mailfrom="gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org" Received: from server2.sourceware.org (ip-8-43-85-97.sourceware.org. [8.43.85.97]) by mx.google.com with ESMTPS id t13-20020aa7d4cd000000b005256d5bdb32si17127520edr.448.2023.10.01.13.14.55 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 01 Oct 2023 13:14:55 -0700 (PDT) Received-SPF: pass (google.com: domain of gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org designates 8.43.85.97 as permitted sender) client-ip=8.43.85.97; Authentication-Results: mx.google.com; spf=pass (google.com: domain of gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org designates 8.43.85.97 as permitted sender) smtp.mailfrom="gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org" Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 663743882AFD for ; Sun, 1 Oct 2023 20:12:54 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from esa3.mentor.iphmx.com (esa3.mentor.iphmx.com [68.232.137.180]) by sourceware.org (Postfix) with ESMTPS id 0200138313B7 for ; Sun, 1 Oct 2023 20:11:26 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 0200138313B7 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-CSE-ConnectionGUID: uR03XYbQRJ2QigsLB1Hz/g== X-CSE-MsgGUID: dl6/TvX7TQCMK1UsmCpe2Q== X-IronPort-AV: E=Sophos;i="6.03,191,1694764800"; d="scan'208";a="18296439" Received: from orw-gwy-02-in.mentorg.com ([192.94.38.167]) by esa3.mentor.iphmx.com with ESMTP; 01 Oct 2023 12:11:26 -0800 IronPort-SDR: k8/ioS3ia/juNOwnyQaOLsuATfUDw2F729QeOdVcRCkl3mUmMhI2Nsj8Dq0M8Fq7EweT6uyISU AmZhgbiew1vDdgbDm7lqs++L9fPpGrlTP0WItcUnp+j3Je/CilpAObHYscdcQ0vyEJgFsSzlAi e7DqeDEa9TEo2cbPeh7I10G/t/nKmO0liaE435ryUZZtolInAYog9wxUcu6T0GiosNUUl8P71X MECVobPvTAcWdO9OpXY4jGvkzxMQmPEec1ykbAxQ6uLWPHwdrrIvuidi4mxnOqCXHIZb2ZmGj/ NV4= From: Sandra Loosemore To: CC: , Subject: [WIP 4/4] OpenMP: C and C++ front-end support for loop transforms. Date: Sun, 1 Oct 2023 14:10:21 -0600 Message-ID: <20231001201021.785572-5-sandra@codesourcery.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20231001201021.785572-1-sandra@codesourcery.com> References: <20231001201021.785572-1-sandra@codesourcery.com> MIME-Version: 1.0 X-ClientProxiedBy: svr-orw-mbx-11.mgc.mentorg.com (147.34.90.211) To svr-orw-mbx-13.mgc.mentorg.com (147.34.90.213) X-Spam-Status: No, score=-10.0 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 X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org X-getmail-retrieved-from-mailbox: INBOX X-GMAIL-THRID: 1778585484318738792 X-GMAIL-MSGID: 1778585484318738792 From: Frederik Harwath gcc/c-family/ChangeLog: * c-gimplify.cc (c_genericize_control_stmt): Handle OMP_LOOP_TRANS. * c-omp.cc (c_omp_directives): Uncomment entries for "tile" and "unroll". * c-pragma.cc (omp_pragmas_simd): Add tile and unroll. * c-pragma.h (enum pragma_kind): Add PRAGMA_OMP_TILE and PRAGMA_OMP_UNROLL. Adjust PRAGMA_OMP__LAST__. (enum pragma_clause): Add PRAGMA_OMP_CLAUSE_FULL, PRAGMA_OMP_CLAUSE_PARTIAL, and PRAGMA_OMP_CLAUSE_TILE. gcc/c/ChangeLog: * c-parser.cc (struct omp_for_parse_data): Add clauses field. (c_parser_skip_std_attribute_spec_seq): New. (check_omp_intervening_code): Reject imperfectly-nested loops with TILE directive. (c_parser_compound_statement_nostart): Handle loop transforms. (c_parser_omp_clause_name): Handle "full" and "partial". (check_no_duplicate_clause): Change to return a boolean error value. (c_parser_omp_clause_unroll_full): New. (c_parser_omp_clause_unroll_partial): New. (c_parser_omp_all_clauses): Handle PRAGMA_OMP_CLAUSE_FULL and PRAGMA_OMP_CLAUSE_PARTIAL. (c_parser_see_omp_loop_nest): New. (c_parser_omp_loop_nest): Error on standard attributes for consistency with C++. Handle loop transformations. (c_parser_omp_for_loop): Handle loop transformations. (OMP_UNROLL_CLAUSE_MASK): Define. (c_parser_omp_tile_sizes): New. (c_parser_omp_loop_transform_clause): New. (c_parser_omp_nested_loop_transform_clauses): New. (c_parser_omp_tile): New. (c_parser_omp_unroll): New. (c_parser_omp_construct): Handle PRAGMA_OMP_TILE and PRAGMA_OMP_UNROLL. * c-typeck.cc (c_finish_omp_clauses): Handle OMP_CLAUSE_UNROLL_FULL and OMP_CLAUSE_UNROLL_PARTIAL. gcc/cp/ChangeLog: * cp/cp-gimplify.cc (cp_gimplify_expr): Handle OMP_LOOP_TRANS. (cp_fold_r): Handle OMP_LOOP_TRANS. (cp_genericize_r): Handle OMP_LOOP_TRANS. * cp/parser.cc (check_omp_intervening_code): Reject imperfectly-nested loops with TILE directive. (cp_parser_statement_seq_opt): Handle loop transforms. (cp_parser_omp_clause_name): Handle "full" and "partial". (check_no_duplicate_clause): Change to return a boolean error value. (cp_parser_omp_clause_unroll_full): New. (cp_parser_omp_clause_unroll_partial): New. (cp_parser_omp_all_clauses): Consume comma even if first. Handle PRAGMA_OMP_CLAUSE_PARTIAL and PRAGMA_OMP_CLAUSE_FULL. (cp_parser_see_omp_loop_nest): New. (cp_parser_omp_loop_nest): Handle standard attribute syntax and loop transforms. (cp_parser_omp_for_loop): Handle loop transforms. (cp_parser_omp_tile_sizes): New. (cp_parser_omp_tile): New. (OMP_UNROLL_CLAUSE_MASK): New. (cp_parser_omp_loop_transform_clause): New. (cp_parser_nested_loop_transform_clauses): New. (cp_parser_omp_unroll): New. (cp_parser_omp_construct): Handle PRAGMA_OMP_TILE and PRAGMA_OMP_UNROLL. (cp_parser_pragma): Handle PRAGMA_OMP_TILE and PRAGMA_OMP_UNROLL. * cp/pt.cc (tsubst_omp_clauses): Handle new loop transform clauses. (tsubst_expr): Handle OMP_LOOP_TRANS. * cp/semantics.cc (finish_omp_clauses): Handle OMP_CLAUSE_TILE, OMP_CLAUSE_UNROLL_FULL, OMP_CLAUSE_UNROLL_PARTIAL, and OMP_CLAUSE_UNROLL_NONE. gcc/testsuite/ChangeLog: * c-c++-common/gomp/imperfect-attributes.c: Adjust for new attribute behavior. * c-c++-common/gomp/loop-transforms/imperfect-loop-nest.c: New. * c-c++-common/gomp/loop-transforms/tile-1.c: New. * c-c++-common/gomp/loop-transforms/tile-2.c: New. * c-c++-common/gomp/loop-transforms/tile-3.c: New. * c-c++-common/gomp/loop-transforms/tile-4.c: New. * c-c++-common/gomp/loop-transforms/tile-5.c: New. * c-c++-common/gomp/loop-transforms/tile-6.c: New. * c-c++-common/gomp/loop-transforms/tile-7.c: New. * c-c++-common/gomp/loop-transforms/tile-8.c: New. * c-c++-common/gomp/loop-transforms/unroll-1.c: New. * c-c++-common/gomp/loop-transforms/unroll-2.c: New. * c-c++-common/gomp/loop-transforms/unroll-3.c: New. * c-c++-common/gomp/loop-transforms/unroll-4.c: New. * c-c++-common/gomp/loop-transforms/unroll-5.c: New. * c-c++-common/gomp/loop-transforms/unroll-6.c: New. * c-c++-common/gomp/loop-transforms/unroll-7.c: New. * c-c++-common/gomp/loop-transforms/unroll-8.c: New. * c-c++-common/gomp/loop-transforms/unroll-inner-1.c: New. * c-c++-common/gomp/loop-transforms/unroll-inner-2.c: New. * c-c++-common/gomp/loop-transforms/unroll-non-rect-1.c: New. * c-c++-common/gomp/loop-transforms/unroll-non-rect-2.c: New. * c-c++-common/gomp/loop-transforms/unroll-simd-1.c: New. * g++.dg/gomp/attrs-4.C: Adjust expected error message. * g++.dg/gomp/for-1.C: Adjust expected error message. * g++.dg/gomp/loop-transforms/attrs-tile-1.C: New. * g++.dg/gomp/loop-transforms/attrs-tile-2.C: New. * g++.dg/gomp/loop-transforms/attrs-tile-3.C: New. * g++.dg/gomp/loop-transforms/attrs-unroll-1.C: New. * g++.dg/gomp/loop-transforms/attrs-unroll-2.C: New. * g++.dg/gomp/loop-transforms/attrs-unroll-3.C: New. * g++.dg/gomp/loop-transforms/attrs-unroll-inner-1.C: New. * g++.dg/gomp/loop-transforms/attrs-unroll-inner-2.C: New. * g++.dg/gomp/loop-transforms/attrs-unroll-inner-3.C: New. * g++.dg/gomp/loop-transforms/tile-1.h: New. * g++.dg/gomp/loop-transforms/tile-1a.C: New. * g++.dg/gomp/loop-transforms/tile-1b.C: New. * g++.dg/gomp/loop-transforms/unroll-1.C: New. * g++.dg/gomp/loop-transforms/unroll-2.C: New. * g++.dg/gomp/loop-transforms/unroll-3.C: New. * g++.dg/gomp/pr94512.C: Adjust expected error message. * gcc.dg/gomp/for-1.c: Adjust expected error message. * gcc.dg/gomp/for-11.c: Adjust expected error message. libgomp/ChangeLog: * testsuite/libgomp.c++/loop-transforms/matrix-no-directive-unroll-full-1.C: New. * testsuite/libgomp.c++/loop-transforms/tile-2.C: New. * testsuite/libgomp.c++/loop-transforms/tile-3.C: New. * testsuite/libgomp.c++/loop-transforms/unroll-1.C: New. * testsuite/libgomp.c++/loop-transforms/unroll-2.C: New. * testsuite/libgomp.c++/loop-transforms/unroll-full-tile.C: New. * testsuite/libgomp.c-c++-common/imperfect-transform-1.c: New. * testsuite/libgomp.c-c++-common/imperfect-transform-2.c: New. * testsuite/libgomp.c-c++-common/loop-transforms/matrix-1.h: New. * testsuite/libgomp.c-c++-common/loop-transforms/matrix-constant-iter.h: New. * testsuite/libgomp.c-c++-common/loop-transforms/matrix-helper.h: New. * testsuite/libgomp.c-c++-common/loop-transforms/matrix-no-directive-1.c: New. * testsuite/libgomp.c-c++-common/loop-transforms/matrix-no-directive-unroll-full-1.c: New. * testsuite/libgomp.c-c++-common/loop-transforms/matrix-omp-distribute-parallel-for-1.c: New. * testsuite/libgomp.c-c++-common/loop-transforms/matrix-omp-for-1.c: New. * testsuite/libgomp.c-c++-common/loop-transforms/matrix-omp-parallel-for-1.c: New. * testsuite/libgomp.c-c++-common/loop-transforms/matrix-omp-parallel-masked-taskloop-1.c: New. * testsuite/libgomp.c-c++-common/loop-transforms/matrix-omp-parallel-masked-taskloop-simd-1.c: New. * testsuite/libgomp.c-c++-common/loop-transforms/matrix-omp-target-parallel-for-1.c: New. * testsuite/libgomp.c-c++-common/loop-transforms/matrix-omp-target-teams-distribute-parallel-for-1.c: New. * testsuite/libgomp.c-c++-common/loop-transforms/matrix-omp-taskloop-1.c: New. * testsuite/libgomp.c-c++-common/loop-transforms/matrix-omp-teams-distribute-parallel-for-1.c: New. * testsuite/libgomp.c-c++-common/loop-transforms/matrix-simd-1.c: New. * testsuite/libgomp.c-c++-common/loop-transforms/matrix-transform-variants-1.h: New. * testsuite/libgomp.c-c++-common/loop-transforms/unroll-1.c: New. * testsuite/libgomp.c-c++-common/loop-transforms/unroll-non-rect-1.c: New. * testsuite/libgomp.c-c++-common/target-imperfect-transform-1.c: New. * testsuite/libgomp.c-c++-common/target-imperfect-transform-2.c: New. Co-Authored-By: Sandra Loosemore --- gcc/c-family/c-gimplify.cc | 1 + gcc/c-family/c-omp.cc | 10 +- gcc/c-family/c-pragma.cc | 2 + gcc/c-family/c-pragma.h | 7 +- gcc/c/c-parser.cc | 515 ++++++++++++++++- gcc/c/c-typeck.cc | 8 + gcc/cp/cp-gimplify.cc | 3 + gcc/cp/parser.cc | 529 +++++++++++++++++- gcc/cp/pt.cc | 13 + gcc/cp/semantics.cc | 95 ++++ .../c-c++-common/gomp/imperfect-attributes.c | 18 +- .../loop-transforms/imperfect-loop-nest.c | 11 + .../gomp/loop-transforms/tile-1.c | 160 ++++++ .../gomp/loop-transforms/tile-2.c | 179 ++++++ .../gomp/loop-transforms/tile-3.c | 109 ++++ .../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-1.c | 133 +++++ .../gomp/loop-transforms/unroll-2.c | 95 ++++ .../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-8.c | 76 +++ .../gomp/loop-transforms/unroll-inner-1.c | 15 + .../gomp/loop-transforms/unroll-inner-2.c | 29 + .../gomp/loop-transforms/unroll-non-rect-1.c | 37 ++ .../gomp/loop-transforms/unroll-non-rect-2.c | 22 + .../gomp/loop-transforms/unroll-simd-1.c | 84 +++ gcc/testsuite/g++.dg/gomp/attrs-4.C | 2 +- gcc/testsuite/g++.dg/gomp/for-1.C | 2 +- .../gomp/loop-transforms/attrs-tile-1.C | 164 ++++++ .../gomp/loop-transforms/attrs-tile-2.C | 174 ++++++ .../gomp/loop-transforms/attrs-tile-3.C | 111 ++++ .../gomp/loop-transforms/attrs-unroll-1.C | 135 +++++ .../gomp/loop-transforms/attrs-unroll-2.C | 81 +++ .../gomp/loop-transforms/attrs-unroll-3.C | 20 + .../loop-transforms/attrs-unroll-inner-1.C | 15 + .../loop-transforms/attrs-unroll-inner-2.C | 29 + .../loop-transforms/attrs-unroll-inner-3.C | 71 +++ .../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 + .../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 ++ gcc/testsuite/g++.dg/gomp/pr94512.C | 2 +- gcc/testsuite/gcc.dg/gomp/for-1.c | 2 +- gcc/testsuite/gcc.dg/gomp/for-11.c | 2 +- .../matrix-no-directive-unroll-full-1.C | 13 + .../libgomp.c++/loop-transforms/tile-2.C | 69 +++ .../libgomp.c++/loop-transforms/tile-3.C | 28 + .../libgomp.c++/loop-transforms/unroll-1.C | 73 +++ .../libgomp.c++/loop-transforms/unroll-2.C | 34 ++ .../loop-transforms/unroll-full-tile.C | 84 +++ .../imperfect-transform-1.c | 79 +++ .../imperfect-transform-2.c | 79 +++ .../loop-transforms/matrix-1.h | 70 +++ .../loop-transforms/matrix-constant-iter.h | 71 +++ .../loop-transforms/matrix-helper.h | 19 + .../loop-transforms/matrix-no-directive-1.c | 11 + .../matrix-no-directive-unroll-full-1.c | 13 + .../matrix-omp-distribute-parallel-for-1.c | 8 + .../loop-transforms/matrix-omp-for-1.c | 13 + .../matrix-omp-parallel-for-1.c | 13 + .../matrix-omp-parallel-masked-taskloop-1.c | 8 + ...trix-omp-parallel-masked-taskloop-simd-1.c | 8 + .../matrix-omp-target-parallel-for-1.c | 15 + ...p-target-teams-distribute-parallel-for-1.c | 10 + .../loop-transforms/matrix-omp-taskloop-1.c | 8 + ...trix-omp-teams-distribute-parallel-for-1.c | 8 + .../loop-transforms/matrix-simd-1.c | 8 + .../matrix-transform-variants-1.h | 191 +++++++ .../loop-transforms/unroll-1.c | 78 +++ .../loop-transforms/unroll-non-rect-1.c | 131 +++++ .../target-imperfect-transform-1.c | 82 +++ .../target-imperfect-transform-2.c | 82 +++ 81 files changed, 5218 insertions(+), 53 deletions(-) create mode 100644 gcc/testsuite/c-c++-common/gomp/loop-transforms/imperfect-loop-nest.c 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/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-8.c create mode 100644 gcc/testsuite/c-c++-common/gomp/loop-transforms/unroll-inner-1.c create mode 100644 gcc/testsuite/c-c++-common/gomp/loop-transforms/unroll-inner-2.c create mode 100644 gcc/testsuite/c-c++-common/gomp/loop-transforms/unroll-non-rect-1.c create mode 100644 gcc/testsuite/c-c++-common/gomp/loop-transforms/unroll-non-rect-2.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/attrs-tile-1.C create mode 100644 gcc/testsuite/g++.dg/gomp/loop-transforms/attrs-tile-2.C create mode 100644 gcc/testsuite/g++.dg/gomp/loop-transforms/attrs-tile-3.C create mode 100644 gcc/testsuite/g++.dg/gomp/loop-transforms/attrs-unroll-1.C create mode 100644 gcc/testsuite/g++.dg/gomp/loop-transforms/attrs-unroll-2.C create mode 100644 gcc/testsuite/g++.dg/gomp/loop-transforms/attrs-unroll-3.C create mode 100644 gcc/testsuite/g++.dg/gomp/loop-transforms/attrs-unroll-inner-1.C create mode 100644 gcc/testsuite/g++.dg/gomp/loop-transforms/attrs-unroll-inner-2.C create mode 100644 gcc/testsuite/g++.dg/gomp/loop-transforms/attrs-unroll-inner-3.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 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/matrix-no-directive-unroll-full-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 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++/loop-transforms/unroll-full-tile.C create mode 100644 libgomp/testsuite/libgomp.c-c++-common/imperfect-transform-1.c create mode 100644 libgomp/testsuite/libgomp.c-c++-common/imperfect-transform-2.c create mode 100644 libgomp/testsuite/libgomp.c-c++-common/loop-transforms/matrix-1.h create mode 100644 libgomp/testsuite/libgomp.c-c++-common/loop-transforms/matrix-constant-iter.h create mode 100644 libgomp/testsuite/libgomp.c-c++-common/loop-transforms/matrix-helper.h create mode 100644 libgomp/testsuite/libgomp.c-c++-common/loop-transforms/matrix-no-directive-1.c create mode 100644 libgomp/testsuite/libgomp.c-c++-common/loop-transforms/matrix-no-directive-unroll-full-1.c create mode 100644 libgomp/testsuite/libgomp.c-c++-common/loop-transforms/matrix-omp-distribute-parallel-for-1.c create mode 100644 libgomp/testsuite/libgomp.c-c++-common/loop-transforms/matrix-omp-for-1.c create mode 100644 libgomp/testsuite/libgomp.c-c++-common/loop-transforms/matrix-omp-parallel-for-1.c create mode 100644 libgomp/testsuite/libgomp.c-c++-common/loop-transforms/matrix-omp-parallel-masked-taskloop-1.c create mode 100644 libgomp/testsuite/libgomp.c-c++-common/loop-transforms/matrix-omp-parallel-masked-taskloop-simd-1.c create mode 100644 libgomp/testsuite/libgomp.c-c++-common/loop-transforms/matrix-omp-target-parallel-for-1.c create mode 100644 libgomp/testsuite/libgomp.c-c++-common/loop-transforms/matrix-omp-target-teams-distribute-parallel-for-1.c create mode 100644 libgomp/testsuite/libgomp.c-c++-common/loop-transforms/matrix-omp-taskloop-1.c create mode 100644 libgomp/testsuite/libgomp.c-c++-common/loop-transforms/matrix-omp-teams-distribute-parallel-for-1.c create mode 100644 libgomp/testsuite/libgomp.c-c++-common/loop-transforms/matrix-simd-1.c create mode 100644 libgomp/testsuite/libgomp.c-c++-common/loop-transforms/matrix-transform-variants-1.h create mode 100644 libgomp/testsuite/libgomp.c-c++-common/loop-transforms/unroll-1.c create mode 100644 libgomp/testsuite/libgomp.c-c++-common/loop-transforms/unroll-non-rect-1.c create mode 100644 libgomp/testsuite/libgomp.c-c++-common/target-imperfect-transform-1.c create mode 100644 libgomp/testsuite/libgomp.c-c++-common/target-imperfect-transform-2.c diff --git a/gcc/c-family/c-gimplify.cc b/gcc/c-family/c-gimplify.cc index 17b0610a89f..35d3a6e10d6 100644 --- a/gcc/c-family/c-gimplify.cc +++ b/gcc/c-family/c-gimplify.cc @@ -508,6 +508,7 @@ c_genericize_control_stmt (tree *stmt_p, int *walk_subtrees, 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 5de3b77c450..980c6fc0867 100644 --- a/gcc/c-family/c-omp.cc +++ b/gcc/c-family/c-omp.cc @@ -3359,14 +3359,14 @@ const struct c_omp_directive c_omp_directives[] = { 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, - 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 293311dd4ce..22e5448331e 100644 --- a/gcc/c-family/c-pragma.cc +++ b/gcc/c-family/c-pragma.cc @@ -1550,6 +1550,8 @@ static const struct omp_pragma_def omp_pragmas_simd[] = { { "target", PRAGMA_OMP_TARGET }, { "taskloop", PRAGMA_OMP_TASKLOOP }, { "teams", PRAGMA_OMP_TEAMS }, + { "tile", PRAGMA_OMP_TILE }, + { "unroll", PRAGMA_OMP_UNROLL }, }; void diff --git a/gcc/c-family/c-pragma.h b/gcc/c-family/c-pragma.h index 603c5151978..703154d224e 100644 --- a/gcc/c-family/c-pragma.h +++ b/gcc/c-family/c-pragma.h @@ -81,8 +81,10 @@ 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_ = PRAGMA_OMP_TEAMS, + PRAGMA_OMP__LAST_ = PRAGMA_OMP_UNROLL, PRAGMA_GCC_PCH_PREPROCESS, PRAGMA_IVDEP, @@ -119,6 +121,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, @@ -141,6 +144,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, @@ -155,6 +159,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 e6342d2188d..45f59ded1a7 100644 --- a/gcc/c/c-parser.cc +++ b/gcc/c/c-parser.cc @@ -1554,6 +1554,7 @@ static tree objc_foreach_break_label, objc_foreach_continue_label; */ struct omp_for_parse_data { enum tree_code code; + tree clauses; tree declv, condv, incrv, initv; tree pre_body; tree bindings; @@ -1662,7 +1663,10 @@ static void c_parser_omp_threadprivate (c_parser *); static void c_parser_omp_barrier (c_parser *); static void c_parser_omp_depobj (c_parser *); static void c_parser_omp_flush (c_parser *); +static bool c_parser_see_omp_loop_nest (c_parser *, enum tree_code, bool); static tree c_parser_omp_loop_nest (c_parser *, bool *); +static int c_parser_omp_nested_loop_transform_clauses (c_parser *, tree &, int, + int, const char *); static tree c_parser_omp_for_loop (location_t, c_parser *, enum tree_code, tree, tree *, bool *); static void c_parser_omp_taskwait (c_parser *); @@ -5720,6 +5724,37 @@ c_parser_nth_token_starts_std_attributes (c_parser *parser, unsigned int n) return token->type == CPP_CLOSE_SQUARE; } +/* Skip standard attribute tokens starting at Nth token (with 1 as the + next token), return index of the first token after the standard + attribute tokens, or N on failure. */ + +static size_t +c_parser_skip_std_attribute_spec_seq (c_parser *parser, size_t n) +{ + size_t orig_n = n; + while (true) + { + if (c_parser_peek_nth_token_raw (parser, n)->type == CPP_OPEN_SQUARE + && (c_parser_peek_nth_token_raw (parser, n + 1)->type + == CPP_OPEN_SQUARE)) + { + unsigned int m = n + 2; + if (!c_parser_check_balanced_raw_token_sequence (parser, &m)) + return orig_n; + c_token *token = c_parser_peek_nth_token_raw (parser, m); + if (token->type != CPP_CLOSE_SQUARE) + return orig_n; + token = c_parser_peek_nth_token_raw (parser, m + 1); + if (token->type != CPP_CLOSE_SQUARE) + return orig_n; + n = m + 2; + } + else + break; + } + return n; +} + static tree c_parser_std_attribute_specifier_sequence (c_parser *parser) { @@ -6305,7 +6340,20 @@ check_omp_intervening_code (c_parser *parser) "% % clause"); omp_for_parse_state->perfect_nesting_fail = true; } - /* TODO: Also reject loops with TILE directive. */ + else + { + tree c = omp_find_clause (omp_for_parse_state->clauses, + OMP_CLAUSE_TILE); + if (c && + ((int) tree_to_uhwi (OMP_CLAUSE_TRANSFORM_LEVEL (c)) + <= omp_for_parse_state->depth)) + { + error_at (omp_for_parse_state->for_loc, + "inner loops must be perfectly nested " + "with % directive"); + omp_for_parse_state->perfect_nesting_fail = true; + } + } if (omp_for_parse_state->perfect_nesting_fail) omp_for_parse_state->fail = true; } @@ -6412,7 +6460,9 @@ c_parser_compound_statement_nostart (c_parser *parser) if (in_omp_loop_block && !last_label) { if (want_nested_loop - && c_parser_next_token_is_keyword (parser, RID_FOR)) + && c_parser_see_omp_loop_nest (parser, + omp_for_parse_state->code, + false)) { /* Found the next nested loop. If there were intervening code statements collected before now, wrap them in an @@ -13953,6 +14003,8 @@ c_parser_omp_clause_name (c_parser *parser) result = PRAGMA_OMP_CLAUSE_FIRSTPRIVATE; else if (!strcmp ("from", p)) result = PRAGMA_OMP_CLAUSE_FROM; + else if (!strcmp ("full", p)) + result = PRAGMA_OMP_CLAUSE_FULL; break; case 'g': if (!strcmp ("gang", p)) @@ -14027,6 +14079,8 @@ c_parser_omp_clause_name (c_parser *parser) case 'p': if (!strcmp ("parallel", p)) result = PRAGMA_OMP_CLAUSE_PARALLEL; + else if (!strcmp ("partial", p)) + result = PRAGMA_OMP_CLAUSE_PARTIAL; else if (!strcmp ("present", p)) result = PRAGMA_OACC_CLAUSE_PRESENT; /* As of OpenACC 2.5, these are now aliases of the non-present_or @@ -14121,12 +14175,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 = omp_find_clause (clauses, code)) + tree c = omp_find_clause (clauses, code); + if (c) error_at (OMP_CLAUSE_LOCATION (c), "too many %qs clauses", name); + + return c == NULL_TREE; } /* OpenACC 2.0 @@ -17993,6 +18050,67 @@ c_parser_omp_clause_uniform (c_parser *parser, tree 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 = c_parser_peek_token (parser)->location; + tree c = build_omp_clause (loc, OMP_CLAUSE_UNROLL_FULL); + OMP_CLAUSE_TRANSFORM_LEVEL (c) = build_int_cst (unsigned_type_node, 0); + OMP_CLAUSE_CHAIN (c) = 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, "partial")) + return list; + + tree c, num = error_mark_node; + HOST_WIDE_INT n; + location_t loc; + + loc = c_parser_peek_token (parser)->location; + c = build_omp_clause (loc, OMP_CLAUSE_UNROLL_PARTIAL); + OMP_CLAUSE_UNROLL_PARTIAL_EXPR (c) = NULL_TREE; + OMP_CLAUSE_TRANSFORM_LEVEL (c) = build_int_cst (unsigned_type_node, 0); + OMP_CLAUSE_CHAIN (c) = list; + + if (!c_parser_next_token_is (parser, CPP_OPEN_PAREN)) + return c; + + matching_parens parens; + parens.consume_open (parser); + num = c_parser_expr_no_commas (parser, NULL).value; + parens.skip_until_found_close (parser); + + if (num == error_mark_node) + return list; + + mark_exp_read (num); + num = c_fully_fold (num, false, NULL); + if (!INTEGRAL_TYPE_P (TREE_TYPE (num)) || !tree_fits_shwi_p (num) + || (n = tree_to_shwi (num)) <= 0 || (int)n != n) + { + error_at (loc, + "partial argument needs positive constant integer expression"); + return list; + } + + OMP_CLAUSE_UNROLL_PARTIAL_EXPR (c) = num; + + return c; +} + /* OpenMP 5.0: detach ( event-handle ) */ @@ -18589,6 +18707,14 @@ c_parser_omp_all_clauses (c_parser *parser, omp_clause_mask mask, clauses); c_name = "enter"; break; + case PRAGMA_OMP_CLAUSE_FULL: + c_name = "full"; + clauses = c_parser_omp_clause_unroll_full (parser, clauses); + break; + case PRAGMA_OMP_CLAUSE_PARTIAL: + c_name = "partial"; + clauses = c_parser_omp_clause_unroll_partial (parser, clauses); + break; default: c_parser_error (parser, "expected an OpenMP clause"); goto saw_error; @@ -20848,6 +20974,44 @@ c_parser_omp_scan_loop_body (c_parser *parser, bool open_brace_parsed) } +/* Check that the next token starts a loop nest. Return true if yes, + otherwise diagnose an error if ERROR_P is true, and return false. */ +static bool +c_parser_see_omp_loop_nest (c_parser *parser, enum tree_code code, + bool error_p) +{ + if (code == OACC_LOOP) + { + if (c_parser_next_token_is_keyword (parser, RID_FOR)) + return true; + if (error_p) + c_parser_error (parser, "for statement expected"); + } + else + { + if (c_parser_next_token_is_keyword (parser, RID_FOR) + || c_parser_peek_token (parser)->pragma_kind == PRAGMA_OMP_UNROLL + || c_parser_peek_token (parser)->pragma_kind == PRAGMA_OMP_TILE) + return true; + + /* For consistency with C++, treat standard attributes followed + by RID_FOR as a loop nest, but diagnose unknown attributes as + an error in c_parser_omp_loop_nest. */ + size_t n = c_parser_skip_std_attribute_spec_seq (parser, 1); + c_token *token = c_parser_peek_nth_token_raw (parser, n); + /* TOKEN is a raw token that hasn't been converted to a keyword yet, + we have to do the lookup explicitly. */ + if (token->type == CPP_NAME + && C_IS_RESERVED_WORD (token->value) + && C_RID_CODE (token->value) == RID_FOR) + return true; + if (error_p) + c_parser_error (parser, "loop nest expected"); + } + + return false; +} + /* This function parses a single level of a loop nest, invoking itself recursively if necessary. @@ -20883,6 +21047,51 @@ c_parser_omp_loop_nest (c_parser *parser, bool *if_p) gcc_assert (omp_for_parse_state); int depth = omp_for_parse_state->depth; + /* Reject non-empty standard attributes with an error. C++ allows OpenMP + directives to be specified with attribute syntax, but C does not. */ + if (c_parser_nth_token_starts_std_attributes (parser, 1)) + { + tree std_attrs = c_parser_std_attribute_specifier_sequence (parser); + if (std_attrs) + error_at (c_parser_peek_token (parser)->location, + "attributes are not allowed on % in loop nest"); + } + + /* Handle loop transformations first. Note that when we get here + omp_for_parse_state->depth has already been incremented to indicate + the depth of the *next* loop, not the level of the loop body the + transformation directive appears in. */ + if (c_parser_peek_token (parser)->pragma_kind == PRAGMA_OMP_UNROLL + || c_parser_peek_token (parser)->pragma_kind == PRAGMA_OMP_TILE) + { + int count = omp_for_parse_state->count; + int more = c_parser_omp_nested_loop_transform_clauses ( + parser, omp_for_parse_state->clauses, + depth, count - depth, "loop collapse"); + if (depth + more > count) + { + count = depth + more; + omp_for_parse_state->count = count; + omp_for_parse_state->declv + = grow_tree_vec (omp_for_parse_state->declv, count); + omp_for_parse_state->initv + = grow_tree_vec (omp_for_parse_state->initv, count); + omp_for_parse_state->condv + = grow_tree_vec (omp_for_parse_state->condv, count); + omp_for_parse_state->incrv + = grow_tree_vec (omp_for_parse_state->incrv, count); + } + if (c_parser_see_omp_loop_nest (parser, omp_for_parse_state->code, + true)) + return c_parser_omp_loop_nest (parser, if_p); + else + { + /* FIXME: Better error recovery here? */ + omp_for_parse_state->fail = true; + return NULL_TREE; + } + } + /* We have already matched the FOR token but not consumed it yet. */ loc = c_parser_peek_token (parser)->location; gcc_assert (c_parser_next_token_is_keyword (parser, RID_FOR)); @@ -21017,7 +21226,9 @@ c_parser_omp_loop_nest (c_parser *parser, bool *if_p) parse_next: moreloops = depth < omp_for_parse_state->count - 1; omp_for_parse_state->want_nested_loop = moreloops; - if (moreloops && c_parser_next_token_is_keyword (parser, RID_FOR)) + if (moreloops + && c_parser_see_omp_loop_nest (parser, omp_for_parse_state->code, + false)) { omp_for_parse_state->depth++; body = c_parser_omp_loop_nest (parser, if_p); @@ -21129,7 +21340,7 @@ c_parser_omp_for_loop (location_t loc, c_parser *parser, enum tree_code code, tree ret = NULL_TREE; tree ordered_cl = NULL_TREE; int i, collapse = 1, ordered = 0, count; - bool tiling = false; + bool oacc_tiling = false; bool inscan = false; struct omp_for_parse_data data; struct omp_for_parse_data *save_data = parser->omp_for_parse_state; @@ -21139,7 +21350,7 @@ c_parser_omp_for_loop (location_t loc, c_parser *parser, enum tree_code code, collapse = tree_to_shwi (OMP_CLAUSE_COLLAPSE_EXPR (cl)); else if (OMP_CLAUSE_CODE (cl) == OMP_CLAUSE_OACC_TILE) { - tiling = true; + oacc_tiling = true; collapse = list_length (OMP_CLAUSE_OACC_TILE_LIST (cl)); } else if (OMP_CLAUSE_CODE (cl) == OMP_CLAUSE_ORDERED @@ -21162,15 +21373,29 @@ c_parser_omp_for_loop (location_t loc, c_parser *parser, enum tree_code code, ordered = collapse; } - gcc_assert (tiling || (collapse >= 1 && ordered >= 0)); - count = ordered ? ordered : collapse; + c_parser_omp_nested_loop_transform_clauses (parser, clauses, 0, collapse, + "loop collapse"); - if (!c_parser_next_token_is_keyword (parser, RID_FOR)) + /* 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 = 0; + for (tree c = clauses; c; c = TREE_CHAIN (c)) { - c_parser_error (parser, "for statement expected"); - return NULL; + if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_TILE) + continue; + + omp_tile_depth = list_length (OMP_CLAUSE_TILE_SIZES (c)); } + gcc_assert (oacc_tiling || (collapse >= 1 && ordered >= 0)); + count = ordered ? ordered : collapse; + count = MAX (count, omp_tile_depth); + + if (!c_parser_see_omp_loop_nest (parser, code, true)) + return NULL; + /* Initialize parse state for recursive descent. */ data.declv = make_tree_vec (count); data.initv = make_tree_vec (count); @@ -21189,9 +21414,11 @@ c_parser_omp_for_loop (location_t loc, c_parser *parser, enum tree_code code, data.inscan = inscan; data.saw_intervening_code = false; data.code = code; + data.clauses = clauses; parser->omp_for_parse_state = &data; body = c_parser_omp_loop_nest (parser, if_p); + count = data.count; /* Add saved bindings for iteration variables that were declared in the nested for loop to the scope surrounding the entire loop. */ @@ -24641,6 +24868,263 @@ c_parser_omp_taskloop (location_t loc, c_parser *parser, return ret; } +#define OMP_UNROLL_CLAUSE_MASK \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PARTIAL) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FULL) ) + +/* 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 = NULL_TREE; + + c_token *tok = c_parser_peek_token (parser); + if (tok->type != 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 = c_parser_peek_token (parser)->location; + c_expr cexpr = c_parser_expr_no_commas (parser, NULL); + cexpr = convert_lvalue_to_rvalue (expr_loc, cexpr, false, true); + tree expr = cexpr.value; + + if (expr == error_mark_node) + { + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, + "expected %<)%>"); + return error_mark_node; + } + + expr = c_fully_fold (expr, false, NULL); + + if (!INTEGRAL_TYPE_P (TREE_TYPE (expr)) || !tree_fits_shwi_p (expr) + || tree_to_shwi (expr) <= 0) + { + c_parser_error (parser, "% argument needs positive" + " integral constant"); + expr = integer_zero_node; + } + + sizes = 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 = build_omp_clause (loc, OMP_CLAUSE_TILE); + OMP_CLAUSE_TRANSFORM_LEVEL (c) = build_int_cst (unsigned_type_node, 0); + OMP_CLAUSE_TILE_SIZES (c) = 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) +{ + c_token *tok = c_parser_peek_token (parser); + if (tok->type != CPP_PRAGMA) + return NULL_TREE; + + tree c; + switch (tok->pragma_kind) + { + case PRAGMA_OMP_UNROLL: + c_parser_consume_pragma (parser); + c = c_parser_omp_all_clauses (parser, OMP_UNROLL_CLAUSE_MASK, + "#pragma omp unroll", false, true); + if (!c && c_parser_next_token_is (parser, CPP_PRAGMA_EOL)) + { + c = build_omp_clause (tok->location, OMP_CLAUSE_UNROLL_NONE); + OMP_CLAUSE_TRANSFORM_LEVEL (c) + = build_int_cst (unsigned_type_node, 0); + } + else if (!c) + c = error_mark_node; + c_parser_skip_to_pragma_eol (parser); + break; + + case PRAGMA_OMP_TILE: + c_parser_consume_pragma (parser); + c = c_parser_omp_tile_sizes (parser, tok->location); + c_parser_skip_to_pragma_eol (parser); + break; + + default: + c = 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, + append all to CLAUSES and record the LEVEL at which the clauses + appear in the loop nest in each clause. + + 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 &clauses, + int level, int required_depth, + const char *outer_descr) +{ + tree c = NULL_TREE; + tree last_c = 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 = 0; + + /* The minimum nesting depth required by the last parsed transformation. */ + int last_depth = required_depth; + while ((c = c_parser_omp_loop_transform_clause (parser))) + { + /* The nesting depth left after the current transformation. */ + int depth = 1; + if (TREE_CODE (c) == 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 = 1; + break; + case OMP_CLAUSE_TILE: + depth = list_length (OMP_CLAUSE_TILE_SIZES (c)); + break; + default: + gcc_unreachable (); + } + + if (depth < last_depth) + { + bool is_outermost_clause = !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; + } + + last_depth = depth; + + if (!transformed_depth) + transformed_depth = last_depth; + + OMP_CLAUSE_TRANSFORM_LEVEL (c) = build_int_cst (unsigned_type_node, level); + if (!clauses) + clauses = c; + else if (last_c) + TREE_CHAIN (last_c) = c; + + last_c = c; + } + + return transformed_depth; + +error: + while (c_parser_omp_loop_transform_clause (parser)) + ; + clauses = 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 = error_mark_node; + + tree clauses = c_parser_omp_tile_sizes (parser, loc); + c_parser_skip_to_pragma_eol (parser); + + if (!clauses || clauses == error_mark_node) + return error_mark_node; + + int required_depth = list_length (OMP_CLAUSE_TILE_SIZES (clauses)); + c_parser_omp_nested_loop_transform_clauses (parser, clauses, 0, + required_depth, + "outer transformation"); + + block = c_begin_compound_stmt (true); + ret = c_parser_omp_for_loop (loc, parser, OMP_LOOP_TRANS, clauses, + NULL, if_p); + block = 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) +{ + tree block, ret; + static const char *p_name = "#pragma omp unroll"; + omp_clause_mask mask = OMP_UNROLL_CLAUSE_MASK; + + tree clauses = c_parser_omp_all_clauses (parser, mask, p_name, false); + int required_depth = 1; + c_parser_omp_nested_loop_transform_clauses (parser, clauses, 0, + required_depth, + "outer transformation"); + + if (!clauses) + { + tree c = build_omp_clause (loc, OMP_CLAUSE_UNROLL_NONE); + OMP_CLAUSE_TRANSFORM_LEVEL (c) = build_int_cst (unsigned_type_node, 0); + OMP_CLAUSE_CHAIN (c) = clauses; + clauses = c; + } + + block = c_begin_compound_stmt (true); + ret = c_parser_omp_for_loop (loc, parser, OMP_LOOP_TRANS, clauses, + NULL, if_p); + block = c_end_compound_stmt (loc, block, true); + add_stmt (block); + + return ret; +} + /* OpenMP 5.1 #pragma omp nothing new-line */ @@ -25032,6 +25516,7 @@ c_parser_omp_construct (c_parser *parser, bool *if_p) p_kind = c_parser_peek_token (parser)->pragma_kind; c_parser_consume_pragma (parser); + gcc_assert (parser->in_pragma); switch (p_kind) { case PRAGMA_OACC_ATOMIC: @@ -25122,6 +25607,12 @@ 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 = c_parser_omp_tile (loc, parser, if_p); + break; + case PRAGMA_OMP_UNROLL: + stmt = 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 54a5f208cb5..7de61ae9a2e 100644 --- a/gcc/c/c-typeck.cc +++ b/gcc/c/c-typeck.cc @@ -15920,6 +15920,14 @@ c_finish_omp_clauses (tree clauses, enum c_omp_region_type ort) pc = &OMP_CLAUSE_CHAIN (c); continue; + case OMP_CLAUSE_UNROLL_FULL: + pc = &OMP_CLAUSE_CHAIN (c); + continue; + + case OMP_CLAUSE_UNROLL_PARTIAL: + pc = &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 bdf6e5f98ff..7d6986be86f 100644 --- a/gcc/cp/cp-gimplify.cc +++ b/gcc/cp/cp-gimplify.cc @@ -647,6 +647,7 @@ cp_gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p) case OMP_DISTRIBUTE: case OMP_LOOP: case OMP_TASKLOOP: + case OMP_LOOP_TRANS: ret = cp_gimplify_omp_for (expr_p, pre_p); break; @@ -1188,6 +1189,7 @@ cp_fold_r (tree *stmt_p, int *walk_subtrees, void *data_) 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); @@ -1964,6 +1966,7 @@ cp_genericize_r (tree *stmt_p, int *walk_subtrees, void *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 defb81ca8c1..91b1a5a1464 100644 --- a/gcc/cp/parser.cc +++ b/gcc/cp/parser.cc @@ -2972,7 +2972,11 @@ static bool cp_parser_skip_up_to_closing_square_bracket static bool cp_parser_skip_to_closing_square_bracket (cp_parser *); static size_t cp_parser_skip_balanced_tokens (cp_parser *, size_t); +static bool cp_parser_see_omp_loop_nest (cp_parser *, enum tree_code, bool); static tree cp_parser_omp_loop_nest (cp_parser *, bool *); +static int cp_parser_omp_nested_loop_transform_clauses (cp_parser *, tree &, + int, int, + const char *); // -------------------------------------------------------------------------- // // Unevaluated Operand Guard @@ -13119,7 +13123,20 @@ check_omp_intervening_code (cp_parser *parser) "% % clause"); omp_for_parse_state->perfect_nesting_fail = true; } - /* TODO: Also reject loops with TILE directive. */ + else + { + tree c = omp_find_clause (omp_for_parse_state->clauses, + OMP_CLAUSE_TILE); + if (c && + ((int) tree_to_uhwi (OMP_CLAUSE_TRANSFORM_LEVEL (c)) + <= omp_for_parse_state->depth)) + { + error_at (omp_for_parse_state->for_loc, + "inner loops must be perfectly nested " + "with % directive"); + omp_for_parse_state->perfect_nesting_fail = true; + } + } if (omp_for_parse_state->perfect_nesting_fail) omp_for_parse_state->fail = true; } @@ -13171,7 +13188,9 @@ cp_parser_statement_seq_opt (cp_parser* parser, tree in_statement_expr) { bool want_nested_loop = omp_for_parse_state->want_nested_loop; if (want_nested_loop - && token->type == CPP_KEYWORD && token->keyword == RID_FOR) + && cp_parser_see_omp_loop_nest (parser, + omp_for_parse_state->code, + false)) { /* Found the nested loop. */ omp_for_parse_state->depth++; @@ -37494,6 +37513,8 @@ cp_parser_omp_clause_name (cp_parser *parser) result = PRAGMA_OMP_CLAUSE_FIRSTPRIVATE; else if (!strcmp ("from", p)) result = PRAGMA_OMP_CLAUSE_FROM; + else if (!strcmp ("full", p)) + result = PRAGMA_OMP_CLAUSE_FULL; break; case 'g': if (!strcmp ("gang", p)) @@ -37568,6 +37589,8 @@ cp_parser_omp_clause_name (cp_parser *parser) case 'p': if (!strcmp ("parallel", p)) result = PRAGMA_OMP_CLAUSE_PARALLEL; + if (!strcmp ("partial", p)) + result = PRAGMA_OMP_CLAUSE_PARTIAL; else if (!strcmp ("present", p)) result = PRAGMA_OACC_CLAUSE_PRESENT; else if (!strcmp ("present_or_copy", p) @@ -37658,12 +37681,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 = omp_find_clause (clauses, code); + if (found) error_at (location, "too many %qs clauses", name); + + return !found; } /* OpenMP 2.5: @@ -39782,6 +39808,58 @@ cp_parser_omp_clause_thread_limit (cp_parser *parser, 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", loc)) + return list; + + tree c = build_omp_clause (loc, OMP_CLAUSE_UNROLL_FULL); + OMP_CLAUSE_TRANSFORM_LEVEL (c) = build_int_cst (unsigned_type_node, 0); + OMP_CLAUSE_CHAIN (c) = 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, "partial", + loc)) + return list; + + tree c, num = error_mark_node; + c = build_omp_clause (loc, OMP_CLAUSE_UNROLL_PARTIAL); + OMP_CLAUSE_UNROLL_PARTIAL_EXPR (c) = NULL_TREE; + OMP_CLAUSE_TRANSFORM_LEVEL (c) = build_int_cst (unsigned_type_node, 0); + OMP_CLAUSE_CHAIN (c) = list; + + if (!cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN)) + return c; + + matching_parens parens; + parens.consume_open (parser); + num = cp_parser_constant_expression (parser); + cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true, + /*or_comma=*/false, + /*consume_paren=*/true); + + if (num == error_mark_node) + return list; + + mark_exp_read (num); + num = fold_non_dependent_expr (num); + + OMP_CLAUSE_UNROLL_PARTIAL_EXPR (c) = num; + return c; +} + /* OpenMP 4.0: aligned ( variable-list ) aligned ( variable-list : constant-expression ) */ @@ -41473,15 +41551,12 @@ cp_parser_omp_all_clauses (cp_parser *parser, omp_clause_mask mask, if (nested && cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_PAREN)) break; - if (!first || nested != 2) - { - if (cp_lexer_next_token_is (parser->lexer, CPP_COMMA)) - cp_lexer_consume_token (parser->lexer); - else if (nested == 2) - error_at (cp_lexer_peek_token (parser->lexer)->location, - "clauses in % trait should be separated " - "by %<,%>"); - } + if (cp_lexer_next_token_is (parser->lexer, CPP_COMMA)) + cp_lexer_consume_token (parser->lexer); + else if (!first && nested == 2) + error_at (cp_lexer_peek_token (parser->lexer)->location, + "clauses in % trait should be separated " + "by %<,%>"); token = cp_lexer_peek_token (parser->lexer); c_kind = cp_parser_omp_clause_name (parser); @@ -41822,6 +41897,16 @@ cp_parser_omp_all_clauses (cp_parser *parser, omp_clause_mask mask, clauses); c_name = "enter"; break; + case PRAGMA_OMP_CLAUSE_PARTIAL: + clauses = cp_parser_omp_clause_unroll_partial (parser, clauses, + token->location); + c_name = "partial"; + break; + case PRAGMA_OMP_CLAUSE_FULL: + clauses = cp_parser_omp_clause_unroll_full (clauses, + token->location); + c_name = "full"; + break; default: cp_parser_error (parser, "expected an OpenMP clause"); goto saw_error; @@ -43999,6 +44084,44 @@ cp_parser_omp_scan_loop_body (cp_parser *parser) } +/* Check that the next token starts a loop nest. Return true if yes, + otherwise diagnose an error if ERROR_P is true and return false. */ +static bool +cp_parser_see_omp_loop_nest (cp_parser *parser, enum tree_code code, + bool error_p) +{ + if (code == OACC_LOOP) + { + if (cp_lexer_next_token_is_keyword (parser->lexer, RID_FOR)) + return true; + if (error_p) + cp_parser_error (parser, "for statement expected"); + } + else + { + if (cp_lexer_next_token_is_keyword (parser->lexer, RID_FOR) + || (cp_parser_pragma_kind (cp_lexer_peek_token (parser->lexer)) + == PRAGMA_OMP_UNROLL) + || (cp_parser_pragma_kind (cp_lexer_peek_token (parser->lexer)) + == PRAGMA_OMP_TILE)) + return true; + /* The OpenMP spec isn't very clear on this. Here we consider that + any attribute specifier sequence followed by a FOR loop is a loop + nest, but cp_parser_omp_loop_nest rejects invalid attributes + with an error. If we rejected such things here, too, then the + associated FOR statement would be considered intervening code + instead, and we would get a different error about a loop in + intervening code. */ + size_t n = cp_parser_skip_std_attribute_spec_seq (parser, 1); + if (cp_lexer_nth_token_is_keyword (parser->lexer, n, RID_FOR)) + return true; + if (error_p) + cp_parser_error (parser, "loop nest expected"); + } + return false; +} + + /* This function parses a single level of a loop nest, invoking itself recursively if necessary. @@ -44051,8 +44174,69 @@ cp_parser_omp_loop_nest (cp_parser *parser, bool *if_p) gcc_assert (omp_for_parse_state); int depth = omp_for_parse_state->depth; - /* We have already matched the FOR token but not consumed it yet. */ - gcc_assert (cp_lexer_next_token_is_keyword (parser->lexer, RID_FOR)); + /* Handle loop transformations first. Note that when we get here + omp_for_parse_state->depth has already been incremented to indicate + the depth of the *next* loop, not the level of the loop body the + transformation directive appears in. */ + + /* Arrange for C++ standard attribute syntax to be parsed as regular + pragmas. Give an error if there are other random attributes present. */ + cp_token *token = cp_lexer_peek_token (parser->lexer); + tree std_attrs = cp_parser_std_attribute_spec_seq (parser); + std_attrs = cp_parser_handle_statement_omp_attributes (parser, std_attrs); + if (std_attrs) + error_at (token->location, + "attributes other than OpenMP directives " + "are not allowed on % in loop nest"); + + if ((cp_parser_pragma_kind (cp_lexer_peek_token (parser->lexer)) + == PRAGMA_OMP_UNROLL) + || (cp_parser_pragma_kind (cp_lexer_peek_token (parser->lexer)) + == PRAGMA_OMP_TILE)) + { + int count = omp_for_parse_state->count; + int more = cp_parser_omp_nested_loop_transform_clauses ( + parser, omp_for_parse_state->clauses, + depth, count - depth, "loop collapse"); + if (depth + more > count) + { + count = depth + more; + omp_for_parse_state->count = count; + omp_for_parse_state->declv + = grow_tree_vec (omp_for_parse_state->declv, count); + omp_for_parse_state->initv + = grow_tree_vec (omp_for_parse_state->initv, count); + omp_for_parse_state->condv + = grow_tree_vec (omp_for_parse_state->condv, count); + omp_for_parse_state->incrv + = grow_tree_vec (omp_for_parse_state->incrv, count); + if (omp_for_parse_state->orig_declv) + omp_for_parse_state->orig_declv + = grow_tree_vec (omp_for_parse_state->orig_declv, count); + } + } + + /* Diagnose errors if we don't have a "for" loop following the + optional loop transforms. Otherwise, consume the token. */ + if (!cp_lexer_next_token_is_keyword (parser->lexer, RID_FOR)) + { + omp_for_parse_state->fail = true; + cp_token *token = cp_lexer_peek_token (parser->lexer); + /* Don't call cp_parser_error here since it overrides the + provided message with a more confusing one if there was + a bad pragma or attribute directive. */ + error_at (token->location, "loop nest expected"); + /* See if we can recover by skipping over bad pragma(s). */ + while (token->type == CPP_PRAGMA) + { + cp_parser_skip_to_pragma_eol (parser, token); + if (cp_parser_see_omp_loop_nest (parser, omp_for_parse_state->code, + false)) + return cp_parser_omp_loop_nest (parser, if_p); + token = cp_lexer_peek_token (parser->lexer); + } + return NULL_TREE; + } loc = cp_lexer_consume_token (parser->lexer)->location; /* Forbid break/continue in the loop initializer, condition, and @@ -44307,7 +44491,9 @@ cp_parser_omp_loop_nest (cp_parser *parser, bool *if_p) moreloops = depth < omp_for_parse_state->count - 1; omp_for_parse_state->want_nested_loop = moreloops; - if (moreloops && cp_lexer_next_token_is_keyword (parser->lexer, RID_FOR)) + if (moreloops + && cp_parser_see_omp_loop_nest (parser, omp_for_parse_state->code, + false)) { omp_for_parse_state->depth++; add_stmt (cp_parser_omp_loop_nest (parser, if_p)); @@ -44582,6 +44768,10 @@ fixup_blocks_walker (tree *tp, int *walk_subtrees, void *dp) return NULL; } +static int cp_parser_omp_nested_loop_transform_clauses (cp_parser *, tree &, + int, int, + const char *); + /* Parse the restricted form of the for statement allowed by OpenMP. */ static tree @@ -44592,7 +44782,7 @@ cp_parser_omp_for_loop (cp_parser *parser, enum tree_code code, tree clauses, tree cl, ordered_cl = NULL_TREE; int collapse = 1, ordered = 0; unsigned int count; - bool tiling = false; + bool oacc_tiling = false; bool inscan = false; struct omp_for_parse_data data; struct omp_for_parse_data *save_data = parser->omp_for_parse_state; @@ -44604,7 +44794,7 @@ cp_parser_omp_for_loop (cp_parser *parser, enum tree_code code, tree clauses, collapse = tree_to_shwi (OMP_CLAUSE_COLLAPSE_EXPR (cl)); else if (OMP_CLAUSE_CODE (cl) == OMP_CLAUSE_OACC_TILE) { - tiling = true; + oacc_tiling = true; collapse = list_length (OMP_CLAUSE_OACC_TILE_LIST (cl)); } else if (OMP_CLAUSE_CODE (cl) == OMP_CLAUSE_ORDERED @@ -44627,14 +44817,28 @@ cp_parser_omp_for_loop (cp_parser *parser, enum tree_code code, tree clauses, ordered = collapse; } - gcc_assert (tiling || (collapse >= 1 && ordered >= 0)); + gcc_assert (oacc_tiling || (collapse >= 1 && ordered >= 0)); count = ordered ? ordered : collapse; - if (!cp_lexer_next_token_is_keyword (parser->lexer, RID_FOR)) + cp_parser_omp_nested_loop_transform_clauses (parser, clauses, 0, 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. */ + unsigned int omp_tile_depth = 0; + for (tree c = clauses; c; c = TREE_CHAIN (c)) { - cp_parser_error (parser, "for statement expected"); - return NULL; + if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_TILE) + continue; + + omp_tile_depth = list_length (OMP_CLAUSE_TILE_SIZES (c)); } + count = MAX (count, omp_tile_depth); + + if (!cp_parser_see_omp_loop_nest (parser, code, true)) + return NULL; /* Initialize parse state for recursive descent. */ data.declv = make_tree_vec (count); @@ -44687,6 +44891,7 @@ cp_parser_omp_for_loop (cp_parser *parser, enum tree_code code, tree clauses, We also need to flatten the init blocks, as some code for later processing of combined directives gets confused otherwise. */ + count = data.count; gcc_assert (vec_safe_length (data.init_blockv) == count); gcc_assert (vec_safe_length (data.body_blockv) == count); gcc_assert (vec_safe_length (data.init_placeholderv) == count); @@ -46479,6 +46684,272 @@ cp_parser_omp_target (cp_parser *parser, cp_token *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 = NULL_TREE; + cp_lexer *lexer = parser->lexer; + + if (cp_lexer_next_token_is (parser->lexer, CPP_COMMA)) + cp_lexer_consume_token (parser->lexer); + + cp_token *tok = cp_lexer_peek_token (lexer); + if (tok->type != 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 = cp_parser_constant_expression (parser); + if (expr == error_mark_node) + { + cp_parser_skip_to_closing_parenthesis (parser, + /*recovering=*/true, + /*or_comma=*/false, + /*consume_paren=*/ + true); + return error_mark_node; + } + + sizes = 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 = build_omp_clause (loc, OMP_CLAUSE_TILE); + OMP_CLAUSE_TRANSFORM_LEVEL (c) = build_int_cst (unsigned_type_node, 0); + OMP_CLAUSE_TILE_SIZES (c) = sizes; + OMP_CLAUSE_TRANSFORM_LEVEL (c) + = build_int_cst (unsigned_type_node, 0); + + 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 = error_mark_node; + + gcc_assert (!parser->omp_for_parse_state); + + tree clauses = cp_parser_omp_tile_sizes (parser, tok->location); + cp_parser_require_pragma_eol (parser, tok); + + if (!clauses || clauses == error_mark_node) + return error_mark_node; + + int required_depth = list_length (OMP_CLAUSE_TILE_SIZES (clauses)); + cp_parser_omp_nested_loop_transform_clauses (parser, clauses, 0, + required_depth, + "outer transformation"); + + block = begin_omp_structured_block (); + clauses = finish_omp_clauses (clauses, C_ORT_OMP); + + ret = cp_parser_omp_for_loop (parser, OMP_LOOP_TRANS, clauses, NULL, if_p); + block = 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 a single OpenMP loop transformation directive and return the + clause that is used internally to represent the directive. */ + +static tree +cp_parser_omp_loop_transform_clause (cp_parser *parser) +{ + cp_lexer *lexer = parser->lexer; + cp_token *tok = cp_lexer_peek_token (lexer); + if (tok->type != CPP_PRAGMA) + return NULL_TREE; + + tree c; + switch (cp_parser_pragma_kind (tok)) + { + case PRAGMA_OMP_UNROLL: + cp_lexer_consume_token (lexer); + lexer->in_pragma = true; + c = cp_parser_omp_all_clauses (parser, OMP_UNROLL_CLAUSE_MASK, + "#pragma omp unroll", tok, + false, true); + if (!c && cp_lexer_next_token_is (lexer, CPP_PRAGMA_EOL)) + { + c = build_omp_clause (tok->location, OMP_CLAUSE_UNROLL_NONE); + OMP_CLAUSE_TRANSFORM_LEVEL (c) + = build_int_cst (unsigned_type_node, 0); + } + else if (!c) + c = error_mark_node; + cp_parser_skip_to_pragma_eol (parser, tok); + break; + + case PRAGMA_OMP_TILE: + cp_lexer_consume_token (lexer); + lexer->in_pragma = true; + c = cp_parser_omp_tile_sizes (parser, tok->location); + cp_parser_require_pragma_eol (parser, tok); + break; + + default: + c = 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, + append all to CLAUSES, and require the level at which the clause + appears in the loop nest in each clause. 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 &clauses, + int level, int required_depth, + const char *outer_descr) +{ + tree c = NULL_TREE; + tree last_c = 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 = 0; + + /* The minimum nesting depth required by the last parsed transformation. */ + int last_depth = required_depth; + + while ((c = cp_parser_omp_loop_transform_clause (parser))) + { + /* The nesting depth left after the current transformation. */ + int depth = 1; + if (TREE_CODE (c) == 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 = 1; + break; + case OMP_CLAUSE_TILE: + depth = list_length (OMP_CLAUSE_TILE_SIZES (c)); + break; + default: + gcc_unreachable (); + } + OMP_CLAUSE_TRANSFORM_LEVEL (c) + = build_int_cst (unsigned_type_node, level); + + if (depth < last_depth) + { + bool is_outermost_clause = !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; + } + + last_depth = depth; + + if (!transformed_depth) + transformed_depth = last_depth; + + c = finish_omp_clauses (c, C_ORT_OMP); + + if (!clauses) + clauses = c; + else if (last_c) + TREE_CHAIN (last_c) = c; + + last_c = c; + } + + return transformed_depth; + +error: + while (cp_parser_omp_loop_transform_clause (parser)) + ; + clauses = NULL_TREE; + return -1; +} + +static tree +cp_parser_omp_unroll (cp_parser *parser, cp_token *tok, bool *if_p) +{ + tree block, ret; + static const char *p_name = "#pragma omp unroll"; + omp_clause_mask mask = OMP_UNROLL_CLAUSE_MASK; + + gcc_assert (!parser->omp_for_parse_state); + + tree clauses = cp_parser_omp_all_clauses (parser, mask, p_name, tok, true); + + if (!clauses) + { + tree c = build_omp_clause (tok->location, OMP_CLAUSE_UNROLL_NONE); + OMP_CLAUSE_TRANSFORM_LEVEL (c) = build_int_cst (unsigned_type_node, 0); + OMP_CLAUSE_CHAIN (c) = clauses; + clauses = c; + } + + int required_depth = 1; + cp_parser_omp_nested_loop_transform_clauses (parser, clauses, 0, + required_depth, + "outer transformation"); + + block = begin_omp_structured_block (); + ret = cp_parser_omp_for_loop (parser, OMP_LOOP_TRANS, clauses, NULL, if_p); + block = finish_omp_structured_block (block); + add_stmt (block); + + return ret; +} + /* OpenACC 2.0: # pragma acc cache (variable-list) new-line */ @@ -49675,6 +50146,12 @@ cp_parser_omp_construct (cp_parser *parser, cp_token *pragma_tok, bool *if_p) case PRAGMA_OMP_ASSUME: cp_parser_omp_assume (parser, pragma_tok, if_p); return; + case PRAGMA_OMP_TILE: + stmt = cp_parser_omp_tile (parser, pragma_tok, if_p); + break; + case PRAGMA_OMP_UNROLL: + stmt = cp_parser_omp_unroll (parser, pragma_tok, if_p); + break; default: gcc_unreachable (); } @@ -50321,6 +50798,14 @@ cp_parser_pragma (cp_parser *parser, enum pragma_context 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 != pragma_stmt && context != pragma_compound) + goto bad_stmt; + stmt = 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 != pragma_external) diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index d44d20767ca..6942a5c69a8 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -18142,6 +18142,16 @@ tsubst_omp_clauses (tree clauses, enum c_omp_region_type ort, OMP_CLAUSE_OPERAND (nc, 0) = tsubst_expr (OMP_CLAUSE_OPERAND (oc, 0), args, complain, in_decl); break; + case OMP_CLAUSE_UNROLL_PARTIAL: + OMP_CLAUSE_UNROLL_PARTIAL_EXPR (nc) + = tsubst_expr (OMP_CLAUSE_UNROLL_PARTIAL_EXPR (oc), args, complain, + in_decl); + break; + case OMP_CLAUSE_TILE: + OMP_CLAUSE_TILE_SIZES (nc) + = tsubst_expr (OMP_CLAUSE_TILE_SIZES (oc), args, complain, + in_decl); + break; case OMP_CLAUSE_REDUCTION: case OMP_CLAUSE_IN_REDUCTION: case OMP_CLAUSE_TASK_REDUCTION: @@ -18222,6 +18232,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 (); @@ -19494,6 +19506,7 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, 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 c934659c9f3..45d0ab8f8d8 100644 --- a/gcc/cp/semantics.cc +++ b/gcc/cp/semantics.cc @@ -6887,6 +6887,7 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type ort) bool mergeable_seen = false; bool implicit_moved = false; bool target_in_reduction_seen = false; + bool unroll_full_seen = false; bitmap_obstack_initialize (NULL); bitmap_initialize (&generic_head, &bitmap_default_obstack); @@ -8876,6 +8877,46 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type ort) } break; + case OMP_CLAUSE_TILE: + for (tree list = OMP_CLAUSE_TILE_SIZES (c); !remove && list; + list = TREE_CHAIN (list)) + { + t = TREE_VALUE (list); + + if (t == error_mark_node) + remove = 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 = true; + } + else + { + t = mark_rvalue_use (t); + if (!processing_template_decl) + { + t = maybe_constant_value (t); + int n; + if (!tree_fits_shwi_p (t) + || !INTEGRAL_TYPE_P (TREE_TYPE (t)) + || (n = tree_to_shwi (t)) <= 0 || (int)n != n) + { + error_at (OMP_CLAUSE_LOCATION (c), + "% argument needs positive " + "integral constant"); + remove = true; + } + t = fold_build_cleanup_point_expr (TREE_TYPE (t), t); + } + } + + /* Update list item. */ + TREE_VALUE (list) = t; + } + break; + case OMP_CLAUSE_ORDERED: ordered_seen = true; break; @@ -8930,6 +8971,60 @@ 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 = true; + } + unroll_full_seen = true; + break; + + case OMP_CLAUSE_UNROLL_PARTIAL: + { + tree t = OMP_CLAUSE_UNROLL_PARTIAL_EXPR (c); + + if (!t) + break; + + if (t == error_mark_node) + remove = 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 = true; + } + else + { + t = mark_rvalue_use (t); + if (!processing_template_decl) + { + t = maybe_constant_value (t); + + int n; + if (!INTEGRAL_TYPE_P (TREE_TYPE (t)) + || !tree_fits_shwi_p (t) + || (n = tree_to_shwi (t)) <= 0 || (int)n != n) + { + error_at (OMP_CLAUSE_LOCATION (c), + "partial argument needs positive constant " + "integer expression"); + remove = true; + } + t = fold_build_cleanup_point_expr (TREE_TYPE (t), t); + } + } + + OMP_CLAUSE_UNROLL_PARTIAL_EXPR (c) = t; + } + break; + + case OMP_CLAUSE_UNROLL_NONE: + break; + default: gcc_unreachable (); } diff --git a/gcc/testsuite/c-c++-common/gomp/imperfect-attributes.c b/gcc/testsuite/c-c++-common/gomp/imperfect-attributes.c index 776295ce22a..3c35e7c54b6 100644 --- a/gcc/testsuite/c-c++-common/gomp/imperfect-attributes.c +++ b/gcc/testsuite/c-c++-common/gomp/imperfect-attributes.c @@ -1,17 +1,20 @@ /* { dg-do compile { target { c || c++11 } } } */ /* Check that a nested FOR loop with standard c/c++ attributes on it - is treated as intervening code, since it doesn't match the grammar - for canonical loop nest form. */ + (not the C++ attribute syntax for OpenMP directives) + gives an error. */ extern void do_something (void); + +/* This one should be OK, an empty attribute list is ignored in both C + and C++. */ void imperfect1 (int x, int y) { #pragma omp for collapse (2) - for (int i = 0; i < x; i++) /* { dg-error "not enough nested loops" } */ + for (int i = 0; i < x; i++) { - [[]] for (int j = 0; j < y; j++) /* { dg-error "loop not permitted in intervening code" } */ + [[]] for (int j = 0; j < y; j++) do_something (); } } @@ -19,16 +22,15 @@ void imperfect1 (int x, int y) void perfect1 (int x, int y) { #pragma omp for ordered (2) - for (int i = 0; i < x; i++) /* { dg-error "not enough nested loops" } */ - /* { dg-error "inner loops must be perfectly nested" "" { target *-*-*} .-1 } */ + for (int i = 0; i < x; i++) { - [[]] for (int j = 0; j < y; j++) /* { dg-error "loop not permitted in intervening code" } */ + [[]] for (int j = 0; j < y; j++) do_something (); } } /* Similar, but put the attributes on a block wrapping the nested loop - instead. */ + instead. This is not allowed by the grammar. */ void imperfect2 (int x, int y) { diff --git a/gcc/testsuite/c-c++-common/gomp/loop-transforms/imperfect-loop-nest.c b/gcc/testsuite/c-c++-common/gomp/loop-transforms/imperfect-loop-nest.c new file mode 100644 index 00000000000..22a1250ed6c --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/loop-transforms/imperfect-loop-nest.c @@ -0,0 +1,11 @@ +void test () +{ +#pragma omp tile sizes (2,4,6) + for (unsigned i = 0; i < 10; i++) /* { dg-error "inner loops must be perfectly nested" } */ + for (unsigned j = 0; j < 10; j++) + { + float intervening_decl = 0; +#pragma omp unroll partial(2) + for (unsigned k = 0; k < 10; k++); + } +} 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..f10aea4c27f --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/loop-transforms/tile-1.c @@ -0,0 +1,160 @@ +extern void dummy (int); + +void +test () +{ + #pragma omp tile sizes(1) + for (int i = 0; i < 100; ++i) + dummy (i); + + #pragma omp tile sizes(0) /* { dg-error {'tile sizes' argument needs positive integral constant} } */ + for (int i = 0; i < 100; ++i) + dummy (i); + + #pragma omp tile sizes(-1) /* { dg-error {'tile sizes' argument needs positive integral constant} } */ + for (int i = 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 = 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 = 0; i < 100; ++i) + dummy (i); + + #pragma omp tile sizes(1,2 /* { dg-error {expected '\,' before end of line} } */ + for (int i = 0; i < 100; ++i) + dummy (i); + + #pragma omp tile sizes /* { dg-error {expected '\(' before end of line} } */ + for (int i = 0; i < 100; ++i) + dummy (i); + + #pragma omp tile sizes(1) sizes(1) /* { dg-error {expected end of line before 'sizes'} } */ + for (int i = 0; i < 100; ++i) + dummy (i); + + #pragma omp tile sizes(1) + #pragma omp tile sizes(1) + for (int i = 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 = 0; i < 100; ++i) + for (int j = 0; j < 100; ++j) + dummy (i); + + #pragma omp tile sizes(1, 2) + #pragma omp tile sizes(1, 2) + for (int i = 0; i < 100; ++i) + for (int j = 0; j < 100; ++j) + dummy (i); + + #pragma omp tile sizes(5, 6) + #pragma omp tile sizes(1, 2, 3) + for (int i = 0; i < 100; ++i) + for (int j = 0; j < 100; ++j) + for (int k = 0; k < 100; ++k) + dummy (i); + + #pragma omp tile sizes(1) + #pragma omp unroll partia /* { dg-error {expected an OpenMP clause before 'partia'} } */ + #pragma omp tile sizes(1) + for (int i = 0; i < 100; ++i) + dummy (i); + + #pragma omp tile sizes(1) + #pragma omp unroll /* { dg-error {'#pragma omp unroll' without 'partial' clause is invalid here; turns loop into non-loop} } */ + for (int i = 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 = 0; i < 100; ++i) + dummy (i); + + #pragma omp tile sizes(1) + #pragma omp unroll partial + #pragma omp tile sizes(1) + for (int i = 0; i < 100; ++i) + dummy (i); + + #pragma omp tile sizes(8,8) + #pragma omp unroll partial /* { dg-error {nesting depth left after this transformation too low for outer transformation} } */ + #pragma omp tile sizes(1) + for (int i = 0; i < 100; ++i) + dummy (i); + + #pragma omp tile sizes(8,8) + #pragma omp unroll partial /* { dg-error {nesting depth left after this transformation too low for outer transformation} } */ + for (int i = 0; i < 100; ++i) + dummy (i); + + #pragma omp tile sizes(1, 2) + for (int i = 0; i < 100; ++i) + for (int j = 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 = 0; i < 100; ++i) + for (int j = 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 = 0; i < 100; ++i) + for (int j = 2; j < i; ++j) + dummy (i); + + #pragma omp tile sizes(1, 2, 3) + for (int i = 0; i < 100; ++i) /* { dg-error {not enough nested loops} } */ + for (int j = 0; j < 100; ++j) + dummy (i); + + #pragma omp tile sizes(1) + for (int i = 0; i < 100; ++i) + { + dummy (i); + for (int j = 0; j < 100; ++j) + dummy (i); + } + + #pragma omp tile sizes(1) + for (int i = 0; i < 100; ++i) + { + for (int j = 0; j < 100; ++j) + dummy (j); + dummy (i); + } + + #pragma omp tile sizes(1, 2) + for (int i = 0; i < 100; ++i) /* { dg-error {inner loops must be perfectly nested} } */ + { + dummy (i); + for (int j = 0; j < 100; ++j) + dummy (j); + } + + #pragma omp tile sizes(1, 2) + for (int i = 0; i < 100; ++i) /* { dg-error {inner loops must be perfectly nested} } */ + { + for (int j = 0; j < 100; ++j) + dummy (j); + dummy (i); + } + + int s; + #pragma omp tile sizes(s) /* { dg-error {'tile sizes' argument needs positive 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 = 0; i < 100; ++i) + dummy (i); + + #pragma omp tile sizes(42.0) /* { dg-error {'tile sizes' argument needs positive integral constant} "" { target c } } */ + /* { dg-error {'tile sizes' argument needs integral type} "" { target c++ } .-1 } */ + for (int i = 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..45b9bb1a3ed --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/loop-transforms/tile-2.c @@ -0,0 +1,179 @@ +extern void dummy (int); + +void +test () +{ + #pragma omp parallel for + #pragma omp tile sizes(1) + for (int i = 0; i < 100; ++i) + dummy (i); + + #pragma omp parallel for + #pragma omp tile sizes(0) /* { dg-error {'tile sizes' argument needs positive integral constant} } */ + for (int i = 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 = 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 = 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 = 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 = 0; i < 100; ++i) + dummy (i); + + #pragma omp parallel for + #pragma omp tile sizes /* { dg-error {expected '\(' before end of line} } */ + for (int i = 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 = 0; i < 100; ++i) + dummy (i); + + #pragma omp parallel for + #pragma omp tile sizes(1) + #pragma omp tile sizes(1) + for (int i = 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 = 0; i < 100; ++i) + for (int j = 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 = 0; i < 100; ++i) + for (int j = 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 = 0; i < 100; ++i) + for (int j = 0; j < 100; ++j) + for (int k = 0; k < 100; ++k) + dummy (i); + + #pragma omp parallel for + #pragma omp tile sizes(1) + #pragma omp unroll partia /* { dg-error {expected an OpenMP clause before 'partia'} } */ + #pragma omp tile sizes(1) + for (int i = 0; i < 100; ++i) + dummy (i); + + #pragma omp parallel for + #pragma omp tile sizes(1) + #pragma omp unroll /* { dg-error {'#pragma omp unroll' without 'partial' clause is invalid here; turns loop into non-loop} } */ + for (int i = 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 = 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 = 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 this transformation too low for outer transformation} } */ + #pragma omp tile sizes(1) + for (int i = 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 this transformation too low for outer transformation} } */ + for (int i = 0; i < 100; ++i) + dummy (i); + + #pragma omp parallel for + #pragma omp tile sizes(1, 2) + for (int i = 0; i < 100; ++i) + for (int j = 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 = 0; i < 100; ++i) + for (int j = 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 = 0; i < 100; ++i) + for (int j = 2; j < i; ++j) + dummy (i); + + #pragma omp parallel for + #pragma omp tile sizes(1, 2, 3) + for (int i = 0; i < 100; ++i) /* { dg-error {not enough nested loops} } */ + for (int j = 0; j < 100; ++j) + dummy (i); + + #pragma omp parallel for + #pragma omp tile sizes(1) + for (int i = 0; i < 100; ++i) + { + dummy (i); + for (int j = 0; j < 100; ++j) + dummy (i); + } + + #pragma omp parallel for + #pragma omp tile sizes(1) + for (int i = 0; i < 100; ++i) + { + for (int j = 0; j < 100; ++j) + dummy (j); + dummy (i); + } + + #pragma omp parallel for + #pragma omp tile sizes(1, 2) + for (int i = 0; i < 100; ++i) /* { dg-error {inner loops must be perfectly nested} } */ + { + dummy (i); + for (int j = 0; j < 100; ++j) + dummy (j); + } + + #pragma omp parallel for + #pragma omp tile sizes(1, 2) + for (int i = 0; i < 100; ++i) /* { dg-error {inner loops must be perfectly nested} } */ + { + for (int j = 0; j < 100; ++j) + dummy (j); + dummy (i); + } + + #pragma omp parallel for + #pragma omp tile sizes(1) + for (int i = 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..e0ba1d6c444 --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/loop-transforms/tile-3.c @@ -0,0 +1,109 @@ +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 = 0; i < 100; ++i) + for (int j = 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 = 0; i < 100; ++i) + for (int j = 0; j < i; ++j) + dummy (i); + + +#pragma omp for collapse(1) + #pragma omp tile sizes(1) + for (int i = 0; i < 100; ++i) + for (int j = 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 = 0; i < 100; ++i) + for (int j = 0; j < 100; ++j) + dummy (i); + +#pragma omp for collapse(2) + #pragma omp tile sizes(1, 2) + for (int i = 0; i < 100; ++i) + for (int j = 0; j < 100; ++j) + 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} } */ + for (int i = 0; i < 100; ++i) /* { dg-error {not enough nested loops} } */ + for (int j = 0; j < 100; ++j) + dummy (i); + +#pragma omp for collapse(1) +#pragma omp tile sizes(1) +#pragma omp tile sizes(1) + for (int i = 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 transformation too low for outer transformation} } */ + for (int i = 0; i < 100; ++i) /* { dg-error {not enough nested loops} } */ + dummy (i); + +#pragma omp for collapse(2) +#pragma omp tile sizes(1, 2) +#pragma omp tile sizes(1, 2) + for (int i = 0; i < 100; ++i) /* { dg-error {not enough nested loops} } */ + dummy (i); + +#pragma omp for collapse(2) +#pragma omp tile sizes(5, 6) +#pragma omp tile sizes(1, 2, 3) + for (int i = 0; i < 100; ++i) /* { dg-error {not enough nested loops} } */ + dummy (i); + +#pragma omp for collapse(1) +#pragma omp tile sizes(1) +#pragma omp tile sizes(1) + for (int i = 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 transformation too low for outer transformation} } */ + for (int i = 0; i < 100; ++i) + for (int j = 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 = 0; i < 100; ++i) + for (int j = 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 = 0; i < 100; ++i) + for (int j = 0; j < 100; ++j) + for (int k = 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 = 0; i < 100; ++i) /* { dg-error {not enough nested loops} } */ + for (int j = 0; j < 100; ++j) + dummy (i); + +#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 = 0; i < 100; ++i) + for (int j = 0; j < 100; ++j) + for (int k = 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 != val) { fprintf (stderr, "%s:%d: Unexpected value %d, expected %d\n", __FILE__, __LINE__, var, val); \ + __builtin_abort (); } + +int +test1 () +{ + int iter = 0; + int i; +#pragma omp tile sizes(3) + for (i = 0; i < 10; i=i+2) + { + ASSERT_EQ (i, iter) + iter = iter + 2; + } + + ASSERT_EQ (i, 10) + return iter; +} + +int +test2 () +{ + int iter = 0; + int i; +#pragma omp tile sizes(3) + for (i = 0; i < 10; i=i+2) + { + ASSERT_EQ (i, iter) + iter = iter + 2; + } + + ASSERT_EQ (i, 10) + return iter; +} + +int +test3 () +{ + int iter = 0; + int i; +#pragma omp tile sizes(8) + for (i = 0; i < 10; i=i+2) + { + ASSERT_EQ (i, iter) + iter = iter + 2; + } + + ASSERT_EQ (i, 10) + return iter; +} + +int +test4 () +{ + int iter = 10; + int i; +#pragma omp tile sizes(8) + for (i = 10; i > 0; i=i-2) + { + ASSERT_EQ (i, iter) + iter = iter - 2; + } + ASSERT_EQ (i, 0) + return iter; +} + +int +test5 () +{ + int iter = 10; + int i; +#pragma omp tile sizes(71) + for (i = 10; i > 0; i=i-2) + { + ASSERT_EQ (i, iter) + iter = iter - 2; + } + + ASSERT_EQ (i, 0) + return iter; +} + +int +test6 () +{ + int iter = 10; + int i; +#pragma omp tile sizes(1) + for (i = 10; i > 0; i=i-2) + { + ASSERT_EQ (i, iter) + iter = iter - 2; + } + ASSERT_EQ (i, 0) + return iter; +} + +int +test7 () +{ + int iter = 5; + int i; +#pragma omp tile sizes(2) + for (i = 5; i < -5; i=i-3) + { + fprintf (stderr, "%d\n", i); + __builtin_abort (); + iter = iter - 3; + } + + ASSERT_EQ (i, 5) + + /* No iteration expected */ + return iter; +} + +int +test8 () +{ + int iter = 5; + int i; +#pragma omp tile sizes(2) + for (i = 5; i > -5; i=i-3) + { + ASSERT_EQ (i, iter) + /* Expect only first iteration of the last tile to execute */ + if (iter != -4) + iter = iter - 3; + } + + ASSERT_EQ (i, -7) + return iter; +} + + +int +test9 () +{ + int iter = 5; + int i; +#pragma omp tile sizes(5) + for (i = 5; i >= -5; i=i-4) + { + ASSERT_EQ (i, iter) + /* Expect only first iteration of the last tile to execute */ + if (iter != - 3) + iter = iter - 4; + } + + ASSERT_EQ (i, -7) + return iter; +} + +int +test10 () +{ + int iter = 5; + int i; +#pragma omp tile sizes(5) + for (i = 5; i >= -5; i--) + { + ASSERT_EQ (i, iter) + iter--; + } + + ASSERT_EQ (i, -6) + return iter; +} + +int +test11 () +{ + int iter = 5; + int i; +#pragma omp tile sizes(15) + for (i = 5; i != -5; i--) + { + ASSERT_EQ (i, iter) + iter--; + } + ASSERT_EQ (i, -5) + return iter; +} + +int +test12 () +{ + int iter = 0; + unsigned i; +#pragma omp tile sizes(3) + for (i = 0; i != 5; i++) + { + ASSERT_EQ (i, iter) + iter++; + } + + ASSERT_EQ (i, 5) + return iter; +} + +int +test13 () +{ + int iter = -5; + long long unsigned int i; +#pragma omp tile sizes(15) + for (int i = -5; i < 5; i=i+3) + { + ASSERT_EQ (i, iter) + iter++; + } + + ASSERT_EQ (i, 5) + return iter; +} + +int +test14 (unsigned init, int step) +{ + int iter = init; + long long unsigned int i; +#pragma omp tile sizes(8) + for (i = init; i < 2*init; i=i+step) + iter++; + + ASSERT_EQ (i, 2*init) + return iter; +} + +int +test15 (unsigned init, int step) +{ + int iter = init; + int i; +#pragma omp tile sizes(8) + for (unsigned i = init; i > 2* init; i=i+step) + iter++; + + return iter; +} + +int +main () +{ + int last_iter; + + last_iter = test1 (); + ASSERT_EQ (last_iter, 10); + + last_iter = test2 (); + ASSERT_EQ (last_iter, 10); + + last_iter = test3 (); + ASSERT_EQ (last_iter, 10); + + last_iter = test4 (); + ASSERT_EQ (last_iter, 0); + + last_iter = test5 (); + ASSERT_EQ (last_iter, 0); + + last_iter = test6 (); + ASSERT_EQ (last_iter, 0); + + last_iter = test7 (); + ASSERT_EQ (last_iter, 5); + + last_iter = test8 (); + ASSERT_EQ (last_iter, -4); + + last_iter = test9 (); + ASSERT_EQ (last_iter, -3); + + last_iter = test10 (); + ASSERT_EQ (last_iter, -6); + return 0; + + last_iter = test11 (); + ASSERT_EQ (last_iter, -4); + return 0; + + last_iter = test12 (); + ASSERT_EQ (last_iter, 5); + return 0; + + last_iter = test13 (); + ASSERT_EQ (last_iter, 4); + return 0; + + last_iter = test14 (0, 1); + ASSERT_EQ (last_iter, 0); + return 0; + + last_iter = test14 (0, -1); + ASSERT_EQ (last_iter, 0); + return 0; + + last_iter = test14 (8, 2); + ASSERT_EQ (last_iter, 16); + return 0; + + last_iter = test14 (5, 3); + ASSERT_EQ (last_iter, 9); + return 0; + + last_iter = test15 (8, -1); + ASSERT_EQ (last_iter, 9); + return 0; + + last_iter = test15 (8, -2); + ASSERT_EQ (last_iter, 10); + return 0; + + last_iter = 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 != val) { fprintf (stderr, "%s:%d: Unexpected value %d\n", __FILE__, __LINE__, var); \ + __builtin_abort (); } + +#define ASSERT_EQ_PTR(var, ptr) if (var != ptr) { fprintf (stderr, "%s:%d: Unexpected value %p\n", __FILE__, __LINE__, var); \ + __builtin_abort (); } + +int +test1 (int data[10]) +{ + int iter = 0; + int *i; + #pragma omp tile sizes(5) + for (i = 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 = 0; + int *i; + #pragma omp tile sizes(5) + for (i = data; i < data + 10 ; i=i+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 = 0; + int *i; + #pragma omp tile sizes(5) + for (i = data; i <= data + 9 ; i=i+2) + { + ASSERT_EQ (*i, data[2 * iter]); + iter++; + } + + ASSERT_EQ_PTR (i, data + 10) + return iter; +} + +int +test4 (int data[10]) +{ + int iter = 0; + int *i; + #pragma omp tile sizes(5) + for (i = data; i != data + 10 ; i=i+1) + { + ASSERT_EQ (*i, data[iter]); + iter++; + } + + ASSERT_EQ_PTR (i, data + 10) + return iter; +} + +int +test5 (int data[10]) +{ + int iter = 0; + int *i; + #pragma omp tile sizes(3) + for (i = data + 9; i >= data ; i--) + { + ASSERT_EQ (*i, data[9 - iter]); + iter++; + } + + ASSERT_EQ_PTR (i, data - 1) + return iter; +} + +int +test6 (int data[10]) +{ + int iter = 0; + int *i; + #pragma omp tile sizes(3) + for (i = 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 = 0; + #pragma omp tile sizes(1) + for (int *i = data + 9; i != data - 1 ; i--) + { + ASSERT_EQ (*i, data[9 - iter]); + iter++; + } + + return iter; +} + +int +main () +{ + int iter_count; + int data[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + + iter_count = test1 (data); + ASSERT_EQ (iter_count, 10); + + iter_count = test2 (data); + ASSERT_EQ (iter_count, 5); + + iter_count = test3 (data); + ASSERT_EQ (iter_count, 5); + + iter_count = test4 (data); + ASSERT_EQ (iter_count, 10); + + iter_count = test5 (data); + ASSERT_EQ (iter_count, 10); + + iter_count = test6 (data); + ASSERT_EQ (iter_count, 10); + + iter_count = 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 = 0; +for (int k = 0; k < 10; k++) + { +#pragma omp tile sizes(5,7) + for (int i = 0; i < 10; i++) + for (int j = 0; j < 10; j=j+2) + { + sum = sum + 1; + } + } + + return sum; +} + +int +main () +{ + int result = test1 (); + + if (result != 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 != val) { fprintf (stderr, "%s:%d: Unexpected value %d\n", __FILE__, __LINE__, var); \ + __builtin_abort (); } + +#define ASSERT_EQ_PTR(var, ptr) if (var != ptr) { fprintf (stderr, "%s:%d: Unexpected value %p\n", __FILE__, __LINE__, var); \ + __builtin_abort (); } + +int +main () +{ + int iter_count; + int data[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + + int iter = 0; + int *i; + #pragma omp tile sizes(1) + for (i = data; i < data + 10; i=i+2) + { + ASSERT_EQ_PTR (i, data + 2 * iter); + ASSERT_EQ (*i, data[2 * iter]); + iter++; + } + + unsigned long real_iter_count = ((unsigned long)i - (unsigned long)data) / (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 != val) { fprintf (stderr, "%s:%d: Unexpected value %d, expected %d\n", __FILE__, __LINE__, var, val); \ + __builtin_abort (); } + +int +main () +{ + int iter_j = 0, iter_k = 0; + unsigned i, j, k; +#pragma omp tile sizes(3,5,8) + for (i = 0; i < 2; i=i+2) + for (j = 0; j < 3; j=j+1) + for (k = 0; k < 5; k=k+3) + { + /* fprintf (stderr, "i=%d j=%d k=%d\n", i, j, k); + * fprintf (stderr, "iter_j=%d iter_k=%d\n", iter_j, iter_k); */ + ASSERT_EQ (i, 0); + if (k == 0) + { + ASSERT_EQ (j, iter_j); + iter_k = 0; + } + + ASSERT_EQ (k, iter_k); + + iter_k = iter_k + 3; + if (k == 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-1.c b/gcc/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 = 0; i < 100; ++i) + dummy (i); +} + +void +test2 () +{ +#pragma omp unroll partial(10) + for (int i = 0; i < 100; ++i) + dummy (i); +} + +void +test3 () +{ +#pragma omp unroll full + for (int i = 0; i < 100; ++i) + dummy (i); +} + +void +test4 () +{ +#pragma omp unroll full + for (int i = 0; i > 100; ++i) + dummy (i); +} + +void +test5 () +{ +#pragma omp unroll full + for (int i = 1; i <= 100; ++i) + dummy (i); +} + +void +test6 () +{ +#pragma omp unroll full + for (int i = 200; i >= 100; i--) + dummy (i); +} + +void +test7 () +{ +#pragma omp unroll full + for (int i = -100; i > 100; ++i) + dummy (i); +} + +void +test8 () +{ +#pragma omp unroll full + for (int i = 100; i > -200; --i) + dummy (i); +} + +void +test9 () +{ +#pragma omp unroll full + for (int i = -300; i != 100; ++i) + dummy (i); +} + +void +test10 () +{ +#pragma omp unroll full + for (int i = -300; i != 100; ++i) + dummy (i); +} + +void +test12 () +{ +#pragma omp unroll full +#pragma omp unroll partial +#pragma omp unroll partial + for (int i = -300; i != 100; ++i) + dummy (i); +} + +void +test13 () +{ + for (int i = 0; i < 100; ++i) +#pragma omp unroll full +#pragma omp unroll partial +#pragma omp unroll partial + for (int j = -300; j != 100; ++j) + dummy (i); +} + +void +test14 () +{ + #pragma omp for + for (int i = 0; i < 100; ++i) +#pragma omp unroll full +#pragma omp unroll partial +#pragma omp unroll partial + for (int j = -300; j != 100; ++j) + dummy (i); +} + +void +test15 () +{ + #pragma omp for + for (int i = 0; i < 100; ++i) + { + + dummy (i); + +#pragma omp unroll full +#pragma omp unroll partial +#pragma omp unroll partial + for (int j = -300; j != 100; ++j) + dummy (j); + + dummy (i); + } + } diff --git a/gcc/testsuite/c-c++-common/gomp/loop-transforms/unroll-2.c b/gcc/testsuite/c-c++-common/gomp/loop-transforms/unroll-2.c new file mode 100644 index 00000000000..cb37e7410c8 --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/loop-transforms/unroll-2.c @@ -0,0 +1,95 @@ +/* { dg-prune-output "error: invalid controlling predicate" } */ +/* { dg-additional-options "-std=c++11" { target c++} } */ + +extern void dummy (int); + +void +test () +{ +#pragma omp unroll partial +#pragma omp unroll full /* { dg-error {'full' clause is invalid here; turns loop into non-loop} } */ + for (int i = -300; i != 100; ++i) + dummy (i); + +#pragma omp for +#pragma omp unroll full /* { dg-error {'full' clause is invalid here; turns loop into non-loop} } */ +#pragma omp unroll partial + for (int i = -300; i != 100; ++i) + dummy (i); + +#pragma omp for +#pragma omp unroll full /* { dg-error {'full' clause is invalid here; turns loop into non-loop} } */ +#pragma omp unroll full + for (int i = -300; i != 100; ++i) + dummy (i); + +#pragma omp for +#pragma omp unroll partial partial /* { dg-error {too many 'partial' clauses} } */ + for (int i = -300; i != 100; ++i) + dummy (i); + +#pragma omp unroll full full /* { dg-error {too many 'full' clauses} } */ + for (int i = -300; i != 100; ++i) + dummy (i); + +#pragma omp unroll partial +#pragma omp unroll /* { dg-error {'#pragma omp unroll' without 'partial' clause is invalid here; turns loop into non-loop} } */ + for (int i = -300; i != 100; ++i) + dummy (i); + +#pragma omp for +#pragma omp unroll /* { dg-error {'#pragma omp unroll' without 'partial' clause is invalid here; turns loop into non-loop} } */ + for (int i = -300; i != 100; ++i) + dummy (i); + + int i; +#pragma omp for +#pragma omp unroll( /* { dg-error {expected an OpenMP clause before '\(' token} } */ + for (int i = -300; i != 100; ++i) + dummy (i); + +#pragma omp for +#pragma omp unroll foo /* { dg-error {expected an OpenMP clause before 'foo'} } */ + for (int i = -300; i != 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} "" { target c++ } .-1 } */ + for (int i = -300; i != 100; ++i) + dummy (i); + +#pragma omp unroll partial() /* { dg-error {expected expression before '\)' token} "" { target c } } */ + /* { dg-error {expected primary-expression before '\)' token} "" { target c++ } .-1 } */ + for (int i = -300; i != 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 expression} "" { target *-*-* } .-2 } */ + for (int i = -300; i != 100; ++i) + dummy (i); + +#pragma omp unroll parti /* { dg-error {expected an OpenMP clause before 'parti'} } */ + for (int i = -300; i != 100; ++i) + dummy (i); + +#pragma omp for +#pragma omp unroll partial(1) +#pragma omp unroll parti /* { dg-error {expected an OpenMP clause before 'parti'} } */ + for (int i = -300; i != 100; ++i) + dummy (i); + +#pragma omp for +#pragma omp unroll partial(1) +#pragma omp unroll parti /* { dg-error {expected an OpenMP clause before 'parti'} } */ + for (int i = -300; i != 100; ++i) + dummy (i); + +int sum = 0; +#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 = 3; i < 10; ++i) + for (int j = -2; j < 7; ++j) + sum++; +} + diff --git a/gcc/testsuite/c-c++-common/gomp/loop-transforms/unroll-3.c b/gcc/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 = 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/gcc/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 = 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/gcc/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 unrolling factor turned into 'partial\(5\)' clause} } */ + for (int i = 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/gcc/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=omp-unroll-default-factor=100" } + * { 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 'omp unroll' directive} } */ + for (int i = 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" "original" } } + * { 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/gcc/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 != val) { fprintf (stderr, "%s:%d: Unexpected value %d\n", __FILE__, __LINE__, var); \ + __builtin_abort (); } + +#define ASSERT_EQ_PTR(var, ptr) if (var != ptr) { fprintf (stderr, "%s:%d: Unexpected value %p\n", __FILE__, __LINE__, var); \ + __builtin_abort (); } + +int +test1 (int data[10]) +{ + int iter = 0; + int *i; + #pragma omp unroll partial(8) + for (i = 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 = 0; + int *i; + #pragma omp unroll partial(8) + for (i = data; i < data + 10 ; i=i+2) + { + ASSERT_EQ_PTR (i, data + 2 * iter); + ASSERT_EQ (*i, data[2 * iter]); + iter++; + } + + return iter; +} + +int +test3 (int data[10]) +{ + int iter = 0; + int *i; + #pragma omp unroll partial(8) + for (i = data; i <= data + 9 ; i=i+2) + { + ASSERT_EQ (*i, data[2 * iter]); + iter++; + } + + return iter; +} + +int +test4 (int data[10]) +{ + int iter = 0; + int *i; + #pragma omp unroll partial(8) + for (i = data; i != data + 10 ; i=i+1) + { + ASSERT_EQ (*i, data[iter]); + iter++; + } + + return iter; +} + +int +test5 (int data[10]) +{ + int iter = 0; + int *i; + #pragma omp unroll partial(7) + for (i = data + 9; i >= data ; i--) + { + ASSERT_EQ (*i, data[9 - iter]); + iter++; + } + + return iter; +} + +int +test6 (int data[10]) +{ + int iter = 0; + int *i; + #pragma omp unroll partial(7) + for (i = data + 9; i > data - 1 ; i--) + { + ASSERT_EQ (*i, data[9 - iter]); + iter++; + } + + return iter; +} + +int +test7 (int data[10]) +{ + int iter = 0; + #pragma omp unroll partial(7) + for (int *i = data + 9; i != data - 1 ; i--) + { + ASSERT_EQ (*i, data[9 - iter]); + iter++; + } + + return iter; +} + +int +main () +{ + int iter_count; + int data[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + + iter_count = test1 (data); + ASSERT_EQ (iter_count, 10); + + iter_count = test2 (data); + ASSERT_EQ (iter_count, 5); + + iter_count = test3 (data); + ASSERT_EQ (iter_count, 5); + + iter_count = test4 (data); + ASSERT_EQ (iter_count, 10); + + iter_count = test5 (data); + ASSERT_EQ (iter_count, 10); + + iter_count = test6 (data); + ASSERT_EQ (iter_count, 10); + + iter_count = test7 (data); + ASSERT_EQ (iter_count, 10); +} diff --git a/gcc/testsuite/c-c++-common/gomp/loop-transforms/unroll-8.c b/gcc/testsuite/c-c++-common/gomp/loop-transforms/unroll-8.c new file mode 100644 index 00000000000..d49d7c42c87 --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/loop-transforms/unroll-8.c @@ -0,0 +1,76 @@ +extern void dummy(int); + +void +test1 () +{ +#pragma omp unroll full /* { dg-warning "Cannot apply full unrolling to infinite loop" } */ + for (int i = 101; i > 100; i++) + dummy (i); +} + + +void +test2 () +{ +#pragma omp unroll full + for (int i = 101; i != 100; i++) + dummy (i); +} + +void +test3 () +{ +#pragma omp unroll full /* { dg-warning "Cannot apply full unrolling to infinite loop" } */ + for (int i = 0; i <= 0; i--) + dummy (i); +} + +void +test4 () +{ +#pragma omp unroll full /* { dg-warning "Cannot apply full unrolling to infinite loop" } */ + for (int i = 101; i > 100; i=i+2) + dummy (i); +} + +void +test5 () +{ +#pragma omp unroll full /* { dg-warning "Cannot apply full unrolling to infinite loop" } */ + for (int i = -101; i < 100; i=i-10) + dummy (i); +} + +void +test6 () +{ +#pragma omp unroll full /* { dg-warning "Cannot apply full unrolling to infinite loop" } */ + for (int i = -101; i < 100; i=i-300) + dummy (i); +} + +void +test7 () +{ +#pragma omp unroll full /* { dg-warning "Cannot apply full unrolling to infinite loop" } */ + for (int i = 101; i > -100; i=i+300) + dummy (i); + + /* Loop does not iterate, hence no warning. */ +#pragma omp unroll full + for (int i = 101; i > 101; i=i+300) + dummy (i); +} + +void +test8 () +{ +#pragma omp unroll full /* { dg-warning "Cannot apply full unrolling to infinite loop" } */ + for (int i = -21; i < -20; i=i-40) + dummy (i); + + /* Loop does not iterate, hence no warning. */ +#pragma omp unroll full + for (int i = -21; i > 20; i=i-40) + dummy (i); +} diff --git a/gcc/testsuite/c-c++-common/gomp/loop-transforms/unroll-inner-1.c b/gcc/testsuite/c-c++-common/gomp/loop-transforms/unroll-inner-1.c new file mode 100644 index 00000000000..c365d942591 --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/loop-transforms/unroll-inner-1.c @@ -0,0 +1,15 @@ +/* { dg-additional-options "-std=c++11" { target c++} } */ + +extern void dummy (int); + +void +test () +{ + +#pragma omp target parallel for collapse(2) + for (int i = -300; i != 100; ++i) + #pragma omp unroll partial + for (int j = 0; j != 100; ++j) + dummy (i); +} + diff --git a/gcc/testsuite/c-c++-common/gomp/loop-transforms/unroll-inner-2.c b/gcc/testsuite/c-c++-common/gomp/loop-transforms/unroll-inner-2.c new file mode 100644 index 00000000000..2082009a385 --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/loop-transforms/unroll-inner-2.c @@ -0,0 +1,29 @@ +/* { dg-additional-options "-std=c++11" { target c++} } */ + +extern void dummy (int); + +void +test () +{ + +#pragma omp target parallel for collapse(2) + for (int i = -300; i != 100; ++i) +#pragma omp tile sizes(2) + for (int j = 0; j != 100; ++j) + dummy (i); + +#pragma omp target parallel for collapse(2) + for (int i = -300; i != 100; ++i) /* { dg-error {not enough nested loops} } */ +#pragma omp tile sizes(2, 3) + for (int j = 0; j != 100; ++j) + dummy (i); + +#pragma omp target parallel for collapse(2) + for (int i = -300; i != 100; ++i) +#pragma omp tile sizes(2, 3) + for (int j = 0; j != 100; ++j) + for (int k = 0; k != 100; ++k) + dummy (i); +} + + diff --git a/gcc/testsuite/c-c++-common/gomp/loop-transforms/unroll-non-rect-1.c b/gcc/testsuite/c-c++-common/gomp/loop-transforms/unroll-non-rect-1.c new file mode 100644 index 00000000000..40e7f8e4bfb --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/loop-transforms/unroll-non-rect-1.c @@ -0,0 +1,37 @@ +extern void dummy (int); + +void +test1 () +{ +#pragma omp target parallel for collapse(2) + for (int i = -300; i != 100; ++i) +#pragma omp unroll partial(2) + for (int j = i * 2; j <= i * 4 + 1; ++j) + dummy (i); + +#pragma omp target parallel for collapse(3) + for (int i = -300; i != 100; ++i) + for (int j = i; j != i * 2; ++j) + #pragma omp unroll partial + for (int k = 2; k != 100; ++k) + dummy (i); + +#pragma omp unroll full + for (int i = -300; i != 100; ++i) + for (int j = i; j != i * 2; ++j) + for (int k = 2; k != 100; ++k) + dummy (i); + + for (int i = -300; i != 100; ++i) +#pragma omp unroll full + for (int j = i; j != i + 10; ++j) + for (int k = 2; k != 100; ++k) + dummy (i); + + for (int i = -300; i != 100; ++i) +#pragma omp unroll full + for (int j = i; j != i + 10; ++j) + for (int k = j; k != 100; ++k) + dummy (i); +} + diff --git a/gcc/testsuite/c-c++-common/gomp/loop-transforms/unroll-non-rect-2.c b/gcc/testsuite/c-c++-common/gomp/loop-transforms/unroll-non-rect-2.c new file mode 100644 index 00000000000..7696e5d5fab --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/loop-transforms/unroll-non-rect-2.c @@ -0,0 +1,22 @@ +extern void dummy (int); + +void +test1 () +{ +#pragma omp target parallel for collapse(2) /* { dg-error {invalid OpenMP non-rectangular loop step; \'\(1 - 0\) \* 1\' is not a multiple of loop 2 step \'5\'} "" { target c } } */ + for (int i = -300; i != 100; ++i) /* { dg-error {invalid OpenMP non-rectangular loop step; \'\(1 - 0\) \* 1\' is not a multiple of loop 2 step \'5\'} "" { target c++ } } */ +#pragma omp unroll partial + for (int j = 2; j != i; ++j) + dummy (i); +} + +void +test2 () +{ + int i,j; +#pragma omp target parallel for collapse(2) + for (i = -300; i != 100; ++i) + #pragma omp unroll partial + for (j = 2; j != i; ++j) + dummy (i); +} 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 = 0; + int i,j; + +#pragma omp simd reduction(+:sum) + for (i = 3; i < 10; ++i) + #pragma omp unroll full + for (j = -2; j < 7; ++j) + sum++; + + if (j != 7) + __builtin_abort; + + return sum; +} + +int compute_sum2() +{ + int sum = 0; + int i,j; +#pragma omp simd reduction(+:sum) +#pragma omp unroll partial(5) + for (i = 3; i < 10; ++i) + for (j = -2; j < 7; ++j) + sum++; + + if (j != 7) + __builtin_abort; + + return sum; +} + +int compute_sum3() +{ + int sum = 0; + int i,j; +#pragma omp simd reduction(+:sum) +#pragma omp unroll partial(1) + for (i = 3; i < 10; ++i) + for (j = -2; j < 7; ++j) + sum++; + + if (j != 7) + __builtin_abort; + + return sum; +} + +int main () +{ + int result = compute_sum1 (); + if (result != 7 * 9) + { + fprintf (stderr, "%d: Wrong result %d\n", __LINE__, result); + __builtin_abort (); + } + + result = compute_sum1 (); + if (result != 7 * 9) + { + fprintf (stderr, "%d: Wrong result %d\n", __LINE__, result); + __builtin_abort (); + } + + result = compute_sum3 (); + if (result != 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_loops" } } */ diff --git a/gcc/testsuite/g++.dg/gomp/attrs-4.C b/gcc/testsuite/g++.dg/gomp/attrs-4.C index 005add826ba..a730ad7db50 100644 --- a/gcc/testsuite/g++.dg/gomp/attrs-4.C +++ b/gcc/testsuite/g++.dg/gomp/attrs-4.C @@ -49,7 +49,7 @@ foo (int x) for (int i = 0; i < 16; i++) ; #pragma omp for - [[omp::directive (master)]] // { dg-error "for statement expected before '\\\[' token" } + [[omp::directive (master)]] // { dg-error "loop nest expected before '\\\[' token" } ; #pragma omp target teams [[omp::directive (parallel)]] // { dg-error "mixing OpenMP directives with attribute and pragma syntax on the same statement" } diff --git a/gcc/testsuite/g++.dg/gomp/for-1.C b/gcc/testsuite/g++.dg/gomp/for-1.C index f8bb9d54727..0e042fd1381 100644 --- a/gcc/testsuite/g++.dg/gomp/for-1.C +++ b/gcc/testsuite/g++.dg/gomp/for-1.C @@ -24,7 +24,7 @@ void foo (int j, int k) // Malformed parallel loops. #pragma omp for - i = 0; // { dg-error "for statement expected" } + i = 0; // { dg-error "loop nest expected" } for ( ; i < 10; ) { baz (i); diff --git a/gcc/testsuite/g++.dg/gomp/loop-transforms/attrs-tile-1.C b/gcc/testsuite/g++.dg/gomp/loop-transforms/attrs-tile-1.C new file mode 100644 index 00000000000..0906ff3bbe8 --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/loop-transforms/attrs-tile-1.C @@ -0,0 +1,164 @@ +// { dg-do compile { target c++11 } } + +extern void dummy (int); + +void +test () +{ + [[omp::directive (tile sizes(1))]] + for (int i = 0; i < 100; ++i) + dummy (i); + + [[omp::directive (tile sizes(0))]] /* { dg-error {'tile sizes' argument needs positive integral constant} } */ + for (int i = 0; i < 100; ++i) + dummy (i); + + [[omp::directive (tile sizes(-1))]] /* { dg-error {'tile sizes' argument needs positive integral constant} } */ + for (int i = 0; i < 100; ++i) + dummy (i); + + [[omp::directive (tile sizes())]] /* { dg-error {expected primary-expression before} } */ + for (int i = 0; i < 100; ++i) + dummy (i); + + [[omp::directive (tile sizes)]] /* { dg-error {expected '\(' before end of line} } */ + for (int i = 0; i < 100; ++i) + dummy (i); + + [[omp::directive (tile sizes(1) sizes(1))]] /* { dg-error {expected end of line before 'sizes'} } */ + for (int i = 0; i < 100; ++i) + dummy (i); + + [[omp::directive (tile, sizes(1), sizes(1))]] /* { dg-error {expected end of line before ','} } */ + for (int i = 0; i < 100; ++i) + dummy (i); + + [[omp::sequence + (directive (tile sizes(1)), + directive (tile sizes(1)))]] + for (int i = 0; i < 100; ++i) + dummy (i); + + [[omp::sequence + (directive (tile sizes(1, 2)), + directive (tile sizes(1)))]] /* { dg-error {nesting depth left after this transformation too low for outer transformation} } */ + for (int i = 0; i < 100; ++i) + for (int j = 0; j < 100; ++j) + dummy (i); + + [[omp::sequence + (directive (tile sizes(1, 2)), + directive (tile sizes(1, 2)))]] + for (int i = 0; i < 100; ++i) + for (int j = 0; j < 100; ++j) + dummy (i); + + [[omp::sequence + (directive (tile sizes(5, 6)), + directive (tile sizes(1, 2, 3)))]] + for (int i = 0; i < 100; ++i) + for (int j = 0; j < 100; ++j) + for (int k = 0; k < 100; ++k) + dummy (i); + + [[omp::sequence + (directive (tile sizes(1)), + directive (unroll partia), /* { dg-error {expected an OpenMP clause before 'partia'} } */ + directive (tile sizes(1)))]] + for (int i = 0; i < 100; ++i) + dummy (i); + + [[omp::sequence + (directive (tile sizes(1)), + directive (unroll))]] /* { dg-error {'#pragma omp unroll' without 'partial' clause is invalid here; turns loop into non-loop} } */ + for (int i = 0; i < 100; ++i) + dummy (i); + + [[omp::sequence + (directive (tile sizes(1)), + directive (unroll full))]] /* { dg-error {'full' clause is invalid here; turns loop into non-loop} } */ + for (int i = 0; i < 100; ++i) + dummy (i); + + [[omp::sequence + (directive (tile sizes(1)), + directive (unroll partial), + directive (tile sizes(1)))]] + for (int i = 0; i < 100; ++i) + dummy (i); + + [[omp::sequence + (directive (tile sizes(8,8)), + directive (unroll partial), /* { dg-error {nesting depth left after this transformation too low for outer transformation} } */ + directive (tile sizes(1)))]] + for (int i = 0; i < 100; ++i) + dummy (i); + + [[omp::sequence + (directive (tile sizes(8,8)), + directive (unroll partial))]] /* { dg-error {nesting depth left after this transformation too low for outer transformation} } */ + for (int i = 0; i < 100; ++i) + dummy (i); + + [[omp::directive (tile sizes(1, 2))]] + for (int i = 0; i < 100; ++i) + for (int j = 0; j < 100; ++j) + dummy (i); + + [[omp::directive (tile sizes(1, 2))]] /* { dg-error {'tile' loop transformation may not appear on non-rectangular for} } */ + for (int i = 0; i < 100; ++i) + for (int j = i; j < 100; ++j) + dummy (i); + + [[omp::directive (tile sizes(1, 2))]] /* { dg-error {'tile' loop transformation may not appear on non-rectangular for} } */ + for (int i = 0; i < 100; ++i) + for (int j = 2; j < i; ++j) + dummy (i); + + [[omp::directive (tile sizes(1, 2, 3))]] + for (int i = 0; i < 100; ++i) /* { dg-error {not enough nested loops} } */ + for (int j = 0; j < 100; ++j) + dummy (i); + + [[omp::directive (tile sizes(1))]] + for (int i = 0; i < 100; ++i) + { + dummy (i); + for (int j = 0; j < 100; ++j) + dummy (i); + } + + [[omp::directive (tile sizes(1))]] + for (int i = 0; i < 100; ++i) + { + for (int j = 0; j < 100; ++j) + dummy (j); + dummy (i); + } + + [[omp::directive (tile sizes(1, 2))]] + for (int i = 0; i < 100; ++i) /* { dg-error {inner loops must be perfectly nested} } */ + { + dummy (i); + for (int j = 0; j < 100; ++j) + dummy (j); + } + + [[omp::directive (tile sizes(1, 2))]] + for (int i = 0; i < 100; ++i) /* { dg-error {inner loops must be perfectly nested} } */ + { + for (int j = 0; j < 100; ++j) + dummy (j); + dummy (i); + } + + int s; + [[omp::directive (tile sizes(s))]] /* { dg-error {'tile sizes' argument needs positive 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 } */ + for (int i = 0; i < 100; ++i) + dummy (i); + + [[omp::directive (tile sizes(42.0))]] /* { dg-error {'tile sizes' argument needs integral type} } */ + for (int i = 0; i < 100; ++i) + dummy (i); +} diff --git a/gcc/testsuite/g++.dg/gomp/loop-transforms/attrs-tile-2.C b/gcc/testsuite/g++.dg/gomp/loop-transforms/attrs-tile-2.C new file mode 100644 index 00000000000..ab02924defa --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/loop-transforms/attrs-tile-2.C @@ -0,0 +1,174 @@ +// { dg-do compile { target c++11 } } + +extern void dummy (int); + +void +test () +{ + [[omp::sequence (directive (parallel for), + directive (tile sizes(1)))]] + for (int i = 0; i < 100; ++i) + dummy (i); + + [[omp::sequence (directive (parallel for), + directive (tile sizes(0)))]] /* { dg-error {'tile sizes' argument needs positive integral constant} } */ + for (int i = 0; i < 100; ++i) + dummy (i); + + [[omp::sequence (directive (parallel for), + directive (tile sizes(-1)))]] /* { dg-error {'tile sizes' argument needs positive integral constant} } */ + for (int i = 0; i < 100; ++i) + dummy (i); + + [[omp::sequence (directive (parallel for), + directive (tile sizes()))]] /* { dg-error {expected primary-expression before} } */ + for (int i = 0; i < 100; ++i) + dummy (i); + + [[omp::sequence (directive (parallel for), + directive (tile sizes(,)))]] /* { dg-error {expected primary-expression before} } */ + for (int i = 0; i < 100; ++i) + dummy (i); + + [[omp::sequence (directive (parallel for), + directive (tile sizes))]] /* { dg-error {expected '\(' before end of line} } */ + for (int i = 0; i < 100; ++i) + dummy (i); + + [[omp::sequence (directive (parallel for), + directive (tile sizes(1) sizes(1)))]] /* { dg-error {expected end of line before 'sizes'} } */ + for (int i = 0; i < 100; ++i) + dummy (i); + + [[omp::sequence (directive (parallel for), + directive (tile sizes(1)), + directive (tile sizes(1)))]] + for (int i = 0; i < 100; ++i) + dummy (i); + + [[omp::sequence (directive (parallel for), + directive (tile sizes(1, 2)), + directive (tile sizes(1)))]] /* { dg-error {nesting depth left after this transformation too low for outer transformation} } */ + for (int i = 0; i < 100; ++i) + for (int j = 0; j < 100; ++j) + dummy (i); + + [[omp::sequence (directive (parallel for), + directive (tile sizes(1, 2)), + directive (tile sizes(1, 2)))]] + for (int i = 0; i < 100; ++i) + for (int j = 0; j < 100; ++j) + dummy (i); + + [[omp::sequence (directive (parallel for), + directive (tile sizes(5, 6)), + directive (tile sizes(1, 2, 3)))]] + for (int i = 0; i < 100; ++i) + for (int j = 0; j < 100; ++j) + for (int k = 0; k < 100; ++k) + dummy (i); + + [[omp::sequence (directive (parallel for), + directive (tile sizes(1)), + directive (unroll partia), /* { dg-error {expected an OpenMP clause before 'partia'} } */ + directive (tile sizes(1)))]] + for (int i = 0; i < 100; ++i) + dummy (i); + + [[omp::sequence (directive (parallel for), + directive (tile sizes(1)), + directive (unroll))]] /* { dg-error {'#pragma omp unroll' without 'partial' clause is invalid here; turns loop into non-loop} } */ + for (int i = 0; i < 100; ++i) + dummy (i); + + [[omp::sequence (directive (parallel for), + directive (tile sizes(1)), + directive (unroll full))]] /* { dg-error {'full' clause is invalid here; turns loop into non-loop} } */ + for (int i = 0; i < 100; ++i) + dummy (i); + + [[omp::sequence (directive (parallel for), + directive (tile sizes(1)), + directive (unroll partial), + directive (tile sizes(1)))]] + for (int i = 0; i < 100; ++i) + dummy (i); + + [[omp::sequence (directive (parallel for), + directive (tile sizes(8,8)), + directive (unroll partial), /* { dg-error {nesting depth left after this transformation too low for outer transformation} } */ + directive (tile sizes(1)))]] + for (int i = 0; i < 100; ++i) + dummy (i); + + [[omp::sequence (directive (parallel for), + directive (tile sizes(8,8)), + directive (unroll partial))]] /* { dg-error {nesting depth left after this transformation too low for outer transformation} } */ + for (int i = 0; i < 100; ++i) + dummy (i); + + [[omp::sequence (directive (parallel for), + directive (tile sizes(1, 2)))]] + for (int i = 0; i < 100; ++i) + for (int j = 0; j < 100; ++j) + dummy (i); + + [[omp::sequence (directive (parallel for), + directive (tile sizes(1, 2)))]] /* { dg-error {'tile' loop transformation may not appear on non-rectangular for} } */ + for (int i = 0; i < 100; ++i) + for (int j = i; j < 100; ++j) + dummy (i); + + [[omp::sequence (directive (parallel for), + directive (tile sizes(1, 2)))]] /* { dg-error {'tile' loop transformation may not appear on non-rectangular for} } */ + for (int i = 0; i < 100; ++i) + for (int j = 2; j < i; ++j) + dummy (i); + + [[omp::sequence (directive (parallel for), + directive (tile sizes(1, 2, 3)))]] + for (int i = 0; i < 100; ++i) /* { dg-error {not enough nested loops} } */ + for (int j = 0; j < 100; ++j) + dummy (i); + + [[omp::sequence (directive (parallel for), + directive (tile sizes(1)))]] + for (int i = 0; i < 100; ++i) + { + dummy (i); + for (int j = 0; j < 100; ++j) + dummy (i); + } + + [[omp::sequence (directive (parallel for), + directive (tile sizes(1)))]] + for (int i = 0; i < 100; ++i) + { + for (int j = 0; j < 100; ++j) + dummy (j); + dummy (i); + } + + [[omp::sequence (directive (parallel for), + directive (tile sizes(1, 2)))]] + for (int i = 0; i < 100; ++i) /* { dg-error {inner loops must be perfectly nested} } */ + { + dummy (i); + for (int j = 0; j < 100; ++j) + dummy (j); + } + + [[omp::sequence (directive (parallel for), + directive (tile sizes(1, 2)))]] + for (int i = 0; i < 100; ++i) /* { dg-error {inner loops must be perfectly nested} } */ + { + for (int j = 0; j < 100; ++j) + dummy (j); + dummy (i); + } + + [[omp::sequence (directive (parallel for), + directive (tile sizes(1)))]] + for (int i = 0; i < 100; ++i) + dummy (i); +} diff --git a/gcc/testsuite/g++.dg/gomp/loop-transforms/attrs-tile-3.C b/gcc/testsuite/g++.dg/gomp/loop-transforms/attrs-tile-3.C new file mode 100644 index 00000000000..95a0115b014 --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/loop-transforms/attrs-tile-3.C @@ -0,0 +1,111 @@ +// { dg-do compile { target c++11 } } + +extern void dummy (int); + +void +test () +{ + [[omp::sequence (directive (for), + directive (tile sizes(1, 2)))]] /* { dg-error {'tile' loop transformation may not appear on non-rectangular for} } */ + for (int i = 0; i < 100; ++i) + for (int j = i; j < 100; ++j) + dummy (i); + + [[omp::sequence (directive (for), + directive (tile sizes(1, 2)))]] /* { dg-error {'tile' loop transformation may not appear on non-rectangular for} } */ + for (int i = 0; i < 100; ++i) + for (int j = 0; j < i; ++j) + dummy (i); + + + [[omp::sequence (directive (for collapse(1)), + directive (tile sizes(1)))]] + for (int i = 0; i < 100; ++i) + for (int j = 0; j < 100; ++j) + dummy (i); + + [[omp::sequence (directive (for collapse(2)), + directive (tile sizes(1)))]] /* { dg-error {nesting depth left after this transformation too low for loop collapse} } */ + for (int i = 0; i < 100; ++i) + for (int j = 0; j < 100; ++j) + dummy (i); + + [[omp::sequence (directive (for collapse(2)), + directive (tile sizes(1, 2)))]] + for (int i = 0; i < 100; ++i) + for (int j = 0; j < 100; ++j) + dummy (i); + + [[omp::sequence (directive (for collapse(3)), + directive (tile sizes(1, 2)))]] /* { dg-error {nesting depth left after this transformation too low for loop collapse} } */ + for (int i = 0; i < 100; ++i) /* { dg-error {not enough nested loops} } */ + for (int j = 0; j < 100; ++j) + dummy (i); + + [[omp::sequence (directive (for collapse(1)), + directive (tile sizes(1)), + directive (tile sizes(1)))]] + for (int i = 0; i < 100; ++i) + dummy (i); + + [[omp::sequence (directive (for collapse(2)), + directive (tile sizes(1, 2)), + directive (tile sizes(1)))]] /* { dg-error {nesting depth left after this transformation too low for outer transformation} } */ + for (int i = 0; i < 100; ++i) /* { dg-error {not enough nested loops} } */ + dummy (i); + + [[omp::sequence (directive (for collapse(2)), + directive (tile sizes(1, 2)), + directive (tile sizes(1, 2)))]] + for (int i = 0; i < 100; ++i) /* { dg-error {not enough nested loops} } */ + dummy (i); + + [[omp::sequence (directive (for collapse(2)), + directive (tile sizes(5, 6)), + directive (tile sizes(1, 2, 3)))]] + for (int i = 0; i < 100; ++i) /* { dg-error {not enough nested loops} } */ + dummy (i); + + [[omp::sequence (directive (for collapse(1)), + directive (tile sizes(1)), + directive (tile sizes(1)))]] + for (int i = 0; i < 100; ++i) + dummy (i); + + [[omp::sequence (directive (for collapse(2)), + directive (tile sizes(1, 2)), + directive (tile sizes(1)))]] /* { dg-error {nesting depth left after this transformation too low for outer transformation} } */ + for (int i = 0; i < 100; ++i) + for (int j = 0; j < 100; ++j) + dummy (i); + + [[omp::sequence (directive (for collapse(2)), + directive (tile sizes(1, 2)), + directive (tile sizes(1, 2)))]] + for (int i = 0; i < 100; ++i) + for (int j = 0; j < 100; ++j) + dummy (i); + + [[omp::sequence (directive (for collapse(2)), + directive (tile sizes(5, 6)), + directive (tile sizes(1, 2, 3)))]] + for (int i = 0; i < 100; ++i) + for (int j = 0; j < 100; ++j) + for (int k = 0; k < 100; ++k) + dummy (i); + + [[omp::sequence (directive (for collapse(3)), + directive (tile sizes(1, 2)), /* { dg-error {nesting depth left after this transformation too low for loop collapse} } */ + directive (tile sizes(1, 2)))]] + for (int i = 0; i < 100; ++i) /* { dg-error {not enough nested loops} } */ + for (int j = 0; j < 100; ++j) + dummy (i); + + [[omp::sequence (directive (for collapse(3)), + directive (tile sizes(5, 6)), /* { dg-error {nesting depth left after this transformation too low for loop collapse} } */ + directive (tile sizes(1, 2, 3)))]] + for (int i = 0; i < 100; ++i) + for (int j = 0; j < 100; ++j) + for (int k = 0; k < 100; ++k) + dummy (i); +} diff --git a/gcc/testsuite/g++.dg/gomp/loop-transforms/attrs-unroll-1.C b/gcc/testsuite/g++.dg/gomp/loop-transforms/attrs-unroll-1.C new file mode 100644 index 00000000000..5b93b9fa59e --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/loop-transforms/attrs-unroll-1.C @@ -0,0 +1,135 @@ +// { dg-do compile { target c++11 } } + +extern void dummy (int); + +void +test1 () +{ +[[omp::directive (unroll partial)]] + for (int i = 0; i < 100; ++i) + dummy (i); +} + +void +test2 () +{ +[[omp::directive (unroll partial(10))]] + for (int i = 0; i < 100; ++i) + dummy (i); +} + +void +test3 () +{ +[[omp::directive (unroll full)]] + for (int i = 0; i < 100; ++i) + dummy (i); +} + +void +test4 () +{ +[[omp::directive (unroll full)]] + for (int i = 0; i > 100; ++i) + dummy (i); +} + +void +test5 () +{ +[[omp::directive (unroll full)]] + for (int i = 1; i <= 100; ++i) + dummy (i); +} + +void +test6 () +{ +[[omp::directive (unroll full)]] + for (int i = 200; i >= 100; i--) + dummy (i); +} + +void +test7 () +{ +[[omp::directive (unroll full)]] + for (int i = -100; i > 100; ++i) + dummy (i); +} + +void +test8 () +{ +[[omp::directive (unroll full)]] + for (int i = 100; i > -200; --i) + dummy (i); +} + +void +test9 () +{ +[[omp::directive (unroll full)]] + for (int i = -300; i != 100; ++i) + dummy (i); +} + +void +test10 () +{ +[[omp::directive (unroll full)]] + for (int i = -300; i != 100; ++i) + dummy (i); +} + +void +test12 () +{ +[[omp::sequence (directive (unroll full), + directive (unroll partial), + directive (unroll partial))]] + for (int i = -300; i != 100; ++i) + dummy (i); +} + +void +test13 () +{ + for (int i = 0; i < 100; ++i) +[[omp::sequence (directive (unroll full), + directive (unroll partial), + directive (unroll partial))]] + for (int j = -300; j != 100; ++j) + dummy (i); +} + +void +test14 () +{ + [[omp::directive (for)]] + for (int i = 0; i < 100; ++i) + [[omp::sequence (directive (unroll full), + directive (unroll partial), + directive (unroll partial))]] + for (int j = -300; j != 100; ++j) + dummy (i); +} + +void +test15 () +{ + [[omp::directive (for)]] + for (int i = 0; i < 100; ++i) + { + + dummy (i); + + [[omp::sequence (directive (unroll full), + directive (unroll partial), + directive (unroll partial))]] + for (int j = -300; j != 100; ++j) + dummy (j); + + dummy (i); + } + } diff --git a/gcc/testsuite/g++.dg/gomp/loop-transforms/attrs-unroll-2.C b/gcc/testsuite/g++.dg/gomp/loop-transforms/attrs-unroll-2.C new file mode 100644 index 00000000000..1a45eadec64 --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/loop-transforms/attrs-unroll-2.C @@ -0,0 +1,81 @@ +/* { dg-prune-output "error: invalid controlling predicate" } */ +// { dg-do compile { target c++11 } } + +extern void dummy (int); + +void +test () +{ +[[omp::sequence (directive (unroll partial), + directive (unroll full))]] /* { dg-error {'full' clause is invalid here; turns loop into non-loop} } */ + for (int i = -300; i != 100; ++i) + dummy (i); + +[[omp::sequence (directive (for), + directive (unroll full), /* { dg-error {'full' clause is invalid here; turns loop into non-loop} } */ + directive (unroll partial))]] + for (int i = -300; i != 100; ++i) + dummy (i); + +[[omp::sequence (directive (for), + directive (unroll full), /* { dg-error {'full' clause is invalid here; turns loop into non-loop} } */ + directive (unroll full))]] + for (int i = -300; i != 100; ++i) + dummy (i); + +[[omp::sequence (directive (for), + directive (unroll partial partial))]] /* { dg-error {too many 'partial' clauses} } */ + for (int i = -300; i != 100; ++i) + dummy (i); + +[[omp::directive (unroll full full)]] /* { dg-error {too many 'full' clauses} } */ + for (int i = -300; i != 100; ++i) + dummy (i); + +[[omp::sequence (directive (unroll partial), + directive (unroll))]] /* { dg-error {'#pragma omp unroll' without 'partial' clause is invalid here; turns loop into non-loop} } */ + for (int i = -300; i != 100; ++i) + dummy (i); + +[[omp::sequence (directive (for), + directive (unroll))]] /* { dg-error {'#pragma omp unroll' without 'partial' clause is invalid here; turns loop into non-loop} } */ + for (int i = -300; i != 100; ++i) + dummy (i); + + int i; + +[[omp::sequence (directive (for), + directive (unroll foo))]] /* { dg-error {expected an OpenMP clause before 'foo'} } */ + for (int i = -300; i != 100; ++i) + dummy (i); + +[[omp::directive (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 expression} "" { target *-*-* } .-2 } */ + for (int i = -300; i != 100; ++i) + dummy (i); + +[[omp::directive (unroll parti)]] /* { dg-error {expected an OpenMP clause before 'parti'} } */ + for (int i = -300; i != 100; ++i) + dummy (i); + +[[omp::sequence (directive (for), + directive (unroll partial(1)), + directive (unroll parti))]] /* { dg-error {expected an OpenMP clause before 'parti'} } */ + for (int i = -300; i != 100; ++i) + dummy (i); + +[[omp::sequence (directive (for), + directive (unroll partial(1)), + directive (unroll parti))]] /* { dg-error {expected an OpenMP clause before 'parti'} } */ + for (int i = -300; i != 100; ++i) + dummy (i); + +int sum = 0; +[[omp::sequence (directive (parallel for reduction(+ : sum) collapse(2)), + directive (unroll partial(1)))]] /* { dg-error {nesting depth left after this transformation too low for loop collapse} } */ + for (int i = 3; i < 10; ++i) + for (int j = -2; j < 7; ++j) + sum++; +} + diff --git a/gcc/testsuite/g++.dg/gomp/loop-transforms/attrs-unroll-3.C b/gcc/testsuite/g++.dg/gomp/loop-transforms/attrs-unroll-3.C new file mode 100644 index 00000000000..20c11c0f314 --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/loop-transforms/attrs-unroll-3.C @@ -0,0 +1,20 @@ +// { dg-do compile { target c++11 } } + +/* { dg-additional-options "-fdump-tree-omp_transform_loops" } + * { dg-additional-options "-fdump-tree-original" } */ + +extern void dummy (int); + +void +test1 () +{ + int i; + [[omp::directive (unroll full)]] + for (int i = 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/g++.dg/gomp/loop-transforms/attrs-unroll-inner-1.C b/gcc/testsuite/g++.dg/gomp/loop-transforms/attrs-unroll-inner-1.C new file mode 100644 index 00000000000..234753ad017 --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/loop-transforms/attrs-unroll-inner-1.C @@ -0,0 +1,15 @@ +// { dg-do compile { target c++11 } } + +extern void dummy (int); + +void +test () +{ + + [[omp::directive (target parallel for collapse(2))]] + for (int i = -300; i != 100; ++i) + [[omp::directive (unroll, partial)]] + for (int j = 0; j != 100; ++j) + dummy (i); +} + diff --git a/gcc/testsuite/g++.dg/gomp/loop-transforms/attrs-unroll-inner-2.C b/gcc/testsuite/g++.dg/gomp/loop-transforms/attrs-unroll-inner-2.C new file mode 100644 index 00000000000..26cc665007d --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/loop-transforms/attrs-unroll-inner-2.C @@ -0,0 +1,29 @@ +// { dg-do compile { target c++11 } } + +extern void dummy (int); + +void +test () +{ + +#pragma omp target parallel for collapse(2) + for (int i = -300; i != 100; ++i) + [[omp::directive (tile sizes (2))]] + for (int j = 0; j != 100; ++j) + dummy (i); + + [[omp::directive (target parallel for collapse(2))]] + for (int i = -300; i != 100; ++i) /* { dg-error {not enough nested loops} } */ + [[omp::directive (tile sizes(2, 3))]] + for (int j = 0; j != 100; ++j) + dummy (i); + + [[omp::directive (target parallel for, collapse(2))]] + for (int i = -300; i != 100; ++i) + [[omp::directive (tile, sizes(2, 3))]] + for (int j = 0; j != 100; ++j) + for (int k = 0; k != 100; ++k) + dummy (i); +} + + diff --git a/gcc/testsuite/g++.dg/gomp/loop-transforms/attrs-unroll-inner-3.C b/gcc/testsuite/g++.dg/gomp/loop-transforms/attrs-unroll-inner-3.C new file mode 100644 index 00000000000..46970b84a24 --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/loop-transforms/attrs-unroll-inner-3.C @@ -0,0 +1,71 @@ +// { dg-do compile { target c++11 } } + +// Test that omp::sequence is handled properly in a loop nest, but that +// invalid attribute specifiers are rejected. + +extern void dummy (int); + +void +test1 () +{ + [[omp::directive (target parallel for collapse(2))]] + for (int i = -300; i != 100; ++i) + [[omp::sequence (directive (unroll, partial))]] // OK + for (int j = 0; j != 100; ++j) + dummy (i); +} + +void +test2 () +{ + [[omp::directive (target parallel for collapse(2))]] + for (int i = -300; i != 100; ++i) + [[omp::directive (masked)]] // { dg-error "loop nest expected" } + for (int j = 0; j != 100; ++j) + dummy (i); +} + +void +test3 () +{ + [[omp::directive (target parallel for collapse(2))]] + for (int i = -300; i != 100; ++i) + [[omp::directive (unroll, partial)]] // { dg-error "attributes on the same statement" } + [[omp::directive (masked)]] + for (int j = 0; j != 100; ++j) + dummy (i); +} + +void +test4 () +{ + [[omp::directive (target parallel for collapse(2))]] + for (int i = -300; i != 100; ++i) + [[omp::sequence (directive (unroll, partial), + directive (masked))]] // { dg-error "loop nest expected" } + for (int j = 0; j != 100; ++j) + dummy (i); +} + +void +test5 () +{ + [[omp::directive (target parallel for collapse(2))]] + for (int i = -300; i != 100; ++i) + [[omp::sequence (directive (masked), // { dg-error "loop nest expected" } + directive (unroll, partial))]] + for (int j = 0; j != 100; ++j) + dummy (i); +} + +void +test6 () +{ + [[omp::directive (target parallel for collapse(2))]] + for (int i = -300; i != 100; ++i) + [[omp::directive (unroll, partial), // { dg-error "attributes on the same statement" } + omp::directive (masked)]] + for (int j = 0; j != 100; ++j) + dummy (i); +} + diff --git a/gcc/testsuite/g++.dg/gomp/loop-transforms/tile-1.h b/gcc/testsuite/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=c++11" } + +#include + +extern void dummy (int); + +template void +test1_template () +{ + std::vector v; + + for (unsigned i = 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/testsuite/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=c++11" } + +#include + +extern void dummy (int); + +template void +test1_template () +{ + std::vector v; + + for (unsigned i = 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/testsuite/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=c++11" } + +#include + +extern void dummy (int); + +template void +test1_template () +{ + std::vector v; + + for (unsigned i = 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 needs positive integral constant} } + 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/unroll-1.C b/gcc/testsuite/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=c++11" } +#include + +extern void dummy (int); + +void +test1 () +{ + std::vector v; + + for (unsigned i = 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 = 0; i < 10; i++) + { + std::vector u; + for (unsigned j = 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/testsuite/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=c++11" } +#include + +extern void dummy (int); + +template void +test_template () +{ + std::vector v; + + for (unsigned i = 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 positive constant integer expression} } + for (T i : v) + dummy (i); + +#pragma omp unroll partial(U3) // { dg-error {partial argument needs positive 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 positive constant integer expression} } + for (T i : v) + dummy (i); + +#pragma omp for +#pragma omp unroll partial(U3) // { dg-error {partial argument needs positive 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/testsuite/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=c++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 <= 2 ? 1 : fib (n-1) + fib (n-2); +} + +void +test1 () +{ + std::vector v; + + for (unsigned i = 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) = 55 times +// ! { dg-final { scan-tree-dump {#pragma omp loop_transform unroll_partial\(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.*? <= .+?.+goto.+else goto.*?$} 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/gcc/testsuite/g++.dg/gomp/pr94512.C b/gcc/testsuite/g++.dg/gomp/pr94512.C index 8ba0e65795f..1d5cf150987 100644 --- a/gcc/testsuite/g++.dg/gomp/pr94512.C +++ b/gcc/testsuite/g++.dg/gomp/pr94512.C @@ -8,7 +8,7 @@ void bar () { #pragma omp parallel master taskloop - foo (); // { dg-error "for statement expected before" } + foo (); // { dg-error "loop nest expected before" } } void diff --git a/gcc/testsuite/gcc.dg/gomp/for-1.c b/gcc/testsuite/gcc.dg/gomp/for-1.c index 80e0d0be844..ecaf0c55796 100644 --- a/gcc/testsuite/gcc.dg/gomp/for-1.c +++ b/gcc/testsuite/gcc.dg/gomp/for-1.c @@ -26,7 +26,7 @@ void foo (int j, int k) /* Malformed parallel loops. */ #pragma omp for - i = 0; /* { dg-error "3:for statement expected" } */ + i = 0; /* { dg-error "3:loop nest expected" } */ for ( ; i < 10; ) { baz (i); diff --git a/gcc/testsuite/gcc.dg/gomp/for-11.c b/gcc/testsuite/gcc.dg/gomp/for-11.c index 8c747cdb981..abafa487283 100644 --- a/gcc/testsuite/gcc.dg/gomp/for-11.c +++ b/gcc/testsuite/gcc.dg/gomp/for-11.c @@ -30,7 +30,7 @@ void foo (int j, int k) /* Malformed parallel loops. */ #pragma omp for - i = 0; /* { dg-error "for statement expected" } */ + i = 0; /* { dg-error "loop nest expected" } */ for ( ; i < 10; ) { baz (i); diff --git a/libgomp/testsuite/libgomp.c++/loop-transforms/matrix-no-directive-unroll-full-1.C b/libgomp/testsuite/libgomp.c++/loop-transforms/matrix-no-directive-unroll-full-1.C new file mode 100644 index 00000000000..3a684219627 --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/loop-transforms/matrix-no-directive-unroll-full-1.C @@ -0,0 +1,13 @@ +/* { dg-additional-options { -O0 -fdump-tree-original -Wall -Wno-unknown-pragmas } } */ + +#define COMMON_DIRECTIVE +#define COMMON_TOP_TRANSFORM omp unroll full +#define COLLAPSE_1 +#define COLLAPSE_2 +#define COLLAPSE_3 +#define IMPLEMENTATION_FILE "../../libgomp.c-c++-common/loop-transforms/matrix-constant-iter.h" + +#include "../../libgomp.c-c++-common/loop-transforms/matrix-transform-variants-1.h" + +/* A consistency check to prevent broken macro usage. */ +/* { dg-final { scan-tree-dump-times "unroll_full" 13 "original" } } */ diff --git a/libgomp/testsuite/libgomp.c++/loop-transforms/tile-2.C b/libgomp/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=c++11" } +// { dg-additional-options "-O0" } + +#include +#include + +constexpr unsigned fib (unsigned n) +{ + return n <= 2 ? 1 : fib (n-1) + fib (n-2); +} + +int +test1 () +{ + std::vector v; + + for (unsigned i = 0; i <= 9; i++) + v.push_back (1); + + int sum = 0; + for (int k = 0; k < 10; k++) + #pragma omp tile sizes(fib(4)) + for (int i : v) { + for (int j = 8; j != -2; --j) + sum = sum + i; + } + + return sum; +} + +int +test2 () +{ + std::vector v; + + for (unsigned i = 0; i <= 10; i++) + v.push_back (i); + + int sum = 0; + for (int k = 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 = 8; j > -2; --j) + sum = sum + i; + + return sum; +} + +int +main () +{ + int result = test1 (); + + if (result != 1000) + { + fprintf (stderr, "%d: Wrong result: %d\n", __LINE__, result); + __builtin_abort (); + } + + result = test2 (); + if (result != 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/libgomp/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=c++11" } +// { dg-additional-options "-O0" } + +#include + +int +main () +{ + std::vector v; + std::vector w; + + for (unsigned i = 0; i <= 9; i++) + v.push_back (i); + + int iter = 0; +#pragma omp for +#pragma omp tile sizes(5) + for (int i : v) + { + w.push_back (iter); + iter++; + } + + for (int i = 0; i < w.size (); i++) + if (w[i] != i) + __builtin_abort (); + return 0; +} diff --git a/libgomp/testsuite/libgomp.c++/loop-transforms/unroll-1.C b/libgomp/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=c++11" } +// { dg-additional-options "-O0" } + +#include +#include + +constexpr unsigned fib (unsigned n) +{ + return n <= 2 ? 1 : fib (n-1) + fib (n-2); +} + +int +test1 () +{ + std::vector v; + + for (unsigned i = 0; i <= 9; i++) + v.push_back (1); + + int sum = 0; + for (int k = 0; k < 10; k++) +#pragma omp unroll partial(fib(3)) + for (int i : v) { + for (int j = 8; j != -2; --j) + sum = sum + i; + } + + return sum; +} + +int +test2 () +{ + std::vector v; + + for (unsigned i = 0; i <= 10; i++) + v.push_back (i); + + int sum = 0; +#pragma omp parallel for reduction(+:sum) + for (int k = 0; k < 10; k++) +#pragma omp unroll +#pragma omp unroll partial(fib(4)) + for (int i : v) + { + #pragma omp unroll full + for (int j = 8; j != -2; --j) + sum = sum + i; + } + + return sum; +} + +int +main () +{ + int result = test1 (); + + if (result != 1000) + { + fprintf (stderr, "Wrong result: %d\n", result); + __builtin_abort (); + } + + result = test2 (); + if (result != 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/libgomp/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=c++11" } +#include +#include + +int +main () +{ + std::vector> v; + std::vector w; + + for (unsigned i = 0; i < 10; i++) + { + std::vector u; + for (unsigned j = 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 = w.size (); + for (std::size_t i = 0; i < l; i++) + { + if (w[i] != i % 10) + __builtin_abort (); + } + + return 0; +} diff --git a/libgomp/testsuite/libgomp.c++/loop-transforms/unroll-full-tile.C b/libgomp/testsuite/libgomp.c++/loop-transforms/unroll-full-tile.C new file mode 100644 index 00000000000..8970bfa7fd8 --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/loop-transforms/unroll-full-tile.C @@ -0,0 +1,84 @@ +#include +#include + +template +int sum () +{ + int sum = 0; +#pragma omp unroll full +#pragma omp tile sizes(dim0, dim1) + for (unsigned i = 0; i < 4; i++) + for (unsigned j = 0; j < 5; j++) + sum++; + + return sum; +} + +int main () +{ + if (sum <1,1> () != 20) + __builtin_abort (); + if (sum <1,2> () != 20) + __builtin_abort (); + if (sum <1,3> () != 20) + __builtin_abort (); + if (sum <1,4> () != 20) + __builtin_abort (); + if (sum <1,5> () != 20) + __builtin_abort (); + + if (sum <2,1> () != 20) + __builtin_abort (); + if (sum <2,2> () != 20) + __builtin_abort (); + if (sum <2,3> () != 20) + __builtin_abort (); + if (sum <2,4> () != 20) + __builtin_abort (); + if (sum <2,5> () != 20) + __builtin_abort (); + + if (sum <3,1> () != 20) + __builtin_abort (); + if (sum <3,2> () != 20) + __builtin_abort (); + if (sum <3,3> () != 20) + __builtin_abort (); + if (sum <3,4> () != 20) + __builtin_abort (); + if (sum <3,5> () != 20) + __builtin_abort (); + + if (sum <4,1> () != 20) + __builtin_abort (); + if (sum <4,2> () != 20) + __builtin_abort (); + if (sum <4,3> () != 20) + __builtin_abort (); + if (sum <4,4> () != 20) + __builtin_abort (); + if (sum <4,5> () != 20) + __builtin_abort (); + + if (sum <5,1> () != 20) + __builtin_abort (); + if (sum <5,2> () != 20) + __builtin_abort (); + if (sum <5,3> () != 20) + __builtin_abort (); + if (sum <5,4> () != 20) + __builtin_abort (); + if (sum <5,5> () != 20) + __builtin_abort (); + + if (sum <6,1> () != 20) + __builtin_abort (); + if (sum <6,2> () != 20) + __builtin_abort (); + if (sum <6,3> () != 20) + __builtin_abort (); + if (sum <6,4> () != 20) + __builtin_abort (); + if (sum <6,5> () != 20) + __builtin_abort (); +} diff --git a/libgomp/testsuite/libgomp.c-c++-common/imperfect-transform-1.c b/libgomp/testsuite/libgomp.c-c++-common/imperfect-transform-1.c new file mode 100644 index 00000000000..6743594b2eb --- /dev/null +++ b/libgomp/testsuite/libgomp.c-c++-common/imperfect-transform-1.c @@ -0,0 +1,79 @@ +/* { dg-do run } */ + +/* Like imperfect1.c, but also includes loop transforms. */ + +static int f1count[3], f2count[3]; + +#ifndef __cplusplus +extern void abort (void); +#else +extern "C" void abort (void); +#endif + +int f1 (int depth, int iter) +{ + f1count[depth]++; + return iter; +} + +int f2 (int depth, int iter) +{ + f2count[depth]++; + return iter; +} + +void s1 (int a1, int a2, int a3) +{ + int i, j, k; + +#pragma omp for collapse(2) + for (i = 0; i < a1; i++) + { + f1 (0, i); + for (j = 0; j < a2; j++) + { + f1 (1, j); +#pragma omp unroll partial + for (k = 0; k < a3; k++) + { + f1 (2, k); + f2 (2, k); + } + f2 (1, j); + } + f2 (0, i); + } +} + +int +main (void) +{ + f1count[0] = 0; + f1count[1] = 0; + f1count[2] = 0; + f2count[0] = 0; + f2count[1] = 0; + f2count[2] = 0; + + s1 (3, 4, 5); + + /* All intervening code at the same depth must be executed the same + number of times. */ + if (f1count[0] != f2count[0]) abort (); + if (f1count[1] != f2count[1]) abort (); + if (f1count[2] != f2count[2]) abort (); + + /* Intervening code must be executed at least as many times as the loop + that encloses it. */ + if (f1count[0] < 3) abort (); + if (f1count[1] < 3 * 4) abort (); + + /* Intervening code must not be executed more times than the number + of logical iterations. */ + if (f1count[0] > 3 * 4 * 5) abort (); + if (f1count[1] > 3 * 4 * 5) abort (); + + /* Check that the innermost loop body is executed exactly the number + of logical iterations expected. */ + if (f1count[2] != 3 * 4 * 5) abort (); +} diff --git a/libgomp/testsuite/libgomp.c-c++-common/imperfect-transform-2.c b/libgomp/testsuite/libgomp.c-c++-common/imperfect-transform-2.c new file mode 100644 index 00000000000..e7d6a9941b4 --- /dev/null +++ b/libgomp/testsuite/libgomp.c-c++-common/imperfect-transform-2.c @@ -0,0 +1,79 @@ +/* { dg-do run } */ + +/* Like imperfect1.c, but also includes loop transforms. */ + +static int f1count[3], f2count[3]; + +#ifndef __cplusplus +extern void abort (void); +#else +extern "C" void abort (void); +#endif + +int f1 (int depth, int iter) +{ + f1count[depth]++; + return iter; +} + +int f2 (int depth, int iter) +{ + f2count[depth]++; + return iter; +} + +void s1 (int a1, int a2, int a3) +{ + int i, j, k; + +#pragma omp for collapse(2) + for (i = 0; i < a1; i++) + { + f1 (0, i); + for (j = 0; j < a2; j++) + { + f1 (1, j); +#pragma omp tile sizes(5) + for (k = 0; k < a3; k++) + { + f1 (2, k); + f2 (2, k); + } + f2 (1, j); + } + f2 (0, i); + } +} + +int +main (void) +{ + f1count[0] = 0; + f1count[1] = 0; + f1count[2] = 0; + f2count[0] = 0; + f2count[1] = 0; + f2count[2] = 0; + + s1 (3, 4, 5); + + /* All intervening code at the same depth must be executed the same + number of times. */ + if (f1count[0] != f2count[0]) abort (); + if (f1count[1] != f2count[1]) abort (); + if (f1count[2] != f2count[2]) abort (); + + /* Intervening code must be executed at least as many times as the loop + that encloses it. */ + if (f1count[0] < 3) abort (); + if (f1count[1] < 3 * 4) abort (); + + /* Intervening code must not be executed more times than the number + of logical iterations. */ + if (f1count[0] > 3 * 4 * 5) abort (); + if (f1count[1] > 3 * 4 * 5) abort (); + + /* Check that the innermost loop body is executed exactly the number + of logical iterations expected. */ + if (f1count[2] != 3 * 4 * 5) abort (); +} diff --git a/libgomp/testsuite/libgomp.c-c++-common/loop-transforms/matrix-1.h b/libgomp/testsuite/libgomp.c-c++-common/loop-transforms/matrix-1.h new file mode 100644 index 00000000000..b9b865cf554 --- /dev/null +++ b/libgomp/testsuite/libgomp.c-c++-common/loop-transforms/matrix-1.h @@ -0,0 +1,70 @@ +#include +#include +#include +#include + +#ifndef FUN_NAME_SUFFIX +#define FUN_NAME_SUFFIX +#endif + +#ifdef MULT +#undef MULT +#endif +#define MULT CAT(mult, FUN_NAME_SUFFIX) + +#ifdef MAIN +#undef MAIN +#endif +#define MAIN CAT(main, FUN_NAME_SUFFIX) + +void MULT (float *matrix1, float *matrix2, float *result, + unsigned dim0, unsigned dim1) +{ + unsigned i; + + memset (result, 0, sizeof (float) * dim0 * dim1); + DIRECTIVE + TRANSFORMATION1 + for (i = 0; i < dim0; i++) + TRANSFORMATION2 + for (unsigned j = 0; j < dim1; j++) + TRANSFORMATION3 + for (unsigned k = 0; k < dim1; k++) + result[i * dim1 + j] += matrix1[i * dim1 + k] * matrix2[k * dim0 + j]; +} + +int MAIN () +{ + unsigned dim0 = 20; + unsigned dim1 = 20; + + float *result = (float *)malloc (sizeof (float) * dim0 * dim1); + float *matrix1 = (float *)malloc (sizeof (float) * dim0 * dim1); + float *matrix2 = (float *)malloc (sizeof (float) * dim0 * dim1); + + for (unsigned i = 0; i < dim0; i++) + for (unsigned j = 0; j < dim1; j++) + matrix1[i * dim1 + j] = j; + + for (unsigned i = 0; i < dim0; i++) + for (unsigned j = 0; j < dim1; j++) + if (i == j) + matrix2[i * dim1 + j] = 1; + else + matrix2[i * dim1 + j] = 0; + + MULT (matrix1, matrix2, result, dim0, dim1); + + for (unsigned i = 0; i < dim0; i++) + for (unsigned j = 0; j < dim1; j++) { + if (matrix1[i * dim1 + j] != result[i * dim1 + j]) { + print_matrix (matrix1, dim0, dim1); + print_matrix (matrix2, dim0, dim1); + print_matrix (result, dim0, dim1); + fprintf(stderr, "%s: ERROR at %d, %d\n", __FUNCTION__, i, j); + abort(); + } + } + + return 0; +} diff --git a/libgomp/testsuite/libgomp.c-c++-common/loop-transforms/matrix-constant-iter.h b/libgomp/testsuite/libgomp.c-c++-common/loop-transforms/matrix-constant-iter.h new file mode 100644 index 00000000000..769c04044c3 --- /dev/null +++ b/libgomp/testsuite/libgomp.c-c++-common/loop-transforms/matrix-constant-iter.h @@ -0,0 +1,71 @@ +#include +#include +#include +#include + +#ifndef FUN_NAME_SUFFIX +#define FUN_NAME_SUFFIX +#endif + +#ifdef MULT +#undef MULT +#endif +#define MULT CAT(mult, FUN_NAME_SUFFIX) + +#ifdef MAIN +#undef MAIN +#endif +#define MAIN CAT(main, FUN_NAME_SUFFIX) + +void MULT (float *matrix1, float *matrix2, float *result) +{ + const unsigned dim0 = 20; + const unsigned dim1 = 20; + + memset (result, 0, sizeof (float) * dim0 * dim1); + DIRECTIVE + TRANSFORMATION1 + for (unsigned i = 0; i < dim0; i++) + TRANSFORMATION2 + for (unsigned j = 0; j < dim1; j++) + TRANSFORMATION3 + for (unsigned k = 0; k < dim1; k++) + result[i * dim1 + j] += matrix1[i * dim1 + k] * matrix2[k * dim0 + j]; +} + +int MAIN () +{ + const unsigned dim0 = 20; + const unsigned dim1 = 20; + + float *result = (float *)malloc (sizeof (float) * dim0 * dim1); + float *matrix1 = (float *)malloc (sizeof (float) * dim0 * dim1); + float *matrix2 = (float *)malloc (sizeof (float) * dim0 * dim1); + + for (unsigned i = 0; i < dim0; i++) + for (unsigned j = 0; j < dim1; j++) + matrix1[i * dim1 + j] = j; + + for (unsigned i = 0; i < dim0; i++) + for (unsigned j = 0; j < dim1; j++) + if (i == j) + matrix2[i * dim1 + j] = 1; + else + matrix2[i * dim1 + j] = 0; + + MULT (matrix1, matrix2, result); + + for (unsigned i = 0; i < dim0; i++) + for (unsigned j = 0; j < dim1; j++) { + if (matrix1[i * dim1 + j] != result[i * dim1 + j]) { + __builtin_printf("%s: error at %d, %d\n", __FUNCTION__, i, j); + print_matrix (matrix1, dim0, dim1); + print_matrix (matrix2, dim0, dim1); + print_matrix (result, dim0, dim1); + __builtin_printf("\n"); + __builtin_abort(); + } + } + + return 0; +} diff --git a/libgomp/testsuite/libgomp.c-c++-common/loop-transforms/matrix-helper.h b/libgomp/testsuite/libgomp.c-c++-common/loop-transforms/matrix-helper.h new file mode 100644 index 00000000000..4f69463d9dd --- /dev/null +++ b/libgomp/testsuite/libgomp.c-c++-common/loop-transforms/matrix-helper.h @@ -0,0 +1,19 @@ +#include +#include + +#define CAT(x,y) XCAT(x,y) +#define XCAT(x,y) x ## y +#define DO_PRAGMA(x) XDO_PRAGMA(x) +#define XDO_PRAGMA(x) _Pragma (#x) + + +void print_matrix (float *matrix, unsigned dim0, unsigned dim1) +{ + for (unsigned i = 0; i < dim0; i++) + { + for (unsigned j = 0; j < dim1; j++) + fprintf (stderr, "%f ", matrix[i * dim1 + j]); + fprintf (stderr, "\n"); + } + fprintf (stderr, "\n"); +} diff --git a/libgomp/testsuite/libgomp.c-c++-common/loop-transforms/matrix-no-directive-1.c b/libgomp/testsuite/libgomp.c-c++-common/loop-transforms/matrix-no-directive-1.c new file mode 100644 index 00000000000..7904a5617f3 --- /dev/null +++ b/libgomp/testsuite/libgomp.c-c++-common/loop-transforms/matrix-no-directive-1.c @@ -0,0 +1,11 @@ +/* { dg-additional-options { -fdump-tree-original -Wall -Wno-unknown-pragmas } } */ + +#define COMMON_DIRECTIVE +#define COLLAPSE_1 collapse(1) +#define COLLAPSE_2 collapse(2) +#define COLLAPSE_3 collapse(3) + +#include "matrix-transform-variants-1.h" + +/* A consistency check to prevent broken macro usage. */ +/* { dg-final { scan-tree-dump-times "unroll_partial" 12 "original" } } */ diff --git a/libgomp/testsuite/libgomp.c-c++-common/loop-transforms/matrix-no-directive-unroll-full-1.c b/libgomp/testsuite/libgomp.c-c++-common/loop-transforms/matrix-no-directive-unroll-full-1.c new file mode 100644 index 00000000000..bd431a25102 --- /dev/null +++ b/libgomp/testsuite/libgomp.c-c++-common/loop-transforms/matrix-no-directive-unroll-full-1.c @@ -0,0 +1,13 @@ +/* { dg-additional-options { -O2 -fdump-tree-original -Wall -Wno-unknown-pragmas } } */ + +#define COMMON_DIRECTIVE +#define COMMON_TOP_TRANSFORM omp unroll full +#define COLLAPSE_1 +#define COLLAPSE_2 +#define COLLAPSE_3 +#define IMPLEMENTATION_FILE "matrix-constant-iter.h" + +#include "matrix-transform-variants-1.h" + +/* A consistency check to prevent broken macro usage. */ +/* { dg-final { scan-tree-dump-times "unroll_full" 13 "original" } } */ diff --git a/libgomp/testsuite/libgomp.c-c++-common/loop-transforms/matrix-omp-distribute-parallel-for-1.c b/libgomp/testsuite/libgomp.c-c++-common/loop-transforms/matrix-omp-distribute-parallel-for-1.c new file mode 100644 index 00000000000..3875014dc96 --- /dev/null +++ b/libgomp/testsuite/libgomp.c-c++-common/loop-transforms/matrix-omp-distribute-parallel-for-1.c @@ -0,0 +1,8 @@ +/* { dg-additional-options { -Wall -Wno-unknown-pragmas } } */ + +#define COMMON_DIRECTIVE "omp teams distribute parallel for" +#define COLLAPSE_1 "collapse(1)" +#define COLLAPSE_2 "collapse(2)" +#define COLLAPSE_3 "collapse(3)" + +#include "matrix-transform-variants-1.h" diff --git a/libgomp/testsuite/libgomp.c-c++-common/loop-transforms/matrix-omp-for-1.c b/libgomp/testsuite/libgomp.c-c++-common/loop-transforms/matrix-omp-for-1.c new file mode 100644 index 00000000000..671396cd533 --- /dev/null +++ b/libgomp/testsuite/libgomp.c-c++-common/loop-transforms/matrix-omp-for-1.c @@ -0,0 +1,13 @@ +/* { dg-additional-options { -fdump-tree-original -Wall -Wno-unknown-pragmas } } */ + +#define COMMON_DIRECTIVE omp for +#define COLLAPSE_1 collapse(1) +#define COLLAPSE_2 collapse(2) +#define COLLAPSE_3 collapse(3) + +#include "matrix-transform-variants-1.h" + + +/* A consistency check to prevent broken macro usage. */ +/* { dg-final { scan-tree-dump-times "omp for" 13 "original" } } */ +/* { dg-final { scan-tree-dump-times "collapse" 12 "original" } } */ diff --git a/libgomp/testsuite/libgomp.c-c++-common/loop-transforms/matrix-omp-parallel-for-1.c b/libgomp/testsuite/libgomp.c-c++-common/loop-transforms/matrix-omp-parallel-for-1.c new file mode 100644 index 00000000000..cc66df42679 --- /dev/null +++ b/libgomp/testsuite/libgomp.c-c++-common/loop-transforms/matrix-omp-parallel-for-1.c @@ -0,0 +1,13 @@ +/* { dg-additional-options { -fdump-tree-original -Wall -Wno-unknown-pragmas } } */ + +#define COMMON_DIRECTIVE omp parallel for +#define COLLAPSE_1 collapse(1) +#define COLLAPSE_2 collapse(2) +#define COLLAPSE_3 + +#include "matrix-transform-variants-1.h" + + +/* A consistency check to prevent broken macro usage. */ +/* { dg-final { scan-tree-dump-times "omp parallel" 13 "original" } } */ +/* { dg-final { scan-tree-dump-times "collapse" 9 "original" } } */ diff --git a/libgomp/testsuite/libgomp.c-c++-common/loop-transforms/matrix-omp-parallel-masked-taskloop-1.c b/libgomp/testsuite/libgomp.c-c++-common/loop-transforms/matrix-omp-parallel-masked-taskloop-1.c new file mode 100644 index 00000000000..890b460f374 --- /dev/null +++ b/libgomp/testsuite/libgomp.c-c++-common/loop-transforms/matrix-omp-parallel-masked-taskloop-1.c @@ -0,0 +1,8 @@ +/* { dg-additional-options { -Wall -Wno-unknown-pragmas } } */ + +#define COMMON_DIRECTIVE omp parallel masked taskloop +#define COLLAPSE_1 collapse(1) +#define COLLAPSE_2 collapse(2) +#define COLLAPSE_3 + +#include "matrix-transform-variants-1.h" diff --git a/libgomp/testsuite/libgomp.c-c++-common/loop-transforms/matrix-omp-parallel-masked-taskloop-simd-1.c b/libgomp/testsuite/libgomp.c-c++-common/loop-transforms/matrix-omp-parallel-masked-taskloop-simd-1.c new file mode 100644 index 00000000000..74f6271504a --- /dev/null +++ b/libgomp/testsuite/libgomp.c-c++-common/loop-transforms/matrix-omp-parallel-masked-taskloop-simd-1.c @@ -0,0 +1,8 @@ +/* { dg-additional-options { -Wall -Wno-unknown-pragmas } } */ + +#define COMMON_DIRECTIVE omp parallel masked taskloop simd +#define COLLAPSE_1 collapse(1) +#define COLLAPSE_2 collapse(2) +#define COLLAPSE_3 + +#include "matrix-transform-variants-1.h" diff --git a/libgomp/testsuite/libgomp.c-c++-common/loop-transforms/matrix-omp-target-parallel-for-1.c b/libgomp/testsuite/libgomp.c-c++-common/loop-transforms/matrix-omp-target-parallel-for-1.c new file mode 100644 index 00000000000..4abeda73b48 --- /dev/null +++ b/libgomp/testsuite/libgomp.c-c++-common/loop-transforms/matrix-omp-target-parallel-for-1.c @@ -0,0 +1,15 @@ +/* This test appears to have too much parallelism to run without a GPU. */ +/* { dg-do run { target { offload_device } } } */ +/* { dg-additional-options { -fdump-tree-original -Wall -Wno-unknown-pragmas } } */ + +#define COMMON_DIRECTIVE omp target parallel for map(tofrom:result[0:dim0*dim1]) map(to:matrix1[0:dim0*dim1], matrix2[0:dim0*dim1]) +#define COLLAPSE_1 collapse(1) +#define COLLAPSE_2 collapse(2) +#define COLLAPSE_3 + +#include "matrix-transform-variants-1.h" + +/* A consistency check to prevent broken macro usage. */ +/* { dg-final { scan-tree-dump-times "omp target" 13 "original" } } */ +/* { dg-final { scan-tree-dump-times "collapse" 9 "original" } } */ +/* { dg-final { scan-tree-dump-times "unroll_partial" 12 "original" } } */ diff --git a/libgomp/testsuite/libgomp.c-c++-common/loop-transforms/matrix-omp-target-teams-distribute-parallel-for-1.c b/libgomp/testsuite/libgomp.c-c++-common/loop-transforms/matrix-omp-target-teams-distribute-parallel-for-1.c new file mode 100644 index 00000000000..f836707c43b --- /dev/null +++ b/libgomp/testsuite/libgomp.c-c++-common/loop-transforms/matrix-omp-target-teams-distribute-parallel-for-1.c @@ -0,0 +1,10 @@ +/* This test appears to have too much parallelism to run without a GPU. */ +/* { dg-do run { target { offload_device } } } */ +/* { dg-additional-options { -Wall -Wno-unknown-pragmas } } */ + +#define COMMON_DIRECTIVE omp target teams distribute parallel for map(tofrom:result[:dim0*dim1]) map(to:matrix1[0:dim0*dim1], matrix2[0:dim0*dim1]) +#define COLLAPSE_1 collapse(1) +#define COLLAPSE_2 collapse(2) +#define COLLAPSE_3 + +#include "matrix-transform-variants-1.h" diff --git a/libgomp/testsuite/libgomp.c-c++-common/loop-transforms/matrix-omp-taskloop-1.c b/libgomp/testsuite/libgomp.c-c++-common/loop-transforms/matrix-omp-taskloop-1.c new file mode 100644 index 00000000000..28edb6ce83e --- /dev/null +++ b/libgomp/testsuite/libgomp.c-c++-common/loop-transforms/matrix-omp-taskloop-1.c @@ -0,0 +1,8 @@ +/* { dg-additional-options { -Wall -Wno-unknown-pragmas } } */ + +#define COMMON_DIRECTIVE omp taskloop +#define COLLAPSE_1 collapse(1) +#define COLLAPSE_2 collapse(2) +#define COLLAPSE_3 collapse(3) + +#include "matrix-transform-variants-1.h" diff --git a/libgomp/testsuite/libgomp.c-c++-common/loop-transforms/matrix-omp-teams-distribute-parallel-for-1.c b/libgomp/testsuite/libgomp.c-c++-common/loop-transforms/matrix-omp-teams-distribute-parallel-for-1.c new file mode 100644 index 00000000000..481a20a18d0 --- /dev/null +++ b/libgomp/testsuite/libgomp.c-c++-common/loop-transforms/matrix-omp-teams-distribute-parallel-for-1.c @@ -0,0 +1,8 @@ +/* { dg-additional-options { -Wall -Wno-unknown-pragmas } } */ + +#define COMMON_DIRECTIVE omp teams distribute parallel for +#define COLLAPSE_1 collapse(1) +#define COLLAPSE_2 collapse(2) +#define COLLAPSE_3 + +#include "matrix-transform-variants-1.h" diff --git a/libgomp/testsuite/libgomp.c-c++-common/loop-transforms/matrix-simd-1.c b/libgomp/testsuite/libgomp.c-c++-common/loop-transforms/matrix-simd-1.c new file mode 100644 index 00000000000..200ddd859f5 --- /dev/null +++ b/libgomp/testsuite/libgomp.c-c++-common/loop-transforms/matrix-simd-1.c @@ -0,0 +1,8 @@ +/* { dg-additional-options { -Wall -Wno-unknown-pragmas } } */ + +#define COMMON_DIRECTIVE omp simd +#define COLLAPSE_1 collapse(1) +#define COLLAPSE_2 collapse(2) +#define COLLAPSE_3 collapse(3) + +#include "matrix-transform-variants-1.h" diff --git a/libgomp/testsuite/libgomp.c-c++-common/loop-transforms/matrix-transform-variants-1.h b/libgomp/testsuite/libgomp.c-c++-common/loop-transforms/matrix-transform-variants-1.h new file mode 100644 index 00000000000..24c3d073024 --- /dev/null +++ b/libgomp/testsuite/libgomp.c-c++-common/loop-transforms/matrix-transform-variants-1.h @@ -0,0 +1,191 @@ +#include "matrix-helper.h" + +#ifndef COMMON_TOP_TRANSFORM +#define COMMON_TOP_TRANSFORM +#endif + +#ifndef IMPLEMENTATION_FILE +#define IMPLEMENTATION_FILE "matrix-1.h" +#endif + +#define FUN_NAME_SUFFIX 1 +#define DIRECTIVE DO_PRAGMA(COMMON_DIRECTIVE) +#define TRANSFORMATION1 DO_PRAGMA(COMMON_TOP_TRANSFORM) _Pragma("omp unroll partial(2)") _Pragma("omp tile sizes(10)") +#define TRANSFORMATION2 +#define TRANSFORMATION3 +#include IMPLEMENTATION_FILE + +#undef DIRECTIVE +#undef TRANSFORMATION1 +#undef TRANSFORMATION2 +#undef TRANSFORMATION3 +#undef FUN_NAME_SUFFIX + +#define FUN_NAME_SUFFIX 2 +#define DIRECTIVE DO_PRAGMA(COMMON_DIRECTIVE COLLAPSE_3) +#define TRANSFORMATION1 DO_PRAGMA(COMMON_TOP_TRANSFORM) _Pragma("omp tile sizes(8,16,4)") +#define TRANSFORMATION2 +#define TRANSFORMATION3 +#include IMPLEMENTATION_FILE + +#undef DIRECTIVE +#undef TRANSFORMATION1 +#undef TRANSFORMATION2 +#undef TRANSFORMATION3 +#undef FUN_NAME_SUFFIX + +#define FUN_NAME_SUFFIX 3 +#define DIRECTIVE DO_PRAGMA(COMMON_DIRECTIVE COLLAPSE_2) +#define TRANSFORMATION1 DO_PRAGMA(COMMON_TOP_TRANSFORM) _Pragma("omp tile sizes(8, 8)") +#define TRANSFORMATION2 +#define TRANSFORMATION3 +#include IMPLEMENTATION_FILE + +#undef DIRECTIVE +#undef TRANSFORMATION1 +#undef TRANSFORMATION2 +#undef TRANSFORMATION3 +#undef FUN_NAME_SUFFIX + +#define FUN_NAME_SUFFIX 4 +#define DIRECTIVE DO_PRAGMA(COMMON_DIRECTIVE COLLAPSE_1) +#define TRANSFORMATION1 DO_PRAGMA(COMMON_TOP_TRANSFORM) _Pragma("omp tile sizes(8, 8)") +#define TRANSFORMATION2 +#define TRANSFORMATION3 +#include IMPLEMENTATION_FILE + +#undef DIRECTIVE +#undef TRANSFORMATION1 +#undef TRANSFORMATION2 +#undef TRANSFORMATION3 +#undef FUN_NAME_SUFFIX + +#define FUN_NAME_SUFFIX 5 +#define DIRECTIVE DO_PRAGMA(COMMON_DIRECTIVE COLLAPSE_1) +#define TRANSFORMATION1 DO_PRAGMA(COMMON_TOP_TRANSFORM) _Pragma("omp tile sizes(8, 8, 8)") +#define TRANSFORMATION2 +#define TRANSFORMATION3 +#include IMPLEMENTATION_FILE + +#undef DIRECTIVE +#undef TRANSFORMATION1 +#undef TRANSFORMATION2 +#undef TRANSFORMATION3 +#undef FUN_NAME_SUFFIX + +#define FUN_NAME_SUFFIX 6 +#define DIRECTIVE DO_PRAGMA(COMMON_DIRECTIVE COLLAPSE_1) +#define TRANSFORMATION1 DO_PRAGMA(COMMON_TOP_TRANSFORM) _Pragma("omp tile sizes(10)") _Pragma("omp unroll partial(2)") +#define TRANSFORMATION2 +#define TRANSFORMATION3 +#include IMPLEMENTATION_FILE + +#undef DIRECTIVE +#undef TRANSFORMATION1 +#undef TRANSFORMATION2 +#undef TRANSFORMATION3 +#undef FUN_NAME_SUFFIX + +#define FUN_NAME_SUFFIX 7 +#define DIRECTIVE DO_PRAGMA(COMMON_DIRECTIVE COLLAPSE_2) +#define TRANSFORMATION1 DO_PRAGMA(COMMON_TOP_TRANSFORM) _Pragma("omp tile sizes(7, 11)") +#define TRANSFORMATION2 _Pragma("omp unroll partial(7)") +#define TRANSFORMATION3 +#include IMPLEMENTATION_FILE + +#undef DIRECTIVE +#undef TRANSFORMATION1 +#undef TRANSFORMATION2 +#undef TRANSFORMATION3 +#undef FUN_NAME_SUFFIX + +#define FUN_NAME_SUFFIX 8 +#define DIRECTIVE DO_PRAGMA(COMMON_DIRECTIVE COLLAPSE_2) +#define TRANSFORMATION1 DO_PRAGMA(COMMON_TOP_TRANSFORM) _Pragma("omp tile sizes(7, 11)") +#define TRANSFORMATION2 _Pragma("omp tile sizes(7)") _Pragma("omp unroll partial(7)") +#define TRANSFORMATION3 +#include IMPLEMENTATION_FILE + +#undef DIRECTIVE +#undef TRANSFORMATION1 +#undef TRANSFORMATION2 +#undef TRANSFORMATION3 +#undef FUN_NAME_SUFFIX + +#define FUN_NAME_SUFFIX 9 +#define DIRECTIVE DO_PRAGMA(COMMON_DIRECTIVE COLLAPSE_2) +#define TRANSFORMATION1 DO_PRAGMA(COMMON_TOP_TRANSFORM) _Pragma("omp tile sizes(7, 11)") +#define TRANSFORMATION2 _Pragma("omp tile sizes(7)") _Pragma("omp unroll partial(3)") _Pragma("omp tile sizes(7)") +#define TRANSFORMATION3 +#include IMPLEMENTATION_FILE + +#undef DIRECTIVE +#undef TRANSFORMATION1 +#undef TRANSFORMATION2 +#undef TRANSFORMATION3 +#undef FUN_NAME_SUFFIX + +#define FUN_NAME_SUFFIX 10 +#define DIRECTIVE DO_PRAGMA(COMMON_DIRECTIVE COLLAPSE_1) +#define TRANSFORMATION1 DO_PRAGMA(COMMON_TOP_TRANSFORM) _Pragma("omp unroll partial(5)") _Pragma("omp tile sizes(7)") _Pragma("omp unroll partial(3)") _Pragma("omp tile sizes(7)") +#define TRANSFORMATION2 +#define TRANSFORMATION3 +#include IMPLEMENTATION_FILE + +#undef DIRECTIVE +#undef TRANSFORMATION1 +#undef TRANSFORMATION2 +#undef TRANSFORMATION3 +#undef FUN_NAME_SUFFIX + +#define FUN_NAME_SUFFIX 11 +#define DIRECTIVE DO_PRAGMA(COMMON_DIRECTIVE COLLAPSE_2) +#define TRANSFORMATION1 DO_PRAGMA(COMMON_TOP_TRANSFORM) +#define TRANSFORMATION2 _Pragma("omp unroll partial(5)") _Pragma("omp tile sizes(7)") _Pragma("omp unroll partial(3)") _Pragma("omp tile sizes(7)") +#define TRANSFORMATION3 +#include IMPLEMENTATION_FILE + +#undef DIRECTIVE +#undef TRANSFORMATION1 +#undef TRANSFORMATION2 +#undef TRANSFORMATION3 +#undef FUN_NAME_SUFFIX + +#define FUN_NAME_SUFFIX 12 +#define DIRECTIVE DO_PRAGMA(COMMON_DIRECTIVE COLLAPSE_3) +#define TRANSFORMATION1 DO_PRAGMA(COMMON_TOP_TRANSFORM) +#define TRANSFORMATION2 +#define TRANSFORMATION3 _Pragma("omp unroll partial(5)") _Pragma("omp tile sizes(7)") _Pragma("omp unroll partial(3)") _Pragma("omp tile sizes(7)") +#include IMPLEMENTATION_FILE + +#undef DIRECTIVE +#undef TRANSFORMATION1 +#undef TRANSFORMATION2 +#undef TRANSFORMATION3 +#undef FUN_NAME_SUFFIX + +#define FUN_NAME_SUFFIX 13 +#define DIRECTIVE DO_PRAGMA(COMMON_DIRECTIVE COLLAPSE_3) +#define TRANSFORMATION1 DO_PRAGMA(COMMON_TOP_TRANSFORM) +#define TRANSFORMATION2 _Pragma("omp tile sizes(7,8)") +#define TRANSFORMATION3 _Pragma("omp unroll partial(3)") _Pragma("omp tile sizes(7)") +#include IMPLEMENTATION_FILE + +int main () +{ + main1 (); + main2 (); + main3 (); + main4 (); + main5 (); + main6 (); + main7 (); + main8 (); + main9 (); + main10 (); + main11 (); + main12 (); + main13 (); + + 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..eb5d3d77eb8 --- /dev/null +++ b/libgomp/testsuite/libgomp.c-c++-common/loop-transforms/unroll-1.c @@ -0,0 +1,78 @@ +/* { dg-additional-options { -Wall -Wno-unknown-pragmas } } */ + +#include + +int compute_sum1 () +{ + int sum = 0; + int i,j; +#pragma omp parallel for reduction(+:sum) lastprivate(j) +#pragma omp unroll partial + for (i = 3; i < 10; ++i) + for (j = -2; j < 7; ++j) + sum++; + + if (j != 7) + __builtin_abort (); + + return sum; +} + +int compute_sum2() +{ + int sum = 0; + int i,j; +#pragma omp parallel for reduction(+:sum) lastprivate(j) +#pragma omp unroll partial(5) + for (i = 3; i < 10; ++i) + for (j = -2; j < 7; ++j) + sum++; + + if (j != 7) + __builtin_abort (); + + return sum; +} + +int compute_sum3() +{ + int sum = 0; + int i,j; +#pragma omp parallel for reduction(+:sum) +#pragma omp unroll partial(1) + for (i = 3; i < 10; ++i) + for (j = -2; j < 7; ++j) + sum++; + + if (j != 7) + __builtin_abort (); + + return sum; +} + +int main () +{ + int result; + result = compute_sum1 (); + if (result != 7 * 9) + { + fprintf (stderr, "%d: Wrong result %d\n", __LINE__, result); + __builtin_abort (); + } + + result = compute_sum2 (); + if (result != 7 * 9) + { + fprintf (stderr, "%d: Wrong result %d\n", __LINE__, result); + __builtin_abort (); + } + + result = compute_sum3 (); + if (result != 7 * 9) + { + fprintf (stderr, "%d: Wrong result %d\n", __LINE__, result); + __builtin_abort (); + } + + return 0; +} diff --git a/libgomp/testsuite/libgomp.c-c++-common/loop-transforms/unroll-non-rect-1.c b/libgomp/testsuite/libgomp.c-c++-common/loop-transforms/unroll-non-rect-1.c new file mode 100644 index 00000000000..7bd9b906235 --- /dev/null +++ b/libgomp/testsuite/libgomp.c-c++-common/loop-transforms/unroll-non-rect-1.c @@ -0,0 +1,131 @@ +/* { dg-additional-options { -Wall -Wno-unknown-pragmas } } */ + +#include +#include + +void test1 () +{ + int sum = 0; + for (int i = -3; i != 1; ++i) + for (int j = -2; j < i * -1; ++j) + sum++; + + if (sum != 14) + { + fprintf (stderr, "%s: Wrong sum: %d\n", __FUNCTION__, sum); + abort (); + } +} + +void test2 () +{ + int sum = 0; + #pragma omp unroll partial + for (int i = -3; i != 1; ++i) + for (int j = -2; j < i * -1; ++j) + sum++; + + if (sum != 14) + { + fprintf (stderr, "%s: Wrong sum: %d\n", __FUNCTION__, sum); + abort (); + } +} + +void test3 () +{ + int sum = 0; + #pragma omp unroll partial + for (int i = -3; i != 1; ++i) + #pragma omp unroll partial + for (int j = -2; j < i * -1; ++j) + sum++; + + if (sum != 14) + { + fprintf (stderr, "%s: Wrong sum: %d\n", __FUNCTION__, sum); + abort (); + } +} + +void test4 () +{ + int sum = 0; +#pragma omp for +#pragma omp unroll partial(5) + for (int i = -3; i != 1; ++i) +#pragma omp unroll partial(2) + for (int j = -2; j < i * -1; ++j) + sum++; + + if (sum != 14) + { + fprintf (stderr, "%s: Wrong sum: %d\n", __FUNCTION__, sum); + abort (); + } +} + +void test5 () +{ + int sum = 0; +#pragma omp parallel for reduction(+:sum) +#pragma omp unroll partial(2) + for (int i = -3; i != 1; ++i) +#pragma omp unroll partial(2) + for (int j = -2; j < i * -1; ++j) + sum++; + + if (sum != 14) + { + fprintf (stderr, "%s: Wrong sum: %d\n", __FUNCTION__, sum); + abort (); + } +} + +void test6 () +{ + int sum = 0; +#pragma omp target parallel for reduction(+:sum) +#pragma omp unroll partial(7) + for (int i = -3; i != 1; ++i) +#pragma omp unroll partial(2) + for (int j = -2; j < i * -1; ++j) + sum++; + + if (sum != 14) + { + fprintf (stderr, "%s: Wrong sum: %d\n", __FUNCTION__, sum); + abort (); + } +} + +void test7 () +{ + int sum = 0; +#pragma omp target teams distribute parallel for reduction(+:sum) +#pragma omp unroll partial(7) + for (int i = -3; i != 1; ++i) +#pragma omp unroll partial(2) + for (int j = -2; j < i * -1; ++j) + sum++; + + if (sum != 14) + { + fprintf (stderr, "%s: Wrong sum: %d\n", __FUNCTION__, sum); + abort (); + } +} + +int +main () +{ + test1 (); + test2 (); + test3 (); + test4 (); + test5 (); + test6 (); + test7 (); + + return 0; +} diff --git a/libgomp/testsuite/libgomp.c-c++-common/target-imperfect-transform-1.c b/libgomp/testsuite/libgomp.c-c++-common/target-imperfect-transform-1.c new file mode 100644 index 00000000000..0e33e028ac2 --- /dev/null +++ b/libgomp/testsuite/libgomp.c-c++-common/target-imperfect-transform-1.c @@ -0,0 +1,82 @@ +/* { dg-do run } */ + +/* Like imperfect-transform.c, but enables offloading. */ + +static int f1count[3], f2count[3]; +#pragma omp declare target enter (f1count, f2count) + +#ifndef __cplusplus +extern void abort (void); +#else +extern "C" void abort (void); +#endif + +int f1 (int depth, int iter) +{ + #pragma omp atomic + f1count[depth]++; + return iter; +} + +int f2 (int depth, int iter) +{ + #pragma omp atomic + f2count[depth]++; + return iter; +} + +void s1 (int a1, int a2, int a3) +{ + int i, j, k; + +#pragma omp target parallel for collapse(2) map(always, tofrom:f1count, f2count) + for (i = 0; i < a1; i++) + { + f1 (0, i); + for (j = 0; j < a2; j++) + { + f1 (1, j); +#pragma omp unroll partial + for (k = 0; k < a3; k++) + { + f1 (2, k); + f2 (2, k); + } + f2 (1, j); + } + f2 (0, i); + } +} + +int +main (void) +{ + f1count[0] = 0; + f1count[1] = 0; + f1count[2] = 0; + f2count[0] = 0; + f2count[1] = 0; + f2count[2] = 0; + + s1 (3, 4, 5); + + /* All intervening code at the same depth must be executed the same + number of times. */ + if (f1count[0] != f2count[0]) abort (); + if (f1count[1] != f2count[1]) abort (); + if (f1count[2] != f2count[2]) abort (); + + /* Intervening code must be executed at least as many times as the loop + that encloses it. */ + if (f1count[0] < 3) abort (); + if (f1count[1] < 3 * 4) abort (); + + /* Intervening code must not be executed more times than the number + of logical iterations. */ + if (f1count[0] > 3 * 4 * 5) abort (); + if (f1count[1] > 3 * 4 * 5) abort (); + + /* Check that the innermost loop body is executed exactly the number + of logical iterations expected. */ + if (f1count[2] != 3 * 4 * 5) abort (); +} diff --git a/libgomp/testsuite/libgomp.c-c++-common/target-imperfect-transform-2.c b/libgomp/testsuite/libgomp.c-c++-common/target-imperfect-transform-2.c new file mode 100644 index 00000000000..78986e8d3ae --- /dev/null +++ b/libgomp/testsuite/libgomp.c-c++-common/target-imperfect-transform-2.c @@ -0,0 +1,82 @@ +/* { dg-do run } */ + +/* Like imperfect-transform.c, but enables offloading. */ + +static int f1count[3], f2count[3]; +#pragma omp declare target enter (f1count, f2count) + +#ifndef __cplusplus +extern void abort (void); +#else +extern "C" void abort (void); +#endif + +int f1 (int depth, int iter) +{ + #pragma omp atomic + f1count[depth]++; + return iter; +} + +int f2 (int depth, int iter) +{ + #pragma omp atomic + f2count[depth]++; + return iter; +} + +void s1 (int a1, int a2, int a3) +{ + int i, j, k; + +#pragma omp target parallel for collapse(2) map(always, tofrom:f1count, f2count) + for (i = 0; i < a1; i++) + { + f1 (0, i); + for (j = 0; j < a2; j++) + { + f1 (1, j); +#pragma omp tile sizes(5) + for (k = 0; k < a3; k++) + { + f1 (2, k); + f2 (2, k); + } + f2 (1, j); + } + f2 (0, i); + } +} + +int +main (void) +{ + f1count[0] = 0; + f1count[1] = 0; + f1count[2] = 0; + f2count[0] = 0; + f2count[1] = 0; + f2count[2] = 0; + + s1 (3, 4, 5); + + /* All intervening code at the same depth must be executed the same + number of times. */ + if (f1count[0] != f2count[0]) abort (); + if (f1count[1] != f2count[1]) abort (); + if (f1count[2] != f2count[2]) abort (); + + /* Intervening code must be executed at least as many times as the loop + that encloses it. */ + if (f1count[0] < 3) abort (); + if (f1count[1] < 3 * 4) abort (); + + /* Intervening code must not be executed more times than the number + of logical iterations. */ + if (f1count[0] > 3 * 4 * 5) abort (); + if (f1count[1] > 3 * 4 * 5) abort (); + + /* Check that the innermost loop body is executed exactly the number + of logical iterations expected. */ + if (f1count[2] != 3 * 4 * 5) abort (); +}