From patchwork Sun Jul 23 22:15:20 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sandra Loosemore X-Patchwork-Id: 124554 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a59:9010:0:b0:3e4:2afc:c1 with SMTP id l16csp1451430vqg; Sun, 23 Jul 2023 15:18:33 -0700 (PDT) X-Google-Smtp-Source: APBJJlHDwhZrXfD+1IzAzPiRKTXEr9QEL6mFmKm5tRnO8xldKOToFUuSfBerDZTJOP1wY394yVI/ X-Received: by 2002:a17:906:cc54:b0:988:f93:32e8 with SMTP id mm20-20020a170906cc5400b009880f9332e8mr7803356ejb.26.1690150712777; Sun, 23 Jul 2023 15:18:32 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1690150712; cv=none; d=google.com; s=arc-20160816; b=Y1uWIvoHH8HEc8fiKSZVzZForo8aHcUEtcs6fIcu1fkylN5Mt9yYiEN0sEGgisPghB Ho3EAc85HC/GfkYkv/uE6TDgKLByGwsXokav2jhC9sJ9oAPLsgDRQusf2F4lMSV9AgxE jqAkPY/OY5zXHO+W03McGL0OMgKvKkQpSKOYgJZ/GOoF5Y29DhM2GkWceL408Rwo5wkB ziWZ1lB8WV4sY/PFCLwDxM0DQXwAVczQIXx+OFsRTjA6SEDbMf2xM9oiwDUmXgcT+xx0 5GCt1Px0UH0GbQ4Q97AChdYZw6PqGbusjexb6TDA2XxvaziIEPY74KiVg8b0Qbm4jyhd bSYg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender: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=xQtuPeDvBO4PvyQHza5Fc/BIUqZfSskChBlxLq0iMKs=; fh=x2if1ZpAyqzzvFTN8g3whRDYBVJRV+wEkJNjaYGbcaY=; b=djsdgbZS6IQ3Rj25pwOwfdIBFYHDpf9ZmVT2isTQ0NTOleaKoBRkbtuOBDYMpSk9B5 zkE/2K2BZlFum5PCJTIZib02ABklBNjoswiOwpLGa3s30pYmSjNT2/zLYa85KPubFHJ5 zEEuL2mT/W3Qlih8uJfo7tXD0wHXAB294Ah9fCYx9gy1ols138JtGxt00aseIDcf8hu9 jCUeNCeWxdEv1+DdtOJ1tsZOwyoeElsyfWS3RIReP7rBZJ1cRFGMdRW0mnMzZbcgNnUY dqD8t4scJvqp5d+8YDGBCprd6sgi72bwezHCUm7FlpzviTocXKz7iB5ifG0QpT2rgZS0 MKSQ== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: domain of gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org designates 2620:52:3:1:0:246e:9693:128c as permitted sender) smtp.mailfrom="gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org" Received: from server2.sourceware.org (server2.sourceware.org. [2620:52:3:1:0:246e:9693:128c]) by mx.google.com with ESMTPS id q18-20020a1709060e5200b00988479dc7f1si5210086eji.764.2023.07.23.15.18.32 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 23 Jul 2023 15:18:32 -0700 (PDT) Received-SPF: pass (google.com: domain of gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org designates 2620:52:3:1:0:246e:9693:128c as permitted sender) client-ip=2620:52:3:1:0:246e:9693:128c; Authentication-Results: mx.google.com; spf=pass (google.com: domain of gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org designates 2620:52:3:1:0:246e:9693:128c 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 B3407388216E for ; Sun, 23 Jul 2023 22:17:08 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from esa4.mentor.iphmx.com (esa4.mentor.iphmx.com [68.232.137.252]) by sourceware.org (Postfix) with ESMTPS id 828E4386075A for ; Sun, 23 Jul 2023 22:16:25 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 828E4386075A Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=codesourcery.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=mentor.com X-IronPort-AV: E=Sophos;i="6.01,228,1684828800"; d="scan'208";a="12541451" Received: from orw-gwy-02-in.mentorg.com ([192.94.38.167]) by esa4.mentor.iphmx.com with ESMTP; 23 Jul 2023 14:16:24 -0800 IronPort-SDR: SmlibzomM8aqSfqqriJx3EcR72voXuwetOmhJhsNv5yT6F/5Y8fjapokG9j4/s9YF+eYenTnqp pYlngXnF9A8kw+y04cHOdMkQo4soLrFfJsEQE4omjJg8XeBeXvQ7eYGyO3QXyx/un/R2NJ+8KF u3C7loVxn2IIxQGhqD73bsAzPsKWKNf8MPZ1eVDiHSf19ZQr2h12mypoKnNCpVfi4/cWR8cnEz 7VCI6BXjiro8X+gQijiFCXXS42bbhiXAO3Nvgwr+GxrDyEuZnZOU/Q7sRQPI8llUX4pxjqAnzE nfA= From: Sandra Loosemore To: CC: Subject: [PATCH V2 4/5] OpenMP: New C/C++ testcases for imperfectly nested loops. Date: Sun, 23 Jul 2023 16:15:20 -0600 Message-ID: <20230723221521.3739463-5-sandra@codesourcery.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20230723221521.3739463-1-sandra@codesourcery.com> References: <20230723221521.3739463-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=-9.9 required=5.0 tests=BAYES_00, GIT_PATCH_0, HEADER_FROM_DIFFERENT_DOMAINS, KAM_DMARC_STATUS, SPF_HELO_PASS, SPF_PASS, TXREP, T_SCC_BODY_TEXT_LINE 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.29 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 Sender: "Gcc-patches" X-getmail-retrieved-from-mailbox: INBOX X-GMAIL-THRID: 1772251473368106651 X-GMAIL-MSGID: 1772251473368106651 gcc/testsuite/ChangeLog * c-c++-common/gomp/imperfect-attributes.c: New. * c-c++-common/gomp/imperfect-badloops.c: New. * c-c++-common/gomp/imperfect-blocks.c: New. * c-c++-common/gomp/imperfect-extension.c: New. * c-c++-common/gomp/imperfect-gotos.c: New. * c-c++-common/gomp/imperfect-invalid-scope.c: New. * c-c++-common/gomp/imperfect-labels.c: New. * c-c++-common/gomp/imperfect-legacy-syntax.c: New. * c-c++-common/gomp/imperfect-pragmas.c: New. * c-c++-common/gomp/imperfect1.c: New. * c-c++-common/gomp/imperfect2.c: New. * c-c++-common/gomp/imperfect3.c: New. * c-c++-common/gomp/imperfect4.c: New. * c-c++-common/gomp/imperfect5.c: New. libgomp/ChangeLog * testsuite/libgomp.c-c++-common/imperfect1.c: New. * testsuite/libgomp.c-c++-common/imperfect2.c: New. * testsuite/libgomp.c-c++-common/imperfect3.c: New. * testsuite/libgomp.c-c++-common/imperfect4.c: New. * testsuite/libgomp.c-c++-common/imperfect5.c: New. * testsuite/libgomp.c-c++-common/imperfect6.c: New. * testsuite/libgomp.c-c++-common/target-imperfect1.c: New. * testsuite/libgomp.c-c++-common/target-imperfect2.c: New. * testsuite/libgomp.c-c++-common/target-imperfect3.c: New. * testsuite/libgomp.c-c++-common/target-imperfect4.c: New. --- .../c-c++-common/gomp/imperfect-attributes.c | 81 ++++++++ .../c-c++-common/gomp/imperfect-badloops.c | 50 +++++ .../c-c++-common/gomp/imperfect-blocks.c | 75 ++++++++ .../c-c++-common/gomp/imperfect-extension.c | 55 ++++++ .../c-c++-common/gomp/imperfect-gotos.c | 174 ++++++++++++++++++ .../gomp/imperfect-invalid-scope.c | 77 ++++++++ .../c-c++-common/gomp/imperfect-labels.c | 85 +++++++++ .../gomp/imperfect-legacy-syntax.c | 44 +++++ .../c-c++-common/gomp/imperfect-pragmas.c | 85 +++++++++ gcc/testsuite/c-c++-common/gomp/imperfect1.c | 38 ++++ gcc/testsuite/c-c++-common/gomp/imperfect2.c | 34 ++++ gcc/testsuite/c-c++-common/gomp/imperfect3.c | 33 ++++ gcc/testsuite/c-c++-common/gomp/imperfect4.c | 33 ++++ gcc/testsuite/c-c++-common/gomp/imperfect5.c | 57 ++++++ .../libgomp.c-c++-common/imperfect1.c | 76 ++++++++ .../libgomp.c-c++-common/imperfect2.c | 114 ++++++++++++ .../libgomp.c-c++-common/imperfect3.c | 119 ++++++++++++ .../libgomp.c-c++-common/imperfect4.c | 117 ++++++++++++ .../libgomp.c-c++-common/imperfect5.c | 49 +++++ .../libgomp.c-c++-common/imperfect6.c | 115 ++++++++++++ .../libgomp.c-c++-common/target-imperfect1.c | 81 ++++++++ .../libgomp.c-c++-common/target-imperfect2.c | 122 ++++++++++++ .../libgomp.c-c++-common/target-imperfect3.c | 125 +++++++++++++ .../libgomp.c-c++-common/target-imperfect4.c | 122 ++++++++++++ 24 files changed, 1961 insertions(+) create mode 100644 gcc/testsuite/c-c++-common/gomp/imperfect-attributes.c create mode 100644 gcc/testsuite/c-c++-common/gomp/imperfect-badloops.c create mode 100644 gcc/testsuite/c-c++-common/gomp/imperfect-blocks.c create mode 100644 gcc/testsuite/c-c++-common/gomp/imperfect-extension.c create mode 100644 gcc/testsuite/c-c++-common/gomp/imperfect-gotos.c create mode 100644 gcc/testsuite/c-c++-common/gomp/imperfect-invalid-scope.c create mode 100644 gcc/testsuite/c-c++-common/gomp/imperfect-labels.c create mode 100644 gcc/testsuite/c-c++-common/gomp/imperfect-legacy-syntax.c create mode 100644 gcc/testsuite/c-c++-common/gomp/imperfect-pragmas.c create mode 100644 gcc/testsuite/c-c++-common/gomp/imperfect1.c create mode 100644 gcc/testsuite/c-c++-common/gomp/imperfect2.c create mode 100644 gcc/testsuite/c-c++-common/gomp/imperfect3.c create mode 100644 gcc/testsuite/c-c++-common/gomp/imperfect4.c create mode 100644 gcc/testsuite/c-c++-common/gomp/imperfect5.c create mode 100644 libgomp/testsuite/libgomp.c-c++-common/imperfect1.c create mode 100644 libgomp/testsuite/libgomp.c-c++-common/imperfect2.c create mode 100644 libgomp/testsuite/libgomp.c-c++-common/imperfect3.c create mode 100644 libgomp/testsuite/libgomp.c-c++-common/imperfect4.c create mode 100644 libgomp/testsuite/libgomp.c-c++-common/imperfect5.c create mode 100644 libgomp/testsuite/libgomp.c-c++-common/imperfect6.c create mode 100644 libgomp/testsuite/libgomp.c-c++-common/target-imperfect1.c create mode 100644 libgomp/testsuite/libgomp.c-c++-common/target-imperfect2.c create mode 100644 libgomp/testsuite/libgomp.c-c++-common/target-imperfect3.c create mode 100644 libgomp/testsuite/libgomp.c-c++-common/target-imperfect4.c diff --git a/gcc/testsuite/c-c++-common/gomp/imperfect-attributes.c b/gcc/testsuite/c-c++-common/gomp/imperfect-attributes.c new file mode 100644 index 00000000000..776295ce22a --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/imperfect-attributes.c @@ -0,0 +1,81 @@ +/* { 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. */ + +extern void do_something (void); + +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 j = 0; j < y; j++) /* { dg-error "loop not permitted in intervening code" } */ + do_something (); + } +} + +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 j = 0; j < y; j++) /* { dg-error "loop not permitted in intervening code" } */ + do_something (); + } +} + +/* Similar, but put the attributes on a block wrapping the nested loop + instead. */ + +void imperfect2 (int x, int y) +{ +#pragma omp for collapse (2) + for (int i = 0; i < x; i++) /* { dg-error "not enough nested loops" } */ + { + [[]] + { + for (int j = 0; j < y; j++) /* { dg-error "loop not permitted in intervening code" } */ + do_something (); + } + } +} + +void perfect2 (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 j = 0; j < y; j++) /* { dg-error "loop not permitted in intervening code" } */ + do_something (); + } + } +} + +/* Make sure attributes are accepted in the innermost loop body, which has + no intervening code restrictions. */ + +void imperfect3 (int x, int y) +{ +#pragma omp for collapse (2) + for (int i = 0; i < x; i++) + for (int j = 0; j < y; j++) + { + [[]] do_something (); + } +} + +void perfect3 (int x, int y) +{ +#pragma omp for ordered (2) + for (int i = 0; i < x; i++) + for (int j = 0; j < y; j++) + { + [[]] do_something (); + } +} diff --git a/gcc/testsuite/c-c++-common/gomp/imperfect-badloops.c b/gcc/testsuite/c-c++-common/gomp/imperfect-badloops.c new file mode 100644 index 00000000000..dfd40b6cb2d --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/imperfect-badloops.c @@ -0,0 +1,50 @@ +/* { dg-do compile } */ + +/* This test case is expected to fail due to errors. */ + +int f1 (int depth, int iter); +int f2 (int depth, int iter); +void do_something (void); + +void s1 (int a1, int a2, int a3) +{ + int i, j, k; + +#pragma omp for collapse(3) + for (i = 0; i < a1; i++) + { + f1 (0, i); + if (a1 < a2) + { + int z = 0; + while (z < i) /* { dg-error "loop not permitted in intervening code " } */ + { + do_something (); + z++; + } + do /* { dg-error "loop not permitted in intervening code " } */ + { + do_something (); + z--; + } while (z >= 0); + } + for (j = 0; j < a2; j++) + { + for (k = 0; k < a3; k++) + { + f1 (2, k); + f2 (2, k); + } + f2 (1, j); + } + if (a1 < a3) + { + int z; + for (z = 0; z < i; z++) /* { dg-error "loop not permitted in intervening code " } */ + { + do_something (); + } + } + f2 (0, i); + } +} diff --git a/gcc/testsuite/c-c++-common/gomp/imperfect-blocks.c b/gcc/testsuite/c-c++-common/gomp/imperfect-blocks.c new file mode 100644 index 00000000000..0fea58faf78 --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/imperfect-blocks.c @@ -0,0 +1,75 @@ +/* { dg-do compile } */ + +/* Check that compound statements in intervening code are correctly + handled. */ + +extern void do_something (void); + +void imperfect1 (int x, int y) +{ +#pragma omp for collapse (2) + for (int i = 0; i < x; i++) + { + {} + for (int j = 0; j < y; j++) + do_something (); + } +} + +void perfect1 (int x, int y) +{ +#pragma omp for ordered (2) + for (int i = 0; i < x; i++) /* { dg-error "inner loops must be perfectly nested" } */ + { + {} + for (int j = 0; j < y; j++) + do_something (); + } +} + +void imperfect2 (int x, int y) +{ +#pragma omp for collapse (2) + for (int i = 0; i < x; i++) + { + for (int j = 0; j < y; j++) + do_something (); + {} + } +} + +void perfect2 (int x, int y) +{ +#pragma omp for ordered (2) + for (int i = 0; i < x; i++) /* { dg-error "inner loops must be perfectly nested" } */ + { + for (int j = 0; j < y; j++) + do_something (); + {} + } +} + +void imperfect3 (int x, int y) +{ +#pragma omp for collapse (2) + for (int i = 0; i < x; i++) + { + { do_something (); } + for (int j = 0; j < y; j++) + do_something (); + { do_something (); } + } +} + +void perfect3 (int x, int y) +{ +#pragma omp for ordered (2) + for (int i = 0; i < x; i++) /* { dg-error "inner loops must be perfectly nested" } */ + { + { do_something (); } + for (int j = 0; j < y; j++) + do_something (); + { do_something (); } + } +} + diff --git a/gcc/testsuite/c-c++-common/gomp/imperfect-extension.c b/gcc/testsuite/c-c++-common/gomp/imperfect-extension.c new file mode 100644 index 00000000000..a8a8f9ebe1d --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/imperfect-extension.c @@ -0,0 +1,55 @@ +/* { dg-do compile } */ + +/* Check that __extension__ introduces intervening code. */ + +extern void do_something (void); + +void imperfect1 (int x, int y) +{ +#pragma omp for collapse (2) + for (int i = 0; i < x; i++) /* { dg-error "not enough nested loops" } */ + { + __extension__ ({ + for (int j = 0; j < y; j++) /* { dg-error "loop not permitted in intervening code" } */ + do_something (); + }); + } +} + +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 } */ + { + __extension__ ({ + for (int j = 0; j < y; j++) /* { dg-error "loop not permitted in intervening code" } */ + do_something (); + }); + } +} + +/* Check that we don't barf on __extension__ in the inner loop body. */ +void imperfect2 (int x, int y) +{ +#pragma omp for collapse (2) + for (int i = 0; i < x; i++) + for (int j = 0; j < y; j++) + { + __extension__ ({ + do_something (); + }); + } +} + +void perfect2 (int x, int y) +{ +#pragma omp for ordered (2) + for (int i = 0; i < x; i++) + for (int j = 0; j < y; j++) + { + __extension__ ({ + do_something (); + }); + } +} diff --git a/gcc/testsuite/c-c++-common/gomp/imperfect-gotos.c b/gcc/testsuite/c-c++-common/gomp/imperfect-gotos.c new file mode 100644 index 00000000000..897eed275ec --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/imperfect-gotos.c @@ -0,0 +1,174 @@ +/* { dg-do compile } */ + +/* This file contains tests that are expected to fail. */ + + +/* These jumps are all OK since they are to/from the same structured block. */ + +void f1a (void) +{ +#pragma omp for collapse(2) + for (int i = 0; i < 64; ++i) + { + goto a; a:; + for (int j = 0; j < 64; ++j) + { + goto c; c:; + } + goto b; b:; + } +} + +/* Jump around loop body to/from different structured blocks of intervening + code. */ +void f2a (void) +{ +#pragma omp for collapse(2) + for (int i = 0; i < 64; ++i) + { + goto a; a:; + if (i > 16) goto b; /* { dg-error "invalid branch to/from OpenMP structured block" } */ + for (int j = 0; j < 64; ++j) + { + goto c; c:; + } + goto b; b:; + } +} + +/* Jump into loop body from intervening code. */ +void f3a (void) +{ +#pragma omp for collapse(2) + for (int i = 0; i < 64; ++i) + { + goto a; a:; + if (i > 16) goto c; /* { dg-error "invalid branch to/from OpenMP structured block" } */ + for (int j = 0; j < 64; ++j) + { + c: + ; + } + goto b; b:; + } +} + +/* Jump out of loop body to intervening code. */ +void f4a (void) +{ +#pragma omp for collapse(2) + for (int i = 0; i < 64; ++i) + { + goto a; a:; + for (int j = 0; j < 64; ++j) + if (i > 16) goto c; /* { dg-error "invalid branch to/from OpenMP structured block" } */ + c: + ; + goto b; b:; + } +} + +/* The next group of tests use the GNU extension for local labels. Expected + behavior is the same as the above group. */ + +/* These jumps are all OK since they are to/from the same structured block. */ + +void f1b (void) +{ +#pragma omp for collapse(2) + for (int i = 0; i < 64; ++i) + { + __label__ a, b, c; + goto a; a:; + for (int j = 0; j < 64; ++j) + { + goto c; c:; + } + goto b; b:; + } +} + +/* Jump around loop body to/from different structured blocks of intervening + code. */ +void f2b (void) +{ +#pragma omp for collapse(2) + for (int i = 0; i < 64; ++i) + { + __label__ a, b, c; + goto a; a:; + if (i > 16) goto b; /* { dg-error "invalid branch to/from OpenMP structured block" } */ + for (int j = 0; j < 64; ++j) + { + goto c; c:; + } + goto b; b:; + } +} + +/* Jump into loop body from intervening code. */ +void f3b (void) +{ +#pragma omp for collapse(2) + for (int i = 0; i < 64; ++i) + { + __label__ a, b, c; + goto a; a:; + if (i > 16) goto c; /* { dg-error "invalid branch to/from OpenMP structured block" } */ + for (int j = 0; j < 64; ++j) + { + c: + ; + } + goto b; b:; + } +} + +/* Jump out of loop body to intervening code. */ +void f4b (void) +{ +#pragma omp for collapse(2) + for (int i = 0; i < 64; ++i) + { + __label__ a, b, c; + goto a; a:; + for (int j = 0; j < 64; ++j) + if (i > 16) goto c; /* { dg-error "invalid branch to/from OpenMP structured block" } */ + c: + ; + goto b; b:; + } +} + +/* Test that the even the valid jumps are rejected when intervening code + is not allowed at all. */ + +void f1c (void) +{ +#pragma omp for ordered(2) + for (int i = 0; i < 64; ++i) /* { dg-error "inner loops must be perfectly nested" } */ + { + goto a; a:; + for (int j = 0; j < 64; ++j) + { + goto c; c:; + } + goto b; b:; + } +} + +void f1d (void) +{ +#pragma omp for ordered(2) + for (int i = 0; i < 64; ++i) /* { dg-error "inner loops must be perfectly nested" } */ + { + __label__ a, b, c; + goto a; a:; + for (int j = 0; j < 64; ++j) + { + goto c; c:; + } + goto b; b:; + } +} + diff --git a/gcc/testsuite/c-c++-common/gomp/imperfect-invalid-scope.c b/gcc/testsuite/c-c++-common/gomp/imperfect-invalid-scope.c new file mode 100644 index 00000000000..5c24aae07cc --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/imperfect-invalid-scope.c @@ -0,0 +1,77 @@ +/* { dg-do compile } */ + +/* Check that various cases of invalid references to variables bound + in an intervening code scope are diagnosed and do not ICE. This test + is expected to produce errors. */ + +extern void foo (int, int); + +void f1 (void) +{ +#pragma omp for collapse (2) + for (int i = 0; i < 64; i++) + { + int v = (i + 4) * 2; + for (int j = v; j < 64; j++) /* { dg-error "initializer is bound in intervening code" } */ + foo (i, j); + } +} + +void f2 (void) +{ +#pragma omp for collapse (2) + for (int i = 0; i < 64; i++) + { + int v = (i + 4) * 2; + for (int j = 0; j < v; j++) /* { dg-error "end test is bound in intervening code" } */ + foo (i, j); + } +} + +void f3 (void) +{ +#pragma omp for collapse (2) + for (int i = 0; i < 64; i++) + { + int v = (i + 4) * 2; + for (int j = 0; j < 64; j = j + v) /* { dg-error "increment expression is bound in intervening code" } */ + foo (i, j); + } +} + +void f4 (void) +{ +#pragma omp for collapse (2) + for (int i = 0; i < 64; i++) + { + int v = 8; + for (int j = v; j < 64; j++) /* { dg-error "initializer is bound in intervening code" } */ + foo (i, j); + } +} + +void f5 (void) +{ +#pragma omp for collapse (2) + for (int i = 0; i < 64; i++) + { + int j; + for (j = 0; j < 64; j++) /* { dg-error "loop variable is bound in intervening code" } */ + foo (i, j); + } +} + +void f6 (void) +{ +#pragma omp for collapse (2) + for (int i = 0; i < 64; i++) + { + int j; + { + int v = 8; + for (j = v; j < 64; j++) /* { dg-error "loop variable is bound in intervening code" } */ + /* { dg-error "initializer is bound in intervening code" "" { target *-*-* } .-1 } */ + foo (i, j); + } + } +} diff --git a/gcc/testsuite/c-c++-common/gomp/imperfect-labels.c b/gcc/testsuite/c-c++-common/gomp/imperfect-labels.c new file mode 100644 index 00000000000..b7a7a4c8358 --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/imperfect-labels.c @@ -0,0 +1,85 @@ +/* { dg-do compile } */ + +/* Check that a nested FOR loop with a label on it is treated as + intervening code, since it doesn't match the grammar for canonical + loop nest form. */ + +extern void do_something (void); + +void imperfect1 (int x, int y) +{ +#pragma omp for collapse (2) + for (int i = 0; i < x; i++) /* { dg-error "not enough nested loops" } */ + { + foo: + for (int j = 0; j < y; j++) /* { dg-error "loop not permitted in intervening code" } */ + do_something (); + } +} + +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 } */ + { + foo: + for (int j = 0; j < y; j++) /* { dg-error "loop not permitted in intervening code" } */ + do_something (); + } +} + + +/* Similar, but put the label on a block wrapping the nested loop instead. */ + +void imperfect2 (int x, int y) +{ +#pragma omp for collapse (2) + for (int i = 0; i < x; i++) /* { dg-error "not enough nested loops" } */ + { + foo: + { + for (int j = 0; j < y; j++) /* { dg-error "loop not permitted in intervening code" } */ + do_something (); + } + } +} + +void perfect2 (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 } */ + { + foo: + { + for (int j = 0; j < y; j++) /* { dg-error "loop not permitted in intervening code" } */ + do_something (); + } + } +} + +/* Sanity check that labels are allowed in the innermost loop body. */ + +void imperfect3 (int x, int y) +{ +#pragma omp for collapse (2) + for (int i = 0; i < x; i++) + for (int j = 0; j < y; j++) + { + foo: + do_something (); + } +} + +void perfect3 (int x, int y) +{ +#pragma omp for ordered (2) + for (int i = 0; i < x; i++) + for (int j = 0; j < y; j++) + { + foo: + do_something (); + } +} + diff --git a/gcc/testsuite/c-c++-common/gomp/imperfect-legacy-syntax.c b/gcc/testsuite/c-c++-common/gomp/imperfect-legacy-syntax.c new file mode 100644 index 00000000000..571e067091b --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/imperfect-legacy-syntax.c @@ -0,0 +1,44 @@ +/* { dg-do compile } */ + +/* Braces may enclose a nested FOR even when intervening code is not + permitted. Before GCC implemented OpenMP 5.1 canonical loop syntax + and support for intervening code, it used to ignore empty statements + instead of treating them as intervening code; as an extension, those + are still accepted without complaint even in constructs where intervening + code is not supposed to be valid. */ + +void s1 (int a1, int a2, int a3) +{ + int i, j, k; + +#pragma omp for ordered(3) + for (i = 0; i < a1; i++) + { + for (j = 0; j < a2; j++) + { + for (k = 0; k < a3; k++) + { + } + } + } +} + +void s2 (int a1, int a2, int a3) +{ + int i, j, k; + +#pragma omp for ordered(3) + for (i = 0; i < a1; i++) + { + ; + for (j = 0; j < a2; j++) + { + ; + for (k = 0; k < a3; k++) + { + } + ; + } + ; + } +} diff --git a/gcc/testsuite/c-c++-common/gomp/imperfect-pragmas.c b/gcc/testsuite/c-c++-common/gomp/imperfect-pragmas.c new file mode 100644 index 00000000000..a9f55224158 --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/imperfect-pragmas.c @@ -0,0 +1,85 @@ +/* { dg-do compile } */ + +/* Check that non-statement pragmas are accepted in a canonical loop nest + even when perfect nesting is required. */ + +extern void do_something (void); + +void imperfect1 (int x, int y) +{ +#pragma omp for collapse (2) + for (int i = 0; i < x; i++) + { +#pragma GCC diagnostic push + for (int j = 0; j < y; j++) + do_something (); +#pragma GCC diagnostic pop + } +} + +void perfect1 (int x, int y) +{ +#pragma omp for ordered (2) + for (int i = 0; i < x; i++) + { +#pragma GCC diagnostic push + for (int j = 0; j < y; j++) + do_something (); +#pragma GCC diagnostic pop + } +} + + +/* "GCC unroll" is a statement pragma that consumes the following loop as + a substatement. Thus, the inner loop should be treated as intervening + code rather than part of the loop nest. */ + +void imperfect2 (int x, int y) +{ +#pragma omp for collapse (2) + for (int i = 0; i < x; i++) /* { dg-error "not enough nested loops" } */ + { +#pragma GCC unroll 4 + for (int j = 0; j < y; j++) /* { dg-error "loop not permitted in intervening code" } */ + do_something (); + } +} + +void perfect2 (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 } */ + { +#pragma GCC unroll 4 + for (int j = 0; j < y; j++) /* { dg-error "loop not permitted in intervening code" } */ + do_something (); + } +} + + +/* Check that statement pragmas are accepted in the innermost loop body. */ + +void imperfect3 (int x, int y) +{ +#pragma omp for collapse (2) + for (int i = 0; i < x; i++) + for (int j = 0; j < y; j++) + { +#pragma GCC unroll 4 + for (int k = 0; k < 4; k++) + do_something (); + } +} + +void perfect3 (int x, int y) +{ +#pragma omp for ordered (2) + for (int i = 0; i < x; i++) + for (int j = 0; j < y; j++) + { +#pragma GCC unroll 4 + for (int k = 0; k < 4; k++) + do_something (); + } +} diff --git a/gcc/testsuite/c-c++-common/gomp/imperfect1.c b/gcc/testsuite/c-c++-common/gomp/imperfect1.c new file mode 100644 index 00000000000..705626ad169 --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/imperfect1.c @@ -0,0 +1,38 @@ +/* { dg-do compile } */ + +/* This test case is expected to fail due to errors. */ + +int f1 (int depth, int iter); +int f2 (int depth, int iter); + +void s1 (int a1, int a2, int a3) +{ + int i, j, k; + +#pragma omp for collapse(3) + for (i = 0; i < a1; i++) + { + f1 (0, i); + for (j = 0; j < a2; j++) + { +#pragma omp barrier /* { dg-error "intervening code must not contain OpenMP directives" } */ + f1 (1, j); + if (i == 2) + continue; /* { dg-error "invalid exit" } */ + else + break; /* { dg-error "invalid exit" } */ + for (k = 0; k < a3; k++) + { + f1 (2, k); + f2 (2, k); + } + f2 (1, j); + } + for (k = 0; k < a3; k++) /* { dg-error "loop not permitted in intervening code " } */ + { + f1 (2, k); + f2 (2, k); + } + f2 (0, i); + } +} diff --git a/gcc/testsuite/c-c++-common/gomp/imperfect2.c b/gcc/testsuite/c-c++-common/gomp/imperfect2.c new file mode 100644 index 00000000000..dff17dd3ca5 --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/imperfect2.c @@ -0,0 +1,34 @@ +/* { dg-do compile } */ + +/* This test case is expected to fail due to errors. */ + +/* These functions that are part of the OpenMP runtime API would ordinarily + be declared in omp.h, but we don't have that here. */ +extern int omp_get_num_threads(void); +extern int omp_get_max_threads(void); + +int f1 (int depth, int iter); +int f2 (int depth, int iter); + +void s1 (int a1, int a2, int a3) +{ + int i, j, k; +#pragma omp for collapse(3) + for (i = 0; i < a1; i++) + { + f1 (0, i); + for (j = 0; j < omp_get_num_threads (); j++) /* This is OK */ + { + f1 (1, omp_get_num_threads ()); /* { dg-error "not permitted in intervening code" } */ + for (k = omp_get_num_threads (); k < a3; k++) /* This is OK */ + { + f1 (2, omp_get_num_threads ()); + f2 (2, omp_get_max_threads ()); + } + f2 (1, omp_get_max_threads ()); /* { dg-error "not permitted in intervening code" } */ + } + f2 (0, i); + } +} + + diff --git a/gcc/testsuite/c-c++-common/gomp/imperfect3.c b/gcc/testsuite/c-c++-common/gomp/imperfect3.c new file mode 100644 index 00000000000..ad727ed3170 --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/imperfect3.c @@ -0,0 +1,33 @@ +/* { dg-do compile } */ + +/* This test case is expected to fail due to errors. */ + +/* Test that the imperfectly-nested loops with the ordered clause gives + an error, and that there is only one error (and not one on every + intervening statement). */ + +int f1 (int depth, int iter); +int f2 (int depth, int iter); + +void s1 (int a1, int a2, int a3) +{ + int i, j, k; + +#pragma omp for ordered(3) + for (i = 0; i < a1; i++) /* { dg-error "inner loops must be perfectly nested" } */ + { + f1 (0, i); + for (j = 0; j < a2; j++) + { + f1 (1, j); + for (k = 0; k < a3; k++) + { + f1 (2, k); + f2 (2, k); + } + f2 (1, j); + } + f2 (0, i); + } +} + diff --git a/gcc/testsuite/c-c++-common/gomp/imperfect4.c b/gcc/testsuite/c-c++-common/gomp/imperfect4.c new file mode 100644 index 00000000000..1a0c07cd48e --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/imperfect4.c @@ -0,0 +1,33 @@ +/* { dg-do compile } */ + +/* This test case is expected to fail due to errors. */ + +int f1 (int depth, int iter); +int f2 (int depth, int iter); + +void s1 (int a1, int a2, int a3) +{ + int i, j, k; + +#pragma omp for collapse(4) + for (i = 0; i < a1; i++) /* { dg-error "not enough nested loops" } */ + { + f1 (0, i); + for (j = 0; j < a2; j++) + { + f1 (1, j); + for (k = 0; k < a3; k++) + { + /* According to the grammar, this is intervening code; we + don't know that we are also missing a nested for loop + until we have parsed this whole compound expression. */ +#pragma omp barrier /* { dg-error "intervening code must not contain OpenMP directives" } */ + f1 (2, k); + f2 (2, k); + } + f2 (1, j); + } + f2 (0, i); + } +} + diff --git a/gcc/testsuite/c-c++-common/gomp/imperfect5.c b/gcc/testsuite/c-c++-common/gomp/imperfect5.c new file mode 100644 index 00000000000..585d89ff789 --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/imperfect5.c @@ -0,0 +1,57 @@ +/* { dg-do compile } */ + +/* This test case is expected to fail due to errors. */ + +int f1 (int depth, int iter); +int f2 (int depth, int iter); +int ijk (int x, int y, int z); +void f3 (int sum); + +/* This function isn't particularly meaningful, but it should compile without + error. */ +int s1 (int a1, int a2, int a3) +{ + int i, j, k; + int r = 0; + +#pragma omp simd collapse(3) reduction (inscan, +:r) + for (i = 0; i < a1; i++) + { + for (j = 0; j < a2; j++) + { + for (k = 0; k < a3; k++) + { + r = r + ijk (i, j, k); +#pragma omp scan exclusive (r) + f3 (r); + } + } + } + return r; +} + +/* Adding intervening code should trigger an error. */ +int s2 (int a1, int a2, int a3) +{ + int i, j, k; + int r = 0; + +#pragma omp simd collapse(3) reduction (inscan, +:r) + for (i = 0; i < a1; i++) /* { dg-error "inner loops must be perfectly nested" } */ + { + f1 (0, i); + for (j = 0; j < a2; j++) + { + f1 (1, j); + for (k = 0; k < a3; k++) + { + r = r + ijk (i, j, k); +#pragma omp scan exclusive (r) + f3 (r); + } + f2 (1, j); + } + f2 (0, i); + } + return r; +} diff --git a/libgomp/testsuite/libgomp.c-c++-common/imperfect1.c b/libgomp/testsuite/libgomp.c-c++-common/imperfect1.c new file mode 100644 index 00000000000..cafdcaf25b0 --- /dev/null +++ b/libgomp/testsuite/libgomp.c-c++-common/imperfect1.c @@ -0,0 +1,76 @@ +/* { dg-do run } */ + +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(3) + for (i = 0; i < a1; i++) + { + f1 (0, i); + for (j = 0; j < a2; j++) + { + f1 (1, j); + 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/imperfect2.c b/libgomp/testsuite/libgomp.c-c++-common/imperfect2.c new file mode 100644 index 00000000000..e2098006eab --- /dev/null +++ b/libgomp/testsuite/libgomp.c-c++-common/imperfect2.c @@ -0,0 +1,114 @@ +/* { dg-do run } */ + +static int f1count[3], f2count[3]; +static int g1count[3], g2count[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; +} + +int g1 (int depth, int iter) +{ + g1count[depth]++; + return iter; +} + +int g2 (int depth, int iter) +{ + g2count[depth]++; + return iter; +} + +void s1 (int a1, int a2, int a3) +{ + int i, j, k; + +#pragma omp for collapse(3) + for (i = 0; i < a1; i++) + { + f1 (0, i); + { + g1 (0, i); + for (j = 0; j < a2; j++) + { + f1 (1, j); + { + g1 (1, j); + for (k = 0; k < a3; k++) + { + f1 (2, k); + { + g1 (2, k); + g2 (2, k); + } + f2 (2, k); + } + g2 (1, j); + } + f2 (1, j); + } + g2 (0, i); + } + f2 (0, i); + } +} + +int +main (void) +{ + f1count[0] = 0; + f1count[1] = 0; + f1count[2] = 0; + f2count[0] = 0; + f2count[1] = 0; + f2count[2] = 0; + + g1count[0] = 0; + g1count[1] = 0; + g1count[2] = 0; + g2count[0] = 0; + g2count[1] = 0; + g2count[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 (); + if (g1count[0] != f1count[0]) abort (); + if (g2count[0] != f1count[0]) abort (); + if (g1count[1] != f1count[1]) abort (); + if (g2count[1] != f1count[1]) abort (); + if (g1count[2] != f1count[2]) abort (); + if (g2count[2] != f1count[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/imperfect3.c b/libgomp/testsuite/libgomp.c-c++-common/imperfect3.c new file mode 100644 index 00000000000..feb5e32d1d6 --- /dev/null +++ b/libgomp/testsuite/libgomp.c-c++-common/imperfect3.c @@ -0,0 +1,119 @@ +/* { dg-do run } */ + +/* Like imperfect2.c, but includes bindings in the blocks. */ + +static int f1count[3], f2count[3]; +static int g1count[3], g2count[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; +} + +int g1 (int depth, int iter) +{ + g1count[depth]++; + return iter; +} + +int g2 (int depth, int iter) +{ + g2count[depth]++; + return iter; +} + +void s1 (int a1, int a2, int a3) +{ + int i, j, k; + +#pragma omp for collapse(3) + for (i = 0; i < a1; i++) + { + int local0 = 0; + f1 (local0, i); + { + g1 (local0, i); + for (j = 0; j < a2; j++) + { + int local1 = 1; + f1 (local1, j); + { + g1 (local1, j); + for (k = 0; k < a3; k++) + { + int local2 = 2; + f1 (local2, k); + { + g1 (local2, k); + g2 (local2, k); + } + f2 (local2, k); + } + g2 (local1, j); + } + f2 (local1, j); + } + g2 (local0, i); + } + f2 (local0, i); + } +} + +int +main (void) +{ + f1count[0] = 0; + f1count[1] = 0; + f1count[2] = 0; + f2count[0] = 0; + f2count[1] = 0; + f2count[2] = 0; + + g1count[0] = 0; + g1count[1] = 0; + g1count[2] = 0; + g2count[0] = 0; + g2count[1] = 0; + g2count[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 (); + if (g1count[0] != f1count[0]) abort (); + if (g2count[0] != f1count[0]) abort (); + if (g1count[1] != f1count[1]) abort (); + if (g2count[1] != f1count[1]) abort (); + if (g1count[2] != f1count[2]) abort (); + if (g2count[2] != f1count[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/imperfect4.c b/libgomp/testsuite/libgomp.c-c++-common/imperfect4.c new file mode 100644 index 00000000000..e29301bfbad --- /dev/null +++ b/libgomp/testsuite/libgomp.c-c++-common/imperfect4.c @@ -0,0 +1,117 @@ +/* { dg-do run } */ + +/* Like imperfect2.c, but includes blocks that are themselves intervening + code. */ + +static int f1count[3], f2count[3]; +static int g1count[3], g2count[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; +} + +int g1 (int depth, int iter) +{ + g1count[depth]++; + return iter; +} + +int g2 (int depth, int iter) +{ + g2count[depth]++; + return iter; +} + +void s1 (int a1, int a2, int a3) +{ + int i, j, k; + +#pragma omp for collapse(3) + for (i = 0; i < a1; i++) + { + { f1 (0, i); } + { + g1 (0, i); + for (j = 0; j < a2; j++) + { + { f1 (1, j); } + { + { g1 (1, j); } + for (k = 0; k < a3; k++) + { + f1 (2, k); + { + g1 (2, k); + g2 (2, k); + } + f2 (2, k); + } + { g2 (1, j); } + } + { f2 (1, j); } + } + { g2 (0, i); } + } + { f2 (0, i); } + } +} + +int +main (void) +{ + f1count[0] = 0; + f1count[1] = 0; + f1count[2] = 0; + f2count[0] = 0; + f2count[1] = 0; + f2count[2] = 0; + + g1count[0] = 0; + g1count[1] = 0; + g1count[2] = 0; + g2count[0] = 0; + g2count[1] = 0; + g2count[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 (); + if (g1count[0] != f1count[0]) abort (); + if (g2count[0] != f1count[0]) abort (); + if (g1count[1] != f1count[1]) abort (); + if (g2count[1] != f1count[1]) abort (); + if (g1count[2] != f1count[2]) abort (); + if (g2count[2] != f1count[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/imperfect5.c b/libgomp/testsuite/libgomp.c-c++-common/imperfect5.c new file mode 100644 index 00000000000..7bd4f12d472 --- /dev/null +++ b/libgomp/testsuite/libgomp.c-c++-common/imperfect5.c @@ -0,0 +1,49 @@ +/* { dg-do run } */ + +#ifndef __cplusplus +extern void abort (void); +#else +extern "C" void abort (void); +#endif + +static int inner_loop_count = 0; +static int intervening_code_count = 0; + +void +g (int x, int y) +{ + inner_loop_count++; +} + +int +foo (int imax, int jmax) +{ + int j = 0; + +#pragma omp for collapse(2) + for (int i = 0; i < imax; ++i) + { + /* All the intervening code at the same level must be executed + the same number of times. */ + ++intervening_code_count; + for (int j = 0; j < jmax; ++j) + { + g (i, j); + } + /* This is the outer j, not the one from the inner collapsed loop. */ + ++j; + } + return j; +} + +int +main (void) +{ + int j = foo (5, 3); + if (j != intervening_code_count) + abort (); + if (inner_loop_count != 5 * 3) + abort (); + if (intervening_code_count < 5 || intervening_code_count > 5 * 3) + abort (); +} diff --git a/libgomp/testsuite/libgomp.c-c++-common/imperfect6.c b/libgomp/testsuite/libgomp.c-c++-common/imperfect6.c new file mode 100644 index 00000000000..808c6540890 --- /dev/null +++ b/libgomp/testsuite/libgomp.c-c++-common/imperfect6.c @@ -0,0 +1,115 @@ +/* { dg-do run } */ + +/* Like imperfect4.c, but bind the iteration variables in the loops. */ + +static int f1count[3], f2count[3]; +static int g1count[3], g2count[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; +} + +int g1 (int depth, int iter) +{ + g1count[depth]++; + return iter; +} + +int g2 (int depth, int iter) +{ + g2count[depth]++; + return iter; +} + +void s1 (int a1, int a2, int a3) +{ + +#pragma omp for collapse(3) + for (int i = 0; i < a1; i++) + { + { f1 (0, i); } + { + g1 (0, i); + for (int j = 0; j < a2; j++) + { + { f1 (1, j); } + { + { g1 (1, j); } + for (int k = 0; k < a3; k++) + { + f1 (2, k); + { + g1 (2, k); + g2 (2, k); + } + f2 (2, k); + } + { g2 (1, j); } + } + { f2 (1, j); } + } + { g2 (0, i); } + } + { f2 (0, i); } + } +} + +int +main (void) +{ + f1count[0] = 0; + f1count[1] = 0; + f1count[2] = 0; + f2count[0] = 0; + f2count[1] = 0; + f2count[2] = 0; + + g1count[0] = 0; + g1count[1] = 0; + g1count[2] = 0; + g2count[0] = 0; + g2count[1] = 0; + g2count[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 (); + if (g1count[0] != f1count[0]) abort (); + if (g2count[0] != f1count[0]) abort (); + if (g1count[1] != f1count[1]) abort (); + if (g2count[1] != f1count[1]) abort (); + if (g1count[2] != f1count[2]) abort (); + if (g2count[2] != f1count[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-imperfect1.c b/libgomp/testsuite/libgomp.c-c++-common/target-imperfect1.c new file mode 100644 index 00000000000..53bc611ace3 --- /dev/null +++ b/libgomp/testsuite/libgomp.c-c++-common/target-imperfect1.c @@ -0,0 +1,81 @@ +/* { dg-do run } */ + +/* Like imperfect1.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(3) map(always, tofrom:f1count, f2count) + for (i = 0; i < a1; i++) + { + f1 (0, i); + for (j = 0; j < a2; j++) + { + f1 (1, j); + 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-imperfect2.c b/libgomp/testsuite/libgomp.c-c++-common/target-imperfect2.c new file mode 100644 index 00000000000..bc2901a517e --- /dev/null +++ b/libgomp/testsuite/libgomp.c-c++-common/target-imperfect2.c @@ -0,0 +1,122 @@ +/* { dg-do run } */ + +/* Like imperfect2.c, but enables offloading. */ + +static int f1count[3], f2count[3]; +static int g1count[3], g2count[3]; +#pragma omp declare target enter (f1count, f2count) +#pragma omp declare target enter (g1count, g2count) + +#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; +} + +int g1 (int depth, int iter) +{ + #pragma omp atomic + g1count[depth]++; + return iter; +} + +int g2 (int depth, int iter) +{ + #pragma omp atomic + g2count[depth]++; + return iter; +} + +void s1 (int a1, int a2, int a3) +{ + int i, j, k; + +#pragma omp target parallel for collapse(3) map(always, tofrom:f1count, f2count, g1count, g2count) + for (i = 0; i < a1; i++) + { + f1 (0, i); + { + g1 (0, i); + for (j = 0; j < a2; j++) + { + f1 (1, j); + { + g1 (1, j); + for (k = 0; k < a3; k++) + { + f1 (2, k); + { + g1 (2, k); + g2 (2, k); + } + f2 (2, k); + } + g2 (1, j); + } + f2 (1, j); + } + g2 (0, i); + } + f2 (0, i); + } +} + +int +main (void) +{ + f1count[0] = 0; + f1count[1] = 0; + f1count[2] = 0; + f2count[0] = 0; + f2count[1] = 0; + f2count[2] = 0; + + g1count[0] = 0; + g1count[1] = 0; + g1count[2] = 0; + g2count[0] = 0; + g2count[1] = 0; + g2count[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 (); + if (g1count[0] != f1count[0]) abort (); + if (g2count[0] != f1count[0]) abort (); + if (g1count[1] != f1count[1]) abort (); + if (g2count[1] != f1count[1]) abort (); + if (g1count[2] != f1count[2]) abort (); + if (g2count[2] != f1count[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-imperfect3.c b/libgomp/testsuite/libgomp.c-c++-common/target-imperfect3.c new file mode 100644 index 00000000000..ddcfcf4b7eb --- /dev/null +++ b/libgomp/testsuite/libgomp.c-c++-common/target-imperfect3.c @@ -0,0 +1,125 @@ +/* { dg-do run } */ + +/* Like imperfect3.c, but enables offloading. */ + +static int f1count[3], f2count[3]; +static int g1count[3], g2count[3]; +#pragma omp declare target enter (f1count, f2count) +#pragma omp declare target enter (g1count, g2count) + +#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; +} + +int g1 (int depth, int iter) +{ + #pragma omp atomic + g1count[depth]++; + return iter; +} + +int g2 (int depth, int iter) +{ + #pragma omp atomic + g2count[depth]++; + return iter; +} + +void s1 (int a1, int a2, int a3) +{ + int i, j, k; + +#pragma omp target parallel for collapse(3) map(always, tofrom:f1count, f2count, g1count, g2count) + for (i = 0; i < a1; i++) + { + int local0 = 0; + f1 (local0, i); + { + g1 (local0, i); + for (j = 0; j < a2; j++) + { + int local1 = 1; + f1 (local1, j); + { + g1 (local1, j); + for (k = 0; k < a3; k++) + { + int local2 = 2; + f1 (local2, k); + { + g1 (local2, k); + g2 (local2, k); + } + f2 (local2, k); + } + g2 (local1, j); + } + f2 (local1, j); + } + g2 (local0, i); + } + f2 (local0, i); + } +} + +int +main (void) +{ + f1count[0] = 0; + f1count[1] = 0; + f1count[2] = 0; + f2count[0] = 0; + f2count[1] = 0; + f2count[2] = 0; + + g1count[0] = 0; + g1count[1] = 0; + g1count[2] = 0; + g2count[0] = 0; + g2count[1] = 0; + g2count[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 (); + if (g1count[0] != f1count[0]) abort (); + if (g2count[0] != f1count[0]) abort (); + if (g1count[1] != f1count[1]) abort (); + if (g2count[1] != f1count[1]) abort (); + if (g1count[2] != f1count[2]) abort (); + if (g2count[2] != f1count[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-imperfect4.c b/libgomp/testsuite/libgomp.c-c++-common/target-imperfect4.c new file mode 100644 index 00000000000..ede488977b8 --- /dev/null +++ b/libgomp/testsuite/libgomp.c-c++-common/target-imperfect4.c @@ -0,0 +1,122 @@ +/* { dg-do run } */ + +/* Like imperfect4.c, but enables offloading. */ + +static int f1count[3], f2count[3]; +static int g1count[3], g2count[3]; +#pragma omp declare target enter (f1count, f2count) +#pragma omp declare target enter (g1count, g2count) + +#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; +} + +int g1 (int depth, int iter) +{ + #pragma omp atomic + g1count[depth]++; + return iter; +} + +int g2 (int depth, int iter) +{ + #pragma omp atomic + g2count[depth]++; + return iter; +} + +void s1 (int a1, int a2, int a3) +{ + int i, j, k; + +#pragma omp target parallel for collapse(3) map(always, tofrom:f1count, f2count, g1count, g2count) + for (i = 0; i < a1; i++) + { + { f1 (0, i); } + { + g1 (0, i); + for (j = 0; j < a2; j++) + { + { f1 (1, j); } + { + { g1 (1, j); } + for (k = 0; k < a3; k++) + { + f1 (2, k); + { + g1 (2, k); + g2 (2, k); + } + f2 (2, k); + } + { g2 (1, j); } + } + { f2 (1, j); } + } + { g2 (0, i); } + } + { f2 (0, i); } + } +} + +int +main (void) +{ + f1count[0] = 0; + f1count[1] = 0; + f1count[2] = 0; + f2count[0] = 0; + f2count[1] = 0; + f2count[2] = 0; + + g1count[0] = 0; + g1count[1] = 0; + g1count[2] = 0; + g2count[0] = 0; + g2count[1] = 0; + g2count[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 (); + if (g1count[0] != f1count[0]) abort (); + if (g2count[0] != f1count[0]) abort (); + if (g1count[1] != f1count[1]) abort (); + if (g2count[1] != f1count[1]) abort (); + if (g1count[2] != f1count[2]) abort (); + if (g2count[2] != f1count[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 (); +}