OSDN Git Service

* config.gcc: Add an extra_header for ARM targets.
[pf3gnuchains/gcc-fork.git] / gcc / local-alloc.c
index 780523b..8e06b8d 100644 (file)
@@ -1,6 +1,6 @@
 /* Allocate registers within a basic block, for GNU compiler.
    Copyright (C) 1987, 1988, 1991, 1993, 1994, 1995, 1996, 1997, 1998,
-   1999, 2000, 2001 Free Software Foundation, Inc.
+   1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -61,10 +61,12 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 
 #include "config.h"
 #include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "hard-reg-set.h"
 #include "rtl.h"
 #include "tm_p.h"
 #include "flags.h"
-#include "hard-reg-set.h"
 #include "basic-block.h"
 #include "regs.h"
 #include "function.h"
@@ -74,12 +76,13 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include "output.h"
 #include "toplev.h"
 #include "except.h"
+#include "integrate.h"
 \f
 /* Next quantity number available for allocation.  */
 
 static int next_qty;
 
-/* Information we maitain about each quantity.  */
+/* Information we maintain about each quantity.  */
 struct qty
 {
   /* The number of refs to quantity Q.  */
@@ -143,12 +146,6 @@ struct qty
      or -1 if none was found.  */
 
   short phys_reg;
-
-  /* Nonzero if this quantity has been used in a SUBREG in some
-     way that is illegal.  */
-
-  char changes_mode;
-
 };
 
 static struct qty *qty;
@@ -244,7 +241,7 @@ static rtx this_insn;
 struct equivalence
 {
   /* Set when an attempt should be made to replace a register
-     with the associated src entry.  */
+     with the associated src_p entry.  */
 
   char replace;
 
@@ -254,7 +251,7 @@ struct equivalence
 
   rtx replacement;
 
-  rtx src;
+  rtx *src_p;
 
   /* Loop depth is used to recognize equivalences which appear
      to be present within the same loop (or in an inner loop).  */
@@ -286,9 +283,9 @@ static void update_equiv_regs       PARAMS ((void));
 static void no_equiv           PARAMS ((rtx, rtx, void *));
 static void block_alloc                PARAMS ((int));
 static int qty_sugg_compare            PARAMS ((int, int));
-static int qty_sugg_compare_1  PARAMS ((const PTR, const PTR));
+static int qty_sugg_compare_1  PARAMS ((const void *, const void *));
 static int qty_compare         PARAMS ((int, int));
-static int qty_compare_1       PARAMS ((const PTR, const PTR));
+static int qty_compare_1       PARAMS ((const void *, const void *));
 static int combine_regs                PARAMS ((rtx, rtx, int, int, rtx, int));
 static int reg_meets_class_p   PARAMS ((int, enum reg_class));
 static void update_qty_class   PARAMS ((int, int));
@@ -327,7 +324,6 @@ alloc_qty (regno, mode, size, birth)
   qty[qtyno].alternate_class = reg_alternate_class (regno);
   qty[qtyno].n_refs = REG_N_REFS (regno);
   qty[qtyno].freq = REG_FREQ (regno);
-  qty[qtyno].changes_mode = REG_CHANGES_MODE (regno);
 }
 \f
 /* Main entry point of this file.  */
