From patchwork Thu Nov 11 08:49:52 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Matthias Kretz X-Patchwork-Id: 47441 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id ABB303858410 for ; Thu, 11 Nov 2021 08:50:13 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from lxmtout2.gsi.de (lxmtout2.gsi.de [140.181.3.112]) by sourceware.org (Postfix) with ESMTPS id 42FC2385842A for ; Thu, 11 Nov 2021 08:49:55 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 42FC2385842A Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=gsi.de Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=gsi.de Received: from localhost (localhost [127.0.0.1]) by lxmtout2.gsi.de (Postfix) with ESMTP id DF601200F33C; Thu, 11 Nov 2021 09:49:53 +0100 (CET) X-Virus-Scanned: Debian amavisd-new at lxmtout2.gsi.de Received: from lxmtout2.gsi.de ([127.0.0.1]) by localhost (lxmtout2.gsi.de [127.0.0.1]) (amavisd-new, port 10024) with LMTP id MSq5qRMIy5je; Thu, 11 Nov 2021 09:49:53 +0100 (CET) Received: from srvex3.campus.gsi.de (unknown [10.10.4.16]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-SHA256 (128/128 bits)) (No client certificate requested) by lxmtout2.gsi.de (Postfix) with ESMTPS id C01E120AE04B; Thu, 11 Nov 2021 09:49:53 +0100 (CET) Received: from excalibur.localnet (140.181.3.12) by srvex3.campus.gsi.de (10.10.4.16) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256_P256) id 15.1.2242.12; Thu, 11 Nov 2021 09:49:53 +0100 From: Matthias Kretz To: Jason Merrill Subject: [PATCH v3] c-family: Add __builtin_assoc_barrier Date: Thu, 11 Nov 2021 09:49:52 +0100 Message-ID: <2187370.SNQ7YSdzHs@excalibur> Organization: GSI Helmholtzzentrum =?utf-8?q?f=C3=BCr?= Schwerionenforschung In-Reply-To: <2930568.SbB2uZ23bb@excalibur> References: <2312888.R4OtGj9PrH@excalibur> <9a9052a4-9b38-57f7-f36a-de247b6aa08e@redhat.com> <2930568.SbB2uZ23bb@excalibur> MIME-Version: 1.0 X-Originating-IP: [140.181.3.12] X-ClientProxiedBy: srvex3.Campus.gsi.de (10.10.4.16) To srvex3.campus.gsi.de (10.10.4.16) X-Spam-Status: No, score=-10.4 required=5.0 tests=BAYES_00, BODY_8BITS, GIT_PATCH_0, KAM_DMARC_STATUS, RCVD_IN_MSPIKE_H2, SPF_PASS, TXREP, T_SPF_HELO_PERMERROR autolearn=ham autolearn_force=no version=3.4.4 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) 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: , Cc: gcc-patches@gcc.gnu.org Errors-To: gcc-patches-bounces+patchwork=sourceware.org@gcc.gnu.org Sender: "Gcc-patches" On Wednesday, 8 September 2021 15:49:27 CET Matthias Kretz wrote: > On Wednesday, 8 September 2021 15:44:28 CEST Jason Merrill wrote: > > On 9/8/21 5:37 AM, Matthias Kretz wrote: > > > On Tuesday, 7 September 2021 19:36:22 CEST Jason Merrill wrote: > > >>> case PAREN_EXPR: > > >>> - RETURN (finish_parenthesized_expr (RECUR (TREE_OPERAND (t, > > >>> 0)))); > > >>> + if (REF_PARENTHESIZED_P (t)) > > >>> + RETURN (finish_parenthesized_expr (RECUR (TREE_OPERAND (t, > > >>> 0)))); > > >>> + else > > >>> + RETURN (RECUR (TREE_OPERAND (t, 0))); > > >> > > >> I think you need to build a new PAREN_EXPR in the assoc barrier case as > > >> well, for it to have any effect in templates. > > > > > > My intent was to ignore __builtin_assoc_barrier in templates / constexpr > > > evaluation since it's not affected by -fassociative-math anyway. Or do > > > you > > > mean something else? > > > > I agree about constexpr, but why wouldn't template instantiations be > > affected by -fassociative-math like any other function? > > Oh, that seems like a major misunderstanding on my part. I assumed > tsubst_copy_and_build would evaluate the expressions in template arguments > ?. I'll expand the test and will fix. Sorry for the long delay. New patch is attached. OK for trunk? New builtin to enable explicit use of PAREN_EXPR in C & C++ code. Signed-off-by: Matthias Kretz gcc/testsuite/ChangeLog: * c-c++-common/builtin-assoc-barrier-1.c: New test. gcc/cp/ChangeLog: * constexpr.c (cxx_eval_constant_expression): Handle PAREN_EXPR via cxx_eval_constant_expression. * cp-objcp-common.c (names_builtin_p): Handle RID_BUILTIN_ASSOC_BARRIER. * cp-tree.h: Adjust TREE_LANG_FLAG documentation to include PAREN_EXPR in REF_PARENTHESIZED_P. (REF_PARENTHESIZED_P): Add PAREN_EXPR. * parser.c (cp_parser_postfix_expression): Handle RID_BUILTIN_ASSOC_BARRIER. * pt.c (tsubst_copy_and_build): If the PAREN_EXPR is not a parenthesized initializer, build a new PAREN_EXPR. * semantics.c (force_paren_expr): Simplify conditionals. Set REF_PARENTHESIZED_P on PAREN_EXPR. (maybe_undo_parenthesized_ref): Test PAREN_EXPR for REF_PARENTHESIZED_P. gcc/c-family/ChangeLog: * c-common.c (c_common_reswords): Add __builtin_assoc_barrier. * c-common.h (enum rid): Add RID_BUILTIN_ASSOC_BARRIER. gcc/c/ChangeLog: * c-decl.c (names_builtin_p): Handle RID_BUILTIN_ASSOC_BARRIER. * c-parser.c (c_parser_postfix_expression): Likewise. gcc/ChangeLog: * doc/extend.texi: Document __builtin_assoc_barrier. --- gcc/c-family/c-common.c | 1 + gcc/c-family/c-common.h | 2 +- gcc/c/c-decl.c | 1 + gcc/c/c-parser.c | 20 ++++++ gcc/cp/constexpr.c | 8 +++ gcc/cp/cp-objcp-common.c | 1 + gcc/cp/cp-tree.h | 12 ++-- gcc/cp/parser.c | 14 ++++ gcc/cp/pt.c | 10 ++- gcc/cp/semantics.c | 23 ++---- gcc/doc/extend.texi | 18 +++++ .../c-c++-common/builtin-assoc-barrier-1.c | 71 +++++++++++++++++++ 12 files changed, 158 insertions(+), 23 deletions(-) create mode 100644 gcc/testsuite/c-c++-common/builtin-assoc-barrier-1.c diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c index 436df45df68..dd2a3d5da9e 100644 --- a/gcc/c-family/c-common.c +++ b/gcc/c-family/c-common.c @@ -384,6 +384,7 @@ const struct c_common_resword c_common_reswords[] = { "__builtin_convertvector", RID_BUILTIN_CONVERTVECTOR, 0 }, { "__builtin_has_attribute", RID_BUILTIN_HAS_ATTRIBUTE, 0 }, { "__builtin_launder", RID_BUILTIN_LAUNDER, D_CXXONLY }, + { "__builtin_assoc_barrier", RID_BUILTIN_ASSOC_BARRIER, 0 }, { "__builtin_shuffle", RID_BUILTIN_SHUFFLE, 0 }, { "__builtin_shufflevector", RID_BUILTIN_SHUFFLEVECTOR, 0 }, { "__builtin_tgmath", RID_BUILTIN_TGMATH, D_CONLY }, diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h index d5dad99ff97..c089fda12e4 100644 --- a/gcc/c-family/c-common.h +++ b/gcc/c-family/c-common.h @@ -108,7 +108,7 @@ enum rid RID_EXTENSION, RID_IMAGPART, RID_REALPART, RID_LABEL, RID_CHOOSE_EXPR, RID_TYPES_COMPATIBLE_P, RID_BUILTIN_COMPLEX, RID_BUILTIN_SHUFFLE, RID_BUILTIN_SHUFFLEVECTOR, RID_BUILTIN_CONVERTVECTOR, RID_BUILTIN_TGMATH, - RID_BUILTIN_HAS_ATTRIBUTE, + RID_BUILTIN_HAS_ATTRIBUTE, RID_BUILTIN_ASSOC_BARRIER, RID_DFLOAT32, RID_DFLOAT64, RID_DFLOAT128, /* TS 18661-3 keywords, in the same sequence as the TI_* values. */ diff --git a/gcc/c/c-decl.c b/gcc/c/c-decl.c index 186fa1692c1..f7407a31d9b 100644 --- a/gcc/c/c-decl.c +++ b/gcc/c/c-decl.c @@ -10619,6 +10619,7 @@ names_builtin_p (const char *name) case RID_BUILTIN_HAS_ATTRIBUTE: case RID_BUILTIN_SHUFFLE: case RID_BUILTIN_SHUFFLEVECTOR: + case RID_BUILTIN_ASSOC_BARRIER: case RID_CHOOSE_EXPR: case RID_OFFSETOF: case RID_TYPES_COMPATIBLE_P: diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c index 80dd61d599e..3770b09998d 100644 --- a/gcc/c/c-parser.c +++ b/gcc/c/c-parser.c @@ -8962,6 +8962,7 @@ c_parser_predefined_identifier (c_parser *parser) assignment-expression , assignment-expression, ) __builtin_convertvector ( assignment-expression , type-name ) + __builtin_assoc_barrier ( assignment-expression ) offsetof-member-designator: identifier @@ -10107,6 +10108,25 @@ c_parser_postfix_expression (c_parser *parser) } } break; + case RID_BUILTIN_ASSOC_BARRIER: + { + location_t start_loc = loc; + c_parser_consume_token (parser); + matching_parens parens; + if (!parens.require_open (parser)) + { + expr.set_error (); + break; + } + e1 = c_parser_expr_no_commas (parser, NULL); + mark_exp_read (e1.value); + location_t end_loc = c_parser_peek_token (parser)->get_finish (); + parens.skip_until_found_close (parser); + expr.value = build1_loc (loc, PAREN_EXPR, TREE_TYPE (e1.value), + e1.value); + set_c_expr_source_range (&expr, start_loc, end_loc); + } + break; case RID_AT_SELECTOR: { gcc_assert (c_dialect_objc ()); diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c index 453007c686b..0548570afe3 100644 --- a/gcc/cp/constexpr.c +++ b/gcc/cp/constexpr.c @@ -6837,6 +6837,14 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, non_constant_p, overflow_p); break; + case PAREN_EXPR: + gcc_assert (!REF_PARENTHESIZED_P (t)); + /* A PAREN_EXPR resulting from __builtin_assoc_barrier has no effect in + constant expressions since it's unaffected by -fassociative-math. */ + r = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 0), lval, + non_constant_p, overflow_p); + break; + case NOP_EXPR: if (REINTERPRET_CAST_P (t)) { diff --git a/gcc/cp/cp-objcp-common.c b/gcc/cp/cp-objcp-common.c index 28f2d7bee71..38eae881f0c 100644 --- a/gcc/cp/cp-objcp-common.c +++ b/gcc/cp/cp-objcp-common.c @@ -404,6 +404,7 @@ names_builtin_p (const char *name) case RID_BUILTIN_SHUFFLE: case RID_BUILTIN_SHUFFLEVECTOR: case RID_BUILTIN_LAUNDER: + case RID_BUILTIN_ASSOC_BARRIER: case RID_BUILTIN_BIT_CAST: case RID_OFFSETOF: case RID_HAS_NOTHROW_ASSIGN: diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index f387b5036d2..5adcd661406 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -473,7 +473,8 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX]; TARGET_EXPR_DIRECT_INIT_P (in TARGET_EXPR) FNDECL_USED_AUTO (in FUNCTION_DECL) DECLTYPE_FOR_LAMBDA_PROXY (in DECLTYPE_TYPE) - REF_PARENTHESIZED_P (in COMPONENT_REF, INDIRECT_REF, SCOPE_REF, VIEW_CONVERT_EXPR) + REF_PARENTHESIZED_P (in COMPONENT_REF, INDIRECT_REF, SCOPE_REF, + VIEW_CONVERT_EXPR, PAREN_EXPR) AGGR_INIT_ZERO_FIRST (in AGGR_INIT_EXPR) CONSTRUCTOR_MUTABLE_POISON (in CONSTRUCTOR) OVL_HIDDEN_P (in OVERLOAD) @@ -4040,12 +4041,13 @@ struct GTY(()) lang_decl { #define PAREN_STRING_LITERAL_P(NODE) \ TREE_LANG_FLAG_0 (STRING_CST_CHECK (NODE)) -/* Indicates whether a COMPONENT_REF or a SCOPE_REF has been parenthesized, or - an INDIRECT_REF comes from parenthesizing a _DECL. Currently only set some - of the time in C++14 mode. */ +/* Indicates whether a COMPONENT_REF or a SCOPE_REF has been parenthesized, an + INDIRECT_REF comes from parenthesizing a _DECL, or a PAREN_EXPR identifies a + parenthesized initializer relevant for decltype(auto). Currently only set + some of the time in C++14 mode. */ #define REF_PARENTHESIZED_P(NODE) \ - TREE_LANG_FLAG_2 (TREE_CHECK4 ((NODE), COMPONENT_REF, INDIRECT_REF, SCOPE_REF, VIEW_CONVERT_EXPR)) + TREE_LANG_FLAG_2 (TREE_CHECK5 ((NODE), COMPONENT_REF, INDIRECT_REF, SCOPE_REF, VIEW_CONVERT_EXPR, PAREN_EXPR)) /* Nonzero if this AGGR_INIT_EXPR provides for initialization via a constructor call, rather than an ordinary function call. */ diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 32de97b08bd..12c598798db 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -7354,6 +7354,7 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p, case RID_BUILTIN_SHUFFLE: case RID_BUILTIN_SHUFFLEVECTOR: case RID_BUILTIN_LAUNDER: + case RID_BUILTIN_ASSOC_BARRIER: { vec *vec; @@ -7396,6 +7397,19 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p, } break; + case RID_BUILTIN_ASSOC_BARRIER: + if (vec->length () == 1) + postfix_expression = build1_loc (loc, PAREN_EXPR, + TREE_TYPE ((*vec)[0]), + (*vec)[0]); + else + { + error_at (loc, "wrong number of arguments to " + "%<__builtin_assoc_barrier%>"); + postfix_expression = error_mark_node; + } + break; + case RID_BUILTIN_SHUFFLE: if (vec->length () == 2) postfix_expression diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index b2916f8aa4b..be79f70f30c 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -21003,7 +21003,15 @@ tsubst_copy_and_build (tree t, integral_constant_expression_p)); case PAREN_EXPR: - RETURN (finish_parenthesized_expr (RECUR (TREE_OPERAND (t, 0)))); + if (REF_PARENTHESIZED_P (t)) + RETURN (finish_parenthesized_expr (RECUR (TREE_OPERAND (t, 0)))); + else + /* Recreate the PAREN_EXPR from __builtin_assoc_barrier. */ + { + tree op0 = RECUR (TREE_OPERAND (t, 0)); + RETURN (build1_loc (input_location, PAREN_EXPR, + TREE_TYPE (op0), op0)); + } case VEC_PERM_EXPR: { diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index 2443d032749..402f5a5556a 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -2048,24 +2048,17 @@ force_paren_expr (tree expr, bool even_uneval) if (cp_unevaluated_operand && !even_uneval) return expr; - if (!DECL_P (tree_strip_any_location_wrapper (expr)) - && TREE_CODE (expr) != COMPONENT_REF - && TREE_CODE (expr) != SCOPE_REF) - return expr; - - location_t loc = cp_expr_location (expr); - if (TREE_CODE (expr) == COMPONENT_REF || TREE_CODE (expr) == SCOPE_REF) REF_PARENTHESIZED_P (expr) = true; - else if (processing_template_decl) - expr = build1_loc (loc, PAREN_EXPR, TREE_TYPE (expr), expr); - else + else if (DECL_P (tree_strip_any_location_wrapper (expr))) { - expr = build1_loc (loc, VIEW_CONVERT_EXPR, TREE_TYPE (expr), expr); + location_t loc = cp_expr_location (expr); + const tree_code code = processing_template_decl ? PAREN_EXPR + : VIEW_CONVERT_EXPR; + expr = build1_loc (loc, code, TREE_TYPE (expr), expr); REF_PARENTHESIZED_P (expr) = true; } - return expr; } @@ -2090,10 +2083,8 @@ maybe_undo_parenthesized_ref (tree t) || TREE_CODE (t) == STATIC_CAST_EXPR); t = TREE_OPERAND (t, 0); } - else if (TREE_CODE (t) == PAREN_EXPR) - t = TREE_OPERAND (t, 0); - else if (TREE_CODE (t) == VIEW_CONVERT_EXPR - && REF_PARENTHESIZED_P (t)) + else if ((TREE_CODE (t) == PAREN_EXPR || TREE_CODE (t) == VIEW_CONVERT_EXPR) + && REF_PARENTHESIZED_P (t)) t = TREE_OPERAND (t, 0); return t; diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi index 6e6c580e329..ef654d7b878 100644 --- a/gcc/doc/extend.texi +++ b/gcc/doc/extend.texi @@ -14043,6 +14043,24 @@ int g (int c) @end deftypefn +@deftypefn {Built-in Function} @var{type} __builtin_assoc_barrier (@var{type} @var{expr}) +This built-in inhibits re-association of the floating-point expression +@var{expr} with expressions consuming the return value of the built-in. The +expression @var{expr} itself can be reordered, and the whole expression +@var{expr} can be reordered with operands after the barrier. The barrier is +only relevant when @code{-fassociative-math} is active, since otherwise +floating-point is not treated as associative. + +@smallexample +float x0 = a + b - b; +float x1 = __builtin_assoc_barrier(a + b) - b; +@end smallexample + +@noindent +means that, with @code{-fassociative-math}, @code{x0} can be optimized to +@code{x0 = a} but @code{x1} cannot. +@end deftypefn + @deftypefn {Built-in Function} {void *} __builtin_assume_aligned (const void *@var{exp}, size_t @var{align}, ...) This function returns its first argument, and allows the compiler to assume that the returned pointer is at least @var{align} bytes diff --git a/gcc/testsuite/c-c++-common/builtin-assoc-barrier-1.c b/gcc/testsuite/c-c++-common/builtin-assoc-barrier-1.c new file mode 100644 index 00000000000..3ff324982cf --- /dev/null +++ b/gcc/testsuite/c-c++-common/builtin-assoc-barrier-1.c @@ -0,0 +1,71 @@ +// { dg-options "-O2 -ffast-math" } +/* { dg-do run } */ + +float a = 1.f; +float b = 1.e20f; + +float +fast() +{ + return __builtin_assoc_barrier (a + b) - b; +} + +__attribute__((optimize("-fno-associative-math"))) +float +normal() +{ + return a + b - b; +} + +void test0() +{ + if (fast() != normal()) + __builtin_abort(); +} + +#ifdef __cplusplus +#ifdef __cpp_constexpr +constexpr float +pm(float x, float y) +{ + return __builtin_assoc_barrier(x + y) - y; +} + +template + constexpr int + f() + { + return x; + } +#endif + +template + T + pm(T x, T y) + { + return __builtin_assoc_barrier(x + y) - y; + } + +void test1() +{ + if (pm(a, b) != normal()) + __builtin_abort(); +#ifdef __cpp_constexpr + constexpr float x = pm(1.f, 1.e20f); + constexpr int y = f(); + if (x != normal()) + __builtin_abort(); + if (y != 0) + __builtin_abort(); +#endif +} +#else +void test1() {} +#endif + +int main() +{ + test0(); + test1(); + return 0; +}