OSDN Git Service

PR c++/10549
[pf3gnuchains/gcc-fork.git] / gcc / emit-rtl.c
index c96bc4e..7048aee 100644 (file)
@@ -111,6 +111,8 @@ REAL_VALUE_TYPE dconst0;
 REAL_VALUE_TYPE dconst1;
 REAL_VALUE_TYPE dconst2;
 REAL_VALUE_TYPE dconstm1;
+REAL_VALUE_TYPE dconstm2;
+REAL_VALUE_TYPE dconsthalf;
 
 /* All references to the following fixed hard registers go through
    these unique rtl objects.  On machines where the frame-pointer and
@@ -238,7 +240,7 @@ const_double_htab_hash (x)
     h = CONST_DOUBLE_LOW (value) ^ CONST_DOUBLE_HIGH (value);
   else
     {
-      h = real_hash (CONST_DOUBLE_REAL_VALUE (value)); 
+      h = real_hash (CONST_DOUBLE_REAL_VALUE (value));
       /* MODE is used in the comparison, so it should be in the hash.  */
       h ^= GET_MODE (value);
     }
@@ -310,13 +312,14 @@ get_mem_attrs (alias, expr, offset, size, align, mode)
   mem_attrs attrs;
   void **slot;
 
-  /* If everything is the default, we can just return zero.  */
+  /* If everything is the default, we can just return zero.
+     This must match what the corresponding MEM_* macros return when the
+     field is not present.  */
   if (alias == 0 && expr == 0 && offset == 0
       && (size == 0
          || (mode != BLKmode && GET_MODE_SIZE (mode) == INTVAL (size)))
-      && (align == BITS_PER_UNIT
-         || (STRICT_ALIGNMENT
-             && mode != BLKmode && align == GET_MODE_ALIGNMENT (mode))))
+      && (STRICT_ALIGNMENT && mode != BLKmode
+         ? align == GET_MODE_ALIGNMENT (mode) : align == BITS_PER_UNIT))
     return 0;
 
   attrs.alias = alias;
@@ -752,7 +755,8 @@ gen_rtx VPARAMS ((enum rtx_code code, enum machine_mode mode, ...))
        {
          switch (*fmt++)
            {
-           case '0':           /* Unused field.  */
+           case '0':           /* Field with unknown use.  Zero it.  */
+             X0EXP (rt_val, i) = NULL_RTX;
              break;
 
            case 'i':           /* An integer?  */
@@ -1077,7 +1081,11 @@ subreg_hard_regno (x, check_mode)
     abort ();
   if (check_mode && ! HARD_REGNO_MODE_OK (base_regno, GET_MODE (reg)))
     abort ();
-
+#ifdef ENABLE_CHECKING
+  if (!subreg_offset_representable_p (REGNO (reg), GET_MODE (reg),
+                                     SUBREG_BYTE (x), mode))
+    abort ();
+#endif
   /* Catch non-congruent offsets too.  */
   byte_offset = SUBREG_BYTE (x);
   if ((byte_offset % GET_MODE_SIZE (mode)) != 0)
@@ -1374,6 +1382,7 @@ gen_lowpart (mode, x)
 
       /* The following exposes the use of "x" to CSE.  */
       if (GET_MODE_SIZE (GET_MODE (x)) <= UNITS_PER_WORD
+         && SCALAR_INT_MODE_P (GET_MODE (x))
          && ! no_new_pseudos)
        return gen_lowpart (mode, force_reg (GET_MODE (x), x));
 
@@ -2042,7 +2051,7 @@ set_mem_attributes_minus_bitpos (ref, t, objectp, bitpos)
        }
     }
 
-  /* If we modified OFFSET based on T, then subtract the outstanding 
+  /* If we modified OFFSET based on T, then subtract the outstanding
      bit position offset.  Similarly, increase the size of the accessed
      object to contain the negative offset.  */
   if (apply_bitpos)
@@ -2309,7 +2318,7 @@ rtx
 offset_address (memref, offset, pow2)
      rtx memref;
      rtx offset;
