MIN/MAX codegen tweek (regression relative to 3.4)

Jan Hubicka jh@suse.cz
Fri Nov 11 16:51:00 GMT 2005


Hi,
with tree-level MIN/MAX discovery we've lost ability to optimize cmp $1 into
test reg,reg in these cases.  This (quite surprisingly) cause about 2%
regression on VPR benchmark.

The patch looks rather large due to re-indenting.  Only real change is the code
dealing with cmpop1.
Bootstrapped/regtested i686-pc-gnu-linux, OK?

Honza

/* { dg-do compile } */
/* { dg-options "-O2 -march=opteron" } */
/* { dg-final { scan-assembler "test" } } */
/* { dg-final { scan-assembler-not "cmp" } } */
#define max(a,b) (((a) > (b))? (a) : (b))
t(int a)
{
  return (max(a,1));
}
/* { dg-do compile } */
/* { dg-options "-O2" } */
/* { dg-final { scan-assembler "test" } } */
/* { dg-final { scan-assembler-not "cmp" } } */
#define max(a,b) (((a) > (b))? (a) : (b))
t(unsigned int a)
{
  return (max(a,1));
}
2005-11-11  Jan Hubicka  <jh@suse.cz>
	* expr.c (expand_expr_real_1): Be more curefull to arrange cmp 0 on
	MIN/MAX exprs.
