diff mbox

Fix for reloads_unique_chain_p

Message ID 525D1FD6.4030001@codesourcery.com
State New
Headers show

Commit Message

Bernd Schmidt Oct. 15, 2013, 10:58 a.m. UTC
We have a testcase where we have this insn:

(insn:HI 53 55 56 2 (set (reg:SI 214 [ D.1303 ])
        (mem:SI (plus:SI (mult:SI (reg/v:SI 219 [ p2 ])
                    (const_int 4 [0x4]))
                (reg/v/f:SI 218 [ p1 ])) [3 S4 A32])) 163

which produces the following reloads:

Reload 0: reload_in (SI)
            = (plus:SI (reg/f:SI 11 fp) (const_int -16384))
    CORE_REGS, RELOAD_FOR_OPERAND_ADDRESS (opnum = 1)
    reload_in_reg: (plus:SI (reg/f:SI 11 fp) (const_int -16384))
    reload_reg_rtx: (reg:SI 2 r2)

Reload 1: reload_in (SI)
            = (mem/c:SI (plus:SI (plus:SI (reg/f:SI 11 fp)
                                          (const_int -16384))
                                 (const_int -536 )))
    GENERAL_REGS, RELOAD_FOR_OPERAND_ADDRESS (opnum = 1), can't combine
    reload_in_reg: (reg/v:SI 219 [ p2 ])
    reload_reg_rtx: (reg:SI 2 r2)
Reload 2: CORE_REGS, RELOAD_FOR_OPERAND_ADDRESS (opnum = 1)
    reload_in_reg: (plus:SI (reg/f:SI 11 fp) (const_int -16384))
Reload 3: reload_in (SI)
             = (mem/c:SI (plus:SI (plus:SI (reg/f:SI 11 fp)
                                           (const_int -16384))
                                  (const_int -532)))
    CORE_REGS, RELOAD_FOR_OPERAND_ADDRESS (opnum = 1), can't combine
    reload_in_reg: (reg/v/f:SI 218 [ p1 ])
    reload_reg_rtx: (reg:SI 1 r1)

Of note here is that reload 2 was made and then discarded, and its
replacements transferred to the identical reload 0.  This means the
reload reg from reload 0 is in use by both reloads 1 and 3.  This means
that the choice of register r2 for reload 1 is wrong: it clobbers r2
which is in use for reload 0.

reloads_conflict incorrectly returns false for 0 and 1, and that in turn
is because reloads_unique_chain_p returns true for them.  In
reloads_unique_chain_p we do try to see if the input of r1 is used in
any other reload, but this is where we fail: reload_order has arranged
for r1==1 and r2==0, so we're testing the wrong reload. Fixed simply by
inverting the order if necessary.

Bootstrapped and tested on x86_64-linux. Andrew has tested on some arm
target with a 4.3-based compiler (I think). Committed (my first
successful attempt at git svn dcommit, so I hope I didn't accidentally
wipe the tree). There's no testcase for this since the problem is only
reproducible with a non-executable complex customer testcase using a
patched gcc-4.3.

I'm thinking this probably ought to go into 4.8 as well.


Bernd
diff mbox

Patch

commit 6a77b1fca11e2fe9ac20aba2a241ead5a8ebd701
Author: Bernd Schmidt <bernds@codesourcery.com>
Date:   Tue Oct 15 12:16:07 2013 +0200

    Fix a miscompilation where a reload reg is reused after it has been clobbered.
    
    	* reload1.c (reloads_unique_chain_p): Ensure that r1 is the input for
    	r2.

diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 39ea203..6bf624e 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,8 @@ 
+2013-10-15  Bernd Schmidt  <bernds@codesourcery.com>
+
+	* reload1.c (reloads_unique_chain_p): Ensure that r1 is the input for
+	r2.
+
 2013-10-15  Richard Biener  <rguenther@suse.de>
 
 	* tree-loop-distribution.c (build_empty_rdg): Inline into
diff --git a/gcc/reload1.c b/gcc/reload1.c
index bb13bf8..d56c554 100644
--- a/gcc/reload1.c
+++ b/gcc/reload1.c
@@ -5560,6 +5560,14 @@  reloads_unique_chain_p (int r1, int r2)
 	    || reg_mentioned_p (rld[r2].in, rld[r1].in)))
     return false;
 
+  /* The following loop assumes that r1 is the reload that feeds r2.  */
+  if (r1 > r2)
+    {
+      int tmp = r2;
+      r2 = r1;
+      r1 = tmp;
+    }
+
   for (i = 0; i < n_reloads; i ++)
     /* Look for input reloads that aren't our two */
     if (i != r1 && i != r2 && rld[i].in)