summaryrefslogtreecommitdiff
blob: 4997b9ba52ab259529657771794291b249e492b1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
Fixes openssl miscompilation at least on ia64.
https://gcc.gnu.org/PR83565

From 86ae8eb8e5ae4b6a5d485fdef4adf818847d0112 Mon Sep 17 00:00:00 2001
From: ebotcazou <ebotcazou@138bc75d-0d04-0410-961f-82ee72b054a4>
Date: Fri, 12 Jan 2018 10:20:42 +0000
Subject: [PATCH] 	PR rtl-optimization/83565 	* rtlanal.c
 (nonzero_bits1): On WORD_REGISTER_OPERATIONS machines, do 	not extend the
 result to a larger mode for rotate operations. 
 (num_sign_bit_copies1): Likewise.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/branches/gcc-7-branch@256573 138bc75d-0d04-0410-961f-82ee72b054a4
---
 gcc/rtlanal.c                                    | 27 ++++++++++----------
 gcc/testsuite/gcc.c-torture/execute/20180112-1.c | 32 ++++++++++++++++++++++++
 2 files changed, 57 insertions(+), 13 deletions(-)
 create mode 100644 gcc/testsuite/gcc.c-torture/execute/20180112-1.c

diff --git a/gcc/rtlanal.c b/gcc/rtlanal.c
index acb4230aac8..b93d19537bb 100644
--- a/gcc/rtlanal.c
+++ b/gcc/rtlanal.c
@@ -4312,7 +4312,7 @@ nonzero_bits1 (const_rtx x, machine_mode mode, const_rtx known_x,
 {
   unsigned HOST_WIDE_INT nonzero = GET_MODE_MASK (mode);
   unsigned HOST_WIDE_INT inner_nz;
-  enum rtx_code code;
+  enum rtx_code code = GET_CODE (x);
   machine_mode inner_mode;
   unsigned int mode_width = GET_MODE_PRECISION (mode);
 
@@ -4335,18 +4335,18 @@ nonzero_bits1 (const_rtx x, machine_mode mode, const_rtx known_x,
     return nonzero;
 
   /* If MODE is wider than X, but both are a single word for both the host
-     and target machines, we can compute this from which bits of the
-     object might be nonzero in its own mode, taking into account the fact
-     that on many CISC machines, accessing an object in a wider mode
-     causes the high-order bits to become undefined.  So they are
-     not known to be zero.  */
-
-  if (!WORD_REGISTER_OPERATIONS
-      && GET_MODE (x) != VOIDmode
+     and target machines, we can compute this from which bits of the object
+     might be nonzero in its own mode, taking into account the fact that, on
+     CISC machines, accessing an object in a wider mode generally causes the
+     high-order bits to become undefined, so they are not known to be zero.
+     We extend this reasoning to RISC machines for rotate operations since the
+     semantics of the operations in the larger mode is not well defined.  */
+  if (GET_MODE (x) != VOIDmode
       && GET_MODE (x) != mode
       && GET_MODE_PRECISION (GET_MODE (x)) <= BITS_PER_WORD
       && GET_MODE_PRECISION (GET_MODE (x)) <= HOST_BITS_PER_WIDE_INT
-      && GET_MODE_PRECISION (mode) > GET_MODE_PRECISION (GET_MODE (x)))
+      && GET_MODE_PRECISION (mode) > GET_MODE_PRECISION (GET_MODE (x))
+      && (!WORD_REGISTER_OPERATIONS || code == ROTATE))
     {
       nonzero &= cached_nonzero_bits (x, GET_MODE (x),
 				      known_x, known_mode, known_ret);
@@ -4356,7 +4356,6 @@ nonzero_bits1 (const_rtx x, machine_mode mode, const_rtx known_x,
 
   /* Please keep nonzero_bits_binary_arith_p above in sync with
      the code in the switch below.  */
-  code = GET_CODE (x);
   switch (code)
     {
     case REG:
@@ -4873,8 +4872,10 @@ num_sign_bit_copies1 (const_rtx x, machine_mode mode, const_rtx known_x,
     {
       /* If this machine does not do all register operations on the entire
 	 register and MODE is wider than the mode of X, we can say nothing
-	 at all about the high-order bits.  */
-      if (!WORD_REGISTER_OPERATIONS)
+	 at all about the high-order bits.  We extend this reasoning to every
+	 machine for rotate operations since the semantics of the operations
+	 in the larger mode is not well defined.  */
+      if (!WORD_REGISTER_OPERATIONS || code == ROTATE || code == ROTATERT)
 	return 1;
 
       /* Likewise on machines that do, if the mode of the object is smaller
diff --git a/gcc/testsuite/gcc.c-torture/execute/20180112-1.c b/gcc/testsuite/gcc.c-torture/execute/20180112-1.c
new file mode 100644
index 00000000000..6752661ecb6
--- /dev/null
+++ b/gcc/testsuite/gcc.c-torture/execute/20180112-1.c
@@ -0,0 +1,32 @@
+/* PR rtl-optimization/83565 */
+/* Testcase by Sergei Trofimovich <slyfox@inbox.ru> */
+
+extern void abort (void);
+
+typedef unsigned int u32;
+
+u32 bug (u32 * result) __attribute__((noinline));
+u32 bug (u32 * result)
+{
+  volatile u32 ss = 0xFFFFffff;
+  volatile u32 d  = 0xEEEEeeee;
+  u32 tt = d & 0x00800000;
+  u32 r  = tt << 8;
+
+  r = (r >> 31) | (r <<  1);
+
+  u32 u = r^ss;
+  u32 off = u >> 1;
+
+  *result = tt;
+  return off;
+}
+
+int main(void)
+{
+  u32 l;
+  u32 off = bug(&l);
+  if (off != 0x7fffffff)
+    abort ();
+  return 0;
+}
-- 
2.15.1