expr.c (queued_subexp_p): Make public.

* 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
This commit is contained in:
Richard Henderson 1999-01-15 10:43:47 -08:00 committed by Richard Henderson
parent d3694e346d
commit 1f06ee8d0d
6 changed files with 306 additions and 39 deletions

View 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

View 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;
{

View 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));

View 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;
}
/* 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.

View 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));

View 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)))))
op = expand_expr (TREE_VALUE (tail), NULL_RTX, VOIDmode, 0);
if (! asm_operand_ok (op, constraint))
{
if (allows_reg)
XVECEXP (body, 3, i)
= force_reg (TYPE_MODE (TREE_TYPE (TREE_VALUE (tail))),
XVECEXP (body, 3, i));
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, 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
XVECEXP (body, 3, i)
= force_const_mem (TYPE_MODE (TREE_TYPE (TREE_VALUE (tail))),
XVECEXP (body, 3, i));
}
if (! allows_reg
&& (GET_CODE (XVECEXP (body, 3, i)) == REG
|| GET_CODE (XVECEXP (body, 3, i)) == SUBREG
|| GET_CODE (XVECEXP (body, 3, i)) == 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;
/* ??? 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++;
}