OSDN Git Service

Set TARGET_LIBGCC2_CFLAGS instead of LIBGCC2_CFLAGS.
[pf3gnuchains/gcc-fork.git] / gcc / combine.c
index 2265eb3..31efa5b 100644 (file)
@@ -445,7 +445,7 @@ static void update_table_tick       PROTO((rtx));
 static void record_value_for_reg  PROTO((rtx, rtx, rtx));
 static void record_dead_and_set_regs_1  PROTO((rtx, rtx));
 static void record_dead_and_set_regs  PROTO((rtx));
-static int get_last_value_validate  PROTO((rtx *, int, int));
+static int get_last_value_validate  PROTO((rtx *, rtx, int, int));
 static rtx get_last_value      PROTO((rtx));
 static int use_crosses_set_p   PROTO((rtx, int));
 static void reg_dead_at_p_1    PROTO((rtx, rtx));
@@ -2699,6 +2699,14 @@ find_split_point (loc, insn)
 
        case SIGN_EXTEND:
          inner = XEXP (SET_SRC (x), 0);
+
+         /* We can't optimize if either mode is a partial integer
+            mode as we don't know how many bits are significant
+            in those modes.  */
+         if (GET_MODE_CLASS (GET_MODE (inner)) == MODE_PARTIAL_INT
+             || GET_MODE_CLASS (GET_MODE (SET_SRC (x))) == MODE_PARTIAL_INT)
+           break;
+
          pos = 0;
          len = GET_MODE_BITSIZE (GET_MODE (inner));
          unsignedp = 0;
