OSDN Git Service

* simplify-rtx.c (simplify_subreg): Fix verification of
[pf3gnuchains/gcc-fork.git] / gcc / combine.c
index 43820b2..d3c70c3 100644 (file)
@@ -1458,7 +1458,7 @@ cant_combine_insn_p (insn)
    Here I1 and I2 appear earlier than I3.
    I1 can be zero; then we combine just I2 into I3.
 
-   It we are combining three insns and the resulting insn is not recognized,
+   If we are combining three insns and the resulting insn is not recognized,
    try splitting it into two insns.  If that happens, I2 and I3 are retained
    and I1 is pseudo-deleted by turning it into a NOTE.  Otherwise, I1 and I2
    are pseudo-deleted.
@@ -3394,7 +3394,16 @@ subst (x, from, to, in_dest, unique_copy)
            }
          else if (fmt[i] == 'e')
            {
-             if (COMBINE_RTX_EQUAL_P (XEXP (x, i), from))
+             /* If this is a register being set, ignore it.  */
+             new = XEXP (x, i);
+             if (in_dest
+                 && (code == SUBREG || code == STRICT_LOW_PART
+                     || code == ZERO_EXTRACT)
+                 && i == 0
+                 && GET_CODE (new) == REG)
+               ;
+
+             else if (COMBINE_RTX_EQUAL_P (XEXP (x, i), from))
                {
                  /* In general, don't install a subreg involving two
                     modes not tieable.  It can worsen register
@@ -3514,12 +3523,7 @@ combine_simplify_rtx (x, op0_mode, last, in_dest)
   /* If this is a commutative operation, put a constant last and a complex
      expression first.  We don't need to do this for comparisons here.  */
   if (GET_RTX_CLASS (code) == 'c'
-      && ((CONSTANT_P (XEXP (x, 0)) && GET_CODE (XEXP (x, 1)) != CONST_INT)
-         || (GET_RTX_CLASS (GET_CODE (XEXP (x, 0))) == 'o'
-             && GET_RTX_CLASS (GET_CODE (XEXP (x, 1))) != 'o')
-         || (GET_CODE (XEXP (x, 0)) == SUBREG
-             && GET_RTX_CLASS (GET_CODE (SUBREG_REG (XEXP (x, 0)))) == 'o'
-             && GET_RTX_CLASS (GET_CODE (XEXP (x, 1))) != 'o')))
+      && swap_commutative_operands_p (XEXP (x, 0), XEXP (x, 1)))
     {
       temp = XEXP (x, 0);
       SUBST (XEXP (x, 0), XEXP (x, 1));
@@ -3698,7 +3702,7 @@ combine_simplify_rtx (x, op0_mode, last, in_dest)
     }
 
   if (temp)
-    x = temp, code = GET_CODE (temp);
+    x = temp, code = GET_CODE (temp), op0_mode = VOIDmode;
 
   /* First see if we can apply the inverse distributive law.  */
   if (code == PLUS || code == MINUS
@@ -3706,11 +3710,12 @@ combine_simplify_rtx (x, op0_mode, last, in_dest)
     {
       x = apply_distributive_law (x);
       code = GET_CODE (x);
+      op0_mode = VOIDmode;
     }
 
   /* If CODE is an associative operation not otherwise handled, see if we
      can associate some operands.  This can win if they are constants or
-     if they are logically related (i.e. (a & b) & a.  */
+     if they are logically related (i.e. (a & b) & a).  */
   if ((code == PLUS || code == MINUS
        || code == MULT || code == AND || code == IOR || code == XOR
        || code == DIV || code == UDIV
@@ -3764,161 +3769,21 @@ combine_simplify_rtx (x, op0_mode, last, in_dest)
       break;
 
     case SUBREG:
-      /* (subreg:A (mem:B X) N) becomes a modified MEM unless the SUBREG
-        is paradoxical.  If we can't do that safely, then it becomes
-        something nonsensical so that this combination won't take place.  */
-
-      if (GET_CODE (SUBREG_REG (x)) == MEM
-         && (GET_MODE_SIZE (mode)
-             <= GET_MODE_SIZE (GET_MODE (SUBREG_REG (x)))))
-       {
-         rtx inner = SUBREG_REG (x);
-         int offset = SUBREG_BYTE (x);
-         /* Don't change the mode of the MEM
-            if that would change the meaning of the address.  */
-         if (MEM_VOLATILE_P (SUBREG_REG (x))
-             || mode_dependent_address_p (XEXP (inner, 0)))
-           return gen_rtx_CLOBBER (mode, const0_rtx);
-
-         /* Note if the plus_constant doesn't make a valid address
-            then this combination won't be accepted.  */
-         x = gen_rtx_MEM (mode,
-                          plus_constant (XEXP (inner, 0), offset));
-         MEM_COPY_ATTRIBUTES (x, inner);
-         return x;
-       }
-
-      /* If we are in a SET_DEST, these other cases can't apply.  */
-      if (in_dest)
-       return x;
-
-      /* Changing mode twice with SUBREG => just change it once,
-        or not at all if changing back to starting mode.  */
-      if (GET_CODE (SUBREG_REG (x)) == SUBREG)
-       {
-         int final_offset;
-         enum machine_mode outer_mode, inner_mode;
-
-         /* If the innermost mode is the same as the goal mode,
-            and the low word is being referenced in both SUBREGs,
-            return the innermost element.  */
-         if (mode == GET_MODE (SUBREG_REG (SUBREG_REG (x))))
-           {
-             int inner_word = SUBREG_BYTE (SUBREG_REG (x));
-             int outer_word = SUBREG_BYTE (x);
-
-             inner_word = (inner_word / UNITS_PER_WORD) * UNITS_PER_WORD;
-             outer_word = (outer_word / UNITS_PER_WORD) * UNITS_PER_WORD;
-             if (inner_word == 0
-                 && outer_word == 0)
-               return SUBREG_REG (SUBREG_REG (x));
-           }
-
-         outer_mode = GET_MODE (SUBREG_REG (x));
-         inner_mode = GET_MODE (SUBREG_REG (SUBREG_REG (x)));
-         final_offset = SUBREG_BYTE (x) + SUBREG_BYTE (SUBREG_REG(x));
-
-         if ((WORDS_BIG_ENDIAN || BYTES_BIG_ENDIAN)
-             && GET_MODE_SIZE (outer_mode) > GET_MODE_SIZE (mode)
-             && GET_MODE_SIZE (outer_mode) > GET_MODE_SIZE (inner_mode))
-           {
-             /* Inner SUBREG is paradoxical, outer is not.  On big endian
-                we have to special case this.  */
-             if (SUBREG_BYTE (SUBREG_REG (x)))
-               abort(); /* Can a paradoxical subreg have nonzero offset? */
-             if (WORDS_BIG_ENDIAN && BYTES_BIG_ENDIAN)
-               final_offset = SUBREG_BYTE (x) - GET_MODE_SIZE (outer_mode)
-                              + GET_MODE_SIZE (inner_mode);
-             else if (WORDS_BIG_ENDIAN)
-               final_offset = (final_offset % UNITS_PER_WORD)
-                              + ((SUBREG_BYTE (x) - GET_MODE_SIZE (outer_mode)
-                                  + GET_MODE_SIZE (inner_mode))
-                                 * UNITS_PER_WORD) / UNITS_PER_WORD;
-             else
-               final_offset = ((final_offset * UNITS_PER_WORD)
-                               / UNITS_PER_WORD)
-                              + ((SUBREG_BYTE (x) - GET_MODE_SIZE (outer_mode)
-                                  + GET_MODE_SIZE (inner_mode))
-                                 % UNITS_PER_WORD);
-           }
-
-         /* The SUBREG rules are that the byte offset must be
-            some multiple of the toplevel SUBREG's mode.  */
-         final_offset = (final_offset / GET_MODE_SIZE (mode));
-         final_offset = (final_offset * GET_MODE_SIZE (mode));
-
-         SUBST_INT (SUBREG_BYTE (x), final_offset);
-         SUBST (SUBREG_REG (x), SUBREG_REG (SUBREG_REG (x)));
-       }
-
-      /* SUBREG of a hard register => just change the register number
-        and/or mode.  If the hard register is not valid in that mode,
-        suppress this combination.  If the hard register is the stack,
-        frame, or argument pointer, leave this as a SUBREG.  */
-
-      if (GET_CODE (SUBREG_REG (x)) == REG
-         && REGNO (SUBREG_REG (x)) < FIRST_PSEUDO_REGISTER
-         && REGNO (SUBREG_REG (x)) != FRAME_POINTER_REGNUM
-#if HARD_FRAME_POINTER_REGNUM != FRAME_POINTER_REGNUM
-         && REGNO (SUBREG_REG (x)) != HARD_FRAME_POINTER_REGNUM
-#endif
-#if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM
-         && REGNO (SUBREG_REG (x)) != ARG_POINTER_REGNUM
-#endif
-         && REGNO (SUBREG_REG (x)) != STACK_POINTER_REGNUM)
-       {
-         int final_regno = subreg_hard_regno (x, 0);
-
-         if (HARD_REGNO_MODE_OK (final_regno, mode))
-           return gen_rtx_REG (mode, final_regno);
-         else
-           return gen_rtx_CLOBBER (mode, const0_rtx);
-       }
-
-      /* For a constant, try to pick up the part we want.  Handle a full
-        word and low-order part.  Only do this if we are narrowing
-        the constant; if it is being widened, we have no idea what
-        the extra bits will have been set to.  */
+      if (op0_mode == VOIDmode)
+       op0_mode = GET_MODE (SUBREG_REG (x));
 
-      if (CONSTANT_P (SUBREG_REG (x)) && op0_mode != VOIDmode
-         && GET_MODE_SIZE (mode) == UNITS_PER_WORD
-         && GET_MODE_SIZE (op0_mode) > UNITS_PER_WORD
-         && GET_MODE_CLASS (mode) == MODE_INT)
-       {
-         temp = operand_subword (SUBREG_REG (x),
-                                 (SUBREG_BYTE (x) / UNITS_PER_WORD),
-                                 0, op0_mode);
-         if (temp)
-           return temp;
-       }
-
-      /* If we want a subreg of a constant, at offset 0,
-        take the low bits.  On a little-endian machine, that's
-        always valid.  On a big-endian machine, it's valid
-        only if the constant's mode fits in one word.   Note that we
-        cannot use subreg_lowpart_p since SUBREG_REG may be VOIDmode.  */
+      /* simplify_subreg can't use gen_lowpart_for_combine.  */
       if (CONSTANT_P (SUBREG_REG (x))
-         && ((GET_MODE_SIZE (op0_mode) <= UNITS_PER_WORD
-             || ! WORDS_BIG_ENDIAN)
-             ? SUBREG_BYTE (x) == 0
-             : (SUBREG_BYTE (x)
-                == (GET_MODE_SIZE (op0_mode) - GET_MODE_SIZE (mode))))
-         && GET_MODE_SIZE (mode) <= GET_MODE_SIZE (op0_mode)
-         && (! WORDS_BIG_ENDIAN
-             || GET_MODE_BITSIZE (op0_mode) <= BITS_PER_WORD))
+         && subreg_lowpart_offset (mode, op0_mode) == SUBREG_BYTE (x))
        return gen_lowpart_for_combine (mode, SUBREG_REG (x));
 
-      /* A paradoxical SUBREG of a VOIDmode constant is the same constant,
-        since we are saying that the high bits don't matter.  */
-      if (CONSTANT_P (SUBREG_REG (x)) && GET_MODE (SUBREG_REG (x)) == VOIDmode
-         && GET_MODE_SIZE (mode) > GET_MODE_SIZE (op0_mode))
-       {
-         if (GET_MODE_SIZE (GET_MODE (SUBREG_REG (x))) > UNITS_PER_WORD
-             && (WORDS_BIG_ENDIAN || SUBREG_BYTE (x) != 0))
-           return constant_subword (SUBREG_REG (x), 
-                                    SUBREG_BYTE (x) / UNITS_PER_WORD, mode);
-         return SUBREG_REG (x);
-       }
+      {
+       rtx temp;
+       temp = simplify_subreg (mode, SUBREG_REG (x), op0_mode,
+                               SUBREG_BYTE (x));
+       if (temp)
+         return temp;
+      }
 
       /* Note that we cannot do any narrowing for non-constants since
         we might have been counting on using the fact that some bits were
@@ -7428,29 +7293,16 @@ if_then_else_cond (x, ptrue, pfalse)
        return cond0;
     }
 
-  /* If X is a normal SUBREG with both inner and outer modes integral,
-     we can narrow both the true and false values of the inner expression,
-     if there is a condition.  */
-  else if (code == SUBREG && GET_MODE_CLASS (mode) == MODE_INT
-          && GET_MODE_CLASS (GET_MODE (SUBREG_REG (x))) == MODE_INT
-          && GET_MODE_SIZE (mode) <= GET_MODE_SIZE (GET_MODE (SUBREG_REG (x)))
+  /* If X is a SUBREG, we can narrow both the true and false values
+     if the inner expression, if there is a condition.  */
+  else if (code == SUBREG
           && 0 != (cond0 = if_then_else_cond (SUBREG_REG (x),
                                               &true0, &false0)))
     {
-      if ((GET_CODE (SUBREG_REG (x)) == REG
-          || GET_CODE (SUBREG_REG (x)) == MEM
-          || CONSTANT_P (SUBREG_REG (x)))
-         && GET_MODE_SIZE (GET_MODE (SUBREG_REG (x))) > UNITS_PER_WORD
-         && (WORDS_BIG_ENDIAN || SUBREG_BYTE (x) >= UNITS_PER_WORD))
-       {
-         true0 = operand_subword (true0, SUBREG_BYTE (x) / UNITS_PER_WORD, 0,
-                                  GET_MODE (SUBREG_REG (x)));
-         false0 = operand_subword (false0, SUBREG_BYTE (x) / UNITS_PER_WORD, 0,
-                                   GET_MODE (SUBREG_REG (x)));
-       }
-      *ptrue = force_to_mode (true0, mode, ~(HOST_WIDE_INT) 0, NULL_RTX, 0);
-      *pfalse
-       = force_to_mode (false0, mode, ~(HOST_WIDE_INT) 0, NULL_RTX, 0);
+      *ptrue = simplify_gen_subreg (mode, true0,
+                                   GET_MODE (SUBREG_REG (x)), SUBREG_BYTE (x));
+      *pfalse = simplify_gen_subreg (mode, false0,
+                                    GET_MODE (SUBREG_REG (x)), SUBREG_BYTE (x));
 
       return cond0;
     }
@@ -9900,18 +9752,13 @@ gen_lowpart_for_combine (mode, x)
   else
     {
       int offset = 0;
+      rtx res;
 
-      if ((WORDS_BIG_ENDIAN || BYTES_BIG_ENDIAN)
-         && GET_MODE_SIZE (GET_MODE (x)) > GET_MODE_SIZE (mode))
-       {
-         int difference = (GET_MODE_SIZE (GET_MODE (x))
-                           - GET_MODE_SIZE (mode));
-         if (WORDS_BIG_ENDIAN)
-           offset += (difference / UNITS_PER_WORD) * UNITS_PER_WORD;
-         if (BYTES_BIG_ENDIAN)
-           offset += difference % UNITS_PER_WORD;
-       }
-      return gen_rtx_SUBREG (mode, x, offset);
+      offset = subreg_lowpart_offset (mode, GET_MODE (x));
+      res = simplify_gen_subreg (mode, x, GET_MODE (x), offset);
+      if (res)
+       return res;
+      return gen_rtx_CLOBBER (GET_MODE (x), const0_rtx);
     }
 }
 \f
@@ -9928,8 +9775,7 @@ gen_binary (code, mode, op0, op1)
   rtx tem;
 
   if (GET_RTX_CLASS (code) == 'c'
-      && (GET_CODE (op0) == CONST_INT
-         || (CONSTANT_P (op0) && GET_CODE (op1) != CONST_INT)))
+      && swap_commutative_operands_p (op0, op1))
     tem = op0, op0 = op1, op1 = tem;
 
   if (GET_RTX_CLASS (code) == '<')
@@ -9957,12 +9803,7 @@ gen_binary (code, mode, op0, op1)
 
   /* Put complex operands first and constants second.  */
   if (GET_RTX_CLASS (code) == 'c'
-      && ((CONSTANT_P (op0) && GET_CODE (op1) != CONST_INT)
-         || (GET_RTX_CLASS (GET_CODE (op0)) == 'o'
-             && GET_RTX_CLASS (GET_CODE (op1)) != 'o')
-         || (GET_CODE (op0) == SUBREG
-             && GET_RTX_CLASS (GET_CODE (SUBREG_REG (op0))) == 'o'
-             && GET_RTX_CLASS (GET_CODE (op1)) != 'o')))
+      && swap_commutative_operands_p (op0, op1))
     return gen_rtx_fmt_ee (code, mode, op1, op0);
 
   /* If we are turning off bits already known off in OP0, we need not do
@@ -10139,7 +9980,7 @@ simplify_comparison (code, pop0, pop1)
   /* If the first operand is a constant, swap the operands and adjust the
      comparison code appropriately, but don't do this if the second operand
      is already a constant integer.  */
-  if (CONSTANT_P (op0) && GET_CODE (op1) != CONST_INT)
+  if (swap_commutative_operands_p (op0, op1))
     {
       tem = op0, op0 = op1, op1 = tem;
       code = swap_condition (code);
@@ -10174,6 +10015,7 @@ simplify_comparison (code, pop0, pop1)
       /* Get the constant we are comparing against and turn off all bits
         not on in our mode.  */
       const_op = trunc_int_for_mode (INTVAL (op1), mode);
+      op1 = GEN_INT (const_op);
 
       /* If we are comparing against a constant power of two and the value
         being compared can only have that single bit nonzero (e.g., it was