[PATCH] New subroutine of expand_expr: expand_operands.

Roger Sayle roger@eyesopen.com
Sat Sep 6 18:26:00 GMT 2003


This patch is a clean-up of the middle-end's RTL expansion machinery.
It factors all of the places where we recursively expand both operands
of a binary operator into a single function.  The immediate benefit,
other than the reduction in source code, is that now all operators
(not just some classes of addition and multiplication) get the equal
operands optimization, where we only expand the RTL once for identical
subexpressions without side-effects (using operand_equal_p).

However, the major benefit is that this now provides a single location
to place logic to decide the order in which to evaluate these operands.
By evaluating the operand that requires the most live pseudos first,
it should be possible to reduce register pressure for later passes.


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

Ok for mainline?


2003-09-06  Roger Sayle  <roger@eyesopen.com>

	* expr.c (expand_operands): New function to expand an operand pair.
	(expand_expr): Call expand_operands whenever we need to expand both
	operands of a binary operator.
	(do_store_flag): Likewise for operands of comparison operations.


Index: expr.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/expr.c,v
retrieving revision 1.582
diff -c -3 -p -r1.582 expr.c
*** expr.c	4 Sep 2003 03:17:46 -0000	1.582
--- expr.c	6 Sep 2003 14:22:50 -0000
*************** static unsigned HOST_WIDE_INT highest_po
*** 164,169 ****
--- 164,171 ----

  static int is_aligning_offset (tree, tree);
  static rtx expand_increment (tree, int, int);
+ static void expand_operands (tree, tree, rtx, rtx*, rtx*,
+ 			     enum expand_modifier);
  static rtx do_store_flag (tree, rtx, enum machine_mode, int);
  #ifdef PUSH_ROUNDING
  static void emit_single_push_insn (enum machine_mode, rtx, tree);
*************** find_placeholder (tree exp, tree *plist)
*** 6523,6528 ****
--- 6525,6554 ----

    return 0;
  }
+
+ /* Subroutine of expand_expr.  Expand the two operands of a binary
+    expression EXP0 and EXP1 placing the results in OP0 and OP1.
+    The value may be stored in TARGET if TARGET is nonzero.  The
+    MODIFIER argument is as documented by expand_expr.  */
+
+ static void
+ expand_operands (tree exp0, tree exp1, rtx target, rtx *op0, rtx *op1,
+ 		 enum expand_modifier modifier)
+ {
+   if (! safe_from_p (target, exp1, 1))
+     target = 0;
+   if (operand_equal_p (exp0, exp1, 0))
+     {
+       *op0 = expand_expr (exp0, target, VOIDmode, modifier);
+       *op1 = copy_rtx (*op0);
+     }
+   else
+     {
+       *op0 = expand_expr (exp0, target, VOIDmode, modifier);
+       *op1 = expand_expr (exp1, NULL_RTX, VOIDmode, modifier);
+     }
+ }
+

  /* expand_expr: generate code for computing expression EXP.
     An rtx for the computed value is returned.  The value is never null.
*************** find_placeholder (tree exp, tree *plist)
*** 6567,6573 ****
     emit_block_move will be flagged with BLOCK_OP_CALL_PARM.  */

  rtx