Index: expr.c
===================================================================
-cp -L expr.c	(revision 106319) -L expr.c	(working copy) .svn/text-base/expr.c.svn-base expr.c
*** expr.c	(revision 106319)
--- expr.c	(working copy)
*************** expand_expr_real_1 (tree exp, rtx target
*** 8020,8088 ****
        if (! CONSTANT_P (op1))
  	op1 = force_reg (mode, op1);
  
  #ifdef HAVE_conditional_move
!       /* Use a conditional move if possible.  */
!       if (can_conditionally_move_p (mode))
! 	{
! 	  enum rtx_code comparison_code;
! 	  rtx insn;
  
! 	  if (code == MAX_EXPR)
! 	    comparison_code = unsignedp ? GEU : GE;
! 	  else
! 	    comparison_code = unsignedp ? LEU : LE;
! 
! 	  /* ??? Same problem as in expmed.c: emit_conditional_move
! 	     forces a stack adjustment via compare_from_rtx, and we
! 	     lose the stack adjustment if the sequence we are about
! 	     to create is discarded.  */
! 	  do_pending_stack_adjust ();
! 
! 	  start_sequence ();
! 
! 	  /* Try to emit the conditional move.  */
! 	  insn = emit_conditional_move (target, comparison_code,
! 					op0, op1, mode,
! 					op0, op1, mode,
! 					unsignedp);
! 
! 	  /* If we could do the conditional move, emit the sequence,
! 	     and return.  */
! 	  if (insn)
! 	    {
! 	      rtx seq = get_insns ();
! 	      end_sequence ();
! 	      emit_insn (seq);
! 	      return target;
! 	    }
  
! 	  /* Otherwise discard the sequence and fall back to code with
! 	     branches.  */
! 	  end_sequence ();
! 	}
  #endif
!       if (target != op0)
! 	emit_move_insn (target, op0);
  
!       temp = gen_label_rtx ();
  
!       /* If this mode is an integer too wide to compare properly,
! 	 compare word by word.  Rely on cse to optimize constant cases.  */
!       if (GET_MODE_CLASS (mode) == MODE_INT
! 	  && ! can_compare_p (GE, mode, ccp_jump))
! 	{
! 	  if (code == MAX_EXPR)
! 	    do_jump_by_parts_greater_rtx (mode, unsignedp, target, op1,
! 					  NULL_RTX, temp);
! 	  else
! 	    do_jump_by_parts_greater_rtx (mode, unsignedp, op1, target,
! 					  NULL_RTX, temp);
! 	}
!       else
! 	{
! 	  do_compare_rtx_and_jump (target, op1, code == MAX_EXPR ? GE : LE,
! 				   unsignedp, mode, NULL_RTX, NULL_RTX, temp);
! 	}
        emit_move_insn (target, op1);
        emit_label (temp);
        return target;
--- 8020,8111 ----
        if (! CONSTANT_P (op1))
  	op1 = force_reg (mode, op1);
  
+       {
+ 	enum rtx_code comparison_code;
+ 	rtx cmpop1 = op1;
+ 
+ 	if (code == MAX_EXPR)
+ 	  comparison_code = unsignedp ? GEU : GE;
+ 	else
+ 	  comparison_code = unsignedp ? LEU : LE;
+ 
+ 	/* Canonicalize to comparsions against 0.  */
+ 	if (op1 == const1_rtx)
+ 	  {
+ 	    /* Converting (a >= 1 ? a : 1) into (a > 0 ? a : 1)
+ 	       or (a != 0 ? a : 1) for unsigned.
+ 	       For MIN we are safe converting (a <= 1 ? a : 1)
+ 	       into (a <= 0 ? a : 1)  */
+ 	    cmpop1 = const0_rtx;
+ 	    if (code == MAX_EXPR)
+ 	      comparison_code = unsignedp ? NE : GT;
+ 	  }
+ 	if (op1 == constm1_rtx && !unsignedp)
+ 	  {
+ 	    /* Converting (a >= -1 ? a : -1) into (a >= 0 ? a : -1)
+ 	       and (a <= -1 ? a : -1) into (a < 0 ? a : -1) */
+ 	    cmpop1 = const0_rtx;
+ 	    if (code == MIN_EXPR)
+ 	      comparison_code = LT;
+ 	  }
  #ifdef HAVE_conditional_move
! 	/* Use a conditional move if possible.  */
! 	if (can_conditionally_move_p (mode))
! 	  {
! 	    rtx insn;
  
! 	    /* ??? Same problem as in expmed.c: emit_conditional_move
! 	       forces a stack adjustment via compare_from_rtx, and we
! 	       lose the stack adjustment if the sequence we are about
! 	       to create is discarded.  */
! 	    do_pending_stack_adjust ();
  
! 	    start_sequence ();
! 
! 	    /* Try to emit the conditional move.  */
! 	    insn = emit_conditional_move (target, comparison_code,
! 					  op0, cmpop1, mode,
! 					  op0, op1, mode,
! 					  unsignedp);
! 
! 	    /* If we could do the conditional move, emit the sequence,
! 	       and return.  */
! 	    if (insn)
! 	      {
! 		rtx seq = get_insns ();
! 		end_sequence ();
! 		emit_insn (seq);
! 		return target;
! 	      }
! 
! 	    /* Otherwise discard the sequence and fall back to code with
! 	       branches.  */
! 	    end_sequence ();
! 	  }
  #endif
! 	if (target != op0)
! 	  emit_move_insn (target, op0);
  
! 	temp = gen_label_rtx ();
  
! 	/* If this mode is an integer too wide to compare properly,
! 	   compare word by word.  Rely on cse to optimize constant cases.  */
! 	if (GET_MODE_CLASS (mode) == MODE_INT
! 	    && ! can_compare_p (GE, mode, ccp_jump))
! 	  {
! 	    if (code == MAX_EXPR)
! 	      do_jump_by_parts_greater_rtx (mode, unsignedp, target, op1,
! 					    NULL_RTX, temp);
! 	    else
! 	      do_jump_by_parts_greater_rtx (mode, unsignedp, op1, target,
! 					    NULL_RTX, temp);
! 	  }
! 	else
! 	  {
! 	    do_compare_rtx_and_jump (target, cmpop1, comparison_code,
! 				     unsignedp, mode, NULL_RTX, NULL_RTX, temp);
! 	  }
!       }
        emit_move_insn (target, op1);
        emit_label (temp);
        return target;



More information about the Gcc-patches mailing list