public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH] c-family: Add __builtin_assoc_barrier
@ 2021-07-19  7:33 Matthias Kretz
  2021-07-19 12:34 ` Richard Biener
  0 siblings, 1 reply; 14+ messages in thread
From: Matthias Kretz @ 2021-07-19  7:33 UTC (permalink / raw)
  To: gcc-patches; +Cc: Richard Biener

[-- Attachment #1: Type: text/plain, Size: 2081 bytes --]

tested on x86_64-pc-linux-gnu with no new failures. OK for master?

New builtin to enable explicit use of PAREN_EXPR in C & C++ code.

Signed-off-by: Matthias Kretz <m.kretz@gsi.de>

gcc/testsuite/ChangeLog:

	* c-c++-common/builtin-assoc-barrier-1.c: New test.

gcc/cp/ChangeLog:

	* cp-objcp-common.c (names_builtin_p): Handle
	RID_BUILTIN_ASSOC_BARRIER.
	* parser.c (cp_parser_postfix_expression): Handle
	RID_BUILTIN_ASSOC_BARRIER.

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/cp-objcp-common.c                      |  1 +
 gcc/cp/parser.c                               | 14 +++++++++++
 gcc/doc/extend.texi                           | 18 ++++++++++++++
 .../c-c++-common/builtin-assoc-barrier-1.c    | 24 +++++++++++++++++++
 8 files changed, 80 insertions(+), 1 deletion(-)
 create mode 100644 gcc/testsuite/c-c++-common/builtin-assoc-barrier-1.c


--
──────────────────────────────────────────────────────────────────────────
 Dr. Matthias Kretz                           https://mattkretz.github.io
 GSI Helmholtz Centre for Heavy Ion Research               https://gsi.de
 std::experimental::simd              https://github.com/VcDevel/std-simd
──────────────────────────────────────────────────────────────────────────

[-- Attachment #2: 0001-c-family-Add-__builtin_assoc_barrier.patch --]
[-- Type: text/x-patch, Size: 6113 bytes --]

diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c
index 681fcc972f4..c62a6398a47 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 50ca8fb6ebd..f34dc47c2ba 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 983d65e930c..dcf4a2d7c32 100644
--- a/gcc/c/c-decl.c
+++ b/gcc/c/c-decl.c
@@ -10557,6 +10557,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 9a56e0c04c6..fffd81f4e5b 100644
--- a/gcc/c/c-parser.c
+++ b/gcc/c/c-parser.c
@@ -8931,6 +8931,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
@@ -10076,6 +10077,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/cp-objcp-common.c b/gcc/cp/cp-objcp-common.c
index ee255732d5a..04522a23eda 100644
--- a/gcc/cp/cp-objcp-common.c
+++ b/gcc/cp/cp-objcp-common.c
@@ -395,6 +395,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/parser.c b/gcc/cp/parser.c
index 62f3465539b..4ee7899ce66 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -7316,6 +7316,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<tree, va_gc> *vec;
 
@@ -7358,6 +7359,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/doc/extend.texi b/gcc/doc/extend.texi
index 96640ba156f..cb08f830940 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -13951,6 +13951,24 @@ int g (int c)
 
 @end deftypefn
 
+@deftypefn {Built-in Function} @var{type} __builtin_assoc_barrier (@var{type} @var{expr})
+This built-in represents a re-association barrier for the floating-point
+expression @var{expr} with operations following the built-in. The expression
+@var{expr} itself can be reordered, and the whole expression @var{expr} can be
+reordered with operations 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..51efb1ab96c
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/builtin-assoc-barrier-1.c
@@ -0,0 +1,24 @@
+/* { dg-do run } */
+
+float a = 1.f;
+float b = 1.e20f;
+
+__attribute__((optimize("-ffast-math")))
+float
+fast()
+{
+  return __builtin_assoc_barrier (a + b) - b;
+}
+
+float
+normal()
+{
+  return a + b - b;
+}
+
+int main()
+{
+  if (fast() != normal())
+    __builtin_abort();
+  return 0;
+}

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH] c-family: Add __builtin_assoc_barrier
  2021-07-19  7:33 [PATCH] c-family: Add __builtin_assoc_barrier Matthias Kretz
@ 2021-07-19 12:34 ` Richard Biener
  2021-07-20 20:22   ` Jason Merrill
  2021-09-06 12:21   ` [PATCH v2] " Matthias Kretz
  0 siblings, 2 replies; 14+ messages in thread
From: Richard Biener @ 2021-07-19 12:34 UTC (permalink / raw)
  To: Matthias Kretz; +Cc: gcc-patches, jason, Joseph S. Myers

On Mon, 19 Jul 2021, Matthias Kretz wrote:

> tested on x86_64-pc-linux-gnu with no new failures. OK for master?

I think now that PAREN_EXPR can appear in C++ code you need to
adjust some machiner to expect it (constexpr folding?  template stuff?).
I suggest to add some testcases covering templates and constexpr
functions.

+@deftypefn {Built-in Function} @var{type} __builtin_assoc_barrier
(@var{type} @var{expr})
+This built-in represents a re-association barrier for the floating-point
+expression @var{expr} with operations following the built-in. The
expression
+@var{expr} itself can be reordered, and the whole expression @var{expr} 
can
be
+reordered with operations after the barrier.

What operations follow the built-in also applies to operations leading
the builtin?  Maybe "This built-in represents a re-association barrier
for the floating-point expression @var{expr} with the expression
consuming its value."  But I'm not an english speaker - I guess
I'm mostly confused about "follow" here.

I'm not sure if there are better C/C++ language terms describing what
the builtin does, but basically it appears as opaque operand to the
surrounding expression and the surrounding expression is opaque
to the expression inside the parens.

 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
+

Otherwise the patch looks OK, but of course C/C++ frontend maintainers
would want to chime in here (I've CCed two).

Richard.


> New builtin to enable explicit use of PAREN_EXPR in C & C++ code.
> 
> Signed-off-by: Matthias Kretz <m.kretz@gsi.de>
> 
> gcc/testsuite/ChangeLog:
> 
> 	* c-c++-common/builtin-assoc-barrier-1.c: New test.
> 
> gcc/cp/ChangeLog:
> 
> 	* cp-objcp-common.c (names_builtin_p): Handle
> 	RID_BUILTIN_ASSOC_BARRIER.
> 	* parser.c (cp_parser_postfix_expression): Handle
> 	RID_BUILTIN_ASSOC_BARRIER.
> 
> 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/cp-objcp-common.c                      |  1 +
>  gcc/cp/parser.c                               | 14 +++++++++++
>  gcc/doc/extend.texi                           | 18 ++++++++++++++
>  .../c-c++-common/builtin-assoc-barrier-1.c    | 24 +++++++++++++++++++
>  8 files changed, 80 insertions(+), 1 deletion(-)
>  create mode 100644 gcc/testsuite/c-c++-common/builtin-assoc-barrier-1.c
> 
> 
> --
> ──────────────────────────────────────────────────────────────────────────
>  Dr. Matthias Kretz                           https://mattkretz.github.io
>  GSI Helmholtz Centre for Heavy Ion Research               https://gsi.de
>  std::experimental::simd              https://github.com/VcDevel/std-simd
> ──────────────────────────────────────────────────────────────────────────

-- 
Richard Biener <rguenther@suse.de>
SUSE Software Solutions Germany GmbH, Maxfeldstrasse 5, 90409 Nuernberg,
Germany; GF: Felix Imendörffer; HRB 36809 (AG Nuernberg)

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH] c-family: Add __builtin_assoc_barrier
  2021-07-19 12:34 ` Richard Biener
@ 2021-07-20 20:22   ` Jason Merrill
  2021-09-06 12:21   ` [PATCH v2] " Matthias Kretz
  1 sibling, 0 replies; 14+ messages in thread
From: Jason Merrill @ 2021-07-20 20:22 UTC (permalink / raw)
  To: Richard Biener, Matthias Kretz; +Cc: gcc-patches, Joseph S. Myers

On 7/19/21 8:34 AM, Richard Biener wrote:
> On Mon, 19 Jul 2021, Matthias Kretz wrote:
> 
>> tested on x86_64-pc-linux-gnu with no new failures. OK for master?
> 
> I think now that PAREN_EXPR can appear in C++ code you need to
> adjust some machiner to expect it (constexpr folding?  template stuff?).
> I suggest to add some testcases covering templates and constexpr
> functions.

Yes.

The C++ front end already uses PAREN_EXPR in templates to indicate 
parenthesized initializers in cases where that matters for 
decltype(auto).  It should be fine to use it for both that and 
__builtin_assoc_barrier, but you probably want to distinguish them with 
a TREE_LANG_FLAG, and change tsubst_copy_and_build to keep the 
PAREN_EXPR in this case.

For constexpr you probably just need to add handling to 
cxx_eval_constant_expression to evaluate its operand instead.

> +@deftypefn {Built-in Function} @var{type} __builtin_assoc_barrier
> (@var{type} @var{expr})
> +This built-in represents a re-association barrier for the floating-point
> +expression @var{expr} with operations following the built-in. The
> expression
> +@var{expr} itself can be reordered, and the whole expression @var{expr}
> can
> be
> +reordered with operations after the barrier.
> 
> What operations follow the built-in also applies to operations leading
> the builtin?  Maybe "This built-in represents a re-association barrier
> for the floating-point expression @var{expr} with the expression
> consuming its value."  But I'm not an english speaker - I guess
> I'm mostly confused about "follow" here.
> 
> I'm not sure if there are better C/C++ language terms describing what
> the builtin does, but basically it appears as opaque operand to the
> surrounding expression and the surrounding expression is opaque
> to the expression inside the parens.
> 
>   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
> +
> 
> Otherwise the patch looks OK, but of course C/C++ frontend maintainers
> would want to chime in here (I've CCed two).
> 
> Richard.
> 
> 
>> New builtin to enable explicit use of PAREN_EXPR in C & C++ code.
>>
>> Signed-off-by: Matthias Kretz <m.kretz@gsi.de>
>>
>> gcc/testsuite/ChangeLog:
>>
>> 	* c-c++-common/builtin-assoc-barrier-1.c: New test.
>>
>> gcc/cp/ChangeLog:
>>
>> 	* cp-objcp-common.c (names_builtin_p): Handle
>> 	RID_BUILTIN_ASSOC_BARRIER.
>> 	* parser.c (cp_parser_postfix_expression): Handle
>> 	RID_BUILTIN_ASSOC_BARRIER.
>>
>> 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/cp-objcp-common.c                      |  1 +
>>   gcc/cp/parser.c                               | 14 +++++++++++
>>   gcc/doc/extend.texi                           | 18 ++++++++++++++
>>   .../c-c++-common/builtin-assoc-barrier-1.c    | 24 +++++++++++++++++++
>>   8 files changed, 80 insertions(+), 1 deletion(-)
>>   create mode 100644 gcc/testsuite/c-c++-common/builtin-assoc-barrier-1.c
>>
>>
>> --
>> ──────────────────────────────────────────────────────────────────────────
>>   Dr. Matthias Kretz                           https://mattkretz.github.io
>>   GSI Helmholtz Centre for Heavy Ion Research               https://gsi.de
>>   std::experimental::simd              https://github.com/VcDevel/std-simd
>> ──────────────────────────────────────────────────────────────────────────
> 


^ permalink raw reply	[flat|nested] 14+ messages in thread

* [PATCH v2] c-family: Add __builtin_assoc_barrier
  2021-07-19 12:34 ` Richard Biener
  2021-07-20 20:22   ` Jason Merrill
@ 2021-09-06 12:21   ` Matthias Kretz
  2021-09-06 12:40     ` Richard Biener
  2021-09-07 17:36     ` Jason Merrill
  1 sibling, 2 replies; 14+ messages in thread
From: Matthias Kretz @ 2021-09-06 12:21 UTC (permalink / raw)
  To: Richard Biener; +Cc: gcc-patches, jason, Joseph S. Myers

[-- Attachment #1: Type: text/plain, Size: 5912 bytes --]

Hi,

On Tuesday, 20 July 2021 22:22:02 CEST Jason Merrill wrote:
> The C++ front end already uses PAREN_EXPR in templates to indicate
> parenthesized initializers in cases where that matters for
> decltype(auto).  It should be fine to use it for both that and
> __builtin_assoc_barrier, but you probably want to distinguish them with
> a TREE_LANG_FLAG, and change tsubst_copy_and_build to keep the
> PAREN_EXPR in this case.

I reused REF_PARENTHESIZED_P for PAREN_EXPR.

> For constexpr you probably just need to add handling to
> cxx_eval_constant_expression to evaluate its operand instead.

OK, that was easy.

On Monday, 19 July 2021 14:34:12 CEST Richard Biener wrote:
> On Mon, 19 Jul 2021, Matthias Kretz wrote:
> > tested on x86_64-pc-linux-gnu with no new failures. OK for master?
> 
> I think now that PAREN_EXPR can appear in C++ code you need to
> adjust some machiner to expect it (constexpr folding?  template stuff?).
> I suggest to add some testcases covering templates and constexpr
> functions.

Right. I expanded the test.

> +@deftypefn {Built-in Function} @var{type} __builtin_assoc_barrier
> (@var{type} @var{expr})
> +This built-in represents a re-association barrier for the floating-point
> +expression @var{expr} with operations following the built-in. The
> expression
> +@var{expr} itself can be reordered, and the whole expression @var{expr}
> can
> be
> +reordered with operations after the barrier.
> 
> What operations follow the built-in also applies to operations leading
> the builtin?  Maybe "This built-in represents a re-association barrier
> for the floating-point expression @var{expr} with the expression
> consuming its value."  But I'm not an english speaker - I guess
> I'm mostly confused about "follow" here.

With "follow" I meant time / precedence and not that the operation follows 
syntactically. So e.g. a + b * c: the addition follows after the 
multiplication. It's probably not as precise as it could/should be. Also "the 
whole expression @var{expr} can be reordered with operations after the 
barrier" probably should say "with operands" not "with operations", right?

> I'm not sure if there are better C/C++ language terms describing what
> the builtin does, but basically it appears as opaque operand to the
> surrounding expression and the surrounding expression is opaque
> to the expression inside the parens.

I can't think of any other term that would help here.

Based upon your suggestion, the attached patch now says:
"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. [...]"

New patch attached. OK to push?

-----------------------------------------------------------

New builtin to enable explicit use of PAREN_EXPR in C & C++ code.

Signed-off-by: Matthias Kretz <m.kretz@gsi.de>

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, evaluate by ignoring the 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                            |  6 +++
 gcc/cp/cp-objcp-common.c                      |  1 +
 gcc/cp/cp-tree.h                              | 12 +++--
 gcc/cp/parser.c                               | 14 ++++++
 gcc/cp/pt.c                                   |  5 +-
 gcc/cp/semantics.c                            | 23 +++------
 gcc/doc/extend.texi                           | 18 +++++++
 .../c-c++-common/builtin-assoc-barrier-1.c    | 48 +++++++++++++++++++
 12 files changed, 128 insertions(+), 23 deletions(-)
 create mode 100644 gcc/testsuite/c-c++-common/builtin-assoc-barrier-1.c

-- 
──────────────────────────────────────────────────────────────────────────
 Dr. Matthias Kretz                           https://mattkretz.github.io
 GSI Helmholtz Centre for Heavy Ion Research               https://gsi.de
 std::experimental::simd              https://github.com/VcDevel/std-simd
──────────────────────────────────────────────────────────────────────────

[-- Attachment #2: 0001-c-family-Add-__builtin_assoc_barrier.patch --]
[-- Type: text/x-patch, Size: 10886 bytes --]

diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c
index 681fcc972f4..c62a6398a47 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 50ca8fb6ebd..f34dc47c2ba 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 983d65e930c..dcf4a2d7c32 100644
--- a/gcc/c/c-decl.c
+++ b/gcc/c/c-decl.c
@@ -10557,6 +10557,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 9a56e0c04c6..fffd81f4e5b 100644
--- a/gcc/c/c-parser.c
+++ b/gcc/c/c-parser.c
@@ -8931,6 +8931,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
@@ -10076,6 +10077,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 31fa5b66865..18fb93fb99a 100644
--- a/gcc/cp/constexpr.c
+++ b/gcc/cp/constexpr.c
@@ -6730,6 +6730,12 @@ 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));
+      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 ee255732d5a..04522a23eda 100644
--- a/gcc/cp/cp-objcp-common.c
+++ b/gcc/cp/cp-objcp-common.c
@@ -395,6 +395,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 792849c361c..354f9ca4f26 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -475,7 +475,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)
@@ -4026,12 +4027,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 8fcd9840ea5..ec5f42e5038 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -7316,6 +7316,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<tree, va_gc> *vec;
 
@@ -7358,6 +7359,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 c7bf7d412ca..032d694e971 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -20826,7 +20826,10 @@ 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
+	RETURN (RECUR (TREE_OPERAND (t, 0)));
 
     case VEC_PERM_EXPR:
       {
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index b97dc1f6624..837fdaa041c 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 96640ba156f..60cafe0b3e3 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -13951,6 +13951,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..6fc90ccc33c
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/builtin-assoc-barrier-1.c
@@ -0,0 +1,48 @@
+// { 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;
+}
+
+#ifdef __cpp_constexpr
+constexpr float
+pm(float x, float y)
+{
+  return __builtin_assoc_barrier(x + y) - y;
+}
+
+template <int x>
+  constexpr int
+  f()
+  {
+    return x;
+  }
+#endif
+
+int main()
+{
+  if (fast() != normal())
+    __builtin_abort();
+#ifdef __cpp_constexpr
+  constexpr float x = pm(1.f, 1.e20f);
+  constexpr int y = f<int(pm(1.f, 1.e20f))>();
+  if (x != normal())
+    __builtin_abort();
+  if (y != 0)
+    __builtin_abort();
+#endif
+  return 0;
+}

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH v2] c-family: Add __builtin_assoc_barrier
  2021-09-06 12:21   ` [PATCH v2] " Matthias Kretz
@ 2021-09-06 12:40     ` Richard Biener
  2021-09-06 12:47       ` Matthias Kretz
  2021-09-07 17:36     ` Jason Merrill
  1 sibling, 1 reply; 14+ messages in thread
From: Richard Biener @ 2021-09-06 12:40 UTC (permalink / raw)
  To: Matthias Kretz; +Cc: gcc-patches, jason, Joseph S. Myers

On Mon, 6 Sep 2021, Matthias Kretz wrote:

> Hi,
> 
> On Tuesday, 20 July 2021 22:22:02 CEST Jason Merrill wrote:
> > The C++ front end already uses PAREN_EXPR in templates to indicate
> > parenthesized initializers in cases where that matters for
> > decltype(auto).  It should be fine to use it for both that and
> > __builtin_assoc_barrier, but you probably want to distinguish them with
> > a TREE_LANG_FLAG, and change tsubst_copy_and_build to keep the
> > PAREN_EXPR in this case.
> 
> I reused REF_PARENTHESIZED_P for PAREN_EXPR.
> 
> > For constexpr you probably just need to add handling to
> > cxx_eval_constant_expression to evaluate its operand instead.
> 
> OK, that was easy.
> 
> On Monday, 19 July 2021 14:34:12 CEST Richard Biener wrote:
> > On Mon, 19 Jul 2021, Matthias Kretz wrote:
> > > tested on x86_64-pc-linux-gnu with no new failures. OK for master?
> > 
> > I think now that PAREN_EXPR can appear in C++ code you need to
> > adjust some machiner to expect it (constexpr folding?  template stuff?).
> > I suggest to add some testcases covering templates and constexpr
> > functions.
> 
> Right. I expanded the test.
> 
> > +@deftypefn {Built-in Function} @var{type} __builtin_assoc_barrier
> > (@var{type} @var{expr})
> > +This built-in represents a re-association barrier for the floating-point
> > +expression @var{expr} with operations following the built-in. The
> > expression
> > +@var{expr} itself can be reordered, and the whole expression @var{expr}
> > can
> > be
> > +reordered with operations after the barrier.
> > 
> > What operations follow the built-in also applies to operations leading
> > the builtin?  Maybe "This built-in represents a re-association barrier
> > for the floating-point expression @var{expr} with the expression
> > consuming its value."  But I'm not an english speaker - I guess
> > I'm mostly confused about "follow" here.
> 
> With "follow" I meant time / precedence and not that the operation follows 
> syntactically. So e.g. a + b * c: the addition follows after the 
> multiplication. It's probably not as precise as it could/should be. Also "the 
> whole expression @var{expr} can be reordered with operations after the 
> barrier" probably should say "with operands" not "with operations", right?
> 
> > I'm not sure if there are better C/C++ language terms describing what
> > the builtin does, but basically it appears as opaque operand to the
> > surrounding expression and the surrounding expression is opaque
> > to the expression inside the parens.
> 
> I can't think of any other term that would help here.
> 
> Based upon your suggestion, the attached patch now says:
> "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. [...]"
> 
> New patch attached. OK to push?

