diff mbox

Avoid zext/sext directly from hard registers during expansion (PR rtl-optimization/53942)

Message ID 20120717095043.GA9077@tucnak.redhat.com
State New
Headers show

Commit Message

Jakub Jelinek July 17, 2012, 9:50 a.m. UTC
Hi!

The following testcase ICEs on i?86, because combiner sees a zero extension
of the likely spilled cx register generated during expansion and as it is
not a simple register move, propagates it into a use many insns later in the
function, enlarging thus the lifetime of the hard register and causing RA
failure on a register in between the two that needs to use that particular
hard register.

cant_combine_insn_p only special cases simple register moves out of or into
likely spilled hard registers.  The following patch fixes it by using
roughly the same condition to decide if it is ok to emit a zero or sign
extension directly from the hard register or if it is better to first copy
the hard register into a pseudo (then combiner (and fwprop etc.) seem to do
the right thing).

Bootstrapped/regtested on x86_64-linux and i686-linux, on both I've verified
it doesn't affect code generation for cc1plus (appart from function.o
obviously), libstdc++.so and libgcj.so.  Ok for trunk (and perhaps after a
while for the 4.7 branch)?

2012-07-17  Jakub Jelinek  <jakub@redhat.com>

	PR rtl-optimization/53942
	* function.c (assign_parm_setup_reg): Avoid zero/sign extension
	directly from likely spilled non-fixed hard registers, move them
	to pseudo first.

	* gcc.dg/pr53942.c: New test.


	Jakub

Comments

Richard Henderson July 19, 2012, 7:35 p.m. UTC | #1
On 07/17/2012 02:50 AM, Jakub Jelinek wrote:
> 2012-07-17  Jakub Jelinek  <jakub@redhat.com>
> 
> 	PR rtl-optimization/53942
> 	* function.c (assign_parm_setup_reg): Avoid zero/sign extension
> 	directly from likely spilled non-fixed hard registers, move them
> 	to pseudo first.
> 
> 	* gcc.dg/pr53942.c: New test.


Ok.


r~
diff mbox

Patch

--- gcc/function.c.jj	2012-06-25 08:38:26.000000000 +0200
+++ gcc/function.c	2012-07-16 13:41:52.847928315 +0200
@@ -2988,11 +2988,26 @@  assign_parm_setup_reg (struct assign_par
 	  && insn_operand_matches (icode, 1, op1))
 	{
 	  enum rtx_code code = unsignedp ? ZERO_EXTEND : SIGN_EXTEND;
-	  rtx insn, insns;
+	  rtx insn, insns, t = op1;
 	  HARD_REG_SET hardregs;
 
 	  start_sequence ();
-	  insn = gen_extend_insn (op0, op1, promoted_nominal_mode,
+	  /* If op1 is a hard register that is likely spilled, first
+	     force it into a pseudo, otherwise combiner might extend
+	     its lifetime too much.  */
+	  if (GET_CODE (t) == SUBREG)
+	    t = SUBREG_REG (t);
+	  if (REG_P (t)
+	      && HARD_REGISTER_P (t)
+	      && ! TEST_HARD_REG_BIT (fixed_reg_set, REGNO (t))
+	      && targetm.class_likely_spilled_p (REGNO_REG_CLASS (REGNO (t))))
+	    {
+	      t = gen_reg_rtx (GET_MODE (op1));
+	      emit_move_insn (t, op1);
+	    }
+	  else
+	    t = op1;
+	  insn = gen_extend_insn (op0, t, promoted_nominal_mode,
 				  data->passed_mode, unsignedp);
 	  emit_insn (insn);
 	  insns = get_insns ();
--- gcc/testsuite/gcc.dg/pr53942.c.jj	2012-06-15 19:53:34.312404791 +0200
+++ gcc/testsuite/gcc.dg/pr53942.c	2012-07-17 11:26:48.863053287 +0200
@@ -0,0 +1,34 @@ 
+/* PR rtl-optimization/53942 */
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+/* { dg-additional-options "-mtune=pentium2" { target { { i?86-*-* x86_64-*-* } && ia32 } } } */
+
+struct S
+{
+  unsigned short w[3];
+  unsigned int x, y;
+};
+
+struct S *baz (void);
+
+__attribute__ ((noinline))
+static unsigned char
+foo (struct S *x, unsigned char y)
+{
+  unsigned char c = 0;
+  unsigned char v = x->w[0];
+  c |= v;
+  v = ((x->w[1]) & (1 << y)) ? 1 : 0;
+  c |= v << 1;
+  v = ((x->w[2]) & 0xff) & (1 << y);
+  c |= v << 2;
+  return c;
+}
+
+void
+bar (void)
+{
+  struct S *s = baz ();
+  s->x = foo (s, 6);
+  s->y = foo (s, 7);
+}