[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