@@ -335,8 +331,9 @@ alloc_qty (regno, mode, size, birth)
 int
 local_alloc ()
 {
-  int b, i;
+  int i;
   int max_qty;
+  basic_block b;
 
   /* We need to keep track of whether or not we recorded a LABEL_REF so
      that we know if the jump optimizer needs to be rerun.  */
@@ -351,7 +348,8 @@ local_alloc ()
 
   /* Promote REG_EQUAL notes to REG_EQUIV notes and adjust status of affected
      registers.  */
-  update_equiv_regs ();
+  if (optimize)
+    update_equiv_regs ();
 
   /* This sets the maximum number of quantities we can have.  Quantity
      numbers start at zero and we can have one for each pseudo.  */
@@ -392,7 +390,7 @@ local_alloc ()
 
   /* Allocate each block's local registers, block by block.  */
 
-  for (b = 0; b < n_basic_blocks; b++)
+  FOR_EACH_BB (b)
     {
       /* NEXT_QTY indicates which elements of the `qty_...'
         vectors might need to be initialized because they were used
@@ -424,7 +422,7 @@ local_alloc ()
 
       next_qty = 0;
 
-      block_alloc (b);
+      block_alloc (b->index);
     }
 
   free (qty);
@@ -538,6 +536,7 @@ equiv_init_varies_p (x)
     case CONST:
     case CONST_INT:
     case CONST_DOUBLE:
+    case CONST_VECTOR:
     case SYMBOL_REF:
     case LABEL_REF:
       return 0;
@@ -573,7 +572,7 @@ equiv_init_varies_p (x)
   return 0;
 }
 
-/* Returns non-zero if X (used to initialize register REGNO) is movable.
+/* Returns nonzero if X (used to initialize register REGNO) is movable.
    X is only movable if the registers it uses have equivalent initializations
    which appear to be within the same loop (or in an inner loop) and movable
    or if they are not candidates for local_alloc and don't vary.  */
@@ -657,10 +656,10 @@ contains_replace_regs (x)
     case LABEL_REF:
     case SYMBOL_REF:
     case CONST_DOUBLE:
+    case CONST_VECTOR:
     case PC:
     case CC0:
     case HIGH:
-    case LO_SUM:
       return 0;
 
     case REG:
@@ -707,6 +706,7 @@ memref_referenced_p (memref, x)
     case LABEL_REF:
     case SYMBOL_REF:
     case CONST_DOUBLE:
+    case CONST_VECTOR:
     case PC:
     case CC0:
     case HIGH:
@@ -778,6 +778,12 @@ memref_used_between_p (memref, start, end)
 }
 \f
 /* Return nonzero if the rtx X is invariant over the current function.  */
+/* ??? Actually, the places this is used in reload expect exactly what
+   is tested here, and not everything that is function invariant.  In
+   particular, the frame pointer and arg pointer are special cased;
+   pic_offset_table_rtx is not, and this will cause aborts when we
+   go to spill these things to memory.  */
+
 int
 function_invariant_p (x)
      rtx x;
@@ -805,7 +811,7 @@ static void
 update_equiv_regs ()
 {
   rtx insn;
-  int block;
+  basic_block bb;
   int loop_depth;
   regset_head cleared_regs;
   int clear_regnos = 0;
@@ -818,9 +824,8 @@ update_equiv_regs ()
   /* Scan the insns and find which registers have equivalences.  Do this
      in a separate scan of the insns because (due to -fcse-follow-jumps)
      a register can be set below its use.  */
-  for (block = 0; block < n_basic_blocks; block++)
+  FOR_EACH_BB (bb)
     {
-      basic_block bb = BASIC_BLOCK (block);
       loop_depth = bb->loop_depth;
 
       for (insn = bb->head; insn != NEXT_INSN (bb->end); insn = NEXT_INSN (insn))
@@ -927,13 +932,9 @@ update_equiv_regs ()
 
          /* cse sometimes generates function invariants, but doesn't put a
             REG_EQUAL note on the insn.  Since this note would be redundant,
-            there's no point creating it earlier than here.  Don't do this
-            for ASM_OPERANDS since eliminate_regs doesn't support it and
-            it serves no useful purpose.  */
-         if (! note && ! rtx_varies_p (src, 0)
-             && GET_CODE (src) != ASM_OPERANDS)
-           REG_NOTES (insn)
-             = note = gen_rtx_EXPR_LIST (REG_EQUAL, src, REG_NOTES (insn));
+            there's no point creating it earlier than here.  */
+         if (! note && ! rtx_varies_p (src, 0))
+           note = set_unique_reg_note (insn, REG_EQUAL, src);
 
          /* Don't bother considering a REG_EQUAL note containing an EXPR_LIST
             since it represents a function call */
@@ -999,7 +1000,7 @@ update_equiv_regs ()
                recorded_label_ref = 1;
 
              reg_equiv[regno].replacement = XEXP (note, 0);
-             reg_equiv[regno].src = src;
+             reg_equiv[regno].src_p = &SET_SRC (set);
              reg_equiv[regno].loop_depth = loop_depth;
 
              /* Don't mess with things live during setjmp.  */
@@ -1038,10 +1039,8 @@ update_equiv_regs ()
      within the same loop (or in an inner loop), then move the register
      initialization just before the use, so that they are in the same
      basic block.  */
-  for (block = n_basic_blocks - 1; block >= 0; block--)
+  FOR_EACH_BB_REVERSE (bb)
     {
-      basic_block bb = BASIC_BLOCK (block);
-
       loop_depth = bb->loop_depth;
       for (insn = bb->end; insn != PREV_INSN (bb->head); insn = PREV_INSN (insn))
        {
@@ -1081,7 +1080,7 @@ update_equiv_regs ()
 
                  if (asm_noperands (PATTERN (equiv_insn)) < 0
                      && validate_replace_rtx (regno_reg_rtx[regno],
-                                              reg_equiv[regno].src, insn))
+                                              *(reg_equiv[regno].src_p), insn))
                    {
                      rtx equiv_link;
                      rtx last_link;
@@ -1111,7 +1110,7 @@ update_equiv_regs ()
                      REG_N_REFS (regno) = 0;
                      REG_FREQ (regno) = 0;
                      delete_insn (equiv_insn);
-                     
+
                      reg_equiv[regno].init_insns
                        = XEXP (reg_equiv[regno].init_insns, 1);
                    }
@@ -1133,12 +1132,12 @@ update_equiv_regs ()
 
                      XEXP (reg_equiv[regno].init_insns, 0) = new_insn;
 
-                     REG_BASIC_BLOCK (regno) = block >= 0 ? block : 0;
+                     REG_BASIC_BLOCK (regno) = bb->index;
                      REG_N_CALLS_CROSSED (regno) = 0;
                      REG_LIVE_LENGTH (regno) = 2;
 
-                     if (block >= 0 && insn == BLOCK_HEAD (block))
-                       BLOCK_HEAD (block) = PREV_INSN (insn);
+                     if (insn == bb->head)
+                       bb->head = PREV_INSN (insn);
 
                      /* Remember to clear REGNO from all basic block's live
                         info.  */
@@ -1153,24 +1152,22 @@ update_equiv_regs ()
   /* Clear all dead REGNOs from all basic block's live info.  */
   if (clear_regnos)
     {
-      int j, l;
+      int j;
       if (clear_regnos > 8)
-        {
-         for (l = 0; l < n_basic_blocks; l++)
+       {
+         FOR_EACH_BB (bb)
            {
-             AND_COMPL_REG_SET (BASIC_BLOCK (l)->global_live_at_start,
-                                &cleared_regs);
-             AND_COMPL_REG_SET (BASIC_BLOCK (l)->global_live_at_end,
-                                &cleared_regs);
+             AND_COMPL_REG_SET (bb->global_live_at_start, &cleared_regs);
+             AND_COMPL_REG_SET (bb->global_live_at_end, &cleared_regs);
            }
        }
       else
-        EXECUTE_IF_SET_IN_REG_SET (&cleared_regs, 0, j,
-          {
-           for (l = 0; l < n_basic_blocks; l++)
+       EXECUTE_IF_SET_IN_REG_SET (&cleared_regs, 0, j,
+         {
+           FOR_EACH_BB (bb)
              {
-               CLEAR_REGNO_REG_SET (BASIC_BLOCK (l)->global_live_at_start, j);
-               CLEAR_REGNO_REG_SET (BASIC_BLOCK (l)->global_live_at_end, j);
+               CLEAR_REGNO_REG_SET (bb->global_live_at_start, j);
+               CLEAR_REGNO_REG_SET (bb->global_live_at_end, j);
              }
          });
     }
@@ -1182,7 +1179,7 @@ update_equiv_regs ()
 }
 
 /* Mark REG as having no known equivalence.
-   Some instructions might have been proceessed before and furnished
+   Some instructions might have been processed before and furnished
    with REG_EQUIV notes for this register; these notes will have to be
    removed.
    STORE is the piece of RTL that does the non-constant / conflicting
@@ -1220,7 +1217,7 @@ block_alloc (b)
 {
   int i, q;
   rtx insn;
-  rtx note;
+  rtx note, hard_reg;
   int insn_number = 0;
   int insn_count = 0;
   int max_uid = get_max_uid ();
@@ -1330,7 +1327,7 @@ block_alloc (b)
                     must match operand zero.  In that case, skip any
                     operand that doesn't list operand 0 since we know that
                     the operand always conflicts with operand 0.  We
-                    ignore commutatity in this case to keep things simple.  */
+                    ignore commutativity in this case to keep things simple.  */
                  if (n_matching_alts == recog_data.n_alternatives
                      && 0 == requires_inout (recog_data.constraints[i]))
                    continue;
@@ -1340,10 +1337,24 @@ block_alloc (b)
                  /* If the operand is an address, find a register in it.
                     There may be more than one register, but we only try one
                     of them.  */
-                 if (recog_data.constraints[i][0] == 'p')
+                 if (recog_data.constraints[i][0] == 'p'
+                     || EXTRA_ADDRESS_CONSTRAINT (recog_data.constraints[i][0],
+                                                  recog_data.constraints[i]))
                    while (GET_CODE (r1) == PLUS || GET_CODE (r1) == MULT)
                      r1 = XEXP (r1, 0);
 
+                 /* Avoid making a call-saved register unnecessarily
+                     clobbered.  */
+                 hard_reg = get_hard_reg_initial_reg (cfun, r1);
+                 if (hard_reg != NULL_RTX)
+                   {
+                     if (GET_CODE (hard_reg) == REG
+                         && IN_RANGE (REGNO (hard_reg),
+                                      0, FIRST_PSEUDO_REGISTER - 1)
+                         && ! call_used_regs[REGNO (hard_reg)])
+                       continue;
+                   }
+
                  if (GET_CODE (r0) == REG || GET_CODE (r0) == SUBREG)
                    {
                      /* We have two priorities for hard register preferences.
@@ -1586,7 +1597,7 @@ block_alloc (b)
             discourage the register allocator from creating false
             dependencies.
 
-            The adjustment value is choosen to indicate that this qty
+            The adjustment value is chosen to indicate that this qty
             conflicts with all the qtys in the instructions immediately
             before and after the lifetime of this qty.
 
@@ -1690,8 +1701,8 @@ qty_compare (q1, q2)
 
 static int
 qty_compare_1 (q1p, q2p)
-     const PTR q1p;
-     const PTR q2p;
+     const void *q1p;
+     const void *q2p;
 {
   int q1 = *(const int *) q1p, q2 = *(const int *) q2p;
   int tem = QTY_CMP_PRI (q2) - QTY_CMP_PRI (q1);
@@ -1730,8 +1741,8 @@ qty_sugg_compare (q1, q2)
 
 static int
 qty_sugg_compare_1 (q1p, q2p)
-     const PTR q1p;
-     const PTR q2p;
+     const void *q1p;
+     const void *q2p;
 {
   int q1 = *(const int *) q1p, q2 = *(const int *) q2p;
   int tem = QTY_CMP_SUGG (q1) - QTY_CMP_SUGG (q2);
@@ -1763,11 +1774,11 @@ qty_sugg_compare_1 (q1p, q2p)
    If we really combined them, we could lose if the pseudo lives
    across an insn that clobbers the hard reg (eg, movstr).
 
-   ALREADY_DEAD is non-zero if USEDREG is known to be dead even though
+   ALREADY_DEAD is nonzero if USEDREG is known to be dead even though
    there is no REG_DEAD note on INSN.  This occurs during the processing
    of REG_NO_CONFLICT blocks.
 
-   MAY_SAVE_COPYCOPY is non-zero if this insn is simply copying USEDREG to
+   MAY_SAVE_COPYCOPY is nonzero if this insn is simply copying USEDREG to
    SETREG or if the input and output must share a register.
    In that case, we record a hard reg suggestion in QTY_PHYS_COPY_SUGG.
 
@@ -1792,20 +1803,29 @@ combine_regs (usedreg, setreg, may_save_copy, insn_number, insn, already_dead)
 
   while (GET_CODE (usedreg) == SUBREG)
     {
-      if (GET_MODE_SIZE (GET_MODE (SUBREG_REG (usedreg))) > UNITS_PER_WORD)
-       may_save_copy = 0;
-      if (REGNO (SUBREG_REG (usedreg)) < FIRST_PSEUDO_REGISTER)
-       offset += subreg_regno_offset (REGNO (SUBREG_REG (usedreg)),
-                                      GET_MODE (SUBREG_REG (usedreg)),
-                                      SUBREG_BYTE (usedreg),
-                                      GET_MODE (usedreg));
-      else
-       offset += (SUBREG_BYTE (usedreg)
-                  / REGMODE_NATURAL_SIZE (GET_MODE (usedreg)));
-      usedreg = SUBREG_REG (usedreg);
+      rtx subreg = SUBREG_REG (usedreg);
+
+      if (GET_CODE (subreg) == REG)
+       {
+         if (GET_MODE_SIZE (GET_MODE (subreg)) > UNITS_PER_WORD)
+           may_save_copy = 0;
+
+         if (REGNO (subreg) < FIRST_PSEUDO_REGISTER)
+           offset += subreg_regno_offset (REGNO (subreg),
+                                          GET_MODE (subreg),
+                                          SUBREG_BYTE (usedreg),
+                                          GET_MODE (usedreg));
+         else
+           offset += (SUBREG_BYTE (usedreg)
+                     / REGMODE_NATURAL_SIZE (GET_MODE (usedreg)));
+       }
+
+      usedreg = subreg;
     }
+
   if (GET_CODE (usedreg) != REG)
     return 0;
+
   ureg = REGNO (usedreg);
   if (ureg < FIRST_PSEUDO_REGISTER)
     usize = HARD_REGNO_NREGS (ureg, GET_MODE (usedreg));
@@ -1816,20 +1836,29 @@ combine_regs (usedreg, setreg, may_save_copy, insn_number, insn, already_dead)
 
   while (GET_CODE (setreg) == SUBREG)
     {
-      if (GET_MODE_SIZE (GET_MODE (SUBREG_REG (setreg))) > UNITS_PER_WORD)
-       may_save_copy = 0;
-      if (REGNO (SUBREG_REG (setreg)) < FIRST_PSEUDO_REGISTER)
-       offset -= subreg_regno_offset (REGNO (SUBREG_REG (setreg)),
-                                      GET_MODE (SUBREG_REG (setreg)),
-                                      SUBREG_BYTE (setreg),
-                                      GET_MODE (setreg));
-      else
-       offset -= (SUBREG_BYTE (setreg)
-                  / REGMODE_NATURAL_SIZE (GET_MODE (setreg)));
-      setreg = SUBREG_REG (setreg);
+      rtx subreg = SUBREG_REG (setreg);
+
+      if (GET_CODE (subreg) == REG)
+       {
+         if (GET_MODE_SIZE (GET_MODE (subreg)) > UNITS_PER_WORD)
+           may_save_copy = 0;
+
+         if (REGNO (subreg) < FIRST_PSEUDO_REGISTER)
+           offset -= subreg_regno_offset (REGNO (subreg),
+                                          GET_MODE (subreg),
+                                          SUBREG_BYTE (setreg),
+                                          GET_MODE (setreg));
+         else
+           offset -= (SUBREG_BYTE (setreg)
+                     / REGMODE_NATURAL_SIZE (GET_MODE (setreg)));
+       }
+
+      setreg = subreg;
     }
+
   if (GET_CODE (setreg) != REG)
     return 0;
+
   sreg = REGNO (setreg);
   if (sreg < FIRST_PSEUDO_REGISTER)
     ssize = HARD_REGNO_NREGS (sreg, GET_MODE (setreg));
@@ -1993,9 +2022,6 @@ update_qty_class (qtyno, reg)
   rclass = reg_alternate_class (reg);
   if (reg_class_subset_p (rclass, qty[qtyno].alternate_class))
     qty[qtyno].alternate_class = rclass;
-
-  if (REG_CHANGES_MODE (reg))
-    qty[qtyno].changes_mode = 1;
 }
 \f
 /* Handle something which alters the value of an rtx REG.
@@ -2066,7 +2092,7 @@ reg_is_born (reg, birth)
     }
 }
 
-/* Record the death of REG in the current insn.  If OUTPUT_P is non-zero,
+/* Record the death of REG in the current insn.  If OUTPUT_P is nonzero,
    REG is an output that is dying (i.e., it is never used), otherwise it
    is an input (the normal case).
    If OUTPUT_P is 1, then we extend the life past the end of this insn.  */
@@ -2135,7 +2161,7 @@ wipe_dead_reg (reg, output_p)
    If QTYNO crosses calls, insist on a register preserved by calls,
    unless ACCEPT_CALL_CLOBBERED is nonzero.
 
-   If JUST_TRY_SUGGESTED is non-zero, only try to see if the suggested
+   If JUST_TRY_SUGGESTED is nonzero, only try to see if the suggested
    register is available.  If not, return -1.  */
 
 static int
@@ -2149,11 +2175,7 @@ find_free_reg (class, mode, qtyno, accept_call_clobbered, just_try_suggested,
      int born_index, dead_index;
 {
   int i, ins;
-#ifdef HARD_REG_SET
-  /* Declare it register if it's a scalar.  */
-  register
-#endif
-    HARD_REG_SET used, first_used;
+  HARD_REG_SET first_used, used;
 #ifdef ELIMINABLE_REGS
   static const struct {const int from, to; } eliminables[] = ELIMINABLE_REGS;
 #endif
@@ -2201,10 +2223,8 @@ find_free_reg (class, mode, qtyno, accept_call_clobbered, just_try_suggested,
   SET_HARD_REG_BIT (used, FRAME_POINTER_REGNUM);
 #endif
 
-#ifdef CLASS_CANNOT_CHANGE_MODE
-  if (qty[qtyno].changes_mode)
-    IOR_HARD_REG_SET (used,
-                     reg_class_contents[(int) CLASS_CANNOT_CHANGE_MODE]);
+#ifdef CANNOT_CHANGE_MODE_CLASS
+  cannot_change_mode_set_regs (&used, mode, qty[qtyno].first_reg);
 #endif
 
   /* Normally, the registers that can be used for the first register in
@@ -2294,7 +2314,7 @@ find_free_reg (class, mode, qtyno, accept_call_clobbered, just_try_suggested,
 }
 \f
 /* Mark that REGNO with machine-mode MODE is live starting from the current
-   insn (if LIFE is non-zero) or dead starting at the current insn (if LIFE
+   insn (if LIFE is nonzero) or dead starting at the current insn (if LIFE
    is zero).  */
 
 static void
@@ -2313,7 +2333,7 @@ mark_life (regno, mode, life)
 }
 
 /* Mark register number REGNO (with machine-mode MODE) as live (if LIFE
-   is non-zero) or dead (if LIFE is zero) from insn number BIRTH (inclusive)
+   is nonzero) or dead (if LIFE is zero) from insn number BIRTH (inclusive)
    to insn number DEATH (exclusive).  */
 
 static void
@@ -2405,49 +2425,56 @@ requires_inout (p)
   int found_zero = 0;
   int reg_allowed = 0;
   int num_matching_alts = 0;
+  int len;
 
-  while ((c = *p++))
-    switch (c)
-      {
-      case '=':  case '+':  case '?':
-      case '#':  case '&':  case '!':
-      case '*':  case '%':
-      case 'm':  case '<':  case '>':  case 'V':  case 'o':
-      case 'E':  case 'F':  case 'G':  case 'H':
-      case 's':  case 'i':  case 'n':
-      case 'I':  case 'J':  case 'K':  case 'L':
-      case 'M':  case 'N':  case 'O':  case 'P':
-      case 'X':
-       /* These don't say anything we care about.  */
-       break;
+  for ( ; (c = *p); p += len)
+    {
+      len = CONSTRAINT_LEN (c, p);
+      switch (c)
+       {
+       case '=':  case '+':  case '?':
+       case '#':  case '&':  case '!':
+       case '*':  case '%':
+       case 'm':  case '<':  case '>':  case 'V':  case 'o':
+       case 'E':  case 'F':  case 'G':  case 'H':
+       case 's':  case 'i':  case 'n':
+       case 'I':  case 'J':  case 'K':  case 'L':
+       case 'M':  case 'N':  case 'O':  case 'P':
+       case 'X':
+         /* These don't say anything we care about.  */
+         break;
 
-      case ',':
-       if (found_zero && ! reg_allowed)
-         num_matching_alts++;
+       case ',':
+         if (found_zero && ! reg_allowed)
+           num_matching_alts++;
 
-       found_zero = reg_allowed = 0;
-       break;
+         found_zero = reg_allowed = 0;
+         break;
 
-      case '0':
-       found_zero = 1;
-       break;
+       case '0':
+         found_zero = 1;
+         break;
 
-      case '1':  case '2':  case '3':  case '4': case '5':
-      case '6':  case '7':  case '8':  case '9':
-       /* Skip the balance of the matching constraint.  */
-       while (ISDIGIT (*p))
-         p++;
-       break;
+       case '1':  case '2':  case '3':  case '4': case '5':
+       case '6':  case '7':  case '8':  case '9':
+         /* Skip the balance of the matching constraint.  */
+         do
+           p++;
+         while (ISDIGIT (*p));
+         len = 0;
+         break;
 
-      default:
-       if (REG_CLASS_FROM_LETTER (c) == NO_REGS)
+       default:
+         if (REG_CLASS_FROM_CONSTRAINT (c, p) == NO_REGS
+             && !EXTRA_ADDRESS_CONSTRAINT (c, p))
+           break;
+         /* FALLTHRU */
+       case 'p':
+       case 'g': case 'r':
+         reg_allowed = 1;
          break;
-       /* FALLTHRU */
-      case 'p':
-      case 'g': case 'r':
-       reg_allowed = 1;
-       break;
-      }
+       }
+    }
 
   if (found_zero && ! reg_allowed)
     num_matching_alts++;