OSDN Git Service

2014-02-26 Fabien Chene <fabien@gcc.gnu.org>
[pf3gnuchains/gcc-fork.git] / gcc / recog.c
index 9331681..32ed021 100644 (file)
@@ -118,6 +118,25 @@ init_recog (void)
 }
 
 \f
+/* Return true if labels in asm operands BODY are LABEL_REFs.  */
+
+static bool
+asm_labels_ok (rtx body)
+{
+  rtx asmop;
+  int i;
+
+  asmop = extract_asm_operands (body);
+  if (asmop == NULL_RTX)
+    return true;
+
+  for (i = 0; i < ASM_OPERANDS_LABEL_LENGTH (asmop); i++)
+    if (GET_CODE (ASM_OPERANDS_LABEL (asmop, i)) != LABEL_REF)
+      return false;
+
+  return true;
+}
+
 /* Check that X is an insn-body for an `asm' with operands
    and that the operands mentioned in it are legitimate.  */
 
@@ -129,6 +148,9 @@ check_asm_operands (rtx x)
   const char **constraints;
   int i;
 
+  if (!asm_labels_ok (x))
+    return 0;
+
   /* Post-reload, be more strict with things.  */
   if (reload_completed)
     {
@@ -903,10 +925,7 @@ next_insn_tests_no_inequality (rtx insn)
    it has.
 
    The main use of this function is as a predicate in match_operand
-   expressions in the machine description.
-
-   For an explanation of this function's behavior for registers of
-   class NO_REGS, see the comment for `register_operand'.  */
+   expressions in the machine description.  */
 
 int
 general_operand (rtx op, enum machine_mode mode)
@@ -976,9 +995,8 @@ general_operand (rtx op, enum machine_mode mode)
     }
 
   if (code == REG)
-    /* A register whose class is NO_REGS is not a general operand.  */
     return (REGNO (op) >= FIRST_PSEUDO_REGISTER
-           || REGNO_REG_CLASS (REGNO (op)) != NO_REGS);
+           || in_hard_reg_set_p (operand_reg_set, GET_MODE (op), REGNO (op)));
 
   if (code == MEM)
     {
@@ -1011,15 +1029,7 @@ address_operand (rtx op, enum machine_mode mode)
    If MODE is VOIDmode, accept a register in any mode.
 
    The main use of this function is as a predicate in match_operand
-   expressions in the machine description.
-
-   As a special exception, registers whose class is NO_REGS are
-   not accepted by `register_operand'.  The reason for this change
-   is to allow the representation of special architecture artifacts
-   (such as a condition code register) without extending the rtl
-   definitions.  Since registers of class NO_REGS cannot be used
-   as registers in any case where register classes are examined,
-   it is most consistent to keep this function from accepting them.  */
+   expressions in the machine description.  */
 
 int
 register_operand (rtx op, enum machine_mode mode)
@@ -1058,11 +1068,10 @@ register_operand (rtx op, enum machine_mode mode)
       op = sub;
     }
 
-  /* We don't consider registers whose class is NO_REGS
-     to be a register operand.  */
   return (REG_P (op)
          && (REGNO (op) >= FIRST_PSEUDO_REGISTER
-             || REGNO_REG_CLASS (REGNO (op)) != NO_REGS));
+             || in_hard_reg_set_p (operand_reg_set,
+                                   GET_MODE (op), REGNO (op))));
 }
 
 /* Return 1 for a register in Pmode; ignore the tested mode.  */
@@ -1181,11 +1190,10 @@ nonmemory_operand (rtx op, enum machine_mode mode)
       op = SUBREG_REG (op);
     }
 
