From e3c8ea672563a4f8762b60f302a0a13c788405f7 Mon Sep 17 00:00:00 2001
From: Richard Henderson <rth@redhat.com>
Date: Thu, 21 Feb 2002 15:06:16 -0800
Subject: [PATCH] emit-rtl.c (offset_address): Use simplify_gen_binary rather
 than gen_rtx_PLUS to form the sum.

        * emit-rtl.c (offset_address): Use simplify_gen_binary rather
        than gen_rtx_PLUS to form the sum.
        * explow.c (force_reg): Rearrange to not allocate new pseudo
        when force_operand returns a register.
        * expr.c (expand_assignment): Allow offset_rtx expansion to
        return a sum.  Do not force addresses into registers.
        (expand_expr): Likewise.
        * simplify-rtx.c (simplify_gen_binary): Use simplify_plus_minus
        to canonicalize arithmetic that didn't simpify.
        (simplify_plus_minus): New argument force; update
        all callers.  Don't split CONST unless we can do something with it,
        and wouldn't lose the constness of the operands.

        * config/i386/i386.c (legitimize_pic_address): Recognize UNSPECs
        that we generated earlier.

From-SVN: r49945
---
 gcc/ChangeLog          | 18 ++++++++++++
 gcc/config/i386/i386.c | 14 ++++++----
 gcc/emit-rtl.c         | 23 +++++++++++++--
 gcc/explow.c           | 24 ++++++++++++----
 gcc/expr.c             | 24 +++-------------
 gcc/simplify-rtx.c     | 63 +++++++++++++++++++++++++++---------------
 6 files changed, 109 insertions(+), 57 deletions(-)

diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index c7878d70e65f..8a8dcac21e70 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,21 @@
+2002-02-21  Richard Henderson  <rth@redhat.com>
+
+	* emit-rtl.c (offset_address): Use simplify_gen_binary rather
+	than gen_rtx_PLUS to form the sum.
+	* explow.c (force_reg): Rearrange to not allocate new pseudo
+	when force_operand returns a register.
+	* expr.c (expand_assignment): Allow offset_rtx expansion to
+	return a sum.  Do not force addresses into registers.
+	(expand_expr): Likewise.
+	* simplify-rtx.c (simplify_gen_binary): Use simplify_plus_minus
+	to canonicalize arithmetic that didn't simpify.
+	(simplify_plus_minus): New argument force; update
+	all callers.  Don't split CONST unless we can do something with it,
+	and wouldn't lose the constness of the operands.
+
+	* config/i386/i386.c (legitimize_pic_address): Recognize UNSPECs
+	that we generated earlier.
+
 2002-02-21  Tom Tromey  <tromey@redhat.com>
 
 	* dwarf2out.c (DWARF_LINE_MIN_INSTR_LENGTH): Removed.
diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
index fd84c07239eb..009b5d8511bc 100644
--- a/gcc/config/i386/i386.c
+++ b/gcc/config/i386/i386.c
@@ -4986,11 +4986,15 @@ legitimize_pic_address (orig, reg)
       if (GET_CODE (addr) == CONST)
 	{
 	  addr = XEXP (addr, 0);
-	  if (GET_CODE (addr) == UNSPEC)
-	    {
-	      /* Check that the unspec is one of the ones we generate?  */
-	    }
-	  else if (GET_CODE (addr) != PLUS)
+
+	  /* We must match stuff we generate before.  Assume the only
+	     unspecs that can get here are ours.  Not that we could do
+	     anything with them anyway...  */
+	  if (GET_CODE (addr) == UNSPEC
+	      || (GET_CODE (addr) == PLUS
+		  && GET_CODE (XEXP (addr, 0)) == UNSPEC))
+	    return orig;
+	  if (GET_CODE (addr) != PLUS)
 	    abort ();
 	}
       if (GET_CODE (addr) == PLUS)
diff --git a/gcc/emit-rtl.c b/gcc/emit-rtl.c
index 82dd61a5f64f..836fbf5385ab 100644
--- a/gcc/emit-rtl.c
+++ b/gcc/emit-rtl.c
@@ -2047,9 +2047,26 @@ offset_address (memref, offset, pow2)
      rtx offset;
      HOST_WIDE_INT pow2;
 {
-  rtx new = change_address_1 (memref, VOIDmode,
-			      gen_rtx_PLUS (Pmode, XEXP (memref, 0),
-					    force_reg (Pmode, offset)), 1);
+  rtx new, addr = XEXP (memref, 0);
+
+  new = simplify_gen_binary (PLUS, Pmode, addr, offset);
+
+  /* At this point we don't know _why_ the address is invalid.  It 
+     could have secondary memory refereces, multiplies or anything.
+
+     However, if we did go and rearrange things, we can wind up not
+     being able to recognize the magic around pic_offset_table_rtx.
+     This stuff is fragile, and is yet another example of why it is
+     bad to expose PIC machinery too early.  */
+  if (! memory_address_p (GET_MODE (memref), new)
+      && GET_CODE (addr) == PLUS
+      && XEXP (addr, 0) == pic_offset_table_rtx)
+    {
+      addr = force_reg (GET_MODE (addr), addr);
+      new = simplify_gen_binary (PLUS, Pmode, addr, offset);
+    }
+
+  new = change_address_1 (memref, VOIDmode, new, 1);
 
   /* Update the alignment to reflect the offset.  Reset the offset, which
      we don't know.  */
diff --git a/gcc/explow.c b/gcc/explow.c
index a72a03be64c7..7a770ee897cf 100644
--- a/gcc/explow.c
+++ b/gcc/explow.c
@@ -732,12 +732,23 @@ force_reg (mode, x)
   if (GET_CODE (x) == REG)
     return x;
 
-  temp = gen_reg_rtx (mode);
-
-  if (! general_operand (x, mode))
-    x = force_operand (x, NULL_RTX);
-
-  insn = emit_move_insn (temp, x);
+  if (general_operand (x, mode))
+    {
+      temp = gen_reg_rtx (mode);
+      insn = emit_move_insn (temp, x);
+    }
+  else
+    {
+      temp = force_operand (x, NULL_RTX);
+      if (GET_CODE (temp) == REG)
+	insn = get_last_insn ();
+      else
+	{
+	  rtx temp2 = gen_reg_rtx (mode);
+	  insn = emit_move_insn (temp2, temp);
+	  temp = temp2;
+	}
+    }
 
   /* Let optimizers know that TEMP's value never changes
      and that X can be substituted for it.  Don't get confused
@@ -746,6 +757,7 @@ force_reg (mode, x)
       && (set = single_set (insn)) != 0
       && SET_DEST (set) == temp)
     set_unique_reg_note (insn, REG_EQUAL, x);
+
   return temp;
 }
 
diff --git a/gcc/expr.c b/gcc/expr.c
index a903b14ebb9b..b7304350b7f6 100644
--- a/gcc/expr.c
+++ b/gcc/expr.c
@@ -3659,7 +3659,7 @@ expand_assignment (to, from, want_value, suggest_reg)
 
       if (offset != 0)
 	{
-	  rtx offset_rtx = expand_expr (offset, NULL_RTX, VOIDmode, 0);
+	  rtx offset_rtx = expand_expr (offset, NULL_RTX, VOIDmode, EXPAND_SUM);
 
 	  if (GET_CODE (to_rtx) != MEM)
 	    abort ();
@@ -3682,15 +3682,7 @@ expand_assignment (to, from, want_value, suggest_reg)
 	      && (bitsize % GET_MODE_ALIGNMENT (mode1)) == 0
 	      && MEM_ALIGN (to_rtx) == GET_MODE_ALIGNMENT (mode1))
 	    {
-	      rtx temp
-		= adjust_address (to_rtx, mode1, bitpos / BITS_PER_UNIT);
-
-	      if (GET_CODE (XEXP (temp, 0)) == REG)
-	        to_rtx = temp;
-	      else
-		to_rtx = (replace_equiv_address
-			  (to_rtx, force_reg (GET_MODE (XEXP (temp, 0)),
-					      XEXP (temp, 0))));
+	      to_rtx = adjust_address (to_rtx, mode1, bitpos / BITS_PER_UNIT);
 	      bitpos = 0;
 	    }
 
@@ -6852,7 +6844,7 @@ expand_expr (exp, target, tmode, modifier)
 
 	if (offset != 0)
 	  {
-	    rtx offset_rtx = expand_expr (offset, NULL_RTX, VOIDmode, 0);
+	    rtx offset_rtx = expand_expr (offset, NULL_RTX, VOIDmode, EXPAND_SUM);
 
 	    /* If this object is in a register, put it into memory.
 	       This case can't occur in C, but can in Ada if we have
@@ -6902,15 +6894,7 @@ expand_expr (exp, target, tmode, modifier)
 		&& (bitsize % GET_MODE_ALIGNMENT (mode1)) == 0
 		&& MEM_ALIGN (op0) == GET_MODE_ALIGNMENT (mode1))
 	      {
-		rtx temp = adjust_address (op0, mode1, bitpos / BITS_PER_UNIT);
-
-		if (GET_CODE (XEXP (temp, 0)) == REG)
-		  op0 = temp;
-		else
-		  op0 = (replace_equiv_address
-			 (op0,
-			  force_reg (GET_MODE (XEXP (temp, 0)),
-				     XEXP (temp, 0))));
+		op0 = adjust_address (op0, mode1, bitpos / BITS_PER_UNIT);
 		bitpos = 0;
 	      }
 
diff --git a/gcc/simplify-rtx.c b/gcc/simplify-rtx.c
index 84b8cb240ceb..55cbfc6fbbe3 100644
--- a/gcc/simplify-rtx.c
+++ b/gcc/simplify-rtx.c
@@ -99,7 +99,8 @@ static rtx neg_const_int PARAMS ((enum machine_mode, rtx));
 static int simplify_plus_minus_op_data_cmp PARAMS ((const void *,
 						    const void *));
 static rtx simplify_plus_minus		PARAMS ((enum rtx_code,
-						 enum machine_mode, rtx, rtx));
+						 enum machine_mode, rtx,
+						 rtx, int));
 static void check_fold_consts		PARAMS ((PTR));
 #if ! defined (REAL_IS_NOT_DOUBLE) || defined (REAL_ARITHMETIC)
 static void simplify_unary_real		PARAMS ((PTR));
@@ -137,21 +138,14 @@ simplify_gen_binary (code, mode, op0, op1)
 
   /* If this simplifies, do it.  */
   tem = simplify_binary_operation (code, mode, op0, op1);
-
   if (tem)
     return tem;
 
-  /* Handle addition and subtraction of CONST_INT specially.  Otherwise,
-     just form the operation.  */
+  /* Handle addition and subtraction specially.  Otherwise, just form
+     the operation.  */
 
-  if (GET_CODE (op1) == CONST_INT
-      && GET_MODE (op0) != VOIDmode
-      && (code == PLUS || code == MINUS))
-    {
-      if (code == MINUS)
-	op1 = neg_const_int (mode, op1);
-      return plus_constant (op0, INTVAL (op1));
-    }
+  if (code == PLUS || code == MINUS)
+    return simplify_plus_minus (code, mode, op0, op1, 1);
   else
     return gen_rtx_fmt_ee (code, mode, op0, op1);
 }
