proposed fix for PRs target/54516 & rtl-optimization/54540

Message ID
State New
Headers show

Commit Message

Richard Earnshaw Sept. 12, 2012, 4:41 p.m.
Although the mersenne twister code is new, the build/runtime failures of
PRs target/54516 and PR rtl-optimization/54540 can be tracked back to
the addition of the variant

	add	%0("=rk"), %1("0"), %2("rk") // size=2

to the thumb2 backend.  This is causing reload to try to do clever
things when we have a large stack adjustment.

Prior to reload we have a sequence of the form:

	r<n>:SI = sp:SI + (-some_const1)
	sp:SI = r<n>:SI + (-some_const2)

Since there is no thumb2 instruction to directly perform the second
operation some reloading is needed.  Reload determines that the new
variant described above is a viable candidate and sets about trying to
create reloads for it.

The first thing it does is rearranges the operands to create

	sp:SI = (-some_const2) + r<n>:SI

which now needs precisely one reload.  The tie operation forces a reload
into sp of the value -some_const2, not realizing that putting random
values into SP is potentially very dangerous to the health of your
program (or system if you're running at a privileged level).

It seems to me that find_dummy_reload is doing an unsafe thing by
permitting the use of a register in fixed_regs[] as a reload register --
writing to fixed regs could have unspecified side effects on the
machine, so they should only be used in the ways that earlier passes
have deemed to be safe, and using them as a temporary is not one of those.

So this patch fixes the problem by forcing find_dummy_reload to reject
OUT as a valid reload register for IN when OUT overlaps a register
mentioned in fixed_regs[].

Bootstrapped on arm-linux-gnueabi with no regressions.  No new tests are
needed as this fixes the execution failures in the mersenne twister tests.

	* reload.c (find_dummy_reload): Don't use OUT as a reload reg
	for IN if it overlaps a fixed register.



--- reload.c	(revision 191208)
+++ reload.c	(local)
@@ -2036,7 +2036,12 @@  find_dummy_reload (rtx real_in, rtx real
 	 However, we only ignore IN in its role as this reload.
 	 If the insn uses IN elsewhere and it contains OUT,
 	 that counts.  We can't be sure it's the "same" operand
-	 so it might not go through this reload.  */
+	 so it might not go through this reload.  
+         We also need to avoid using OUT if it, or part of it, is a
+         fixed register.  Modifying such registers, even transiently,
+         may have undefined effects on the machine, such as modifying
+         the stack pointer.  */
       saved_rtx = *inloc;
       *inloc = const0_rtx;
@@ -2049,7 +2054,8 @@  find_dummy_reload (rtx real_in, rtx real
 	  for (i = 0; i < nwords; i++)
 	    if (! TEST_HARD_REG_BIT (reg_class_contents[(int) rclass],
-				     regno + i))
+				     regno + i)
+		|| fixed_regs[regno + i])
 	  if (i == nwords)