The x86 backend can generate non-canonical RTL when it simplifies
address expressions.
In particular addresses which have the form
(plus (mult) (A) (B) (label_ref))
If the multiplication can be simplified to a constant, the x86 backend
will end up generating
(plus (constant) (label_ref))
Which is obviously non-canonical and should be written
(const (plus (label_ref) (constant))
This change merely canonicalizes the RTL, leaving it to other code to
simplify. At first I wanted to simplify, but it just gets painful if,
for example B above is (const_int 0), in which case our example
collapses into
(label_ref)
The subsequent code in the ix86_legitimize_address assumes it's still
working with a PLUS. Fixable, but painful.
It's also the case that simplify_rtx might return NULL. So the code
also has to DTRT in that case and the caller's don't DTRT if
ix86_legitimize_address returns NULL.
Anyway, I did verify that the relevant code in the short example gets
optimized if we just fix the canonicalization (namely the addition of
(const_int 0) is eliminated).
Bootstrapped and regression tested on x86_64-unknown-linux-gnu.
Verified it fixes the original and reduced testcase.
OK for the trunk?
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 53d58b3..80f0ba8 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,8 @@
+2014-03-26 Jeff Law <l...@redhat.com>
+
+ * i386/i386.c (ix86_legitimize_address): Canonicalize
+ (plus (const) (label_ref)).
+
2014-03-26 Richard Biener <rguent...@suse.de>
* tree-pretty-print.c (percent_K_format): Implement special
diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
index 842be68..79f4aff 100644
--- a/gcc/config/i386/i386.c
+++ b/gcc/config/i386/i386.c
@@ -13939,6 +13939,28 @@ ix86_legitimize_address (rtx x, rtx oldx
ATTRIBUTE_UNUSED,
&& REG_P (XEXP (x, 0)))
return x;
+ /* We might have started with something like
+
+ (plus (mult (const_int 1) (const_int 4)) (label_ref))
+
+ Which we change into:
+
+ (plus (const_int 4) (label_ref))
+
+ Which is obviously not canonical RTL. Passing the non
+ canonical RTL up to our caller is bad.
+
+ Do not simplify, just canonicalize. Simplification opens up
+ a can of worms here as that can change the structure of X which
+ this code isn't really prepared to handle. */
+ if (COMMUTATIVE_ARITH_P (x)
+ && swap_commutative_operands_p (XEXP (x, 0), XEXP (x, 1)))
+ {
+ rtx temp = XEXP (x, 0);
+ XEXP (x, 0) = XEXP (x, 1);
+ XEXP (x, 1) = temp;
+ }
+
if (flag_pic && SYMBOLIC_CONST (XEXP (x, 1)))
{
changed = 1;
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index cdc8e9a..789e27d 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,8 @@
+2014-02-27 Jeff Law <l...@redhat.com>
+
+ PR target/60648
+ * g++.dg/pr60648.C: New test.
+
2014-03-26 Jakub Jelinek <ja...@redhat.com>
PR sanitizer/60636