Patchwork [RS6000] Fix PR52107, TFmode constant load.

login
register
mail settings
Submitter Alan Modra
Date Feb. 4, 2012, 5:46 a.m.
Message ID <20120204054652.GC4832@bubble.grove.modra.org>
Download mbox | patch
Permalink /patch/139530/
State New
Headers show

Comments

Alan Modra - Feb. 4, 2012, 5:46 a.m.
http://gcc.gnu.org/ml/gcc-patches/2007-01/msg01835.html changed the
code I'm tweaking here to use DFmode subregs when loading a TFmode
constant into regs for e500.  This just extends that change to all
rs6000 targets, the simplest fix I found for PR52107, a problem I
discovered when looking at powerpc64-linux libgcc.

If we leave these constant loads as DImode, here's what happens at
various stages of rtl optimisation:

.expand
(insn 7 6 8 (set (reg:DI 35 3)
        (mem/u/c:DI (unspec:DI [
                    (symbol_ref/u:DI ("*.LC1") [flags 0x2])
                    (reg:DI 2 2)
                ] UNSPEC_TOCREL) [5 S8 A8])) /src/tmp/floatconst.c:10 -1
     (nil))

.cse1
(insn 7 6 8 2 (set (reg:DI 35 3)
        (const_int 4318952042648305664 [0x3bf0000000000000])) /src/tmp/floatconst.c:10 401 {*movdi_internal64}
     (nil))

.split1
(insn 21 3 22 2 (set (reg:DI 35 3)
        (mem/u/c:DI (unspec:DI [
                    (symbol_ref/u:DI ("*.LC3") [flags 0x2])
                    (reg:DI 2 2)
                ] UNSPEC_TOCREL) [5 S8 A8])) /src/tmp/floatconst.c:10 -1
     (expr_list:REG_EQUAL (const_int 1005584384 [0x3bf00000])
        (nil)))

(insn 22 21 8 2 (set (reg:DI 35 3)
        (ashift:DI (reg:DI 35 3)
            (const_int 32 [0x20]))) /src/tmp/floatconst.c:10 -1
     (expr_list:REG_EQUAL (const_int 4318952042648305664 [0x3bf0000000000000])
        (nil)))

It would also be possible to fix this in the rs6000.md movdi splitter
dealing with large constants, at least for this testcase when we know
we are dealing with a hard float reg.  However, I think it's better
not to generate DImode fp values in the first place.  Bootstrapped and
regression tested powerpc64-linux.  OK to apply everywhere?

Note that the comment I remove is no longer true.

	PR target/52107
	* config/rs6000/rs6000.c (rs6000_emit_move): Don't create DImode
	subregs of TFmode.
David Edelsohn - Feb. 6, 2012, 5:06 p.m.
On Sat, Feb 4, 2012 at 12:46 AM, Alan Modra <amodra@gmail.com> wrote:
> http://gcc.gnu.org/ml/gcc-patches/2007-01/msg01835.html changed the
> code I'm tweaking here to use DFmode subregs when loading a TFmode
> constant into regs for e500.  This just extends that change to all
> rs6000 targets, the simplest fix I found for PR52107, a problem I
> discovered when looking at powerpc64-linux libgcc.

> It would also be possible to fix this in the rs6000.md movdi splitter
> dealing with large constants, at least for this testcase when we know
> we are dealing with a hard float reg.  However, I think it's better
> not to generate DImode fp values in the first place.  Bootstrapped and
> regression tested powerpc64-linux.  OK to apply everywhere?

>        PR target/52107
>        * config/rs6000/rs6000.c (rs6000_emit_move): Don't create DImode
>        subregs of TFmode.

This fix is okay in trunk and 4.6.  I am more reluctant to approve
backporting it to GCC 4.5 at this late date.

Thanks, David

Patch

Index: gcc/config/rs6000/rs6000.c
===================================================================
--- gcc/config/rs6000/rs6000.c	(revision 183781)
+++ gcc/config/rs6000/rs6000.c	(working copy)
@@ -7006,17 +7006,14 @@  rs6000_emit_move (rtx dest, rtx source, 
   if (!TARGET_IEEEQUAD && TARGET_LONG_DOUBLE_128
       && mode == TFmode && GET_CODE (operands[1]) == CONST_DOUBLE)
     {
-      /* DImode is used, not DFmode, because simplify_gen_subreg doesn't
-	 know how to get a DFmode SUBREG of a TFmode.  */
-      enum machine_mode imode = (TARGET_E500_DOUBLE ? DFmode : DImode);
-      rs6000_emit_move (simplify_gen_subreg (imode, operands[0], mode, 0),
-			simplify_gen_subreg (imode, operands[1], mode, 0),
-			imode);
-      rs6000_emit_move (simplify_gen_subreg (imode, operands[0], mode,
-					     GET_MODE_SIZE (imode)),
-			simplify_gen_subreg (imode, operands[1], mode,
-					     GET_MODE_SIZE (imode)),
-			imode);
+      rs6000_emit_move (simplify_gen_subreg (DFmode, operands[0], mode, 0),
+			simplify_gen_subreg (DFmode, operands[1], mode, 0),
+			DFmode);
+      rs6000_emit_move (simplify_gen_subreg (DFmode, operands[0], mode,
+					     GET_MODE_SIZE (DFmode)),
+			simplify_gen_subreg (DFmode, operands[1], mode,
+					     GET_MODE_SIZE (DFmode)),
+			DFmode);
       return;
     }