OSDN Git Service

* config/xtensa/xtensa.md: Remove unused type attributes.
[pf3gnuchains/gcc-fork.git] / gcc / combine.c
index 663fd1d..0f17559 100644 (file)
@@ -424,6 +424,33 @@ do_SUBST (into, newval)
   if (oldval == newval)
     return;
 
+  /* We'd like to catch as many invalid transformations here as
+     possible.  Unfortunately, there are way too many mode changes
+     that are perfectly valid, so we'd waste too much effort for
+     little gain doing the checks here.  Focus on catching invalid
+     transformations involving integer constants.  */
+  if (GET_MODE_CLASS (GET_MODE (oldval)) == MODE_INT
+      && GET_CODE (newval) == CONST_INT)
+    {
+      /* Sanity check that we're replacing oldval with a CONST_INT
+        that is a valid sign-extension for the original mode.  */
+      if (INTVAL (newval) != trunc_int_for_mode (INTVAL (newval),
+                                                GET_MODE (oldval)))
+       abort ();
+
+      /* Replacing the operand of a SUBREG or a ZERO_EXTEND with a
+        CONST_INT is not valid, because after the replacement, the
+        original mode would be gone.  Unfortunately, we can't tell
+        when do_SUBST is called to replace the operand thereof, so we
+        perform this test on oldval instead, checking whether an
+        invalid replacement took place before we got here.  */
+      if ((GET_CODE (oldval) == SUBREG
+          && GET_CODE (SUBREG_REG (oldval)) == CONST_INT)
+         || (GET_CODE (oldval) == ZERO_EXTEND
+             && GET_CODE (XEXP (oldval, 0)) == CONST_INT))
+       abort ();
+     }
+
   if (undobuf.frees)
     buf = undobuf.frees, undobuf.frees = buf->next;
   else
@@ -712,14 +739,16 @@ combine_instructions (f, nregs)
          ;
        }
     }
+  clear_bb_flags ();
 
+  EXECUTE_IF_SET_IN_SBITMAP (refresh_blocks, 0, this_basic_block,
+                            BASIC_BLOCK (this_basic_block)->flags |= BB_DIRTY);
+  new_direct_jump_p |= purge_all_dead_edges (0);
   delete_noop_moves (f);
 
-  if (need_refresh)
-    {
-      update_life_info (refresh_blocks, UPDATE_LIFE_GLOBAL_RM_NOTES,
-                       PROP_DEATH_NOTES);
-    }
+  update_life_info_in_dirty_blocks (UPDATE_LIFE_GLOBAL_RM_NOTES,
+                                   PROP_DEATH_NOTES | PROP_SCAN_DEAD_CODE
+                                   | PROP_KILL_DEAD_CODE);
 
   /* Clean up.  */
   sbitmap_free (refresh_blocks);
