gcc/sccvn-Improve-handling-of-load-masked-with-integer.patch
eastb233 01e0ec8ea6 Upload GCC feature and bugfix patches.
- avoid-cycling-on-vertain-subreg-reloads.patch: Add patch source comment
- change-gcc-BASE-VER.patch: Likewise
- dont-generate-IF_THEN_ELSE.patch: Likewise
- fix-ICE-in-compute_live_loop_exits.patch: Likewise
- fix-ICE-in-eliminate_stmt.patch: Likewise
- fix-ICE-in-vect_create_epilog_for_reduction.patch: Likewise
- fix-ICE-in-vect_stmt_to_vectorize.patch: Likewise
- fix-ICE-in-verify_ssa.patch: Likewise
- fix-ICE-when-vectorizing-nested-cycles.patch: Likewise
- fix-cost-of-plus.patch: Likewise
- ipa-const-prop-self-recursion-bugfix.patch: Likewise
- simplify-removing-subregs.patch: Likewise
- medium-code-mode.patch: Bugfix
- fix-when-peeling-for-alignment.patch: Move to ...
- fix-PR-92351-When-peeling-for-alignment.patch: ... this
- AArch64-Fix-constraints-for-CPY-M.patch: New file
- Apply-maximum-nunits-for-BB-SLP.patch: New file
- Fix-EXTRACT_LAST_REDUCTION-segfault.patch: New file
- Fix-up-push_partial_def-little-endian-bitfield.patch: New file
- Fix-zero-masking-for-vcvtps2ph.patch: New file
- IRA-Handle-fully-tied-destinations.patch: New file
- SLP-VECT-Add-check-to-fix-96837.patch: New file
- aarch64-Fix-ash-lr-lshr-mode-3-expanders.patch: New file
- aarch64-Fix-bf16-and-matrix-g++-gfortran.patch: New file
- aarch64-Fix-mismatched-SVE-predicate-modes.patch: New file
- aarch64-fix-sve-acle-error.patch: New file
- adjust-vector-cost-and-move-EXTRACT_LAST_REDUCTION-costing.patch: New file
- bf16-and-matrix-characteristic.patch: New file
- fix-ICE-IPA-compare-VRP-types.patch: New file
- fix-ICE-in-affine-combination.patch: New file
- fix-ICE-in-pass-vect.patch: New file
- fix-ICE-in-vect_update_misalignment_for_peel.patch: New file
- fix-addlosymdi-ICE-in-pass-reload.patch: New file
- fix-an-ICE-in-vect_recog_mask_conversion_pattern.patch: New file
- fix-avx512vl-vcvttpd2dq-2-fail.patch: New file
- fix-issue499-add-nop-convert.patch: New file
- fix-issue604-ldist-dependency-fixup.patch: New file
- modulo-sched-Carefully-process-loop-counter-initiali.patch: New file
- re-PR-target-91124-gcc.target-i386-avx512vl-vpshldvd.patch: New file
- reduction-paths-with-unhandled-live-stmt.patch: New file
- redundant-loop-elimination.patch: New file
- sccvn-Improve-handling-of-load-masked-with-integer.patch: New file
- speed-up-DDG-analysis-and-fix-bootstrap-compare-debug.patch: New file
- store-merging-Consider-also-overlapping-stores-earlier.patch: New file
- tree-optimization-96920-another-ICE-when-vectorizing.patch: New file
- tree-optimization-97812-fix-range-query-in-VRP-asser.patch: New file
- vectorizable-comparison-Swap-operands-only-once.patch: New file
- x86-Fix-bf16-and-matrix.patch: New file
2020-12-30 09:54:10 +08:00

2398 lines
79 KiB
Diff

This backport contains 14 patch from gcc main stream tree.
The commit id of these patchs list as following in the order of time.
c2851dc2896bfc0d27b32c90cafc873f67cd6727
0001-tree-ssa-sccvn.c-struct-vn_walk_cb_data-Add-orig_ref.patch
69b5279e977593d656906288316ee03a8bf79c6a
0001-gimple-parser.c-c_parser_gimple_postfix_expression-H.patch
8389386c6d55d57afc3ae01f71546ac4468f7926
0001-gimple-parser.c-c_parser_gimple_postfix_expression-S.patch
d1f2e4c1027b826cf3ba353e86c37589f63f8efe
0001-tree-ssa-sccvn.c-vn_walk_cb_data-push_partial_def-Re.patch
62e3e66f130fc280eac0bbb6b69e9adca328c03b
0001-re-PR-tree-optimization-83518-Missing-optimization-u.patch
10f30ac9cda947d117e50f0cbd4cf94ee70a944f
0001-re-PR-tree-optimization-91756-g-.dg-lto-alias-3-FAIL.patch
1284e2b104a81ad93daab5110cd844981e501086
0001-re-PR-tree-optimization-90883-Generated-code-is-wors.patch
fb08a53b2eb01cc06d66f479c865aca55c91fd26
0001-tree-ssa-sccvn.c-vn_walk_cb_data-push_partial_def-Ba.patch
0849cdae714ddf056a4944f31eef53a465f1bcd0
0001-tree-ssa-sccvn.c-vn_walk_cb_data-push_partial_def-Ha.patch
5f0653a8b75a5ad5a5405a27dd92d3a5759eed4c
0001-tree-optimization-91123-restore-redundant-store-remo.patch
8aba425f4ebc5e2c054776d3cdddf13f7c1918f8
0001-sccvn-Handle-bitfields-in-vn_reference_lookup_3-PR93.patch
7f5617b00445dcc861a498a4cecc8aaa59e05b8c
0001-sccvn-Handle-bitfields-in-push_partial_def-PR93582.patch
5f9cd512c4278621435cce486dd00248ea2e821c
0001-sccvn-Handle-non-byte-aligned-offset-or-size-for-mem.patch
b07e4e7c7520ca3e798f514dec0711eea2c027be
0001-sccvn-Improve-handling-of-load-masked-with-integer-c.patch
diff -urpN a/gcc/c/gimple-parser.c b/gcc/c/gimple-parser.c
--- a/gcc/c/gimple-parser.c 2020-11-26 22:26:34.848000000 -0500
+++ b/gcc/c/gimple-parser.c 2020-11-26 22:06:08.032000000 -0500
@@ -1320,17 +1320,24 @@ c_parser_gimple_postfix_expression (gimp
}
else
{
- bool neg_p;
+ bool neg_p, addr_p;
if ((neg_p = c_parser_next_token_is (parser, CPP_MINUS)))
c_parser_consume_token (parser);
+ if ((addr_p = c_parser_next_token_is (parser, CPP_AND)))
+ c_parser_consume_token (parser);
tree val = c_parser_gimple_postfix_expression (parser).value;
if (! val
|| val == error_mark_node
- || ! CONSTANT_CLASS_P (val))
+ || (!CONSTANT_CLASS_P (val)
+ && !(addr_p
+ && (TREE_CODE (val) == STRING_CST
+ || DECL_P (val)))))
{
c_parser_error (parser, "invalid _Literal");
return expr;
}
+ if (addr_p)
+ val = build1 (ADDR_EXPR, type, val);
if (neg_p)
{
val = const_unop (NEGATE_EXPR, TREE_TYPE (val), val);
diff -urpN a/gcc/fold-const.c b/gcc/fold-const.c
--- a/gcc/fold-const.c 2020-11-26 22:26:32.816000000 -0500
+++ b/gcc/fold-const.c 2020-11-26 22:06:08.036000000 -0500
@@ -7773,6 +7773,70 @@ native_decode_vector_tree (tree type, ve
return builder.build ();
}
+/* Routines for manipulation of native_encode_expr encoded data if the encoded
+ or extracted constant positions and/or sizes aren't byte aligned. */
+
+/* Shift left the bytes in PTR of SZ elements by AMNT bits, carrying over the
+ bits between adjacent elements. AMNT should be within
+ [0, BITS_PER_UNIT).
+ Example, AMNT = 2:
+ 00011111|11100000 << 2 = 01111111|10000000
+ PTR[1] | PTR[0] PTR[1] | PTR[0]. */
+
+void
+shift_bytes_in_array_left (unsigned char *ptr, unsigned int sz,
+ unsigned int amnt)
+{
+ if (amnt == 0)
+ return;
+
+ unsigned char carry_over = 0U;
+ unsigned char carry_mask = (~0U) << (unsigned char) (BITS_PER_UNIT - amnt);
+ unsigned char clear_mask = (~0U) << amnt;
+
+ for (unsigned int i = 0; i < sz; i++)
+ {
+ unsigned prev_carry_over = carry_over;
+ carry_over = (ptr[i] & carry_mask) >> (BITS_PER_UNIT - amnt);
+
+ ptr[i] <<= amnt;
+ if (i != 0)
+ {
+ ptr[i] &= clear_mask;
+ ptr[i] |= prev_carry_over;
+ }
+ }
+}
+
+/* Like shift_bytes_in_array_left but for big-endian.
+ Shift right the bytes in PTR of SZ elements by AMNT bits, carrying over the
+ bits between adjacent elements. AMNT should be within
+ [0, BITS_PER_UNIT).
+ Example, AMNT = 2:
+ 00011111|11100000 >> 2 = 00000111|11111000
+ PTR[0] | PTR[1] PTR[0] | PTR[1]. */
+
+void
+shift_bytes_in_array_right (unsigned char *ptr, unsigned int sz,
+ unsigned int amnt)
+{
+ if (amnt == 0)
+ return;
+
+ unsigned char carry_over = 0U;
+ unsigned char carry_mask = ~(~0U << amnt);
+
+ for (unsigned int i = 0; i < sz; i++)
+ {
+ unsigned prev_carry_over = carry_over;
+ carry_over = ptr[i] & carry_mask;
+
+ carry_over <<= (unsigned char) BITS_PER_UNIT - amnt;
+ ptr[i] >>= amnt;
+ ptr[i] |= prev_carry_over;
+ }
+}
+
/* Try to view-convert VECTOR_CST EXPR to VECTOR_TYPE TYPE by operating
directly on the VECTOR_CST encoding, in a way that works for variable-
length vectors. Return the resulting VECTOR_CST on success or null
diff -urpN a/gcc/fold-const.h b/gcc/fold-const.h
--- a/gcc/fold-const.h 2020-11-26 22:26:32.816000000 -0500
+++ b/gcc/fold-const.h 2020-11-26 22:06:08.036000000 -0500
@@ -27,6 +27,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 tree native_interpret_expr (tree, const unsigned char *, int);
+extern void shift_bytes_in_array_left (unsigned char *, unsigned int,
+ unsigned int);
+extern void shift_bytes_in_array_right (unsigned char *, unsigned int,
+ unsigned int);
/* Fold constants as much as possible in an expression.
Returns the simplified expression.
diff -urpN a/gcc/gimple-ssa-store-merging.c b/gcc/gimple-ssa-store-merging.c
--- a/gcc/gimple-ssa-store-merging.c 2020-11-26 22:26:32.860000000 -0500
+++ b/gcc/gimple-ssa-store-merging.c 2020-11-26 22:06:08.036000000 -0500
@@ -1464,66 +1464,6 @@ dump_char_array (FILE *fd, unsigned char
fprintf (fd, "\n");
}
-/* Shift left the bytes in PTR of SZ elements by AMNT bits, carrying over the
- bits between adjacent elements. AMNT should be within
- [0, BITS_PER_UNIT).
- Example, AMNT = 2:
- 00011111|11100000 << 2 = 01111111|10000000
- PTR[1] | PTR[0] PTR[1] | PTR[0]. */
-
-static void
-shift_bytes_in_array (unsigned char *ptr, unsigned int sz, unsigned int amnt)
-{
- if (amnt == 0)
- return;
-
- unsigned char carry_over = 0U;
- unsigned char carry_mask = (~0U) << (unsigned char) (BITS_PER_UNIT - amnt);
- unsigned char clear_mask = (~0U) << amnt;
-
- for (unsigned int i = 0; i < sz; i++)
- {
- unsigned prev_carry_over = carry_over;
- carry_over = (ptr[i] & carry_mask) >> (BITS_PER_UNIT - amnt);
-
- ptr[i] <<= amnt;
- if (i != 0)
- {
- ptr[i] &= clear_mask;
- ptr[i] |= prev_carry_over;
- }
- }
-}
-
-/* Like shift_bytes_in_array but for big-endian.
- Shift right the bytes in PTR of SZ elements by AMNT bits, carrying over the
- bits between adjacent elements. AMNT should be within
- [0, BITS_PER_UNIT).
- Example, AMNT = 2:
- 00011111|11100000 >> 2 = 00000111|11111000
- PTR[0] | PTR[1] PTR[0] | PTR[1]. */
-
-static void
-shift_bytes_in_array_right (unsigned char *ptr, unsigned int sz,
- unsigned int amnt)
-{
- if (amnt == 0)
- return;
-
- unsigned char carry_over = 0U;
- unsigned char carry_mask = ~(~0U << amnt);
-
- for (unsigned int i = 0; i < sz; i++)
- {
- unsigned prev_carry_over = carry_over;
- carry_over = ptr[i] & carry_mask;
-
- carry_over <<= (unsigned char) BITS_PER_UNIT - amnt;
- ptr[i] >>= amnt;
- ptr[i] |= prev_carry_over;
- }
-}
-
/* Clear out LEN bits starting from bit START in the byte array
PTR. This clears the bits to the *right* from START.
START must be within [0, BITS_PER_UNIT) and counts starting from
@@ -1749,7 +1689,7 @@ encode_tree_to_bitpos (tree expr, unsign
/* Create the shifted version of EXPR. */
if (!BYTES_BIG_ENDIAN)
{
- shift_bytes_in_array (tmpbuf, byte_size, shift_amnt);
+ shift_bytes_in_array_left (tmpbuf, byte_size, shift_amnt);
if (shift_amnt == 0)
byte_size--;
}
@@ -4667,11 +4607,11 @@ verify_array_eq (unsigned char *x, unsig
}
}
-/* Test shift_bytes_in_array and that it carries bits across between
+/* Test shift_bytes_in_array_left and that it carries bits across between
bytes correctly. */
static void
-verify_shift_bytes_in_array (void)
+verify_shift_bytes_in_array_left (void)
{
/* byte 1 | byte 0
00011111 | 11100000. */
@@ -4680,13 +4620,13 @@ verify_shift_bytes_in_array (void)
memcpy (in, orig, sizeof orig);
unsigned char expected[2] = { 0x80, 0x7f };
- shift_bytes_in_array (in, sizeof (in), 2);
+ shift_bytes_in_array_left (in, sizeof (in), 2);
verify_array_eq (in, expected, sizeof (in));
memcpy (in, orig, sizeof orig);
memcpy (expected, orig, sizeof orig);
/* Check that shifting by zero doesn't change anything. */
- shift_bytes_in_array (in, sizeof (in), 0);
+ shift_bytes_in_array_left (in, sizeof (in), 0);
verify_array_eq (in, expected, sizeof (in));
}
@@ -4771,7 +4711,7 @@ verify_clear_bit_region_be (void)
void
store_merging_c_tests (void)
{
- verify_shift_bytes_in_array ();
+ verify_shift_bytes_in_array_left ();
verify_shift_bytes_in_array_right ();
verify_clear_bit_region ();
verify_clear_bit_region_be ();
diff -urpN a/gcc/testsuite/gcc.c-torture/execute/pr93582.c b/gcc/testsuite/gcc.c-torture/execute/pr93582.c
--- a/gcc/testsuite/gcc.c-torture/execute/pr93582.c 1969-12-31 19:00:00.000000000 -0500
+++ b/gcc/testsuite/gcc.c-torture/execute/pr93582.c 2020-11-26 22:25:43.532000000 -0500
@@ -0,0 +1,22 @@
+/* PR tree-optimization/93582 */
+
+short a;
+int b, c;
+
+__attribute__((noipa)) void
+foo (void)
+{
+ b = c;
+ a &= 7;
+}
+
+int
+main ()
+{
+ c = 27;
+ a = 14;
+ foo ();
+ if (b != 27 || a != 6)
+ __builtin_abort ();
+ return 0;
+}
diff -urpN a/gcc/testsuite/gcc.dg/gimplefe-42.c b/gcc/testsuite/gcc.dg/gimplefe-42.c
--- a/gcc/testsuite/gcc.dg/gimplefe-42.c 1969-12-31 19:00:00.000000000 -0500
+++ b/gcc/testsuite/gcc.dg/gimplefe-42.c 2020-11-26 22:06:08.036000000 -0500
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+/* { dg-options "-fgimple" } */
+
+typedef char ref_all_char __attribute__((may_alias));
+char a[7];
+__GIMPLE void f()
+{
+ int _1;
+ /* string literals inside __MEM need their address taken. */
+ __MEM <char[7]> ((ref_all_char *)&a)
+ = __MEM <char[7]> (_Literal (char *) &"654321");
+ /* but plain assignment also works. */
+ __MEM <char[7]> ((ref_all_char *)&a) = "654321";
+ /* also punning with int. */
+ _1 = __MEM <int> (_Literal (char *) &"654321");
+ __MEM <int> ((ref_all_char *)&a) = _1;
+ return;
+}
diff -urpN a/gcc/testsuite/gcc.dg/pr93582.c b/gcc/testsuite/gcc.dg/pr93582.c
--- a/gcc/testsuite/gcc.dg/pr93582.c 1969-12-31 19:00:00.000000000 -0500
+++ b/gcc/testsuite/gcc.dg/pr93582.c 2020-11-26 22:26:15.784000000 -0500
@@ -0,0 +1,57 @@
+/* PR tree-optimization/93582 */
+/* { dg-do compile } */
+/* { dg-options "-O2 -Warray-bounds" } */
+
+struct S {
+ unsigned int s1:1;
+ unsigned int s2:1;
+ unsigned int s3:1;
+ unsigned int s4:1;
+ unsigned int s5:4;
+ unsigned char s6;
+ unsigned short s7;
+ unsigned short s8;
+};
+struct T {
+ int t1;
+ int t2;
+};
+
+static inline int
+bar (struct S *x)
+{
+ if (x->s4)
+ return ((struct T *)(x + 1))->t1 + ((struct T *)(x + 1))->t2; /* { dg-bogus "array subscript 1 is outside array bounds of" } */
+ else
+ return 0;
+}
+
+int
+foo (int x, int y)
+{
+ struct S s; /* { dg-bogus "while referencing" } */
+ s.s6 = x;
+ s.s7 = y & 0x1FFF;
+ s.s4 = 0;
+ return bar (&s);
+}
+
+static inline int
+qux (struct S *x)
+{
+ int s4 = x->s4;
+ if (s4)
+ return ((struct T *)(x + 1))->t1 + ((struct T *)(x + 1))->t2;
+ else
+ return 0;
+}
+
+int
+baz (int x, int y)
+{
+ struct S s;
+ s.s6 = x;
+ s.s7 = y & 0x1FFF;
+ s.s4 = 0;
+ return qux (&s);
+}
diff -urpN a/gcc/testsuite/gcc.dg/torture/ssa-fre-5.c b/gcc/testsuite/gcc.dg/torture/ssa-fre-5.c
--- a/gcc/testsuite/gcc.dg/torture/ssa-fre-5.c 1969-12-31 19:00:00.000000000 -0500
+++ b/gcc/testsuite/gcc.dg/torture/ssa-fre-5.c 2020-11-26 22:06:08.036000000 -0500
@@ -0,0 +1,27 @@
+/* { dg-do compile } */
+/* { dg-skip-if "" { *-*-* } { "-O0" } { "" } } */
+/* { dg-additional-options "-fgimple -fdump-tree-fre1" } */
+
+typedef int v4si __attribute__((vector_size(16)));
+
+int __GIMPLE (ssa,startwith("fre"))
+foo ()
+{
+ int * p;
+ int i;
+ int x[4];
+ long unsigned int _1;
+ long unsigned int _2;
+ int _7;
+
+ __BB(2):
+ i_3 = 0;
+ _1 = (long unsigned int) i_3;
+ _2 = _1 * 4ul;
+ p_4 = _Literal (int *) &x + _2;
+ __MEM <v4si> ((v4si *)p_4) = _Literal (v4si) { 1, 2, 3, 4 };
+ _7 = x[0];
+ return _7;
+}
+
+/* { dg-final { scan-tree-dump "return 1;" "fre1" } } */
diff -urpN a/gcc/testsuite/gcc.dg/torture/ssa-fre-6.c b/gcc/testsuite/gcc.dg/torture/ssa-fre-6.c
--- a/gcc/testsuite/gcc.dg/torture/ssa-fre-6.c 1969-12-31 19:00:00.000000000 -0500
+++ b/gcc/testsuite/gcc.dg/torture/ssa-fre-6.c 2020-11-26 22:06:08.036000000 -0500
@@ -0,0 +1,27 @@
+/* { dg-do compile } */
+/* { dg-skip-if "" { *-*-* } { "-O0" } { "" } } */
+/* { dg-additional-options "-fgimple -fdump-tree-fre1" } */
+
+typedef int v4si __attribute__((vector_size(16)));
+
+int __GIMPLE (ssa,startwith("fre"))
+foo ()
+{
+ int * p;
+ int i;
+ int x[4];
+ long unsigned int _1;
+ long unsigned int _2;
+ int _7;
+
+ __BB(2):
+ i_3 = 0;
+ _1 = (long unsigned int) i_3;
+ _2 = _1 * 4ul;
+ p_4 = _Literal (int *) &x + _2;
+ __MEM <v4si> ((v4si *)p_4) = _Literal (v4si) {};
+ _7 = x[0];
+ return _7;
+}
+
+/* { dg-final { scan-tree-dump "return 0;" "fre1" } } */
diff -urpN a/gcc/testsuite/gcc.dg/torture/ssa-fre-7.c b/gcc/testsuite/gcc.dg/torture/ssa-fre-7.c
--- a/gcc/testsuite/gcc.dg/torture/ssa-fre-7.c 1969-12-31 19:00:00.000000000 -0500
+++ b/gcc/testsuite/gcc.dg/torture/ssa-fre-7.c 2020-11-26 22:06:08.036000000 -0500
@@ -0,0 +1,29 @@
+/* { dg-do compile } */
+/* { dg-skip-if "" { *-*-* } { "-O0" } { "" } } */
+/* { dg-additional-options "-fgimple -fdump-tree-fre1" } */
+
+typedef int v4si __attribute__((vector_size(16)));
+
+int __GIMPLE (ssa,startwith("fre"))
+foo (int c)
+{
+ int * p;
+ int i;
+ int x[4];
+ long unsigned int _1;
+ long unsigned int _2;
+ int _7;
+ v4si _6;
+
+ __BB(2):
+ i_3 = 0;
+ _1 = (long unsigned int) i_3;
+ _2 = _1 * 4ul;
+ p_4 = _Literal (int *) &x + _2;
+ _6 = _Literal (v4si) { c_5(D), c_5(D), c_5(D), c_5(D) };
+ __MEM <v4si> ((v4si *)p_4) = _6;
+ _7 = x[0];
+ return _7;
+}
+
+/* { dg-final { scan-tree-dump "return c_5\\(D\\);" "fre1" } } */
diff -urpN a/gcc/testsuite/gcc.dg/tree-ssa/alias-access-path-1.c b/gcc/testsuite/gcc.dg/tree-ssa/alias-access-path-1.c
--- a/gcc/testsuite/gcc.dg/tree-ssa/alias-access-path-1.c 2020-11-26 22:26:34.324000000 -0500
+++ b/gcc/testsuite/gcc.dg/tree-ssa/alias-access-path-1.c 2020-11-26 22:06:08.036000000 -0500
@@ -1,5 +1,5 @@
/* { dg-do compile } */
-/* { dg-options "-O2 -fdump-tree-fre3" } */
+/* { dg-options "-O2 -fdump-tree-fre1" } */
struct foo
{
int val;
@@ -18,4 +18,4 @@ test ()
return barptr->val2;
}
-/* { dg-final { scan-tree-dump-times "return 123" 1 "fre3"} } */
+/* { dg-final { scan-tree-dump-times "return 123" 1 "fre1"} } */
diff -urpN a/gcc/testsuite/gcc.dg/tree-ssa/pr93582-10.c b/gcc/testsuite/gcc.dg/tree-ssa/pr93582-10.c
--- a/gcc/testsuite/gcc.dg/tree-ssa/pr93582-10.c 1969-12-31 19:00:00.000000000 -0500
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr93582-10.c 2020-11-26 22:24:45.812000000 -0500
@@ -0,0 +1,29 @@
+/* PR tree-optimization/93582 */
+/* { dg-do compile { target int32 } } */
+/* { dg-options "-O2 -fdump-tree-fre1" } */
+/* { dg-final { scan-tree-dump "return 72876566;" "fre1" { target le } } } */
+/* { dg-final { scan-tree-dump "return 559957376;" "fre1" { target be } } } */
+
+union U {
+ struct S { int a : 12, b : 5, c : 10, d : 5; } s;
+ unsigned int i;
+};
+struct A { char a[12]; union U u; };
+void bar (struct A *);
+
+unsigned
+foo (void)
+{
+ struct A a;
+ bar (&a);
+ a.u.s.a = 1590;
+ a.u.s.c = -404;
+#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+#define M 0x67e0a5f
+#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
+#define M 0xa5f067e0
+#else
+#define M 0
+#endif
+ return a.u.i & M;
+}
diff -urpN a/gcc/testsuite/gcc.dg/tree-ssa/pr93582-1.c b/gcc/testsuite/gcc.dg/tree-ssa/pr93582-1.c
--- a/gcc/testsuite/gcc.dg/tree-ssa/pr93582-1.c 1969-12-31 19:00:00.000000000 -0500
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr93582-1.c 2020-11-26 22:18:39.368000000 -0500
@@ -0,0 +1,18 @@
+/* PR tree-optimization/93582 */
+/* { dg-do compile { target int32 } } */
+/* { dg-options "-O2 -fdump-tree-fre1" } */
+/* { dg-final { scan-tree-dump "return 1;" "fre1" } } */
+
+union U {
+ struct S { int a : 1, b : 4, c : 27; } s;
+ struct T { int d : 2; int e : 2; int f : 28; } t;
+};
+
+int
+foo (void)
+{
+ union U u;
+ u.s.b = 10;
+ return u.t.e;
+}
+
diff -urpN a/gcc/testsuite/gcc.dg/tree-ssa/pr93582-2.c b/gcc/testsuite/gcc.dg/tree-ssa/pr93582-2.c
--- a/gcc/testsuite/gcc.dg/tree-ssa/pr93582-2.c 1969-12-31 19:00:00.000000000 -0500
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr93582-2.c 2020-11-26 22:18:44.832000000 -0500
@@ -0,0 +1,17 @@
+/* PR tree-optimization/93582 */
+/* { dg-do compile { target int32 } } */
+/* { dg-options "-O2 -fdump-tree-fre1" } */
+/* { dg-final { scan-tree-dump "return 593;" "fre1" } } */
+
+union U {
+ struct S { int a : 1, b : 14, c : 17; } s;
+ struct T { int d : 2; int e : 12; int f : 18; } t;
+};
+
+int
+foo (void)
+{
+ union U u;
+ u.s.b = -7005;
+ return u.t.e;
+}
diff -urpN a/gcc/testsuite/gcc.dg/tree-ssa/pr93582-3.c b/gcc/testsuite/gcc.dg/tree-ssa/pr93582-3.c
--- a/gcc/testsuite/gcc.dg/tree-ssa/pr93582-3.c 1969-12-31 19:00:00.000000000 -0500
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr93582-3.c 2020-11-26 22:21:44.936000000 -0500
@@ -0,0 +1,19 @@
+/* PR tree-optimization/93582 */
+/* { dg-do compile { target int32 } } */
+/* { dg-options "-O2 -fdump-tree-fre1" } */
+/* { dg-final { scan-tree-dump "return 1;" "fre1" { target be } } } */
+/* { dg-final { scan-tree-dump "return 2;" "fre1" { target le } } } */
+
+union U {
+ struct S { int a : 1, b : 14, c : 17; } s;
+ struct T { int d : 10; int e : 4; int f : 18; } t;
+};
+
+int
+foo (void)
+{
+ union U u;
+ u.s.b = -7005;
+ return u.t.e;
+}
+
diff -urpN a/gcc/testsuite/gcc.dg/tree-ssa/pr93582-4.c b/gcc/testsuite/gcc.dg/tree-ssa/pr93582-4.c
--- a/gcc/testsuite/gcc.dg/tree-ssa/pr93582-4.c 1969-12-31 19:00:00.000000000 -0500
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr93582-4.c 2020-11-26 22:23:33.236000000 -0500
@@ -0,0 +1,24 @@
+/* PR tree-optimization/93582 */
+/* { dg-do compile { target int32 } } */
+/* { dg-options "-O2 -fdump-tree-fre1" } */
+/* { dg-final { scan-tree-dump "return -1991560811;" "fre1" { target le } } } */
+/* { dg-final { scan-tree-dump "return -733324916;" "fre1" { target be } } } */
+
+union U {
+ struct S { int a : 1, b : 4, c : 27; } s;
+ unsigned int i;
+};
+struct A { char a[24]; union U u; };
+void bar (struct A *);
+
+int
+foo (void)
+{
+ struct A a;
+ bar (&a);
+ a.u.s.a = -1;
+ a.u.s.b = -6;
+ a.u.s.c = -62236276;
+ return a.u.i;
+}
+
diff -urpN a/gcc/testsuite/gcc.dg/tree-ssa/pr93582-5.c b/gcc/testsuite/gcc.dg/tree-ssa/pr93582-5.c
--- a/gcc/testsuite/gcc.dg/tree-ssa/pr93582-5.c 1969-12-31 19:00:00.000000000 -0500
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr93582-5.c 2020-11-26 22:23:38.324000000 -0500
@@ -0,0 +1,26 @@
+/* PR tree-optimization/93582 */
+/* { dg-do compile { target int32 } } */
+/* { dg-options "-O2 -fdump-tree-fre1" } */
+/* { dg-final { scan-tree-dump "return -1462729318;" "fre1" { target le } } } */
+/* { dg-final { scan-tree-dump "return 1300568597;" "fre1" { target be } } } */
+
+union U {
+ struct S { int a : 1, b : 7, c : 8, d : 11, e : 5; } s;
+ unsigned int i;
+};
+struct A { char a[8]; union U u; };
+void bar (struct A *);
+
+int
+foo (void)
+{
+ struct A a;
+ bar (&a);
+ a.u.s.a = 0;
+ a.u.s.b = -51;
+ a.u.s.c = -123;
+ a.u.s.d = 208;
+ a.u.s.e = -11;
+ return a.u.i;
+}
+
diff -urpN a/gcc/testsuite/gcc.dg/tree-ssa/pr93582-6.c b/gcc/testsuite/gcc.dg/tree-ssa/pr93582-6.c
--- a/gcc/testsuite/gcc.dg/tree-ssa/pr93582-6.c 1969-12-31 19:00:00.000000000 -0500
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr93582-6.c 2020-11-26 22:23:42.348000000 -0500
@@ -0,0 +1,25 @@
+/* PR tree-optimization/93582 */
+/* { dg-do compile { target int32 } } */
+/* { dg-options "-O2 -fdump-tree-fre1" } */
+/* { dg-final { scan-tree-dump "return 890118;" "fre1" { target le } } } */
+/* { dg-final { scan-tree-dump "return 447899;" "fre1" { target be } } } */
+
+union U {
+ struct S { int a : 16, b : 5, c : 10, d : 1; } s;
+ struct T { int a : 8, b : 21, c : 3; } t;
+};
+struct A { char a[4]; union U u; };
+void bar (struct A *);
+
+int
+foo (void)
+{
+ struct A a;
+ bar (&a);
+ a.u.s.a = 1590;
+ a.u.s.b = -11;
+ a.u.s.c = 620;
+ a.u.s.d = -1;
+ return a.u.t.b;
+}
+
diff -urpN a/gcc/testsuite/gcc.dg/tree-ssa/pr93582-7.c b/gcc/testsuite/gcc.dg/tree-ssa/pr93582-7.c
--- a/gcc/testsuite/gcc.dg/tree-ssa/pr93582-7.c 1969-12-31 19:00:00.000000000 -0500
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr93582-7.c 2020-11-26 22:23:45.756000000 -0500
@@ -0,0 +1,25 @@
+/* PR tree-optimization/93582 */
+/* { dg-do compile { target int32 } } */
+/* { dg-options "-O2 -fdump-tree-fre1" } */
+/* { dg-final { scan-tree-dump "return -413012;" "fre1" { target le } } } */
+/* { dg-final { scan-tree-dump "return -611112;" "fre1" { target be } } } */
+
+union U {
+ struct S { int a : 12, b : 5, c : 10, d : 5; } s;
+ struct T { int a : 7, b : 21, c : 4; } t;
+};
+struct A { char a[48]; union U u; };
+void bar (struct A *);
+
+int
+foo (void)
+{
+ struct A a;
+ bar (&a);
+ a.u.s.a = 1590;
+ a.u.s.b = -11;
+ a.u.s.c = -404;
+ a.u.s.d = 7;
+ return a.u.t.b;
+}
+
diff -urpN a/gcc/testsuite/gcc.dg/tree-ssa/pr93582-8.c b/gcc/testsuite/gcc.dg/tree-ssa/pr93582-8.c
--- a/gcc/testsuite/gcc.dg/tree-ssa/pr93582-8.c 1969-12-31 19:00:00.000000000 -0500
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr93582-8.c 2020-11-26 22:23:53.088000000 -0500
@@ -0,0 +1,15 @@
+/* PR tree-optimization/93582 */
+/* { dg-do compile { target int32 } } */
+/* { dg-options "-O2 -fdump-tree-fre1" } */
+/* { dg-final { scan-tree-dump "return 0;" "fre1" { target le } } } */
+/* { dg-final { scan-tree-dump "return -8531;" "fre1" { target be } } } */
+
+short
+foo (void)
+{
+ union U { char c[32]; short s[16]; int i[8]; } u;
+ __builtin_memset (u.c + 1, '\0', 5);
+ u.s[3] = 0xdead;
+ return u.i[1];
+}
+
diff -urpN a/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-82.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-82.c
--- a/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-82.c 1969-12-31 19:00:00.000000000 -0500
+++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-82.c 2020-11-26 22:06:08.036000000 -0500
@@ -0,0 +1,25 @@
+/* { dg-do run } */
+/* { dg-options "-O -fdump-tree-fre1-details" } */
+
+struct S { _Bool x; };
+
+void
+foo (struct S *s)
+{
+ __builtin_memset (s, 1, sizeof (struct S));
+ s->x = 1;
+}
+
+int
+main ()
+{
+ struct S s;
+ foo (&s);
+ char c;
+ __builtin_memcpy (&c, &s.x, 1);
+ if (c != 1)
+ __builtin_abort ();
+ return 0;
+}
+
+/* { dg-final { scan-tree-dump "Deleted redundant store" "fre1" } } */
diff -urpN a/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-83.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-83.c
--- a/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-83.c 1969-12-31 19:00:00.000000000 -0500
+++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-83.c 2020-11-26 22:06:08.036000000 -0500
@@ -0,0 +1,32 @@
+/* { dg-do compile } */
+/* { dg-options "-O -fdump-tree-fre1-details" } */
+
+struct X
+{
+ int a : 1;
+ int b : 1;
+} x;
+
+void foo (int v)
+{
+ x.a = 1;
+ x.b = v;
+ x.a = 1;
+ x.b = v;
+}
+
+struct Y
+{
+ _Bool a;
+ _Bool b;
+} y;
+
+void bar (int v)
+{
+ y.a = 1;
+ y.b = v;
+ y.a = 1;
+ y.b = v;
+}
+
+/* { dg-final { scan-tree-dump-times "Deleted redundant store" 4 "fre1" } } */
diff -urpN a/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-84.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-84.c
--- a/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-84.c 1969-12-31 19:00:00.000000000 -0500
+++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-84.c 2020-11-26 22:06:08.036000000 -0500
@@ -0,0 +1,19 @@
+/* { dg-do compile } */
+/* { dg-options "-O -fdump-tree-fre1" } */
+
+typedef int v4si __attribute__((vector_size(16)));
+
+void foo (v4si *dst, int x)
+{
+ v4si v[2];
+ v[0][0] = 1;
+ v[0][1] = x;
+ v[0][2] = 2;
+ v[0][3] = 3;
+ v[0][1] = 0;
+ *dst = v[0];
+}
+
+/* The shadowed non-constant assign to v[0][1] shouldn't prevent us from
+ value-numbering the load to a constant. */
+/* { dg-final { scan-tree-dump "\\*dst_\[0-9\]*\\\(D\\) = { 1, 0, 2, 3 };" "fre1" } } */
diff -urpN a/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-85.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-85.c
--- a/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-85.c 1969-12-31 19:00:00.000000000 -0500
+++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-85.c 2020-11-26 22:06:08.036000000 -0500
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-options "-O -fstrict-aliasing -fdump-tree-fre1-details" } */
+
+struct X { int i; int j; };
+
+struct X x, y;
+void foo ()
+{
+ x.i = 1;
+ y = x;
+ y.i = 1; // redundant
+}
+
+/* { dg-final { scan-tree-dump "Deleted redundant store y.i" "fre1" } } */
diff -urpN a/gcc/tree-ssa-alias.c b/gcc/tree-ssa-alias.c
--- a/gcc/tree-ssa-alias.c 2020-11-26 22:26:32.884000000 -0500
+++ b/gcc/tree-ssa-alias.c 2020-11-26 22:06:08.036000000 -0500
@@ -2628,7 +2628,8 @@ static bool
maybe_skip_until (gimple *phi, tree &target, basic_block target_bb,
ao_ref *ref, tree vuse, bool tbaa_p, unsigned int &limit,
bitmap *visited, bool abort_on_visited,
- void *(*translate)(ao_ref *, tree, void *, bool *),
+ void *(*translate)(ao_ref *, tree, void *, translate_flags *),
+ translate_flags disambiguate_only,
void *data)
{
basic_block bb = gimple_bb (phi);
@@ -2663,7 +2664,7 @@ maybe_skip_until (gimple *phi, tree &tar
return !abort_on_visited;
vuse = get_continuation_for_phi (def_stmt, ref, tbaa_p, limit,
visited, abort_on_visited,
- translate, data);
+ translate, data, disambiguate_only);
if (!vuse)
return false;
continue;
@@ -2678,9 +2679,9 @@ maybe_skip_until (gimple *phi, tree &tar
--limit;
if (stmt_may_clobber_ref_p_1 (def_stmt, ref, tbaa_p))
{
- bool disambiguate_only = true;
+ translate_flags tf = disambiguate_only;
if (translate
- && (*translate) (ref, vuse, data, &disambiguate_only) == NULL)
+ && (*translate) (ref, vuse, data, &tf) == NULL)
;
else
return false;
@@ -2711,8 +2712,10 @@ tree
get_continuation_for_phi (gimple *phi, ao_ref *ref, bool tbaa_p,
unsigned int &limit, bitmap *visited,
bool abort_on_visited,
- void *(*translate)(ao_ref *, tree, void *, bool *),
- void *data)
+ void *(*translate)(ao_ref *, tree, void *,
+ translate_flags *),
+ void *data,
+ translate_flags disambiguate_only)
{
unsigned nargs = gimple_phi_num_args (phi);
@@ -2754,13 +2757,15 @@ get_continuation_for_phi (gimple *phi, a
else if (! maybe_skip_until (phi, arg0, dom, ref, arg1, tbaa_p,
limit, visited,
abort_on_visited,
- /* Do not translate when walking over
+ translate,
+ /* Do not valueize when walking over
backedges. */
dominated_by_p
(CDI_DOMINATORS,
gimple_bb (SSA_NAME_DEF_STMT (arg1)),
phi_bb)
- ? NULL : translate, data))
+ ? TR_DISAMBIGUATE
+ : disambiguate_only, data))
return NULL_TREE;
}
@@ -2798,7 +2803,8 @@ get_continuation_for_phi (gimple *phi, a
void *
walk_non_aliased_vuses (ao_ref *ref, tree vuse, bool tbaa_p,
void *(*walker)(ao_ref *, tree, void *),
- void *(*translate)(ao_ref *, tree, void *, bool *),
+ void *(*translate)(ao_ref *, tree, void *,
+ translate_flags *),
tree (*valueize)(tree),
unsigned &limit, void *data)
{
@@ -2851,7 +2857,7 @@ walk_non_aliased_vuses (ao_ref *ref, tre
{
if (!translate)
break;
- bool disambiguate_only = false;
+ translate_flags disambiguate_only = TR_TRANSLATE;
res = (*translate) (ref, vuse, data, &disambiguate_only);
/* Failed lookup and translation. */
if (res == (void *)-1)
@@ -2863,7 +2869,7 @@ walk_non_aliased_vuses (ao_ref *ref, tre
else if (res != NULL)
break;
/* Translation succeeded, continue walking. */
- translated = translated || !disambiguate_only;
+ translated = translated || disambiguate_only == TR_TRANSLATE;
}
vuse = gimple_vuse (def_stmt);
}
diff -urpN a/gcc/tree-ssa-alias.h b/gcc/tree-ssa-alias.h
--- a/gcc/tree-ssa-alias.h 2020-11-26 22:26:32.868000000 -0500
+++ b/gcc/tree-ssa-alias.h 2020-11-26 22:06:08.040000000 -0500
@@ -131,13 +131,18 @@ extern bool call_may_clobber_ref_p (gcal
extern bool call_may_clobber_ref_p_1 (gcall *, ao_ref *);
extern bool stmt_kills_ref_p (gimple *, tree);
extern bool stmt_kills_ref_p (gimple *, ao_ref *);
+enum translate_flags
+ { TR_TRANSLATE, TR_VALUEIZE_AND_DISAMBIGUATE, TR_DISAMBIGUATE };
extern tree get_continuation_for_phi (gimple *, ao_ref *, bool,
unsigned int &, bitmap *, bool,
- void *(*)(ao_ref *, tree, void *, bool *),
- void *);
+ void *(*)(ao_ref *, tree, void *,
+ translate_flags *),
+ void *, translate_flags
+ = TR_VALUEIZE_AND_DISAMBIGUATE);
extern void *walk_non_aliased_vuses (ao_ref *, tree, bool,
void *(*)(ao_ref *, tree, void *),
- void *(*)(ao_ref *, tree, void *, bool *),
+ void *(*)(ao_ref *, tree, void *,
+ translate_flags *),
tree (*)(tree), unsigned &, void *);
extern int walk_aliased_vdefs (ao_ref *, tree,
bool (*)(ao_ref *, tree, void *),
diff -urpN a/gcc/tree-ssa-sccvn.c b/gcc/tree-ssa-sccvn.c
--- a/gcc/tree-ssa-sccvn.c 2020-11-26 22:26:32.836000000 -0500
+++ b/gcc/tree-ssa-sccvn.c 2020-11-27 03:17:41.080000000 -0500
@@ -1684,24 +1684,75 @@ struct pd_data
struct vn_walk_cb_data
{
- vn_walk_cb_data (vn_reference_t vr_, tree *last_vuse_ptr_,
- vn_lookup_kind vn_walk_kind_, bool tbaa_p_)
- : vr (vr_), last_vuse_ptr (last_vuse_ptr_), vn_walk_kind (vn_walk_kind_),
- tbaa_p (tbaa_p_), known_ranges (NULL)
- {}
+ vn_walk_cb_data (vn_reference_t vr_, tree orig_ref_, tree *last_vuse_ptr_,
+ vn_lookup_kind vn_walk_kind_, bool tbaa_p_, tree mask_)
+ : vr (vr_), last_vuse_ptr (last_vuse_ptr_), last_vuse (NULL_TREE),
+ mask (mask_), masked_result (NULL_TREE), vn_walk_kind (vn_walk_kind_),
+ tbaa_p (tbaa_p_), saved_operands (vNULL), first_set (-2),
+ known_ranges (NULL)
+ {
+ if (!last_vuse_ptr)
+ last_vuse_ptr = &last_vuse;
+ ao_ref_init (&orig_ref, orig_ref_);
+ if (mask)
+ {
+ wide_int w = wi::to_wide (mask);
+ unsigned int pos = 0, prec = w.get_precision ();
+ pd_data pd;
+ pd.rhs = build_constructor (NULL_TREE, NULL);
+ /* When bitwise and with a constant is done on a memory load,
+ we don't really need all the bits to be defined or defined
+ to constants, we don't really care what is in the position
+ corresponding to 0 bits in the mask.
+ So, push the ranges of those 0 bits in the mask as artificial
+ zero stores and let the partial def handling code do the
+ rest. */
+ while (pos < prec)
+ {
+ int tz = wi::ctz (w);
+ if (pos + tz > prec)
+ tz = prec - pos;
+ if (tz)
+ {
+ if (BYTES_BIG_ENDIAN)
+ pd.offset = prec - pos - tz;
+ else
+ pd.offset = pos;
+ pd.size = tz;
+ void *r = push_partial_def (pd, 0, prec);
+ gcc_assert (r == NULL_TREE);
+ }
+ pos += tz;
+ if (pos == prec)
+ break;
+ w = wi::lrshift (w, tz);
+ tz = wi::ctz (wi::bit_not (w));
+ if (pos + tz > prec)
+ tz = prec - pos;
+ pos += tz;
+ w = wi::lrshift (w, tz);
+ }
+ }
+ }
~vn_walk_cb_data ();
- void *push_partial_def (const pd_data& pd, tree, HOST_WIDE_INT);
+ void *finish (alias_set_type, tree);
+ void *push_partial_def (const pd_data& pd, alias_set_type, HOST_WIDE_INT);
vn_reference_t vr;
+ ao_ref orig_ref;
tree *last_vuse_ptr;
+ tree last_vuse;
+ tree mask;
+ tree masked_result;
vn_lookup_kind vn_walk_kind;
bool tbaa_p;
+ vec<vn_reference_op_s> saved_operands;
/* The VDEFs of partial defs we come along. */
auto_vec<pd_data, 2> partial_defs;
/* The first defs range to avoid splay tree setup in most cases. */
pd_range first_range;
- tree first_vuse;
+ alias_set_type first_set;
splay_tree known_ranges;
obstack ranges_obstack;
};
@@ -1713,6 +1764,23 @@ vn_walk_cb_data::~vn_walk_cb_data ()
splay_tree_delete (known_ranges);
obstack_free (&ranges_obstack, NULL);
}
+ saved_operands.release ();
+}
+
+void *
+vn_walk_cb_data::finish (alias_set_type set, tree val)
+{
+ if (first_set != -2)
+ set = first_set;
+ if (mask)
+ {
+ masked_result = val;
+ return (void *) -1;
+ }
+ vec<vn_reference_op_s> &operands
+ = saved_operands.exists () ? saved_operands : vr->operands;
+ return vn_reference_lookup_or_insert_for_pieces (last_vuse, set,
+ vr->type, operands, val);
}
/* pd_range splay-tree helpers. */
@@ -1742,168 +1810,306 @@ pd_tree_dealloc (void *, void *)
}
/* Push PD to the vector of partial definitions returning a
- value when we are ready to combine things with VUSE and MAXSIZEI,
+ value when we are ready to combine things with VUSE, SET and MAXSIZEI,
NULL when we want to continue looking for partial defs or -1
on failure. */
void *
-vn_walk_cb_data::push_partial_def (const pd_data &pd, tree vuse,
- HOST_WIDE_INT maxsizei)
+vn_walk_cb_data::push_partial_def (const pd_data &pd,
+ alias_set_type set, HOST_WIDE_INT maxsizei)
{
+ const HOST_WIDE_INT bufsize = 64;
+ /* We're using a fixed buffer for encoding so fail early if the object
+ we want to interpret is bigger. */
+ if (maxsizei > bufsize * BITS_PER_UNIT
+ || CHAR_BIT != 8
+ || BITS_PER_UNIT != 8
+ /* Not prepared to handle PDP endian. */
+ || BYTES_BIG_ENDIAN != WORDS_BIG_ENDIAN)
+ return (void *)-1;
+
+ bool pd_constant_p = (TREE_CODE (pd.rhs) == CONSTRUCTOR
+ || CONSTANT_CLASS_P (pd.rhs));
if (partial_defs.is_empty ())
{
+ if (!pd_constant_p)
+ return (void *)-1;
partial_defs.safe_push (pd);
first_range.offset = pd.offset;
first_range.size = pd.size;
- first_vuse = vuse;
+ first_set = set;
last_vuse_ptr = NULL;
+ /* Continue looking for partial defs. */
+ return NULL;
+ }
+
+ if (!known_ranges)
+ {
+ /* ??? Optimize the case where the 2nd partial def completes things. */
+ gcc_obstack_init (&ranges_obstack);
+ known_ranges = splay_tree_new_with_allocator (pd_range_compare, 0, 0,
+ pd_tree_alloc,
+ pd_tree_dealloc, this);
+ splay_tree_insert (known_ranges,
+ (splay_tree_key)&first_range.offset,
+ (splay_tree_value)&first_range);
+ }
+
+ pd_range newr = { pd.offset, pd.size };
+ splay_tree_node n;
+ pd_range *r;
+ /* Lookup the predecessor of offset + 1 and see if we need to merge. */
+ HOST_WIDE_INT loffset = newr.offset + 1;
+ if ((n = splay_tree_predecessor (known_ranges, (splay_tree_key)&loffset))
+ && ((r = (pd_range *)n->value), true)
+ && ranges_known_overlap_p (r->offset, r->size + 1,
+ newr.offset, newr.size))
+ {
+ /* Ignore partial defs already covered. */
+ if (known_subrange_p (newr.offset, newr.size, r->offset, r->size))
+ return NULL;
+ r->size = MAX (r->offset + r->size, newr.offset + newr.size) - r->offset;
}
else
{
- if (!known_ranges)
- {
- /* ??? Optimize the case where the second partial def
- completes things. */
- gcc_obstack_init (&ranges_obstack);
- known_ranges
- = splay_tree_new_with_allocator (pd_range_compare, 0, 0,
- pd_tree_alloc,
- pd_tree_dealloc, this);
- splay_tree_insert (known_ranges,
- (splay_tree_key)&first_range.offset,
- (splay_tree_value)&first_range);
- }
- if (known_ranges)
- {
- pd_range newr = { pd.offset, pd.size };
- splay_tree_node n;
- pd_range *r;
- /* Lookup the predecessor of offset + 1 and see if
- we need to merge with it. */
- HOST_WIDE_INT loffset = newr.offset + 1;
- if ((n = splay_tree_predecessor (known_ranges,
- (splay_tree_key)&loffset))
- && ((r = (pd_range *)n->value), true)
- && ranges_known_overlap_p (r->offset, r->size + 1,
- newr.offset, newr.size))
- {
- /* Ignore partial defs already covered. */
- if (known_subrange_p (newr.offset, newr.size,
- r->offset, r->size))
- return NULL;
- r->size = MAX (r->offset + r->size,
- newr.offset + newr.size) - r->offset;
- }
- else
- {
- /* newr.offset wasn't covered yet, insert the
- range. */
- r = XOBNEW (&ranges_obstack, pd_range);
- *r = newr;
- splay_tree_insert (known_ranges,
- (splay_tree_key)&r->offset,
- (splay_tree_value)r);
- }
- /* Merge r which now contains newr and is a member
- of the splay tree with adjacent overlapping ranges. */
- pd_range *rafter;
- while ((n = splay_tree_successor (known_ranges,
- (splay_tree_key)&r->offset))
- && ((rafter = (pd_range *)n->value), true)
- && ranges_known_overlap_p (r->offset, r->size + 1,
- rafter->offset, rafter->size))
- {
- r->size = MAX (r->offset + r->size,
- rafter->offset + rafter->size) - r->offset;
- splay_tree_remove (known_ranges,
- (splay_tree_key)&rafter->offset);
- }
- partial_defs.safe_push (pd);
-
- /* Now we have merged newr into the range tree.
- When we have covered [offseti, sizei] then the
- tree will contain exactly one node which has
- the desired properties and it will be 'r'. */
- if (known_subrange_p (0, maxsizei / BITS_PER_UNIT,
- r->offset, r->size))
- {
- /* Now simply native encode all partial defs
- in reverse order. */
- unsigned ndefs = partial_defs.length ();
- /* We support up to 512-bit values (for V8DFmode). */
- unsigned char buffer[64];
- int len;
+ /* newr.offset wasn't covered yet, insert the range. */
+ r = XOBNEW (&ranges_obstack, pd_range);
+ *r = newr;
+ splay_tree_insert (known_ranges, (splay_tree_key)&r->offset,
+ (splay_tree_value)r);
+ }
+ /* Merge r which now contains newr and is a member of the splay tree with
+ adjacent overlapping ranges. */
+ pd_range *rafter;
+ while ((n = splay_tree_successor (known_ranges, (splay_tree_key)&r->offset))
+ && ((rafter = (pd_range *)n->value), true)
+ && ranges_known_overlap_p (r->offset, r->size + 1,
+ rafter->offset, rafter->size))
+ {
+ r->size = MAX (r->offset + r->size,
+ rafter->offset + rafter->size) - r->offset;
+ splay_tree_remove (known_ranges, (splay_tree_key)&rafter->offset);
+ }
+ /* Non-constants are OK as long as they are shadowed by a constant. */
+ if (!pd_constant_p)
+ return (void *)-1;
+ partial_defs.safe_push (pd);
+
+ /* Now we have merged newr into the range tree. When we have covered
+ [offseti, sizei] then the tree will contain exactly one node which has
+ the desired properties and it will be 'r'. */
+ if (!known_subrange_p (0, maxsizei, r->offset, r->size))
+ /* Continue looking for partial defs. */
+ return NULL;
- while (!partial_defs.is_empty ())
+ /* Now simply native encode all partial defs in reverse order. */
+ unsigned ndefs = partial_defs.length ();
+ /* We support up to 512-bit values (for V8DFmode). */
+ unsigned char buffer[bufsize + 1];
+ unsigned char this_buffer[bufsize + 1];
+ int len;
+
+ memset (buffer, 0, bufsize + 1);
+ unsigned needed_len = ROUND_UP (maxsizei, BITS_PER_UNIT) / BITS_PER_UNIT;
+ while (!partial_defs.is_empty ())
+ {
+ pd_data pd = partial_defs.pop ();
+ unsigned int amnt;
+ if (TREE_CODE (pd.rhs) == CONSTRUCTOR)
+ {
+ /* Empty CONSTRUCTOR. */
+ if (pd.size >= needed_len * BITS_PER_UNIT)
+ len = needed_len;
+ else
+ len = ROUND_UP (pd.size, BITS_PER_UNIT) / BITS_PER_UNIT;
+ memset (this_buffer, 0, len);
+ }
+ else
+ {
+ len = native_encode_expr (pd.rhs, this_buffer, bufsize,
+ MAX (0, -pd.offset) / BITS_PER_UNIT);
+ if (len <= 0
+ || len < (ROUND_UP (pd.size, BITS_PER_UNIT) / BITS_PER_UNIT
+ - MAX (0, -pd.offset) / BITS_PER_UNIT))
+ {
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ fprintf (dump_file, "Failed to encode %u "
+ "partial definitions\n", ndefs);
+ return (void *)-1;
+ }
+ }
+
+ unsigned char *p = buffer;
+ HOST_WIDE_INT size = pd.size;
+ if (pd.offset < 0)
+ size -= ROUND_DOWN (-pd.offset, BITS_PER_UNIT);
+ this_buffer[len] = 0;
+ if (BYTES_BIG_ENDIAN)
+ {
+ /* LSB of this_buffer[len - 1] byte should be at
+ pd.offset + pd.size - 1 bits in buffer. */
+ amnt = ((unsigned HOST_WIDE_INT) pd.offset
+ + pd.size) % BITS_PER_UNIT;
+ if (amnt)
+ shift_bytes_in_array_right (this_buffer, len + 1, amnt);
+ unsigned char *q = this_buffer;
+ unsigned int off = 0;
+ if (pd.offset >= 0)
+ {
+ unsigned int msk;
+ off = pd.offset / BITS_PER_UNIT;
+ gcc_assert (off < needed_len);
+ p = buffer + off;
+ if (size <= amnt)
{
- pd_data pd = partial_defs.pop ();
- if (TREE_CODE (pd.rhs) == CONSTRUCTOR)
- /* Empty CONSTRUCTOR. */
- memset (buffer + MAX (0, pd.offset),
- 0, MIN ((HOST_WIDE_INT)sizeof (buffer)
- - MAX (0, pd.offset),
- pd.size + MIN (0, pd.offset)));
- else
+ msk = ((1 << size) - 1) << (BITS_PER_UNIT - amnt);
+ *p = (*p & ~msk) | (this_buffer[len] & msk);
+ size = 0;
+ }
+ else
+ {
+ if (TREE_CODE (pd.rhs) != CONSTRUCTOR)
+ q = (this_buffer + len
+ - (ROUND_UP (size - amnt, BITS_PER_UNIT)
+ / BITS_PER_UNIT));
+ if (pd.offset % BITS_PER_UNIT)
{
- len = native_encode_expr (pd.rhs,
- buffer + MAX (0, pd.offset),
- sizeof (buffer)
- - MAX (0, pd.offset),
- MAX (0, -pd.offset));
- if (len <= 0
- || len < (pd.size - MAX (0, -pd.offset)))
- {
- if (dump_file && (dump_flags & TDF_DETAILS))
- fprintf (dump_file, "Failed to encode %u "
- "partial definitions\n", ndefs);
- return (void *)-1;
- }
+ msk = -1U << (BITS_PER_UNIT
+ - (pd.offset % BITS_PER_UNIT));
+ *p = (*p & msk) | (*q & ~msk);
+ p++;
+ q++;
+ off++;
+ size -= BITS_PER_UNIT - (pd.offset % BITS_PER_UNIT);
+ gcc_assert (size >= 0);
}
}
-
- tree type = vr->type;
- /* Make sure to interpret in a type that has a range
- covering the whole access size. */
- if (INTEGRAL_TYPE_P (vr->type)
- && maxsizei != TYPE_PRECISION (vr->type))
- type = build_nonstandard_integer_type (maxsizei,
- TYPE_UNSIGNED (type));
- tree val = native_interpret_expr (type, buffer,
- maxsizei / BITS_PER_UNIT);
- /* If we chop off bits because the types precision doesn't
- match the memory access size this is ok when optimizing
- reads but not when called from the DSE code during
- elimination. */
- if (val
- && type != vr->type)
+ }
+ else if (TREE_CODE (pd.rhs) != CONSTRUCTOR)
+ {
+ q = (this_buffer + len
+ - (ROUND_UP (size - amnt, BITS_PER_UNIT)
+ / BITS_PER_UNIT));
+ if (pd.offset % BITS_PER_UNIT)
{
- if (! int_fits_type_p (val, vr->type))
- val = NULL_TREE;
- else
- val = fold_convert (vr->type, val);
+ q++;
+ size -= BITS_PER_UNIT - ((unsigned HOST_WIDE_INT) pd.offset
+ % BITS_PER_UNIT);
+ gcc_assert (size >= 0);
}
-
- if (val)
+ }
+ if ((unsigned HOST_WIDE_INT) size / BITS_PER_UNIT + off
+ > needed_len)
+ size = (needed_len - off) * BITS_PER_UNIT;
+ memcpy (p, q, size / BITS_PER_UNIT);
+ if (size % BITS_PER_UNIT)
+ {
+ unsigned int msk
+ = -1U << (BITS_PER_UNIT - (size % BITS_PER_UNIT));
+ p += size / BITS_PER_UNIT;
+ q += size / BITS_PER_UNIT;
+ *p = (*q & msk) | (*p & ~msk);
+ }
+ }
+ else
+ {
+ size = MIN (size, (HOST_WIDE_INT) needed_len * BITS_PER_UNIT);
+ if (pd.offset >= 0)
+ {
+ /* LSB of this_buffer[0] byte should be at pd.offset bits
+ in buffer. */
+ unsigned int msk;
+ amnt = pd.offset % BITS_PER_UNIT;
+ if (amnt)
+ shift_bytes_in_array_left (this_buffer, len + 1, amnt);
+ unsigned int off = pd.offset / BITS_PER_UNIT;
+ gcc_assert (off < needed_len);
+ p = buffer + off;
+ if (amnt + size < BITS_PER_UNIT)
{
- if (dump_file && (dump_flags & TDF_DETAILS))
- fprintf (dump_file, "Successfully combined %u "
- "partial definitions\n", ndefs);
- return vn_reference_lookup_or_insert_for_pieces
- (first_vuse,
- vr->set, vr->type, vr->operands, val);
+ /* Low amnt bits come from *p, then size bits
+ from this_buffer[0] and the remaining again from
+ *p. */
+ msk = ((1 << size) - 1) << amnt;
+ *p = (*p & ~msk) | (this_buffer[0] & msk);
+ size = 0;
}
- else
+ else if (amnt)
{
- if (dump_file && (dump_flags & TDF_DETAILS))
- fprintf (dump_file, "Failed to interpret %u "
- "encoded partial definitions\n", ndefs);
- return (void *)-1;
+ msk = -1U << amnt;
+ *p = (*p & ~msk) | (this_buffer[0] & msk);
+ p++;
+ size -= (BITS_PER_UNIT - amnt);
}
}
+ else
+ {
+ amnt = (unsigned HOST_WIDE_INT) pd.offset % BITS_PER_UNIT;
+ if (amnt)
+ shift_bytes_in_array_left (this_buffer, len + 1, amnt);
+ }
+ memcpy (p, this_buffer + (amnt != 0), size / BITS_PER_UNIT);
+ p += size / BITS_PER_UNIT;
+ if (size % BITS_PER_UNIT)
+ {
+ unsigned int msk = -1U << (size % BITS_PER_UNIT);
+ *p = (this_buffer[(amnt != 0) + size / BITS_PER_UNIT]
+ & ~msk) | (*p & msk);
+ }
}
}
- /* Continue looking for partial defs. */
- return NULL;
+
+ tree type = vr->type;
+ /* Make sure to interpret in a type that has a range covering the whole
+ access size. */
+ if (INTEGRAL_TYPE_P (vr->type) && maxsizei != TYPE_PRECISION (vr->type))
+ type = build_nonstandard_integer_type (maxsizei, TYPE_UNSIGNED (type));
+ tree val;
+ if (BYTES_BIG_ENDIAN)
+ {
+ unsigned sz = needed_len;
+ if (maxsizei % BITS_PER_UNIT)
+ shift_bytes_in_array_right (buffer, needed_len,
+ BITS_PER_UNIT
+ - (maxsizei % BITS_PER_UNIT));
+ if (INTEGRAL_TYPE_P (type))
+ sz = GET_MODE_SIZE (SCALAR_INT_TYPE_MODE (type));
+ if (sz > needed_len)
+ {
+ memcpy (this_buffer + (sz - needed_len), buffer, needed_len);
+ val = native_interpret_expr (type, this_buffer, sz);
+ }
+ else
+ val = native_interpret_expr (type, buffer, needed_len);
+ }
+ else
+ val = native_interpret_expr (type, buffer, bufsize);
+ /* If we chop off bits because the types precision doesn't match the memory
+ access size this is ok when optimizing reads but not when called from
+ the DSE code during elimination. */
+ if (val && type != vr->type)
+ {
+ if (! int_fits_type_p (val, vr->type))
+ val = NULL_TREE;
+ else
+ val = fold_convert (vr->type, val);
+ }
+ if (val)
+ {
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ fprintf (dump_file,
+ "Successfully combined %u partial definitions\n", ndefs);
+ /* We are using the alias-set of the first store we encounter which
+ should be appropriate here. */
+ return finish (first_set, val);
+ }
+ else
+ {
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ fprintf (dump_file,
+ "Failed to interpret %u encoded partial definitions\n", ndefs);
+ return (void *)-1;
+ }
}
/* Callback for walk_non_aliased_vuses. Adjusts the vn_reference_t VR_
@@ -1923,7 +2129,10 @@ vn_reference_lookup_2 (ao_ref *op ATTRIB
return NULL;
if (data->last_vuse_ptr)
- *data->last_vuse_ptr = vuse;
+ {
+ *data->last_vuse_ptr = vuse;
+ data->last_vuse = vuse;
+ }
/* Fixup vuse and hash. */
if (vr->vuse)
@@ -1935,7 +2144,11 @@ vn_reference_lookup_2 (ao_ref *op ATTRIB
hash = vr->hashcode;
slot = valid_info->references->find_slot_with_hash (vr, hash, NO_INSERT);
if (slot)
- return *slot;
+ {
+ if ((*slot)->result && data->saved_operands.exists ())
+ return data->finish (vr->set, (*slot)->result);
+ return *slot;
+ }
return NULL;
}
@@ -2221,13 +2434,13 @@ adjust_offsets_for_equal_base_address (t
static void *
vn_reference_lookup_3 (ao_ref *ref, tree vuse, void *data_,
- bool *disambiguate_only)
+ translate_flags *disambiguate_only)
{
vn_walk_cb_data *data = (vn_walk_cb_data *)data_;
vn_reference_t vr = data->vr;
gimple *def_stmt = SSA_NAME_DEF_STMT (vuse);
tree base = ao_ref_base (ref);
- HOST_WIDE_INT offseti, maxsizei;
+ HOST_WIDE_INT offseti = 0, maxsizei, sizei = 0;
static vec<vn_reference_op_s> lhs_ops;
ao_ref lhs_ref;
bool lhs_ref_ok = false;
@@ -2242,8 +2455,11 @@ vn_reference_lookup_3 (ao_ref *ref, tree
lhs_ops.truncate (0);
basic_block saved_rpo_bb = vn_context_bb;
vn_context_bb = gimple_bb (def_stmt);
- copy_reference_ops_from_ref (lhs, &lhs_ops);
- lhs_ops = valueize_refs_1 (lhs_ops, &valueized_anything, true);
+ if (*disambiguate_only <= TR_VALUEIZE_AND_DISAMBIGUATE)
+ {
+ copy_reference_ops_from_ref (lhs, &lhs_ops);
+ lhs_ops = valueize_refs_1 (lhs_ops, &valueized_anything, true);
+ }
vn_context_bb = saved_rpo_bb;
if (valueized_anything)
{
@@ -2253,7 +2469,7 @@ vn_reference_lookup_3 (ao_ref *ref, tree
if (lhs_ref_ok
&& !refs_may_alias_p_1 (ref, &lhs_ref, data->tbaa_p))
{
- *disambiguate_only = true;
+ *disambiguate_only = TR_VALUEIZE_AND_DISAMBIGUATE;
return NULL;
}
}
@@ -2263,6 +2479,30 @@ vn_reference_lookup_3 (ao_ref *ref, tree
lhs_ref_ok = true;
}
+ /* Besides valueizing the LHS we can also use access-path based
+ disambiguation on the original non-valueized ref. */
+ if (!ref->ref
+ && lhs_ref_ok
+ && data->orig_ref.ref)
+ {
+ /* We want to use the non-valueized LHS for this, but avoid redundant
+ work. */
+ ao_ref *lref = &lhs_ref;
+ ao_ref lref_alt;
+ if (valueized_anything)
+ {
+ ao_ref_init (&lref_alt, lhs);
+ lref = &lref_alt;
+ }
+ if (!refs_may_alias_p_1 (&data->orig_ref, lref, data->tbaa_p))
+ {
+ *disambiguate_only = (valueized_anything
+ ? TR_VALUEIZE_AND_DISAMBIGUATE
+ : TR_DISAMBIGUATE);
+ return NULL;
+ }
+ }
+
/* If we reach a clobbering statement try to skip it and see if
we find a VN result with exactly the same value as the
possible clobber. In this case we can ignore the clobber
@@ -2299,7 +2539,8 @@ vn_reference_lookup_3 (ao_ref *ref, tree
}
}
}
- else if (gimple_call_builtin_p (def_stmt, BUILT_IN_NORMAL)
+ else if (*disambiguate_only <= TR_VALUEIZE_AND_DISAMBIGUATE
+ && gimple_call_builtin_p (def_stmt, BUILT_IN_NORMAL)
&& gimple_call_num_args (def_stmt) <= 4)
{
/* For builtin calls valueize its arguments and call the
@@ -2328,15 +2569,13 @@ vn_reference_lookup_3 (ao_ref *ref, tree
gimple_call_set_arg (def_stmt, i, oldargs[i]);
if (!res)
{
- *disambiguate_only = true;
+ *disambiguate_only = TR_VALUEIZE_AND_DISAMBIGUATE;
return NULL;
}
}
}
- /* If we are looking for redundant stores do not create new hashtable
- entries from aliasing defs with made up alias-sets. */
- if (*disambiguate_only || !data->tbaa_p)
+ if (*disambiguate_only > TR_TRANSLATE)
return (void *)-1;
/* If we cannot constrain the size of the reference we cannot
@@ -2359,10 +2598,14 @@ vn_reference_lookup_3 (ao_ref *ref, tree
&& (integer_zerop (gimple_call_arg (def_stmt, 1))
|| ((TREE_CODE (gimple_call_arg (def_stmt, 1)) == INTEGER_CST
|| (INTEGRAL_TYPE_P (vr->type) && known_eq (ref->size, 8)))
- && CHAR_BIT == 8 && BITS_PER_UNIT == 8
+ && CHAR_BIT == 8
+ && BITS_PER_UNIT == 8
+ && BYTES_BIG_ENDIAN == WORDS_BIG_ENDIAN
&& offset.is_constant (&offseti)
- && offseti % BITS_PER_UNIT == 0
&& multiple_p (ref->size, BITS_PER_UNIT)))
+ && ref->size.is_constant (&sizei)
+ && (offseti % BITS_PER_UNIT == 0
+ || TREE_CODE (gimple_call_arg (def_stmt, 1)) == INTEGER_CST)
&& poly_int_tree_p (gimple_call_arg (def_stmt, 2))
&& (TREE_CODE (gimple_call_arg (def_stmt, 0)) == ADDR_EXPR
|| TREE_CODE (gimple_call_arg (def_stmt, 0)) == SSA_NAME))
@@ -2423,7 +2666,13 @@ vn_reference_lookup_3 (ao_ref *ref, tree
else
return (void *)-1;
tree len = gimple_call_arg (def_stmt, 2);
- HOST_WIDE_INT leni, offset2i, offseti;
+ HOST_WIDE_INT leni, offset2i;
+ /* Sometimes the above trickery is smarter than alias analysis. Take
+ advantage of that. */
+ if (!ranges_maybe_overlap_p (offset, maxsize, offset2,
+ (wi::to_poly_offset (len)
+ << LOG2_BITS_PER_UNIT)))
+ return NULL;
if (data->partial_defs.is_empty ()
&& known_subrange_p (offset, maxsize, offset2,
wi::to_poly_offset (len) << LOG2_BITS_PER_UNIT))
@@ -2432,7 +2681,8 @@ vn_reference_lookup_3 (ao_ref *ref, tree
if (integer_zerop (gimple_call_arg (def_stmt, 1)))
val = build_zero_cst (vr->type);
else if (INTEGRAL_TYPE_P (vr->type)
- && known_eq (ref->size, 8))
+ && known_eq (ref->size, 8)
+ && offseti % BITS_PER_UNIT == 0)
{
gimple_match_op res_op (gimple_match_cond::UNCOND, NOP_EXPR,
vr->type, gimple_call_arg (def_stmt, 1));
@@ -2444,30 +2694,57 @@ vn_reference_lookup_3 (ao_ref *ref, tree
}
else
{
- unsigned len = TREE_INT_CST_LOW (TYPE_SIZE_UNIT (vr->type));
- unsigned char *buf = XALLOCAVEC (unsigned char, len);
+ unsigned buflen = TREE_INT_CST_LOW (TYPE_SIZE_UNIT (vr->type))
+ + 1;
+ if (INTEGRAL_TYPE_P (vr->type))
+ buflen = GET_MODE_SIZE (SCALAR_INT_TYPE_MODE (vr->type)) + 1;
+ unsigned char *buf = XALLOCAVEC (unsigned char, buflen);
memset (buf, TREE_INT_CST_LOW (gimple_call_arg (def_stmt, 1)),
- len);
- val = native_interpret_expr (vr->type, buf, len);
+ buflen);
+ if (BYTES_BIG_ENDIAN)
+ {
+ unsigned int amnt
+ = (((unsigned HOST_WIDE_INT) offseti + sizei)
+ % BITS_PER_UNIT);
+ if (amnt)
+ {
+ shift_bytes_in_array_right (buf, buflen,
+ BITS_PER_UNIT - amnt);
+ buf++;
+ buflen--;
+ }
+ }
+ else if (offseti % BITS_PER_UNIT != 0)
+ {
+ unsigned int amnt
+ = BITS_PER_UNIT - ((unsigned HOST_WIDE_INT) offseti
+ % BITS_PER_UNIT);
+ shift_bytes_in_array_left (buf, buflen, amnt);
+ buf++;
+ buflen--;
+ }
+ val = native_interpret_expr (vr->type, buf, buflen);
if (!val)
return (void *)-1;
}
- return vn_reference_lookup_or_insert_for_pieces
- (vuse, vr->set, vr->type, vr->operands, val);
+ return data->finish (0, val);
}
/* For now handle clearing memory with partial defs. */
else if (known_eq (ref->size, maxsize)
&& integer_zerop (gimple_call_arg (def_stmt, 1))
&& tree_to_poly_int64 (len).is_constant (&leni)
+ && leni <= INTTYPE_MAXIMUM (HOST_WIDE_INT) / BITS_PER_UNIT
&& offset.is_constant (&offseti)
&& offset2.is_constant (&offset2i)
- && maxsize.is_constant (&maxsizei))
+ && maxsize.is_constant (&maxsizei)
+ && ranges_known_overlap_p (offseti, maxsizei, offset2i,
+ leni << LOG2_BITS_PER_UNIT))
{
pd_data pd;
pd.rhs = build_constructor (NULL_TREE, NULL);
- pd.offset = (offset2i - offseti) / BITS_PER_UNIT;
- pd.size = leni;
- return data->push_partial_def (pd, vuse, maxsizei);
+ pd.offset = offset2i - offseti;
+ pd.size = leni << LOG2_BITS_PER_UNIT;
+ return data->push_partial_def (pd, 0, maxsizei);
}
}
@@ -2477,12 +2754,22 @@ vn_reference_lookup_3 (ao_ref *ref, tree
&& gimple_assign_rhs_code (def_stmt) == CONSTRUCTOR
&& CONSTRUCTOR_NELTS (gimple_assign_rhs1 (def_stmt)) == 0)
{
+ tree lhs = gimple_assign_lhs (def_stmt);
tree base2;
poly_int64 offset2, size2, maxsize2;
HOST_WIDE_INT offset2i, size2i;
bool reverse;
- base2 = get_ref_base_and_extent (gimple_assign_lhs (def_stmt),
- &offset2, &size2, &maxsize2, &reverse);
+ if (lhs_ref_ok)
+ {
+ base2 = ao_ref_base (&lhs_ref);
+ offset2 = lhs_ref.offset;
+ size2 = lhs_ref.size;
+ maxsize2 = lhs_ref.max_size;
+ reverse = reverse_storage_order_for_component_p (lhs);
+ }
+ else
+ base2 = get_ref_base_and_extent (lhs,
+ &offset2, &size2, &maxsize2, &reverse);
if (known_size_p (maxsize2)
&& known_eq (maxsize2, size2)
&& adjust_offsets_for_equal_base_address (base, &offset,
@@ -2492,24 +2779,21 @@ vn_reference_lookup_3 (ao_ref *ref, tree
&& known_subrange_p (offset, maxsize, offset2, size2))
{
tree val = build_zero_cst (vr->type);
- return vn_reference_lookup_or_insert_for_pieces
- (vuse, vr->set, vr->type, vr->operands, val);
+ return data->finish (get_alias_set (lhs), val);
}
else if (known_eq (ref->size, maxsize)
&& maxsize.is_constant (&maxsizei)
- && maxsizei % BITS_PER_UNIT == 0
&& offset.is_constant (&offseti)
- && offseti % BITS_PER_UNIT == 0
&& offset2.is_constant (&offset2i)
- && offset2i % BITS_PER_UNIT == 0
&& size2.is_constant (&size2i)
- && size2i % BITS_PER_UNIT == 0)
+ && ranges_known_overlap_p (offseti, maxsizei,
+ offset2i, size2i))
{
pd_data pd;
pd.rhs = gimple_assign_rhs1 (def_stmt);
- pd.offset = (offset2i - offseti) / BITS_PER_UNIT;
- pd.size = size2i / BITS_PER_UNIT;
- return data->push_partial_def (pd, vuse, maxsizei);
+ pd.offset = offset2i - offseti;
+ pd.size = size2i;
+ return data->push_partial_def (pd, get_alias_set (lhs), maxsizei);
}
}
}
@@ -2520,28 +2804,36 @@ vn_reference_lookup_3 (ao_ref *ref, tree
&& is_gimple_reg_type (vr->type)
&& !contains_storage_order_barrier_p (vr->operands)
&& gimple_assign_single_p (def_stmt)
- && CHAR_BIT == 8 && BITS_PER_UNIT == 8
+ && CHAR_BIT == 8
+ && BITS_PER_UNIT == 8
+ && BYTES_BIG_ENDIAN == WORDS_BIG_ENDIAN
/* native_encode and native_decode operate on arrays of bytes
and so fundamentally need a compile-time size and offset. */
&& maxsize.is_constant (&maxsizei)
- && maxsizei % BITS_PER_UNIT == 0
&& offset.is_constant (&offseti)
- && offseti % BITS_PER_UNIT == 0
&& (is_gimple_min_invariant (gimple_assign_rhs1 (def_stmt))
|| (TREE_CODE (gimple_assign_rhs1 (def_stmt)) == SSA_NAME
&& is_gimple_min_invariant (SSA_VAL (gimple_assign_rhs1 (def_stmt))))))
{
+ tree lhs = gimple_assign_lhs (def_stmt);
tree base2;
poly_int64 offset2, size2, maxsize2;
HOST_WIDE_INT offset2i, size2i;
bool reverse;
- base2 = get_ref_base_and_extent (gimple_assign_lhs (def_stmt),
- &offset2, &size2, &maxsize2, &reverse);
+ if (lhs_ref_ok)
+ {
+ base2 = ao_ref_base (&lhs_ref);
+ offset2 = lhs_ref.offset;
+ size2 = lhs_ref.size;
+ maxsize2 = lhs_ref.max_size;
+ reverse = reverse_storage_order_for_component_p (lhs);
+ }
+ else
+ base2 = get_ref_base_and_extent (lhs,
+ &offset2, &size2, &maxsize2, &reverse);
if (base2
&& !reverse
&& known_eq (maxsize2, size2)
- && multiple_p (size2, BITS_PER_UNIT)
- && multiple_p (offset2, BITS_PER_UNIT)
&& adjust_offsets_for_equal_base_address (base, &offset,
base2, &offset2)
&& offset.is_constant (&offseti)
@@ -2552,37 +2844,80 @@ vn_reference_lookup_3 (ao_ref *ref, tree
&& known_subrange_p (offseti, maxsizei, offset2, size2))
{
/* We support up to 512-bit values (for V8DFmode). */
- unsigned char buffer[64];
+ unsigned char buffer[65];
int len;
tree rhs = gimple_assign_rhs1 (def_stmt);
if (TREE_CODE (rhs) == SSA_NAME)
rhs = SSA_VAL (rhs);
- unsigned pad = 0;
- if (BYTES_BIG_ENDIAN
- && is_a <scalar_mode> (TYPE_MODE (TREE_TYPE (rhs))))
- {
- /* On big-endian the padding is at the 'front' so
- just skip the initial bytes. */
- fixed_size_mode mode
- = as_a <fixed_size_mode> (TYPE_MODE (TREE_TYPE (rhs)));
- pad = GET_MODE_SIZE (mode) - size2i / BITS_PER_UNIT;
- }
len = native_encode_expr (rhs,
- buffer, sizeof (buffer),
- ((offseti - offset2i) / BITS_PER_UNIT
- + pad));
+ buffer, sizeof (buffer) - 1,
+ (offseti - offset2i) / BITS_PER_UNIT);
if (len > 0 && len * BITS_PER_UNIT >= maxsizei)
{
tree type = vr->type;
+ unsigned char *buf = buffer;
+ unsigned int amnt = 0;
/* Make sure to interpret in a type that has a range
covering the whole access size. */
if (INTEGRAL_TYPE_P (vr->type)
&& maxsizei != TYPE_PRECISION (vr->type))
type = build_nonstandard_integer_type (maxsizei,
TYPE_UNSIGNED (type));
- tree val = native_interpret_expr (type, buffer,
- maxsizei / BITS_PER_UNIT);
+ if (BYTES_BIG_ENDIAN)
+ {
+ /* For big-endian native_encode_expr stored the rhs
+ such that the LSB of it is the LSB of buffer[len - 1].
+ That bit is stored into memory at position
+ offset2 + size2 - 1, i.e. in byte
+ base + (offset2 + size2 - 1) / BITS_PER_UNIT.
+ E.g. for offset2 1 and size2 14, rhs -1 and memory
+ previously cleared that is:
+ 0 1
+ 01111111|11111110
+ Now, if we want to extract offset 2 and size 12 from
+ it using native_interpret_expr (which actually works
+ for integral bitfield types in terms of byte size of
+ the mode), the native_encode_expr stored the value
+ into buffer as
+ XX111111|11111111
+ and returned len 2 (the X bits are outside of
+ precision).
+ Let sz be maxsize / BITS_PER_UNIT if not extracting
+ a bitfield, and GET_MODE_SIZE otherwise.
+ We need to align the LSB of the value we want to
+ extract as the LSB of buf[sz - 1].
+ The LSB from memory we need to read is at position
+ offset + maxsize - 1. */
+ HOST_WIDE_INT sz = maxsizei / BITS_PER_UNIT;
+ if (INTEGRAL_TYPE_P (type))
+ sz = GET_MODE_SIZE (SCALAR_INT_TYPE_MODE (type));
+ amnt = ((unsigned HOST_WIDE_INT) offset2i + size2i
+ - offseti - maxsizei) % BITS_PER_UNIT;
+ if (amnt)
+ shift_bytes_in_array_right (buffer, len, amnt);
+ amnt = ((unsigned HOST_WIDE_INT) offset2i + size2i
+ - offseti - maxsizei - amnt) / BITS_PER_UNIT;
+ if ((unsigned HOST_WIDE_INT) sz + amnt > (unsigned) len)
+ len = 0;
+ else
+ {
+ buf = buffer + len - sz - amnt;
+ len -= (buf - buffer);
+ }
+ }
+ else
+ {
+ amnt = ((unsigned HOST_WIDE_INT) offset2i
+ - offseti) % BITS_PER_UNIT;
+ if (amnt)
+ {
+ buffer[len] = 0;
+ shift_bytes_in_array_left (buffer, len + 1, amnt);
+ buf = buffer + 1;
+ }
+ }
+ tree val = native_interpret_expr (type, buf, len);
/* If we chop off bits because the types precision doesn't
match the memory access size this is ok when optimizing
reads but not when called from the DSE code during
@@ -2597,73 +2932,95 @@ vn_reference_lookup_3 (ao_ref *ref, tree
}
if (val)
- return vn_reference_lookup_or_insert_for_pieces
- (vuse, vr->set, vr->type, vr->operands, val);
+ return data->finish (get_alias_set (lhs), val);
}
}
- else if (ranges_known_overlap_p (offseti, maxsizei, offset2i, size2i))
+ else if (ranges_known_overlap_p (offseti, maxsizei, offset2i,
+ size2i))
{
pd_data pd;
tree rhs = gimple_assign_rhs1 (def_stmt);
if (TREE_CODE (rhs) == SSA_NAME)
rhs = SSA_VAL (rhs);
pd.rhs = rhs;
- pd.offset = (offset2i - offseti) / BITS_PER_UNIT;
- pd.size = size2i / BITS_PER_UNIT;
- return data->push_partial_def (pd, vuse, maxsizei);
+ pd.offset = offset2i - offseti;
+ pd.size = size2i;
+ return data->push_partial_def (pd, get_alias_set (lhs), maxsizei);
}
}
}
/* 4) Assignment from an SSA name which definition we may be able
- to access pieces from. */
+ to access pieces from or we can combine to a larger entity. */
else if (known_eq (ref->size, maxsize)
&& is_gimple_reg_type (vr->type)
&& !contains_storage_order_barrier_p (vr->operands)
&& gimple_assign_single_p (def_stmt)
- && TREE_CODE (gimple_assign_rhs1 (def_stmt)) == SSA_NAME
- /* A subset of partial defs from non-constants can be handled
- by for example inserting a CONSTRUCTOR, a COMPLEX_EXPR or
- even a (series of) BIT_INSERT_EXPR hoping for simplifications
- downstream, not so much for actually doing the insertion. */
- && data->partial_defs.is_empty ())
+ && TREE_CODE (gimple_assign_rhs1 (def_stmt)) == SSA_NAME)
{
+ tree lhs = gimple_assign_lhs (def_stmt);
tree base2;
poly_int64 offset2, size2, maxsize2;
+ HOST_WIDE_INT offset2i, size2i, offseti;
bool reverse;
- base2 = get_ref_base_and_extent (gimple_assign_lhs (def_stmt),
- &offset2, &size2, &maxsize2,
- &reverse);
+ if (lhs_ref_ok)
+ {
+ base2 = ao_ref_base (&lhs_ref);
+ offset2 = lhs_ref.offset;
+ size2 = lhs_ref.size;
+ maxsize2 = lhs_ref.max_size;
+ reverse = reverse_storage_order_for_component_p (lhs);
+ }
+ else
+ base2 = get_ref_base_and_extent (lhs,
+ &offset2, &size2, &maxsize2, &reverse);
tree def_rhs = gimple_assign_rhs1 (def_stmt);
if (!reverse
&& known_size_p (maxsize2)
&& known_eq (maxsize2, size2)
&& adjust_offsets_for_equal_base_address (base, &offset,
- base2, &offset2)
- && known_subrange_p (offset, maxsize, offset2, size2)
- /* ??? We can't handle bitfield precision extracts without
- either using an alternate type for the BIT_FIELD_REF and
- then doing a conversion or possibly adjusting the offset
- according to endianness. */
- && (! INTEGRAL_TYPE_P (vr->type)
- || known_eq (ref->size, TYPE_PRECISION (vr->type)))
- && multiple_p (ref->size, BITS_PER_UNIT)
- && (! INTEGRAL_TYPE_P (TREE_TYPE (def_rhs))
- || type_has_mode_precision_p (TREE_TYPE (def_rhs))))
- {
- gimple_match_op op (gimple_match_cond::UNCOND,
- BIT_FIELD_REF, vr->type,
- vn_valueize (def_rhs),
- bitsize_int (ref->size),
- bitsize_int (offset - offset2));
- tree val = vn_nary_build_or_lookup (&op);
- if (val
- && (TREE_CODE (val) != SSA_NAME
- || ! SSA_NAME_OCCURS_IN_ABNORMAL_PHI (val)))
- {
- vn_reference_t res = vn_reference_lookup_or_insert_for_pieces
- (vuse, vr->set, vr->type, vr->operands, val);
- return res;
+ base2, &offset2))
+ {
+ if (data->partial_defs.is_empty ()
+ && known_subrange_p (offset, maxsize, offset2, size2)
+ /* ??? We can't handle bitfield precision extracts without
+ either using an alternate type for the BIT_FIELD_REF and
+ then doing a conversion or possibly adjusting the offset
+ according to endianness. */
+ && (! INTEGRAL_TYPE_P (vr->type)
+ || known_eq (ref->size, TYPE_PRECISION (vr->type)))
+ && multiple_p (ref->size, BITS_PER_UNIT))
+ {
+ if (known_eq (ref->size, size2))
+ return vn_reference_lookup_or_insert_for_pieces
+ (vuse, get_alias_set (lhs), vr->type, vr->operands,
+ SSA_VAL (def_rhs));
+ else if (! INTEGRAL_TYPE_P (TREE_TYPE (def_rhs))
+ || type_has_mode_precision_p (TREE_TYPE (def_rhs)))
+ {
+ gimple_match_op op (gimple_match_cond::UNCOND,
+ BIT_FIELD_REF, vr->type,
+ SSA_VAL (def_rhs),
+ bitsize_int (ref->size),
+ bitsize_int (offset - offset2));
+ tree val = vn_nary_build_or_lookup (&op);
+ if (val
+ && (TREE_CODE (val) != SSA_NAME
+ || ! SSA_NAME_OCCURS_IN_ABNORMAL_PHI (val)))
+ return data->finish (get_alias_set (lhs), val);
+ }
+ }
+ else if (maxsize.is_constant (&maxsizei)
+ && offset.is_constant (&offseti)
+ && offset2.is_constant (&offset2i)
+ && size2.is_constant (&size2i)
+ && ranges_known_overlap_p (offset, maxsize, offset2, size2))
+ {
+ pd_data pd;
+ pd.rhs = SSA_VAL (def_rhs);
+ pd.offset = offset2i - offseti;
+ pd.size = size2i;
+ return data->push_partial_def (pd, get_alias_set (lhs), maxsizei);
}
}
}
@@ -2678,6 +3035,7 @@ vn_reference_lookup_3 (ao_ref *ref, tree
/* Handling this is more complicated, give up for now. */
&& data->partial_defs.is_empty ())
{
+ tree lhs = gimple_assign_lhs (def_stmt);
tree base2;
int i, j, k;
auto_vec<vn_reference_op_s> rhs;
@@ -2747,7 +3105,8 @@ vn_reference_lookup_3 (ao_ref *ref, tree
}
/* Now re-write REF to be based on the rhs of the assignment. */
- copy_reference_ops_from_ref (gimple_assign_rhs1 (def_stmt), &rhs);
+ tree rhs1 = gimple_assign_rhs1 (def_stmt);
+ copy_reference_ops_from_ref (rhs1, &rhs);
/* Apply an extra offset to the inner MEM_REF of the RHS. */
if (maybe_ne (extra_off, 0))
@@ -2764,6 +3123,11 @@ vn_reference_lookup_3 (ao_ref *ref, tree
extra_off));
}
+ /* Save the operands since we need to use the original ones for
+ the hash entry we use. */
+ if (!data->saved_operands.exists ())
+ data->saved_operands = vr->operands.copy ();
+
/* We need to pre-pend vr->operands[0..i] to rhs. */
vec<vn_reference_op_s> old = vr->operands;
if (i + 1 + rhs.length () > vr->operands.length ())
@@ -2780,11 +3144,11 @@ vn_reference_lookup_3 (ao_ref *ref, tree
/* Try folding the new reference to a constant. */
tree val = fully_constant_vn_reference_p (vr);
if (val)
- return vn_reference_lookup_or_insert_for_pieces
- (vuse, vr->set, vr->type, vr->operands, val);
+ return data->finish (get_alias_set (lhs), val);
/* Adjust *ref from the new operands. */
- if (!ao_ref_init_from_vn_reference (&r, vr->set, vr->type, vr->operands))
+ if (!ao_ref_init_from_vn_reference (&r, get_alias_set (rhs1),
+ vr->type, vr->operands))
return (void *)-1;
/* This can happen with bitfields. */
if (maybe_ne (ref->size, r.size))
@@ -2793,6 +3157,12 @@ vn_reference_lookup_3 (ao_ref *ref, tree
/* Do not update last seen VUSE after translating. */
data->last_vuse_ptr = NULL;
+ /* Invalidate the original access path since it now contains
+ the wrong base. */
+ data->orig_ref.ref = NULL_TREE;
+ /* Use the alias-set of this LHS for recording an eventual result. */
+ if (data->first_set == -2)
+ data->first_set = get_alias_set (lhs);
/* Keep looking for the adjusted *REF / VR pair. */
return NULL;
@@ -2912,6 +3282,11 @@ vn_reference_lookup_3 (ao_ref *ref, tree
if (!known_subrange_p (at, byte_maxsize, lhs_offset, copy_size))
return (void *)-1;
+ /* Save the operands since we need to use the original ones for
+ the hash entry we use. */
+ if (!data->saved_operands.exists ())
+ data->saved_operands = vr->operands.copy ();
+
/* Make room for 2 operands in the new reference. */
if (vr->operands.length () < 2)
{
@@ -2940,11 +3315,10 @@ vn_reference_lookup_3 (ao_ref *ref, tree
/* Try folding the new reference to a constant. */
tree val = fully_constant_vn_reference_p (vr);
if (val)
- return vn_reference_lookup_or_insert_for_pieces
- (vuse, vr->set, vr->type, vr->operands, val);
+ return data->finish (0, val);
/* Adjust *ref from the new operands. */
- if (!ao_ref_init_from_vn_reference (&r, vr->set, vr->type, vr->operands))
+ if (!ao_ref_init_from_vn_reference (&r, 0, vr->type, vr->operands))
return (void *)-1;
/* This can happen with bitfields. */
if (maybe_ne (ref->size, r.size))
@@ -2953,6 +3327,12 @@ vn_reference_lookup_3 (ao_ref *ref, tree
/* Do not update last seen VUSE after translating. */
data->last_vuse_ptr = NULL;
+ /* Invalidate the original access path since it now contains
+ the wrong base. */
+ data->orig_ref.ref = NULL_TREE;
+ /* Use the alias-set of this stmt for recording an eventual result. */
+ if (data->first_set == -2)
+ data->first_set = 0;
/* Keep looking for the adjusted *REF / VR pair. */
return NULL;
@@ -3013,13 +3393,13 @@ vn_reference_lookup_pieces (tree vuse, a
{
ao_ref r;
unsigned limit = PARAM_VALUE (PARAM_SCCVN_MAX_ALIAS_QUERIES_PER_ACCESS);
- vn_walk_cb_data data (&vr1, NULL, kind, true);
+ vn_walk_cb_data data (&vr1, NULL_TREE, NULL, kind, true, NULL_TREE);
if (ao_ref_init_from_vn_reference (&r, set, type, vr1.operands))
- *vnresult =
- (vn_reference_t)walk_non_aliased_vuses (&r, vr1.vuse, true,
- vn_reference_lookup_2,
- vn_reference_lookup_3,
- vuse_valueize, limit, &data);
+ *vnresult
+ = ((vn_reference_t)
+ walk_non_aliased_vuses (&r, vr1.vuse, true, vn_reference_lookup_2,
+ vn_reference_lookup_3, vuse_valueize,
+ limit, &data));
gcc_checking_assert (vr1.operands == shared_lookup_references);
}
@@ -3035,15 +3415,19 @@ vn_reference_lookup_pieces (tree vuse, a
was NULL.. VNRESULT will be filled in with the vn_reference_t
stored in the hashtable if one exists. When TBAA_P is false assume
we are looking up a store and treat it as having alias-set zero.
- *LAST_VUSE_PTR will be updated with the VUSE the value lookup succeeded. */
+ *LAST_VUSE_PTR will be updated with the VUSE the value lookup succeeded.
+ MASK is either NULL_TREE, or can be an INTEGER_CST if the result of the
+ load is bitwise anded with MASK and so we are only interested in a subset
+ of the bits and can ignore if the other bits are uninitialized or
+ not initialized with constants. */
tree
vn_reference_lookup (tree op, tree vuse, vn_lookup_kind kind,
- vn_reference_t *vnresult, bool tbaa_p, tree *last_vuse_ptr)
+ vn_reference_t *vnresult, bool tbaa_p,
+ tree *last_vuse_ptr, tree mask)
{
vec<vn_reference_op_s> operands;
struct vn_reference_s vr1;
- tree cst;
bool valuezied_anything;
if (vnresult)
@@ -3055,11 +3439,11 @@ vn_reference_lookup (tree op, tree vuse,
vr1.type = TREE_TYPE (op);
vr1.set = get_alias_set (op);
vr1.hashcode = vn_reference_compute_hash (&vr1);
- if ((cst = fully_constant_vn_reference_p (&vr1)))
- return cst;
+ if (mask == NULL_TREE)
+ if (tree cst = fully_constant_vn_reference_p (&vr1))
+ return cst;
- if (kind != VN_NOWALK
- && vr1.vuse)
+ if (kind != VN_NOWALK && vr1.vuse)
{
vn_reference_t wvnresult;
ao_ref r;
@@ -3070,23 +3454,32 @@ vn_reference_lookup (tree op, tree vuse,
|| !ao_ref_init_from_vn_reference (&r, vr1.set, vr1.type,
vr1.operands))
ao_ref_init (&r, op);
- vn_walk_cb_data data (&vr1, last_vuse_ptr, kind, tbaa_p);
- wvnresult =
- (vn_reference_t)walk_non_aliased_vuses (&r, vr1.vuse, tbaa_p,
- vn_reference_lookup_2,
- vn_reference_lookup_3,
- vuse_valueize, limit, &data);
+ vn_walk_cb_data data (&vr1, r.ref ? NULL_TREE : op,
+ last_vuse_ptr, kind, tbaa_p, mask);
+
+ wvnresult
+ = ((vn_reference_t)
+ walk_non_aliased_vuses (&r, vr1.vuse, tbaa_p, vn_reference_lookup_2,
+ vn_reference_lookup_3, vuse_valueize, limit,
+ &data));
gcc_checking_assert (vr1.operands == shared_lookup_references);
if (wvnresult)
{
+ gcc_assert (mask == NULL_TREE);
if (vnresult)
*vnresult = wvnresult;
return wvnresult->result;
}
+ else if (mask)
+ return data.masked_result;
return NULL_TREE;
}
+ if (last_vuse_ptr)
+ *last_vuse_ptr = vr1.vuse;
+ if (mask)
+ return NULL_TREE;
return vn_reference_lookup_1 (&vr1, vnresult);
}
@@ -4333,7 +4726,39 @@ visit_nary_op (tree lhs, gassign *stmt)
}
}
}
- default:;
+ break;
+ case BIT_AND_EXPR:
+ if (INTEGRAL_TYPE_P (type)
+ && TREE_CODE (rhs1) == SSA_NAME
+ && TREE_CODE (gimple_assign_rhs2 (stmt)) == INTEGER_CST
+ && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (rhs1)
+ && default_vn_walk_kind != VN_NOWALK
+ && CHAR_BIT == 8
+ && BITS_PER_UNIT == 8
+ && BYTES_BIG_ENDIAN == WORDS_BIG_ENDIAN
+ && !integer_all_onesp (gimple_assign_rhs2 (stmt))
+ && !integer_zerop (gimple_assign_rhs2 (stmt)))
+ {
+ gassign *ass = dyn_cast <gassign *> (SSA_NAME_DEF_STMT (rhs1));
+ if (ass
+ && !gimple_has_volatile_ops (ass)
+ && vn_get_stmt_kind (ass) == VN_REFERENCE)
+ {
+ tree last_vuse = gimple_vuse (ass);
+ tree op = gimple_assign_rhs1 (ass);
+ tree result = vn_reference_lookup (op, gimple_vuse (ass),
+ default_vn_walk_kind,
+ NULL, true, &last_vuse,
+ gimple_assign_rhs2 (stmt));
+ if (result
+ && useless_type_conversion_p (TREE_TYPE (result),
+ TREE_TYPE (op)))
+ return set_ssa_val_to (lhs, result);
+ }
+ }
+ break;
+ default:
+ break;
}
bool changed = set_ssa_val_to (lhs, lhs);
@@ -4844,14 +5269,14 @@ visit_stmt (gimple *stmt, bool backedges
switch (vn_get_stmt_kind (ass))
{
case VN_NARY:
- changed = visit_nary_op (lhs, ass);
- break;
+ changed = visit_nary_op (lhs, ass);
+ break;
case VN_REFERENCE:
- changed = visit_reference_op_load (lhs, rhs1, ass);
- break;
+ changed = visit_reference_op_load (lhs, rhs1, ass);
+ break;
default:
- changed = defs_to_varying (ass);
- break;
+ changed = defs_to_varying (ass);
+ break;
}
}
}
@@ -5525,8 +5950,48 @@ eliminate_dom_walker::eliminate_stmt (ba
tree val;
tree rhs = gimple_assign_rhs1 (stmt);
vn_reference_t vnresult;
- val = vn_reference_lookup (lhs, gimple_vuse (stmt), VN_WALKREWRITE,
- &vnresult, false);
+ /* ??? gcc.dg/torture/pr91445.c shows that we lookup a boolean
+ typed load of a byte known to be 0x11 as 1 so a store of
+ a boolean 1 is detected as redundant. Because of this we
+ have to make sure to lookup with a ref where its size
+ matches the precision. */
+ tree lookup_lhs = lhs;
+ if (INTEGRAL_TYPE_P (TREE_TYPE (lhs))
+ && (TREE_CODE (lhs) != COMPONENT_REF
+ || !DECL_BIT_FIELD_TYPE (TREE_OPERAND (lhs, 1)))
+ && !type_has_mode_precision_p (TREE_TYPE (lhs)))
+ {
+ if (TREE_CODE (lhs) == COMPONENT_REF
+ || TREE_CODE (lhs) == MEM_REF)
+ {
+ tree ltype = build_nonstandard_integer_type
+ (TREE_INT_CST_LOW (TYPE_SIZE (TREE_TYPE (lhs))),
+ TYPE_UNSIGNED (TREE_TYPE (lhs)));
+ if (TREE_CODE (lhs) == COMPONENT_REF)
+ {
+ tree foff = component_ref_field_offset (lhs);
+ tree f = TREE_OPERAND (lhs, 1);
+ if (!poly_int_tree_p (foff))
+ lookup_lhs = NULL_TREE;
+ else
+ lookup_lhs = build3 (BIT_FIELD_REF, ltype,
+ TREE_OPERAND (lhs, 0),
+ TYPE_SIZE (TREE_TYPE (lhs)),
+ bit_from_pos
+ (foff, DECL_FIELD_BIT_OFFSET (f)));
+ }
+ else
+ lookup_lhs = build2 (MEM_REF, ltype,
+ TREE_OPERAND (lhs, 0),
+ TREE_OPERAND (lhs, 1));
+ }
+ else
+ lookup_lhs = NULL_TREE;
+ }
+ val = NULL_TREE;
+ if (lookup_lhs)
+ val = vn_reference_lookup (lookup_lhs, gimple_vuse (stmt),
+ VN_WALKREWRITE, &vnresult, false);
if (TREE_CODE (rhs) == SSA_NAME)
rhs = VN_INFO (rhs)->valnum;
if (val
diff -urpN a/gcc/tree-ssa-sccvn.h b/gcc/tree-ssa-sccvn.h
--- a/gcc/tree-ssa-sccvn.h 2020-11-26 22:26:32.856000000 -0500
+++ b/gcc/tree-ssa-sccvn.h 2020-11-26 22:06:08.040000000 -0500
@@ -235,7 +235,7 @@ tree vn_reference_lookup_pieces (tree, a
vec<vn_reference_op_s> ,
vn_reference_t *, vn_lookup_kind);
tree vn_reference_lookup (tree, tree, vn_lookup_kind, vn_reference_t *, bool,
- tree * = NULL);
+ tree * = NULL, tree = NULL_TREE);
void vn_reference_lookup_call (gcall *, vn_reference_t *, vn_reference_t);
vn_reference_t vn_reference_insert_pieces (tree, alias_set_type, tree,
vec<vn_reference_op_s> ,