This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

RFA: Fix PR 32897 (invalid constants generated by find_reloads_toplev)


The following testcase:

---------------------------------------------------------------------------
volatile int g[32];
long long gll;
double gd;

#define MULTI(X) \
        X( 1), X( 2), X( 3), X( 4), X( 5), X( 6), X( 7), X( 8), X( 9), X(10), \
        X(11), X(12), X(13), X(14), X(15), X(16), X(17), X(18), X(19), X(20), \
        X(21), X(22), X(23), X(24), X(25), X(26), X(27), X(28), X(29), X(30)

#define DECLARE(INDEX) x##INDEX
#define COPY_IN(INDEX) x##INDEX = g[INDEX]
#define COPY_OUT(INDEX) g[INDEX] = x##INDEX

void
test (int n)
{
  union { long long l; double d; } u = { 0x12345678 };
  gll = u.l;
  int MULTI (DECLARE);
  MULTI (COPY_IN);
  MULTI (COPY_OUT);
  MULTI (COPY_OUT);
  MULTI (COPY_OUT);
  gd = u.d;
}
---------------------------------------------------------------------------

fails for mips*-elf targets when compiled with -G0 and with
optimisation enabled:

internal compiler error: in emit_move_insn, at expr.c:3317

The pseudo register that holds "u" is not allocated a hard
register, so we rematerialise the constant 0x1234567 on demand.
We check when setting reg_equiv_constant that 0x1234567 does indeed
satisfy LEGITIMATE_CONSTANT_P; we'd force it into memory otherwise.

However, find_reloads_toplev assumes that simplified subregs of
reg_equiv_constant entries also satisfy LEGITIMATE_CONSTANT_P.
This isn't true here: the original 0x12345678 CONST_INT is legitimate,
but the equivalent DFmode CONST_DOUBLE is not.

(I came across this while working on another patch.  The original
test was more natural; the one above was just reverse-engineered
after the fact.)

I think the fix is to force the subregged constant into the
constant pool if it isn't itself legitimate.  We must then
reload the new MEM's address.

There are actually two blocks of code that try to create the
subreg of a constant:

      if (subreg_lowpart_p (x)
	  && regno >= FIRST_PSEUDO_REGISTER
	  && reg_renumber[regno] < 0
	  && reg_equiv_constant[regno] != 0
	  && (tem = gen_lowpart_common (GET_MODE (x),
					reg_equiv_constant[regno])) != 0)
	return tem;

      if (regno >= FIRST_PSEUDO_REGISTER
	  && reg_renumber[regno] < 0
	  && reg_equiv_constant[regno] != 0)
	{
	  tem =
	    simplify_gen_subreg (GET_MODE (x), reg_equiv_constant[regno],
				 GET_MODE (SUBREG_REG (x)), SUBREG_BYTE (x));
	  gcc_assert (tem);
	  return tem;
	}

But this is redundant: gen_lowpart_common now uses simplify_gen_subreg
for constants anyway.  The first block isn't even a fast path; we spend
longer working out whether the special case applies, and what
simplify_gen_subreg's arguments should be if so, than we would if we
went straight to the second block.

So, rather than add special constant pool handling to both blocks of code,
I simply removed the first block and added the special handling to the second.

find_reloads assumes that, if find_reloads_toplev returns a MEM for
a SUBREG of a REG, the inner register must be equivalent to a memory
location.  That's no longer true, so I've made it also check that the
REG is not equivalent to a constant.  (I think that's better than checking
the reg_equiv_mem* arrays, because it documents why the extra condition
is needed.)

Bootstrapped & regression tested on x86_64-linux-gnu.  Also regression-
tested on mipsisa64-elf (flags {,-mips32}{-EB,-EL}{,-msoft-float}).
OK to install?

Richard


gcc/
	PR middle-end/32897
	* reload.c (find_reloads): Check that the memory returned by
	find_reloads_toplev was not the result of forcing a constant
	to memory.
	(find_reloads_toplev): Always use simplify_gen_subreg to get
	the subreg of a constant.  If the result is also a constant,
	but not a legitimate one, force it into the constant pool
	and reload its address.

gcc/testsuite/
	* gcc.dg/torture/pr32897.c: New test.

Index: gcc/reload.c
===================================================================
--- gcc/reload.c	(revision 126918)
+++ gcc/reload.c	(working copy)
@@ -2795,7 +2795,8 @@ find_reloads (rtx insn, int replace, int
 	      && MEM_P (op)
 	      && REG_P (reg)
 	      && (GET_MODE_SIZE (GET_MODE (reg))
-		  >= GET_MODE_SIZE (GET_MODE (op))))
+		  >= GET_MODE_SIZE (GET_MODE (op)))
+	      && reg_equiv_constant[REGNO (reg)] == 0)
 	    set_unique_reg_note (emit_insn_before (gen_rtx_USE (VOIDmode, reg),
 						   insn),
 				 REG_EQUAL, reg_equiv_memory_loc[REGNO (reg)]);
@@ -4601,14 +4602,6 @@ find_reloads_toplev (rtx x, int opnum, e
       int regno = REGNO (SUBREG_REG (x));
       rtx tem;
 
-      if (subreg_lowpart_p (x)
-	  && regno >= FIRST_PSEUDO_REGISTER
-	  && reg_renumber[regno] < 0
-	  && reg_equiv_constant[regno] != 0
-	  && (tem = gen_lowpart_common (GET_MODE (x),
-					reg_equiv_constant[regno])) != 0)
-	return tem;
-
       if (regno >= FIRST_PSEUDO_REGISTER
 	  && reg_renumber[regno] < 0
 	  && reg_equiv_constant[regno] != 0)
@@ -4617,6 +4610,15 @@ find_reloads_toplev (rtx x, int opnum, e
 	    simplify_gen_subreg (GET_MODE (x), reg_equiv_constant[regno],
 				 GET_MODE (SUBREG_REG (x)), SUBREG_BYTE (x));
 	  gcc_assert (tem);
+	  if (CONSTANT_P (tem) && !LEGITIMATE_CONSTANT_P (tem))
+	    {
+	      tem = force_const_mem (GET_MODE (x), tem);
+	      i = find_reloads_address (GET_MODE (tem), &tem, XEXP (tem, 0),
+					&XEXP (tem, 0), opnum, type,
+					ind_levels, insn);
+	      if (address_reloaded)
+		*address_reloaded = i;
+	    }
 	  return tem;
 	}
 
Index: gcc/testsuite/gcc.dg/torture/pr32897.c
===================================================================
--- gcc/testsuite/gcc.dg/torture/pr32897.c	(revision 0)
+++ gcc/testsuite/gcc.dg/torture/pr32897.c	(revision 0)
@@ -0,0 +1,27 @@
+/* { dg-options "-G0" { target mips*-*-* } } */
+
+volatile int g[32];
+long long gll;
+double gd;
+
+#define MULTI(X) \
+	X( 1), X( 2), X( 3), X( 4), X( 5), X( 6), X( 7), X( 8), X( 9), X(10), \
+	X(11), X(12), X(13), X(14), X(15), X(16), X(17), X(18), X(19), X(20), \
+	X(21), X(22), X(23), X(24), X(25), X(26), X(27), X(28), X(29), X(30)
+
+#define DECLARE(INDEX) x##INDEX
+#define COPY_IN(INDEX) x##INDEX = g[INDEX]
+#define COPY_OUT(INDEX) g[INDEX] = x##INDEX
+
+void
+test (int n)
+{
+  union { long long l; double d; } u = { 0x12345678 };
+  gll = u.l;
+  int MULTI (DECLARE);
+  MULTI (COPY_IN);
+  MULTI (COPY_OUT);
+  MULTI (COPY_OUT);
+  MULTI (COPY_OUT);
+  gd = u.d;
+}


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]