OSDN Git Service

* expr.c (queued_subexp_p): Make public.
authorrth <rth@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 15 Jan 1999 18:43:47 +0000 (18:43 +0000)
committerrth <rth@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 15 Jan 1999 18:43:47 +0000 (18:43 +0000)
        * expr.h (queued_subexp_p): Declare it.
        * recog.c (asm_operand_ok): New function.
        (check_asm_operands): Use it.  After reload, use constrain_operands
        instead.
        * recog.h (asm_operand_ok): Declare it.
        * stmt.c (expand_asm_operands): Use it to try harder to make
        asms initially satisfy their constraints.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@24686 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/ChangeLog
gcc/expr.c
gcc/expr.h
gcc/recog.c
gcc/recog.h
gcc/stmt.c

index 045b9d4..199a8d4 100644 (file)
@@ -1,3 +1,14 @@
+Fri Jan 15 18:42:12 1999  Richard Henderson  <rth@cygnus.com>
+
+       * expr.c (queued_subexp_p): Make public.
+       * expr.h (queued_subexp_p): Declare it.
+       * recog.c (asm_operand_ok): New function.
+       (check_asm_operands): Use it.  After reload, use constrain_operands 
+       instead.
+       * recog.h (asm_operand_ok): Declare it.
+       * stmt.c (expand_asm_operands): Use it to try harder to make
+       asms initially satisfy their constraints.
+
 Fri Jan 15 17:43:59 1999  Jeffrey A. Law  <law@rtl.cygnus.com>
 
        * sparc.h (LEGITIMIZE_RELOAD_ADDRESS): Do not create
index 12e0cd0..1d2a399 100644 (file)
@@ -149,7 +149,6 @@ extern rtx arg_pointer_save_area;
 static rtx get_push_address    PROTO ((int));
 
 static rtx enqueue_insn                PROTO((rtx, rtx));
