* 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.
From-SVN: r24686
+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
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,
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;
{
/* 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));
/* 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.
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;
}
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.
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));
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
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 '&'. */
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':
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++;
}