@@ -3375,7 +3383,7 @@ simplify_rtx (x, op0_mode, last, in_dest)
 
       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_SIZE (op0_mode) > UNITS_PER_WORD
          && GET_MODE_CLASS (mode) == MODE_INT)
        {
          temp = operand_subword (SUBREG_REG (x), SUBREG_WORD (x),
@@ -3387,8 +3395,16 @@ simplify_rtx (x, op0_mode, last, in_dest)
       /* 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.  */
-      if (CONSTANT_P (SUBREG_REG (x)) && subreg_lowpart_p (x)
+        only if the constant's mode fits in one word.   Note that we
+        cannot use subreg_lowpart_p since SUBREG_REG may be VOIDmode.  */
+      if (CONSTANT_P (SUBREG_REG (x))
+         && ((GET_MODE_SIZE (op0_mode) <= UNITS_PER_WORD
+             || ! WORDS_BIG_ENDIAN)
+             ? SUBREG_WORD (x) == 0
+             : (SUBREG_WORD (x)
+                == ((GET_MODE_SIZE (op0_mode)
+                     - MAX (GET_MODE_SIZE (mode), UNITS_PER_WORD))
+                    / UNITS_PER_WORD)))
          && GET_MODE_SIZE (mode) <= GET_MODE_SIZE (op0_mode)
          && (! WORDS_BIG_ENDIAN
              || GET_MODE_BITSIZE (op0_mode) <= BITS_PER_WORD))
@@ -3582,6 +3598,12 @@ simplify_rtx (x, op0_mode, last, in_dest)
       break;
 
     case TRUNCATE:
+      /* We can't handle truncation to a partial integer mode here
+        because we don't know the real bitsize of the partial
+        integer mode.  */
+      if (GET_MODE_CLASS (mode) == MODE_PARTIAL_INT)
+       break;
+
       if (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT)
        SUBST (XEXP (x, 0),
               force_to_mode (XEXP (x, 0), GET_MODE (XEXP (x, 0)),
@@ -6490,6 +6512,14 @@ if_then_else_cond (x, ptrue, pfalse)
       if ((cond0 != 0 || cond1 != 0)
          && ! (cond0 != 0 && cond1 != 0 && ! rtx_equal_p (cond0, cond1)))
        {
+         /* If if_then_else_cond returned zero, then true/false are the
+            same rtl.  We must copy one of them to prevent invalid rtl
+            sharing.  */
+         if (cond0 == 0)
+           true0 = copy_rtx (true0);
+         else if (cond1 == 0)
+           true1 = copy_rtx (true1);
+
          *ptrue = gen_binary (code, mode, true0, true1);
          *pfalse = gen_binary (code, mode, false0, false1);
          return cond0 ? cond0 : cond1;
@@ -10173,11 +10203,12 @@ record_value_for_reg (reg, insn, value)
   /* The value being assigned might refer to X (like in "x++;").  In that
      case, we must replace it with (clobber (const_int 0)) to prevent
      infinite loops.  */
-  if (value && ! get_last_value_validate (&value,
+  if (value && ! get_last_value_validate (&value, insn,
                                          reg_last_set_label[regno], 0))
     {
       value = copy_rtx (value);
-      if (! get_last_value_validate (&value, reg_last_set_label[regno], 1))
+      if (! get_last_value_validate (&value, insn,
+                                    reg_last_set_label[regno], 1))
        value = 0;
     }
 
@@ -10298,8 +10329,9 @@ record_dead_and_set_regs (insn)
    we don't know exactly what registers it was produced from.  */
 
 static int
-get_last_value_validate (loc, tick, replace)
+get_last_value_validate (loc, insn, tick, replace)
      rtx *loc;
+     rtx insn;
      int tick;
      int replace;
 {
@@ -10329,10 +10361,20 @@ get_last_value_validate (loc, tick, replace)
 
       return 1;
     }
+  /* If this is a memory reference, make sure that there were
+     no stores after it that might have clobbered the value.  We don't
+     have alias info, so we assume any store invalidates it.  */
+  else if (GET_CODE (x) == MEM && ! RTX_UNCHANGING_P (x)
+          && INSN_CUID (insn) <= mem_last_set)
+    {
+      if (replace)
+       *loc = gen_rtx (CLOBBER, GET_MODE (x), const0_rtx);
+      return replace;
+    }
 
   for (i = 0; i < len; i++)
     if ((fmt[i] == 'e'
-        && get_last_value_validate (&XEXP (x, i), tick, replace) == 0)
+        && get_last_value_validate (&XEXP (x, i), insn, tick, replace) == 0)
        /* Don't bother with these.  They shouldn't occur anyway.  */
        || fmt[i] == 'E')
       return 0;
@@ -10429,14 +10471,16 @@ get_last_value (x)
     }
 
   /* If the value has all its registers valid, return it.  */
-  if (get_last_value_validate (&value, reg_last_set_label[regno], 0))
+  if (get_last_value_validate (&value, reg_last_set[regno],
+                              reg_last_set_label[regno], 0))
     return value;
 
   /* Otherwise, make a copy and replace any invalid register with
      (clobber (const_int 0)).  If that fails for some reason, return 0.  */
 
   value = copy_rtx (value);
-  if (get_last_value_validate (&value, reg_last_set_label[regno], 1))
+  if (get_last_value_validate (&value, reg_last_set[regno],
+                              reg_last_set_label[regno], 1))
     return value;
 
   return 0;
@@ -10770,7 +10814,7 @@ move_deaths (x, maybe_kill_insn, from_cuid, to_insn, pnotes)
 
          if (note != 0 && regno < FIRST_PSEUDO_REGISTER
              && (GET_MODE_SIZE (GET_MODE (XEXP (note, 0)))
-                 != GET_MODE_SIZE (GET_MODE (x))))
+                 > GET_MODE_SIZE (GET_MODE (x))))
            {
              int deadregno = REGNO (XEXP (note, 0));
              int deadend
@@ -10786,18 +10830,28 @@ move_deaths (x, maybe_kill_insn, from_cuid, to_insn, pnotes)
                               gen_rtx (REG, reg_raw_mode[i], i),
                               REG_NOTES (where_dead));
            }
-         /* If we didn't find any note, and we have a multi-reg hard
+         /* If we didn't find any note, or if we found a REG_DEAD note that
+            covers only part of the given reg, and we have a multi-reg hard
             register, then to be safe we must check for REG_DEAD notes
             for each register other than the first.  They could have
             their own REG_DEAD notes lying around.  */
-         else if (note == 0 && regno < FIRST_PSEUDO_REGISTER
+         else if ((note == 0
+                   || (note != 0
+                       && (GET_MODE_SIZE (GET_MODE (XEXP (note, 0)))
+                           < GET_MODE_SIZE (GET_MODE (x)))))
+                  && regno < FIRST_PSEUDO_REGISTER
                   && HARD_REGNO_NREGS (regno, GET_MODE (x)) > 1)
            {
              int ourend = regno + HARD_REGNO_NREGS (regno, GET_MODE (x));
-             int i;
+             int i, offset;
              rtx oldnotes = 0;
 
-             for (i = regno + 1; i < ourend; i++)
+             if (note)
+               offset = HARD_REGNO_NREGS (regno, GET_MODE (XEXP (note, 0)));
+             else
+               offset = 1;
+
+             for (i = regno + offset; i < ourend; i++)
                move_deaths (gen_rtx (REG, reg_raw_mode[i], i),
                             maybe_kill_insn, from_cuid, to_insn, &oldnotes);
            }
@@ -10955,6 +11009,14 @@ distribute_notes (notes, from_insn, i3, i2, elim_i2, elim_i1)
       next_note = XEXP (note, 1);
       switch (REG_NOTE_KIND (note))
        {
+       case REG_BR_PROB:
+       case REG_EXEC_COUNT:
+         /* Doesn't matter much where we put this, as long as it's somewhere.
+            It is preferable to keep these notes on branches, which is most
+            likely to be i3.  */
+         place = i3;
+         break;
+
        case REG_UNUSED:
          /* Any clobbers for i3 may still exist, and so we must process
             REG_UNUSED notes from that insn.