OSDN Git Service

PR c/39902
[pf3gnuchains/gcc-fork.git] / gcc / recog.c
index 7ab6a1d..138b03b 100644 (file)
@@ -1,6 +1,6 @@
 /* Subroutines used by or related to instruction recognition.
    Copyright (C) 1987, 1988, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998
-   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
+   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
    Free Software Foundation, Inc.
 
 This file is part of GCC.
@@ -77,7 +77,7 @@ static rtx split_insn (rtx);
    This should be 0 if you are generating rtl, such as if you are calling
    the functions in optabs.c and expmed.c (most of the time).
    This should be 1 if all valid insns need to be recognized,
-   such as in regclass.c and final.c and reload.c.
+   such as in reginfo.c and final.c and reload.c.
 
    init_recog and init_recog_no_volatile are responsible for setting this.  */
 
@@ -156,10 +156,7 @@ check_asm_operands (rtx x)
       const char *c = constraints[i];
       if (c[0] == '%')
        c++;
-      if (ISDIGIT ((unsigned char) c[0]) && c[1] == '\0')
-       c = constraints[c[0] - '0'];
-
-      if (! asm_operand_ok (operands[i], c))
+      if (! asm_operand_ok (operands[i], c, constraints))
        return 0;
     }
 
@@ -382,6 +379,16 @@ verify_changes (int num)
          if (! memory_address_p (GET_MODE (object), XEXP (object, 0)))
            break;
        }
