OSDN Git Service

* combine.c (expand_compound_operation) <ZERO_EXTRACT>: Add
[pf3gnuchains/gcc-fork.git] / gcc / cse.c
index 4e35b34..eee2742 100644 (file)
--- a/gcc/cse.c
+++ b/gcc/cse.c
@@ -761,6 +761,57 @@ approx_reg_cost (rtx x)
   return cost;
 }
 
+/* Returns a canonical version of X for the address, from the point of view,
+   that all multiplications are represented as MULT instead of the multiply
+   by a power of 2 being represented as ASHIFT.  */
+
+static rtx
+canon_for_address (rtx x)
+{
+  enum rtx_code code;
+  enum machine_mode mode;
+  rtx new = 0;
+  int i;
+  const char *fmt;
+  
+  if (!x)
+    return x;
+  
+  code = GET_CODE (x);
+  mode = GET_MODE (x);
+  
+  switch (code)
+    {
+    case ASHIFT:
+      if (GET_CODE (XEXP (x, 1)) == CONST_INT
+         && INTVAL (XEXP (x, 1)) < GET_MODE_BITSIZE (mode)
+         && INTVAL (XEXP (x, 1)) >= 0)
+        {
+         new = canon_for_address (XEXP (x, 0));
+         new = gen_rtx_MULT (mode, new,
+                             gen_int_mode ((HOST_WIDE_INT) 1
+                                           << INTVAL (XEXP (x, 1)),
+                                           mode));
+       }
+      break;
+    default:
+      break;
+      
+    }
+  if (new)
+    return new;
+  
+  /* Now recursively process each operand of this operation.  */
+  fmt = GET_RTX_FORMAT (code);
+  for (i = 0; i < GET_RTX_LENGTH (code); i++)
+    if (fmt[i] == 'e')
+      {
+       new = canon_for_address (XEXP (x, i));
+       XEXP (x, i) = new;
+      }
+  return x;
+}
+
 /* Return a negative value if an rtx A, whose costs are given by COST_A
    and REGCOST_A, is more desirable than an rtx B.
    Return a positive value if A is less desirable, or 0 if the two are
@@ -2933,6 +2984,11 @@ find_best_addr (rtx insn, rtx *loc, enum machine_mode mode)
                rtx new = simplify_gen_binary (GET_CODE (*loc), Pmode,
                                               p->exp, op1);
                int new_cost;
+               
+               /* Get the canonical version of the address so we can accept
+                  more. */
+               new = canon_for_address (new);
+               
                new_cost = address_cost (new, mode);
 
                if (new_cost < best_addr_cost
@@ -3809,6 +3865,10 @@ fold_rtx (rtx x, rtx insn)
         constant, set CONST_ARG0 and CONST_ARG1 appropriately.  We needn't
         do anything if both operands are already known to be constant.  */
 
+      /* ??? Vector mode comparisons are not supported yet.  */
+      if (VECTOR_MODE_P (mode))
+       break;
+
       if (const_arg0 == 0 || const_arg1 == 0)
        {
          struct table_elt *p0, *p1;
@@ -4335,6 +4395,18 @@ record_jump_equiv (rtx insn, int taken)
   record_jump_cond (code, mode, op0, op1, reversed_nonequality);
 }
 
+/* Yet another form of subreg creation.  In this case, we want something in
+   MODE, and we should assume OP has MODE iff it is naturally modeless.  */
+
+static rtx
+record_jump_cond_subreg (enum machine_mode mode, rtx op)
+{
+  enum machine_mode op_mode = GET_MODE (op);
+  if (op_mode == mode || op_mode == VOIDmode)
+    return op;
+  return lowpart_subreg (mode, op, op_mode);
+}
+
 /* We know that comparison CODE applied to OP0 and OP1 in MODE is true.
    REVERSED_NONEQUALITY is nonzero if CODE had to be swapped.
    Make any useful entries we can with that information.  Called from
@@ -4359,11 +4431,10 @@ record_jump_cond (enum rtx_code code, enum machine_mode mode, rtx op0,
          > GET_MODE_SIZE (GET_MODE (SUBREG_REG (op0)))))
     {
       enum machine_mode inner_mode = GET_MODE (SUBREG_REG (op0));
-      rtx tem = gen_lowpart (inner_mode, op1);
-
-      record_jump_cond (code, mode, SUBREG_REG (op0),
-                       tem ? tem : gen_rtx_SUBREG (inner_mode, op1, 0),
-                       reversed_nonequality);
+      rtx tem = record_jump_cond_subreg (inner_mode, op1);
+      if (tem)
+       record_jump_cond (code, mode, SUBREG_REG (op0), tem,
+                         reversed_nonequality);
     }
 
   if (code == EQ && GET_CODE (op1) == SUBREG
@@ -4371,11 +4442,10 @@ record_jump_cond (enum rtx_code code, enum machine_mode mode, rtx op0,
          > GET_MODE_SIZE (GET_MODE (SUBREG_REG (op1)))))
     {
       enum machine_mode inner_mode = GET_MODE (SUBREG_REG (op1));
-      rtx tem = gen_lowpart (inner_mode, op0);
-
-      record_jump_cond (code, mode, SUBREG_REG (op1),
-                       tem ? tem : gen_rtx_SUBREG (inner_mode, op0, 0),
-                       reversed_nonequality);
+      rtx tem = record_jump_cond_subreg (inner_mode, op0);
+      if (tem)
+       record_jump_cond (code, mode, SUBREG_REG (op1), tem,
+                         reversed_nonequality);
     }
 
   /* Similarly, if this is an NE comparison, and either is a SUBREG
@@ -4391,11 +4461,10 @@ record_jump_cond (enum rtx_code code, enum machine_mode mode, rtx op0,
          < GET_MODE_SIZE (GET_MODE (SUBREG_REG (op0)))))
     {
       enum machine_mode inner_mode = GET_MODE (SUBREG_REG (op0));
-      rtx tem = gen_lowpart (inner_mode, op1);
-
-      record_jump_cond (code, mode, SUBREG_REG (op0),
-                       tem ? tem : gen_rtx_SUBREG (inner_mode, op1, 0),
-                       reversed_nonequality);
+      rtx tem = record_jump_cond_subreg (inner_mode, op1);
+      if (tem)
+       record_jump_cond (code, mode, SUBREG_REG (op0), tem,
+                         reversed_nonequality);
     }
 
   if (code == NE && GET_CODE (op1) == SUBREG
@@ -4404,11 +4473,10 @@ record_jump_cond (enum rtx_code code, enum machine_mode mode, rtx op0,
          < GET_MODE_SIZE (GET_MODE (SUBREG_REG (op1)))))
     {
       enum machine_mode inner_mode = GET_MODE (SUBREG_REG (op1));
-      rtx tem = gen_lowpart (inner_mode, op0);
-
-      record_jump_cond (code, mode, SUBREG_REG (op1),
-                       tem ? tem : gen_rtx_SUBREG (inner_mode, op0, 0),
-                       reversed_nonequality);
+      rtx tem = record_jump_cond_subreg (inner_mode, op0);
+      if (tem)
+       record_jump_cond (code, mode, SUBREG_REG (op1), tem,
+                         reversed_nonequality);
     }
 
   /* Hash both operands.  */
@@ -4797,7 +4865,7 @@ cse_insn (rtx insn, rtx libcall_insn)
       else
        SET_SRC (sets[i].rtl) = new;
 
-      if (GET_CODE (dest) == ZERO_EXTRACT || GET_CODE (dest) == SIGN_EXTRACT)
+      if (GET_CODE (dest) == ZERO_EXTRACT)
        {
          validate_change (insn, &XEXP (dest, 1),
                           canon_reg (XEXP (dest, 1), insn), 1);
@@ -4805,9 +4873,9 @@ cse_insn (rtx insn, rtx libcall_insn)
                           canon_reg (XEXP (dest, 2), insn), 1);
        }
 
-      while (GET_CODE (dest) == SUBREG || GET_CODE (dest) == STRICT_LOW_PART
+      while (GET_CODE (dest) == SUBREG
             || GET_CODE (dest) == ZERO_EXTRACT
-            || GET_CODE (dest) == SIGN_EXTRACT)
+            || GET_CODE (dest) == STRICT_LOW_PART)
        dest = XEXP (dest, 0);
 
       if (MEM_P (dest))
@@ -4904,8 +4972,7 @@ cse_insn (rtx insn, rtx libcall_insn)
         causes later instructions to be mis-optimized.  */
       /* If storing a constant in a bitfield, pre-truncate the constant
         so we will be able to record it later.  */
-      if (GET_CODE (SET_DEST (sets[i].rtl)) == ZERO_EXTRACT
-         || GET_CODE (SET_DEST (sets[i].rtl)) == SIGN_EXTRACT)
+      if (GET_CODE (SET_DEST (sets[i].rtl)) == ZERO_EXTRACT)
        {
          rtx width = XEXP (SET_DEST (sets[i].rtl), 1);
 
@@ -5561,11 +5628,9 @@ cse_insn (rtx insn, rtx libcall_insn)
       /* Now deal with the destination.  */
       do_not_record = 0;
 
-      /* Look within any SIGN_EXTRACT or ZERO_EXTRACT
-        to the MEM or REG within it.  */
-      while (GET_CODE (dest) == SIGN_EXTRACT
+      /* Look within any ZERO_EXTRACT to the MEM or REG within it.  */
+      while (GET_CODE (dest) == SUBREG
             || GET_CODE (dest) == ZERO_EXTRACT
-            || GET_CODE (dest) == SUBREG
             || GET_CODE (dest) == STRICT_LOW_PART)
        dest = XEXP (dest, 0);
 
@@ -5593,8 +5658,7 @@ cse_insn (rtx insn, rtx libcall_insn)
         because the value in it after the store
         may not equal what was stored, due to truncation.  */
 
-      if (GET_CODE (SET_DEST (sets[i].rtl)) == ZERO_EXTRACT
-         || GET_CODE (SET_DEST (sets[i].rtl)) == SIGN_EXTRACT)
+      if (GET_CODE (SET_DEST (sets[i].rtl)) == ZERO_EXTRACT)
        {
          rtx width = XEXP (SET_DEST (sets[i].rtl), 1);