aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Matz <matz@suse.de>2008-08-06 15:34:45 +0000
committerMichael Matz <matz@gcc.gnu.org>2008-08-06 15:34:45 +0000
commit46662f25ea011aa367beab9b6dd6276a47c4e48a (patch)
treea4d32cf8ff61e118247e78a10c552488a93ca876
parente94a448f66945080611074fc7859bea46e6fc688 (diff)
downloadgcc-46662f25ea011aa367beab9b6dd6276a47c4e48a.zip
gcc-46662f25ea011aa367beab9b6dd6276a47c4e48a.tar.gz
gcc-46662f25ea011aa367beab9b6dd6276a47c4e48a.tar.bz2
re PR target/36613 (likely codegen bug)
PR target/36613 * reload.c (push_reload): Merge in,out,in_reg,out_reg members for reused reload, instead of overwriting them. * gcc.target/i386/pr36613.c: New testcase. From-SVN: r138807
-rw-r--r--gcc/ChangeLog6
-rw-r--r--gcc/reload.c31
-rw-r--r--gcc/testsuite/ChangeLog5
-rw-r--r--gcc/testsuite/gcc.target/i386/pr36613.c44
4 files changed, 82 insertions, 4 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index a22491f..a08bd6e 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,9 @@
+2008-08-06 Michael Matz <matz@suse.de>
+
+ PR target/36613
+ * reload.c (push_reload): Merge in,out,in_reg,out_reg members
+ for reused reload, instead of overwriting them.
+
2008-08-06 H.J. Lu <hongjiu.lu@intel.com>
PR middle-end/37009
diff --git a/gcc/reload.c b/gcc/reload.c
index 93fff404..5a79c44 100644
--- a/gcc/reload.c
+++ b/gcc/reload.c
@@ -1403,13 +1403,36 @@ push_reload (rtx in, rtx out, rtx *inloc, rtx *outloc,
else
remove_address_replacements (rld[i].in);
}
- rld[i].in = in;
- rld[i].in_reg = in_reg;
+ /* When emitting reloads we don't necessarily look at the in-
+ and outmode, but also directly at the operands (in and out).
+ So we can't simply overwrite them with whatever we have found
+ for this (to-be-merged) reload, we have to "merge" that too.
+ Reusing another reload already verified that we deal with the
+ same operands, just possibly in different modes. So we
+ overwrite the operands only when the new mode is larger.
+ See also PR33613. */
+ if (!rld[i].in
+ || GET_MODE_SIZE (GET_MODE (in))
+ > GET_MODE_SIZE (GET_MODE (rld[i].in)))
+ rld[i].in = in;
+ if (!rld[i].in_reg
+ || (in_reg
+ && GET_MODE_SIZE (GET_MODE (in_reg))
+ > GET_MODE_SIZE (GET_MODE (rld[i].in_reg))))
+ rld[i].in_reg = in_reg;
}
if (out != 0)
{
- rld[i].out = out;
- rld[i].out_reg = outloc ? *outloc : 0;
+ if (!rld[i].out
+ || (out
+ && GET_MODE_SIZE (GET_MODE (out))
+ > GET_MODE_SIZE (GET_MODE (rld[i].out))))
+ rld[i].out = out;
+ if (outloc
+ && (!rld[i].out_reg
+ || GET_MODE_SIZE (GET_MODE (*outloc))
+ > GET_MODE_SIZE (GET_MODE (rld[i].out_reg))))
+ rld[i].out_reg = *outloc;
}
if (reg_class_subset_p (rclass, rld[i].rclass))
rld[i].rclass = rclass;
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index ead9638..d5b229a 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,8 @@
+2008-08-06 Michael Matz <matz@suse.de>
+
+ PR target/36613
+ * gcc.target/i386/pr36613.c: New testcase.
+
2008-08-06 H.J. Lu <hongjiu.lu@intel.com>
PR middle-end/37009
diff --git a/gcc/testsuite/gcc.target/i386/pr36613.c b/gcc/testsuite/gcc.target/i386/pr36613.c
new file mode 100644
index 0000000..e9d7d11
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr36613.c
@@ -0,0 +1,44 @@
+/* { dg-do run { target { { i?86-*-linux* x86_64-*-linux* } && ilp32 } } } */
+/* { dg-options "-Os" } */
+/* PR target/36613 */
+
+extern void abort (void);
+
+static inline int
+lshifts (int val, int cnt)
+{
+ if (val < 0)
+ return val;
+ return val << cnt;
+}
+
+static inline unsigned int
+lshiftu (unsigned int val, unsigned int cnt)
+{
+ if (cnt >= sizeof (unsigned int) * __CHAR_BIT__
+ || val > ((__INT_MAX__ * 2U) >> cnt))
+ return val;
+ return val << cnt;
+}
+
+static inline int
+rshifts (int val, unsigned int cnt)
+{
+ if (val < 0 || cnt >= sizeof (int) * __CHAR_BIT__)
+ return val;
+ return val >> cnt;
+}
+
+int
+foo (unsigned int val)
+{
+ return rshifts (1 + val, lshifts (lshiftu (val, val), 1));
+}
+
+int
+main (void)
+{
+ if (foo (1) != 0)
+ abort ();
+ return 0;
+}