-     HOST_WIDE_INT pow2;
+     unsigned HOST_WIDE_INT pow2;
 {
   rtx new, addr = XEXP (memref, 0);
 
@@ -2337,8 +2346,7 @@ offset_address (memref, offset, pow2)
      we don't know.  */
   MEM_ATTRS (new)
     = get_mem_attrs (MEM_ALIAS_SET (memref), MEM_EXPR (memref), 0, 0,
-                    MIN (MEM_ALIGN (memref),
-                         (unsigned HOST_WIDE_INT) pow2 * BITS_PER_UNIT),
+                    MIN (MEM_ALIGN (memref), pow2 * BITS_PER_UNIT),
                     GET_MODE (new));
   return new;
 }
@@ -3374,6 +3382,8 @@ try_split (pat, trial, last)
   rtx tem;
   rtx note, seq;
   int probability;
+  rtx insn_last, insn;
+  int njumps = 0;
 
   if (any_condjump_p (trial)
       && (note = find_reg_note (trial, REG_BR_PROB, 0)))
@@ -3392,172 +3402,147 @@ try_split (pat, trial, last)
       after = NEXT_INSN (after);
     }
 
-  if (seq)
+  if (!seq)
+    return trial;
+
+  /* Avoid infinite loop if any insn of the result matches
+     the original pattern.  */
+  insn_last = seq;
+  while (1)
     {
-      /* Sometimes there will be only one insn in that list, this case will
-        normally arise only when we want it in turn to be split (SFmode on
-        the 29k is an example).  */
-      if (NEXT_INSN (seq) != NULL_RTX)
-       {
-         rtx insn_last, insn;
-         int njumps = 0;
+      if (INSN_P (insn_last)
+         && rtx_equal_p (PATTERN (insn_last), pat))
+       return trial;
+      if (!NEXT_INSN (insn_last))
+       break;
+      insn_last = NEXT_INSN (insn_last);
+    }
 
-         /* Avoid infinite loop if any insn of the result matches
-            the original pattern.  */
-         insn_last = seq;
-         while (1)
+  /* Mark labels.  */
+  for (insn = insn_last; insn ; insn = PREV_INSN (insn))
+    {
+      if (GET_CODE (insn) == JUMP_INSN)
+       {
+         mark_jump_label (PATTERN (insn), insn, 0);
+         njumps++;
+         if (probability != -1
+             && any_condjump_p (insn)
+             && !find_reg_note (insn, REG_BR_PROB, 0))
            {
-             if (INSN_P (insn_last)
-                 && rtx_equal_p (PATTERN (insn_last), pat))
-               return trial;
-             if (NEXT_INSN (insn_last) == NULL_RTX)
-               break;
-             insn_last = NEXT_INSN (insn_last);
+             /* We can preserve the REG_BR_PROB notes only if exactly
+                one jump is created, otherwise the machine description
+                is responsible for this step using
+                split_branch_probability variable.  */
+             if (njumps != 1)
+               abort ();
+             REG_NOTES (insn)
+               = gen_rtx_EXPR_LIST (REG_BR_PROB,
+                                    GEN_INT (probability),
+                                    REG_NOTES (insn));
            }
+       }
+    }
+
+  /* If we are splitting a CALL_INSN, look for the CALL_INSN
+     in SEQ and copy our CALL_INSN_FUNCTION_USAGE to it.  */
+  if (GET_CODE (trial) == CALL_INSN)
+    {
+      for (insn = insn_last; insn ; insn = PREV_INSN (insn))
+       if (GET_CODE (insn) == CALL_INSN)
+         {
+           CALL_INSN_FUNCTION_USAGE (insn)
+             = CALL_INSN_FUNCTION_USAGE (trial);
+           SIBLING_CALL_P (insn) = SIBLING_CALL_P (trial);
+         }
+    }
 
-         /* Mark labels.  */
+  /* Copy notes, particularly those related to the CFG.  */
+  for (note = REG_NOTES (trial); note; note = XEXP (note, 1))
+    {
+      switch (REG_NOTE_KIND (note))
+       {
+       case REG_EH_REGION:
          insn = insn_last;
          while (insn != NULL_RTX)
            {
-             if (GET_CODE (insn) == JUMP_INSN)
-               {
-                 mark_jump_label (PATTERN (insn), insn, 0);
-                 njumps++;
-                 if (probability != -1
-                     && any_condjump_p (insn)
-                     && !find_reg_note (insn, REG_BR_PROB, 0))
-                   {
-                     /* We can preserve the REG_BR_PROB notes only if exactly
-                        one jump is created, otherwise the machine description
-                        is responsible for this step using
-                        split_branch_probability variable.  */
-                     if (njumps != 1)
-                       abort ();
-                     REG_NOTES (insn)
-                       = gen_rtx_EXPR_LIST (REG_BR_PROB,
-                                            GEN_INT (probability),
-                                            REG_NOTES (insn));
-                   }
-               }
-
+             if (GET_CODE (insn) == CALL_INSN
+                 || (flag_non_call_exceptions
+                     && may_trap_p (PATTERN (insn))))
+               REG_NOTES (insn)
+                 = gen_rtx_EXPR_LIST (REG_EH_REGION,
+                                      XEXP (note, 0),
+                                      REG_NOTES (insn));
              insn = PREV_INSN (insn);
            }
+         break;
 
-         /* If we are splitting a CALL_INSN, look for the CALL_INSN
-            in SEQ and copy our CALL_INSN_FUNCTION_USAGE to it.  */
-         if (GET_CODE (trial) == CALL_INSN)
+       case REG_NORETURN:
+       case REG_SETJMP:
+       case REG_ALWAYS_RETURN:
+         insn = insn_last;
+         while (insn != NULL_RTX)
            {
-             insn = insn_last;
-             while (insn != NULL_RTX)
-               {
-                 if (GET_CODE (insn) == CALL_INSN)
-                   CALL_INSN_FUNCTION_USAGE (insn)
-                     = CALL_INSN_FUNCTION_USAGE (trial);
-
-                 insn = PREV_INSN (insn);
-               }
+             if (GET_CODE (insn) == CALL_INSN)
+               REG_NOTES (insn)
+                 = gen_rtx_EXPR_LIST (REG_NOTE_KIND (note),
+                                      XEXP (note, 0),
+                                      REG_NOTES (insn));
+             insn = PREV_INSN (insn);
            }
+         break;
 
-         /* Copy notes, particularly those related to the CFG.  */
-         for (note = REG_NOTES (trial); note; note = XEXP (note, 1))
+       case REG_NON_LOCAL_GOTO:
+         insn = insn_last;
+         while (insn != NULL_RTX)
            {
-             switch (REG_NOTE_KIND (note))
-               {
-               case REG_EH_REGION:
-                 insn = insn_last;
-                 while (insn != NULL_RTX)
-                   {
-                     if (GET_CODE (insn) == CALL_INSN
-                         || (flag_non_call_exceptions
-                             && may_trap_p (PATTERN (insn))))
-                       REG_NOTES (insn)
-                         = gen_rtx_EXPR_LIST (REG_EH_REGION,
-                                              XEXP (note, 0),
-                                              REG_NOTES (insn));
-                     insn = PREV_INSN (insn);
-                   }
-                 break;
-
-               case REG_NORETURN:
-               case REG_SETJMP:
-               case REG_ALWAYS_RETURN:
-                 insn = insn_last;
-                 while (insn != NULL_RTX)
-                   {
-                     if (GET_CODE (insn) == CALL_INSN)
-                       REG_NOTES (insn)
-                         = gen_rtx_EXPR_LIST (REG_NOTE_KIND (note),
-                                              XEXP (note, 0),
-                                              REG_NOTES (insn));
-                     insn = PREV_INSN (insn);
-                   }
-                 break;
-
-               case REG_NON_LOCAL_GOTO:
-                 insn = insn_last;
-                 while (insn != NULL_RTX)
-                   {
-                     if (GET_CODE (insn) == JUMP_INSN)
-                       REG_NOTES (insn)
-                         = gen_rtx_EXPR_LIST (REG_NOTE_KIND (note),
-                                              XEXP (note, 0),
-                                              REG_NOTES (insn));
-                     insn = PREV_INSN (insn);
-                   }
-                 break;
-
-               default:
-                 break;
-               }
+             if (GET_CODE (insn) == JUMP_INSN)
+               REG_NOTES (insn)
+                 = gen_rtx_EXPR_LIST (REG_NOTE_KIND (note),
+                                      XEXP (note, 0),
+                                      REG_NOTES (insn));
+             insn = PREV_INSN (insn);
            }
+         break;
 
-         /* If there are LABELS inside the split insns increment the
-            usage count so we don't delete the label.  */
-         if (GET_CODE (trial) == INSN)
-           {
-             insn = insn_last;
-             while (insn != NULL_RTX)
-               {
-                 if (GET_CODE (insn) == INSN)
-                   mark_label_nuses (PATTERN (insn));
+       default:
+         break;
+       }
+    }
 
-                 insn = PREV_INSN (insn);
-               }
-           }
+  /* If there are LABELS inside the split insns increment the
+     usage count so we don't delete the label.  */
+  if (GET_CODE (trial) == INSN)
+    {
+      insn = insn_last;
+      while (insn != NULL_RTX)
+       {
+         if (GET_CODE (insn) == INSN)
+           mark_label_nuses (PATTERN (insn));
 
-         tem = emit_insn_after_scope (seq, trial, INSN_SCOPE (trial));
+         insn = PREV_INSN (insn);
+       }
+    }
 
-         delete_insn (trial);
-         if (has_barrier)
-           emit_barrier_after (tem);
+  tem = emit_insn_after_scope (seq, trial, INSN_SCOPE (trial));
 
-         /* Recursively call try_split for each new insn created; by the
-            time control returns here that insn will be fully split, so
-            set LAST and continue from the insn after the one returned.
-            We can't use next_active_insn here since AFTER may be a note.
-            Ignore deleted insns, which can be occur if not optimizing.  */
-         for (tem = NEXT_INSN (before); tem != after; tem = NEXT_INSN (tem))
-           if (! INSN_DELETED_P (tem) && INSN_P (tem))
-             tem = try_split (PATTERN (tem), tem, 1);
-       }
-      /* Avoid infinite loop if the result matches the original pattern.  */
-      else if (rtx_equal_p (PATTERN (seq), pat))
-       return trial;
-      else
-       {
-         PATTERN (trial) = PATTERN (seq);
-         INSN_CODE (trial) = -1;
-         try_split (PATTERN (trial), trial, last);
-       }
+  delete_insn (trial);
+  if (has_barrier)
+    emit_barrier_after (tem);
 
