Commit f62a15e3 by Bernd Schmidt Committed by Bernd Schmidt

final.c (cleanup_subreg_operands): Delete some unused code.

	* final.c (cleanup_subreg_operands): Delete some unused code.
	* recog.h (MAX_RECOG_ALTERNATIVES): New macro.
	(struct insn_alternative): New structure definition.
	(recog_op_alt): Declare variable.
	(preprocess_constraints): Declare function.
	* recog.c (recog_op_alt): New variable.
	(extract_insn): Verify number of alternatives is in range.
	(preprocess_constraints): New function.
	* reg-stack.c: Include recog.h.
	(constrain_asm_operands): Delete.
	(get_asm_operand_lengths): Delete.
	(get_asm_operand_n_inputs): New function.
	(record_asm_reg_life): Delete OPERANDS, CONSTRAINTS, N_INPUTS and
	N_OUTPUTS args.  All callers changed.
	Compute number of inputs and outputs here by calling
	get_asm_operand_n_inputs.
	Instead of constrain_asm_operands, call extract_insn,
	constrain_operands and preprocess_constaints.  Use information
	computed by these functions throughout.
	(record_reg_life): Delete code that is unused due to changes in
	record_asm_reg_life.
	(subst_asm_stack_regs): Delete OPERANDS, OPERAND_LOC, CONSTRAINTS,
	N_INPUTS and N_OUTPUTS args.  All callers changed.
	Similar changes as in record_asm_reg_life.
	(subst_stack_regs): Move n_operands declaration into the if statement
	where it's used.
	Delete code that is unused due to changes in subst_asm_stack_regs.
	* stmt.c (expand_asm_operands): Verify number of alternatives is in
	range.
	* Makefile.in (reg-stack.o): Depend on recog.h.