@@ -1478,6 +1507,7 @@ try_combine (i3, i2, i1, new_direct_jump_p)
 {
   /* New patterns for I3 and I2, respectively.  */
   rtx newpat, newi2pat = 0;
+  int substed_i2 = 0, substed_i1 = 0;
   /* Indicates need to preserve SET in I1 or I2 in I3 if it is not dead.  */
   int added_sets_1, added_sets_2;
   /* Total number of SETs to put into I3.  */
@@ -1939,6 +1969,7 @@ try_combine (i3, i2, i1, new_direct_jump_p)
       subst_low_cuid = INSN_CUID (i2);
       newpat = subst (PATTERN (i3), i2dest, i2src, 0,
                      ! i1_feeds_i3 && i1dest_in_i1src);
+      substed_i2 = 1;
 
       /* Record whether i2's body now appears within i3's body.  */
       i2_is_used = n_occurrences;
@@ -1963,6 +1994,7 @@ try_combine (i3, i2, i1, new_direct_jump_p)
       n_occurrences = 0;
       subst_low_cuid = INSN_CUID (i1);
       newpat = subst (newpat, i1dest, i1src, 0, 0);
+      substed_i1 = 1;
     }
 
   /* Fail if an autoincrement side-effect has been duplicated.  Be careful
@@ -2534,6 +2566,23 @@ try_combine (i3, i2, i1, new_direct_jump_p)
 
     INSN_CODE (i3) = insn_code_number;
     PATTERN (i3) = newpat;
+
+    if (GET_CODE (i3) == CALL_INSN && CALL_INSN_FUNCTION_USAGE (i3))
+      {
+       rtx call_usage = CALL_INSN_FUNCTION_USAGE (i3);
+
+       reset_used_flags (call_usage);
+       call_usage = copy_rtx (call_usage);
+
+       if (substed_i2)
+         replace_rtx (call_usage, i2dest, i2src);
+
+       if (substed_i1)
+         replace_rtx (call_usage, i1dest, i1src);
+
+       CALL_INSN_FUNCTION_USAGE (i3) = call_usage;
+      }
+
     if (undobuf.other_insn)
       INSN_CODE (undobuf.other_insn) = other_code_number;
 
@@ -3485,7 +3534,24 @@ subst (x, from, to, in_dest, unique_copy)
              if (GET_CODE (new) == CLOBBER && XEXP (new, 0) == const0_rtx)
                return new;
 
-             SUBST (XEXP (x, i), new);
+             if (GET_CODE (new) == CONST_INT && GET_CODE (x) == SUBREG)
+               {
+                 x = simplify_subreg (GET_MODE (x), new,
+                                      GET_MODE (SUBREG_REG (x)),
+                                      SUBREG_BYTE (x));
+                 if (! x)
+                   abort ();
+               }
+             else if (GET_CODE (new) == CONST_INT
+                      && GET_CODE (x) == ZERO_EXTEND)
+               {
+                 x = simplify_unary_operation (ZERO_EXTEND, GET_MODE (x),
+                                               new, GET_MODE (XEXP (x, 0)));
+                 if (! x)
+                   abort ();
+               }
+             else
+               SUBST (XEXP (x, i), new);
            }
        }
     }
@@ -3914,12 +3980,14 @@ combine_simplify_rtx (x, op0_mode, last, in_dest)
       if (GET_CODE (XEXP (x, 0)) == NOT)
        return plus_constant (XEXP (XEXP (x, 0), 0), 1);
 
-      /* (neg (minus X Y)) can become (minus Y X).  */
+      /* (neg (minus X Y)) can become (minus Y X).  This transformation
+        isn't safe for modes with signed zeros, since if X and Y are
+        both +0, (minus Y X) is the same as (minus X Y).  If the rounding
+        mode is towards +infinity (or -infinity) then the two expressions
+        will be rounded differently.  */
       if (GET_CODE (XEXP (x, 0)) == MINUS
-         && (! FLOAT_MODE_P (mode)
-             /* x-y != -(y-x) with IEEE floating point.  */
-             || TARGET_FLOAT_FORMAT != IEEE_FLOAT_FORMAT
-             || flag_unsafe_math_optimizations))
+         && !HONOR_SIGNED_ZEROS (mode)
+         && !HONOR_SIGN_DEPENDENT_ROUNDING (mode))
        return gen_binary (MINUS, mode, XEXP (XEXP (x, 0), 1),
                           XEXP (XEXP (x, 0), 0));
 
@@ -4081,10 +4149,11 @@ combine_simplify_rtx (x, op0_mode, last, in_dest)
       if (XEXP (x, 1) == const0_rtx)
        return XEXP (x, 0);
 
-      /* In IEEE floating point, x-0 is not the same as x.  */
-      if ((TARGET_FLOAT_FORMAT != IEEE_FLOAT_FORMAT
-          || ! FLOAT_MODE_P (GET_MODE (XEXP (x, 0)))
-          || flag_unsafe_math_optimizations)
+      /* x - 0 is the same as x unless x's mode has signed zeros and
+        allows rounding towards -infinity.  Under those conditions,
+        0 - 0 is -0.  */
+      if (!(HONOR_SIGNED_ZEROS (GET_MODE (XEXP (x, 0)))
+           && HONOR_SIGN_DEPENDENT_ROUNDING (GET_MODE (XEXP (x, 0))))
          && XEXP (x, 1) == CONST0_RTX (GET_MODE (XEXP (x, 0))))
        return XEXP (x, 0);
       break;
@@ -5963,6 +6032,9 @@ make_extraction (mode, inner, pos, pos_rtx, len,
       if (mode == tmode)
        return new;
 
+      if (GET_CODE (new) == CONST_INT)
+       return gen_int_mode (INTVAL (new), mode);
+
       /* If we know that no extraneous bits are set, and that the high
         bit is not set, convert the extraction to the cheaper of
         sign and zero extension, that are equivalent in these cases.  */
@@ -6701,7 +6773,8 @@ force_to_mode (x, mode, mask, reg, just_select)
             need it.  */
 
          if (GET_CODE (x) == AND && GET_CODE (XEXP (x, 1)) == CONST_INT
-             && (unsigned HOST_WIDE_INT) INTVAL (XEXP (x, 1)) == mask)
+             && ((INTVAL (XEXP (x, 1)) & GET_MODE_MASK (GET_MODE (x)))
+                 == (HOST_WIDE_INT) mask))
            x = XEXP (x, 0);
 
          /* If it remains an AND, try making another AND with the bits
@@ -6752,33 +6825,12 @@ force_to_mode (x, mode, mask, reg, just_select)
          smask |= (HOST_WIDE_INT) -1 << width;
 
        if (GET_CODE (XEXP (x, 1)) == CONST_INT
-           && exact_log2 (- smask) >= 0)
-         {
-#ifdef STACK_BIAS
-           if (STACK_BIAS
-               && (XEXP (x, 0) == stack_pointer_rtx
-                   || XEXP (x, 0) == frame_pointer_rtx))
-             {
-               int sp_alignment = STACK_BOUNDARY / BITS_PER_UNIT;
-               unsigned HOST_WIDE_INT sp_mask = GET_MODE_MASK (mode);
-
-               sp_mask &= ~(sp_alignment - 1);
-               if ((sp_mask & ~smask) == 0
-                   && ((INTVAL (XEXP (x, 1)) - STACK_BIAS) & ~smask) != 0)
-                 return force_to_mode (plus_constant (XEXP (x, 0),
-                                                      ((INTVAL (XEXP (x, 1)) -
-                                                        STACK_BIAS) & smask)
-                                                      + STACK_BIAS),
-                                       mode, smask, reg, next_select);
-             }
-#endif
-           if ((nonzero_bits (XEXP (x, 0), mode) & ~smask) == 0
-               && (INTVAL (XEXP (x, 1)) & ~smask) != 0)
-             return force_to_mode (plus_constant (XEXP (x, 0),
-                                                  (INTVAL (XEXP (x, 1))
-                                                   & smask)),
-                                   mode, smask, reg, next_select);
-         }
+           && exact_log2 (- smask) >= 0
+           && (nonzero_bits (XEXP (x, 0), mode) & ~smask) == 0
+           && (INTVAL (XEXP (x, 1)) & ~smask) != 0)
+         return force_to_mode (plus_constant (XEXP (x, 0),
+                                              (INTVAL (XEXP (x, 1)) & smask)),
+                               mode, smask, reg, next_select);
       }
 
       /* ... fall through ...  */
@@ -7430,6 +7482,50 @@ known_cond (x, cond, reg, val)
            }
        }
     }