+      else if (REG_P (changes[i].old)
+              && asm_noperands (PATTERN (object)) > 0
+              && REG_EXPR (changes[i].old) != NULL_TREE
+              && DECL_ASSEMBLER_NAME_SET_P (REG_EXPR (changes[i].old))
+              && DECL_REGISTER (REG_EXPR (changes[i].old)))
+       {
+         /* Don't allow changes of hard register operands to inline
+            assemblies if they have been defined as register asm ("x").  */
+         break;
+       }
       else if (insn_invalid_p (object))
        {
          rtx pat = PATTERN (object);
@@ -543,13 +550,13 @@ simplify_while_replacing (rtx *loc, rtx to, rtx object,
          simplify_gen_binary to try to simplify it.
          ??? We may want later to remove this, once simplification is
          separated from this function.  */
-      if (GET_CODE (XEXP (x, 1)) == CONST_INT && XEXP (x, 1) == to)
+      if (CONST_INT_P (XEXP (x, 1)) && XEXP (x, 1) == to)
        validate_change (object, loc,
                         simplify_gen_binary
                         (PLUS, GET_MODE (x), XEXP (x, 0), XEXP (x, 1)), 1);
       break;
     case MINUS:
-      if (GET_CODE (XEXP (x, 1)) == CONST_INT
+      if (CONST_INT_P (XEXP (x, 1))
          || GET_CODE (XEXP (x, 1)) == CONST_DOUBLE)
        validate_change (object, loc,
                         simplify_gen_binary
@@ -590,8 +597,8 @@ simplify_while_replacing (rtx *loc, rtx to, rtx object,
          happen, we might just fail in some cases).  */
 
       if (MEM_P (XEXP (x, 0))
-         && GET_CODE (XEXP (x, 1)) == CONST_INT
-         && GET_CODE (XEXP (x, 2)) == CONST_INT
+         && CONST_INT_P (XEXP (x, 1))
+         && CONST_INT_P (XEXP (x, 2))
          && !mode_dependent_address_p (XEXP (XEXP (x, 0), 0))
          && !MEM_VOLATILE_P (XEXP (x, 0)))
        {
@@ -731,6 +738,17 @@ validate_replace_rtx_1 (rtx *loc, rtx from, rtx to, rtx object,
     simplify_while_replacing (loc, to, object, op0_mode);
 }
 
+/* Try replacing every occurrence of FROM in subexpression LOC of INSN
+   with TO.  After all changes have been made, validate by seeing
+   if INSN is still valid.  */
+
+int
+validate_replace_rtx_subexp (rtx from, rtx to, rtx insn, rtx *loc)
+{
+  validate_replace_rtx_1 (loc, from, to, insn, true);
+  return apply_change_group ();
+}
+
 /* Try replacing every occurrence of FROM in INSN with TO.  After all
    changes have been made, validate by seeing if INSN is still valid.  */
 
@@ -894,7 +912,7 @@ general_operand (rtx op, enum machine_mode mode)
       && GET_MODE_CLASS (mode) != MODE_PARTIAL_INT)
     return 0;
 
-  if (GET_CODE (op) == CONST_INT
+  if (CONST_INT_P (op)
       && mode != VOIDmode
       && trunc_int_for_mode (INTVAL (op), mode) != INTVAL (op))
     return 0;
@@ -1071,7 +1089,7 @@ immediate_operand (rtx op, enum machine_mode mode)
       && GET_MODE_CLASS (mode) != MODE_PARTIAL_INT)
     return 0;
 
-  if (GET_CODE (op) == CONST_INT
+  if (CONST_INT_P (op)
       && mode != VOIDmode
       && trunc_int_for_mode (INTVAL (op), mode) != INTVAL (op))
     return 0;
@@ -1088,7 +1106,7 @@ immediate_operand (rtx op, enum machine_mode mode)
 int
 const_int_operand (rtx op, enum machine_mode mode)
 {
-  if (GET_CODE (op) != CONST_INT)
+  if (!CONST_INT_P (op))
     return 0;
 
   if (mode != VOIDmode
@@ -1111,7 +1129,7 @@ const_double_operand (rtx op, enum machine_mode mode)
       && GET_MODE_CLASS (mode) != MODE_PARTIAL_INT)
     return 0;
 
-  return ((GET_CODE (op) == CONST_DOUBLE || GET_CODE (op) == CONST_INT)
+  return ((GET_CODE (op) == CONST_DOUBLE || CONST_INT_P (op))
          && (mode == VOIDmode || GET_MODE (op) == mode
              || GET_MODE (op) == VOIDmode));
 }
@@ -1138,7 +1156,7 @@ nonmemory_operand (rtx op, enum machine_mode mode)
          && GET_MODE_CLASS (mode) != MODE_PARTIAL_INT)
        return 0;
 
-      if (GET_CODE (op) == CONST_INT
+      if (CONST_INT_P (op)
          && mode != VOIDmode
          && trunc_int_for_mode (INTVAL (op), mode) != INTVAL (op))
        return 0;
@@ -1205,7 +1223,7 @@ push_operand (rtx op, enum machine_mode mode)
       if (GET_CODE (op) != PRE_MODIFY
          || GET_CODE (XEXP (op, 1)) != PLUS
          || XEXP (XEXP (op, 1), 0) != XEXP (op, 0)
-         || GET_CODE (XEXP (XEXP (op, 1), 1)) != CONST_INT
+         || !CONST_INT_P (XEXP (XEXP (op, 1), 1))
 #ifdef STACK_GROWS_DOWNWARD
          || INTVAL (XEXP (XEXP (op, 1), 1)) != - (int) rounded_size
 #else
@@ -1246,11 +1264,15 @@ pop_operand (rtx op, enum machine_mode mode)
 int
 memory_address_p (enum machine_mode mode ATTRIBUTE_UNUSED, rtx addr)
 {
+#ifdef GO_IF_LEGITIMATE_ADDRESS
   GO_IF_LEGITIMATE_ADDRESS (mode, addr, win);
   return 0;
 
  win:
   return 1;
+#else
+  return targetm.legitimate_address_p (mode, addr, 0);
+#endif
 }
 
 /* Return 1 if OP is a valid memory reference with mode MODE,
@@ -1302,7 +1324,7 @@ indirect_operand (rtx op, enum machine_mode mode)
 
       return ((offset == 0 && general_operand (XEXP (inner, 0), Pmode))
              || (GET_CODE (XEXP (inner, 0)) == PLUS
-                 && GET_CODE (XEXP (XEXP (inner, 0), 1)) == CONST_INT
+                 && CONST_INT_P (XEXP (XEXP (inner, 0), 1))
                  && INTVAL (XEXP (XEXP (inner, 0), 1)) == -offset
                  && general_operand (XEXP (XEXP (inner, 0), 0), Pmode)));
     }
@@ -1312,6 +1334,32 @@ indirect_operand (rtx op, enum machine_mode mode)
          && general_operand (XEXP (op, 0), Pmode));
 }
 
+/* Return 1 if this is an ordered comparison operator (not including
+   ORDERED and UNORDERED).  */
+
+int
+ordered_comparison_operator (rtx op, enum machine_mode mode)
+{
+  if (mode != VOIDmode && GET_MODE (op) != mode)
+    return false;
+  switch (GET_CODE (op))
+    {
+    case EQ:
+    case NE:
+    case LT:
+    case LTU:
+    case LE:
+    case LEU:
+    case GT:
+    case GTU:
+    case GE:
+    case GEU:
+      return true;
+    default:
+      return false;
+    }
+}
+
 /* Return 1 if this is a comparison operator.  This allows the use of
    MATCH_OPERATOR to recognize all the branch insns.  */
 
@@ -1547,7 +1595,7 @@ decode_asm_operands (rtx body, rtx *operands, rtx **operand_locs,
    Return > 0 if ok, = 0 if bad, < 0 if inconclusive.  */
 
 int
-asm_operand_ok (rtx op, const char *constraint)
+asm_operand_ok (rtx op, const char *constraint, const char **constraints)
 {
   int result = 0;
 
@@ -1575,15 +1623,29 @@ asm_operand_ok (rtx op, const char *constraint)
 
        case '0': case '1': case '2': case '3': case '4':
        case '5': case '6': case '7': case '8': case '9':
-         /* For best results, our caller should have given us the
-            proper matching constraint, but we can't actually fail
-            the check if they didn't.  Indicate that results are
-            inconclusive.  */
-         do
-           constraint++;
-         while (ISDIGIT (*constraint));
-         if (! result)
-           result = -1;
+         /* If caller provided constraints pointer, look up
+            the maching constraint.  Otherwise, our caller should have
+            given us the proper matching constraint, but we can't
+            actually fail the check if they didn't.  Indicate that
+            results are inconclusive.  */
+         if (constraints)
+           {
+             char *end;
+             unsigned long match;
+
+             match = strtoul (constraint, &end, 10);
+             if (!result)
+               result = asm_operand_ok (op, constraints[match], NULL);
+             constraint = (const char *) end;
+           }
+         else
+           {
+             do
+               constraint++;
+             while (ISDIGIT (*constraint));
+             if (! result)
+               result = -1;
+           }
          continue;
 
        case 'p':
@@ -1645,7 +1707,7 @@ asm_operand_ok (rtx op, const char *constraint)
          break;
 
        case 's':
-         if (GET_CODE (op) == CONST_INT
+         if (CONST_INT_P (op)
              || (GET_CODE (op) == CONST_DOUBLE
                  && GET_MODE (op) == VOIDmode))
            break;
@@ -1657,49 +1719,49 @@ asm_operand_ok (rtx op, const char *constraint)
          break;
 
        case 'n':
-         if (GET_CODE (op) == CONST_INT
+         if (CONST_INT_P (op)
              || (GET_CODE (op) == CONST_DOUBLE
                  && GET_MODE (op) == VOIDmode))
            result = 1;
          break;
 
        case 'I':
-         if (GET_CODE (op) == CONST_INT
+         if (CONST_INT_P (op)
              && CONST_OK_FOR_CONSTRAINT_P (INTVAL (op), 'I', constraint))
            result = 1;
          break;
        case 'J':
-         if (GET_CODE (op) == CONST_INT
+         if (CONST_INT_P (op)
              && CONST_OK_FOR_CONSTRAINT_P (INTVAL (op), 'J', constraint))
            result = 1;
          break;
        case 'K':
-         if (GET_CODE (op) == CONST_INT
+         if (CONST_INT_P (op)
              && CONST_OK_FOR_CONSTRAINT_P (INTVAL (op), 'K', constraint))
            result = 1;
          break;
        case 'L':
-         if (GET_CODE (op) == CONST_INT
+         if (CONST_INT_P (op)
              && CONST_OK_FOR_CONSTRAINT_P (INTVAL (op), 'L', constraint))
            result = 1;
          break;
        case 'M':
-         if (GET_CODE (op) == CONST_INT
+         if (CONST_INT_P (op)
              && CONST_OK_FOR_CONSTRAINT_P (INTVAL (op), 'M', constraint))
            result = 1;
          break;
        case 'N':
-         if (GET_CODE (op) == CONST_INT
+         if (CONST_INT_P (op)
              && CONST_OK_FOR_CONSTRAINT_P (INTVAL (op), 'N', constraint))
            result = 1;
          break;
        case 'O':
-         if (GET_CODE (op) == CONST_INT
+         if (CONST_INT_P (op)
              && CONST_OK_FOR_CONSTRAINT_P (INTVAL (op), 'O', constraint))
            result = 1;
          break;
        case 'P':
-         if (GET_CODE (op) == CONST_INT
+         if (CONST_INT_P (op)
              && CONST_OK_FOR_CONSTRAINT_P (INTVAL (op), 'P', constraint))
            result = 1;
          break;
@@ -2485,7 +2547,7 @@ constrain_operands (int strict)
                break;
 
              case 's':
-               if (GET_CODE (op) == CONST_INT
+               if (CONST_INT_P (op)
                    || (GET_CODE (op) == CONST_DOUBLE
                        && GET_MODE (op) == VOIDmode))
                  break;
@@ -2495,7 +2557,7 @@ constrain_operands (int strict)
                break;
 
              case 'n':
-               if (GET_CODE (op) == CONST_INT
+               if (CONST_INT_P (op)
                    || (GET_CODE (op) == CONST_DOUBLE
                        && GET_MODE (op) == VOIDmode))
                  win = 1;
@@ -2509,7 +2571,7 @@ constrain_operands (int strict)
              case 'N':
              case 'O':
              case 'P':
-               if (GET_CODE (op) == CONST_INT
+               if (CONST_INT_P (op)
                    && CONST_OK_FOR_CONSTRAINT_P (INTVAL (op), c, p))
                  win = 1;
                break;
@@ -3005,6 +3067,26 @@ peep2_find_free_register (int from, int to, const char *class_str,
   return NULL_RTX;
 }
 
+/* Forget all currently tracked instructions, only remember current
+   LIVE regset.  */
+
+static void
+peep2_reinit_state (regset live)
+{
+  int i;
+
+  /* Indicate that all slots except the last holds invalid data.  */
+  for (i = 0; i < MAX_INSNS_PER_PEEP2; ++i)
+    peep2_insn_data[i].insn = NULL_RTX;
+  peep2_current_count = 0;
+
+  /* Indicate that the last slot contains live_after data.  */
+  peep2_insn_data[MAX_INSNS_PER_PEEP2].insn = PEEP2_EOB;
+  peep2_current = MAX_INSNS_PER_PEEP2;
+
+  COPY_REG_SET (peep2_insn_data[MAX_INSNS_PER_PEEP2].live_before, live);
+}
+
 /* Perform the peephole2 optimization pass.  */
 
 static void
@@ -3028,19 +3110,11 @@ peephole2_optimize (void)
   FOR_EACH_BB_REVERSE (bb)
     {
       rtl_profile_for_bb (bb);
-      /* Indicate that all slots except the last holds invalid data.  */
-      for (i = 0; i < MAX_INSNS_PER_PEEP2; ++i)
-       peep2_insn_data[i].insn = NULL_RTX;
-      peep2_current_count = 0;
-
-      /* Indicate that the last slot contains live_after data.  */
-      peep2_insn_data[MAX_INSNS_PER_PEEP2].insn = PEEP2_EOB;
-      peep2_current = MAX_INSNS_PER_PEEP2;
 
       /* Start up propagation.  */
       bitmap_copy (live, DF_LR_OUT (bb));
-      df_simulate_artificial_refs_at_end (bb, live);
-      bitmap_copy (peep2_insn_data[MAX_INSNS_PER_PEEP2].live_before, live);
+      df_simulate_initialize_backwards (bb, live);
+      peep2_reinit_state (live);
 
       for (insn = BB_END (bb); ; insn = prev)
        {
@@ -3059,7 +3133,7 @@ peephole2_optimize (void)
                  && peep2_insn_data[peep2_current].insn == NULL_RTX)
                peep2_current_count++;
              peep2_insn_data[peep2_current].insn = insn;
-             df_simulate_one_insn (bb, insn, live);
+             df_simulate_one_insn_backwards (bb, insn, live);
              COPY_REG_SET (peep2_insn_data[peep2_current].live_before, live);
 
              if (RTX_FRAME_RELATED_P (insn))
@@ -3067,7 +3141,7 @@ peephole2_optimize (void)
                  /* If an insn has RTX_FRAME_RELATED_P set, peephole
                     substitution would lose the
                     REG_FRAME_RELATED_EXPR that is attached.  */
-                 peep2_current_count = 0;
+                 peep2_reinit_state (live);
                  attempt = NULL;
                }
              else
@@ -3218,7 +3292,7 @@ peephole2_optimize (void)
                            peep2_current_count++;
                          peep2_insn_data[i].insn = x;
                          df_insn_rescan (x);
-                         df_simulate_one_insn (bb, x, live);
+                         df_simulate_one_insn_backwards (bb, x, live);
                          bitmap_copy (peep2_insn_data[i].live_before, live);
                        }
                      x = PREV_INSN (x);
@@ -3453,7 +3527,7 @@ struct rtl_opt_pass pass_split_all_insns =
   NULL,                                 /* sub */
   NULL,                                 /* next */
   0,                                    /* static_pass_number */
-  0,                                    /* tv_id */
+  TV_NONE,                              /* tv_id */
   0,                                    /* properties_required */
   0,                                    /* properties_provided */
   0,                                    /* properties_destroyed */
@@ -3483,7 +3557,7 @@ struct rtl_opt_pass pass_split_after_reload =
   NULL,                                 /* sub */
   NULL,                                 /* next */
   0,                                    /* static_pass_number */
-  0,                                    /* tv_id */
+  TV_NONE,                              /* tv_id */
   0,                                    /* properties_required */
   0,                                    /* properties_provided */
   0,                                    /* properties_destroyed */
@@ -3527,7 +3601,7 @@ struct rtl_opt_pass pass_split_before_regstack =
   NULL,                                 /* sub */
   NULL,                                 /* next */
   0,                                    /* static_pass_number */
-  0,                                    /* tv_id */
+  TV_NONE,                              /* tv_id */
   0,                                    /* properties_required */
   0,                                    /* properties_provided */
   0,                                    /* properties_destroyed */
@@ -3565,7 +3639,7 @@ struct rtl_opt_pass pass_split_before_sched2 =
   NULL,                                 /* sub */
   NULL,                                 /* next */
   0,                                    /* static_pass_number */
-  0,                                    /* tv_id */
+  TV_NONE,                              /* tv_id */
   0,                                    /* properties_required */
   0,                                    /* properties_provided */
   0,                                    /* properties_destroyed */
@@ -3597,7 +3671,7 @@ struct rtl_opt_pass pass_split_for_shorten_branches =
   NULL,                                 /* sub */
   NULL,                                 /* next */
   0,                                    /* static_pass_number */
-  0,                                    /* tv_id */
+  TV_NONE,                              /* tv_id */
   0,                                    /* properties_required */
   0,                                    /* properties_provided */
   0,                                    /* properties_destroyed */
@@ -3605,5 +3679,3 @@ struct rtl_opt_pass pass_split_for_shorten_branches =
   TODO_dump_func | TODO_verify_rtl_sharing /* todo_flags_finish */
  }
 };
-
-