mirror of
git://gcc.gnu.org/git/gcc.git
synced 2024-12-18 05:09:01 +08:00
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:
parent
d3694e346d
commit
1f06ee8d0d
@ -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
|
||||
|
@ -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;
|
||||
{
|
||||
|
@ -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));
|
||||
|
227
gcc/recog.c
227
gcc/recog.c
@ -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.
|
||||
|
@ -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));
|
||||
|
100
gcc/stmt.c
100
gcc/stmt.c
@ -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++;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user