-      /* Return either the first or the last insn, depending on which was
-        requested.  */
-      return last
-               ? (after ? PREV_INSN (after) : last_insn)
-               : NEXT_INSN (before);
-    }
+  /* Recursively call try_split for each new insn created; by the
+     time control returns here that insn will be fully split, so
+     set LAST and continue from the insn after the one returned.
+     We can't use next_active_insn here since AFTER may be a note.
+     Ignore deleted insns, which can be occur if not optimizing.  */
+  for (tem = NEXT_INSN (before); tem != after; tem = NEXT_INSN (tem))
+    if (! INSN_DELETED_P (tem) && INSN_P (tem))
+      tem = try_split (PATTERN (tem), tem, 1);
 
-  return trial;
+  /* Return either the first or the last insn, depending on which was
+     requested.  */
+  return last
+    ? (after ? PREV_INSN (after) : last_insn)
+    : NEXT_INSN (before);
 }
 \f
 /* Make and return an INSN rtx, initializing all its slots.
@@ -5574,6 +5559,10 @@ init_emit_once (line_numbers)
   REAL_VALUE_FROM_INT (dconst1,   1,  0, double_mode);
   REAL_VALUE_FROM_INT (dconst2,   2,  0, double_mode);
   REAL_VALUE_FROM_INT (dconstm1, -1, -1, double_mode);
+  REAL_VALUE_FROM_INT (dconstm2, -2, -1, double_mode);
+
+  dconsthalf = dconst1;
+  dconsthalf.exp--;
 
   for (i = 0; i <= 2; i++)
     {