[PATCH] Optimize reads from multiple elts in fold_ctor_reference (PR tree-optimization/93210)

Richard Biener rguenther@suse.de
Fri Jan 10 20:46:00 GMT 2020


On January 10, 2020 3:04:07 PM GMT+01:00, Jakub Jelinek <jakub@redhat.com> wrote:
>Hi!
>
>The C++ testcase shows we aren't able to determine constant when
>loading
>from
>const union U { struct V { int a, b; } c; long long d; } u = { { 1, 2 }
>};
>u.d, but since your patch in the summer can handle
>const union V { int a[2]; long long d; } v = { { 1, 2 } };
>v.d.
>
>I have noticed dwarf2out.c already has native_encode_initializer that
>can
>deal with extracting stuff from CONSTRUCTORs (recursively), the
>following
>patch just moves it over next to native_encode_expr and adjusts it to
>match
>the native_encode_expr argument standards, i.e. ptr == NULL for
>dry-run,
>off -1 when the whole object needs to be extracted and fitted into ptr
>through ptr + len - 1, and then other off values to extract base + off
>up to base + off + len - 1 bytes from the ctor into ptr up to ptr + len
>- 1
>and added to the toplevel fold_ctor_reference this
>native_encode_initializer
>as fallback if other ways failed.  E.g. we can't ATM extract
>RECORD_TYPEs
>etc. through native_interpret_expr, while
>fold_{,non}array_ctor_reference
>can extract them, but only if it doesn't overlap multiple initializers.
>I;ve done it in the toplevel fold_ctor_reference, not recursive calls,
>as I think that would imply exponential compile time behavior.
>
>Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

Ok. 

Richard. 

