📄 reg-stack.c
字号:
find_blocks (first); stack_reg_life_analysis (first, &stackentry); /* Dump the life analysis debug information before jump optimization, as that will destroy the LABEL_REFS we keep the information in. */ if (file) dump_stack_info (file); convert_regs (); if (optimize) jump_optimize (first, 2, 0, 0);}/* Check PAT, which is in INSN, for LABEL_REFs. Add INSN to the label's chain of references, and note which insn contains each reference. */static voidrecord_label_references (insn, pat) rtx insn, pat;{ register enum rtx_code code = GET_CODE (pat); register int i; register char *fmt; if (code == LABEL_REF) { register rtx label = XEXP (pat, 0); register rtx ref; if (GET_CODE (label) != CODE_LABEL) abort (); /* Don't make a duplicate in the code_label's chain. */ for (ref = LABEL_REFS (label); ref && ref != label; ref = LABEL_NEXTREF (ref)) if (CONTAINING_INSN (ref) == insn) return; CONTAINING_INSN (pat) = insn; LABEL_NEXTREF (pat) = LABEL_REFS (label); LABEL_REFS (label) = pat; return; } fmt = GET_RTX_FORMAT (code); for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) { if (fmt[i] == 'e') record_label_references (insn, XEXP (pat, i)); if (fmt[i] == 'E') { register int j; for (j = 0; j < XVECLEN (pat, i); j++) record_label_references (insn, XVECEXP (pat, i, j)); } }}/* Return a pointer to the REG expression within PAT. If PAT is not a REG, possible enclosed by a conversion rtx, return the inner part of PAT that stopped the search. */static rtx *get_true_reg (pat) rtx *pat;{ for (;;) switch (GET_CODE (*pat)) { case SUBREG: /* eliminate FP subregister accesses in favour of the actual FP register in use. */ { rtx subreg; if (FP_REG_P (subreg = SUBREG_REG (*pat))) { *pat = FP_MODE_REG (REGNO (subreg) + SUBREG_WORD (*pat), GET_MODE (subreg)); default: return pat; } } case FLOAT: case FIX: case FLOAT_EXTEND: pat = & XEXP (*pat, 0); }}/* 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 intconstrain_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. */ 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. OPERANDS is an array of all operands for the insn, and is assumed to contain all output operands, then all inputs operands. There are many rules that an asm statement for stack-like regs must follow. Those rules are explained at the top of this file: the rule numbers below refer to that explanation. */static voidrecord_asm_reg_life (insn, regstack, operands, constraints, n_inputs, n_outputs) 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]; rtx *clobber_reg; /* 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; /* 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]); /* Set up CLOBBER_REG. */ n_clobbers = 0; if (GET_CODE (body) == PARALLEL) { 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) { rtx clobber = XVECEXP (body, 0, i); rtx reg = XEXP (clobber, 0); if (GET_CODE (reg) == SUBREG && GET_CODE (SUBREG_REG (reg)) == REG) reg = SUBREG_REG (reg); if (STACK_REG_P (reg)) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -