From patchwork Wed Jun 28 13:41:46 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tamar Christina X-Patchwork-Id: 1801093 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=2620:52:3:1:0:246e:9693:128c; helo=sourceware.org; envelope-from=gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Authentication-Results: legolas.ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.a=rsa-sha256 header.s=default header.b=H3Yh1wHe; dkim-atps=neutral Received: from sourceware.org (server2.sourceware.org [IPv6:2620:52:3:1:0:246e:9693:128c]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-384) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4QrjSr5c4Dz20ZV for ; Wed, 28 Jun 2023 23:42:52 +1000 (AEST) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 7F90B3858C31 for ; Wed, 28 Jun 2023 13:42:50 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 7F90B3858C31 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1687959770; bh=h2vmavDAAMhEi1B7s7UbrcmmXw0boOtAzKQB4tyVQyI=; h=Date:To:Cc:Subject:In-Reply-To:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To: From; b=H3Yh1wHeNonEh3wiTZaHqgoKrewG5+bMe2M/ocFIdHWFaheDVjwonrnMPjIEEeDfW C+nqtl3fng9hJJf0gmo4pvvR2EasywtjaHyioJazsNI2ZyLwZ2nBNUqq8nsXeGIt5F 79sLg3WVUx3TGSsdaR/fDicPpCRCgBBpq1zJpnpA= X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from EUR03-DBA-obe.outbound.protection.outlook.com (mail-dbaeur03on2047.outbound.protection.outlook.com [40.107.104.47]) by sourceware.org (Postfix) with ESMTPS id 40E863858032 for ; Wed, 28 Jun 2023 13:42:10 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 40E863858032 Received: from AM6P194CA0029.EURP194.PROD.OUTLOOK.COM (2603:10a6:209:90::42) by DB8PR08MB5500.eurprd08.prod.outlook.com (2603:10a6:10:11e::8) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.6521.26; Wed, 28 Jun 2023 13:42:05 +0000 Received: from AM7EUR03FT058.eop-EUR03.prod.protection.outlook.com (2603:10a6:209:90:cafe::b2) by AM6P194CA0029.outlook.office365.com (2603:10a6:209:90::42) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.6544.19 via Frontend Transport; Wed, 28 Jun 2023 13:42:05 +0000 X-MS-Exchange-Authentication-Results: spf=pass (sender IP is 63.35.35.123) smtp.mailfrom=arm.com; dkim=pass (signature was verified) header.d=armh.onmicrosoft.com;dmarc=pass action=none header.from=arm.com; Received-SPF: Pass (protection.outlook.com: domain of arm.com designates 63.35.35.123 as permitted sender) receiver=protection.outlook.com; client-ip=63.35.35.123; helo=64aa7808-outbound-1.mta.getcheckrecipient.com; pr=C Received: from 64aa7808-outbound-1.mta.getcheckrecipient.com (63.35.35.123) by AM7EUR03FT058.mail.protection.outlook.com (100.127.140.247) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.6544.20 via Frontend Transport; Wed, 28 Jun 2023 13:42:05 +0000 Received: ("Tessian outbound d6c4ee3ba1eb:v142"); Wed, 28 Jun 2023 13:42:05 +0000 X-CheckRecipientChecked: true X-CR-MTA-CID: 760dc4d3ace42c35 X-CR-MTA-TID: 64aa7808 Received: from 93c57f0344e5.1 by 64aa7808-outbound-1.mta.getcheckrecipient.com id DB2DBC78-54C9-41C3-809C-BC513B5D8A7D.1; Wed, 28 Jun 2023 13:41:58 +0000 Received: from EUR01-DB5-obe.outbound.protection.outlook.com by 64aa7808-outbound-1.mta.getcheckrecipient.com with ESMTPS id 93c57f0344e5.1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384); Wed, 28 Jun 2023 13:41:58 +0000 ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=gAAZqY9AxytGGOKZq7jo74Ksmow70OYBMHV74cFyBsyO/3DhUtVBF/tVRGXWkC0pQEq5buFL/PMvB1KWvHaqQvMdOhlhztNrKC8S8pSMdzX5qVZZg6fzCij1yY/y3n0wyDa7zB3IhsePN6nDZGTItDaP8juxTne/d6yf91b0OFO/AoGvL/Er18Hqf6yHTa8ac11jOVN/TyBdcxzq+RlUoJGYlCNWVWdR07wS2cBXhbh0ExYtB+AwLQxhzxeImuwpH2v1VeFL8gEbIN70bVJWa804FaYuSDUS/sko+45z1gyonEr4dBMv7LINrMQ6QLQWEhCqdjeuRifXh2+WW+pZ8Q== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=h2vmavDAAMhEi1B7s7UbrcmmXw0boOtAzKQB4tyVQyI=; b=OkbIsdB1TV+QAJTeBCidiQnVKTg8NBpB20C+TRHQ73PjRGV4u7e6/JqLWp252VWoE+JttsBAaftL/Ie/WzzLho3DY7ql7jIsMfc2HqqKIVNIkY9uTxt43cbe9bz+bEyi2FMsaytwt0ZNzMCj0qtJG5qexwwuwxjE32iSdc36BQA3dzapwT8mXNEstOBh4EfwpEeOsr5yDJnzXadlzyS93kun0HM4EvlKUMKDs9mGUudnvBhlagx8ZKDYWqM9MmvJXg0pAeAXMW+yBgla4BXt+CASAyWJMw7PU+IqOwtwlGPAHNIFag+Mbv5pl9YIuQXkrQCi8nbIxIIK7NZjbg8/og== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=arm.com; dmarc=pass action=none header.from=arm.com; dkim=pass header.d=arm.com; arc=none Authentication-Results-Original: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=arm.com; Received: from VI1PR08MB5325.eurprd08.prod.outlook.com (2603:10a6:803:13e::17) by DBAPR08MB5576.eurprd08.prod.outlook.com (2603:10a6:10:1ae::11) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.6521.26; Wed, 28 Jun 2023 13:41:54 +0000 Received: from VI1PR08MB5325.eurprd08.prod.outlook.com ([fe80::2301:1cde:cfe7:eaf0]) by VI1PR08MB5325.eurprd08.prod.outlook.com ([fe80::2301:1cde:cfe7:eaf0%6]) with mapi id 15.20.6521.026; Wed, 28 Jun 2023 13:41:54 +0000 Date: Wed, 28 Jun 2023 14:41:46 +0100 To: gcc-patches@gcc.gnu.org Cc: nd@arm.com, joseph@codesourcery.com, rguenther@suse.de, nathan@acm.org, jason@redhat.com Subject: [PATCH 2/19][front-end] C/C++ front-end: add pragma GCC novector Message-ID: Content-Disposition: inline In-Reply-To: X-ClientProxiedBy: DM6PR02CA0040.namprd02.prod.outlook.com (2603:10b6:5:177::17) To VI1PR08MB5325.eurprd08.prod.outlook.com (2603:10a6:803:13e::17) MIME-Version: 1.0 X-MS-TrafficTypeDiagnostic: VI1PR08MB5325:EE_|DBAPR08MB5576:EE_|AM7EUR03FT058:EE_|DB8PR08MB5500:EE_ X-MS-Office365-Filtering-Correlation-Id: 785579b6-7ac7-4b4f-aaf2-08db77dd760c x-checkrecipientrouted: true NoDisclaimer: true X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam-Untrusted: BCL:0; X-Microsoft-Antispam-Message-Info-Original: XR2Va+t8ee9NskseHtLMHRByYn3s5e1QfI9id/lSxTTecyouoqDbdgEkVHd1VHimyUMbzWyRoz3lc0s+OPuBrvgXjbOhJGp0xN0dUlsF6Oaw0UL+XOhxh47jzS87fB1s2Ikf2AKJYHqJt+BQEuoB0D7jQolz1VobivDBWCCupipMsjFe/Q9lgYo8h5dw59aM0ljp8tUVQbJ1zW/F+yTtpi4ZDE/+h2HE4XHBI+N+tx2fY+KIL2EBx5TQQDIG4w9m3JPOU7Ozs9++BY59w/ViO2fBuDpM4qdqvtsiopWTET+bzPL6q+40T+KbXnN07IyU4vU7P+zgT9YslgNUkSIYwvnY5QFwUXDKpg9p8scdW4oPDND4aaQNDd1aneaaLso1NwiUEyYYGDBNt6exMdx4IVqMKZpBrmz4DtYEb9bkXPOaZ+eE7Zdcr6j6uBuW8bK0iuOz1FY1Dh2HvPLzbe66q61zMxkPe2qB80aGFGcBT3U= X-Forefront-Antispam-Report-Untrusted: CIP:255.255.255.255; CTRY:; LANG:en; SCL:1; SRV:; IPV:NLI; SFV:NSPM; H:VI1PR08MB5325.eurprd08.prod.outlook.com; PTR:; CAT:NONE; SFS:(13230028)(4636009)(136003)(346002)(39860400002)(396003)(376002)(366004)(451199021)(6486002)(2616005)(83380400001)(33964004)(6666004)(6512007)(4743002)(6506007)(26005)(44144004)(2906002)(186003)(478600001)(235185007)(30864003)(44832011)(6916009)(5660300002)(36756003)(4326008)(66946007)(316002)(38100700002)(8936002)(41300700001)(66476007)(8676002)(86362001)(84970400001)(66556008)(2700100001); DIR:OUT; SFP:1101; X-MS-Exchange-Transport-CrossTenantHeadersStamped: DBAPR08MB5576 Original-Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=arm.com; X-EOPAttributedMessage: 0 X-MS-Exchange-Transport-CrossTenantHeadersStripped: AM7EUR03FT058.eop-EUR03.prod.protection.outlook.com X-MS-PublicTrafficType: Email X-MS-Office365-Filtering-Correlation-Id-Prvs: 95fa6741-25ef-42f7-326b-08db77dd6f03 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: +z0I9yjzMvOkqSiksn6En7EIIrtMu9yY2Sr5mp8yQNHOrSMjvd4TlgY30h4ADsm9PpmAc5Gb48PzrqibKpP+xOXse0abblglcQePCt+/rnK29BUc17WWciVIjekqO5HXLS76xwpuipFwO3pM0EdQGGlWNuGsBNRJyjDWREeeD/sIimp26908M+MQ0ioD5JeSwWXE6XFYIln1D1ITxn6Etr/INCwarSMV16s60UZSOeVbsfdhDQ03PTVlgpLGDSg2PJrsWbXpV2/92K/CE3EZXS9ms6A1s/9KBAVK2sI9+g9U7g+Sb76vkJ8qYKe92RFk7dxqgTxjpDyn842ODwPCNmlCy9CBcVoBSb1Ot/l66QPKjM2d3kv9TKumr16+Z4Fnv39q6xA1RqmLvvjljcC0btDIBytvk7ZYzawEhusZtMT0XHzTbd8h44SGwbUJnk0GExqkHYXPw0vk1Itkfy9pCe6FlrN+IhOKxUqBs8ptQRMmTq5MxaA9tyupM6RMFrnhcGp4nD2rTA4EbX8NPa9uD34d7hKv62N2BXtNrS9erAY7u14IQcioFCeWbK/I1tbP4WsrYATZSdN9QHCTQ7e4SPzV45u7WpdC6Z2/28iPuhzLl9uQC7J5aJBOjxbzug/luWwjGQHHB3MfyB28+Uks7bM94lt0PF69Y/zTqt+IG7Zjf2zmc2jISlDpie+GfbXCJB3wT5SOyHpIAk+TkN6uzaUbB3PL+nZ27bCrc5iBtEPuR4t0F2MuIekiKQTyHRCD8NIqh5oHyWWUHTmEgt8bsQ== X-Forefront-Antispam-Report: CIP:63.35.35.123; CTRY:IE; LANG:en; SCL:1; SRV:; IPV:CAL; SFV:NSPM; H:64aa7808-outbound-1.mta.getcheckrecipient.com; PTR:ec2-63-35-35-123.eu-west-1.compute.amazonaws.com; CAT:NONE; SFS:(13230028)(4636009)(136003)(39860400002)(396003)(346002)(376002)(451199021)(40470700004)(36840700001)(46966006)(6512007)(84970400001)(36860700001)(26005)(82310400005)(6916009)(82740400003)(356005)(44832011)(5660300002)(235185007)(40460700003)(70206006)(86362001)(8936002)(41300700001)(4326008)(316002)(8676002)(81166007)(70586007)(30864003)(40480700001)(107886003)(47076005)(36756003)(6506007)(6486002)(186003)(2906002)(4743002)(83380400001)(44144004)(33964004)(6666004)(336012)(2616005)(478600001)(2700100001); DIR:OUT; SFP:1101; X-OriginatorOrg: arm.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 28 Jun 2023 13:42:05.4295 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: 785579b6-7ac7-4b4f-aaf2-08db77dd760c X-MS-Exchange-CrossTenant-Id: f34e5979-57d9-4aaa-ad4d-b122a662184d X-MS-Exchange-CrossTenant-OriginalAttributedTenantConnectingIp: TenantId=f34e5979-57d9-4aaa-ad4d-b122a662184d; Ip=[63.35.35.123]; Helo=[64aa7808-outbound-1.mta.getcheckrecipient.com] X-MS-Exchange-CrossTenant-AuthSource: AM7EUR03FT058.eop-EUR03.prod.protection.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Anonymous X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: DB8PR08MB5500 X-Spam-Status: No, score=-12.6 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, GIT_PATCH_0, KAM_DMARC_NONE, KAM_LOTSOFHASH, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H2, SPF_HELO_NONE, SPF_NONE, TXREP, T_SCC_BODY_TEXT_LINE, UNPARSEABLE_RELAY 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: , X-Patchwork-Original-From: Tamar Christina via Gcc-patches From: Tamar Christina Reply-To: Tamar Christina Errors-To: gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org Sender: "Gcc-patches" Hi All, FORTRAN currently has a pragma NOVECTOR for indicating that vectorization should not be applied to a particular loop. ICC/ICX also has such a pragma for C and C++ called #pragma novector. As part of this patch series I need a way to easily turn off vectorization of particular loops, particularly for testsuite reasons. This patch proposes a #pragma GCC novector that does the same for C and C++ as gfortan does for FORTRAN and what ICX/ICX does for C and C++. I added only some basic tests here, but the next patch in the series uses this in the testsuite in about ~800 tests. Bootstrapped Regtested on aarch64-none-linux-gnu and no issues. Ok for master? Thanks, Tamar gcc/c-family/ChangeLog: * c-pragma.h (enum pragma_kind): Add PRAGMA_NOVECTOR. * c-pragma.cc (init_pragma): Use it. gcc/c/ChangeLog: * c-parser.cc (c_parser_while_statement, c_parser_do_statement, c_parser_for_statement, c_parser_statement_after_labels, c_parse_pragma_novector, c_parser_pragma): Wire through novector and default to false. gcc/cp/ChangeLog: * cp-tree.def (RANGE_FOR_STMT): Update comment. * cp-tree.h (RANGE_FOR_NOVECTOR): New. (cp_convert_range_for, finish_while_stmt_cond, finish_do_stmt, finish_for_cond): Add novector param. * init.cc (build_vec_init): Default novector to false. * method.cc (build_comparison_op): Likewise. * parser.cc (cp_parser_statement): Likewise. (cp_parser_for, cp_parser_c_for, cp_parser_range_for, cp_convert_range_for, cp_parser_iteration_statement, cp_parser_omp_for_loop, cp_parser_pragma): Support novector. (cp_parser_pragma_novector): New. * pt.cc (tsubst_expr): Likewise. * semantics.cc (finish_while_stmt_cond, finish_do_stmt, finish_for_cond): Likewise. gcc/ChangeLog: * doc/extend.texi: Document it. * tree-core.h (struct tree_base): Add lang_flag_7 and reduce spare0. * tree.h (TREE_LANG_FLAG_7): New. gcc/testsuite/ChangeLog: * g++.dg/vect/vect-novector-pragma.cc: New test. * gcc.dg/vect/vect-novector-pragma.c: New test. --- inline copy of patch -- diff --git a/gcc/c-family/c-pragma.h b/gcc/c-family/c-pragma.h index 9cc95ab3ee376628dbef2485b84e6008210fa8fc..99cf2e8bd1c05537c198470f1aaa0a5a9da4e576 100644 --- diff --git a/gcc/c-family/c-pragma.h b/gcc/c-family/c-pragma.h index 9cc95ab3ee376628dbef2485b84e6008210fa8fc..99cf2e8bd1c05537c198470f1aaa0a5a9da4e576 100644 --- a/gcc/c-family/c-pragma.h +++ b/gcc/c-family/c-pragma.h @@ -87,6 +87,7 @@ enum pragma_kind { PRAGMA_GCC_PCH_PREPROCESS, PRAGMA_IVDEP, PRAGMA_UNROLL, + PRAGMA_NOVECTOR, PRAGMA_FIRST_EXTERNAL }; diff --git a/gcc/c-family/c-pragma.cc b/gcc/c-family/c-pragma.cc index 0d2b333cebbed32423d5dc6fd2a3ac0ce0bf8b94..848a850b8e123ff1c6ae1ec4b7f8ccbd599b1a88 100644 --- a/gcc/c-family/c-pragma.cc +++ b/gcc/c-family/c-pragma.cc @@ -1862,6 +1862,10 @@ init_pragma (void) cpp_register_deferred_pragma (parse_in, "GCC", "unroll", PRAGMA_UNROLL, false, false); + if (!flag_preprocess_only) + cpp_register_deferred_pragma (parse_in, "GCC", "novector", PRAGMA_NOVECTOR, + false, false); + #ifdef HANDLE_PRAGMA_PACK_WITH_EXPANSION c_register_pragma_with_expansion (0, "pack", handle_pragma_pack); #else diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc index 24a6eb6e4596f32c477e3f1c3f98b9792f7bc92c..9d35fe68704c8aca197bcd4805a146c655959621 100644 --- a/gcc/c/c-parser.cc +++ b/gcc/c/c-parser.cc @@ -1572,9 +1572,11 @@ static tree c_parser_c99_block_statement (c_parser *, bool *, location_t * = NULL); static void c_parser_if_statement (c_parser *, bool *, vec *); static void c_parser_switch_statement (c_parser *, bool *); -static void c_parser_while_statement (c_parser *, bool, unsigned short, bool *); -static void c_parser_do_statement (c_parser *, bool, unsigned short); -static void c_parser_for_statement (c_parser *, bool, unsigned short, bool *); +static void c_parser_while_statement (c_parser *, bool, unsigned short, bool, + bool *); +static void c_parser_do_statement (c_parser *, bool, unsigned short, bool); +static void c_parser_for_statement (c_parser *, bool, unsigned short, bool, + bool *); static tree c_parser_asm_statement (c_parser *); static tree c_parser_asm_operands (c_parser *); static tree c_parser_asm_goto_operands (c_parser *); @@ -6644,13 +6646,13 @@ c_parser_statement_after_labels (c_parser *parser, bool *if_p, c_parser_switch_statement (parser, if_p); break; case RID_WHILE: - c_parser_while_statement (parser, false, 0, if_p); + c_parser_while_statement (parser, false, 0, false, if_p); break; case RID_DO: - c_parser_do_statement (parser, false, 0); + c_parser_do_statement (parser, false, 0, false); break; case RID_FOR: - c_parser_for_statement (parser, false, 0, if_p); + c_parser_for_statement (parser, false, 0, false, if_p); break; case RID_GOTO: c_parser_consume_token (parser); @@ -7146,7 +7148,7 @@ c_parser_switch_statement (c_parser *parser, bool *if_p) static void c_parser_while_statement (c_parser *parser, bool ivdep, unsigned short unroll, - bool *if_p) + bool novector, bool *if_p) { tree block, cond, body; unsigned char save_in_statement; @@ -7168,6 +7170,11 @@ c_parser_while_statement (c_parser *parser, bool ivdep, unsigned short unroll, build_int_cst (integer_type_node, annot_expr_unroll_kind), build_int_cst (integer_type_node, unroll)); + if (novector && cond != error_mark_node) + cond = build3 (ANNOTATE_EXPR, TREE_TYPE (cond), cond, + build_int_cst (integer_type_node, + annot_expr_no_vector_kind), + integer_zero_node); save_in_statement = in_statement; in_statement = IN_ITERATION_STMT; @@ -7199,7 +7206,8 @@ c_parser_while_statement (c_parser *parser, bool ivdep, unsigned short unroll, */ static void -c_parser_do_statement (c_parser *parser, bool ivdep, unsigned short unroll) +c_parser_do_statement (c_parser *parser, bool ivdep, unsigned short unroll, + bool novector) { tree block, cond, body; unsigned char save_in_statement; @@ -7228,6 +7236,11 @@ c_parser_do_statement (c_parser *parser, bool ivdep, unsigned short unroll) build_int_cst (integer_type_node, annot_expr_unroll_kind), build_int_cst (integer_type_node, unroll)); + if (novector && cond != error_mark_node) + cond = build3 (ANNOTATE_EXPR, TREE_TYPE (cond), cond, + build_int_cst (integer_type_node, + annot_expr_no_vector_kind), + integer_zero_node); if (!c_parser_require (parser, CPP_SEMICOLON, "expected %<;%>")) c_parser_skip_to_end_of_block_or_statement (parser); @@ -7296,7 +7309,7 @@ c_parser_do_statement (c_parser *parser, bool ivdep, unsigned short unroll) static void c_parser_for_statement (c_parser *parser, bool ivdep, unsigned short unroll, - bool *if_p) + bool novector, bool *if_p) { tree block, cond, incr, body; unsigned char save_in_statement; @@ -7430,6 +7443,12 @@ c_parser_for_statement (c_parser *parser, bool ivdep, unsigned short unroll, "with % pragma"); cond = error_mark_node; } + else if (novector) + { + c_parser_error (parser, "missing loop condition in loop " + "with % pragma"); + cond = error_mark_node; + } else { c_parser_consume_token (parser); @@ -7452,6 +7471,11 @@ c_parser_for_statement (c_parser *parser, bool ivdep, unsigned short unroll, build_int_cst (integer_type_node, annot_expr_unroll_kind), build_int_cst (integer_type_node, unroll)); + if (novector && cond != error_mark_node) + cond = build3 (ANNOTATE_EXPR, TREE_TYPE (cond), cond, + build_int_cst (integer_type_node, + annot_expr_no_vector_kind), + integer_zero_node); } /* Parse the increment expression (the third expression in a for-statement). In the case of a foreach-statement, this is @@ -13037,6 +13061,16 @@ c_parse_pragma_ivdep (c_parser *parser) return true; } +/* Parse a pragma GCC novector. */ + +static bool +c_parse_pragma_novector (c_parser *parser) +{ + c_parser_consume_pragma (parser); + c_parser_skip_to_pragma_eol (parser); + return true; +} + /* Parse a pragma GCC unroll. */ static unsigned short @@ -13264,11 +13298,12 @@ c_parser_pragma (c_parser *parser, enum pragma_context context, bool *if_p) case PRAGMA_IVDEP: { const bool ivdep = c_parse_pragma_ivdep (parser); - unsigned short unroll; + unsigned short unroll = 0; + bool novector = false; if (c_parser_peek_token (parser)->pragma_kind == PRAGMA_UNROLL) unroll = c_parser_pragma_unroll (parser); - else - unroll = 0; + if (c_parser_peek_token (parser)->pragma_kind == PRAGMA_NOVECTOR) + novector = c_parse_pragma_novector (parser); if (!c_parser_next_token_is_keyword (parser, RID_FOR) && !c_parser_next_token_is_keyword (parser, RID_WHILE) && !c_parser_next_token_is_keyword (parser, RID_DO)) @@ -13277,22 +13312,48 @@ c_parser_pragma (c_parser *parser, enum pragma_context context, bool *if_p) return false; } if (c_parser_next_token_is_keyword (parser, RID_FOR)) - c_parser_for_statement (parser, ivdep, unroll, if_p); + c_parser_for_statement (parser, ivdep, unroll, novector, if_p); else if (c_parser_next_token_is_keyword (parser, RID_WHILE)) - c_parser_while_statement (parser, ivdep, unroll, if_p); + c_parser_while_statement (parser, ivdep, unroll, novector, if_p); else - c_parser_do_statement (parser, ivdep, unroll); + c_parser_do_statement (parser, ivdep, unroll, novector); } return true; case PRAGMA_UNROLL: { unsigned short unroll = c_parser_pragma_unroll (parser); - bool ivdep; + bool ivdep = false; + bool novector = false; if (c_parser_peek_token (parser)->pragma_kind == PRAGMA_IVDEP) ivdep = c_parse_pragma_ivdep (parser); + if (c_parser_peek_token (parser)->pragma_kind == PRAGMA_NOVECTOR) + novector = c_parse_pragma_novector (parser); + if (!c_parser_next_token_is_keyword (parser, RID_FOR) + && !c_parser_next_token_is_keyword (parser, RID_WHILE) + && !c_parser_next_token_is_keyword (parser, RID_DO)) + { + c_parser_error (parser, "for, while or do statement expected"); + return false; + } + if (c_parser_next_token_is_keyword (parser, RID_FOR)) + c_parser_for_statement (parser, ivdep, unroll, novector, if_p); + else if (c_parser_next_token_is_keyword (parser, RID_WHILE)) + c_parser_while_statement (parser, ivdep, unroll, novector, if_p); else - ivdep = false; + c_parser_do_statement (parser, ivdep, unroll, novector); + } + return true; + + case PRAGMA_NOVECTOR: + { + bool novector = c_parse_pragma_novector (parser); + unsigned short unroll = 0; + bool ivdep = false; + if (c_parser_peek_token (parser)->pragma_kind == PRAGMA_IVDEP) + ivdep = c_parse_pragma_ivdep (parser); + if (c_parser_peek_token (parser)->pragma_kind == PRAGMA_UNROLL) + unroll = c_parser_pragma_unroll (parser); if (!c_parser_next_token_is_keyword (parser, RID_FOR) && !c_parser_next_token_is_keyword (parser, RID_WHILE) && !c_parser_next_token_is_keyword (parser, RID_DO)) @@ -13301,11 +13362,11 @@ c_parser_pragma (c_parser *parser, enum pragma_context context, bool *if_p) return false; } if (c_parser_next_token_is_keyword (parser, RID_FOR)) - c_parser_for_statement (parser, ivdep, unroll, if_p); + c_parser_for_statement (parser, ivdep, unroll, novector, if_p); else if (c_parser_next_token_is_keyword (parser, RID_WHILE)) - c_parser_while_statement (parser, ivdep, unroll, if_p); + c_parser_while_statement (parser, ivdep, unroll, novector, if_p); else - c_parser_do_statement (parser, ivdep, unroll); + c_parser_do_statement (parser, ivdep, unroll, novector); } return true; diff --git a/gcc/cp/cp-tree.def b/gcc/cp/cp-tree.def index 0e66ca70e00caa1dc4beada1024ace32954e2aaf..c13c8ea98a523c4ef1c55a11e02d5da9db7e367e 100644 --- a/gcc/cp/cp-tree.def +++ b/gcc/cp/cp-tree.def @@ -305,8 +305,8 @@ DEFTREECODE (IF_STMT, "if_stmt", tcc_statement, 4) /* Used to represent a range-based `for' statement. The operands are RANGE_FOR_DECL, RANGE_FOR_EXPR, RANGE_FOR_BODY, RANGE_FOR_SCOPE, - RANGE_FOR_UNROLL, and RANGE_FOR_INIT_STMT, respectively. Only used in - templates. */ + RANGE_FOR_UNROLL, RANGE_FOR_NOVECTOR and RANGE_FOR_INIT_STMT, + respectively. Only used in templates. */ DEFTREECODE (RANGE_FOR_STMT, "range_for_stmt", tcc_statement, 6) /* Used to represent an expression statement. Use `EXPR_STMT_EXPR' to diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 8398223311194837441107cb335d497ff5f5ec1c..50b0f20817a168b5e9ac58db59ad44233f079e11 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -5377,6 +5377,7 @@ get_vec_init_expr (tree t) #define RANGE_FOR_UNROLL(NODE) TREE_OPERAND (RANGE_FOR_STMT_CHECK (NODE), 4) #define RANGE_FOR_INIT_STMT(NODE) TREE_OPERAND (RANGE_FOR_STMT_CHECK (NODE), 5) #define RANGE_FOR_IVDEP(NODE) TREE_LANG_FLAG_6 (RANGE_FOR_STMT_CHECK (NODE)) +#define RANGE_FOR_NOVECTOR(NODE) TREE_LANG_FLAG_7 (RANGE_FOR_STMT_CHECK (NODE)) /* STMT_EXPR accessor. */ #define STMT_EXPR_STMT(NODE) TREE_OPERAND (STMT_EXPR_CHECK (NODE), 0) @@ -7286,7 +7287,7 @@ extern bool maybe_clone_body (tree); /* In parser.cc */ extern tree cp_convert_range_for (tree, tree, tree, tree, unsigned int, bool, - unsigned short); + unsigned short, bool); extern void cp_convert_omp_range_for (tree &, vec *, tree &, tree &, tree &, tree &, tree &, tree &); extern void cp_finish_omp_range_for (tree, tree); @@ -7609,16 +7610,19 @@ extern void begin_else_clause (tree); extern void finish_else_clause (tree); extern void finish_if_stmt (tree); extern tree begin_while_stmt (void); -extern void finish_while_stmt_cond (tree, tree, bool, unsigned short); +extern void finish_while_stmt_cond (tree, tree, bool, unsigned short, + bool); extern void finish_while_stmt (tree); extern tree begin_do_stmt (void); extern void finish_do_body (tree); -extern void finish_do_stmt (tree, tree, bool, unsigned short); +extern void finish_do_stmt (tree, tree, bool, unsigned short, + bool); extern tree finish_return_stmt (tree); extern tree begin_for_scope (tree *); extern tree begin_for_stmt (tree, tree); extern void finish_init_stmt (tree); -extern void finish_for_cond (tree, tree, bool, unsigned short); +extern void finish_for_cond (tree, tree, bool, unsigned short, + bool); extern void finish_for_expr (tree, tree); extern void finish_for_stmt (tree); extern tree begin_range_for_stmt (tree, tree); diff --git a/gcc/cp/init.cc b/gcc/cp/init.cc index af6e30f511e142c7a594e742d128b2bf0aa8fb8d..5b735b27e6f5bc6b439ae64665902f4f1ca76f95 100644 --- a/gcc/cp/init.cc +++ b/gcc/cp/init.cc @@ -4846,7 +4846,7 @@ build_vec_init (tree base, tree maxindex, tree init, finish_init_stmt (for_stmt); finish_for_cond (build2 (GT_EXPR, boolean_type_node, iterator, build_int_cst (TREE_TYPE (iterator), -1)), - for_stmt, false, 0); + for_stmt, false, 0, false); /* We used to pass this decrement to finish_for_expr; now we add it to elt_init below so it's part of the same full-expression as the initialization, and thus happens before any potentially throwing diff --git a/gcc/cp/method.cc b/gcc/cp/method.cc index 91cf943f11089c0e6bcbe8377daa4e016f956d56..fce49c796199c2c65cd70684e2942fea1b6b2ebd 100644 --- a/gcc/cp/method.cc +++ b/gcc/cp/method.cc @@ -1645,7 +1645,8 @@ build_comparison_op (tree fndecl, bool defining, tsubst_flags_t complain) add_stmt (idx); finish_init_stmt (for_stmt); finish_for_cond (build2 (LE_EXPR, boolean_type_node, idx, - maxval), for_stmt, false, 0); + maxval), for_stmt, false, 0, + false); finish_for_expr (cp_build_unary_op (PREINCREMENT_EXPR, TARGET_EXPR_SLOT (idx), false, complain), diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc index dd3665c8ccf48a8a0b1ba2c06400fe50999ea240..0bc110121d51ee13258b7ff0e4ad7851b4eae78e 100644 --- a/gcc/cp/parser.cc +++ b/gcc/cp/parser.cc @@ -2324,15 +2324,15 @@ static tree cp_parser_selection_statement static tree cp_parser_condition (cp_parser *); static tree cp_parser_iteration_statement - (cp_parser *, bool *, bool, unsigned short); + (cp_parser *, bool *, bool, unsigned short, bool); static bool cp_parser_init_statement (cp_parser *, tree *decl); static tree cp_parser_for - (cp_parser *, bool, unsigned short); + (cp_parser *, bool, unsigned short, bool); static tree cp_parser_c_for - (cp_parser *, tree, tree, bool, unsigned short); + (cp_parser *, tree, tree, bool, unsigned short, bool); static tree cp_parser_range_for - (cp_parser *, tree, tree, tree, bool, unsigned short, bool); + (cp_parser *, tree, tree, tree, bool, unsigned short, bool, bool); static void do_range_for_auto_deduction (tree, tree, tree, unsigned int); static tree cp_parser_perform_range_for_lookup @@ -12414,7 +12414,8 @@ cp_parser_statement (cp_parser* parser, tree in_statement_expr, case RID_DO: case RID_FOR: std_attrs = process_stmt_hotness_attribute (std_attrs, attrs_loc); - statement = cp_parser_iteration_statement (parser, if_p, false, 0); + statement = cp_parser_iteration_statement (parser, if_p, false, 0, + false); break; case RID_BREAK: @@ -13594,7 +13595,8 @@ cp_parser_condition (cp_parser* parser) not included. */ static tree -cp_parser_for (cp_parser *parser, bool ivdep, unsigned short unroll) +cp_parser_for (cp_parser *parser, bool ivdep, unsigned short unroll, + bool novector) { tree init, scope, decl; bool is_range_for; @@ -13624,14 +13626,14 @@ cp_parser_for (cp_parser *parser, bool ivdep, unsigned short unroll) if (is_range_for) return cp_parser_range_for (parser, scope, init, decl, ivdep, unroll, - false); + novector, false); else - return cp_parser_c_for (parser, scope, init, ivdep, unroll); + return cp_parser_c_for (parser, scope, init, ivdep, unroll, novector); } static tree cp_parser_c_for (cp_parser *parser, tree scope, tree init, bool ivdep, - unsigned short unroll) + unsigned short unroll, bool novector) { /* Normal for loop */ tree condition = NULL_TREE; @@ -13658,7 +13660,13 @@ cp_parser_c_for (cp_parser *parser, tree scope, tree init, bool ivdep, "% pragma"); condition = error_mark_node; } - finish_for_cond (condition, stmt, ivdep, unroll); + else if (novector) + { + cp_parser_error (parser, "missing loop condition in loop with " + "% pragma"); + condition = error_mark_node; + } + finish_for_cond (condition, stmt, ivdep, unroll, novector); /* Look for the `;'. */ cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON); @@ -13682,7 +13690,8 @@ cp_parser_c_for (cp_parser *parser, tree scope, tree init, bool ivdep, static tree cp_parser_range_for (cp_parser *parser, tree scope, tree init, tree range_decl, - bool ivdep, unsigned short unroll, bool is_omp) + bool ivdep, unsigned short unroll, bool novector, + bool is_omp) { tree stmt, range_expr; auto_vec bindings; @@ -13758,6 +13767,8 @@ cp_parser_range_for (cp_parser *parser, tree scope, tree init, tree range_decl, RANGE_FOR_IVDEP (stmt) = 1; if (unroll) RANGE_FOR_UNROLL (stmt) = build_int_cst (integer_type_node, unroll); + if (novector) + RANGE_FOR_NOVECTOR (stmt) = 1; finish_range_for_decl (stmt, range_decl, range_expr); if (!type_dependent_expression_p (range_expr) /* do_auto_deduction doesn't mess with template init-lists. */ @@ -13770,7 +13781,7 @@ cp_parser_range_for (cp_parser *parser, tree scope, tree init, tree range_decl, stmt = begin_for_stmt (scope, init); stmt = cp_convert_range_for (stmt, range_decl, range_expr, decomp_first_name, decomp_cnt, ivdep, - unroll); + unroll, novector); } return stmt; } @@ -13948,7 +13959,7 @@ warn_for_range_copy (tree decl, tree expr) tree cp_convert_range_for (tree statement, tree range_decl, tree range_expr, tree decomp_first_name, unsigned int decomp_cnt, - bool ivdep, unsigned short unroll) + bool ivdep, unsigned short unroll, bool novector) { tree begin, end; tree iter_type, begin_expr, end_expr; @@ -14008,7 +14019,7 @@ cp_convert_range_for (tree statement, tree range_decl, tree range_expr, begin, ERROR_MARK, end, ERROR_MARK, NULL_TREE, NULL, tf_warning_or_error); - finish_for_cond (condition, statement, ivdep, unroll); + finish_for_cond (condition, statement, ivdep, unroll, novector); /* The new increment expression. */ expression = finish_unary_op_expr (input_location, @@ -14175,7 +14186,7 @@ cp_parser_range_for_member_function (tree range, tree identifier) static tree cp_parser_iteration_statement (cp_parser* parser, bool *if_p, bool ivdep, - unsigned short unroll) + unsigned short unroll, bool novector) { cp_token *token; enum rid keyword; @@ -14209,7 +14220,7 @@ cp_parser_iteration_statement (cp_parser* parser, bool *if_p, bool ivdep, parens.require_open (parser); /* Parse the condition. */ condition = cp_parser_condition (parser); - finish_while_stmt_cond (condition, statement, ivdep, unroll); + finish_while_stmt_cond (condition, statement, ivdep, unroll, novector); /* Look for the `)'. */ parens.require_close (parser); /* Parse the dependent statement. */ @@ -14244,7 +14255,7 @@ cp_parser_iteration_statement (cp_parser* parser, bool *if_p, bool ivdep, /* Parse the expression. */ expression = cp_parser_expression (parser); /* We're done with the do-statement. */ - finish_do_stmt (expression, statement, ivdep, unroll); + finish_do_stmt (expression, statement, ivdep, unroll, novector); /* Look for the `)'. */ parens.require_close (parser); /* Look for the `;'. */ @@ -14258,7 +14269,7 @@ cp_parser_iteration_statement (cp_parser* parser, bool *if_p, bool ivdep, matching_parens parens; parens.require_open (parser); - statement = cp_parser_for (parser, ivdep, unroll); + statement = cp_parser_for (parser, ivdep, unroll, novector); /* Look for the `)'. */ parens.require_close (parser); @@ -43815,7 +43826,7 @@ cp_parser_omp_for_loop (cp_parser *parser, enum tree_code code, tree clauses, cp_parser_require (parser, CPP_COLON, RT_COLON); init = cp_parser_range_for (parser, NULL_TREE, NULL_TREE, decl, - false, 0, true); + false, 0, true, false); cp_convert_omp_range_for (this_pre_body, for_block, decl, orig_decl, init, orig_init, @@ -49300,6 +49311,15 @@ cp_parser_pragma_unroll (cp_parser *parser, cp_token *pragma_tok) return unroll; } +/* Parse a pragma GCC novector. */ + +static bool +cp_parser_pragma_novector (cp_parser *parser, cp_token *pragma_tok) +{ + cp_parser_skip_to_pragma_eol (parser, pragma_tok); + return true; +} + /* Normal parsing of a pragma token. Here we can (and must) use the regular lexer. */ @@ -49613,17 +49633,33 @@ cp_parser_pragma (cp_parser *parser, enum pragma_context context, bool *if_p) break; } const bool ivdep = cp_parser_pragma_ivdep (parser, pragma_tok); - unsigned short unroll; + unsigned short unroll = 0; + bool novector = false; cp_token *tok = cp_lexer_peek_token (the_parser->lexer); - if (tok->type == CPP_PRAGMA - && cp_parser_pragma_kind (tok) == PRAGMA_UNROLL) + + while (tok->type == CPP_PRAGMA) { - tok = cp_lexer_consume_token (parser->lexer); - unroll = cp_parser_pragma_unroll (parser, tok); - tok = cp_lexer_peek_token (the_parser->lexer); + switch (cp_parser_pragma_kind (tok)) + { + case PRAGMA_UNROLL: + { + tok = cp_lexer_consume_token (parser->lexer); + unroll = cp_parser_pragma_unroll (parser, tok); + tok = cp_lexer_peek_token (the_parser->lexer); + break; + } + case PRAGMA_NOVECTOR: + { + tok = cp_lexer_consume_token (parser->lexer); + novector = cp_parser_pragma_novector (parser, tok); + tok = cp_lexer_peek_token (the_parser->lexer); + break; + } + default: + gcc_unreachable (); + } } - else - unroll = 0; + if (tok->type != CPP_KEYWORD || (tok->keyword != RID_FOR && tok->keyword != RID_WHILE @@ -49632,7 +49668,7 @@ cp_parser_pragma (cp_parser *parser, enum pragma_context context, bool *if_p) cp_parser_error (parser, "for, while or do statement expected"); return false; } - cp_parser_iteration_statement (parser, if_p, ivdep, unroll); + cp_parser_iteration_statement (parser, if_p, ivdep, unroll, novector); return true; } @@ -49646,17 +49682,82 @@ cp_parser_pragma (cp_parser *parser, enum pragma_context context, bool *if_p) } const unsigned short unroll = cp_parser_pragma_unroll (parser, pragma_tok); - bool ivdep; + bool ivdep = false; + bool novector = false; cp_token *tok = cp_lexer_peek_token (the_parser->lexer); - if (tok->type == CPP_PRAGMA - && cp_parser_pragma_kind (tok) == PRAGMA_IVDEP) + + while (tok->type == CPP_PRAGMA) { - tok = cp_lexer_consume_token (parser->lexer); - ivdep = cp_parser_pragma_ivdep (parser, tok); - tok = cp_lexer_peek_token (the_parser->lexer); + switch (cp_parser_pragma_kind (tok)) + { + case PRAGMA_IVDEP: + { + tok = cp_lexer_consume_token (parser->lexer); + ivdep = cp_parser_pragma_ivdep (parser, tok); + tok = cp_lexer_peek_token (the_parser->lexer); + break; + } + case PRAGMA_NOVECTOR: + { + tok = cp_lexer_consume_token (parser->lexer); + novector = cp_parser_pragma_novector (parser, tok); + tok = cp_lexer_peek_token (the_parser->lexer); + break; + } + default: + gcc_unreachable (); + } } - else - ivdep = false; + + if (tok->type != CPP_KEYWORD + || (tok->keyword != RID_FOR + && tok->keyword != RID_WHILE + && tok->keyword != RID_DO)) + { + cp_parser_error (parser, "for, while or do statement expected"); + return false; + } + cp_parser_iteration_statement (parser, if_p, ivdep, unroll, novector); + return true; + } + + case PRAGMA_NOVECTOR: + { + if (context == pragma_external) + { + error_at (pragma_tok->location, + "%<#pragma GCC novector%> must be inside a function"); + break; + } + const bool novector + = cp_parser_pragma_novector (parser, pragma_tok); + bool ivdep = false; + unsigned short unroll; + cp_token *tok = cp_lexer_peek_token (the_parser->lexer); + + while (tok->type == CPP_PRAGMA) + { + switch (cp_parser_pragma_kind (tok)) + { + case PRAGMA_IVDEP: + { + tok = cp_lexer_consume_token (parser->lexer); + ivdep = cp_parser_pragma_ivdep (parser, tok); + tok = cp_lexer_peek_token (the_parser->lexer); + break; + } + case PRAGMA_UNROLL: + { + tok = cp_lexer_consume_token (parser->lexer); + unroll = cp_parser_pragma_unroll (parser, tok); + tok = cp_lexer_peek_token (the_parser->lexer); + break; + } + default: + gcc_unreachable (); + } + } + if (tok->type != CPP_KEYWORD || (tok->keyword != RID_FOR && tok->keyword != RID_WHILE @@ -49665,7 +49766,7 @@ cp_parser_pragma (cp_parser *parser, enum pragma_context context, bool *if_p) cp_parser_error (parser, "for, while or do statement expected"); return false; } - cp_parser_iteration_statement (parser, if_p, ivdep, unroll); + cp_parser_iteration_statement (parser, if_p, ivdep, unroll, novector); return true; } diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index 2345a18becc1160b9d12f3d88cccb66c8917373c..7b0d01a90e3c4012ec603ebe04cbbb31a7dd1570 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -19036,7 +19036,7 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl) RECUR (FOR_INIT_STMT (t)); finish_init_stmt (stmt); tmp = RECUR (FOR_COND (t)); - finish_for_cond (tmp, stmt, false, 0); + finish_for_cond (tmp, stmt, false, 0, false); tmp = RECUR (FOR_EXPR (t)); finish_for_expr (tmp, stmt); { @@ -19073,6 +19073,7 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl) { RANGE_FOR_IVDEP (stmt) = RANGE_FOR_IVDEP (t); RANGE_FOR_UNROLL (stmt) = RANGE_FOR_UNROLL (t); + RANGE_FOR_NOVECTOR (stmt) = RANGE_FOR_NOVECTOR (t); finish_range_for_decl (stmt, decl, expr); if (decomp_first && decl != error_mark_node) cp_finish_decomp (decl, decomp_first, decomp_cnt); @@ -19083,7 +19084,8 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl) ? tree_to_uhwi (RANGE_FOR_UNROLL (t)) : 0); stmt = cp_convert_range_for (stmt, decl, expr, decomp_first, decomp_cnt, - RANGE_FOR_IVDEP (t), unroll); + RANGE_FOR_IVDEP (t), unroll, + RANGE_FOR_NOVECTOR (t)); } bool prev = note_iteration_stmt_body_start (); @@ -19096,7 +19098,7 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl) case WHILE_STMT: stmt = begin_while_stmt (); tmp = RECUR (WHILE_COND (t)); - finish_while_stmt_cond (tmp, stmt, false, 0); + finish_while_stmt_cond (tmp, stmt, false, 0, false); { bool prev = note_iteration_stmt_body_start (); RECUR (WHILE_BODY (t)); @@ -19114,7 +19116,7 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl) } finish_do_body (stmt); tmp = RECUR (DO_COND (t)); - finish_do_stmt (tmp, stmt, false, 0); + finish_do_stmt (tmp, stmt, false, 0, false); break; case IF_STMT: diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc index 8fb47fd179eb2af2e82bf31d188023e9b9d41de9..b79975109c22ebcfcb060b4f20f32f69f3c3c444 100644 --- a/gcc/cp/semantics.cc +++ b/gcc/cp/semantics.cc @@ -1148,7 +1148,7 @@ begin_while_stmt (void) void finish_while_stmt_cond (tree cond, tree while_stmt, bool ivdep, - unsigned short unroll) + unsigned short unroll, bool novector) { cond = maybe_convert_cond (cond); finish_cond (&WHILE_COND (while_stmt), cond); @@ -1168,6 +1168,13 @@ finish_while_stmt_cond (tree cond, tree while_stmt, bool ivdep, annot_expr_unroll_kind), build_int_cst (integer_type_node, unroll)); + if (novector && cond != error_mark_node) + WHILE_COND (while_stmt) = build3 (ANNOTATE_EXPR, + TREE_TYPE (WHILE_COND (while_stmt)), + WHILE_COND (while_stmt), + build_int_cst (integer_type_node, + annot_expr_no_vector_kind), + integer_zero_node); simplify_loop_decl_cond (&WHILE_COND (while_stmt), WHILE_BODY (while_stmt)); } @@ -1212,7 +1219,8 @@ finish_do_body (tree do_stmt) COND is as indicated. */ void -finish_do_stmt (tree cond, tree do_stmt, bool ivdep, unsigned short unroll) +finish_do_stmt (tree cond, tree do_stmt, bool ivdep, unsigned short unroll, + bool novector) { cond = maybe_convert_cond (cond); end_maybe_infinite_loop (cond); @@ -1229,6 +1237,10 @@ finish_do_stmt (tree cond, tree do_stmt, bool ivdep, unsigned short unroll) cond = build3 (ANNOTATE_EXPR, TREE_TYPE (cond), cond, build_int_cst (integer_type_node, annot_expr_unroll_kind), build_int_cst (integer_type_node, unroll)); + if (novector && cond != error_mark_node) + cond = build3 (ANNOTATE_EXPR, TREE_TYPE (cond), cond, + build_int_cst (integer_type_node, annot_expr_no_vector_kind), + integer_zero_node); DO_COND (do_stmt) = cond; } @@ -1325,7 +1337,7 @@ finish_init_stmt (tree for_stmt) FOR_STMT. */ void -finish_for_cond (tree cond, tree for_stmt, bool ivdep, unsigned short unroll) +finish_for_cond (tree cond, tree for_stmt, bool ivdep, unsigned short unroll, bool novector) { cond = maybe_convert_cond (cond); finish_cond (&FOR_COND (for_stmt), cond); @@ -1345,6 +1357,13 @@ finish_for_cond (tree cond, tree for_stmt, bool ivdep, unsigned short unroll) annot_expr_unroll_kind), build_int_cst (integer_type_node, unroll)); + if (novector && cond != error_mark_node) + FOR_COND (for_stmt) = build3 (ANNOTATE_EXPR, + TREE_TYPE (FOR_COND (for_stmt)), + FOR_COND (for_stmt), + build_int_cst (integer_type_node, + annot_expr_no_vector_kind), + integer_zero_node); simplify_loop_decl_cond (&FOR_COND (for_stmt), FOR_BODY (for_stmt)); } diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi index 3040a9bdea65d27f8d20572b4ed37375f5fe949b..baac6643d1abbf33d592e68aca49ac83e3c29188 100644 --- a/gcc/doc/extend.texi +++ b/gcc/doc/extend.texi @@ -24349,6 +24349,25 @@ void ignore_vec_dep (int *a, int k, int c, int m) @} @end smallexample +@cindex pragma GCC novector +@item #pragma GCC novector + +With this pragma, the programmer asserts that the following loop should be +prevented from executing concurrently with SIMD (single instruction multiple +data) instructions. + +For example, the compiler cannot vectorize the following loop with the pragma: + +@smallexample +void foo (int n, int *a, int *b, int *c) +@{ + int i, j; +#pragma GCC novector + for (i = 0; i < n; ++i) + a[i] = b[i] + c[i]; +@} +@end smallexample + @cindex pragma GCC unroll @var{n} @item #pragma GCC unroll @var{n} diff --git a/gcc/testsuite/g++.dg/vect/vect-novector-pragma.cc b/gcc/testsuite/g++.dg/vect/vect-novector-pragma.cc new file mode 100644 index 0000000000000000000000000000000000000000..4667935b641a06e3004904dc86c4513a78736f04 --- /dev/null +++ b/gcc/testsuite/g++.dg/vect/vect-novector-pragma.cc @@ -0,0 +1,29 @@ +/* { dg-do compile } */ +/* { dg-require-effective-target vect_int } */ + +#include + +void f4 (std::vector a, std::vector b, int n) +{ + int i = 0; +#pragma GCC novector + while (i < (n & -8)) + { + a[i] += b[i]; + i++; + } +} + + +void f5 (std::vector a, std::vector b, int n) +{ + int i = 0; +#pragma GCC novector + for (auto x : b) + { + a[i] += x; + i++; + } +} + +/* { dg-final { scan-tree-dump-not "LOOP VECTORIZED" "vect" } } */ diff --git a/gcc/testsuite/gcc.dg/vect/vect-novector-pragma.c b/gcc/testsuite/gcc.dg/vect/vect-novector-pragma.c new file mode 100644 index 0000000000000000000000000000000000000000..c4b3957711db8f78d26a32634e9bbfdc11a33302 --- /dev/null +++ b/gcc/testsuite/gcc.dg/vect/vect-novector-pragma.c @@ -0,0 +1,34 @@ +/* { dg-do compile } */ +/* { dg-require-effective-target vect_int } */ + +void f1 (int * restrict a, int * restrict b, int n) +{ +#pragma GCC novector + for (int i = 0; i < (n & -8); i++) + a[i] += b[i]; +} + +void f2 (int * restrict a, int * restrict b, int n) +{ + int i = 0; +#pragma GCC novector + do + { + a[i] += b[i]; + i++; + } + while (i < (n & -8)); +} + +void f3 (int * restrict a, int * restrict b, int n) +{ + int i = 0; +#pragma GCC novector + while (i < (n & -8)) + { + a[i] += b[i]; + i++; + } +} + +/* { dg-final { scan-tree-dump-not "LOOP VECTORIZED" "vect" } } */ diff --git a/gcc/tree-core.h b/gcc/tree-core.h index c48a12b378f0b3086747bee43b38e2da3f90b24d..9268a0668390192caac9efaade0a53d9359cf9a7 100644 --- a/gcc/tree-core.h +++ b/gcc/tree-core.h @@ -1063,6 +1063,7 @@ struct GTY(()) tree_base { unsigned lang_flag_4 : 1; unsigned lang_flag_5 : 1; unsigned lang_flag_6 : 1; + unsigned lang_flag_7 : 1; unsigned saturating_flag : 1; unsigned unsigned_flag : 1; @@ -1071,7 +1072,7 @@ struct GTY(()) tree_base { unsigned nameless_flag : 1; unsigned atomic_flag : 1; unsigned unavailable_flag : 1; - unsigned spare0 : 2; + unsigned spare0 : 1; unsigned spare1 : 8; diff --git a/gcc/tree.h b/gcc/tree.h index 1854fe4a7d4d25b0cb55ee70402d5721f8b629ba..e96e8884bf68de77d19c95a87ae1c147460c23df 100644 --- a/gcc/tree.h +++ b/gcc/tree.h @@ -1112,6 +1112,8 @@ extern void omp_clause_range_check_failed (const_tree, const char *, int, (TREE_NOT_CHECK2 (NODE, TREE_VEC, SSA_NAME)->base.u.bits.lang_flag_5) #define TREE_LANG_FLAG_6(NODE) \ (TREE_NOT_CHECK2 (NODE, TREE_VEC, SSA_NAME)->base.u.bits.lang_flag_6) +#define TREE_LANG_FLAG_7(NODE) \ + (TREE_NOT_CHECK2 (NODE, TREE_VEC, SSA_NAME)->base.u.bits.lang_flag_7) /* Define additional fields and accessors for nodes representing constants. */ --- a/gcc/c-family/c-pragma.h +++ b/gcc/c-family/c-pragma.h @@ -87,6 +87,7 @@ enum pragma_kind { PRAGMA_GCC_PCH_PREPROCESS, PRAGMA_IVDEP, PRAGMA_UNROLL, + PRAGMA_NOVECTOR, PRAGMA_FIRST_EXTERNAL }; diff --git a/gcc/c-family/c-pragma.cc b/gcc/c-family/c-pragma.cc index 0d2b333cebbed32423d5dc6fd2a3ac0ce0bf8b94..848a850b8e123ff1c6ae1ec4b7f8ccbd599b1a88 100644 --- a/gcc/c-family/c-pragma.cc +++ b/gcc/c-family/c-pragma.cc @@ -1862,6 +1862,10 @@ init_pragma (void) cpp_register_deferred_pragma (parse_in, "GCC", "unroll", PRAGMA_UNROLL, false, false); + if (!flag_preprocess_only) + cpp_register_deferred_pragma (parse_in, "GCC", "novector", PRAGMA_NOVECTOR, + false, false); + #ifdef HANDLE_PRAGMA_PACK_WITH_EXPANSION c_register_pragma_with_expansion (0, "pack", handle_pragma_pack); #else diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc index 24a6eb6e4596f32c477e3f1c3f98b9792f7bc92c..9d35fe68704c8aca197bcd4805a146c655959621 100644 --- a/gcc/c/c-parser.cc +++ b/gcc/c/c-parser.cc @@ -1572,9 +1572,11 @@ static tree c_parser_c99_block_statement (c_parser *, bool *, location_t * = NULL); static void c_parser_if_statement (c_parser *, bool *, vec *); static void c_parser_switch_statement (c_parser *, bool *); -static void c_parser_while_statement (c_parser *, bool, unsigned short, bool *); -static void c_parser_do_statement (c_parser *, bool, unsigned short); -static void c_parser_for_statement (c_parser *, bool, unsigned short, bool *); +static void c_parser_while_statement (c_parser *, bool, unsigned short, bool, + bool *); +static void c_parser_do_statement (c_parser *, bool, unsigned short, bool); +static void c_parser_for_statement (c_parser *, bool, unsigned short, bool, + bool *); static tree c_parser_asm_statement (c_parser *); static tree c_parser_asm_operands (c_parser *); static tree c_parser_asm_goto_operands (c_parser *); @@ -6644,13 +6646,13 @@ c_parser_statement_after_labels (c_parser *parser, bool *if_p, c_parser_switch_statement (parser, if_p); break; case RID_WHILE: - c_parser_while_statement (parser, false, 0, if_p); + c_parser_while_statement (parser, false, 0, false, if_p); break; case RID_DO: - c_parser_do_statement (parser, false, 0); + c_parser_do_statement (parser, false, 0, false); break; case RID_FOR: - c_parser_for_statement (parser, false, 0, if_p); + c_parser_for_statement (parser, false, 0, false, if_p); break; case RID_GOTO: c_parser_consume_token (parser); @@ -7146,7 +7148,7 @@ c_parser_switch_statement (c_parser *parser, bool *if_p) static void c_parser_while_statement (c_parser *parser, bool ivdep, unsigned short unroll, - bool *if_p) + bool novector, bool *if_p) { tree block, cond, body; unsigned char save_in_statement; @@ -7168,6 +7170,11 @@ c_parser_while_statement (c_parser *parser, bool ivdep, unsigned short unroll, build_int_cst (integer_type_node, annot_expr_unroll_kind), build_int_cst (integer_type_node, unroll)); + if (novector && cond != error_mark_node) + cond = build3 (ANNOTATE_EXPR, TREE_TYPE (cond), cond, + build_int_cst (integer_type_node, + annot_expr_no_vector_kind), + integer_zero_node); save_in_statement = in_statement; in_statement = IN_ITERATION_STMT; @@ -7199,7 +7206,8 @@ c_parser_while_statement (c_parser *parser, bool ivdep, unsigned short unroll, */ static void -c_parser_do_statement (c_parser *parser, bool ivdep, unsigned short unroll) +c_parser_do_statement (c_parser *parser, bool ivdep, unsigned short unroll, + bool novector) { tree block, cond, body; unsigned char save_in_statement; @@ -7228,6 +7236,11 @@ c_parser_do_statement (c_parser *parser, bool ivdep, unsigned short unroll) build_int_cst (integer_type_node, annot_expr_unroll_kind), build_int_cst (integer_type_node, unroll)); + if (novector && cond != error_mark_node) + cond = build3 (ANNOTATE_EXPR, TREE_TYPE (cond), cond, + build_int_cst (integer_type_node, + annot_expr_no_vector_kind), + integer_zero_node); if (!c_parser_require (parser, CPP_SEMICOLON, "expected %<;%>")) c_parser_skip_to_end_of_block_or_statement (parser); @@ -7296,7 +7309,7 @@ c_parser_do_statement (c_parser *parser, bool ivdep, unsigned short unroll) static void c_parser_for_statement (c_parser *parser, bool ivdep, unsigned short unroll, - bool *if_p) + bool novector, bool *if_p) { tree block, cond, incr, body; unsigned char save_in_statement; @@ -7430,6 +7443,12 @@ c_parser_for_statement (c_parser *parser, bool ivdep, unsigned short unroll, "with % pragma"); cond = error_mark_node; } + else if (novector) + { + c_parser_error (parser, "missing loop condition in loop " + "with % pragma"); + cond = error_mark_node; + } else { c_parser_consume_token (parser); @@ -7452,6 +7471,11 @@ c_parser_for_statement (c_parser *parser, bool ivdep, unsigned short unroll, build_int_cst (integer_type_node, annot_expr_unroll_kind), build_int_cst (integer_type_node, unroll)); + if (novector && cond != error_mark_node) + cond = build3 (ANNOTATE_EXPR, TREE_TYPE (cond), cond, + build_int_cst (integer_type_node, + annot_expr_no_vector_kind), + integer_zero_node); } /* Parse the increment expression (the third expression in a for-statement). In the case of a foreach-statement, this is @@ -13037,6 +13061,16 @@ c_parse_pragma_ivdep (c_parser *parser) return true; } +/* Parse a pragma GCC novector. */ + +static bool +c_parse_pragma_novector (c_parser *parser) +{ + c_parser_consume_pragma (parser); + c_parser_skip_to_pragma_eol (parser); + return true; +} + /* Parse a pragma GCC unroll. */ static unsigned short @@ -13264,11 +13298,12 @@ c_parser_pragma (c_parser *parser, enum pragma_context context, bool *if_p) case PRAGMA_IVDEP: { const bool ivdep = c_parse_pragma_ivdep (parser); - unsigned short unroll; + unsigned short unroll = 0; + bool novector = false; if (c_parser_peek_token (parser)->pragma_kind == PRAGMA_UNROLL) unroll = c_parser_pragma_unroll (parser); - else - unroll = 0; + if (c_parser_peek_token (parser)->pragma_kind == PRAGMA_NOVECTOR) + novector = c_parse_pragma_novector (parser); if (!c_parser_next_token_is_keyword (parser, RID_FOR) && !c_parser_next_token_is_keyword (parser, RID_WHILE) && !c_parser_next_token_is_keyword (parser, RID_DO)) @@ -13277,22 +13312,48 @@ c_parser_pragma (c_parser *parser, enum pragma_context context, bool *if_p) return false; } if (c_parser_next_token_is_keyword (parser, RID_FOR)) - c_parser_for_statement (parser, ivdep, unroll, if_p); + c_parser_for_statement (parser, ivdep, unroll, novector, if_p); else if (c_parser_next_token_is_keyword (parser, RID_WHILE)) - c_parser_while_statement (parser, ivdep, unroll, if_p); + c_parser_while_statement (parser, ivdep, unroll, novector, if_p); else - c_parser_do_statement (parser, ivdep, unroll); + c_parser_do_statement (parser, ivdep, unroll, novector); } return true; case PRAGMA_UNROLL: { unsigned short unroll = c_parser_pragma_unroll (parser); - bool ivdep; + bool ivdep = false; + bool novector = false; if (c_parser_peek_token (parser)->pragma_kind == PRAGMA_IVDEP) ivdep = c_parse_pragma_ivdep (parser); + if (c_parser_peek_token (parser)->pragma_kind == PRAGMA_NOVECTOR) + novector = c_parse_pragma_novector (parser); + if (!c_parser_next_token_is_keyword (parser, RID_FOR) + && !c_parser_next_token_is_keyword (parser, RID_WHILE) + && !c_parser_next_token_is_keyword (parser, RID_DO)) + { + c_parser_error (parser, "for, while or do statement expected"); + return false; + } + if (c_parser_next_token_is_keyword (parser, RID_FOR)) + c_parser_for_statement (parser, ivdep, unroll, novector, if_p); + else if (c_parser_next_token_is_keyword (parser, RID_WHILE)) + c_parser_while_statement (parser, ivdep, unroll, novector, if_p); else - ivdep = false; + c_parser_do_statement (parser, ivdep, unroll, novector); + } + return true; + + case PRAGMA_NOVECTOR: + { + bool novector = c_parse_pragma_novector (parser); + unsigned short unroll = 0; + bool ivdep = false; + if (c_parser_peek_token (parser)->pragma_kind == PRAGMA_IVDEP) + ivdep = c_parse_pragma_ivdep (parser); + if (c_parser_peek_token (parser)->pragma_kind == PRAGMA_UNROLL) + unroll = c_parser_pragma_unroll (parser); if (!c_parser_next_token_is_keyword (parser, RID_FOR) && !c_parser_next_token_is_keyword (parser, RID_WHILE) && !c_parser_next_token_is_keyword (parser, RID_DO)) @@ -13301,11 +13362,11 @@ c_parser_pragma (c_parser *parser, enum pragma_context context, bool *if_p) return false; } if (c_parser_next_token_is_keyword (parser, RID_FOR)) - c_parser_for_statement (parser, ivdep, unroll, if_p); + c_parser_for_statement (parser, ivdep, unroll, novector, if_p); else if (c_parser_next_token_is_keyword (parser, RID_WHILE)) - c_parser_while_statement (parser, ivdep, unroll, if_p); + c_parser_while_statement (parser, ivdep, unroll, novector, if_p); else - c_parser_do_statement (parser, ivdep, unroll); + c_parser_do_statement (parser, ivdep, unroll, novector); } return true; diff --git a/gcc/cp/cp-tree.def b/gcc/cp/cp-tree.def index 0e66ca70e00caa1dc4beada1024ace32954e2aaf..c13c8ea98a523c4ef1c55a11e02d5da9db7e367e 100644 --- a/gcc/cp/cp-tree.def +++ b/gcc/cp/cp-tree.def @@ -305,8 +305,8 @@ DEFTREECODE (IF_STMT, "if_stmt", tcc_statement, 4) /* Used to represent a range-based `for' statement. The operands are RANGE_FOR_DECL, RANGE_FOR_EXPR, RANGE_FOR_BODY, RANGE_FOR_SCOPE, - RANGE_FOR_UNROLL, and RANGE_FOR_INIT_STMT, respectively. Only used in - templates. */ + RANGE_FOR_UNROLL, RANGE_FOR_NOVECTOR and RANGE_FOR_INIT_STMT, + respectively. Only used in templates. */ DEFTREECODE (RANGE_FOR_STMT, "range_for_stmt", tcc_statement, 6) /* Used to represent an expression statement. Use `EXPR_STMT_EXPR' to diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 8398223311194837441107cb335d497ff5f5ec1c..50b0f20817a168b5e9ac58db59ad44233f079e11 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -5377,6 +5377,7 @@ get_vec_init_expr (tree t) #define RANGE_FOR_UNROLL(NODE) TREE_OPERAND (RANGE_FOR_STMT_CHECK (NODE), 4) #define RANGE_FOR_INIT_STMT(NODE) TREE_OPERAND (RANGE_FOR_STMT_CHECK (NODE), 5) #define RANGE_FOR_IVDEP(NODE) TREE_LANG_FLAG_6 (RANGE_FOR_STMT_CHECK (NODE)) +#define RANGE_FOR_NOVECTOR(NODE) TREE_LANG_FLAG_7 (RANGE_FOR_STMT_CHECK (NODE)) /* STMT_EXPR accessor. */ #define STMT_EXPR_STMT(NODE) TREE_OPERAND (STMT_EXPR_CHECK (NODE), 0) @@ -7286,7 +7287,7 @@ extern bool maybe_clone_body (tree); /* In parser.cc */ extern tree cp_convert_range_for (tree, tree, tree, tree, unsigned int, bool, - unsigned short); + unsigned short, bool); extern void cp_convert_omp_range_for (tree &, vec *, tree &, tree &, tree &, tree &, tree &, tree &); extern void cp_finish_omp_range_for (tree, tree); @@ -7609,16 +7610,19 @@ extern void begin_else_clause (tree); extern void finish_else_clause (tree); extern void finish_if_stmt (tree); extern tree begin_while_stmt (void); -extern void finish_while_stmt_cond (tree, tree, bool, unsigned short); +extern void finish_while_stmt_cond (tree, tree, bool, unsigned short, + bool); extern void finish_while_stmt (tree); extern tree begin_do_stmt (void); extern void finish_do_body (tree); -extern void finish_do_stmt (tree, tree, bool, unsigned short); +extern void finish_do_stmt (tree, tree, bool, unsigned short, + bool); extern tree finish_return_stmt (tree); extern tree begin_for_scope (tree *); extern tree begin_for_stmt (tree, tree); extern void finish_init_stmt (tree); -extern void finish_for_cond (tree, tree, bool, unsigned short); +extern void finish_for_cond (tree, tree, bool, unsigned short, + bool); extern void finish_for_expr (tree, tree); extern void finish_for_stmt (tree); extern tree begin_range_for_stmt (tree, tree); diff --git a/gcc/cp/init.cc b/gcc/cp/init.cc index af6e30f511e142c7a594e742d128b2bf0aa8fb8d..5b735b27e6f5bc6b439ae64665902f4f1ca76f95 100644 --- a/gcc/cp/init.cc +++ b/gcc/cp/init.cc @@ -4846,7 +4846,7 @@ build_vec_init (tree base, tree maxindex, tree init, finish_init_stmt (for_stmt); finish_for_cond (build2 (GT_EXPR, boolean_type_node, iterator, build_int_cst (TREE_TYPE (iterator), -1)), - for_stmt, false, 0); + for_stmt, false, 0, false); /* We used to pass this decrement to finish_for_expr; now we add it to elt_init below so it's part of the same full-expression as the initialization, and thus happens before any potentially throwing diff --git a/gcc/cp/method.cc b/gcc/cp/method.cc index 91cf943f11089c0e6bcbe8377daa4e016f956d56..fce49c796199c2c65cd70684e2942fea1b6b2ebd 100644 --- a/gcc/cp/method.cc +++ b/gcc/cp/method.cc @@ -1645,7 +1645,8 @@ build_comparison_op (tree fndecl, bool defining, tsubst_flags_t complain) add_stmt (idx); finish_init_stmt (for_stmt); finish_for_cond (build2 (LE_EXPR, boolean_type_node, idx, - maxval), for_stmt, false, 0); + maxval), for_stmt, false, 0, + false); finish_for_expr (cp_build_unary_op (PREINCREMENT_EXPR, TARGET_EXPR_SLOT (idx), false, complain), diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc index dd3665c8ccf48a8a0b1ba2c06400fe50999ea240..0bc110121d51ee13258b7ff0e4ad7851b4eae78e 100644 --- a/gcc/cp/parser.cc +++ b/gcc/cp/parser.cc @@ -2324,15 +2324,15 @@ static tree cp_parser_selection_statement static tree cp_parser_condition (cp_parser *); static tree cp_parser_iteration_statement - (cp_parser *, bool *, bool, unsigned short); + (cp_parser *, bool *, bool, unsigned short, bool); static bool cp_parser_init_statement (cp_parser *, tree *decl); static tree cp_parser_for - (cp_parser *, bool, unsigned short); + (cp_parser *, bool, unsigned short, bool); static tree cp_parser_c_for - (cp_parser *, tree, tree, bool, unsigned short); + (cp_parser *, tree, tree, bool, unsigned short, bool); static tree cp_parser_range_for - (cp_parser *, tree, tree, tree, bool, unsigned short, bool); + (cp_parser *, tree, tree, tree, bool, unsigned short, bool, bool); static void do_range_for_auto_deduction (tree, tree, tree, unsigned int); static tree cp_parser_perform_range_for_lookup @@ -12414,7 +12414,8 @@ cp_parser_statement (cp_parser* parser, tree in_statement_expr, case RID_DO: case RID_FOR: std_attrs = process_stmt_hotness_attribute (std_attrs, attrs_loc); - statement = cp_parser_iteration_statement (parser, if_p, false, 0); + statement = cp_parser_iteration_statement (parser, if_p, false, 0, + false); break; case RID_BREAK: @@ -13594,7 +13595,8 @@ cp_parser_condition (cp_parser* parser) not included. */ static tree -cp_parser_for (cp_parser *parser, bool ivdep, unsigned short unroll) +cp_parser_for (cp_parser *parser, bool ivdep, unsigned short unroll, + bool novector) { tree init, scope, decl; bool is_range_for; @@ -13624,14 +13626,14 @@ cp_parser_for (cp_parser *parser, bool ivdep, unsigned short unroll) if (is_range_for) return cp_parser_range_for (parser, scope, init, decl, ivdep, unroll, - false); + novector, false); else - return cp_parser_c_for (parser, scope, init, ivdep, unroll); + return cp_parser_c_for (parser, scope, init, ivdep, unroll, novector); } static tree cp_parser_c_for (cp_parser *parser, tree scope, tree init, bool ivdep, - unsigned short unroll) + unsigned short unroll, bool novector) { /* Normal for loop */ tree condition = NULL_TREE; @@ -13658,7 +13660,13 @@ cp_parser_c_for (cp_parser *parser, tree scope, tree init, bool ivdep, "% pragma"); condition = error_mark_node; } - finish_for_cond (condition, stmt, ivdep, unroll); + else if (novector) + { + cp_parser_error (parser, "missing loop condition in loop with " + "% pragma"); + condition = error_mark_node; + } + finish_for_cond (condition, stmt, ivdep, unroll, novector); /* Look for the `;'. */ cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON); @@ -13682,7 +13690,8 @@ cp_parser_c_for (cp_parser *parser, tree scope, tree init, bool ivdep, static tree cp_parser_range_for (cp_parser *parser, tree scope, tree init, tree range_decl, - bool ivdep, unsigned short unroll, bool is_omp) + bool ivdep, unsigned short unroll, bool novector, + bool is_omp) { tree stmt, range_expr; auto_vec bindings; @@ -13758,6 +13767,8 @@ cp_parser_range_for (cp_parser *parser, tree scope, tree init, tree range_decl, RANGE_FOR_IVDEP (stmt) = 1; if (unroll) RANGE_FOR_UNROLL (stmt) = build_int_cst (integer_type_node, unroll); + if (novector) + RANGE_FOR_NOVECTOR (stmt) = 1; finish_range_for_decl (stmt, range_decl, range_expr); if (!type_dependent_expression_p (range_expr) /* do_auto_deduction doesn't mess with template init-lists. */ @@ -13770,7 +13781,7 @@ cp_parser_range_for (cp_parser *parser, tree scope, tree init, tree range_decl, stmt = begin_for_stmt (scope, init); stmt = cp_convert_range_for (stmt, range_decl, range_expr, decomp_first_name, decomp_cnt, ivdep, - unroll); + unroll, novector); } return stmt; } @@ -13948,7 +13959,7 @@ warn_for_range_copy (tree decl, tree expr) tree cp_convert_range_for (tree statement, tree range_decl, tree range_expr, tree decomp_first_name, unsigned int decomp_cnt, - bool ivdep, unsigned short unroll) + bool ivdep, unsigned short unroll, bool novector) { tree begin, end; tree iter_type, begin_expr, end_expr; @@ -14008,7 +14019,7 @@ cp_convert_range_for (tree statement, tree range_decl, tree range_expr, begin, ERROR_MARK, end, ERROR_MARK, NULL_TREE, NULL, tf_warning_or_error); - finish_for_cond (condition, statement, ivdep, unroll); + finish_for_cond (condition, statement, ivdep, unroll, novector); /* The new increment expression. */ expression = finish_unary_op_expr (input_location, @@ -14175,7 +14186,7 @@ cp_parser_range_for_member_function (tree range, tree identifier) static tree cp_parser_iteration_statement (cp_parser* parser, bool *if_p, bool ivdep, - unsigned short unroll) + unsigned short unroll, bool novector) { cp_token *token; enum rid keyword; @@ -14209,7 +14220,7 @@ cp_parser_iteration_statement (cp_parser* parser, bool *if_p, bool ivdep, parens.require_open (parser); /* Parse the condition. */ condition = cp_parser_condition (parser); - finish_while_stmt_cond (condition, statement, ivdep, unroll); + finish_while_stmt_cond (condition, statement, ivdep, unroll, novector); /* Look for the `)'. */ parens.require_close (parser); /* Parse the dependent statement. */ @@ -14244,7 +14255,7 @@ cp_parser_iteration_statement (cp_parser* parser, bool *if_p, bool ivdep, /* Parse the expression. */ expression = cp_parser_expression (parser); /* We're done with the do-statement. */ - finish_do_stmt (expression, statement, ivdep, unroll); + finish_do_stmt (expression, statement, ivdep, unroll, novector); /* Look for the `)'. */ parens.require_close (parser); /* Look for the `;'. */ @@ -14258,7 +14269,7 @@ cp_parser_iteration_statement (cp_parser* parser, bool *if_p, bool ivdep, matching_parens parens; parens.require_open (parser); - statement = cp_parser_for (parser, ivdep, unroll); + statement = cp_parser_for (parser, ivdep, unroll, novector); /* Look for the `)'. */ parens.require_close (parser); @@ -43815,7 +43826,7 @@ cp_parser_omp_for_loop (cp_parser *parser, enum tree_code code, tree clauses, cp_parser_require (parser, CPP_COLON, RT_COLON); init = cp_parser_range_for (parser, NULL_TREE, NULL_TREE, decl, - false, 0, true); + false, 0, true, false); cp_convert_omp_range_for (this_pre_body, for_block, decl, orig_decl, init, orig_init, @@ -49300,6 +49311,15 @@ cp_parser_pragma_unroll (cp_parser *parser, cp_token *pragma_tok) return unroll; } +/* Parse a pragma GCC novector. */ + +static bool +cp_parser_pragma_novector (cp_parser *parser, cp_token *pragma_tok) +{ + cp_parser_skip_to_pragma_eol (parser, pragma_tok); + return true; +} + /* Normal parsing of a pragma token. Here we can (and must) use the regular lexer. */ @@ -49613,17 +49633,33 @@ cp_parser_pragma (cp_parser *parser, enum pragma_context context, bool *if_p) break; } const bool ivdep = cp_parser_pragma_ivdep (parser, pragma_tok); - unsigned short unroll; + unsigned short unroll = 0; + bool novector = false; cp_token *tok = cp_lexer_peek_token (the_parser->lexer); - if (tok->type == CPP_PRAGMA - && cp_parser_pragma_kind (tok) == PRAGMA_UNROLL) + + while (tok->type == CPP_PRAGMA) { - tok = cp_lexer_consume_token (parser->lexer); - unroll = cp_parser_pragma_unroll (parser, tok); - tok = cp_lexer_peek_token (the_parser->lexer); + switch (cp_parser_pragma_kind (tok)) + { + case PRAGMA_UNROLL: + { + tok = cp_lexer_consume_token (parser->lexer); + unroll = cp_parser_pragma_unroll (parser, tok); + tok = cp_lexer_peek_token (the_parser->lexer); + break; + } + case PRAGMA_NOVECTOR: + { + tok = cp_lexer_consume_token (parser->lexer); + novector = cp_parser_pragma_novector (parser, tok); + tok = cp_lexer_peek_token (the_parser->lexer); + break; + } + default: + gcc_unreachable (); + } } - else - unroll = 0; + if (tok->type != CPP_KEYWORD || (tok->keyword != RID_FOR && tok->keyword != RID_WHILE @@ -49632,7 +49668,7 @@ cp_parser_pragma (cp_parser *parser, enum pragma_context context, bool *if_p) cp_parser_error (parser, "for, while or do statement expected"); return false; } - cp_parser_iteration_statement (parser, if_p, ivdep, unroll); + cp_parser_iteration_statement (parser, if_p, ivdep, unroll, novector); return true; } @@ -49646,17 +49682,82 @@ cp_parser_pragma (cp_parser *parser, enum pragma_context context, bool *if_p) } const unsigned short unroll = cp_parser_pragma_unroll (parser, pragma_tok); - bool ivdep; + bool ivdep = false; + bool novector = false; cp_token *tok = cp_lexer_peek_token (the_parser->lexer); - if (tok->type == CPP_PRAGMA - && cp_parser_pragma_kind (tok) == PRAGMA_IVDEP) + + while (tok->type == CPP_PRAGMA) { - tok = cp_lexer_consume_token (parser->lexer); - ivdep = cp_parser_pragma_ivdep (parser, tok); - tok = cp_lexer_peek_token (the_parser->lexer); + switch (cp_parser_pragma_kind (tok)) + { + case PRAGMA_IVDEP: + { + tok = cp_lexer_consume_token (parser->lexer); + ivdep = cp_parser_pragma_ivdep (parser, tok); + tok = cp_lexer_peek_token (the_parser->lexer); + break; + } + case PRAGMA_NOVECTOR: + { + tok = cp_lexer_consume_token (parser->lexer); + novector = cp_parser_pragma_novector (parser, tok); + tok = cp_lexer_peek_token (the_parser->lexer); + break; + } + default: + gcc_unreachable (); + } } - else - ivdep = false; + + if (tok->type != CPP_KEYWORD + || (tok->keyword != RID_FOR + && tok->keyword != RID_WHILE + && tok->keyword != RID_DO)) + { + cp_parser_error (parser, "for, while or do statement expected"); + return false; + } + cp_parser_iteration_statement (parser, if_p, ivdep, unroll, novector); + return true; + } + + case PRAGMA_NOVECTOR: + { + if (context == pragma_external) + { + error_at (pragma_tok->location, + "%<#pragma GCC novector%> must be inside a function"); + break; + } + const bool novector + = cp_parser_pragma_novector (parser, pragma_tok); + bool ivdep = false; + unsigned short unroll; + cp_token *tok = cp_lexer_peek_token (the_parser->lexer); + + while (tok->type == CPP_PRAGMA) + { + switch (cp_parser_pragma_kind (tok)) + { + case PRAGMA_IVDEP: + { + tok = cp_lexer_consume_token (parser->lexer); + ivdep = cp_parser_pragma_ivdep (parser, tok); + tok = cp_lexer_peek_token (the_parser->lexer); + break; + } + case PRAGMA_UNROLL: + { + tok = cp_lexer_consume_token (parser->lexer); + unroll = cp_parser_pragma_unroll (parser, tok); + tok = cp_lexer_peek_token (the_parser->lexer); + break; + } + default: + gcc_unreachable (); + } + } + if (tok->type != CPP_KEYWORD || (tok->keyword != RID_FOR && tok->keyword != RID_WHILE @@ -49665,7 +49766,7 @@ cp_parser_pragma (cp_parser *parser, enum pragma_context context, bool *if_p) cp_parser_error (parser, "for, while or do statement expected"); return false; } - cp_parser_iteration_statement (parser, if_p, ivdep, unroll); + cp_parser_iteration_statement (parser, if_p, ivdep, unroll, novector); return true; } diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index 2345a18becc1160b9d12f3d88cccb66c8917373c..7b0d01a90e3c4012ec603ebe04cbbb31a7dd1570 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -19036,7 +19036,7 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl) RECUR (FOR_INIT_STMT (t)); finish_init_stmt (stmt); tmp = RECUR (FOR_COND (t)); - finish_for_cond (tmp, stmt, false, 0); + finish_for_cond (tmp, stmt, false, 0, false); tmp = RECUR (FOR_EXPR (t)); finish_for_expr (tmp, stmt); { @@ -19073,6 +19073,7 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl) { RANGE_FOR_IVDEP (stmt) = RANGE_FOR_IVDEP (t); RANGE_FOR_UNROLL (stmt) = RANGE_FOR_UNROLL (t); + RANGE_FOR_NOVECTOR (stmt) = RANGE_FOR_NOVECTOR (t); finish_range_for_decl (stmt, decl, expr); if (decomp_first && decl != error_mark_node) cp_finish_decomp (decl, decomp_first, decomp_cnt); @@ -19083,7 +19084,8 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl) ? tree_to_uhwi (RANGE_FOR_UNROLL (t)) : 0); stmt = cp_convert_range_for (stmt, decl, expr, decomp_first, decomp_cnt, - RANGE_FOR_IVDEP (t), unroll); + RANGE_FOR_IVDEP (t), unroll, + RANGE_FOR_NOVECTOR (t)); } bool prev = note_iteration_stmt_body_start (); @@ -19096,7 +19098,7 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl) case WHILE_STMT: stmt = begin_while_stmt (); tmp = RECUR (WHILE_COND (t)); - finish_while_stmt_cond (tmp, stmt, false, 0); + finish_while_stmt_cond (tmp, stmt, false, 0, false); { bool prev = note_iteration_stmt_body_start (); RECUR (WHILE_BODY (t)); @@ -19114,7 +19116,7 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl) } finish_do_body (stmt); tmp = RECUR (DO_COND (t)); - finish_do_stmt (tmp, stmt, false, 0); + finish_do_stmt (tmp, stmt, false, 0, false); break; case IF_STMT: diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc index 8fb47fd179eb2af2e82bf31d188023e9b9d41de9..b79975109c22ebcfcb060b4f20f32f69f3c3c444 100644 --- a/gcc/cp/semantics.cc +++ b/gcc/cp/semantics.cc @@ -1148,7 +1148,7 @@ begin_while_stmt (void) void finish_while_stmt_cond (tree cond, tree while_stmt, bool ivdep, - unsigned short unroll) + unsigned short unroll, bool novector) { cond = maybe_convert_cond (cond); finish_cond (&WHILE_COND (while_stmt), cond); @@ -1168,6 +1168,13 @@ finish_while_stmt_cond (tree cond, tree while_stmt, bool ivdep, annot_expr_unroll_kind), build_int_cst (integer_type_node, unroll)); + if (novector && cond != error_mark_node) + WHILE_COND (while_stmt) = build3 (ANNOTATE_EXPR, + TREE_TYPE (WHILE_COND (while_stmt)), + WHILE_COND (while_stmt), + build_int_cst (integer_type_node, + annot_expr_no_vector_kind), + integer_zero_node); simplify_loop_decl_cond (&WHILE_COND (while_stmt), WHILE_BODY (while_stmt)); } @@ -1212,7 +1219,8 @@ finish_do_body (tree do_stmt) COND is as indicated. */ void -finish_do_stmt (tree cond, tree do_stmt, bool ivdep, unsigned short unroll) +finish_do_stmt (tree cond, tree do_stmt, bool ivdep, unsigned short unroll, + bool novector) { cond = maybe_convert_cond (cond); end_maybe_infinite_loop (cond); @@ -1229,6 +1237,10 @@ finish_do_stmt (tree cond, tree do_stmt, bool ivdep, unsigned short unroll) cond = build3 (ANNOTATE_EXPR, TREE_TYPE (cond), cond, build_int_cst (integer_type_node, annot_expr_unroll_kind), build_int_cst (integer_type_node, unroll)); + if (novector && cond != error_mark_node) + cond = build3 (ANNOTATE_EXPR, TREE_TYPE (cond), cond, + build_int_cst (integer_type_node, annot_expr_no_vector_kind), + integer_zero_node); DO_COND (do_stmt) = cond; } @@ -1325,7 +1337,7 @@ finish_init_stmt (tree for_stmt) FOR_STMT. */ void -finish_for_cond (tree cond, tree for_stmt, bool ivdep, unsigned short unroll) +finish_for_cond (tree cond, tree for_stmt, bool ivdep, unsigned short unroll, bool novector) { cond = maybe_convert_cond (cond); finish_cond (&FOR_COND (for_stmt), cond); @@ -1345,6 +1357,13 @@ finish_for_cond (tree cond, tree for_stmt, bool ivdep, unsigned short unroll) annot_expr_unroll_kind), build_int_cst (integer_type_node, unroll)); + if (novector && cond != error_mark_node) + FOR_COND (for_stmt) = build3 (ANNOTATE_EXPR, + TREE_TYPE (FOR_COND (for_stmt)), + FOR_COND (for_stmt), + build_int_cst (integer_type_node, + annot_expr_no_vector_kind), + integer_zero_node); simplify_loop_decl_cond (&FOR_COND (for_stmt), FOR_BODY (for_stmt)); } diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi index 3040a9bdea65d27f8d20572b4ed37375f5fe949b..baac6643d1abbf33d592e68aca49ac83e3c29188 100644 --- a/gcc/doc/extend.texi +++ b/gcc/doc/extend.texi @@ -24349,6 +24349,25 @@ void ignore_vec_dep (int *a, int k, int c, int m) @} @end smallexample +@cindex pragma GCC novector +@item #pragma GCC novector + +With this pragma, the programmer asserts that the following loop should be +prevented from executing concurrently with SIMD (single instruction multiple +data) instructions. + +For example, the compiler cannot vectorize the following loop with the pragma: + +@smallexample +void foo (int n, int *a, int *b, int *c) +@{ + int i, j; +#pragma GCC novector + for (i = 0; i < n; ++i) + a[i] = b[i] + c[i]; +@} +@end smallexample + @cindex pragma GCC unroll @var{n} @item #pragma GCC unroll @var{n} diff --git a/gcc/testsuite/g++.dg/vect/vect-novector-pragma.cc b/gcc/testsuite/g++.dg/vect/vect-novector-pragma.cc new file mode 100644 index 0000000000000000000000000000000000000000..4667935b641a06e3004904dc86c4513a78736f04 --- /dev/null +++ b/gcc/testsuite/g++.dg/vect/vect-novector-pragma.cc @@ -0,0 +1,29 @@ +/* { dg-do compile } */ +/* { dg-require-effective-target vect_int } */ + +#include + +void f4 (std::vector a, std::vector b, int n) +{ + int i = 0; +#pragma GCC novector + while (i < (n & -8)) + { + a[i] += b[i]; + i++; + } +} + + +void f5 (std::vector a, std::vector b, int n) +{ + int i = 0; +#pragma GCC novector + for (auto x : b) + { + a[i] += x; + i++; + } +} + +/* { dg-final { scan-tree-dump-not "LOOP VECTORIZED" "vect" } } */ diff --git a/gcc/testsuite/gcc.dg/vect/vect-novector-pragma.c b/gcc/testsuite/gcc.dg/vect/vect-novector-pragma.c new file mode 100644 index 0000000000000000000000000000000000000000..c4b3957711db8f78d26a32634e9bbfdc11a33302 --- /dev/null +++ b/gcc/testsuite/gcc.dg/vect/vect-novector-pragma.c @@ -0,0 +1,34 @@ +/* { dg-do compile } */ +/* { dg-require-effective-target vect_int } */ + +void f1 (int * restrict a, int * restrict b, int n) +{ +#pragma GCC novector + for (int i = 0; i < (n & -8); i++) + a[i] += b[i]; +} + +void f2 (int * restrict a, int * restrict b, int n) +{ + int i = 0; +#pragma GCC novector + do + { + a[i] += b[i]; + i++; + } + while (i < (n & -8)); +} + +void f3 (int * restrict a, int * restrict b, int n) +{ + int i = 0; +#pragma GCC novector + while (i < (n & -8)) + { + a[i] += b[i]; + i++; + } +} + +/* { dg-final { scan-tree-dump-not "LOOP VECTORIZED" "vect" } } */ diff --git a/gcc/tree-core.h b/gcc/tree-core.h index c48a12b378f0b3086747bee43b38e2da3f90b24d..9268a0668390192caac9efaade0a53d9359cf9a7 100644 --- a/gcc/tree-core.h +++ b/gcc/tree-core.h @@ -1063,6 +1063,7 @@ struct GTY(()) tree_base { unsigned lang_flag_4 : 1; unsigned lang_flag_5 : 1; unsigned lang_flag_6 : 1; + unsigned lang_flag_7 : 1; unsigned saturating_flag : 1; unsigned unsigned_flag : 1; @@ -1071,7 +1072,7 @@ struct GTY(()) tree_base { unsigned nameless_flag : 1; unsigned atomic_flag : 1; unsigned unavailable_flag : 1; - unsigned spare0 : 2; + unsigned spare0 : 1; unsigned spare1 : 8; diff --git a/gcc/tree.h b/gcc/tree.h index 1854fe4a7d4d25b0cb55ee70402d5721f8b629ba..e96e8884bf68de77d19c95a87ae1c147460c23df 100644 --- a/gcc/tree.h +++ b/gcc/tree.h @@ -1112,6 +1112,8 @@ extern void omp_clause_range_check_failed (const_tree, const char *, int, (TREE_NOT_CHECK2 (NODE, TREE_VEC, SSA_NAME)->base.u.bits.lang_flag_5) #define TREE_LANG_FLAG_6(NODE) \ (TREE_NOT_CHECK2 (NODE, TREE_VEC, SSA_NAME)->base.u.bits.lang_flag_6) +#define TREE_LANG_FLAG_7(NODE) \ + (TREE_NOT_CHECK2 (NODE, TREE_VEC, SSA_NAME)->base.u.bits.lang_flag_7) /* Define additional fields and accessors for nodes representing constants. */