OK from my side, I'll leave the C++ frontend parts to Jason.

I'll note that currently a + PAREN_EXPR (b * c) is for example
also not contracted to PAREN_EXPR (FMA (PAREN_EXPR (a), b, c))
even though technically FP contraction is not association.  But
that's an implementation detail that could be changed.  There
are likely other transforms that it prevents as well that are
not assocations, the implementation focus was correctness
as to preventing association, not so much not hindering
unrelated optimizations.  If you run into any such issues
reporting a bugzilla would be welcome.

Thanks,
Richard.

> -----------------------------------------------------------
> 
> New builtin to enable explicit use of PAREN_EXPR in C & C++ code.
> 
> Signed-off-by: Matthias Kretz <m.kretz@gsi.de>
> 
> 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, evaluate by ignoring the 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                            |  6 +++
>  gcc/cp/cp-objcp-common.c                      |  1 +
>  gcc/cp/cp-tree.h                              | 12 +++--
>  gcc/cp/parser.c                               | 14 ++++++
>  gcc/cp/pt.c                                   |  5 +-
>  gcc/cp/semantics.c                            | 23 +++------
>  gcc/doc/extend.texi                           | 18 +++++++
>  .../c-c++-common/builtin-assoc-barrier-1.c    | 48 +++++++++++++++++++
>  12 files changed, 128 insertions(+), 23 deletions(-)
>  create mode 100644 gcc/testsuite/c-c++-common/builtin-assoc-barrier-1.c
> 
> 

-- 
Richard Biener <rguenther@suse.de>
SUSE Software Solutions Germany GmbH, Maxfeldstrasse 5, 90409 Nuernberg,
Germany; GF: Felix Imendörffer; HRB 36809 (AG Nuernberg)

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH v2] c-family: Add __builtin_assoc_barrier
  2021-09-06 12:40     ` Richard Biener
@ 2021-09-06 12:47       ` Matthias Kretz
  2021-09-06 12:59         ` Richard Biener
  0 siblings, 1 reply; 14+ messages in thread
From: Matthias Kretz @ 2021-09-06 12:47 UTC (permalink / raw)
  To: Richard Biener; +Cc: gcc-patches

On Monday, 6 September 2021 14:40:31 CEST Richard Biener wrote:
> I'll note that currently a + PAREN_EXPR (b * c) is for example
> also not contracted to PAREN_EXPR (FMA (PAREN_EXPR (a), b, c))
> even though technically FP contraction is not association.  But
> that's an implementation detail that could be changed.  There
> are likely other transforms that it prevents as well that are
> not assocations, the implementation focus was correctness
> as to preventing association, not so much not hindering
> unrelated optimizations.  If you run into any such issues
> reporting a bugzilla would be welcome.

Thanks, interesting point. I believe it might even be useful to nail down that 
behavior (i.e. document it and write a test). Because a + b * c evaluates b * 
c before the addition in any case. So why would anyone add a PAREN_EXPR around 
b * c?

We have (std::)fma (__builtin_fma) to explicitly request contraction. 
PAREN_EXPR seems like a good fit to inhibit contraction.

-- 
──────────────────────────────────────────────────────────────────────────
 Dr. Matthias Kretz                           https://mattkretz.github.io
 GSI Helmholtz Centre for Heavy Ion Research               https://gsi.de
 stdₓ::simd
──────────────────────────────────────────────────────────────────────────

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH v2] c-family: Add __builtin_assoc_barrier
  2021-09-06 12:47       ` Matthias Kretz
@ 2021-09-06 12:59         ` Richard Biener
  2021-09-06 15:15           ` Matthias Kretz
  0 siblings, 1 reply; 14+ messages in thread
From: Richard Biener @ 2021-09-06 12:59 UTC (permalink / raw)
  To: Matthias Kretz; +Cc: gcc-patches

On Mon, 6 Sep 2021, Matthias Kretz wrote:

> On Monday, 6 September 2021 14:40:31 CEST Richard Biener wrote:
> > I'll note that currently a + PAREN_EXPR (b * c) is for example
> > also not contracted to PAREN_EXPR (FMA (PAREN_EXPR (a), b, c))
> > even though technically FP contraction is not association.  But
> > that's an implementation detail that could be changed.  There
> > are likely other transforms that it prevents as well that are
> > not assocations, the implementation focus was correctness
> > as to preventing association, not so much not hindering
> > unrelated optimizations.  If you run into any such issues
> > reporting a bugzilla would be welcome.
> 
> Thanks, interesting point. I believe it might even be useful to nail down that 
> behavior (i.e. document it and write a test). Because a + b * c evaluates b * 
> c before the addition in any case. So why would anyone add a PAREN_EXPR around 
> b * c?