-static int queued_subexp_p     PROTO((rtx));
 static void init_queue         PROTO((void));
 static int move_by_pieces_ninsns PROTO((unsigned int, int));
 static void move_by_pieces_1   PROTO((rtx (*) (rtx, ...), enum machine_mode,
@@ -478,7 +477,7 @@ protect_from_queue (x, modify)
    We handle only combinations of MEM, PLUS, MINUS and MULT operators
    since memory addresses generally contain only those.  */
 
-static int
+int
 queued_subexp_p (x)
      rtx x;
 {
index cc2fb30..5b32937 100644 (file)
@@ -716,6 +716,9 @@ extern rtx protect_from_queue PROTO((rtx, int));
 /* Perform all the pending incrementations.  */
 extern void emit_queue PROTO((void));
 
+/* Tell if something has a queued subexpression.  */
+extern int queued_subexp_p PROTO((rtx));
+
 /* Emit some rtl insns to move data between rtx's, converting machine modes.
    Both modes must be floating or both fixed.  */
 extern void convert_move PROTO((rtx, rtx, int));
index fa8c069..0d87386 100644 (file)
@@ -1,5 +1,5 @@
 /* Subroutines used by or related to instruction recognition.
-   Copyright (C) 1987, 1988, 91-97, 1998 Free Software Foundation, Inc.
+   Copyright (C) 1987, 1988, 91-98, 1999 Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
@@ -152,21 +152,40 @@ int
 check_asm_operands (x)
      rtx x;
 {
-  int noperands = asm_noperands (x);
+  int noperands;
   rtx *operands;
+  char **constraints;
   int i;
 
+  /* Post-reload, be more strict with things.  */
+  if (reload_completed)
+    {
+      /* ??? Doh!  We've not got the wrapping insn.  Cook one up.  */
+      extract_insn (make_insn_raw (x));
+      constrain_operands (1);
+      return which_alternative >= 0;
+    }
+
+  noperands = asm_noperands (x);
   if (noperands < 0)
     return 0;
   if (noperands == 0)
     return 1;
 
   operands = (rtx *) alloca (noperands * sizeof (rtx));
-  decode_asm_operands (x, operands, NULL_PTR, NULL_PTR, NULL_PTR);
+  constraints = (char **) alloca (noperands * sizeof (char *));
+
+  decode_asm_operands (x, operands, NULL_PTR, constraints, NULL_PTR);
 
   for (i = 0; i < noperands; i++)
-    if (!general_operand (operands[i], VOIDmode))
-      return 0;
+    {
+      char *c = constraints[i];
+      if (ISDIGIT ((unsigned char)c[0]))
+       c = constraints[c[0] - '0'];
+
+      if (! asm_operand_ok (operands[i], c))
+        return 0;
+    }
 
   return 1;
 }
@@ -1493,6 +1512,204 @@ decode_asm_operands (body, operands, operand_locs, constraints, modes)
 
   return template;
 }
+
+/* Check if an asm_operand matches it's constraints.  */
+
+int
+asm_operand_ok (op, constraint)
+     rtx op;
+     const char *constraint;
+{
+  /* Use constrain_operands after reload.  */
+  if (reload_completed)
+    abort ();
+
+  while (*constraint)
+    {
+      switch (*constraint++)
+       {
+       case '=':
+       case '+':
+       case '*':
+       case '%':
+       case '?':
+       case '!':
+       case '#':
+       case '&':
+       case ',':
+         break;
+
+       case '0': case '1': case '2': case '3': case '4':
+       case '5': case '6': case '7': case '8': case '9':
+         /* Our caller is supposed to have given us the proper
+            matching constraint.  */
+         /* abort (); */
+         break;
+
+       case 'p':
+         if (address_operand (op, VOIDmode))
+           return 1;
+         break;
+
+       case 'm':
+       case 'V': /* non-offsettable */
+         if (memory_operand (op, VOIDmode))
+           return 1;
+         break;
+
+       case 'o': /* offsettable */
+         if (offsettable_nonstrict_memref_p (op))
+           return 1;
+         break;
+
+       case '<':
+         if (GET_CODE (op) == MEM
+             && (GET_CODE (XEXP (op, 0)) == PRE_DEC
+                  || GET_CODE (XEXP (op, 0)) == POST_DEC))
+           return 1;
+         break;
+
+       case '>':
+         if (GET_CODE (op) == MEM
+             && (GET_CODE (XEXP (op, 0)) == PRE_INC
+                  || GET_CODE (XEXP (op, 0)) == POST_INC))
+           return 1;
+         break;
+
+       case 'E':
+#ifndef REAL_ARITHMETIC
+         /* Match any floating double constant, but only if
+            we can examine the bits of it reliably.  */
+         if ((HOST_FLOAT_FORMAT != TARGET_FLOAT_FORMAT
+              || HOST_BITS_PER_WIDE_INT != BITS_PER_WORD)
+             && GET_MODE (op) != VOIDmode && ! flag_pretend_float)
+           break;
+#endif
+         /* FALLTHRU */
+
+       case 'F':
+         if (GET_CODE (op) == CONST_DOUBLE)
+           return 1;
+         break;
+
+       case 'G':
+         if (GET_CODE (op) == CONST_DOUBLE
+             && CONST_DOUBLE_OK_FOR_LETTER_P (op, 'G'))
+           return 1;
+         break;
+       case 'H':
+         if (GET_CODE (op) == CONST_DOUBLE
+             && CONST_DOUBLE_OK_FOR_LETTER_P (op, 'H'))
+           return 1;
+         break;
+
+       case 's':
+         if (GET_CODE (op) == CONST_INT
+             || (GET_CODE (op) == CONST_DOUBLE
+                 && GET_MODE (op) == VOIDmode))
+           break;
+         /* FALLTHRU */
+
+       case 'i':
+         if (CONSTANT_P (op)
+#ifdef LEGITIMATE_PIC_OPERAND_P
+             && (! flag_pic || LEGITIMATE_PIC_OPERAND_P (op))
+#endif
+             )
+           return 1;
+         break;
+
+       case 'n':
+         if (GET_CODE (op) == CONST_INT
+             || (GET_CODE (op) == CONST_DOUBLE
+                 && GET_MODE (op) == VOIDmode))
+           return 1;
+         break;
+
+       case 'I':
+         if (GET_CODE (op) == CONST_INT
+             && CONST_OK_FOR_LETTER_P (INTVAL (op), 'I'))
+           return 1;
+         break;
+       case 'J':
+         if (GET_CODE (op) == CONST_INT
+             && CONST_OK_FOR_LETTER_P (INTVAL (op), 'J'))
+           return 1;
+         break;
+       case 'K':
+         if (GET_CODE (op) == CONST_INT
+             && CONST_OK_FOR_LETTER_P (INTVAL (op), 'K'))
+           return 1;
+         break;
+       case 'L':
+         if (GET_CODE (op) == CONST_INT
+             && CONST_OK_FOR_LETTER_P (INTVAL (op), 'L'))
+           return 1;
+         break;
+       case 'M':
+         if (GET_CODE (op) == CONST_INT
+             && CONST_OK_FOR_LETTER_P (INTVAL (op), 'M'))
+           return 1;
+         break;
+       case 'N':
+         if (GET_CODE (op) == CONST_INT
+             && CONST_OK_FOR_LETTER_P (INTVAL (op), 'N'))
+           return 1;
+         break;
+       case 'O':
+         if (GET_CODE (op) == CONST_INT
+             && CONST_OK_FOR_LETTER_P (INTVAL (op), 'O'))
+           return 1;
+         break;
+       case 'P':
+         if (GET_CODE (op) == CONST_INT
+             && CONST_OK_FOR_LETTER_P (INTVAL (op), 'P'))
+           return 1;
+         break;
+
+       case 'X':
+         return 1;
+
+       case 'g':
+         if (general_operand (op, VOIDmode))
+           return 1;
+         break;
+
+#ifdef EXTRA_CONSTRAINT
+       case 'Q':
+         if (EXTRA_CONSTRAINT (op, 'Q'))
+           return 1;
+         break;
+       case 'R':
+         if (EXTRA_CONSTRAINT (op, 'R'))
+           return 1;
+         break;
+       case 'S':
+         if (EXTRA_CONSTRAINT (op, 'S'))
+           return 1;
+         break;
+       case 'T':
+         if (EXTRA_CONSTRAINT (op, 'T'))
+           return 1;
+         break;
+       case 'U':
+         if (EXTRA_CONSTRAINT (op, 'U'))
+           return 1;
+         break;
+#endif
+
+       case 'r':
+       default:
+         if (GET_MODE (op) == BLKmode)
+           break;
+         if (register_operand (op, VOIDmode))
+           return 1;
+         break;
+       }
+    }
+
+  return 0;
+}
 \f
 /* 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.
index ded5667..d85cc0f 100644 (file)
@@ -70,6 +70,7 @@ extern void init_recog                        PROTO((void));
 extern void init_recog_no_volatile     PROTO((void));
 extern int recog_memoized              PROTO((rtx));
 extern int check_asm_operands          PROTO((rtx));
+extern int asm_operand_ok              PROTO((rtx, const char *));
 extern int validate_change             PROTO((rtx, rtx *, rtx, int));
 extern int apply_change_group          PROTO((void));
 extern int num_validated_changes       PROTO((void));
index 4f2e911..4e972e9 100644 (file)
@@ -1397,9 +1397,10 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
   for (tail = inputs; tail; tail = TREE_CHAIN (tail))
     {
       int j;
-      int allows_reg = 0;
-      char *constraint;
+      int allows_reg = 0, allows_mem = 0;
+      char *constraint, *orig_constraint;
       int c_len;
+      rtx op;
 
       /* If there's an erroneous arg, emit no insn,
         because the ASM_INPUT would get VOIDmode
@@ -1417,6 +1418,7 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
 
       c_len = TREE_STRING_LENGTH (TREE_PURPOSE (tail)) - 1;
       constraint = TREE_STRING_POINTER (TREE_PURPOSE (tail));
+      orig_constraint = constraint;
 
       /* Make sure constraint has neither `=', `+', nor '&'.  */
 
@@ -1424,19 +1426,28 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
        switch (constraint[j])
          {
          case '+':  case '=':  case '&':
-           error ("input operand constraint contains `%c'", constraint[j]);
-           return;
+           if (constraint == orig_constraint)
+             {
+               error ("input operand constraint contains `%c'", constraint[j]);
+               return;
+             }
+           break;
 
          case '%':
-           if (i + 1 == ninputs - ninout)
+           if (constraint == orig_constraint
+               && i + 1 == ninputs - ninout)
              {
                error ("`%%' constraint used with last operand");
                return;
              }
            break;
 
+         case 'V':  case 'm':  case 'o':
+           allows_mem = 1;
+           break;
+
+         case '<':  case '>':
          case '?':  case '!':  case '*':
-         case 'V':  case 'm':  case 'o':  case '<':  case '>':
          case 'E':  case 'F':  case 'G':  case 'H':  case 'X':
          case 's':  case 'i':  case 'n':
          case 'I':  case 'J':  case 'K':  case 'L':  case 'M':
@@ -1460,48 +1471,73 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
                return;
              }
 
+           /* Try and find the real constraint for this dup.  */
+           if (j == 0 && c_len == 1)
+             {
+               tree o = outputs;
+               for (j = constraint[j] - '0'; j > 0; --j)
+                 o = TREE_CHAIN (o);
+       
+               c_len = TREE_STRING_LENGTH (TREE_PURPOSE (o)) - 1;
+               constraint = TREE_STRING_POINTER (TREE_PURPOSE (o));
+               j = 0;
+               break;
+             }
+
            /* ... fall through ... */
 
-         case 'p':  case 'g':  case 'r':
+         case 'p':  case 'r':
          default:
            allows_reg = 1;
            break;
+
+         case 'g':
+           allows_reg = 1;
+           allows_mem = 1;
+           break;
          }
 
-      if (! allows_reg)
+      if (! allows_reg && allows_mem)
        mark_addressable (TREE_VALUE (tail));
 
-      XVECEXP (body, 3, i)      /* argvec */
-       = expand_expr (TREE_VALUE (tail), NULL_RTX, VOIDmode, 0);
-      if (CONSTANT_P (XVECEXP (body, 3, i))
-         && ! general_operand (XVECEXP (body, 3, i),
-                               TYPE_MODE (TREE_TYPE (TREE_VALUE (tail)))))
-       {
-         if (allows_reg)
-           XVECEXP (body, 3, i)
-             = force_reg (TYPE_MODE (TREE_TYPE (TREE_VALUE (tail))),
-                          XVECEXP (body, 3, i));
-         else
-           XVECEXP (body, 3, i)
-             = force_const_mem (TYPE_MODE (TREE_TYPE (TREE_VALUE (tail))),
-                                XVECEXP (body, 3, i));
-       }
+      op = expand_expr (TREE_VALUE (tail), NULL_RTX, VOIDmode, 0);
 
-      if (! allows_reg
-         && (GET_CODE (XVECEXP (body, 3, i)) == REG
-             || GET_CODE (XVECEXP (body, 3, i)) == SUBREG
-             || GET_CODE (XVECEXP (body, 3, i)) == CONCAT))
+      if (! asm_operand_ok (op, constraint))
        {
-         tree type = TREE_TYPE (TREE_VALUE (tail));
-         rtx memloc = assign_temp (type, 1, 1, 1);
+         if (allows_reg)
+           op = force_reg (TYPE_MODE (TREE_TYPE (TREE_VALUE (tail))), op);
+         else if (!allows_mem)
+           warning ("asm operand %d probably doesn't match constraints", i);
+         else if (CONSTANT_P (op))
+           op = force_const_mem (TYPE_MODE (TREE_TYPE (TREE_VALUE (tail))),
+                                 op);
+         else if (GET_CODE (op) == REG
+                  || GET_CODE (op) == SUBREG
+                  || GET_CODE (op) == CONCAT)
+           {
+             tree type = TREE_TYPE (TREE_VALUE (tail));
+             rtx memloc = assign_temp (type, 1, 1, 1);
 
-         emit_move_insn (memloc, XVECEXP (body, 3, i));
-         XVECEXP (body, 3, i) = memloc;
+             emit_move_insn (memloc, op);
+             op = memloc;
+           }
+         else if (GET_CODE (op) == MEM && MEM_VOLATILE_P (op))
+           /* We won't recognize volatile memory as available a
+              memory_operand at this point.  Ignore it.  */
+           ;
+         else if (queued_subexp_p (op))
+           ;
+         else
+           /* ??? Leave this only until we have experience with what
+              happens in combine and elsewhere when constraints are
+              not satisfied.  */
+           warning ("asm operand %d probably doesn't match constraints", i);
        }
+      XVECEXP (body, 3, i) = op;
 
       XVECEXP (body, 4, i)      /* constraints */
        = gen_rtx_ASM_INPUT (TYPE_MODE (TREE_TYPE (TREE_VALUE (tail))),
-                            constraint);
+                            orig_constraint);
       i++;
     }