diff options
Diffstat (limited to 'contrib/gcc/reg-stack.c')
-rw-r--r-- | contrib/gcc/reg-stack.c | 787 |
1 files changed, 279 insertions, 508 deletions
diff --git a/contrib/gcc/reg-stack.c b/contrib/gcc/reg-stack.c index d92a1f9..dd4a87e 100644 --- a/contrib/gcc/reg-stack.c +++ b/contrib/gcc/reg-stack.c @@ -1,5 +1,5 @@ /* Register to Stack convert for GNU compiler. - Copyright (C) 1992, 93, 94, 95, 96, 97, 1998 Free Software Foundation, Inc. + Copyright (C) 1992, 93-98, 1999 Free Software Foundation, Inc. This file is part of GNU CC. @@ -74,13 +74,6 @@ Boston, MA 02111-1307, USA. */ deleted and recreated from scratch. REG_DEAD is never created for a SET_DEST, only REG_UNUSED. - Before life analysis, the mode of each insn is set based on whether - or not any stack registers are mentioned within that insn. VOIDmode - means that no regs are mentioned anyway, and QImode means that at - least one pattern within the insn mentions stack registers. This - information is valid until after reg_to_stack returns, and is used - from jump_optimize. - * asm_operands: There are several rules on the usage of stack-like regs in @@ -166,7 +159,9 @@ Boston, MA 02111-1307, USA. */ #include "hard-reg-set.h" #include "flags.h" #include "insn-flags.h" +#include "recog.h" #include "toplev.h" +#include "varray.h" #ifdef STACK_REGS @@ -218,6 +213,14 @@ static HARD_REG_SET *block_out_reg_set; add insns within a block. */ static int *block_number; +/* We use this array to cache info about insns, because otherwise we + spend too much time in stack_regs_mentioned_p. + + Indexed by insn UIDs. A value of zero is uninitialized, one indicates + the insn uses stack registers, two indicates the insn does not use + stack registers. */ +static varray_type stack_regs_mentioned_data; + /* This is the register file for all register after conversion */ static rtx FP_mode_reg[LAST_STACK_REG+1-FIRST_STACK_REG][(int) MAX_MACHINE_MODE]; @@ -228,9 +231,23 @@ static rtx /* Get the basic block number of an insn. See note at block_number definition are validity of this information. */ -#define BLOCK_NUM(INSN) \ - ((INSN_UID (INSN) > max_uid) \ - ? (abort() , -1) : block_number[INSN_UID (INSN)]) +static int BLOCK_NUM PROTO((rtx)); + +#ifdef __GNUC__ +__inline__ +#endif +static int +BLOCK_NUM(insn) + rtx insn; +{ + int tmp = INSN_UID (insn); + if (tmp > max_uid) + abort (); + tmp = block_number[tmp]; + if (tmp < 0) + abort (); + return tmp; +} extern rtx forced_labels; @@ -241,14 +258,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 +277,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 (*) ())); @@ -272,6 +285,47 @@ static void goto_block_pat PROTO((rtx, stack, rtx)); static void convert_regs PROTO((void)); static void print_blocks PROTO((FILE *, rtx, rtx)); static void dump_stack_info PROTO((FILE *)); +static int check_stack_regs_mentioned PROTO((rtx insn)); + +/* Initialize stack_regs_mentioned_data for INSN (growing the virtual array + if needed. Return nonzero if INSN mentions stacked registers. */ + +static int +check_stack_regs_mentioned (insn) + rtx insn; +{ + unsigned int uid = INSN_UID (insn); + if (uid >= VARRAY_SIZE (stack_regs_mentioned_data)) + /* Allocate some extra size to avoid too many reallocs, but + do not grow exponentially. */ + VARRAY_GROW (stack_regs_mentioned_data, uid + uid / 20); + if (stack_regs_mentioned_p (PATTERN (insn))) + { + VARRAY_CHAR (stack_regs_mentioned_data, uid) = 1; + return 1; + } + else + VARRAY_CHAR (stack_regs_mentioned_data, uid) = 2; + return 0; +} + +/* Return nonzero if INSN mentions stacked registers, else return + zero. */ + +int +stack_regs_mentioned (insn) + rtx insn; +{ + unsigned int uid; + if (GET_RTX_CLASS (GET_CODE (insn)) != 'i') + return 0; + uid = INSN_UID (insn); + if (uid >= VARRAY_SIZE (stack_regs_mentioned_data) + || ! VARRAY_CHAR (stack_regs_mentioned_data, uid)) + return (check_stack_regs_mentioned (insn)); + return VARRAY_CHAR (stack_regs_mentioned_data, uid) == 1; +} + /* Mark all registers needed for this pattern. */ @@ -401,6 +455,10 @@ reg_to_stack (first, file) enum machine_mode mode; HARD_REG_SET stackentry; + max_uid = get_max_uid (); + VARRAY_CHAR_INIT (stack_regs_mentioned_data, max_uid + 1, + "stack_regs_mentioned cache"); + CLEAR_HARD_REG_SET (stackentry); { @@ -461,7 +519,7 @@ reg_to_stack (first, file) && stack_regs_mentioned_p (PATTERN (insn))) { stack_reg_seen = 1; - PUT_MODE (insn, QImode); + VARRAY_CHAR (stack_regs_mentioned_data, INSN_UID (insn)) = 1; /* Note any register passing parameters. */ @@ -471,7 +529,7 @@ reg_to_stack (first, file) &stackentry, 1); } else - PUT_MODE (insn, VOIDmode); + VARRAY_CHAR (stack_regs_mentioned_data, INSN_UID (insn)) = 2; if (code == CODE_LABEL) LABEL_REFS (insn) = insn; /* delete old chain */ @@ -485,7 +543,10 @@ reg_to_stack (first, file) anything to convert. */ if (! stack_reg_seen) - return; + { + VARRAY_FREE (stack_regs_mentioned_data); + return; + } /* If there are stack registers, there must be at least one block. */ @@ -505,6 +566,7 @@ reg_to_stack (first, file) bzero ((char *) block_out_reg_set, blocks * sizeof (HARD_REG_SET)); block_number = (int *) alloca ((max_uid + 1) * sizeof (int)); + memset (block_number, -1, (max_uid + 1) * sizeof (int)); find_blocks (first); stack_reg_life_analysis (first, &stackentry); @@ -520,6 +582,8 @@ reg_to_stack (first, file) if (optimize) jump_optimize (first, 2, 0, 0); + + VARRAY_FREE (stack_regs_mentioned_data); } /* Check PAT, which is in INSN, for LABEL_REFs. Add INSN to the @@ -607,297 +671,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 +681,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); + VARRAY_CHAR (stack_regs_mentioned_data, INSN_UID (insn)) = 2; + 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. */ @@ -950,7 +729,7 @@ record_asm_reg_life (insn, regstack, operands, constraints, if (GET_CODE (body) == PARALLEL) { - clobber_reg = (rtx *) alloca (XVECLEN (body, 0) * sizeof (rtx *)); + clobber_reg = (rtx *) alloca (XVECLEN (body, 0) * sizeof (rtx)); for (i = 0; i < XVECLEN (body, 0); i++) if (GET_CODE (XVECEXP (body, 0, i)) == CLOBBER) @@ -978,15 +757,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 +790,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 +828,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); @@ -1067,14 +846,14 @@ record_asm_reg_life (insn, regstack, operands, constraints, { /* Avoid further trouble with this insn. */ PATTERN (insn) = gen_rtx_USE (VOIDmode, const0_rtx); - PUT_MODE (insn, VOIDmode); + VARRAY_CHAR (stack_regs_mentioned_data, INSN_UID (insn)) = 2; return; } /* 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 +875,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 +890,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 +957,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 +1019,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; } @@ -1310,7 +1074,6 @@ record_reg_life (insn, block, regstack) pat = gen_rtx_SET (VOIDmode, FP_MODE_REG (reg, DFmode), CONST0_RTX (DFmode)); init = emit_insn_after (pat, insn); - PUT_MODE (init, QImode); CLEAR_HARD_REG_BIT (regstack->reg_set, reg); @@ -1487,14 +1250,14 @@ stack_reg_life_analysis (first, stackentry) for (block = blocks - 1; --block >= 0;) if (GET_CODE (block_end[block]) == JUMP_INSN - && GET_CODE (PATTERN (block_end[block])) == RETURN) + && returnjump_p (block_end[block])) mark_regs_pat (retvalue, block_out_reg_set+block); /* Mark off the end of last block if we "fall off" the end of the function into the epilogue. */ if (GET_CODE (block_end[blocks-1]) != JUMP_INSN - || GET_CODE (PATTERN (block_end[blocks-1])) == RETURN) + || returnjump_p (block_end[blocks-1])) mark_regs_pat (retvalue, block_out_reg_set+blocks-1); } } @@ -1520,7 +1283,7 @@ stack_reg_life_analysis (first, stackentry) everything dies. But otherwise don't process unless there are some stack regs present. */ - if (GET_MODE (insn) == QImode || GET_CODE (insn) == CALL_INSN) + if (stack_regs_mentioned (insn) || GET_CODE (insn) == CALL_INSN) record_reg_life (insn, block, ®stack); } while (insn != block_begin[block]); @@ -1606,7 +1369,6 @@ stack_reg_life_analysis (first, stackentry) init_rtx = gen_rtx_SET (VOIDmode, FP_MODE_REG(reg, DFmode), CONST0_RTX (DFmode)); block_begin[0] = emit_insn_after (init_rtx, first); - PUT_MODE (block_begin[0], QImode); CLEAR_HARD_REG_BIT (block_stack_in[0].reg_set, reg); } @@ -1693,6 +1455,14 @@ static void delete_insn_for_stacker (insn) rtx insn; { + int i; + + /* Ensure that the side effects were clobbers when deleting a PARALLEL. */ + if (GET_CODE (PATTERN (insn)) == PARALLEL) + for (i = 1; i < XVECLEN (PATTERN (insn), 0); i++) + if (GET_CODE (XVECEXP (PATTERN (insn), 0, i)) != CLOBBER) + abort (); + PUT_CODE (insn, NOTE); NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED; NOTE_SOURCE_FILE (insn) = 0; @@ -1700,9 +1470,12 @@ delete_insn_for_stacker (insn) /* Emit an insn to pop virtual register REG before or after INSN. REGSTACK is the stack state after INSN and is updated to reflect this - pop. WHEN is either emit_insn_before or emit_insn_after. A pop insn - is represented as a SET whose destination is the register to be popped - and source is the top of stack. A death note for the top of stack + pop. WHEN is either emit_insn_before, emit_insn_after or NULL. + in case WHEN is NULL we don't really emit the insn, just modify stack + information. Caller is expected to emit insn himself. + + A pop insn is represented as a SET whose destination is the register to + be popped and source is the top of stack. A death note for the top of stack cases the movdf pattern to pop. */ static rtx @@ -1720,16 +1493,18 @@ emit_pop_insn (insn, regstack, reg, when) if (hard_regno < FIRST_STACK_REG) abort (); - pop_rtx = gen_rtx_SET (VOIDmode, FP_MODE_REG (hard_regno, DFmode), - FP_MODE_REG (FIRST_STACK_REG, DFmode)); + if (when) + { + pop_rtx = gen_rtx_SET (VOIDmode, FP_MODE_REG (hard_regno, DFmode), + FP_MODE_REG (FIRST_STACK_REG, DFmode)); - pop_insn = (*when) (pop_rtx, insn); - /* ??? This used to be VOIDmode, but that seems wrong. */ - PUT_MODE (pop_insn, QImode); + pop_insn = (*when) (pop_rtx, insn); - REG_NOTES (pop_insn) = gen_rtx_EXPR_LIST (REG_DEAD, - FP_MODE_REG (FIRST_STACK_REG, DFmode), - REG_NOTES (pop_insn)); + REG_NOTES (pop_insn) = gen_rtx_EXPR_LIST (REG_DEAD, + FP_MODE_REG (FIRST_STACK_REG, + DFmode), + REG_NOTES (pop_insn)); + } regstack->reg[regstack->top - (hard_regno - FIRST_STACK_REG)] = regstack->reg[regstack->top]; @@ -1776,7 +1551,7 @@ emit_swap_insn (insn, regstack, reg) /* Find the previous insn involving stack regs, but don't go past any labels, calls or jumps. */ i1 = prev_nonnote_insn (insn); - while (i1 && GET_CODE (i1) == INSN && GET_MODE (i1) != QImode) + while (i1 && GET_CODE (i1) == INSN && !stack_regs_mentioned (i1)) i1 = prev_nonnote_insn (i1); if (i1) @@ -1814,8 +1589,6 @@ emit_swap_insn (insn, regstack, reg) swap_rtx = gen_swapdf (FP_MODE_REG (hard_regno, DFmode), FP_MODE_REG (FIRST_STACK_REG, DFmode)); swap_insn = emit_insn_after (swap_rtx, i1); - /* ??? This used to be VOIDmode, but that seems wrong. */ - PUT_MODE (swap_insn, QImode); } /* Handle a move to or from a stack register in PAT, which is in INSN. @@ -1932,7 +1705,6 @@ move_for_stack_reg (insn, regstack, pat) push_rtx = gen_movxf (top_stack_reg, top_stack_reg); push_insn = emit_insn_before (push_rtx, insn); - PUT_MODE (push_insn, QImode); REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_DEAD, top_stack_reg, REG_NOTES (insn)); } @@ -1992,10 +1764,18 @@ swap_rtx_condition (pat) /* Handle a comparison. Special care needs to be taken to avoid causing comparisons that a 387 cannot do correctly, such as EQ. - Also, a pop insn may need to be emitted. The 387 does have an + Also, a fstp instruction may need to be emitted. The 387 does have an `fcompp' insn that can pop two regs, but it is sometimes too expensive to do this - a `fcomp' followed by a `fstpl %st(0)' may be easier to - set up. */ + set up. + + We can not handle this by emiting fpop instruction after compare, because + it appears between cc0 setter and user. So we emit only + REG_DEAD note and handle it as a special case in machine description. + + This code used trick with delay_slot filling to emit pop insn after + comparsion but it didn't worked because it caused confusion with cc_status + in final pass. */ static void compare_for_stack_reg (insn, regstack, pat) @@ -2007,6 +1787,7 @@ compare_for_stack_reg (insn, regstack, pat) rtx src1_note, src2_note; rtx cc0_user; int have_cmove; + int hard_regno; src1 = get_true_reg (&XEXP (SET_SRC (pat), 0)); src2 = get_true_reg (&XEXP (SET_SRC (pat), 1)); @@ -2073,7 +1854,10 @@ compare_for_stack_reg (insn, regstack, pat) replace_reg (src1, FIRST_STACK_REG); if (STACK_REG_P (*src2)) - replace_reg (src2, get_hard_regnum (regstack, *src2)); + { + hard_regno = get_hard_regnum (regstack, *src2); + replace_reg (src2, hard_regno); + } if (src1_note) { @@ -2102,16 +1886,11 @@ compare_for_stack_reg (insn, regstack, pat) } else { - /* The 386 can only represent death of the first operand in - the case handled above. In all other cases, emit a separate - pop and remove the death note from here. */ - - link_cc0_insns (insn); + /* Pop of second operand is handled using special REG_DEAD note + because we can't emit pop insn after cc0 setter. */ - remove_regno_note (insn, REG_DEAD, REGNO (XEXP (src2_note, 0))); - - emit_pop_insn (insn, regstack, XEXP (src2_note, 0), - emit_insn_after); + emit_pop_insn (insn, regstack, XEXP (src2_note, 0), NULL); + replace_reg (&XEXP (src2_note, 0), hard_regno); } } } @@ -2419,12 +2198,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 @@ -2433,21 +2207,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 */ @@ -2461,24 +2226,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; + + preprocess_constraints (); - i = constrain_asm_operands (n_operands, operands, 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 (); /* 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. */ @@ -2519,8 +2291,8 @@ subst_asm_stack_regs (insn, regstack, operands, operands_loc, constraints, if (GET_CODE (body) == PARALLEL) { - clobber_reg = (rtx *) alloca (XVECLEN (body, 0) * sizeof (rtx *)); - clobber_loc = (rtx **) alloca (XVECLEN (body, 0) * sizeof (rtx **)); + clobber_reg = (rtx *) alloca (XVECLEN (body, 0) * sizeof (rtx)); + clobber_loc = (rtx **) alloca (XVECLEN (body, 0) * sizeof (rtx *)); for (i = 0; i < XVECLEN (body, 0); i++) if (GET_CODE (XVECEXP (body, 0, i)) == CLOBBER) @@ -2548,34 +2320,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]; @@ -2591,15 +2364,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++) @@ -2631,21 +2404,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. */ @@ -2666,7 +2439,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); @@ -2682,31 +2455,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; } @@ -2725,7 +2499,6 @@ subst_stack_regs (insn, regstack) { register rtx *note_link, note; register int i; - int n_operands; if (GET_CODE (insn) == CALL_INSN) { @@ -2755,27 +2528,16 @@ subst_stack_regs (insn, regstack) we must check each pattern in a parallel here. A call_value_pop could fail otherwise. */ - if (GET_MODE (insn) == QImode) + if (stack_regs_mentioned (insn)) { - 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; } @@ -2783,8 +2545,14 @@ subst_stack_regs (insn, regstack) for (i = 0; i < XVECLEN (PATTERN (insn), 0); i++) { if (stack_regs_mentioned_p (XVECEXP (PATTERN (insn), 0, i))) - subst_stack_regs_pat (insn, regstack, - XVECEXP (PATTERN (insn), 0, i)); + { + subst_stack_regs_pat (insn, regstack, + XVECEXP (PATTERN (insn), 0, i)); + + /* subst_stack_regs_pat may have deleted a no-op insn. */ + if (GET_CODE (insn) == NOTE) + break; + } } else subst_stack_regs_pat (insn, regstack, PATTERN (insn)); @@ -2872,43 +2640,46 @@ change_stack (insn, old, new, when) if (old->top != new->top) abort (); - /* Loop here emitting swaps until the stack is correct. The - worst case number of swaps emitted is N + 2, where N is the + /* If the stack is not empty (new->top != -1), loop here emitting + swaps until the stack is correct. + + The worst case number of swaps emitted is N + 2, where N is the depth of the stack. In some cases, the reg at the top of stack may be correct, but swapped anyway in order to fix other regs. But since we never swap any other reg away from its correct slot, this algorithm will converge. */ - do - { - /* Swap the reg at top of stack into the position it is - supposed to be in, until the correct top of stack appears. */ + if (new->top != -1) + do + { + /* Swap the reg at top of stack into the position it is + supposed to be in, until the correct top of stack appears. */ - while (old->reg[old->top] != new->reg[new->top]) - { - for (reg = new->top; reg >= 0; reg--) - if (new->reg[reg] == old->reg[old->top]) - break; + while (old->reg[old->top] != new->reg[new->top]) + { + for (reg = new->top; reg >= 0; reg--) + if (new->reg[reg] == old->reg[old->top]) + break; - if (reg == -1) - abort (); + if (reg == -1) + abort (); - emit_swap_insn (insn, old, - FP_MODE_REG (old->reg[reg], DFmode)); - } + emit_swap_insn (insn, old, + FP_MODE_REG (old->reg[reg], DFmode)); + } - /* See if any regs remain incorrect. If so, bring an + /* See if any regs remain incorrect. If so, bring an incorrect reg to the top of stack, and let the while loop above fix it. */ - for (reg = new->top; reg >= 0; reg--) - if (new->reg[reg] != old->reg[reg]) - { - emit_swap_insn (insn, old, - FP_MODE_REG (old->reg[reg], DFmode)); - break; - } - } while (reg >= 0); + for (reg = new->top; reg >= 0; reg--) + if (new->reg[reg] != old->reg[reg]) + { + emit_swap_insn (insn, old, + FP_MODE_REG (old->reg[reg], DFmode)); + break; + } + } while (reg >= 0); /* At this point there must be no differences. */ @@ -3082,7 +2853,7 @@ convert_regs () mentioned or if it's a CALL_INSN (register passing of floating point values). */ - if (GET_MODE (insn) == QImode || GET_CODE (insn) == CALL_INSN) + if (stack_regs_mentioned (insn) || GET_CODE (insn) == CALL_INSN) subst_stack_regs (insn, ®stack); } while (insn != block_end[block]); |