@@ -1152,7 +1146,7 @@ simplify_binary_operation (code, mode, op0, op1)
 		      && GET_CODE (XEXP (op0, 0)) == PLUS)
 		  || (GET_CODE (op1) == CONST
 		      && GET_CODE (XEXP (op1, 0)) == PLUS))
-	      && (tem = simplify_plus_minus (code, mode, op0, op1)) != 0)
+	      && (tem = simplify_plus_minus (code, mode, op0, op1, 0)) != 0)
 	    return tem;
 	  break;
 
@@ -1289,7 +1283,7 @@ simplify_binary_operation (code, mode, op0, op1)
 		      && GET_CODE (XEXP (op0, 0)) == PLUS)
 		  || (GET_CODE (op1) == CONST
 		      && GET_CODE (XEXP (op1, 0)) == PLUS))
-	      && (tem = simplify_plus_minus (code, mode, op0, op1)) != 0)
+	      && (tem = simplify_plus_minus (code, mode, op0, op1, 0)) != 0)
 	    return tem;
 
 	  /* Don't let a relocatable value get a negative coeff.  */
@@ -1728,7 +1722,10 @@ simplify_binary_operation (code, mode, op0, op1)
 
    Rather than test for specific case, we do this by a brute-force method
    and do all possible simplifications until no more changes occur.  Then
-   we rebuild the operation.  */
+   we rebuild the operation. 
+
+   If FORCE is true, then always generate the rtx.  This is used to 
+   canonicalize stuff emitted from simplify_gen_binary.  */
 
 struct simplify_plus_minus_op_data
 {
@@ -1749,10 +1746,11 @@ simplify_plus_minus_op_data_cmp (p1, p2)
 }
 
 static rtx
-simplify_plus_minus (code, mode, op0, op1)
+simplify_plus_minus (code, mode, op0, op1, force)
      enum rtx_code code;
      enum machine_mode mode;
      rtx op0, op1;
+     int force;
 {
   struct simplify_plus_minus_op_data ops[8];
   rtx result, tem;
@@ -1786,7 +1784,11 @@ simplify_plus_minus (code, mode, op0, op1)
 	    case PLUS:
 	    case MINUS:
 	      if (n_ops == 7)
-		return 0;
+		{
+		  if (force)
+		    abort ();
+		  return NULL_RTX;
+		}
 
 	      ops[n_ops].op = XEXP (this_op, 1);
 	      ops[n_ops].neg = (this_code == MINUS) ^ this_neg;
@@ -1804,9 +1806,18 @@ simplify_plus_minus (code, mode, op0, op1)
 	      break;
 
 	    case CONST:
-	      ops[i].op = XEXP (this_op, 0);
-	      input_consts++;
-	      changed = 1;
+	      if (n_ops < 7
+		  && GET_CODE (XEXP (this_op, 0)) == PLUS
+		  && CONSTANT_P (XEXP (XEXP (this_op, 0), 0))
+		  && CONSTANT_P (XEXP (XEXP (this_op, 0), 1)))
+		{
+		  ops[i].op = XEXP (XEXP (this_op, 0), 0);
+		  ops[n_ops].op = XEXP (XEXP (this_op, 0), 1);
+		  ops[n_ops].neg = this_neg;
+		  n_ops++;
+		  input_consts++;
+		  changed = 1;
+		}
 	      break;
 
 	    case NOT:
@@ -1838,9 +1849,14 @@ simplify_plus_minus (code, mode, op0, op1)
   while (changed);
 
   /* If we only have two operands, we can't do anything.  */
-  if (n_ops <= 2)
+  if (n_ops <= 2 && !force)
     return NULL_RTX;
 
+  /* Count the number of CONSTs we didn't split above.  */
+  for (i = 0; i < n_ops; i++)
+    if (GET_CODE (ops[i].op) == CONST)
+      input_consts++;
+
   /* Now simplify each pair of operands until nothing changes.  The first
      time through just simplify constants against each other.  */
 
@@ -1941,8 +1957,9 @@ simplify_plus_minus (code, mode, op0, op1)
      sure we count a CONST as two operands.  If we have the same
      number of operands, but have made more CONSTs than before, this
      is also an improvement, so accept it.  */
-  if (n_ops + n_consts > input_ops
-      || (n_ops + n_consts == input_ops && n_consts <= input_consts))
+  if (!force
+      && (n_ops + n_consts > input_ops
+          || (n_ops + n_consts == input_ops && n_consts <= input_consts)))
     return NULL_RTX;
 
   /* Put a non-negated operand first.  If there aren't any, make all
-- 
GitLab