! expand_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier modifier)
  {
    rtx op0, op1, temp;
    tree type = TREE_TYPE (exp);
--- 6593,6600 ----
     emit_block_move will be flagged with BLOCK_OP_CALL_PARM.  */

  rtx
! expand_expr (tree exp, rtx target, enum machine_mode tmode,
! 	     enum expand_modifier modifier)
  {
    rtx op0, op1, temp;
    tree type = TREE_TYPE (exp);
*************** expand_expr (tree exp, rtx target, enum
*** 8141,8152 ****
        if ((modifier != EXPAND_SUM && modifier != EXPAND_INITIALIZER)
  	  || mode != ptr_mode)
  	{
! 	  op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0);
! 	  if (! operand_equal_p (TREE_OPERAND (exp, 0),
! 				 TREE_OPERAND (exp, 1), 0))
! 	    op1 = expand_expr (TREE_OPERAND (exp, 1), NULL_RTX, VOIDmode, 0);
! 	  else
! 	    op1 = op0;
  	  if (op0 == const0_rtx)
  	    return op1;
  	  if (op1 == const0_rtx)
--- 8168,8175 ----
        if ((modifier != EXPAND_SUM && modifier != EXPAND_INITIALIZER)
  	  || mode != ptr_mode)
  	{
! 	  expand_operands (TREE_OPERAND (exp, 0), TREE_OPERAND (exp, 1),
! 			   subtarget, &op0, &op1, 0);
  	  if (op0 == const0_rtx)
  	    return op1;
  	  if (op1 == const0_rtx)
*************** expand_expr (tree exp, rtx target, enum
*** 8154,8166 ****
  	  goto binop2;
  	}

!       op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, modifier);
!       if (! operand_equal_p (TREE_OPERAND (exp, 0),
! 			     TREE_OPERAND (exp, 1), 0))
! 	op1 = expand_expr (TREE_OPERAND (exp, 1), NULL_RTX,
! 			   VOIDmode, modifier);
!       else
! 	op1 = op0;
        return simplify_gen_binary (PLUS, mode, op0, op1);

      case MINUS_EXPR:
--- 8177,8184 ----
  	  goto binop2;
  	}

!       expand_operands (TREE_OPERAND (exp, 0), TREE_OPERAND (exp, 1),
! 		       subtarget, &op0, &op1, modifier);
        return simplify_gen_binary (PLUS, mode, op0, op1);

      case MINUS_EXPR:
*************** expand_expr (tree exp, rtx target, enum
*** 8173,8182 ****
  	  && really_constant_p (TREE_OPERAND (exp, 0))
  	  && really_constant_p (TREE_OPERAND (exp, 1)))
  	{
! 	  rtx op0 = expand_expr (TREE_OPERAND (exp, 0), NULL_RTX, VOIDmode,
! 				 modifier);
! 	  rtx op1 = expand_expr (TREE_OPERAND (exp, 1), NULL_RTX, VOIDmode,
! 				 modifier);

  	  /* If the last operand is a CONST_INT, use plus_constant of
  	     the negated constant.  Else make the MINUS.  */
--- 8191,8198 ----
  	  && really_constant_p (TREE_OPERAND (exp, 0))
  	  && really_constant_p (TREE_OPERAND (exp, 1)))
  	{
! 	  expand_operands (TREE_OPERAND (exp, 0), TREE_OPERAND (exp, 1),
! 			   NULL_RTX, &op0, &op1, modifier);

  	  /* If the last operand is a CONST_INT, use plus_constant of
  	     the negated constant.  Else make the MINUS.  */
*************** expand_expr (tree exp, rtx target, enum
*** 8198,8208 ****
  	  || mode != ptr_mode)
  	goto binop;

!       if (! safe_from_p (subtarget, TREE_OPERAND (exp, 1), 1))
! 	subtarget = 0;
!
!       op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, modifier);
!       op1 = expand_expr (TREE_OPERAND (exp, 1), NULL_RTX, VOIDmode, modifier);

        /* Convert A - const to A + (-const).  */
        if (GET_CODE (op1) == CONST_INT)
--- 8214,8221 ----
  	  || mode != ptr_mode)
  	goto binop;

!       expand_operands (TREE_OPERAND (exp, 0), TREE_OPERAND (exp, 1),
! 		       subtarget, &op0, &op1, modifier);

        /* Convert A - const to A + (-const).  */
        if (GET_CODE (op1) == CONST_INT)
*************** expand_expr (tree exp, rtx target, enum
*** 8297,8310 ****
  	    {
  	      if (this_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
  		{
- 		  op0 = expand_expr (TREE_OPERAND (TREE_OPERAND (exp, 0), 0),
- 				     NULL_RTX, VOIDmode, 0);
  		  if (TREE_CODE (TREE_OPERAND (exp, 1)) == INTEGER_CST)
! 		    op1 = expand_expr (TREE_OPERAND (exp, 1), NULL_RTX,
! 				       VOIDmode, 0);
  		  else
! 		    op1 = expand_expr (TREE_OPERAND (TREE_OPERAND (exp, 1), 0),
! 				       NULL_RTX, VOIDmode, 0);
  		  goto binop2;
  		}
  	      else if (other_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing
--- 8310,8323 ----
  	    {
  	      if (this_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
  		{
  		  if (TREE_CODE (TREE_OPERAND (exp, 1)) == INTEGER_CST)
! 		    expand_operands (TREE_OPERAND (TREE_OPERAND (exp, 0), 0),
! 				     TREE_OPERAND (exp, 1),
! 				     NULL_RTX, &op0, &op1, 0);
  		  else
! 		    expand_operands (TREE_OPERAND (TREE_OPERAND (exp, 0), 0),
! 				     TREE_OPERAND (TREE_OPERAND (exp, 1), 0),
! 				     NULL_RTX, &op0, &op1, 0);
  		  goto binop2;
  		}
  	      else if (other_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing
*************** expand_expr (tree exp, rtx target, enum
*** 8333,8344 ****
  		}
  	    }
  	}
!       op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0);
!       if (! operand_equal_p (TREE_OPERAND (exp, 0),
! 			     TREE_OPERAND (exp, 1), 0))
! 	op1 = expand_expr (TREE_OPERAND (exp, 1), NULL_RTX, VOIDmode, 0);
!       else
! 	op1 = op0;
        return expand_mult (mode, op0, op1, target, unsignedp);

      case TRUNC_DIV_EXPR:
--- 8346,8353 ----
  		}
  	    }
  	}
!       expand_operands (TREE_OPERAND (exp, 0), TREE_OPERAND (exp, 1),
! 		       subtarget, &op0, &op1, 0);
        return expand_mult (mode, op0, op1, target, unsignedp);

      case TRUNC_DIV_EXPR:
*************** expand_expr (tree exp, rtx target, enum
*** 8346,8360 ****
      case CEIL_DIV_EXPR:
      case ROUND_DIV_EXPR:
      case EXACT_DIV_EXPR:
-       if (! safe_from_p (subtarget, TREE_OPERAND (exp, 1), 1))
- 	subtarget = 0;
        if (modifier == EXPAND_STACK_PARM)
  	target = 0;
        /* Possible optimization: compute the dividend with EXPAND_SUM
  	 then if the divisor is constant can optimize the case
  	 where some terms of the dividend have coeffs divisible by it.  */
!       op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0);
!       op1 = expand_expr (TREE_OPERAND (exp, 1), NULL_RTX, VOIDmode, 0);
        return expand_divmod (0, code, mode, op0, op1, target, unsignedp);

      case RDIV_EXPR:
--- 8355,8367 ----
      case CEIL_DIV_EXPR:
      case ROUND_DIV_EXPR:
      case EXACT_DIV_EXPR:
        if (modifier == EXPAND_STACK_PARM)
  	target = 0;
        /* Possible optimization: compute the dividend with EXPAND_SUM
  	 then if the divisor is constant can optimize the case
  	 where some terms of the dividend have coeffs divisible by it.  */
!       expand_operands (TREE_OPERAND (exp, 0), TREE_OPERAND (exp, 1),
! 		       subtarget, &op0, &op1, 0);
        return expand_divmod (0, code, mode, op0, op1, target, unsignedp);

      case RDIV_EXPR:
*************** expand_expr (tree exp, rtx target, enum
*** 8376,8387 ****
      case FLOOR_MOD_EXPR:
      case CEIL_MOD_EXPR:
      case ROUND_MOD_EXPR:
-       if (! safe_from_p (subtarget, TREE_OPERAND (exp, 1), 1))
- 	subtarget = 0;
        if (modifier == EXPAND_STACK_PARM)
  	target = 0;
!       op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0);
!       op1 = expand_expr (TREE_OPERAND (exp, 1), NULL_RTX, VOIDmode, 0);
        return expand_divmod (1, code, mode, op0, op1, target, unsignedp);

      case FIX_ROUND_EXPR:
--- 8383,8392 ----
      case FLOOR_MOD_EXPR:
      case CEIL_MOD_EXPR:
      case ROUND_MOD_EXPR:
        if (modifier == EXPAND_STACK_PARM)
  	target = 0;
!       expand_operands (TREE_OPERAND (exp, 0), TREE_OPERAND (exp, 1),
! 		       subtarget, &op0, &op1, 0);
        return expand_divmod (1, code, mode, op0, op1, target, unsignedp);

      case FIX_ROUND_EXPR:
*************** expand_expr (tree exp, rtx target, enum
*** 8450,8457 ****
  	  || (GET_CODE (target) == REG
  	      && REGNO (target) < FIRST_PSEUDO_REGISTER))
  	target = gen_reg_rtx (mode);
!       op1 = expand_expr (TREE_OPERAND (exp, 1), NULL_RTX, VOIDmode, 0);
!       op0 = expand_expr (TREE_OPERAND (exp, 0), target, VOIDmode, 0);

        /* First try to do it with a special MIN or MAX instruction.
  	 If that does not win, use a conditional jump to select the proper
--- 8455,8462 ----
  	  || (GET_CODE (target) == REG
  	      && REGNO (target) < FIRST_PSEUDO_REGISTER))
  	target = gen_reg_rtx (mode);
!       expand_operands (TREE_OPERAND (exp, 0), TREE_OPERAND (exp, 1),
! 		       target, &op0, &op1, 0);

        /* First try to do it with a special MIN or MAX instruction.
  	 If that does not win, use a conditional jump to select the proper
*************** expand_expr (tree exp, rtx target, enum
*** 9506,9515 ****
    /* Here to do an ordinary binary operator, generating an instruction
       from the optab already placed in `this_optab'.  */
   binop:
!   if (! safe_from_p (subtarget, TREE_OPERAND (exp, 1), 1))
!     subtarget = 0;
!   op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0);
!   op1 = expand_expr (TREE_OPERAND (exp, 1), NULL_RTX, VOIDmode, 0);
   binop2:
    if (modifier == EXPAND_STACK_PARM)
      target = 0;
--- 9511,9518 ----
    /* Here to do an ordinary binary operator, generating an instruction
       from the optab already placed in `this_optab'.  */
   binop:
!   expand_operands (TREE_OPERAND (exp, 0), TREE_OPERAND (exp, 1),
! 		   subtarget, &op0, &op1, 0);
   binop2:
    if (modifier == EXPAND_STACK_PARM)
      target = 0;
*************** do_store_flag (tree exp, rtx target, enu
*** 10008,10015 ****
        || ! safe_from_p (subtarget, arg1, 1))
      subtarget = 0;

!   op0 = expand_expr (arg0, subtarget, VOIDmode, 0);
!   op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);

    if (target == 0)
      target = gen_reg_rtx (mode);
--- 10011,10017 ----
        || ! safe_from_p (subtarget, arg1, 1))
      subtarget = 0;

!   expand_operands (arg0, arg1, subtarget, &op0, &op1, 0);

    if (target == 0)
      target = gen_reg_rtx (mode);


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