From-SVN: r24090
parent 71eb0b9e
Fri Dec 4 20:15:57 1998 Bernd Schmidt <crux@pool.informatik.rwth-aachen.de>
* final.c (cleanup_subreg_operands): Delete some unused code.
* recog.h (MAX_RECOG_ALTERNATIVES): New macro.
(struct insn_alternative): New structure definition.
(recog_op_alt): Declare variable.
(preprocess_constraints): Declare function.
* recog.c (recog_op_alt): New variable.
(extract_insn): Verify number of alternatives is in range.
(preprocess_constraints): New function.
* reg-stack.c: Include recog.h.
(constrain_asm_operands): Delete.
(get_asm_operand_lengths): Delete.
(get_asm_operand_n_inputs): New function.
(record_asm_reg_life): Delete OPERANDS, CONSTRAINTS, N_INPUTS and
N_OUTPUTS args. All callers changed.
Compute number of inputs and outputs here by calling
get_asm_operand_n_inputs.
Instead of constrain_asm_operands, call extract_insn,
constrain_operands and preprocess_constaints. Use information
computed by these functions throughout.
(record_reg_life): Delete code that is unused due to changes in
record_asm_reg_life.
(subst_asm_stack_regs): Delete OPERANDS, OPERAND_LOC, CONSTRAINTS,
N_INPUTS and N_OUTPUTS args. All callers changed.
Similar changes as in record_asm_reg_life.
(subst_stack_regs): Move n_operands declaration into the if statement
where it's used.
Delete code that is unused due to changes in subst_asm_stack_regs.
* stmt.c (expand_asm_operands): Verify number of alternatives is in
range.
* Makefile.in (reg-stack.o): Depend on recog.h.
Fri Dec 4 02:23:24 1998 Jeffrey A Law (law@cygnus.com) Fri Dec 4 02:23:24 1998 Jeffrey A Law (law@cygnus.com)
* except.c (set_exception_version_code): Argument is an "int". * except.c (set_exception_version_code): Argument is an "int".
......
...@@ -1535,7 +1535,7 @@ final.o : final.c $(CONFIG_H) system.h $(RTL_H) $(TREE_H) flags.h $(REGS_H) \ ...@@ -1535,7 +1535,7 @@ final.o : final.c $(CONFIG_H) system.h $(RTL_H) $(TREE_H) flags.h $(REGS_H) \
recog.o : recog.c $(CONFIG_H) system.h $(RTL_H) \ recog.o : recog.c $(CONFIG_H) system.h $(RTL_H) \
$(REGS_H) $(RECOG_H) hard-reg-set.h flags.h insn-config.h insn-attr.h \ $(REGS_H) $(RECOG_H) hard-reg-set.h flags.h insn-config.h insn-attr.h \
insn-flags.h insn-codes.h real.h toplev.h insn-flags.h insn-codes.h real.h toplev.h
reg-stack.o : reg-stack.c $(CONFIG_H) system.h $(RTL_H) $(TREE_H) \ reg-stack.o : reg-stack.c $(CONFIG_H) system.h $(RTL_H) $(TREE_H) recog.h \
$(REGS_H) hard-reg-set.h flags.h insn-config.h insn-flags.h toplev.h $(REGS_H) hard-reg-set.h flags.h insn-config.h insn-flags.h toplev.h
dyn-string.o: dyn-string.c dyn-string.h $(CONFIG_H) system.h dyn-string.o: dyn-string.c dyn-string.h $(CONFIG_H) system.h
......
...@@ -3031,23 +3031,8 @@ void ...@@ -3031,23 +3031,8 @@ void
cleanup_subreg_operands (insn) cleanup_subreg_operands (insn)
rtx insn; rtx insn;
{ {
int insn_code_number, i; int i;
/* Ignore things we can not handle. */
if (GET_RTX_CLASS (GET_CODE (insn)) != 'i'
|| GET_CODE (PATTERN (insn)) == USE
|| GET_CODE (PATTERN (insn)) == ADDR_VEC
|| GET_CODE (PATTERN (insn)) == ADDR_DIFF_VEC
|| GET_CODE (PATTERN (insn)) == ASM_INPUT
|| asm_noperands (PATTERN (insn)) >= 0)
return;
/* Try to recognize the instruction.
If successful, verify that the operands satisfy the
constraints for the instruction. Crash if they don't,
since `reload' should have changed them so that they do. */
insn_code_number = recog_memoized (insn);
extract_insn (insn); extract_insn (insn);
for (i = 0; i < recog_n_operands; i++) for (i = 0; i < recog_n_operands; i++)
{ {
......
...@@ -96,6 +96,10 @@ enum op_type recog_op_type[MAX_RECOG_OPERANDS]; ...@@ -96,6 +96,10 @@ enum op_type recog_op_type[MAX_RECOG_OPERANDS];
char recog_operand_address_p[MAX_RECOG_OPERANDS]; char recog_operand_address_p[MAX_RECOG_OPERANDS];
#endif #endif
/* Contains a vector of operand_alternative structures for every operand.
Set up by preprocess_constraints. */
struct operand_alternative recog_op_alt[MAX_RECOG_OPERANDS][MAX_RECOG_ALTERNATIVES];
/* On return from `constrain_operands', indicate which alternative /* On return from `constrain_operands', indicate which alternative
was satisfied. */ was satisfied. */
...@@ -1803,8 +1807,115 @@ extract_insn (insn) ...@@ -1803,8 +1807,115 @@ extract_insn (insn)
recog_op_type[i] = (recog_constraints[i][0] == '=' ? OP_OUT recog_op_type[i] = (recog_constraints[i][0] == '=' ? OP_OUT
: recog_constraints[i][0] == '+' ? OP_INOUT : recog_constraints[i][0] == '+' ? OP_INOUT
: OP_IN); : OP_IN);
if (recog_n_alternatives > MAX_RECOG_ALTERNATIVES)
abort ();
} }
/* After calling extract_insn, you can use this function to extract some
information from the constraint strings into a more usable form.
The collected data is stored in recog_op_alt. */
void
preprocess_constraints ()
{
int i;
for (i = 0; i < recog_n_operands; i++)
{
int j;
struct operand_alternative *op_alt;
char *p = recog_constraints[i];
op_alt = recog_op_alt[i];
for (j = 0; j < recog_n_alternatives; j++)
{
op_alt[j].class = NO_REGS;
op_alt[j].constraint = p;
op_alt[j].matches = -1;
op_alt[j].matched = -1;
if (*p == '\0' || *p == ',')
{
op_alt[j].anything_ok = 1;
continue;
}
for (;;)
{
char c = *p++;
if (c == '#')
do
c = *p++;
while (c != ',' && c != '\0');
if (c == ',' || c == '\0')
break;
switch (c)
{
case '=': case '+': case '*': case '%':
case 'E': case 'F': case 'G': case 'H':
case 's': case 'i': case 'n':
case 'I': case 'J': case 'K': case 'L':
case 'M': case 'N': case 'O': case 'P':
#ifdef EXTRA_CONSTRAINT
case 'Q': case 'R': case 'S': case 'T': case 'U':
#endif
/* These don't say anything we care about. */
break;
case '?':
op_alt[j].reject += 6;
break;
case '!':
op_alt[j].reject += 600;
break;
case '&':
op_alt[j].earlyclobber = 1;
break;
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
op_alt[j].matches = c - '0';
op_alt[op_alt[j].matches].matched = i;
break;
case 'm':
op_alt[j].memory_ok = 1;
break;
case '<':
op_alt[j].decmem_ok = 1;
break;
case '>':
op_alt[j].incmem_ok = 1;
break;
case 'V':
op_alt[j].nonoffmem_ok = 1;
break;
case 'o':
op_alt[j].offmem_ok = 1;
break;
case 'X':
op_alt[j].anything_ok = 1;
break;
case 'p':
op_alt[j].class = reg_class_subunion[(int) op_alt[j].class][(int) BASE_REG_CLASS];
break;
case 'g': case 'r':
op_alt[j].class = reg_class_subunion[(int) op_alt[j].class][(int) GENERAL_REGS];
break;
default:
op_alt[j].class = reg_class_subunion[(int) op_alt[j].class][(int) REG_CLASS_FROM_LETTER (c)];
break;
}
}
}
}
}
#ifdef REGISTER_CONSTRAINTS #ifdef REGISTER_CONSTRAINTS
/* Check the operands of an insn against the insn's operand constraints /* Check the operands of an insn against the insn's operand constraints
......
...@@ -18,6 +18,9 @@ along with GNU CC; see the file COPYING. If not, write to ...@@ -18,6 +18,9 @@ along with GNU CC; see the file COPYING. If not, write to
the Free Software Foundation, 59 Temple Place - Suite 330, the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */ Boston, MA 02111-1307, USA. */
/* Random number that should be large enough for all purposes. */
#define MAX_RECOG_ALTERNATIVES 30
/* Types of operands. */ /* Types of operands. */
enum op_type { enum op_type {
OP_IN, OP_IN,
...@@ -25,6 +28,44 @@ enum op_type { ...@@ -25,6 +28,44 @@ enum op_type {
OP_INOUT OP_INOUT
}; };
struct operand_alternative
{
/* Pointer to the beginning of the constraint string for this alternative,
for easier access by alternative number. */
char *constraint;
/* The register class valid for this alternative (possibly NO_REGS). */
enum reg_class class;
/* "Badness" of this alternative, computed from number of '?' and '!'
characters in the constraint string. */
unsigned int reject;
/* -1 if no matching constraint was found, or an operand number. */
int matches;
/* The same information, but reversed: -1 if this operand is not
matched by any other, or the operand number of the operand that
matches this one. */
int matched;
/* Nonzero if '&' was found in the constraint string. */
unsigned int earlyclobber:1;
/* Nonzero if 'm' was found in the constraint string. */
unsigned int memory_ok:1;
/* Nonzero if 'o' was found in the constraint string. */
unsigned int offmem_ok:1;
/* Nonzero if 'V' was found in the constraint string. */
unsigned int nonoffmem_ok:1;
/* Nonzero if '<' was found in the constraint string. */
unsigned int decmem_ok:1;
/* Nonzero if '>' was found in the constraint string. */
unsigned int incmem_ok:1;
/* Nonzero if 'X' was found in the constraint string, or if the constraint
string for this alternative was empty. */
unsigned int anything_ok:1;
};
extern void init_recog PROTO((void)); 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));
...@@ -67,6 +108,7 @@ extern int recog PROTO((rtx, rtx, int *)); ...@@ -67,6 +108,7 @@ extern int recog PROTO((rtx, rtx, int *));
extern void add_clobbers PROTO((rtx, int)); extern void add_clobbers PROTO((rtx, int));
extern void insn_extract PROTO((rtx)); extern void insn_extract PROTO((rtx));
extern void extract_insn PROTO((rtx)); extern void extract_insn PROTO((rtx));
extern void preprocess_constraints PROTO((void));
/* Nonzero means volatile operands are recognized. */ /* Nonzero means volatile operands are recognized. */
extern int volatile_ok; extern int volatile_ok;
...@@ -116,6 +158,10 @@ extern enum op_type recog_op_type[]; ...@@ -116,6 +158,10 @@ extern enum op_type recog_op_type[];
extern char recog_operand_address_p[]; extern char recog_operand_address_p[];
#endif #endif
/* Contains a vector of operand_alternative structures for every operand.
Set up by preprocess_constraints. */
struct operand_alternative recog_op_alt[MAX_RECOG_OPERANDS][MAX_RECOG_ALTERNATIVES];
/* Access the output function for CODE. */ /* Access the output function for CODE. */
#define OUT_FCN(CODE) (*insn_outfun[(int) (CODE)]) #define OUT_FCN(CODE) (*insn_outfun[(int) (CODE)])
......
...@@ -166,6 +166,7 @@ Boston, MA 02111-1307, USA. */ ...@@ -166,6 +166,7 @@ Boston, MA 02111-1307, USA. */
#include "hard-reg-set.h" #include "hard-reg-set.h"
#include "flags.h" #include "flags.h"
#include "insn-flags.h" #include "insn-flags.h"
#include "recog.h"
#include "toplev.h" #include "toplev.h"
#ifdef STACK_REGS #ifdef STACK_REGS
...@@ -241,14 +242,11 @@ static void straighten_stack PROTO((rtx, stack)); ...@@ -241,14 +242,11 @@ static void straighten_stack PROTO((rtx, stack));
static void pop_stack PROTO((stack, int)); static void pop_stack PROTO((stack, int));
static void record_label_references PROTO((rtx, rtx)); static void record_label_references PROTO((rtx, rtx));
static rtx *get_true_reg PROTO((rtx *)); static rtx *get_true_reg PROTO((rtx *));
static int constrain_asm_operands PROTO((int, rtx *, char **, int *,
enum reg_class *));
static void record_asm_reg_life PROTO((rtx,stack, rtx *, char **, static void record_asm_reg_life PROTO((rtx, stack));
int, int));
static void record_reg_life_pat PROTO((rtx, HARD_REG_SET *, static void record_reg_life_pat PROTO((rtx, HARD_REG_SET *,
HARD_REG_SET *, int)); HARD_REG_SET *, int));
static void get_asm_operand_lengths PROTO((rtx, int, int *, int *)); static int get_asm_operand_n_inputs PROTO((rtx));
static void record_reg_life PROTO((rtx, int, stack)); static void record_reg_life PROTO((rtx, int, stack));
static void find_blocks PROTO((rtx)); static void find_blocks PROTO((rtx));
static rtx stack_result PROTO((tree)); static rtx stack_result PROTO((tree));
...@@ -263,8 +261,7 @@ static void move_for_stack_reg PROTO((rtx, stack, rtx)); ...@@ -263,8 +261,7 @@ static void move_for_stack_reg PROTO((rtx, stack, rtx));
static void swap_rtx_condition PROTO((rtx)); static void swap_rtx_condition PROTO((rtx));
static void compare_for_stack_reg PROTO((rtx, stack, rtx)); static void compare_for_stack_reg PROTO((rtx, stack, rtx));
static void subst_stack_regs_pat PROTO((rtx, stack, rtx)); static void subst_stack_regs_pat PROTO((rtx, stack, rtx));
static void subst_asm_stack_regs PROTO((rtx, stack, rtx *, rtx **, static void subst_asm_stack_regs PROTO((rtx, stack));
char **, int, int));
static void subst_stack_regs PROTO((rtx, stack)); static void subst_stack_regs PROTO((rtx, stack));
static void change_stack PROTO((rtx, stack, stack, rtx (*) ())); static void change_stack PROTO((rtx, stack, stack, rtx (*) ()));
...@@ -607,297 +604,8 @@ get_true_reg (pat) ...@@ -607,297 +604,8 @@ get_true_reg (pat)
} }
} }
/* Scan the OPERANDS and OPERAND_CONSTRAINTS of an asm_operands.
N_OPERANDS is the total number of operands. Return which alternative
matched, or -1 is no alternative matches.
OPERAND_MATCHES is an array which indicates which operand this
operand matches due to the constraints, or -1 if no match is required.
If two operands match by coincidence, but are not required to match by
the constraints, -1 is returned.
OPERAND_CLASS is an array which indicates the smallest class
required by the constraints. If the alternative that matches calls
for some class `class', and the operand matches a subclass of `class',
OPERAND_CLASS is set to `class' as required by the constraints, not to
the subclass. If an alternative allows more than one class,
OPERAND_CLASS is set to the smallest class that is a union of the
allowed classes. */
static int
constrain_asm_operands (n_operands, operands, operand_constraints,
operand_matches, operand_class)
int n_operands;
rtx *operands;
char **operand_constraints;
int *operand_matches;
enum reg_class *operand_class;
{
char **constraints = (char **) alloca (n_operands * sizeof (char *));
char *q;
int this_alternative, this_operand;
int n_alternatives;
int j;
for (j = 0; j < n_operands; j++)
constraints[j] = operand_constraints[j];
/* Compute the number of alternatives in the operands. reload has
already guaranteed that all operands have the same number of
alternatives. */
if (n_operands == 0)
n_alternatives = 0;
else
{
n_alternatives = 1;
for (q = constraints[0]; *q; q++)
n_alternatives += (*q == ',');
}
this_alternative = 0;
while (this_alternative < n_alternatives)
{
int lose = 0;
int i;
/* No operands match, no narrow class requirements yet. */
for (i = 0; i < n_operands; i++)
{
operand_matches[i] = -1;
operand_class[i] = NO_REGS;
}
for (this_operand = 0; this_operand < n_operands; this_operand++)
{
rtx op = operands[this_operand];
enum machine_mode mode = GET_MODE (op);
char *p = constraints[this_operand];
int offset = 0;
int win = 0;
int c;
if (GET_CODE (op) == SUBREG)
{
if (GET_CODE (SUBREG_REG (op)) == REG
&& REGNO (SUBREG_REG (op)) < FIRST_PSEUDO_REGISTER)
offset = SUBREG_WORD (op);
op = SUBREG_REG (op);
}
/* An empty constraint or empty alternative
allows anything which matched the pattern. */
if (*p == 0 || *p == ',')
win = 1;
while (*p && (c = *p++) != ',')
switch (c)
{
case '=':
case '+':
case '?':
case '&':
case '!':
case '*':
case '%':
/* Ignore these. */
break;
case '#':
/* Ignore rest of this alternative. */
while (*p && *p != ',') p++;
break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
/* This operand must be the same as a previous one.
This kind of constraint is used for instructions such
as add when they take only two operands.
Note that the lower-numbered operand is passed first. */
if (operands_match_p (operands[c - '0'],
operands[this_operand]))
{
operand_matches[this_operand] = c - '0';
win = 1;
}
break;
case 'p':
/* p is used for address_operands. Since this is an asm,
just to make sure that the operand is valid for Pmode. */
if (strict_memory_address_p (Pmode, op))
win = 1;
break;
case 'g':
/* Anything goes unless it is a REG and really has a hard reg
but the hard reg is not in the class GENERAL_REGS. */
if (GENERAL_REGS == ALL_REGS
|| GET_CODE (op) != REG
|| reg_fits_class_p (op, GENERAL_REGS, offset, mode))
{
if (GET_CODE (op) == REG)
operand_class[this_operand]
= reg_class_subunion[(int) operand_class[this_operand]][(int) GENERAL_REGS];
win = 1;
}
break;
case 'r':
if (GET_CODE (op) == REG
&& (GENERAL_REGS == ALL_REGS
|| reg_fits_class_p (op, GENERAL_REGS, offset, mode)))
{
operand_class[this_operand]
= reg_class_subunion[(int) operand_class[this_operand]][(int) GENERAL_REGS];
win = 1;
}
break;
case 'X':
/* This is used for a MATCH_SCRATCH in the cases when we
don't actually need anything. So anything goes any time. */
win = 1;
break;
case 'm':
if (GET_CODE (op) == MEM)
win = 1;
break;
case '<':
if (GET_CODE (op) == MEM
&& (GET_CODE (XEXP (op, 0)) == PRE_DEC
|| GET_CODE (XEXP (op, 0)) == POST_DEC))
win = 1;
break;
case '>':
if (GET_CODE (op) == MEM
&& (GET_CODE (XEXP (op, 0)) == PRE_INC
|| GET_CODE (XEXP (op, 0)) == POST_INC))
win = 1;
break;
case 'E':
/* Match any CONST_DOUBLE, 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_CODE (op) != VOIDmode && ! flag_pretend_float)
break;
if (GET_CODE (op) == CONST_DOUBLE)
win = 1;
break;
case 'F':
if (GET_CODE (op) == CONST_DOUBLE)
win = 1;
break;
case 'G':
case 'H':
if (GET_CODE (op) == CONST_DOUBLE
&& CONST_DOUBLE_OK_FOR_LETTER_P (op, c))
win = 1;
break;
case 's':
if (GET_CODE (op) == CONST_INT
|| (GET_CODE (op) == CONST_DOUBLE
&& GET_MODE (op) == VOIDmode))
break;
/* Fall through */
case 'i':
if (CONSTANT_P (op))
win = 1;
break;
case 'n':
if (GET_CODE (op) == CONST_INT
|| (GET_CODE (op) == CONST_DOUBLE
&& GET_MODE (op) == VOIDmode))
win = 1;
break;
case 'I':
case 'J':
case 'K':
case 'L':
case 'M':
case 'N':
case 'O':
case 'P':
if (GET_CODE (op) == CONST_INT
&& CONST_OK_FOR_LETTER_P (INTVAL (op), c))
win = 1;
break;
#ifdef EXTRA_CONSTRAINT
case 'Q':
case 'R':
case 'S':
case 'T':
case 'U':
if (EXTRA_CONSTRAINT (op, c))
win = 1;
break;
#endif
case 'V':
if (GET_CODE (op) == MEM && ! offsettable_memref_p (op))
win = 1;
break;
case 'o':
if (offsettable_memref_p (op))
win = 1;
break;
default:
if (GET_CODE (op) == REG
&& reg_fits_class_p (op, REG_CLASS_FROM_LETTER (c),
offset, mode))
{
operand_class[this_operand]
= reg_class_subunion[(int)operand_class[this_operand]][(int) REG_CLASS_FROM_LETTER (c)];
win = 1;
}
}
constraints[this_operand] = p;
/* If this operand did not win somehow,
this alternative loses. */
if (! win)
lose = 1;
}
/* This alternative won; the operands are ok.
Change whichever operands this alternative says to change. */
if (! lose)
break;
this_alternative++;
}
/* For operands constrained to match another operand, copy the other
operand's class to this operand's class. */
for (j = 0; j < n_operands; j++)
if (operand_matches[j] >= 0)
operand_class[j] = operand_class[operand_matches[j]];
return this_alternative == n_alternatives ? -1 : this_alternative;
}
/* Record the life info of each stack reg in INSN, updating REGSTACK. /* Record the life info of each stack reg in INSN, updating REGSTACK.
N_INPUTS is the number of inputs; N_OUTPUTS the outputs. CONSTRAINTS N_INPUTS is the number of inputs; N_OUTPUTS the outputs.
is an array of the constraint strings used in the asm statement.
OPERANDS is an array of all operands for the insn, and is assumed to OPERANDS is an array of all operands for the insn, and is assumed to
contain all output operands, then all inputs operands. contain all output operands, then all inputs operands.
...@@ -906,43 +614,47 @@ constrain_asm_operands (n_operands, operands, operand_constraints, ...@@ -906,43 +614,47 @@ constrain_asm_operands (n_operands, operands, operand_constraints,
numbers below refer to that explanation. */ numbers below refer to that explanation. */
static void static void
record_asm_reg_life (insn, regstack, operands, constraints, record_asm_reg_life (insn, regstack)
n_inputs, n_outputs)
rtx insn; rtx insn;
stack regstack; stack regstack;
rtx *operands;
char **constraints;
int n_inputs, n_outputs;
{ {
int i; int i;
int n_operands = n_inputs + n_outputs;
int first_input = n_outputs;
int n_clobbers; int n_clobbers;
int malformed_asm = 0; int malformed_asm = 0;
rtx body = PATTERN (insn); rtx body = PATTERN (insn);
int *operand_matches = (int *) alloca (n_operands * sizeof (int));
enum reg_class *operand_class
= (enum reg_class *) alloca (n_operands * sizeof (enum reg_class));
int reg_used_as_output[FIRST_PSEUDO_REGISTER]; int reg_used_as_output[FIRST_PSEUDO_REGISTER];
int implicitly_dies[FIRST_PSEUDO_REGISTER]; int implicitly_dies[FIRST_PSEUDO_REGISTER];
int alt;
rtx *clobber_reg; rtx *clobber_reg;
int n_inputs, n_outputs;
/* Find out what the constraints require. If no constraint /* Find out what the constraints require. If no constraint
alternative matches, this asm is malformed. */ alternative matches, this asm is malformed. */
i = constrain_asm_operands (n_operands, operands, constraints, extract_insn (insn);
operand_matches, operand_class); constrain_operands (1);
if (i < 0) alt = which_alternative;
malformed_asm = 1;
preprocess_constraints ();
n_inputs = get_asm_operand_n_inputs (body);
n_outputs = recog_n_operands - n_inputs;
if (alt < 0)
{
malformed_asm = 1;
/* Avoid further trouble with this insn. */
PATTERN (insn) = gen_rtx_USE (VOIDmode, const0_rtx);
PUT_MODE (insn, VOIDmode);
return;
}
/* Strip SUBREGs here to make the following code simpler. */ /* Strip SUBREGs here to make the following code simpler. */
for (i = 0; i < n_operands; i++) for (i = 0; i < recog_n_operands; i++)
if (GET_CODE (operands[i]) == SUBREG if (GET_CODE (recog_operand[i]) == SUBREG
&& GET_CODE (SUBREG_REG (operands[i])) == REG) && GET_CODE (SUBREG_REG (recog_operand[i])) == REG)
operands[i] = SUBREG_REG (operands[i]); recog_operand[i] = SUBREG_REG (recog_operand[i]);
/* Set up CLOBBER_REG. */ /* Set up CLOBBER_REG. */
...@@ -978,15 +690,15 @@ record_asm_reg_life (insn, regstack, operands, constraints, ...@@ -978,15 +690,15 @@ record_asm_reg_life (insn, regstack, operands, constraints,
bzero ((char *) reg_used_as_output, sizeof (reg_used_as_output)); bzero ((char *) reg_used_as_output, sizeof (reg_used_as_output));
for (i = 0; i < n_outputs; i++) for (i = 0; i < n_outputs; i++)
if (STACK_REG_P (operands[i])) if (STACK_REG_P (recog_operand[i]))
{ {
if (reg_class_size[(int) operand_class[i]] != 1) if (reg_class_size[(int) recog_op_alt[i][alt].class] != 1)
{ {
error_for_asm (insn, "Output constraint %d must specify a single register", i); error_for_asm (insn, "Output constraint %d must specify a single register", i);
malformed_asm = 1; malformed_asm = 1;
} }
else else
reg_used_as_output[REGNO (operands[i])] = 1; reg_used_as_output[REGNO (recog_operand[i])] = 1;
} }
...@@ -1011,19 +723,19 @@ record_asm_reg_life (insn, regstack, operands, constraints, ...@@ -1011,19 +723,19 @@ record_asm_reg_life (insn, regstack, operands, constraints,
popped. */ popped. */
bzero ((char *) implicitly_dies, sizeof (implicitly_dies)); bzero ((char *) implicitly_dies, sizeof (implicitly_dies));
for (i = first_input; i < first_input + n_inputs; i++) for (i = n_outputs; i < n_outputs + n_inputs; i++)
if (STACK_REG_P (operands[i])) if (STACK_REG_P (recog_operand[i]))
{ {
/* An input reg is implicitly popped if it is tied to an /* An input reg is implicitly popped if it is tied to an
output, or if there is a CLOBBER for it. */ output, or if there is a CLOBBER for it. */
int j; int j;
for (j = 0; j < n_clobbers; j++) for (j = 0; j < n_clobbers; j++)
if (operands_match_p (clobber_reg[j], operands[i])) if (operands_match_p (clobber_reg[j], recog_operand[i]))
break; break;
if (j < n_clobbers || operand_matches[i] >= 0) if (j < n_clobbers || recog_op_alt[i][alt].matches >= 0)
implicitly_dies[REGNO (operands[i])] = 1; implicitly_dies[REGNO (recog_operand[i])] = 1;
} }
/* Search for first non-popped reg. */ /* Search for first non-popped reg. */
...@@ -1049,13 +761,13 @@ record_asm_reg_life (insn, regstack, operands, constraints, ...@@ -1049,13 +761,13 @@ record_asm_reg_life (insn, regstack, operands, constraints,
??? Detect this more deterministically by having constraint_asm_operands ??? Detect this more deterministically by having constraint_asm_operands
record any earlyclobber. */ record any earlyclobber. */
for (i = first_input; i < first_input + n_inputs; i++) for (i = n_outputs; i < n_outputs + n_inputs; i++)
if (operand_matches[i] == -1) if (recog_op_alt[i][alt].matches == -1)
{ {
int j; int j;
for (j = 0; j < n_outputs; j++) for (j = 0; j < n_outputs; j++)
if (operands_match_p (operands[j], operands[i])) if (operands_match_p (recog_operand[j], recog_operand[i]))
{ {
error_for_asm (insn, error_for_asm (insn,
"Output operand %d must use `&' constraint", j); "Output operand %d must use `&' constraint", j);
...@@ -1074,7 +786,7 @@ record_asm_reg_life (insn, regstack, operands, constraints, ...@@ -1074,7 +786,7 @@ record_asm_reg_life (insn, regstack, operands, constraints,
/* Process all outputs */ /* Process all outputs */
for (i = 0; i < n_outputs; i++) for (i = 0; i < n_outputs; i++)
{ {
rtx op = operands[i]; rtx op = recog_operand[i];
if (! STACK_REG_P (op)) if (! STACK_REG_P (op))
{ {
...@@ -1096,11 +808,12 @@ record_asm_reg_life (insn, regstack, operands, constraints, ...@@ -1096,11 +808,12 @@ record_asm_reg_life (insn, regstack, operands, constraints,
} }
/* Process all inputs */ /* Process all inputs */
for (i = first_input; i < first_input + n_inputs; i++) for (i = n_outputs; i < n_outputs + n_inputs; i++)
{ {
if (! STACK_REG_P (operands[i])) rtx op = recog_operand[i];
if (! STACK_REG_P (op))
{ {
if (stack_regs_mentioned_p (operands[i])) if (stack_regs_mentioned_p (op))
abort (); abort ();
else else
continue; continue;
...@@ -1110,13 +823,12 @@ record_asm_reg_life (insn, regstack, operands, constraints, ...@@ -1110,13 +823,12 @@ record_asm_reg_life (insn, regstack, operands, constraints,
But don't record a death note if there is already a death note, But don't record a death note if there is already a death note,
or if the input is also an output. */ or if the input is also an output. */
if (! TEST_HARD_REG_BIT (regstack->reg_set, REGNO (operands[i])) if (! TEST_HARD_REG_BIT (regstack->reg_set, REGNO (op))
&& operand_matches[i] == -1 && recog_op_alt[i][alt].matches == -1
&& find_regno_note (insn, REG_DEAD, REGNO (operands[i])) == NULL_RTX) && find_regno_note (insn, REG_DEAD, REGNO (op)) == NULL_RTX)
REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_DEAD, operands[i], REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_DEAD, op, REG_NOTES (insn));
REG_NOTES (insn));
SET_HARD_REG_BIT (regstack->reg_set, REGNO (operands[i])); SET_HARD_REG_BIT (regstack->reg_set, REGNO (op));
} }
} }
...@@ -1178,29 +890,25 @@ record_reg_life_pat (pat, src, dest, douse) ...@@ -1178,29 +890,25 @@ record_reg_life_pat (pat, src, dest, douse)
N_INPUTS and N_OUTPUTS are pointers to ints into which the results are N_INPUTS and N_OUTPUTS are pointers to ints into which the results are
placed. */ placed. */
static void static int
get_asm_operand_lengths (body, n_operands, n_inputs, n_outputs) get_asm_operand_n_inputs (body)
rtx body; rtx body;
int n_operands;
int *n_inputs, *n_outputs;
{ {
if (GET_CODE (body) == SET && GET_CODE (SET_SRC (body)) == ASM_OPERANDS) if (GET_CODE (body) == SET && GET_CODE (SET_SRC (body)) == ASM_OPERANDS)
*n_inputs = ASM_OPERANDS_INPUT_LENGTH (SET_SRC (body)); return ASM_OPERANDS_INPUT_LENGTH (SET_SRC (body));
else if (GET_CODE (body) == ASM_OPERANDS) else if (GET_CODE (body) == ASM_OPERANDS)
*n_inputs = ASM_OPERANDS_INPUT_LENGTH (body); return ASM_OPERANDS_INPUT_LENGTH (body);
else if (GET_CODE (body) == PARALLEL else if (GET_CODE (body) == PARALLEL
&& GET_CODE (XVECEXP (body, 0, 0)) == SET) && GET_CODE (XVECEXP (body, 0, 0)) == SET)
*n_inputs = ASM_OPERANDS_INPUT_LENGTH (SET_SRC (XVECEXP (body, 0, 0))); return ASM_OPERANDS_INPUT_LENGTH (SET_SRC (XVECEXP (body, 0, 0)));
else if (GET_CODE (body) == PARALLEL else if (GET_CODE (body) == PARALLEL
&& GET_CODE (XVECEXP (body, 0, 0)) == ASM_OPERANDS) && GET_CODE (XVECEXP (body, 0, 0)) == ASM_OPERANDS)
*n_inputs = ASM_OPERANDS_INPUT_LENGTH (XVECEXP (body, 0, 0)); return ASM_OPERANDS_INPUT_LENGTH (XVECEXP (body, 0, 0));
else
abort ();
*n_outputs = n_operands - *n_inputs; abort ();
} }
/* Scan INSN, which is in BLOCK, and record the life & death of stack /* Scan INSN, which is in BLOCK, and record the life & death of stack
...@@ -1244,18 +952,7 @@ record_reg_life (insn, block, regstack) ...@@ -1244,18 +952,7 @@ record_reg_life (insn, block, regstack)
n_operands = asm_noperands (PATTERN (insn)); n_operands = asm_noperands (PATTERN (insn));
if (n_operands >= 0) if (n_operands >= 0)
{ {
/* This insn is an `asm' with operands. Decode the operands, record_asm_reg_life (insn, regstack);
decide how many are inputs, and record the life information. */
rtx operands[MAX_RECOG_OPERANDS];
rtx body = PATTERN (insn);
int n_inputs, n_outputs;
char **constraints = (char **) alloca (n_operands * sizeof (char *));
decode_asm_operands (body, operands, NULL_PTR, constraints, NULL_PTR);
get_asm_operand_lengths (body, n_operands, &n_inputs, &n_outputs);
record_asm_reg_life (insn, regstack, operands, constraints,
n_inputs, n_outputs);
return; return;
} }
...@@ -2417,12 +2114,7 @@ subst_stack_regs_pat (insn, regstack, pat) ...@@ -2417,12 +2114,7 @@ subst_stack_regs_pat (insn, regstack, pat)
/* Substitute hard regnums for any stack regs in INSN, which has /* Substitute hard regnums for any stack regs in INSN, which has
N_INPUTS inputs and N_OUTPUTS outputs. REGSTACK is the stack info N_INPUTS inputs and N_OUTPUTS outputs. REGSTACK is the stack info
before the insn, and is updated with changes made here. CONSTRAINTS is before the insn, and is updated with changes made here.
an array of the constraint strings used in the asm statement.
OPERANDS is an array of the operands, and OPERANDS_LOC is a
parallel array of where the operands were found. The output operands
all precede the input operands.
There are several requirements and assumptions about the use of There are several requirements and assumptions about the use of
stack-like regs in asm statements. These rules are enforced by stack-like regs in asm statements. These rules are enforced by
...@@ -2431,21 +2123,12 @@ subst_stack_regs_pat (insn, regstack, pat) ...@@ -2431,21 +2123,12 @@ subst_stack_regs_pat (insn, regstack, pat)
requirements, since record_asm_stack_regs removes any problem asm. */ requirements, since record_asm_stack_regs removes any problem asm. */
static void static void
subst_asm_stack_regs (insn, regstack, operands, operands_loc, constraints, subst_asm_stack_regs (insn, regstack)
n_inputs, n_outputs)
rtx insn; rtx insn;
stack regstack; stack regstack;
rtx *operands, **operands_loc;
char **constraints;
int n_inputs, n_outputs;
{ {
int n_operands = n_inputs + n_outputs;
int first_input = n_outputs;
rtx body = PATTERN (insn); rtx body = PATTERN (insn);
int alt;
int *operand_matches = (int *) alloca (n_operands * sizeof (int));
enum reg_class *operand_class
= (enum reg_class *) alloca (n_operands * sizeof (enum reg_class));
rtx *note_reg; /* Array of note contents */ rtx *note_reg; /* Array of note contents */
rtx **note_loc; /* Address of REG field of each note */ rtx **note_loc; /* Address of REG field of each note */
...@@ -2459,24 +2142,31 @@ subst_asm_stack_regs (insn, regstack, operands, operands_loc, constraints, ...@@ -2459,24 +2142,31 @@ subst_asm_stack_regs (insn, regstack, operands, operands_loc, constraints,
int n_clobbers; int n_clobbers;
rtx note; rtx note;
int i; int i;
int n_inputs, n_outputs;
/* Find out what the constraints required. If no constraint /* Find out what the constraints required. If no constraint
alternative matches, that is a compiler bug: we should have caught alternative matches, that is a compiler bug: we should have caught
such an insn during the life analysis pass (and reload should have such an insn during the life analysis pass (and reload should have
caught it regardless). */ caught it regardless). */
extract_insn (insn);
constrain_operands (1);
alt = which_alternative;
i = constrain_asm_operands (n_operands, operands, constraints, preprocess_constraints ();
operand_matches, operand_class);
if (i < 0) n_inputs = get_asm_operand_n_inputs (body);
n_outputs = recog_n_operands - n_inputs;
if (alt < 0)
abort (); abort ();
/* Strip SUBREGs here to make the following code simpler. */ /* Strip SUBREGs here to make the following code simpler. */
for (i = 0; i < n_operands; i++) for (i = 0; i < recog_n_operands; i++)
if (GET_CODE (operands[i]) == SUBREG if (GET_CODE (recog_operand[i]) == SUBREG
&& GET_CODE (SUBREG_REG (operands[i])) == REG) && GET_CODE (SUBREG_REG (recog_operand[i])) == REG)
{ {
operands_loc[i] = & SUBREG_REG (operands[i]); recog_operand_loc[i] = & SUBREG_REG (recog_operand[i]);
operands[i] = SUBREG_REG (operands[i]); recog_operand[i] = SUBREG_REG (recog_operand[i]);
} }
/* Set up NOTE_REG, NOTE_LOC and NOTE_KIND. */ /* Set up NOTE_REG, NOTE_LOC and NOTE_KIND. */
...@@ -2546,34 +2236,35 @@ subst_asm_stack_regs (insn, regstack, operands, operands_loc, constraints, ...@@ -2546,34 +2236,35 @@ subst_asm_stack_regs (insn, regstack, operands, operands_loc, constraints,
/* Put the input regs into the desired place in TEMP_STACK. */ /* Put the input regs into the desired place in TEMP_STACK. */
for (i = first_input; i < first_input + n_inputs; i++) for (i = n_outputs; i < n_outputs + n_inputs; i++)
if (STACK_REG_P (operands[i]) if (STACK_REG_P (recog_operand[i])
&& reg_class_subset_p (operand_class[i], FLOAT_REGS) && reg_class_subset_p (recog_op_alt[i][alt].class,
&& operand_class[i] != FLOAT_REGS) FLOAT_REGS)
&& recog_op_alt[i][alt].class != FLOAT_REGS)
{ {
/* If an operand needs to be in a particular reg in /* If an operand needs to be in a particular reg in
FLOAT_REGS, the constraint was either 't' or 'u'. Since FLOAT_REGS, the constraint was either 't' or 'u'. Since
these constraints are for single register classes, and reload these constraints are for single register classes, and reload
guaranteed that operand[i] is already in that class, we can guaranteed that operand[i] is already in that class, we can
just use REGNO (operands[i]) to know which actual reg this just use REGNO (recog_operand[i]) to know which actual reg this
operand needs to be in. */ operand needs to be in. */
int regno = get_hard_regnum (&temp_stack, operands[i]); int regno = get_hard_regnum (&temp_stack, recog_operand[i]);
if (regno < 0) if (regno < 0)
abort (); abort ();
if (regno != REGNO (operands[i])) if (regno != REGNO (recog_operand[i]))
{ {
/* operands[i] is not in the right place. Find it /* recog_operand[i] is not in the right place. Find it
and swap it with whatever is already in I's place. and swap it with whatever is already in I's place.
K is where operands[i] is now. J is where it should K is where recog_operand[i] is now. J is where it should
be. */ be. */
int j, k, temp; int j, k, temp;
k = temp_stack.top - (regno - FIRST_STACK_REG); k = temp_stack.top - (regno - FIRST_STACK_REG);
j = (temp_stack.top j = (temp_stack.top
- (REGNO (operands[i]) - FIRST_STACK_REG)); - (REGNO (recog_operand[i]) - FIRST_STACK_REG));
temp = temp_stack.reg[k]; temp = temp_stack.reg[k];
temp_stack.reg[k] = temp_stack.reg[j]; temp_stack.reg[k] = temp_stack.reg[j];
...@@ -2589,15 +2280,15 @@ subst_asm_stack_regs (insn, regstack, operands, operands_loc, constraints, ...@@ -2589,15 +2280,15 @@ subst_asm_stack_regs (insn, regstack, operands, operands_loc, constraints,
/* Make the needed input register substitutions. Do death notes and /* Make the needed input register substitutions. Do death notes and
clobbers too, because these are for inputs, not outputs. */ clobbers too, because these are for inputs, not outputs. */
for (i = first_input; i < first_input + n_inputs; i++) for (i = n_outputs; i < n_outputs + n_inputs; i++)
if (STACK_REG_P (operands[i])) if (STACK_REG_P (recog_operand[i]))
{ {
int regnum = get_hard_regnum (regstack, operands[i]); int regnum = get_hard_regnum (regstack, recog_operand[i]);
if (regnum < 0) if (regnum < 0)
abort (); abort ();
replace_reg (operands_loc[i], regnum); replace_reg (recog_operand_loc[i], regnum);
} }
for (i = 0; i < n_notes; i++) for (i = 0; i < n_notes; i++)
...@@ -2629,21 +2320,21 @@ subst_asm_stack_regs (insn, regstack, operands, operands_loc, constraints, ...@@ -2629,21 +2320,21 @@ subst_asm_stack_regs (insn, regstack, operands, operands_loc, constraints,
/* Now remove from REGSTACK any inputs that the asm implicitly popped. */ /* Now remove from REGSTACK any inputs that the asm implicitly popped. */
for (i = first_input; i < first_input + n_inputs; i++) for (i = n_outputs; i < n_outputs + n_inputs; i++)
if (STACK_REG_P (operands[i])) if (STACK_REG_P (recog_operand[i]))
{ {
/* An input reg is implicitly popped if it is tied to an /* An input reg is implicitly popped if it is tied to an
output, or if there is a CLOBBER for it. */ output, or if there is a CLOBBER for it. */
int j; int j;
for (j = 0; j < n_clobbers; j++) for (j = 0; j < n_clobbers; j++)
if (operands_match_p (clobber_reg[j], operands[i])) if (operands_match_p (clobber_reg[j], recog_operand[i]))
break; break;
if (j < n_clobbers || operand_matches[i] >= 0) if (j < n_clobbers || recog_op_alt[i][alt].matches >= 0)
{ {
/* operands[i] might not be at the top of stack. But that's OK, /* recog_operand[i] might not be at the top of stack. But that's
because all we need to do is pop the right number of regs OK, because all we need to do is pop the right number of regs
off of the top of the reg-stack. record_asm_stack_regs off of the top of the reg-stack. record_asm_stack_regs
guaranteed that all implicitly popped regs were grouped guaranteed that all implicitly popped regs were grouped
at the top of the reg-stack. */ at the top of the reg-stack. */
...@@ -2664,7 +2355,7 @@ subst_asm_stack_regs (insn, regstack, operands, operands_loc, constraints, ...@@ -2664,7 +2355,7 @@ subst_asm_stack_regs (insn, regstack, operands, operands_loc, constraints,
int j; int j;
for (j = 0; j < n_outputs; j++) for (j = 0; j < n_outputs; j++)
if (STACK_REG_P (operands[j]) && REGNO (operands[j]) == i) if (STACK_REG_P (recog_operand[j]) && REGNO (recog_operand[j]) == i)
{ {
regstack->reg[++regstack->top] = i; regstack->reg[++regstack->top] = i;
SET_HARD_REG_BIT (regstack->reg_set, i); SET_HARD_REG_BIT (regstack->reg_set, i);
...@@ -2680,31 +2371,32 @@ subst_asm_stack_regs (insn, regstack, operands, operands_loc, constraints, ...@@ -2680,31 +2371,32 @@ subst_asm_stack_regs (insn, regstack, operands, operands_loc, constraints,
in the death notes have already been substituted. */ in the death notes have already been substituted. */
for (i = 0; i < n_outputs; i++) for (i = 0; i < n_outputs; i++)
if (STACK_REG_P (operands[i])) if (STACK_REG_P (recog_operand[i]))
{ {
int j; int j;
for (j = 0; j < n_notes; j++) for (j = 0; j < n_notes; j++)
if (REGNO (operands[i]) == REGNO (note_reg[j]) if (REGNO (recog_operand[i]) == REGNO (note_reg[j])
&& note_kind[j] == REG_UNUSED) && note_kind[j] == REG_UNUSED)
{ {
insn = emit_pop_insn (insn, regstack, operands[i], insn = emit_pop_insn (insn, regstack, recog_operand[i],
emit_insn_after); emit_insn_after);
break; break;
} }
} }
for (i = first_input; i < first_input + n_inputs; i++) for (i = n_outputs; i < n_outputs + n_inputs; i++)
if (STACK_REG_P (operands[i])) if (STACK_REG_P (recog_operand[i]))
{ {
int j; int j;
for (j = 0; j < n_notes; j++) for (j = 0; j < n_notes; j++)
if (REGNO (operands[i]) == REGNO (note_reg[j]) if (REGNO (recog_operand[i]) == REGNO (note_reg[j])
&& note_kind[j] == REG_DEAD && note_kind[j] == REG_DEAD
&& TEST_HARD_REG_BIT (regstack->reg_set, REGNO (operands[i]))) && TEST_HARD_REG_BIT (regstack->reg_set,
REGNO (recog_operand[i])))
{ {
insn = emit_pop_insn (insn, regstack, operands[i], insn = emit_pop_insn (insn, regstack, recog_operand[i],
emit_insn_after); emit_insn_after);
break; break;
} }
...@@ -2723,7 +2415,6 @@ subst_stack_regs (insn, regstack) ...@@ -2723,7 +2415,6 @@ subst_stack_regs (insn, regstack)
{ {
register rtx *note_link, note; register rtx *note_link, note;
register int i; register int i;
int n_operands;
if (GET_CODE (insn) == CALL_INSN) if (GET_CODE (insn) == CALL_INSN)
{ {
...@@ -2755,25 +2446,14 @@ subst_stack_regs (insn, regstack) ...@@ -2755,25 +2446,14 @@ subst_stack_regs (insn, regstack)
if (GET_MODE (insn) == QImode) if (GET_MODE (insn) == QImode)
{ {
n_operands = asm_noperands (PATTERN (insn)); int n_operands = asm_noperands (PATTERN (insn));
if (n_operands >= 0) if (n_operands >= 0)
{ {
/* This insn is an `asm' with operands. Decode the operands, /* This insn is an `asm' with operands. Decode the operands,
decide how many are inputs, and do register substitution. decide how many are inputs, and do register substitution.
Any REG_UNUSED notes will be handled by subst_asm_stack_regs. */ Any REG_UNUSED notes will be handled by subst_asm_stack_regs. */
rtx operands[MAX_RECOG_OPERANDS]; subst_asm_stack_regs (insn, regstack);
rtx *operands_loc[MAX_RECOG_OPERANDS];
rtx body = PATTERN (insn);
int n_inputs, n_outputs;
char **constraints
= (char **) alloca (n_operands * sizeof (char *));
decode_asm_operands (body, operands, operands_loc,
constraints, NULL_PTR);
get_asm_operand_lengths (body, n_operands, &n_inputs, &n_outputs);
subst_asm_stack_regs (insn, regstack, operands, operands_loc,
constraints, n_inputs, n_outputs);
return; return;
} }
......
...@@ -1219,6 +1219,12 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line) ...@@ -1219,6 +1219,12 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
int nalternatives = n_occurrences (',', TREE_STRING_POINTER (tmp)); int nalternatives = n_occurrences (',', TREE_STRING_POINTER (tmp));
tree next = inputs; tree next = inputs;
if (nalternatives + 1 > MAX_RECOG_ALTERNATIVES)
{
error ("too many alternatives in `asm'");
return;
}
tmp = outputs; tmp = outputs;
while (tmp) while (tmp)
{ {
......
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