>2020-01-10  Jakub Jelinek  <jakub@redhat.com>
>
>	PR tree-optimization/93210
>	* fold-const.h (native_encode_initializer,
>	can_native_interpret_type_p): Declare.
>	* fold-const.c (native_encode_string): Fix up handling with off != -1,
>	simplify.
>	(native_encode_initializer): New function, moved from dwarf2out.c.
>	Adjust to native_encode_expr compatible arguments, including dry-run
>	and partial extraction modes.  Don't handle STRING_CST.
>	(can_native_interpret_type_p): No longer static.
>	* gimple-fold.c (fold_ctor_reference): For native_encode_expr, verify
>	offset / BITS_PER_UNIT fits into int and don't call it if
>	can_native_interpret_type_p fails.  If suboff is NULL and for
>	CONSTRUCTOR fold_{,non}array_ctor_reference returns NULL, retry with
>	native_encode_initializer.
>	(fold_const_aggregate_ref_1): Formatting fix.
>	* dwarf2out.c (native_encode_initializer): Moved to fold-const.c.
>	(tree_add_const_value_attribute): Adjust caller.
>
>	* gcc.dg/pr93210.c: New test.
>	* g++.dg/opt/pr93210.C: New test.
>
>--- gcc/fold-const.h.jj	2020-01-01 12:15:53.773522669 +0100
>+++ gcc/fold-const.h	2020-01-10 11:33:37.516681975 +0100
>@@ -26,7 +26,10 @@ extern int folding_initializer;
> 
> /* Convert between trees and native memory representation.  */
>extern int native_encode_expr (const_tree, unsigned char *, int, int
>off = -1);
>+extern int native_encode_initializer (tree, unsigned char *, int,
>+				      int off = -1);
> extern tree native_interpret_expr (tree, const unsigned char *, int);
>+extern bool can_native_interpret_type_p (tree);
> 
> /* Fold constants as much as possible in an expression.
>    Returns the simplified expression.
>--- gcc/fold-const.c.jj	2020-01-01 12:15:52.894535959 +0100
>+++ gcc/fold-const.c	2020-01-10 12:47:13.637310535 +0100
>@@ -7837,9 +7837,10 @@ native_encode_string (const_tree expr, u
>     return 0;
>   if (off == -1)
>     off = 0;
>+  len = MIN (total_bytes - off, len);
>   if (ptr == NULL)
>     /* Dry run.  */;
>-  else if (TREE_STRING_LENGTH (expr) - off < MIN (total_bytes, len))
>+  else
>     {
>       int written = 0;
>       if (off < TREE_STRING_LENGTH (expr))
>@@ -7847,12 +7848,9 @@ native_encode_string (const_tree expr, u
> 	  written = MIN (len, TREE_STRING_LENGTH (expr) - off);
> 	  memcpy (ptr, TREE_STRING_POINTER (expr) + off, written);
> 	}
>-      memset (ptr + written, 0,
>-	      MIN (total_bytes - written, len - written));
>+      memset (ptr + written, 0, len - written);
>     }
>-  else
>-    memcpy (ptr, TREE_STRING_POINTER (expr) + off, MIN (total_bytes,
>len));
>-  return MIN (total_bytes - off, len);
>+  return len;
> }
> 
> 
>@@ -7895,6 +7893,213 @@ native_encode_expr (const_tree expr, uns
>     }
> }
> 
>+/* Similar to native_encode_expr, but also handle CONSTRUCTORs, VCEs,
>+   NON_LVALUE_EXPRs and nops.  */
>+
>+int
>+native_encode_initializer (tree init, unsigned char *ptr, int len,
>+			   int off)
>+{
>+  /* We don't support starting at negative offset and -1 is special. 
>*/
>+  if (off < -1 || init == NULL_TREE)
>+    return 0;
>+
>+  STRIP_NOPS (init);
>+  switch (TREE_CODE (init))
>+    {
>+    case VIEW_CONVERT_EXPR:
>+    case NON_LVALUE_EXPR:
>+      return native_encode_initializer (TREE_OPERAND (init, 0), ptr,
>len, off);
>+    default:
>+      return native_encode_expr (init, ptr, len, off);
>+    case CONSTRUCTOR:
>+      tree type = TREE_TYPE (init);
>+      HOST_WIDE_INT total_bytes = int_size_in_bytes (type);
>+      if (total_bytes < 0)
>+	return 0;
>+      if ((off == -1 && total_bytes > len) || off >= total_bytes)
>+	return 0;
>+      int o = off == -1 ? 0 : off;
>+      if (TREE_CODE (type) == ARRAY_TYPE)
>+	{
>+	  HOST_WIDE_INT min_index;
>+	  unsigned HOST_WIDE_INT cnt;
>+	  HOST_WIDE_INT curpos = 0, fieldsize;
>+	  constructor_elt *ce;
>+
>+	  if (TYPE_DOMAIN (type) == NULL_TREE
>+	      || !tree_fits_shwi_p (TYPE_MIN_VALUE (TYPE_DOMAIN (type))))
>+	    return 0;
>+
>+	  fieldsize = int_size_in_bytes (TREE_TYPE (type));
>+	  if (fieldsize <= 0)
>+	    return 0;
>+
>+	  min_index = tree_to_shwi (TYPE_MIN_VALUE (TYPE_DOMAIN (type)));
>+	  if (ptr != NULL)
>+	    memset (ptr, '\0', MIN (total_bytes - off, len));
>+
>+	  FOR_EACH_VEC_SAFE_ELT (CONSTRUCTOR_ELTS (init), cnt, ce)
>+	    {
>+	      tree val = ce->value;
>+	      tree index = ce->index;
>+	      HOST_WIDE_INT pos = curpos, count = 0;
>+	      bool full = false;
>+	      if (index && TREE_CODE (index) == RANGE_EXPR)
>+		{
>+		  if (!tree_fits_shwi_p (TREE_OPERAND (index, 0))
>+		      || !tree_fits_shwi_p (TREE_OPERAND (index, 1)))
>+		    return 0;
>+		  pos = (tree_to_shwi (TREE_OPERAND (index, 0)) - min_index)
>+			* fieldsize;
>+		  count = (tree_to_shwi (TREE_OPERAND (index, 1))
>+			   - tree_to_shwi (TREE_OPERAND (index, 0)));
>+		}
>+	      else if (index)
>+		{
>+		  if (!tree_fits_shwi_p (index))
>+		    return 0;
>+		  pos = (tree_to_shwi (index) - min_index) * fieldsize;
>+		}
>+
>+	      curpos = pos;
>+	      if (val)
>+		do
>+		  {
>+		    if (off == -1
>+			|| (curpos >= off
>+			    && (curpos + fieldsize
>+				<= (HOST_WIDE_INT) off + len)))
>+		      {
>+			if (full)
>+			  {
>+			    if (ptr)
>+			      memcpy (ptr + (curpos - o), ptr + (pos - o),
>+				      fieldsize);
>+			  }
>+			else if (!native_encode_initializer (val,
>+							     ptr
>+							     ? ptr + curpos - o
>+							     : NULL,
>+							     fieldsize,
>+							     off == -1 ? -1
>+								       : 0))
>+			  return 0;
>+			else
>+			  {
>+			    full = true;
>+			    pos = curpos;
>+			  }
>+		      }
>+		    else if (curpos + fieldsize > off
>+			     && curpos < (HOST_WIDE_INT) off + len)
>+		      {
>+			/* Partial overlap.  */
>+			unsigned char *p = NULL;
>+			int no = 0;
>+			int l;
>+			if (curpos >= off)
>+			  {
>+			    if (ptr)
>+			      p = ptr + curpos - off;
>+			    l = MIN ((HOST_WIDE_INT) off + len - curpos,
>+				     fieldsize);
>+			  }
>+			else
>+			  {
>+			    p = ptr;
>+			    no = off - curpos;
>+			    l = len;
>+			  }
>+			if (!native_encode_initializer (val, p, l, no))
>+			  return 0;
>+		      }
>+		    curpos += fieldsize;
>+		  }
>+		while (count-- != 0);
>+	    }
>+	  return MIN (total_bytes - off, len);
>+	}
>+      else if (TREE_CODE (type) == RECORD_TYPE
>+	       || TREE_CODE (type) == UNION_TYPE)
>+	{
>+	  unsigned HOST_WIDE_INT cnt;
>+	  constructor_elt *ce;
>+
>+	  if (ptr != NULL)
>+	    memset (ptr, '\0', MIN (total_bytes - off, len));
>+	  FOR_EACH_VEC_SAFE_ELT (CONSTRUCTOR_ELTS (init), cnt, ce)
>+	    {
>+	      tree field = ce->index;
>+	      tree val = ce->value;
>+	      HOST_WIDE_INT pos, fieldsize;
>+
>+	      if (field == NULL_TREE)
>+		return 0;
>+
>+	      pos = int_byte_position (field);
>+	      if (off != -1 && (HOST_WIDE_INT) off + len <= pos)
>+		continue;
>+
>+	      if (TREE_CODE (TREE_TYPE (field)) == ARRAY_TYPE
>+		  && TYPE_DOMAIN (TREE_TYPE (field))
>+		  && ! TYPE_MAX_VALUE (TYPE_DOMAIN (TREE_TYPE (field))))
>+		return 0;
>+	      if (DECL_SIZE_UNIT (field) == NULL_TREE
>+		  || !tree_fits_shwi_p (DECL_SIZE_UNIT (field)))
>+		return 0;
>+	      fieldsize = tree_to_shwi (DECL_SIZE_UNIT (field));
>+	      if (fieldsize == 0)
>+		continue;
>+
>+	      if (off != -1 && pos + fieldsize <= off)
>+		continue;
>+
>+	      if (DECL_BIT_FIELD (field))
>+		return 0;
>+
>+	      if (val == NULL_TREE)
>+		continue;
>+
>+	      if (off == -1
>+		  || (pos >= off
>+		      && (pos + fieldsize <= (HOST_WIDE_INT) off + len)))
>+		{
>+		  if (!native_encode_initializer (val, ptr ? ptr + pos - o
>+							   : NULL,
>+						  fieldsize,
>+						  off == -1 ? -1 : 0))
>+		    return 0;
>+		}
>+	      else
>+		{
>+		  /* Partial overlap.  */
>+		  unsigned char *p = NULL;
>+		  int no = 0;
>+		  int l;
>+		  if (pos >= off)
>+		    {
>+		      if (ptr)
>+			p = ptr + pos - off;
>+		      l = MIN ((HOST_WIDE_INT) off + len - pos,
>+				fieldsize);
>+		    }
>+		  else
>+		    {
>+		      p = ptr;
>+		      no = off - pos;
>+		      l = len;
>+		    }
>+		  if (!native_encode_initializer (val, p, l, no))
>+		    return 0;
>+		}
>+	    }
>+	  return MIN (total_bytes - off, len);
>+	}
>+      return 0;
>+    }
>+}
>+
> 
> /* Subroutine of native_interpret_expr.  Interpret the contents of
>    the buffer PTR of length LEN as an INTEGER_CST of type TYPE.
>@@ -8129,7 +8334,7 @@ native_interpret_expr (tree type, const
> /* Returns true if we can interpret the contents of a native encoding
>    as TYPE.  */
> 
>-static bool
>+bool
> can_native_interpret_type_p (tree type)
> {
>   switch (TREE_CODE (type))
>--- gcc/gimple-fold.c.jj	2020-01-08 16:54:04.781286448 +0100
>+++ gcc/gimple-fold.c	2020-01-10 11:23:54.071459431 +0100
>@@ -6919,8 +6919,10 @@ fold_ctor_reference (tree type, tree cto
>   if (CONSTANT_CLASS_P (ctor)
>       && BITS_PER_UNIT == 8
>       && offset % BITS_PER_UNIT == 0
>+      && offset / BITS_PER_UNIT <= INT_MAX
>       && size % BITS_PER_UNIT == 0
>-      && size <= MAX_BITSIZE_MODE_ANY_MODE)
>+      && size <= MAX_BITSIZE_MODE_ANY_MODE
>+      && can_native_interpret_type_p (type))
>     {
>       unsigned char buf[MAX_BITSIZE_MODE_ANY_MODE / BITS_PER_UNIT];
>       int len = native_encode_expr (ctor, buf, size / BITS_PER_UNIT,
>@@ -6934,13 +6936,35 @@ fold_ctor_reference (tree type, tree cto
>       if (!suboff)
> 	suboff = &dummy;
> 
>+      tree ret;
>       if (TREE_CODE (TREE_TYPE (ctor)) == ARRAY_TYPE
> 	  || TREE_CODE (TREE_TYPE (ctor)) == VECTOR_TYPE)
>-	return fold_array_ctor_reference (type, ctor, offset, size,
>-					  from_decl, suboff);
>+	ret = fold_array_ctor_reference (type, ctor, offset, size,
>+					 from_decl, suboff);
>+      else
>+	ret = fold_nonarray_ctor_reference (type, ctor, offset, size,
>+					    from_decl, suboff);
>+
>+      /* Fall back to native_encode_initializer.  Needs to be done
>+	 only in the outermost fold_ctor_reference call (because it itself
>+	 recurses into CONSTRUCTORs) and doesn't update suboff.  */
>+      if (ret == NULL_TREE
>+	  && suboff == &dummy
>+	  && BITS_PER_UNIT == 8
>+	  && offset % BITS_PER_UNIT == 0
>+	  && offset / BITS_PER_UNIT <= INT_MAX
>+	  && size % BITS_PER_UNIT == 0
>+	  && size <= MAX_BITSIZE_MODE_ANY_MODE
>+	  && can_native_interpret_type_p (type))
>+	{
>+	  unsigned char buf[MAX_BITSIZE_MODE_ANY_MODE / BITS_PER_UNIT];
>+	  int len = native_encode_initializer (ctor, buf, size /
>BITS_PER_UNIT,
>+					       offset / BITS_PER_UNIT);
>+	  if (len > 0)
>+	    return native_interpret_expr (type, buf, len);
>+	}
> 
>-      return fold_nonarray_ctor_reference (type, ctor, offset, size,
>-					   from_decl, suboff);
>+      return ret;
>     }
> 
>   return NULL_TREE;
>@@ -7049,7 +7073,7 @@ fold_const_aggregate_ref_1 (tree t, tree
> 	tree c = fold_const_aggregate_ref_1 (TREE_OPERAND (t, 0), valueize);
> 	if (c && TREE_CODE (c) == COMPLEX_CST)
> 	  return fold_build1_loc (EXPR_LOCATION (t),
>-			      TREE_CODE (t), TREE_TYPE (t), c);
>+				  TREE_CODE (t), TREE_TYPE (t), c);
> 	break;
>       }
> 
>--- gcc/dwarf2out.c.jj	2020-01-01 12:15:43.000000000 +0100
>+++ gcc/dwarf2out.c	2020-01-10 11:06:03.370522471 +0100
>@@ -20258,150 +20258,6 @@ add_location_or_const_value_attribute (d
>   return tree_add_const_value_attribute_for_decl (die, decl);
> }
> 
>-/* Helper function for tree_add_const_value_attribute.  Natively
>encode
>-   initializer INIT into an array.  Return true if successful.  */
>-
>-static bool
>-native_encode_initializer (tree init, unsigned char *array, int size)
>-{
>-  tree type;
>-
>-  if (init == NULL_TREE)
>-    return false;
>-
>-  STRIP_NOPS (init);
>-  switch (TREE_CODE (init))
>-    {
>-    case STRING_CST:
>-      type = TREE_TYPE (init);
>-      if (TREE_CODE (type) == ARRAY_TYPE)
>-	{
>-	  tree enttype = TREE_TYPE (type);
>-	  scalar_int_mode mode;
>-
>-	  if (!is_int_mode (TYPE_MODE (enttype), &mode)
>-	      || GET_MODE_SIZE (mode) != 1)
>-	    return false;
>-	  if (int_size_in_bytes (type) != size)
>-	    return false;
>-	  if (size > TREE_STRING_LENGTH (init))
>-	    {
>-	      memcpy (array, TREE_STRING_POINTER (init),
>-		      TREE_STRING_LENGTH (init));
>-	      memset (array + TREE_STRING_LENGTH (init),
>-		      '\0', size - TREE_STRING_LENGTH (init));
>-	    }
>-	  else
>-	    memcpy (array, TREE_STRING_POINTER (init), size);
>-	  return true;
>-	}
>-      return false;
>-    case CONSTRUCTOR:
>-      type = TREE_TYPE (init);
>-      if (int_size_in_bytes (type) != size)
>-	return false;
>-      if (TREE_CODE (type) == ARRAY_TYPE)
>-	{
>-	  HOST_WIDE_INT min_index;
>-	  unsigned HOST_WIDE_INT cnt;
>-	  int curpos = 0, fieldsize;
>-	  constructor_elt *ce;
>-
>-	  if (TYPE_DOMAIN (type) == NULL_TREE
>-	      || !tree_fits_shwi_p (TYPE_MIN_VALUE (TYPE_DOMAIN (type))))
>-	    return false;
>-
>-	  fieldsize = int_size_in_bytes (TREE_TYPE (type));
>-	  if (fieldsize <= 0)
>-	    return false;
>-
>-	  min_index = tree_to_shwi (TYPE_MIN_VALUE (TYPE_DOMAIN (type)));
>-	  memset (array, '\0', size);
>-	  FOR_EACH_VEC_SAFE_ELT (CONSTRUCTOR_ELTS (init), cnt, ce)
>-	    {
>-	      tree val = ce->value;
>-	      tree index = ce->index;
>-	      int pos = curpos;
>-	      if (index && TREE_CODE (index) == RANGE_EXPR)
>-		pos = (tree_to_shwi (TREE_OPERAND (index, 0)) - min_index)
>-		      * fieldsize;
>-	      else if (index)
>-		pos = (tree_to_shwi (index) - min_index) * fieldsize;
>-
>-	      if (val)
>-		{
>-		  STRIP_NOPS (val);
>-		  if (!native_encode_initializer (val, array + pos, fieldsize))
>-		    return false;
>-		}
>-	      curpos = pos + fieldsize;
>-	      if (index && TREE_CODE (index) == RANGE_EXPR)
>-		{
>-		  int count = tree_to_shwi (TREE_OPERAND (index, 1))
>-			      - tree_to_shwi (TREE_OPERAND (index, 0));
>-		  while (count-- > 0)
>-		    {
>-		      if (val)
>-			memcpy (array + curpos, array + pos, fieldsize);
>-		      curpos += fieldsize;
>-		    }
>-		}
>-	      gcc_assert (curpos <= size);
>-	    }
>-	  return true;
>-	}
>-      else if (TREE_CODE (type) == RECORD_TYPE
>-	       || TREE_CODE (type) == UNION_TYPE)
>-	{
>-	  tree field = NULL_TREE;
>-	  unsigned HOST_WIDE_INT cnt;
>-	  constructor_elt *ce;
>-
>-	  if (int_size_in_bytes (type) != size)
>-	    return false;
>-
>-	  if (TREE_CODE (type) == RECORD_TYPE)
>-	    field = TYPE_FIELDS (type);
>-
>-	  FOR_EACH_VEC_SAFE_ELT (CONSTRUCTOR_ELTS (init), cnt, ce)
>-	    {
>-	      tree val = ce->value;
>-	      int pos, fieldsize;
>-
>-	      if (ce->index != 0)
>-		field = ce->index;
>-
>-	      if (val)
>-		STRIP_NOPS (val);
>-
>-	      if (field == NULL_TREE || DECL_BIT_FIELD (field))
>-		return false;
>-
>-	      if (TREE_CODE (TREE_TYPE (field)) == ARRAY_TYPE
>-		  && TYPE_DOMAIN (TREE_TYPE (field))
>-		  && ! TYPE_MAX_VALUE (TYPE_DOMAIN (TREE_TYPE (field))))
>-		return false;
>-	      else if (DECL_SIZE_UNIT (field) == NULL_TREE
>-		       || !tree_fits_shwi_p (DECL_SIZE_UNIT (field)))
>-		return false;
>-	      fieldsize = tree_to_shwi (DECL_SIZE_UNIT (field));
>-	      pos = int_byte_position (field);
>-	      gcc_assert (pos + fieldsize <= size);
>-	      if (val && fieldsize != 0
>-		  && !native_encode_initializer (val, array + pos, fieldsize))
>-		return false;
>-	    }
>-	  return true;
>-	}
>-      return false;
>-    case VIEW_CONVERT_EXPR:
>-    case NON_LVALUE_EXPR:
>-      return native_encode_initializer (TREE_OPERAND (init, 0), array,
>size);
>-    default:
>-      return native_encode_expr (init, array, size) == size;
>-    }
>-}
>-
> /* Attach a DW_AT_const_value attribute to DIE. The value of the
>    attribute is the const value T.  */
> 
>@@ -20446,7 +20302,7 @@ tree_add_const_value_attribute (dw_die_r
> 	{
> 	  unsigned char *array = ggc_cleared_vec_alloc<unsigned char> (size);
> 
>-	  if (native_encode_initializer (init, array, size))
>+	  if (native_encode_initializer (init, array, size) == size)
> 	    {
> 	      add_AT_vec (die, DW_AT_const_value, size, 1, array);
> 	      return true;
>--- gcc/testsuite/gcc.dg/pr93210.c.jj	2020-01-10 13:03:25.901743750
>+0100
>+++ gcc/testsuite/gcc.dg/pr93210.c	2020-01-10 13:01:21.567607632 +0100
>@@ -0,0 +1,66 @@
>+/* PR tree-optimization/93210 */
>+/* { dg-do run } */
>+/* { dg-options "-O2 -fdump-tree-optimized" } */
>+/* { dg-final { scan-tree-dump-times "return \[0-9]\[0-9a-fA-FxX]*;"
>31 "optimized" } } */
>+
>+#ifdef __SIZEOF_INT128__
>+typedef unsigned __int128 L;
>+#else
>+typedef unsigned long long L;
>+#endif
>+struct S { signed char a, b; unsigned char c; };
>+struct T { signed char d; struct S e[25]; signed char f; };
>+union U { struct T g; L h[10]; };
>+const union U u = { { 1, { { 2, 3, 4 }, { 5, 6, 7 }, { 8, 9, 10 },
>+                           { 12, 13, 14 }, { 15, 16, 17 }, { 18, 19,
>20 },
>+                           { 22, 23, 24 }, { 25, 26, 27 }, { 28, 29,
>30 },
>+                           { 32, 33, 34 }, { 35, 36, 37 }, { 38, 39,
>40 },
>+                           { 42, 43, 44 }, { 45, 46, 47 }, { 48, 49,
>50 },
>+                           { 52, 53, 54 }, { 55, 56, 57 }, { 58, 59,
>60 },
>+                           { 62, 63, 64 }, { 65, 66, 67 }, { 68, 69,
>70 },
>+                           { 72, 73, 74 }, { 75, 76, 77 }, { 78, 79,
>80 },
>+                           { 82, 83, 84 } }, 85 } };
>+const union U v = { { 1, { { 2, 3, 4 }, [1 ... 23] = { 5, 6, 7 },
>+			   { 8, 9, 10 } }, 86 } };
>+struct A { char a[5]; char b[16]; char c[7]; };
>+union V { struct A d; unsigned int e[10]; };
>+const union V w = { { "abcde", "ijkl", "mnopqr" } };
>+#define N(n) __attribute__((noipa)) L foo##n (void) { return u.h[n]; }
>+#define M N(0) N(1) N(2) N(3) N(4) N(5) N(6) N(7) N(8) N(9)
>+M
>+#undef N
>+#define N(n) __attribute__((noipa)) L bar##n (void) { return v.h[n]; }
>+M
>+#undef N
>+#define N(n) __attribute__((noipa)) L baz##n (void) { return w.e[n]; }
>+M
>+
>+typedef L (*F) (void);
>+F arr[30] = {
>+#undef N
>+#define N(n) foo##n,
>+M
>+#undef N
>+#define N(n) bar##n,
>+M
>+#undef N
>+#define N(n) baz##n,
>+M
>+};
>+
>+int
>+main ()
>+{
>+  const union U *p = &u;
>+  const union U *q = &v;
>+  const union V *r = &w;
>+  __asm ("" : "+g" (p));
>+  __asm ("" : "+g" (q));
>+  __asm ("" : "+g" (r));
>+  for (int i = 0; i < 10; i++)
>+    if (arr[i] () != p->h[i]
>+	|| arr[i + 10] () != q->h[i]
>+	|| arr[i + 20] () != r->e[i])
>+      __builtin_abort ();
>+  return 0;
>+}
>--- gcc/testsuite/g++.dg/opt/pr93210.C.jj	2020-01-10 13:11:57.065082378
>+0100
>+++ gcc/testsuite/g++.dg/opt/pr93210.C	2020-01-10 13:13:53.138342895
>+0100
>@@ -0,0 +1,37 @@
>+// PR tree-optimization/93210
>+// { dg-do compile { target c++11 } }
>+// { dg-options "-O2 -fdump-tree-optimized" }
>+// { dg-final { scan-tree-dump-not "static_member\.d" "optimized" } }
>+
>+union U { struct { unsigned int a, b; } c; unsigned long long d; };
>+
>+inline
>+bool operator == (U const &x, U const &y) noexcept
>+{
>+  return x.d == y.d;
>+};
>+
>+struct S
>+{
>+  static constexpr U static_member = { { 13, 42 } };
>+  bool foo (U const &y) const noexcept;
>+  bool bar (U const &y) const noexcept;
>+};
>+
>+#if __cpp_inline_variables < 201606L
>+constexpr U S::static_member;
>+#endif
>+
>+#if __SIZEOF_INT__ * 2 == __SIZEOF_LONG_LONG__
>+bool
>+S::foo (U const &y) const noexcept
>+{
>+  return static_member == y;
>+}
>+
>+bool
>+S::bar (U const &y) const noexcept
>+{
>+  return U (static_member) == y;
>+}
>+#endif
>
>	Jakub



More information about the Gcc-patches mailing list