fix for e_pow.o failure

Geoff Keating geoffk@cygnus.com
Mon Oct 23 11:41:00 GMT 2000


The regression tester, while trying to qualify a new version of
binutils so it could upgrade to it, kept finding that
execute/980709-1.c was failing.  It turned out that gcc was
miscompiling e_pow.o in newlib's libm.  The bad code sequence was:

  t = z * z;
  t1 = z - t*(P1+t*(P2+t*(P3+t*(P4+t*P5))));

which got compiled into

---at this point, t is in %f11 aka (reg/v:DF 84)
        fmul %f11,%f11,%f11      # 1393 muldf3  [length = 4]
---now z is in %f11 aka (reg/v:DF 95)
        stfd %f11,72(%r1)        # 2336 *movdf_hardfloat32/9    [length = 4]
        lis %r9,.LC23@ha         # 1635 elf_high        [length = 4]
        lfd %f0,.LC23@l(%r9)     # 1632 *movdf_hardfloat32/8    [length = 4]
        lis %r9,.LC24@ha         # 1634 elf_high        [length = 4]
        lfd %f13,.LC24@l(%r9)    # 1633 *movdf_hardfloat32/8    [length = 4]
        fmr %f10,%f11    # 2345 *movdf_hardfloat32/7    [length = 4]
        fmadd %f0,%f10,%f0,%f13  # 1404 divdf3+1        [length = 4]
        lis %r9,.LC25@ha         # 1631 elf_high        [length = 4]
        lfd %f13,.LC25@l(%r9)    # 1409 *movdf_hardfloat32/8    [length = 4]
        fmadd %f0,%f10,%f0,%f13  # 1410 divdf3+1        [length = 4]
        lis %r9,.LC26@ha         # 1630 elf_high        [length = 4]
        lfd %f13,.LC26@l(%r9)    # 1415 *movdf_hardfloat32/8    [length = 4]
        fmadd %f0,%f10,%f0,%f13  # 1416 divdf3+1        [length = 4]
        lis %r9,.LC27@ha         # 1629 elf_high        [length = 4]
        lfd %f13,.LC27@l(%r9)    # 1421 *movdf_hardfloat32/8    [length = 4]
        fmadd %f0,%f10,%f0,%f13  # 1422 divdf3+1        [length = 4]
        fmul %f0,%f10,%f0        # 1423 muldf3  [length = 4]
--- this is the subtract insn
        fsub %f11,%f11,%f0       # 1424 subdf3  [length = 4]

which is wrong, as it computes

     t1 = t - t*(P1+t*(P2+t*(P3+t*(P4+t*P5))));

Insn 1393 comes into reload_as_needed as:

(insn 1393 1391 1395 (set (reg/v:DF 5 r5)
        (mult:DF (reg/v:DF 11 r11)
            (reg/v:DF 11 r11))) 188 {muldf3} (nil)
    (nil))

which is a spectacularly poor register choice, due to the recent cost
changes; I'll be fixing that in a later patch but I wanted to fix the
reload bug first.

We generate these reloads for it:

Reload 0: reload_out (DF) = (reg/v:DF 5 r5)
        FLOAT_REGS, RELOAD_FOR_OUTPUT (opnum = 0)
        reload_out_reg: (reg/v:DF 5 r5)
Reload 1: reload_in (DF) = (reg/v:DF 11 r11)
        FLOAT_REGS, RELOAD_FOR_INPUT (opnum = 1)
        reload_in_reg: (reg/v:DF 11 r11)
Reload 2: reload_in (DF) = (reg/v:DF 11 r11)
        FLOAT_REGS, RELOAD_FOR_INPUT (opnum = 2)
        reload_in_reg: (reg/v:DF 11 r11)

combine_reloads then turns this into:

Reload 0: FLOAT_REGS, RELOAD_FOR_OUTPUT (opnum = 0)
        reload_out_reg: (reg/v:DF 5 r5)
Reload 1: reload_in (DF) = (reg/v:DF 11 r11)
        reload_out (DF) = (reg/v:DF 5 r5)
        FLOAT_REGS, RELOAD_OTHER (opnum = 1)
        reload_in_reg: (reg/v:DF 11 r11)
        reload_out_reg: (reg/v:DF 5 r5)
        reload_reg_rtx: (reg:DF 43 f11)
Reload 2: reload_in (DF) = (reg/v:DF 11 r11)
        FLOAT_REGS, RELOAD_FOR_INPUT (opnum = 2)
        reload_in_reg: (reg/v:DF 11 r11)
        reload_reg_rtx: (reg:DF 43 f11)

(reload has combined reloads 0 and 1 to save reload registers).

The code that sets up the register elimination mechanism failed to
detect that register f11, which is used by both reload 1 and reload 2,
has a final value from reload 1 (because 1 is both an input and
output reload) not reload 2.  It therefore thinks that register f11
holds 'z', not 't', thus the bug.

The patch below was bootstrapped and tested on powerpc-linux.

-- 
- Geoffrey Keating <geoffk@cygnus.com>

===File ~/patches/cygnus/gcc-powbug.patch===================
2000-10-23  Geoff Keating  <geoffk@cygnus.com>

	* reload1.c (reload_reg_reaches_end_p): A RELOAD_OTHER can
	overwrite the value in a RELOAD_FOR_INPUT and other kinds of
	reloads just like an RELOAD_FOR_OUTPUT would.

Index: reload1.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/reload1.c,v
retrieving revision 1.232
diff -p -u -u -p -r1.232 reload1.c
--- reload1.c	2000/10/18 02:26:26	1.232
+++ reload1.c	2000/10/23 18:27:48
@@ -4480,8 +4480,9 @@ reload_reg_reaches_end_p (regno, opnum, 
       if (TEST_HARD_REG_BIT (reload_reg_used_in_op_addr_reload, regno))
 	return 0;
 
-      return (! TEST_HARD_REG_BIT (reload_reg_used_in_op_addr, regno)
-	      && ! TEST_HARD_REG_BIT (reload_reg_used_in_insn, regno));
+      return (!TEST_HARD_REG_BIT (reload_reg_used_in_op_addr, regno)
+	      && !TEST_HARD_REG_BIT (reload_reg_used_in_insn, regno)
+	      && !TEST_HARD_REG_BIT (reload_reg_used, regno));
 
     case RELOAD_FOR_INPUT:
       /* Similar to input address, except we start at the next operand for
@@ -4506,7 +4507,7 @@ reload_reg_reaches_end_p (regno, opnum, 
 	    || TEST_HARD_REG_BIT (reload_reg_used_in_output[i], regno))
 	  return 0;
 
-      return 1;
+      return (!TEST_HARD_REG_BIT (reload_reg_used, regno));
 
     case RELOAD_FOR_OPADDR_ADDR:
       for (i = 0; i < reload_n_operands; i++)
@@ -4515,8 +4516,9 @@ reload_reg_reaches_end_p (regno, opnum, 
 	    || TEST_HARD_REG_BIT (reload_reg_used_in_output[i], regno))
 	  return 0;
 
-      return (! TEST_HARD_REG_BIT (reload_reg_used_in_op_addr, regno)
-	      && !TEST_HARD_REG_BIT (reload_reg_used_in_insn, regno));
+      return (!TEST_HARD_REG_BIT (reload_reg_used_in_op_addr, regno)
+	      && !TEST_HARD_REG_BIT (reload_reg_used_in_insn, regno)
+	      && !TEST_HARD_REG_BIT (reload_reg_used, regno));
 
     case RELOAD_FOR_INSN:
       /* These conflict with other outputs with RELOAD_OTHER.  So
============================================================


More information about the Gcc-patches mailing list