+  else if (code == SUBREG)
+    {
+      enum machine_mode inner_mode = GET_MODE (SUBREG_REG (x));
+      rtx new, r = known_cond (SUBREG_REG (x), cond, reg, val);
+
+      if (SUBREG_REG (x) != r)
+       {
+         /* We must simplify subreg here, before we lose track of the
+            original inner_mode.  */
+         new = simplify_subreg (GET_MODE (x), r,
+                                inner_mode, SUBREG_BYTE (x));
+         if (new)
+           return new;
+         else
+           SUBST (SUBREG_REG (x), r);
+       }
+
+      return x;
+    }
+  /* We don't have to handle SIGN_EXTEND here, because even in the
+     case of replacing something with a modeless CONST_INT, a
+     CONST_INT is already (supposed to be) a valid sign extension for
+     its narrower mode, which implies it's already properly
+     sign-extended for the wider mode.  Now, for ZERO_EXTEND, the
+     story is different.  */
+  else if (code == ZERO_EXTEND)
+    {
+      enum machine_mode inner_mode = GET_MODE (XEXP (x, 0));
+      rtx new, r = known_cond (XEXP (x, 0), cond, reg, val);
+
+      if (XEXP (x, 0) != r)
+       {
+         /* We must simplify the zero_extend here, before we lose
+             track of the original inner_mode.  */
+         new = simplify_unary_operation (ZERO_EXTEND, GET_MODE (x),
+                                         r, inner_mode);
+         if (new)
+           return new;
+         else
+           SUBST (XEXP (x, 0), r);
+       }
+
+      return x;
+    }
 
   fmt = GET_RTX_FORMAT (code);
   for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
@@ -7755,7 +7851,6 @@ simplify_and_const_int (x, mode, varop, constop)
      MODE.  */
 
   nonzero = nonzero_bits (varop, mode) & GET_MODE_MASK (mode);
-  nonzero = trunc_int_for_mode (nonzero, mode);
 
   /* Turn off all bits in the constant that are known to already be zero.
      Thus, if the AND isn't needed at all, we will have CONSTOP == NONZERO_BITS
@@ -7823,19 +7918,22 @@ simplify_and_const_int (x, mode, varop, constop)
   /* If we are only masking insignificant bits, return VAROP.  */
   if (constop == nonzero)
     x = varop;
-
-  /* Otherwise, return an AND.  See how much, if any, of X we can use.  */
-  else if (x == 0 || GET_CODE (x) != AND || GET_MODE (x) != mode)
-    x = gen_binary (AND, mode, varop, GEN_INT (constop));
-
   else
     {
+      /* Otherwise, return an AND.  */
       constop = trunc_int_for_mode (constop, mode);
-      if (GET_CODE (XEXP (x, 1)) != CONST_INT
-         || (unsigned HOST_WIDE_INT) INTVAL (XEXP (x, 1)) != constop)
-       SUBST (XEXP (x, 1), GEN_INT (constop));
+      /* See how much, if any, of X we can use.  */
+      if (x == 0 || GET_CODE (x) != AND || GET_MODE (x) != mode)
+       x = gen_binary (AND, mode, varop, GEN_INT (constop));
 
-      SUBST (XEXP (x, 0), varop);
+      else
+       {
+         if (GET_CODE (XEXP (x, 1)) != CONST_INT
+             || (unsigned HOST_WIDE_INT) INTVAL (XEXP (x, 1)) != constop)
+           SUBST (XEXP (x, 1), GEN_INT (constop));
+
+         SUBST (XEXP (x, 0), varop);
+       }
     }
 
   return x;
@@ -7913,40 +8011,28 @@ nonzero_bits (x, mode)
        nonzero &= GET_MODE_MASK (ptr_mode);
 #endif
 
-#ifdef STACK_BOUNDARY
-      /* If this is the stack pointer, we may know something about its
-        alignment.  If PUSH_ROUNDING is defined, it is possible for the
-        stack to be momentarily aligned only to that amount, so we pick
-        the least alignment.  */
-
-      /* We can't check for arg_pointer_rtx here, because it is not
-        guaranteed to have as much alignment as the stack pointer.
-        In particular, in the Irix6 n64 ABI, the stack has 128 bit
-        alignment but the argument pointer has only 64 bit alignment.  */
-
-      if ((x == frame_pointer_rtx
-          || x == stack_pointer_rtx
-          || x == hard_frame_pointer_rtx
-          || (REGNO (x) >= FIRST_VIRTUAL_REGISTER
-              && REGNO (x) <= LAST_VIRTUAL_REGISTER))
-#ifdef STACK_BIAS
-         && !STACK_BIAS
-#endif
-             )
+      /* Include declared information about alignment of pointers.  */
+      /* ??? We don't properly preserve REG_POINTER changes across
+        pointer-to-integer casts, so we can't trust it except for
+        things that we know must be pointers.  See execute/960116-1.c.  */
+      if ((x == stack_pointer_rtx
+          || x == frame_pointer_rtx
+          || x == arg_pointer_rtx)
+         && REGNO_POINTER_ALIGN (REGNO (x)))
        {
-         int sp_alignment = STACK_BOUNDARY / BITS_PER_UNIT;
+         unsigned HOST_WIDE_INT alignment
+           = REGNO_POINTER_ALIGN (REGNO (x)) / BITS_PER_UNIT;
 
 #ifdef PUSH_ROUNDING
-         if (REGNO (x) == STACK_POINTER_REGNUM && PUSH_ARGS)
-           sp_alignment = MIN (PUSH_ROUNDING (1), sp_alignment);
+         /* If PUSH_ROUNDING is defined, it is possible for the
+            stack to be momentarily aligned only to that amount,
+            so we pick the least alignment.  */
+         if (x == stack_pointer_rtx && PUSH_ARGS)
+           alignment = MIN (PUSH_ROUNDING (1), alignment);
 #endif
 
-         /* We must return here, otherwise we may get a worse result from
-            one of the choices below.  There is nothing useful below as
-            far as the stack pointer is concerned.  */
-         return nonzero &= ~(sp_alignment - 1);
+         nonzero &= ~(alignment - 1);
        }
-#endif
 
       /* If X is a register whose nonzero bits value is current, use it.
         Otherwise, if X is a register whose value we can find, use that
@@ -7961,7 +8047,7 @@ nonzero_bits (x, mode)
                  && ! REGNO_REG_SET_P (BASIC_BLOCK (0)->global_live_at_start,
                                        REGNO (x))))
          && INSN_CUID (reg_last_set[REGNO (x)]) < subst_low_cuid)
-       return reg_last_set_nonzero_bits[REGNO (x)];
+       return reg_last_set_nonzero_bits[REGNO (x)] & nonzero;
 
       tem = get_last_value (x);
 
@@ -7987,7 +8073,7 @@ nonzero_bits (x, mode)
                           | ((HOST_WIDE_INT) (-1)
                              << GET_MODE_BITSIZE (GET_MODE (x))));
 #endif
-         return nonzero_bits (tem, mode);
+         return nonzero_bits (tem, mode) & nonzero;
        }
       else if (nonzero_sign_valid && reg_nonzero_bits[REGNO (x)])
        {
@@ -8125,22 +8211,6 @@ nonzero_bits (x, mode)
        switch (code)
          {
          case PLUS:
-#ifdef STACK_BIAS
-           if (STACK_BIAS
-               && (XEXP (x, 0) == stack_pointer_rtx
-                   || XEXP (x, 0) == frame_pointer_rtx)
-               && GET_CODE (XEXP (x, 1)) == CONST_INT)
-             {
-               int sp_alignment = STACK_BOUNDARY / BITS_PER_UNIT;
-
-               nz0 = (GET_MODE_MASK (mode) & ~(sp_alignment - 1));
-               nz1 = INTVAL (XEXP (x, 1)) - STACK_BIAS;
-               width0 = floor_log2 (nz0) + 1;
-               width1 = floor_log2 (nz1) + 1;
-               low0 = floor_log2 (nz0 & -nz0);
-               low1 = floor_log2 (nz1 & -nz1);
-             }
-#endif
            result_width = MAX (width0, width1) + 1;
            result_low = MIN (low0, low1);
            break;
@@ -8208,7 +8278,7 @@ nonzero_bits (x, mode)
         been zero-extended, we know that at least the high-order bits
         are zero, though others might be too.  */
 
-      if (SUBREG_PROMOTED_VAR_P (x) && SUBREG_PROMOTED_UNSIGNED_P (x))
+      if (SUBREG_PROMOTED_VAR_P (x) && SUBREG_PROMOTED_UNSIGNED_P (x) > 0)
        nonzero = (GET_MODE_MASK (GET_MODE (x))
                   & nonzero_bits (SUBREG_REG (x), GET_MODE (x)));
 
@@ -9587,7 +9657,7 @@ recog_for_combine (pnewpat, insn, pnotes)
   int num_clobbers_to_add = 0;
   int i;
   rtx notes = 0;
-  rtx old_notes;
+  rtx dummy_insn;
 
   /* If PAT is a PARALLEL, check to see if it contains the CLOBBER
      we use to indicate that something didn't match.  If we find such a
@@ -9598,11 +9668,13 @@ recog_for_combine (pnewpat, insn, pnotes)
          && XEXP (XVECEXP (pat, 0, i), 0) == const0_rtx)
        return -1;
 
-  /* Remove the old notes prior to trying to recognize the new pattern.  */
-  old_notes = REG_NOTES (insn);
-  REG_NOTES (insn) = 0;
+  /* *pnewpat does not have to be actual PATTERN (insn), so make a dummy
+     instruction for pattern recognition.  */
+  dummy_insn = shallow_copy_rtx (insn);
+  PATTERN (dummy_insn) = pat;
+  REG_NOTES (dummy_insn) = 0;
 
-  insn_code_number = recog (pat, insn, &num_clobbers_to_add);
+  insn_code_number = recog (pat, dummy_insn, &num_clobbers_to_add);
 
   /* If it isn't, there is the possibility that we previously had an insn
      that clobbered some register as a side effect, but the combined
@@ -9627,15 +9699,14 @@ recog_for_combine (pnewpat, insn, pnotes)
       if (pos == 1)
        pat = XVECEXP (pat, 0, 0);
 
-      insn_code_number = recog (pat, insn, &num_clobbers_to_add);
+      PATTERN (dummy_insn) = pat;
+      insn_code_number = recog (pat, dummy_insn, &num_clobbers_to_add);
     }
 
   /* Recognize all noop sets, these will be killed by followup pass.  */
   if (insn_code_number < 0 && GET_CODE (pat) == SET && set_noop_p (pat))
     insn_code_number = NOOP_MOVE_INSN_CODE, num_clobbers_to_add = 0;
 
-  REG_NOTES (insn) = old_notes;
-
   /* If we had any clobbers to add, make a new pattern than contains
      them.  Then check to make sure that all of them are dead.  */
   if (num_clobbers_to_add)
@@ -10721,7 +10792,7 @@ simplify_comparison (code, pop0, pop1)
              unsigned HOST_WIDE_INT temp = const_op & GET_MODE_MASK (mode);
 
              temp >>= INTVAL (XEXP (op0, 1));
-             op1 = GEN_INT (trunc_int_for_mode (temp, mode));
+             op1 = gen_int_mode (temp, mode);
              op0 = XEXP (op0, 0);
              continue;
            }
@@ -10822,6 +10893,11 @@ simplify_comparison (code, pop0, pop1)
                  || (floor_log2 (const_op) + INTVAL (XEXP (op0, 1))
                      < mode_width)))
            {
+             /* If the shift was logical, then we must make the condition
+                unsigned.  */
+             if (GET_CODE (op0) == LSHIFTRT)
+               code = unsigned_condition (code);
+
              const_op <<= INTVAL (XEXP (op0, 1));
              op1 = GEN_INT (const_op);
              op0 = XEXP (op0, 0);
@@ -11262,7 +11338,7 @@ record_promoted_value (insn, subreg)
 
       if (reg_last_set[regno] == insn)
        {
-         if (SUBREG_PROMOTED_UNSIGNED_P (subreg))
+         if (SUBREG_PROMOTED_UNSIGNED_P (subreg) > 0)
            reg_last_set_nonzero_bits[regno] &= GET_MODE_MASK (mode);
        }
 
@@ -11609,6 +11685,7 @@ mark_used_regs_combine (x)
     case CONST_INT:
     case CONST:
     case CONST_DOUBLE:
+    case CONST_VECTOR:
     case PC:
     case ADDR_VEC:
     case ADDR_DIFF_VEC: