aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorBernd Schmidt <crux@pool.informatik.rwth-aachen.de>1998-12-04 12:55:59 +0000
committerBernd Schmidt <crux@gcc.gnu.org>1998-12-04 12:55:59 +0000
commitf62a15e367dd53a270f7766c5c62a82629478d3e (patch)
tree7eac8b63b458dd5da67b48a5a4d8ca0d0304223f /gcc
parent71eb0b9ec35acd4843115354a94be4dcb150f7af (diff)
downloadgcc-f62a15e367dd53a270f7766c5c62a82629478d3e.zip
gcc-f62a15e367dd53a270f7766c5c62a82629478d3e.tar.gz
gcc-f62a15e367dd53a270f7766c5c62a82629478d3e.tar.bz2
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
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog34
-rw-r--r--gcc/Makefile.in2
-rw-r--r--gcc/final.c17
-rw-r--r--gcc/recog.c111
-rw-r--r--gcc/recog.h46
-rw-r--r--gcc/reg-stack.c538
-rw-r--r--gcc/stmt.c6
7 files changed, 308 insertions, 446 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index c2744d3..fac1096 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,37 @@
+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)
* except.c (set_exception_version_code): Argument is an "int".
diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index f154b3e..97bec24 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -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) \
$(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
-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
dyn-string.o: dyn-string.c dyn-string.h $(CONFIG_H) system.h
diff --git a/gcc/final.c b/gcc/final.c
index 5bcfd6b..32ed6fb 100644
--- a/gcc/final.c
+++ b/gcc/final.c
@@ -3031,23 +3031,8 @@ void
cleanup_subreg_operands (insn)
rtx insn;
{
- int insn_code_number, 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. */
+ int i;
- insn_code_number = recog_memoized (insn);
extract_insn (insn);
for (i = 0; i < recog_n_operands; i++)
{
diff --git a/gcc/recog.c b/gcc/recog.c
index 6ae7a31..19bc3b2 100644
--- a/gcc/recog.c
+++ b/gcc/recog.c
@@ -96,6 +96,10 @@ enum op_type recog_op_type[MAX_RECOG_OPERANDS];
char recog_operand_address_p[MAX_RECOG_OPERANDS];
#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
was satisfied. */
@@ -1803,8 +1807,115 @@ extract_insn (insn)
recog_op_type[i] = (recog_constraints[i][0] == '=' ? OP_OUT
: recog_constraints[i][0] == '+' ? OP_INOUT
: 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
/* Check the operands of an insn against the insn's operand constraints
diff --git a/gcc/recog.h b/gcc/recog.h
index bbed6c1..d30b992 100644
--- a/gcc/recog.h
+++ b/gcc/recog.h
@@ -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,
Boston, MA 02111-1307, USA. */
+/* Random number that should be large enough for all purposes. */
+#define MAX_RECOG_ALTERNATIVES 30
+
/* Types of operands. */
enum op_type {
OP_IN,
@@ -25,6 +28,44 @@ enum op_type {
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_no_volatile PROTO((void));
extern int recog_memoized PROTO((rtx));
@@ -67,6 +108,7 @@ extern int recog PROTO((rtx, rtx, int *));
extern void add_clobbers PROTO((rtx, int));
extern void insn_extract PROTO((rtx));
extern void extract_insn PROTO((rtx));
+extern void preprocess_constraints PROTO((void));
/* Nonzero means volatile operands are recognized. */
extern int volatile_ok;
@@ -116,6 +158,10 @@ extern enum op_type recog_op_type[];
extern char recog_operand_address_p[];
#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. */
#define OUT_FCN(CODE) (*insn_outfun[(int) (CODE)])
diff --git a/gcc/reg-stack.c b/gcc/reg-stack.c
index b8fc938..e391706 100644
--- a/gcc/reg-stack.c
+++ b/gcc/reg-stack.c
@@ -166,6 +166,7 @@ Boston, MA 02111-1307, USA. */
#include "hard-reg-set.h"
#include "flags.h"
#include "insn-flags.h"
+#include "recog.h"
#include "toplev.h"
#ifdef STACK_REGS
@@ -241,14 +242,11 @@ static void straighten_stack PROTO((rtx, stack));
static void pop_stack PROTO((stack, int));
static void record_label_references PROTO((rtx, 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 **,
- int, int));
+static void record_asm_reg_life PROTO((rtx, stack));
static void record_reg_life_pat PROTO((rtx, HARD_REG_SET *,
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 find_blocks PROTO((rtx));
static rtx stack_result PROTO((tree));
@@ -263,8 +261,7 @@ static void move_for_stack_reg PROTO((rtx, stack, rtx));
static void swap_rtx_condition PROTO((rtx));
static void compare_for_stack_reg 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 **,
- char **, int, int));
+static void subst_asm_stack_regs PROTO((rtx, stack));
static void subst_stack_regs PROTO((rtx, stack));
static void change_stack PROTO((rtx, stack, stack, rtx (*) ()));
@@ -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.
- N_INPUTS is the number of inputs; N_OUTPUTS the outputs. CONSTRAINTS
- is an array of the constraint strings used in the asm statement.
+ N_INPUTS is the number of inputs; N_OUTPUTS the outputs.
OPERANDS is an array of all operands for the insn, and is assumed to
contain all output operands, then all inputs operands.
@@ -906,43 +614,47 @@ constrain_asm_operands (n_operands, operands, operand_constraints,
numbers below refer to that explanation. */
static void
-record_asm_reg_life (insn, regstack, operands, constraints,
- n_inputs, n_outputs)
+record_asm_reg_life (insn, regstack)
rtx insn;
stack regstack;
- rtx *operands;
- char **constraints;
- int n_inputs, n_outputs;
{
int i;
- int n_operands = n_inputs + n_outputs;
- int first_input = n_outputs;
int n_clobbers;
int malformed_asm = 0;
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 implicitly_dies[FIRST_PSEUDO_REGISTER];
+ int alt;
rtx *clobber_reg;
+ int n_inputs, n_outputs;
/* Find out what the constraints require. If no constraint
alternative matches, this asm is malformed. */
- i = constrain_asm_operands (n_operands, operands, constraints,
- operand_matches, operand_class);
- if (i < 0)
- malformed_asm = 1;
+ extract_insn (insn);
+ constrain_operands (1);
+ alt = which_alternative;
+
+ 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. */
- for (i = 0; i < n_operands; i++)
- if (GET_CODE (operands[i]) == SUBREG
- && GET_CODE (SUBREG_REG (operands[i])) == REG)
- operands[i] = SUBREG_REG (operands[i]);
+ for (i = 0; i < recog_n_operands; i++)
+ if (GET_CODE (recog_operand[i]) == SUBREG
+ && GET_CODE (SUBREG_REG (recog_operand[i])) == REG)
+ recog_operand[i] = SUBREG_REG (recog_operand[i]);
/* Set up CLOBBER_REG. */
@@ -978,15 +690,15 @@ record_asm_reg_life (insn, regstack, operands, constraints,
bzero ((char *) reg_used_as_output, sizeof (reg_used_as_output));
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);
malformed_asm = 1;
}
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,
popped. */
bzero ((char *) implicitly_dies, sizeof (implicitly_dies));
- for (i = first_input; i < first_input + n_inputs; i++)
- if (STACK_REG_P (operands[i]))
+ for (i = n_outputs; i < n_outputs + n_inputs; i++)
+ if (STACK_REG_P (recog_operand[i]))
{
/* An input reg is implicitly popped if it is tied to an
output, or if there is a CLOBBER for it. */
int 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;
- if (j < n_clobbers || operand_matches[i] >= 0)
- implicitly_dies[REGNO (operands[i])] = 1;
+ if (j < n_clobbers || recog_op_alt[i][alt].matches >= 0)
+ implicitly_dies[REGNO (recog_operand[i])] = 1;
}
/* Search for first non-popped reg. */
@@ -1049,13 +761,13 @@ record_asm_reg_life (insn, regstack, operands, constraints,
??? Detect this more deterministically by having constraint_asm_operands
record any earlyclobber. */
- for (i = first_input; i < first_input + n_inputs; i++)
- if (operand_matches[i] == -1)
+ for (i = n_outputs; i < n_outputs + n_inputs; i++)
+ if (recog_op_alt[i][alt].matches == -1)
{
int 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,
"Output operand %d must use `&' constraint", j);
@@ -1074,7 +786,7 @@ record_asm_reg_life (insn, regstack, operands, constraints,
/* Process all outputs */
for (i = 0; i < n_outputs; i++)
{
- rtx op = operands[i];
+ rtx op = recog_operand[i];
if (! STACK_REG_P (op))
{
@@ -1096,11 +808,12 @@ record_asm_reg_life (insn, regstack, operands, constraints,
}
/* 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 ();
else
continue;
@@ -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,
or if the input is also an output. */
- if (! TEST_HARD_REG_BIT (regstack->reg_set, REGNO (operands[i]))
- && operand_matches[i] == -1
- && find_regno_note (insn, REG_DEAD, REGNO (operands[i])) == NULL_RTX)
- REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_DEAD, operands[i],
- REG_NOTES (insn));
+ if (! TEST_HARD_REG_BIT (regstack->reg_set, REGNO (op))
+ && recog_op_alt[i][alt].matches == -1
+ && find_regno_note (insn, REG_DEAD, REGNO (op)) == NULL_RTX)
+ REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_DEAD, op, 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)
N_INPUTS and N_OUTPUTS are pointers to ints into which the results are
placed. */
-static void
-get_asm_operand_lengths (body, n_operands, n_inputs, n_outputs)
+static int
+get_asm_operand_n_inputs (body)
rtx body;
- int n_operands;
- int *n_inputs, *n_outputs;
{
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)
- *n_inputs = ASM_OPERANDS_INPUT_LENGTH (body);
+ return ASM_OPERANDS_INPUT_LENGTH (body);
else if (GET_CODE (body) == PARALLEL
&& 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
&& GET_CODE (XVECEXP (body, 0, 0)) == ASM_OPERANDS)
- *n_inputs = ASM_OPERANDS_INPUT_LENGTH (XVECEXP (body, 0, 0));
- else
- abort ();
+ return ASM_OPERANDS_INPUT_LENGTH (XVECEXP (body, 0, 0));
- *n_outputs = n_operands - *n_inputs;
+ abort ();
}
/* Scan INSN, which is in BLOCK, and record the life & death of stack
@@ -1244,18 +952,7 @@ record_reg_life (insn, block, regstack)
n_operands = asm_noperands (PATTERN (insn));
if (n_operands >= 0)
{
- /* This insn is an `asm' with operands. Decode the operands,
- 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);
+ record_asm_reg_life (insn, regstack);
return;
}
@@ -2417,12 +2114,7 @@ subst_stack_regs_pat (insn, regstack, pat)
/* Substitute hard regnums for any stack regs in INSN, which has
N_INPUTS inputs and N_OUTPUTS outputs. REGSTACK is the stack info
- before the insn, and is updated with changes made here. CONSTRAINTS is
- 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.
+ before the insn, and is updated with changes made here.
There are several requirements and assumptions about the use of
stack-like regs in asm statements. These rules are enforced by
@@ -2431,21 +2123,12 @@ subst_stack_regs_pat (insn, regstack, pat)
requirements, since record_asm_stack_regs removes any problem asm. */
static void
-subst_asm_stack_regs (insn, regstack, operands, operands_loc, constraints,
- n_inputs, n_outputs)
+subst_asm_stack_regs (insn, regstack)
rtx insn;
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);
-
- 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 alt;
rtx *note_reg; /* Array of note contents */
rtx **note_loc; /* Address of REG field of each note */
@@ -2459,24 +2142,31 @@ subst_asm_stack_regs (insn, regstack, operands, operands_loc, constraints,
int n_clobbers;
rtx note;
int i;
+ int n_inputs, n_outputs;
/* Find out what the constraints required. If no constraint
alternative matches, that is a compiler bug: we should have caught
such an insn during the life analysis pass (and reload should have
caught it regardless). */
+ extract_insn (insn);
+ constrain_operands (1);
+ alt = which_alternative;
- i = constrain_asm_operands (n_operands, operands, constraints,
- operand_matches, operand_class);
- if (i < 0)
+ preprocess_constraints ();
+
+ n_inputs = get_asm_operand_n_inputs (body);
+ n_outputs = recog_n_operands - n_inputs;
+
+ if (alt < 0)
abort ();
/* Strip SUBREGs here to make the following code simpler. */
- for (i = 0; i < n_operands; i++)
- if (GET_CODE (operands[i]) == SUBREG
- && GET_CODE (SUBREG_REG (operands[i])) == REG)
+ for (i = 0; i < recog_n_operands; i++)
+ if (GET_CODE (recog_operand[i]) == SUBREG
+ && GET_CODE (SUBREG_REG (recog_operand[i])) == REG)
{
- operands_loc[i] = & SUBREG_REG (operands[i]);
- operands[i] = SUBREG_REG (operands[i]);
+ recog_operand_loc[i] = & SUBREG_REG (recog_operand[i]);
+ recog_operand[i] = SUBREG_REG (recog_operand[i]);
}
/* Set up NOTE_REG, NOTE_LOC and NOTE_KIND. */
@@ -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. */
- for (i = first_input; i < first_input + n_inputs; i++)
- if (STACK_REG_P (operands[i])
- && reg_class_subset_p (operand_class[i], FLOAT_REGS)
- && operand_class[i] != FLOAT_REGS)
+ for (i = n_outputs; i < n_outputs + n_inputs; i++)
+ if (STACK_REG_P (recog_operand[i])
+ && reg_class_subset_p (recog_op_alt[i][alt].class,
+ FLOAT_REGS)
+ && recog_op_alt[i][alt].class != FLOAT_REGS)
{
/* If an operand needs to be in a particular reg in
FLOAT_REGS, the constraint was either 't' or 'u'. Since
these constraints are for single register classes, and reload
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. */
- int regno = get_hard_regnum (&temp_stack, operands[i]);
+ int regno = get_hard_regnum (&temp_stack, recog_operand[i]);
if (regno < 0)
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.
- 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. */
int j, k, temp;
k = temp_stack.top - (regno - FIRST_STACK_REG);
j = (temp_stack.top
- - (REGNO (operands[i]) - FIRST_STACK_REG));
+ - (REGNO (recog_operand[i]) - FIRST_STACK_REG));
temp = temp_stack.reg[k];
temp_stack.reg[k] = temp_stack.reg[j];
@@ -2589,15 +2280,15 @@ subst_asm_stack_regs (insn, regstack, operands, operands_loc, constraints,
/* Make the needed input register substitutions. Do death notes and
clobbers too, because these are for inputs, not outputs. */
- for (i = first_input; i < first_input + n_inputs; i++)
- if (STACK_REG_P (operands[i]))
+ for (i = n_outputs; i < n_outputs + n_inputs; 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)
abort ();
- replace_reg (operands_loc[i], regnum);
+ replace_reg (recog_operand_loc[i], regnum);
}
for (i = 0; i < n_notes; i++)
@@ -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. */
- for (i = first_input; i < first_input + n_inputs; i++)
- if (STACK_REG_P (operands[i]))
+ for (i = n_outputs; i < n_outputs + n_inputs; i++)
+ if (STACK_REG_P (recog_operand[i]))
{
/* An input reg is implicitly popped if it is tied to an
output, or if there is a CLOBBER for it. */
int 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;
- 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,
- because all we need to do is pop the right number of regs
+ /* recog_operand[i] might not be at the top of stack. But that's
+ 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
guaranteed that all implicitly popped regs were grouped
at the top of the reg-stack. */
@@ -2664,7 +2355,7 @@ subst_asm_stack_regs (insn, regstack, operands, operands_loc, constraints,
int 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;
SET_HARD_REG_BIT (regstack->reg_set, i);
@@ -2680,31 +2371,32 @@ subst_asm_stack_regs (insn, regstack, operands, operands_loc, constraints,
in the death notes have already been substituted. */
for (i = 0; i < n_outputs; i++)
- if (STACK_REG_P (operands[i]))
+ if (STACK_REG_P (recog_operand[i]))
{
int 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)
{
- insn = emit_pop_insn (insn, regstack, operands[i],
+ insn = emit_pop_insn (insn, regstack, recog_operand[i],
emit_insn_after);
break;
}
}
- for (i = first_input; i < first_input + n_inputs; i++)
- if (STACK_REG_P (operands[i]))
+ for (i = n_outputs; i < n_outputs + n_inputs; i++)
+ if (STACK_REG_P (recog_operand[i]))
{
int 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
- && 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);
break;
}
@@ -2723,7 +2415,6 @@ subst_stack_regs (insn, regstack)
{
register rtx *note_link, note;
register int i;
- int n_operands;
if (GET_CODE (insn) == CALL_INSN)
{
@@ -2755,25 +2446,14 @@ subst_stack_regs (insn, regstack)
if (GET_MODE (insn) == QImode)
{
- n_operands = asm_noperands (PATTERN (insn));
+ int n_operands = asm_noperands (PATTERN (insn));
if (n_operands >= 0)
{
/* This insn is an `asm' with operands. Decode the operands,
decide how many are inputs, and do register substitution.
Any REG_UNUSED notes will be handled by subst_asm_stack_regs. */
- rtx operands[MAX_RECOG_OPERANDS];
- 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);
+ subst_asm_stack_regs (insn, regstack);
return;
}
diff --git a/gcc/stmt.c b/gcc/stmt.c
index affd4b5..7a8a657 100644
--- a/gcc/stmt.c
+++ b/gcc/stmt.c
@@ -1219,6 +1219,12 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
int nalternatives = n_occurrences (',', TREE_STRING_POINTER (tmp));
tree next = inputs;
+ if (nalternatives + 1 > MAX_RECOG_ALTERNATIVES)
+ {
+ error ("too many alternatives in `asm'");
+ return;
+ }
+
tmp = outputs;
while (tmp)
{