📄 reg-stack.c
字号:
return 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 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, that is a compiler bug: we should have caught such an insn during reload. */ i = constrain_asm_operands (n_operands, operands, constraints, operand_matches, operand_class); if (i < 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) 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)) { clobber_reg[n_clobbers] = reg; n_clobbers++; } } } /* Enforce rule #4: Output operands must specifically indicate which reg an output appears in after an asm. "=f" is not allowed: the operand constraints must select a class with a single reg. Also enforce rule #5: Output operands must start at the top of the reg-stack: output operands may not "skip" a reg. */ bzero (reg_used_as_output, sizeof (reg_used_as_output)); for (i = 0; i < n_outputs; i++) if (STACK_REG_P (operands[i])) if (reg_class_size[operand_class[i]] != 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; /* Search for first non-popped reg. */ for (i = FIRST_STACK_REG; i < LAST_STACK_REG + 1; i++) if (! reg_used_as_output[i]) break; /* If there are any other popped regs, that's an error. */ for (; i < LAST_STACK_REG + 1; i++) if (reg_used_as_output[i]) break; if (i != LAST_STACK_REG + 1) { error_for_asm (insn, "Output regs must be grouped at top of stack"); malformed_asm = 1; } /* Enforce rule #2: All implicitly popped input regs must be closer to the top of the reg-stack than any input that is not implicitly popped. */ bzero (implicitly_dies, sizeof (implicitly_dies)); for (i = first_input; i < first_input + n_inputs; i++) if (STACK_REG_P (operands[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])) break; if (j < n_clobbers || operand_matches[i] >= 0) implicitly_dies[REGNO (operands[i])] = 1; } /* Search for first non-popped reg. */ for (i = FIRST_STACK_REG; i < LAST_STACK_REG + 1; i++) if (! implicitly_dies[i]) break; /* If there are any other popped regs, that's an error. */ for (; i < LAST_STACK_REG + 1; i++) if (implicitly_dies[i]) break; if (i != LAST_STACK_REG + 1) { error_for_asm (insn, "Implicitly popped regs must be grouped at top of stack"); malformed_asm = 1; } /* Enfore rule #3: If any input operand uses the "f" constraint, all output constraints must use the "&" earlyclobber. ??? 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) { int j;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -