[Committed] PR middle-end/18548: RTL expansion of MAX_EXPR

Roger Sayle roger@eyesopen.com
Sat Dec 18 14:38:00 GMT 2004


This patch resolves PR middle-end/18548 which is a wrong-code regression
on mainline.  The problem is that the RTL sequences generated for MIN_EXPR
and MAX_EXPR generated can clobber "target" which may still be required
to evaluate op0 and/or op1.

Consider the problematic case of "a = MAX(b, a+1)", where we expand_expr
ends up with target = (reg A), op0 = (reg B) and op1 = (plus (reg A) 1).
Although we use safe_from_p in expand_operands which ensures that we
don't overwrite target when evaluating op0 and op1, the later code
doesn't test for this interaction.  So instead we generate

	target = op0		(set (reg A) (reg B))
	if (target < op1)	(compare (reg A) (plus (reg A) 1))
	  target = op1		(set (reg A) (plus (reg A) 1))


My first thoughts on a solution were to use reg_overlap_mentioned_p
to ensure that register "target" is mentioned in "op1".  However,
although we're sure that target isn't a MEM at this point, we're not
certain it's a register.  However thinking about forcing things to
be registers revealed the real problem above, that we should be
forcing op1 into a register, rather than performing the addition
twice.  If target, op0 and op1 are all registers (or op0/op1 are
constants), is impossible to clobber op1 with an assignment to
target in this part of the code.


The following patch has been tested on i686-pc-linux-gnu with a full
"make bootstrap", all default languages, and regression tested with a
top-level "make -k check" with no new failures.

Committed to mainline CVS.



2004-12-18  Roger Sayle  <roger@eyesopen.com>

	PR middle-end/18548
	* expr.c (expand_expr_real_1) <MAX_EXPR>: Ensure that target, op0
	and op1 are all registers (or constants) before expanding the RTL
	comparison sequence [to avoid reg_overlap_mentioned (target, op1)].

	* gcc.dg/max-1.c: New test case.


Index: expr.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/expr.c,v
retrieving revision 1.760
diff -c -3 -p -r1.760 expr.c
*** expr.c	12 Dec 2004 21:12:43 -0000	1.760
--- expr.c	18 Dec 2004 04:48:47 -0000
*************** expand_expr_real_1 (tree exp, rtx target
*** 7671,7677 ****
        /* At this point, a MEM target is no longer useful; we will get better
  	 code without it.  */

!       if (MEM_P (target))
  	target = gen_reg_rtx (mode);

        /* If op1 was placed in target, swap op0 and op1.  */
--- 7671,7677 ----
        /* At this point, a MEM target is no longer useful; we will get better
  	 code without it.  */

!       if (! REG_P (target))
  	target = gen_reg_rtx (mode);

        /* If op1 was placed in target, swap op0 and op1.  */
*************** expand_expr_real_1 (tree exp, rtx target
*** 7682,7687 ****
--- 7682,7692 ----
  	  op1 = tem;
  	}

+       /* We generate better code and avoid problems with op1 mentioning
+ 	 target by forcing op1 into a pseudo if it isn't a constant.  */
+       if (! CONSTANT_P (op1))
+ 	op1 = force_reg (mode, op1);
+
        if (target != op0)
  	emit_move_insn (target, op0);



/* PR middle-end/18548 */
/* Test case reduced by Andrew Pinski <pinskia@physics.uc.edu> */
/* { dg-do run } */
/* { dg-options "-O1 -fno-tree-lrs" } */

extern void abort (void);

long fff[10];

void f(long a, long b)
{
  long crcc = b;
  long d = *((long*)(a+1));
  int i;

  a = d >= b? d:b;


  for(i=0;i<10;i++)
   fff[i] = a;
}

int main(void)
{
  int i;
  long a = 10;
  f((long)(&a)-1,0);
  for(i = 0;i<10;i++)
   if (fff[i]!=10)
    abort ();
  return 0;
}


Roger
--
Roger Sayle,                         E-mail: roger@eyesopen.com
OpenEye Scientific Software,         WWW: http://www.eyesopen.com/
Suite 1107, 3600 Cerrillos Road,     Tel: (+1) 505-473-7385
Santa Fe, New Mexico, 87507.         Fax: (+1) 505-473-0833



More information about the Gcc-patches mailing list