At least for integers we have transforms that do a + a * c -> a * (1 + c)
so one could think of (x/y) + (x/y)*c -> (x/y) * (1 + c) which would
then have associated the c * (x/y) multiplication ...  Or when
c is constant then a + a * C can be simplified.

> We have (std::)fma (__builtin_fma) to explicitly request contraction. 
> PAREN_EXPR seems like a good fit to inhibit contraction.

OK, I guess it should apply to PAREN_EXPR (a + a) + a as well
which then does not become 3 * PAREN_EXPR (a).  Likewise
PAREN_EXPR (a) - a might eventually not become zero (I'm not
absolutely sure about that ;))

Richard.

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH v2] c-family: Add __builtin_assoc_barrier
  2021-09-06 12:59         ` Richard Biener
@ 2021-09-06 15:15           ` Matthias Kretz
  0 siblings, 0 replies; 14+ messages in thread
From: Matthias Kretz @ 2021-09-06 15:15 UTC (permalink / raw)
  To: Richard Biener; +Cc: gcc-patches

On Monday, 6 September 2021 14:59:27 CEST Richard Biener wrote:
> On Mon, 6 Sep 2021, Matthias Kretz wrote:
> > On Monday, 6 September 2021 14:40:31 CEST Richard Biener wrote:
> > > I'll note that currently a + PAREN_EXPR (b * c) is for example
> > > also not contracted to PAREN_EXPR (FMA (PAREN_EXPR (a), b, c))
> > > even though technically FP contraction is not association.  But
> > > that's an implementation detail that could be changed.  There
> > > are likely other transforms that it prevents as well that are
> > > not assocations, the implementation focus was correctness
> > > as to preventing association, not so much not hindering
> > > unrelated optimizations.  If you run into any such issues
> > > reporting a bugzilla would be welcome.
> > 
> > Thanks, interesting point. I believe it might even be useful to nail down
> > that behavior (i.e. document it and write a test). Because a + b * c
> > evaluates b * c before the addition in any case. So why would anyone add
> > a PAREN_EXPR around b * c?
> 
> At least for integers we have transforms that do a + a * c -> a * (1 + c)
> so one could think of (x/y) + (x/y)*c -> (x/y) * (1 + c) which would
> then have associated the c * (x/y) multiplication ...  Or when
> c is constant then a + a * C can be simplified.

Right given float a, `a + 2.1f * a` is compiled to `3.1f * a` with -ffast-
math. So yes, there's a reason one might want `a + 
__builtin_assoc_barrier(2.1f * a)` without inhibiting contraction. I'll 
investigate more and might submit a PR...

> > We have (std::)fma (__builtin_fma) to explicitly request contraction.
> > PAREN_EXPR seems like a good fit to inhibit contraction.
> 
> OK, I guess it should apply to PAREN_EXPR (a + a) + a as well
> which then does not become 3 * PAREN_EXPR (a).  Likewise
> PAREN_EXPR (a) - a might eventually not become zero (I'm not
> absolutely sure about that ;))

Just tested it. PAREN_EXPR inhibits both transformations.

-- 
──────────────────────────────────────────────────────────────────────────
 Dr. Matthias Kretz                           https://mattkretz.github.io
 GSI Helmholtz Centre for Heavy Ion Research               https://gsi.de
 stdₓ::simd
──────────────────────────────────────────────────────────────────────────

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH v2] c-family: Add __builtin_assoc_barrier
  2021-09-06 12:21   ` [PATCH v2] " Matthias Kretz
  2021-09-06 12:40     ` Richard Biener
@ 2021-09-07 17:36     ` Jason Merrill
  2021-09-08  9:37       ` Matthias Kretz
  1 sibling, 1 reply; 14+ messages in thread
From: Jason Merrill @ 2021-09-07 17:36 UTC (permalink / raw)
  To: Matthias Kretz, Richard Biener; +Cc: gcc-patches, Joseph S. Myers

On 9/6/21 8:21 AM, Matthias Kretz wrote:
> Hi,
> 
> On Tuesday, 20 July 2021 22:22:02 CEST Jason Merrill wrote:
>> The C++ front end already uses PAREN_EXPR in templates to indicate
>> parenthesized initializers in cases where that matters for
>> decltype(auto).  It should be fine to use it for both that and
>> __builtin_assoc_barrier, but you probably want to distinguish them with
>> a TREE_LANG_FLAG, and change tsubst_copy_and_build to keep the
>> PAREN_EXPR in this case.
> 
> I reused REF_PARENTHESIZED_P for PAREN_EXPR.
> 
>> For constexpr you probably just need to add handling to
>> cxx_eval_constant_expression to evaluate its operand instead.
> 
> OK, that was easy.
> 
> On Monday, 19 July 2021 14:34:12 CEST Richard Biener wrote:
>> On Mon, 19 Jul 2021, Matthias Kretz wrote:
>>> tested on x86_64-pc-linux-gnu with no new failures. OK for master?
>>
>> I think now that PAREN_EXPR can appear in C++ code you need to
>> adjust some machiner to expect it (constexpr folding?  template stuff?).
>> I suggest to add some testcases covering templates and constexpr
>> functions.
> 
> Right. I expanded the test.
> 
>> +@deftypefn {Built-in Function} @var{type} __builtin_assoc_barrier
>> (@var{type} @var{expr})
>> +This built-in represents a re-association barrier for the floating-point
>> +expression @var{expr} with operations following the built-in. The
>> expression
>> +@var{expr} itself can be reordered, and the whole expression @var{expr}
>> can
>> be
>> +reordered with operations after the barrier.
>>
>> What operations follow the built-in also applies to operations leading
>> the builtin?  Maybe "This built-in represents a re-association barrier
>> for the floating-point expression @var{expr} with the expression
>> consuming its value."  But I'm not an english speaker - I guess
>> I'm mostly confused about "follow" here.
> 
> With "follow" I meant time / precedence and not that the operation follows
> syntactically. So e.g. a + b * c: the addition follows after the
> multiplication. It's probably not as precise as it could/should be. Also "the
> whole expression @var{expr} can be reordered with operations after the
> barrier" probably should say "with operands" not "with operations", right?
> 
>> I'm not sure if there are better C/C++ language terms describing what
>> the builtin does, but basically it appears as opaque operand to the
>> surrounding expression and the surrounding expression is opaque
>> to the expression inside the parens.
> 
> I can't think of any other term that would help here.
> 
> Based upon your suggestion, the attached patch now says:
> "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. [...]"
> 
> New patch attached. OK to push?
> 
> -----------------------------------------------------------
> 
> New builtin to enable explicit use of PAREN_EXPR in C & C++ code.
> 
> Signed-off-by: Matthias Kretz <m.kretz@gsi.de>
> 
> 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, evaluate by ignoring the 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                            |  6 +++
>   gcc/cp/cp-objcp-common.c                      |  1 +
>   gcc/cp/cp-tree.h                              | 12 +++--
>   gcc/cp/parser.c                               | 14 ++++++
>   gcc/cp/pt.c                                   |  5 +-
>   gcc/cp/semantics.c                            | 23 +++------
>   gcc/doc/extend.texi                           | 18 +++++++
>   .../c-c++-common/builtin-assoc-barrier-1.c    | 48 +++++++++++++++++++
>   12 files changed, 128 insertions(+), 23 deletions(-)
>   create mode 100644 gcc/testsuite/c-c++-common/builtin-assoc-barrier-1.c

>      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.

Please also add a comment mentioning __builtin_assoc_barrier.

Jason


^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH v2] c-family: Add __builtin_assoc_barrier
  2021-09-07 17:36     ` Jason Merrill
@ 2021-09-08  9:37       ` Matthias Kretz
  2021-09-08 13:44         ` Jason Merrill
  0 siblings, 1 reply; 14+ messages in thread
From: Matthias Kretz @ 2021-09-08  9:37 UTC (permalink / raw)
  To: Richard Biener, Jason Merrill; +Cc: gcc-patches

[-- Attachment #1: Type: text/plain, Size: 1425 bytes --]

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?

> Please also add a comment mentioning __builtin_assoc_barrier.

I added a comment to that effect to both the cp/pt.c and cp/constexpr.c 
changes.

New patch attached.

-- 
──────────────────────────────────────────────────────────────────────────
 Dr. Matthias Kretz                           https://mattkretz.github.io
 GSI Helmholtz Centre for Heavy Ion Research               https://gsi.de
 stdₓ::simd
──────────────────────────────────────────────────────────────────────────

[-- Attachment #2: 0001-c-family-Add-__builtin_assoc_barrier.patch --]
[-- Type: text/x-patch, Size: 11180 bytes --]

diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c
index 681fcc972f4..c62a6398a47 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 50ca8fb6ebd..f34dc47c2ba 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 983d65e930c..dcf4a2d7c32 100644
--- a/gcc/c/c-decl.c
+++ b/gcc/c/c-decl.c
@@ -10557,6 +10557,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 9a56e0c04c6..fffd81f4e5b 100644
--- a/gcc/c/c-parser.c
+++ b/gcc/c/c-parser.c
@@ -8931,6 +8931,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
@@ -10076,6 +10077,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 31fa5b66865..6e964837d24 100644
--- a/gcc/cp/constexpr.c
+++ b/gcc/cp/constexpr.c
@@ -6730,6 +6730,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 ee255732d5a..04522a23eda 100644
--- a/gcc/cp/cp-objcp-common.c
+++ b/gcc/cp/cp-objcp-common.c
@@ -395,6 +395,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 792849c361c..354f9ca4f26 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -475,7 +475,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)
@@ -4026,12 +4027,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 8fcd9840ea5..ec5f42e5038 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -7316,6 +7316,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<tree, va_gc> *vec;
 
@@ -7358,6 +7359,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 c7bf7d412ca..0e9c151aced 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -20826,7 +20826,12 @@ 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
+	/* A PAREN_EXPR resulting from __builtin_assoc_barrier has no effect in
+	   tsubst since it's unaffected by -fassociative-math.  */
+	RETURN (RECUR (TREE_OPERAND (t, 0)));
 
     case VEC_PERM_EXPR:
       {
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index b97dc1f6624..837fdaa041c 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 96640ba156f..60cafe0b3e3 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -13951,6 +13951,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..6fc90ccc33c
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/builtin-assoc-barrier-1.c
@@ -0,0 +1,48 @@
+// { 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;
+}
+
+#ifdef __cpp_constexpr
+constexpr float
+pm(float x, float y)
+{
+  return __builtin_assoc_barrier(x + y) - y;
+}
+
+template <int x>
+  constexpr int
+  f()
+  {
+    return x;
+  }
+#endif
+
+int main()
+{
+  if (fast() != normal())
+    __builtin_abort();
+#ifdef __cpp_constexpr
+  constexpr float x = pm(1.f, 1.e20f);
+  constexpr int y = f<int(pm(1.f, 1.e20f))>();
+  if (x != normal())
+    __builtin_abort();
+  if (y != 0)
+    __builtin_abort();
+#endif
+  return 0;
+}

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH v2] c-family: Add __builtin_assoc_barrier
  2021-09-08  9:37       ` Matthias Kretz
@ 2021-09-08 13:44         ` Jason Merrill
  2021-09-08 13:49           ` Matthias Kretz
  0 siblings, 1 reply; 14+ messages in thread
From: Jason Merrill @ 2021-09-08 13:44 UTC (permalink / raw)
  To: Matthias Kretz, Richard Biener; +Cc: gcc-patches

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?

Jason


^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH v2] c-family: Add __builtin_assoc_barrier
  2021-09-08 13:44         ` Jason Merrill
@ 2021-09-08 13:49           ` Matthias Kretz
  2021-11-11  8:49             ` [PATCH v3] " Matthias Kretz
  0 siblings, 1 reply; 14+ messages in thread
From: Matthias Kretz @ 2021-09-08 13:49 UTC (permalink / raw)
  To: Richard Biener, Jason Merrill; +Cc: gcc-patches

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.

-- 
──────────────────────────────────────────────────────────────────────────
 Dr. Matthias Kretz                           https://mattkretz.github.io
 GSI Helmholtz Centre for Heavy Ion Research               https://gsi.de
 stdₓ::simd
──────────────────────────────────────────────────────────────────────────

^ permalink raw reply	[flat|nested] 14+ messages in thread

* [PATCH v3] c-family: Add __builtin_assoc_barrier
  2021-09-08 13:49           ` Matthias Kretz
@ 2021-11-11  8:49             ` Matthias Kretz
  2021-11-17 18:35               ` Jason Merrill
  0 siblings, 1 reply; 14+ messages in thread
From: Matthias Kretz @ 2021-11-11  8:49 UTC (permalink / raw)
  To: Jason Merrill; +Cc: gcc-patches

[-- Attachment #1: Type: text/plain, Size: 4230 bytes --]

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 <m.kretz@gsi.de>

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


-- 
──────────────────────────────────────────────────────────────────────────
 Dr. Matthias Kretz                           https://mattkretz.github.io
 GSI Helmholtz Centre for Heavy Ion Research               https://gsi.de
 stdₓ::simd
──────────────────────────────────────────────────────────────────────────

[-- Attachment #2: 0001-c-family-Add-__builtin_assoc_barrier.patch --]
[-- Type: text/x-patch, Size: 11480 bytes --]

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<tree, va_gc> *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 <int x>
+  constexpr int
+  f()
+  {
+    return x;
+  }
+#endif
+
+template <class T>
+  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<int(pm(1.f, 1.e20f))>();
+  if (x != normal())
+    __builtin_abort();
+  if (y != 0)
+    __builtin_abort();
+#endif
+}
+#else
+void test1() {}
+#endif
+
+int main()
+{
+  test0();
+  test1();
+  return 0;
+}

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH v3] c-family: Add __builtin_assoc_barrier
  2021-11-11  8:49             ` [PATCH v3] " Matthias Kretz
@ 2021-11-17 18:35               ` Jason Merrill
  0 siblings, 0 replies; 14+ messages in thread
From: Jason Merrill @ 2021-11-17 18:35 UTC (permalink / raw)
  To: Matthias Kretz; +Cc: gcc-patches

On 11/11/21 03:49, Matthias Kretz wrote:
> 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?

OK.

> New builtin to enable explicit use of PAREN_EXPR in C & C++ code.
> 
> Signed-off-by: Matthias Kretz <m.kretz@gsi.de>
> 
> 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
> 
> 


^ permalink raw reply	[flat|nested] 14+ messages in thread

end of thread, other threads:[~2021-11-17 18:35 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-07-19  7:33 [PATCH] c-family: Add __builtin_assoc_barrier Matthias Kretz
2021-07-19 12:34 ` Richard Biener
2021-07-20 20:22   ` Jason Merrill
2021-09-06 12:21   ` [PATCH v2] " Matthias Kretz
2021-09-06 12:40     ` Richard Biener
2021-09-06 12:47       ` Matthias Kretz
2021-09-06 12:59         ` Richard Biener
2021-09-06 15:15           ` Matthias Kretz
2021-09-07 17:36     ` Jason Merrill
2021-09-08  9:37       ` Matthias Kretz
2021-09-08 13:44         ` Jason Merrill
2021-09-08 13:49           ` Matthias Kretz
2021-11-11  8:49             ` [PATCH v3] " Matthias Kretz
2021-11-17 18:35               ` Jason Merrill

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).