Commit 1f06ee8d by Richard Henderson Committed by Richard Henderson

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
parent d3694e34
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> Fri Jan 15 17:43:59 1999 Jeffrey A. Law <law@rtl.cygnus.com>
* sparc.h (LEGITIMIZE_RELOAD_ADDRESS): Do not create * sparc.h (LEGITIMIZE_RELOAD_ADDRESS): Do not create
......
...@@ -149,7 +149,6 @@ extern rtx arg_pointer_save_area; ...@@ -149,7 +149,6 @@ extern rtx arg_pointer_save_area;
static rtx get_push_address PROTO ((int)); static rtx get_push_address PROTO ((int));
static rtx enqueue_insn PROTO((rtx, rtx)); static rtx enqueue_insn PROTO((rtx, rtx));
static int queued_subexp_p PROTO((rtx));
static void init_queue PROTO((void)); static void init_queue PROTO((void));
static int move_by_pieces_ninsns PROTO((unsigned int, int)); static int move_by_pieces_ninsns PROTO((unsigned int, int));
static void move_by_pieces_1 PROTO((rtx (*) (rtx, ...), enum machine_mode, static void move_by_pieces_1 PROTO((rtx (*) (rtx, ...), enum machine_mode,
...@@ -478,7 +477,7 @@ protect_from_queue (x, modify) ...@@ -478,7 +477,7 @@ protect_from_queue (x, modify)
We handle only combinations of MEM, PLUS, MINUS and MULT operators We handle only combinations of MEM, PLUS, MINUS and MULT operators
since memory addresses generally contain only those. */ since memory addresses generally contain only those. */
static int int
queued_subexp_p (x) queued_subexp_p (x)
rtx x; rtx x;
{ {
......
...@@ -716,6 +716,9 @@ extern rtx protect_from_queue PROTO((rtx, int)); ...@@ -716,6 +716,9 @@ extern rtx protect_from_queue PROTO((rtx, int));
/* Perform all the pending incrementations. */ /* Perform all the pending incrementations. */
extern void emit_queue PROTO((void)); 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. /* Emit some rtl insns to move data between rtx's, converting machine modes.
Both modes must be floating or both fixed. */ Both modes must be floating or both fixed. */
extern void convert_move PROTO((rtx, rtx, int)); extern void convert_move PROTO((rtx, rtx, int));
......
/* Subroutines used by or related to instruction recognition. /* 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. This file is part of GNU CC.
...@@ -152,21 +152,40 @@ int ...@@ -152,21 +152,40 @@ int
check_asm_operands (x) check_asm_operands (x)
rtx x; rtx x;
{ {
int noperands = asm_noperands (x); int noperands;
rtx *operands; rtx *operands;
char **constraints;
int i; 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) if (noperands < 0)
return 0; return 0;
if (noperands == 0) if (noperands == 0)
return 1; return 1;
operands = (rtx *) alloca (noperands * sizeof (rtx)); 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++) 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 1;
} }
...@@ -1493,6 +1512,204 @@ decode_asm_operands (body, operands, operand_locs, constraints, modes) ...@@ -1493,6 +1512,204 @@ decode_asm_operands (body, operands, operand_locs, constraints, modes)
return template; 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, /* 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. return the location (type rtx *) of the pointer to that constant term.
......
...@@ -70,6 +70,7 @@ extern void init_recog PROTO((void)); ...@@ -70,6 +70,7 @@ extern void init_recog PROTO((void));
extern void init_recog_no_volatile PROTO((void)); extern void init_recog_no_volatile PROTO((void));
extern int recog_memoized PROTO((rtx)); extern int recog_memoized PROTO((rtx));
extern int check_asm_operands 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 validate_change PROTO((rtx, rtx *, rtx, int));
extern int apply_change_group PROTO((void)); extern int apply_change_group PROTO((void));
extern int num_validated_changes PROTO((void)); extern int num_validated_changes PROTO((void));
......
...@@ -1397,9 +1397,10 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line) ...@@ -1397,9 +1397,10 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
for (tail = inputs; tail; tail = TREE_CHAIN (tail)) for (tail = inputs; tail; tail = TREE_CHAIN (tail))
{ {
int j; int j;
int allows_reg = 0; int allows_reg = 0, allows_mem = 0;
char *constraint; char *constraint, *orig_constraint;
int c_len; int c_len;
rtx op;
/* If there's an erroneous arg, emit no insn, /* If there's an erroneous arg, emit no insn,
because the ASM_INPUT would get VOIDmode because the ASM_INPUT would get VOIDmode
...@@ -1417,6 +1418,7 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line) ...@@ -1417,6 +1418,7 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
c_len = TREE_STRING_LENGTH (TREE_PURPOSE (tail)) - 1; c_len = TREE_STRING_LENGTH (TREE_PURPOSE (tail)) - 1;
constraint = TREE_STRING_POINTER (TREE_PURPOSE (tail)); constraint = TREE_STRING_POINTER (TREE_PURPOSE (tail));
orig_constraint = constraint;
/* Make sure constraint has neither `=', `+', nor '&'. */ /* Make sure constraint has neither `=', `+', nor '&'. */
...@@ -1424,19 +1426,28 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line) ...@@ -1424,19 +1426,28 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
switch (constraint[j]) switch (constraint[j])
{ {
case '+': case '=': case '&': case '+': case '=': case '&':
error ("input operand constraint contains `%c'", constraint[j]); if (constraint == orig_constraint)
return; {
error ("input operand constraint contains `%c'", constraint[j]);
return;
}
break;
case '%': case '%':
if (i + 1 == ninputs - ninout) if (constraint == orig_constraint
&& i + 1 == ninputs - ninout)
{ {
error ("`%%' constraint used with last operand"); error ("`%%' constraint used with last operand");
return; return;
} }
break; break;
case 'V': case 'm': case 'o':
allows_mem = 1;
break;
case '<': case '>':
case '?': case '!': case '*': case '?': case '!': case '*':
case 'V': case 'm': case 'o': case '<': case '>':
case 'E': case 'F': case 'G': case 'H': case 'X': case 'E': case 'F': case 'G': case 'H': case 'X':
case 's': case 'i': case 'n': case 's': case 'i': case 'n':
case 'I': case 'J': case 'K': case 'L': case 'M': case 'I': case 'J': case 'K': case 'L': case 'M':
...@@ -1460,48 +1471,73 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line) ...@@ -1460,48 +1471,73 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
return; 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 ... */ /* ... fall through ... */
case 'p': case 'g': case 'r': case 'p': case 'r':
default: default:
allows_reg = 1; allows_reg = 1;
break; break;
case 'g':
allows_reg = 1;
allows_mem = 1;
break;
} }
if (! allows_reg) if (! allows_reg && allows_mem)
mark_addressable (TREE_VALUE (tail)); mark_addressable (TREE_VALUE (tail));
XVECEXP (body, 3, i) /* argvec */ op = expand_expr (TREE_VALUE (tail), NULL_RTX, VOIDmode, 0);
= 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));
}
if (! allows_reg if (! asm_operand_ok (op, constraint))
&& (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)); if (allows_reg)
rtx memloc = assign_temp (type, 1, 1, 1); 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)); emit_move_insn (memloc, op);
XVECEXP (body, 3, i) = memloc; 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 */ XVECEXP (body, 4, i) /* constraints */
= gen_rtx_ASM_INPUT (TYPE_MODE (TREE_TYPE (TREE_VALUE (tail))), = gen_rtx_ASM_INPUT (TYPE_MODE (TREE_TYPE (TREE_VALUE (tail))),
constraint); orig_constraint);
i++; i++;
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment