On January 10, 2020 3:04:07 PM GMT+01:00, Jakub Jelinek <ja...@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  <ja...@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

Reply via email to