-  /* We don't consider registers whose class is NO_REGS
-     to be a register operand.  */
   return (REG_P (op)
          && (REGNO (op) >= FIRST_PSEUDO_REGISTER
-             || REGNO_REG_CLASS (REGNO (op)) != NO_REGS));
+             || in_hard_reg_set_p (operand_reg_set,
+                                   GET_MODE (op), REGNO (op))));
 }
 
 /* Return 1 if OP is a valid operand that stands for pushing a
@@ -2259,7 +2267,8 @@ preprocess_constraints (void)
                case 'p':
                  op_alt[j].is_address = 1;
                  op_alt[j].cl = reg_class_subunion[(int) op_alt[j].cl]
-                     [(int) base_reg_class (VOIDmode, ADDRESS, SCRATCH)];
+                     [(int) base_reg_class (VOIDmode, ADDR_SPACE_GENERIC,
+                                            ADDRESS, SCRATCH)];
                  break;
 
                case 'g':
@@ -2280,8 +2289,8 @@ preprocess_constraints (void)
                      op_alt[j].cl
                        = (reg_class_subunion
                           [(int) op_alt[j].cl]
-                          [(int) base_reg_class (VOIDmode, ADDRESS,
-                                                 SCRATCH)]);
+                          [(int) base_reg_class (VOIDmode, ADDR_SPACE_GENERIC,
+                                                 ADDRESS, SCRATCH)]);
                      break;
                    }
 
@@ -2664,6 +2673,16 @@ constrain_operands (int strict)
                           /* Every address operand can be reloaded to fit.  */
                           && strict < 0)
                    win = 1;
+                 /* Cater to architectures like IA-64 that define extra memory
+                    constraints without using define_memory_constraint.  */
+                 else if (reload_in_progress
+                          && REG_P (op)
+                          && REGNO (op) >= FIRST_PSEUDO_REGISTER
+                          && reg_renumber[REGNO (op)] < 0
+                          && reg_equiv_mem (REGNO (op)) != 0
+                          && EXTRA_CONSTRAINT_STR
+                             (reg_equiv_mem (REGNO (op)), c, p))
+                   win = 1;
 #endif
                  break;
                }
@@ -3011,6 +3030,9 @@ peep2_reg_dead_p (int ofs, rtx reg)
   return 1;
 }
 
+/* Regno offset to be used in the register search.  */
+static int search_ofs;
+
 /* Try to find a hard register of mode MODE, matching the register class in
    CLASS_STR, which is available at the beginning of insn CURRENT_INSN and
    remains available until the end of LAST_INSN.  LAST_INSN may be NULL_RTX,
@@ -3026,9 +3048,9 @@ rtx
 peep2_find_free_register (int from, int to, const char *class_str,
                          enum machine_mode mode, HARD_REG_SET *reg_set)
 {
-  static int search_ofs;
   enum reg_class cl;
   HARD_REG_SET live;
+  df_ref *def_rec;
   int i;
 
   gcc_assert (from < MAX_INSNS_PER_PEEP2 + 1);
@@ -3042,12 +3064,14 @@ peep2_find_free_register (int from, int to, const char *class_str,
 
   while (from != to)
     {
-      HARD_REG_SET this_live;
+      gcc_assert (peep2_insn_data[from].insn != NULL_RTX);
+
+      /* Don't use registers set or clobbered by the insn.  */
+      for (def_rec = DF_INSN_DEFS (peep2_insn_data[from].insn);
+          *def_rec; def_rec++)
+       SET_HARD_REG_BIT (live, DF_REF_REGNO (*def_rec));
 
       from = peep2_buf_position (from + 1);
