OSDN Git Service

* expr.c (move_block_from_reg): Try using an integral mov operation first.
[pf3gnuchains/gcc-fork.git] / gcc / recog.c
index 640bc0b..92fc6d8 100644 (file)
@@ -1,5 +1,5 @@
 /* Subroutines used by or related to instruction recognition.
-   Copyright (C) 1987, 1988, 1991 Free Software Foundation, Inc.
+   Copyright (C) 1987, 1988, 1991-6, 1997 Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
@@ -15,7 +15,8 @@ GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with GNU CC; see the file COPYING.  If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
 
 
 #include "config.h"
@@ -84,7 +85,7 @@ init_recog ()
 
 /* Try recognizing the instruction INSN,
    and return the code number that results.
-   Remeber the code so that repeated calls do not
+   Remember the code so that repeated calls do not
    need to spend the time for actual rerecognition.
 
    This function is the normal interface to instruction recognition.
@@ -96,7 +97,7 @@ recog_memoized (insn)
      rtx insn;
 {
   if (INSN_CODE (insn) < 0)
-    INSN_CODE (insn) = recog (PATTERN (insn), insn, 0);
+    INSN_CODE (insn) = recog (PATTERN (insn), insn, NULL_PTR);
   return INSN_CODE (insn);
 }
 \f
@@ -117,7 +118,7 @@ check_asm_operands (x)
     return 1;
 
   operands = (rtx *) alloca (noperands * sizeof (rtx));
-  decode_asm_operands (x, operands, 0, 0, 0);
+  decode_asm_operands (x, operands, NULL_PTR, NULL_PTR, NULL_PTR);
 
   for (i = 0; i < noperands; i++)
     if (!general_operand (operands[i], VOIDmode))
@@ -373,15 +374,28 @@ validate_replace_rtx_1 (loc, from, to, object)
        }
     }
 
+  /* Note that if CODE's RTX_CLASS is "c" or "<" we will have already
+     done the substitution, otherwise we won't.  */
+
   switch (code)
     {
     case PLUS:
       /* If we have have a PLUS whose second operand is now a CONST_INT, use
         plus_constant to try to simplify it.  */
       if (GET_CODE (XEXP (x, 1)) == CONST_INT && XEXP (x, 1) == to)
-       validate_change (object, loc, 
-                        plus_constant (XEXP (x, 0), INTVAL (XEXP (x, 1))), 1);
+       validate_change (object, loc, plus_constant (XEXP (x, 0), INTVAL (to)),
+                        1);
       return;
+
+    case MINUS:
+      if (GET_CODE (to) == CONST_INT && XEXP (x, 1) == from)
+       {
+         validate_change (object, loc,
+                          plus_constant (XEXP (x, 0), - INTVAL (to)),
+                          1);
+         return;
+       }
+      break;
       
     case ZERO_EXTEND:
     case SIGN_EXTEND:
@@ -389,7 +403,7 @@ validate_replace_rtx_1 (loc, from, to, object)
         of the operand.  If we are replacing the operand with a VOIDmode
         constant, we lose the information.  So try to simplify the operation
         in that case.  If it fails, substitute in something that we know
-        won't be recogized.  */
+        won't be recognized.  */
       if (GET_MODE (to) == VOIDmode
          && (XEXP (x, 0) == from
              || (GET_CODE (XEXP (x, 0)) == REG && GET_CODE (from) == REG
@@ -423,11 +437,10 @@ validate_replace_rtx_1 (loc, from, to, object)
          enum machine_mode mode = GET_MODE (x);
          rtx new;
 
-#if BYTES_BIG_ENDIAN
-         offset += (MIN (UNITS_PER_WORD,
-                         GET_MODE_SIZE (GET_MODE (SUBREG_REG (x))))
-                    - MIN (UNITS_PER_WORD, GET_MODE_SIZE (mode)));
-#endif
+         if (BYTES_BIG_ENDIAN)
+           offset += (MIN (UNITS_PER_WORD,
+                           GET_MODE_SIZE (GET_MODE (SUBREG_REG (x))))
+                      - MIN (UNITS_PER_WORD, GET_MODE_SIZE (mode)));
 
          new = gen_rtx (MEM, mode, plus_constant (XEXP (to, 0), offset));
          MEM_VOLATILE_P (new) = MEM_VOLATILE_P (to);
@@ -465,7 +478,7 @@ validate_replace_rtx_1 (loc, from, to, object)
            wanted_mode = insn_operand_mode[(int) CODE_FOR_extv][1];
 #endif
 
-         /* If we have a narrower mode, we can do someting.  */
+         /* If we have a narrower mode, we can do something.  */
          if (wanted_mode != VOIDmode
              && GET_MODE_SIZE (wanted_mode) < GET_MODE_SIZE (is_mode))
            {
@@ -474,10 +487,9 @@ validate_replace_rtx_1 (loc, from, to, object)
 
                  /* If the bytes and bits are counted differently, we
                     must adjust the offset.  */
-#if BYTES_BIG_ENDIAN != BITS_BIG_ENDIAN
-             offset = (GET_MODE_SIZE (is_mode) - GET_MODE_SIZE (wanted_mode)
-                       - offset);
-#endif
+             if (BYTES_BIG_ENDIAN != BITS_BIG_ENDIAN)
+               offset = (GET_MODE_SIZE (is_mode) - GET_MODE_SIZE (wanted_mode)
+                         - offset);
 
              pos %= GET_MODE_BITSIZE (wanted_mode);
 
@@ -487,8 +499,7 @@ validate_replace_rtx_1 (loc, from, to, object)
              MEM_VOLATILE_P (newmem) = MEM_VOLATILE_P (to);
              MEM_IN_STRUCT_P (newmem) = MEM_IN_STRUCT_P (to);
 
-             validate_change (object, &XEXP (x, 2),
-                              gen_rtx (CONST_INT, VOIDmode, pos), 1);
+             validate_change (object, &XEXP (x, 2), GEN_INT (pos), 1);
              validate_change (object, &XEXP (x, 0), newmem, 1);
            }
        }
@@ -745,7 +756,7 @@ find_single_use (dest, insn, ploc)
    The main use of this function is as a predicate in match_operand
    expressions in the machine description.
 
-   For an explaination of this function's behavior for registers of
+   For an explanation of this function's behavior for registers of
    class NO_REGS, see the comment for `register_operand'.  */
 
 int
@@ -762,7 +773,8 @@ general_operand (op, mode)
   /* Don't accept CONST_INT or anything similar
      if the caller wants something floating.  */
   if (GET_MODE (op) == VOIDmode && mode != VOIDmode
-      && GET_MODE_CLASS (mode) != MODE_INT)
+      && GET_MODE_CLASS (mode) != MODE_INT
+      && GET_MODE_CLASS (mode) != MODE_PARTIAL_INT)
     return 0;
 
   if (CONSTANT_P (op))
@@ -865,6 +877,19 @@ register_operand (op, mode)
         reg went on the stack.)  */
       if (! reload_completed && GET_CODE (SUBREG_REG (op)) == MEM)
        return general_operand (op, mode);
+
+#ifdef CLASS_CANNOT_CHANGE_SIZE
+      if (GET_CODE (SUBREG_REG (op)) == REG
+         && REGNO (SUBREG_REG (op)) < FIRST_PSEUDO_REGISTER
+         && TEST_HARD_REG_BIT (reg_class_contents[(int) CLASS_CANNOT_CHANGE_SIZE],
+                               REGNO (SUBREG_REG (op)))
+         && (GET_MODE_SIZE (mode)
+             != GET_MODE_SIZE (GET_MODE (SUBREG_REG (op))))
+         && GET_MODE_CLASS (GET_MODE (SUBREG_REG (op))) != MODE_COMPLEX_INT
+         && GET_MODE_CLASS (GET_MODE (SUBREG_REG (op))) != MODE_COMPLEX_FLOAT)
+       return 0;
+#endif
+
       op = SUBREG_REG (op);
     }
 
@@ -902,7 +927,8 @@ immediate_operand (op, mode)
   /* Don't accept CONST_INT or anything similar
      if the caller wants something floating.  */
   if (GET_MODE (op) == VOIDmode && mode != VOIDmode
-      && GET_MODE_CLASS (mode) != MODE_INT)
+      && GET_MODE_CLASS (mode) != MODE_INT
+      && GET_MODE_CLASS (mode) != MODE_PARTIAL_INT)
     return 0;
 
   return (CONSTANT_P (op)
@@ -935,7 +961,8 @@ const_double_operand (op, mode)
   /* Don't accept CONST_INT or anything similar
      if the caller wants something floating.  */
   if (GET_MODE (op) == VOIDmode && mode != VOIDmode
-      && GET_MODE_CLASS (mode) != MODE_INT)
+      && GET_MODE_CLASS (mode) != MODE_INT
+      && GET_MODE_CLASS (mode) != MODE_PARTIAL_INT)
     return 0;
 
   return ((GET_CODE (op) == CONST_DOUBLE || GET_CODE (op) == CONST_INT)
@@ -965,7 +992,8 @@ nonmemory_operand (op, mode)
       /* Don't accept CONST_INT or anything similar
         if the caller wants something floating.  */
       if (GET_MODE (op) == VOIDmode && mode != VOIDmode
-         && GET_MODE_CLASS (mode) != MODE_INT)
+         && GET_MODE_CLASS (mode) != MODE_INT
+         && GET_MODE_CLASS (mode) != MODE_PARTIAL_INT)
        return 0;
 
       return ((GET_MODE (op) == VOIDmode || GET_MODE (op) == mode)
@@ -1080,10 +1108,12 @@ indirect_operand (op, mode)
       register int offset = SUBREG_WORD (op) * UNITS_PER_WORD;
       rtx inner = SUBREG_REG (op);
 
-#if BYTES_BIG_ENDIAN
-      offset -= (MIN (UNITS_PER_WORD, GET_MODE_SIZE (GET_MODE (op)))
-                - MIN (UNITS_PER_WORD, GET_MODE_SIZE (GET_MODE (inner))));
-#endif
+      if (BYTES_BIG_ENDIAN)
+       offset -= (MIN (UNITS_PER_WORD, GET_MODE_SIZE (GET_MODE (op)))
+                  - MIN (UNITS_PER_WORD, GET_MODE_SIZE (GET_MODE (inner))));
+
+      if (mode != VOIDmode && GET_MODE (op) != mode)
+       return 0;
 
       /* The only way that we can have a general_operand as the resulting
         address is if OFFSET is zero and the address already is an operand
@@ -1329,9 +1359,6 @@ decode_asm_operands (body, operands, operand_locs, constraints, modes)
   return template;
 }
 \f
-extern rtx plus_constant_for_output ();
-extern rtx copy_rtx ();
-
 /* Given an rtx *P, if it is a sum containing an integer constant term,
    return the location (type rtx *) of the pointer to that constant term.
    Otherwise, return a null pointer.  */
@@ -1599,6 +1626,9 @@ constrain_operands (insn_code_num, strict)
      int strict;
 {
   char *constraints[MAX_RECOG_OPERANDS];
+  int matching_operands[MAX_RECOG_OPERANDS];
+  enum op_type {OP_IN, OP_OUT, OP_INOUT} op_types[MAX_RECOG_OPERANDS];
+  int earlyclobber[MAX_RECOG_OPERANDS];
   register int c;
   int noperands = insn_n_operands[insn_code_num];
 
@@ -1610,7 +1640,11 @@ constrain_operands (insn_code_num, strict)
     return 1;
 
   for (c = 0; c < noperands; c++)
-    constraints[c] = insn_operand_constraint[insn_code_num][c];
+    {
+      constraints[c] = insn_operand_constraint[insn_code_num][c];
+      matching_operands[c] = -1;
+      op_types[c] = OP_IN;
+    }
 
   which_alternative = 0;
 
@@ -1629,6 +1663,13 @@ constrain_operands (insn_code_num, strict)
          int win = 0;
          int val;
 
+         earlyclobber[opno] = 0;
+
+         /* A unary operator may be accepted by the predicate, but it
+            is irrelevant for matching contraints.  */
+         if (GET_RTX_CLASS (GET_CODE (op)) == '1')
+           op = XEXP (op, 0);
+
          if (GET_CODE (op) == SUBREG)
            {
              if (GET_CODE (SUBREG_REG (op)) == REG
@@ -1645,16 +1686,31 @@ constrain_operands (insn_code_num, strict)
          while (*p && (c = *p++) != ',')
            switch (c)
              {
-             case '=':
-             case '+':
              case '?':
-             case '#':
-             case '&':
              case '!':
              case '*':
              case '%':
                break;
 
+             case '#':
+               /* Ignore rest of this alternative as far as
+                  constraint checking is concerned.  */
+               while (*p && *p != ',')
+                 p++;
+               break;
+
+             case '=':
+               op_types[opno] = OP_OUT;
+               break;
+
+             case '+':
+               op_types[opno] = OP_INOUT;
+               break;
+
+             case '&':
+               earlyclobber[opno] = 1;
+               break;
+
              case '0':
              case '1':
              case '2':
@@ -1674,6 +1730,9 @@ constrain_operands (insn_code_num, strict)
                  val = operands_match_p (recog_operand[c - '0'],
                                          recog_operand[opno]);
 
+               matching_operands[opno] = c - '0';
+               matching_operands[c - '0'] = opno;
+
                if (val != 0)
                  win = 1;
                /* If output is *x and input is *--x,
@@ -1688,9 +1747,9 @@ constrain_operands (insn_code_num, strict)
 
              case 'p':
                /* p is used for address_operands.  When we are called by
-                  gen_input_reload, no one will have checked that the
-                  address is strictly valid, i.e., that all pseudos
-                  requiring hard regs have gotten them.  */
+                  gen_reload, no one will have checked that the address is
+                  strictly valid, i.e., that all pseudos requiring hard regs
+                  have gotten them.  */
                if (strict <= 0
                    || (strict_memory_address_p
                        (insn_operand_mode[insn_code_num][opno], op)))
@@ -1705,6 +1764,8 @@ constrain_operands (insn_code_num, strict)
                if (strict < 0
                    || GENERAL_REGS == ALL_REGS
                    || GET_CODE (op) != REG
+                   || (reload_in_progress
+                       && REGNO (op) >= FIRST_PSEUDO_REGISTER)
                    || reg_fits_class_p (op, GENERAL_REGS, offset, mode))
                  win = 1;
                break;
@@ -1716,22 +1777,27 @@ constrain_operands (insn_code_num, strict)
                        && REGNO (op) >= FIRST_PSEUDO_REGISTER)
                    || (strict == 0 && GET_CODE (op) == SCRATCH)
                    || (GET_CODE (op) == REG
-                       && (GENERAL_REGS == ALL_REGS
+                       && ((GENERAL_REGS == ALL_REGS
+                            && REGNO (op) < FIRST_PSEUDO_REGISTER)
                            || reg_fits_class_p (op, GENERAL_REGS,
                                                 offset, mode))))
                  win = 1;
                break;
 
              case 'X':
-               /* This is used for a MATCH_SCRATCH in the cases when we
-                  don't actually need anything.  So anything goes any time. */
+               /* This is used for a MATCH_SCRATCH in the cases when
+                  we don't actually need anything.  So anything goes
+                  any time.  */
                win = 1;
                break;
 
              case 'm':
                if (GET_CODE (op) == MEM
                    /* Before reload, accept what reload can turn into mem.  */
-                   || (strict < 0 && CONSTANT_P (op)))
+                   || (strict < 0 && CONSTANT_P (op))
+                   /* During reload, accept a pseudo  */
+                   || (reload_in_progress && GET_CODE (op) == REG
+                       && REGNO (op) >= FIRST_PSEUDO_REGISTER))
                  win = 1;
                break;
 
@@ -1750,12 +1816,14 @@ constrain_operands (insn_code_num, strict)
                break;
 
              case 'E':
+#ifndef REAL_ARITHMETIC
                /* Match any CONST_DOUBLE, but only if
                   we can examine the bits of it reliably.  */
                if ((HOST_FLOAT_FORMAT != TARGET_FLOAT_FORMAT
-                    || HOST_BITS_PER_INT != BITS_PER_WORD)
+                    || HOST_BITS_PER_WIDE_INT != BITS_PER_WORD)
                    && GET_MODE (op) != VOIDmode && ! flag_pretend_float)
                  break;
+#endif
                if (GET_CODE (op) == CONST_DOUBLE)
                  win = 1;
                break;
@@ -1815,7 +1883,12 @@ constrain_operands (insn_code_num, strict)
 
              case 'V':
                if (GET_CODE (op) == MEM
-                   && ! offsettable_memref_p (op))
+                   && ((strict > 0 && ! offsettable_memref_p (op))
+                       || (strict < 0
+                           && !(CONSTANT_P (op) || GET_CODE (op) == MEM))
+                       || (reload_in_progress
+                           && !(GET_CODE (op) == REG
+                                && REGNO (op) >= FIRST_PSEUDO_REGISTER))))
                  win = 1;
                break;
 
@@ -1824,7 +1897,10 @@ constrain_operands (insn_code_num, strict)
                    || (strict == 0 && offsettable_nonstrict_memref_p (op))
                    /* Before reload, accept what reload can handle.  */
                    || (strict < 0
-                       && (CONSTANT_P (op) || GET_CODE (op) == MEM)))
+                       && (CONSTANT_P (op) || GET_CODE (op) == MEM))
+                   /* During reload, accept a pseudo  */
+                   || (reload_in_progress && GET_CODE (op) == REG
+                       && REGNO (op) >= FIRST_PSEUDO_REGISTER))
                  win = 1;
                break;
 
@@ -1850,12 +1926,41 @@ constrain_operands (insn_code_num, strict)
         Change whichever operands this alternative says to change.  */
       if (! lose)
        {
-         while (--funny_match_index >= 0)
+         int opno, eopno;
+
+         /* See if any earlyclobber operand conflicts with some other
+            operand.  */
+
+         if (strict > 0)
+           for (eopno = 0; eopno < noperands; eopno++)
+             /* Ignore earlyclobber operands now in memory,
+                because we would often report failure when we have
+                two memory operands, one of which was formerly a REG.  */
+             if (earlyclobber[eopno]
+                 && GET_CODE (recog_operand[eopno]) == REG)
+               for (opno = 0; opno < noperands; opno++)
+                 if ((GET_CODE (recog_operand[opno]) == MEM
+                      || op_types[opno] != OP_OUT)
+                     && opno != eopno
+                     /* Ignore things like match_operator operands.  */
+                     && *insn_operand_constraint[insn_code_num][opno] != 0
+                     && ! (matching_operands[opno] == eopno
+                           && rtx_equal_p (recog_operand[opno],
+                                           recog_operand[eopno]))
+                     && ! safe_from_earlyclobber (recog_operand[opno],
+                                                  recog_operand[eopno]))
+                   lose = 1;
+
+         if (! lose)
            {
-             recog_operand[funny_match[funny_match_index].other]
-               = recog_operand[funny_match[funny_match_index].this];
+             while (--funny_match_index >= 0)
+               {
+                 recog_operand[funny_match[funny_match_index].other]
+                   = recog_operand[funny_match[funny_match_index].this];
+               }
+
+             return 1;
            }
-         return 1;
        }
 
       which_alternative++;