-      gcc_assert (peep2_insn_data[from].insn != NULL_RTX);
-      REG_SET_TO_HARD_REG_SET (this_live, peep2_insn_data[from].live_before);
-      IOR_HARD_REG_SET (live, this_live);
     }
 
   cl = (class_str[0] == 'r' ? GENERAL_REGS
@@ -3146,16 +3170,17 @@ static rtx
 peep2_attempt (basic_block bb, rtx insn, int match_len, rtx attempt)
 {
   int i;
-  rtx last, note, before_try, x;
+  rtx last, eh_note, as_note, before_try, x;
   rtx old_insn, new_insn;
   bool was_call = false;
 
-  /* If we are splittind an RTX_FRAME_RELATED_P insn, do not allow it to
+  /* If we are splitting an RTX_FRAME_RELATED_P insn, do not allow it to
      match more than one insn, or to be split into more than one insn.  */
   old_insn = peep2_insn_data[peep2_current].insn;
   if (RTX_FRAME_RELATED_P (old_insn))
     {
       bool any_note = false;
+      rtx note;
 
       if (match_len != 0)
        return NULL;
@@ -3236,6 +3261,7 @@ peep2_attempt (basic_block bb, rtx insn, int match_len, rtx attempt)
   for (i = 0; i <= match_len; ++i)
     {
       int j;
+      rtx note;
 
       j = peep2_buf_position (peep2_current + i);
       old_insn = peep2_insn_data[j].insn;
@@ -3263,6 +3289,7 @@ peep2_attempt (basic_block bb, rtx insn, int match_len, rtx attempt)
          {
          case REG_NORETURN:
          case REG_SETJMP:
+         case REG_TM:
            add_reg_note (new_insn, REG_NOTE_KIND (note),
                          XEXP (note, 0));
            break;
@@ -3281,9 +3308,21 @@ peep2_attempt (basic_block bb, rtx insn, int match_len, rtx attempt)
       break;
     }
 
-  i = peep2_buf_position (peep2_current + match_len);
+  /* If we matched any instruction that had a REG_ARGS_SIZE, then
+     move those notes over to the new sequence.  */
+  as_note = NULL;
+  for (i = match_len; i >= 0; --i)
+    {
+      int j = peep2_buf_position (peep2_current + i);
+      old_insn = peep2_insn_data[j].insn;
+
+      as_note = find_reg_note (old_insn, REG_ARGS_SIZE, NULL);
+      if (as_note)
+       break;
+    }
 
-  note = find_reg_note (peep2_insn_data[i].insn, REG_EH_REGION, NULL_RTX);
+  i = peep2_buf_position (peep2_current + match_len);
+  eh_note = find_reg_note (peep2_insn_data[i].insn, REG_EH_REGION, NULL_RTX);
 
   /* Replace the old sequence with the new.  */
   last = emit_insn_after_setloc (attempt,
@@ -3293,7 +3332,7 @@ peep2_attempt (basic_block bb, rtx insn, int match_len, rtx attempt)
   delete_insn_chain (insn, peep2_insn_data[i].insn, false);
 
   /* Re-insert the EH_REGION notes.  */
-  if (note || (was_call && nonlocal_goto_handler_labels))
+  if (eh_note || (was_call && nonlocal_goto_handler_labels))
     {
       edge eh_edge;
       edge_iterator ei;
@@ -3302,8 +3341,8 @@ peep2_attempt (basic_block bb, rtx insn, int match_len, rtx attempt)
        if (eh_edge->flags & (EDGE_EH | EDGE_ABNORMAL_CALL))
          break;
 
-      if (note)
-       copy_reg_eh_region_note_backward (note, last, before_try);
+      if (eh_note)
+       copy_reg_eh_region_note_backward (eh_note, last, before_try);
 
       if (eh_edge)
        for (x = last; x != before_try; x = PREV_INSN (x))
@@ -3336,6 +3375,10 @@ peep2_attempt (basic_block bb, rtx insn, int match_len, rtx attempt)
       peep2_do_cleanup_cfg |= purge_dead_edges (bb);
     }
 
+  /* Re-insert the ARGS_SIZE notes.  */
+  if (as_note)
+    fixup_args_size_notes (before_try, last, INTVAL (XEXP (as_note, 0)));
+
   /* If we generated a jump instruction, it won't have
      JUMP_LABEL set.  Recompute after we're done.  */
   for (x = last; x != before_try; x = PREV_INSN (x))
@@ -3447,6 +3490,7 @@ peephole2_optimize (void)
   /* Initialize the regsets we're going to use.  */
   for (i = 0; i < MAX_INSNS_PER_PEEP2 + 1; ++i)
     peep2_insn_data[i].live_before = BITMAP_ALLOC (&reg_obstack);
+  search_ofs = 0;
   live = BITMAP_ALLOC (&reg_obstack);
 
   FOR_EACH_BB_REVERSE (bb)