📄 recog.c
字号:
/* Use QImode because an odd displacement may be automatically invalid for any wider mode. But it should be valid for a single byte. */ return (*addressp) (QImode, z);}/* Return 1 if ADDR is an address-expression whose effect depends on the mode of the memory reference it is used in. Autoincrement addressing is a typical example of mode-dependence because the amount of the increment depends on the mode. */intmode_dependent_address_p (addr) rtx addr;{ GO_IF_MODE_DEPENDENT_ADDRESS (addr, win); return 0; win: return 1;}/* Return 1 if OP is a general operand other than a memory ref with a mode dependent address. */intmode_independent_operand (op, mode) enum machine_mode mode; rtx op;{ rtx addr; if (! general_operand (op, mode)) return 0; if (GET_CODE (op) != MEM) return 1; addr = XEXP (op, 0); GO_IF_MODE_DEPENDENT_ADDRESS (addr, lose); return 1; lose: return 0;}/* Given an operand OP that is a valid memory reference which satisfies offsettable_memref_p, return a new memory reference whose address has been adjusted by OFFSET. OFFSET should be positive and less than the size of the object referenced.*/rtxadj_offsettable_operand (op, offset) rtx op; int offset;{ register enum rtx_code code = GET_CODE (op); if (code == MEM) { register rtx y = XEXP (op, 0); register rtx new; if (CONSTANT_ADDRESS_P (y)) { new = gen_rtx (MEM, GET_MODE (op), plus_constant_for_output (y, offset)); RTX_UNCHANGING_P (new) = RTX_UNCHANGING_P (op); return new; } if (GET_CODE (y) == PLUS) { rtx z = y; register rtx *const_loc; op = copy_rtx (op); z = XEXP (op, 0); const_loc = find_constant_term_loc (&z); if (const_loc) { *const_loc = plus_constant_for_output (*const_loc, offset); return op; } } new = gen_rtx (MEM, GET_MODE (op), plus_constant_for_output (y, offset)); RTX_UNCHANGING_P (new) = RTX_UNCHANGING_P (op); return new; } abort ();}#ifdef REGISTER_CONSTRAINTS/* Check the operands of an insn (found in recog_operands) against the insn's operand constraints (found via INSN_CODE_NUM) and return 1 if they are valid. WHICH_ALTERNATIVE is set to a number which indicates which alternative of constraints was matched: 0 for the first alternative, 1 for the next, etc. In addition, when two operands are match and it happens that the output operand is (reg) while the input operand is --(reg) or ++(reg) (a pre-inc or pre-dec), make the output operand look like the input. This is because the output operand is the one the template will print. This is used in final, just before printing the assembler code and by the routines that determine an insn's attribute. If STRICT is a positive non-zero value, it means that we have been called after reload has been completed. In that case, we must do all checks strictly. If it is zero, it means that we have been called before reload has completed. In that case, we first try to see if we can find an alternative that matches strictly. If not, we try again, this time assuming that reload will fix up the insn. This provides a "best guess" for the alternative and is used to compute attributes of insns prior to reload. A negative value of STRICT is used for this internal call. */struct funny_match{ int this, other;};intconstrain_operands (insn_code_num, strict) int insn_code_num; int strict;{ char *constraints[MAX_RECOG_OPERANDS]; int matching_operands[MAX_RECOG_OPERANDS]; enum op_type {OP_IN, OP_OUT, OP_INOUT} op_types[MAX_RECOG_OPERANDS]; int earlyclobber[MAX_RECOG_OPERANDS]; register int c; int noperands = insn_n_operands[insn_code_num]; struct funny_match funny_match[MAX_RECOG_OPERANDS]; int funny_match_index; int nalternatives = insn_n_alternatives[insn_code_num]; if (noperands == 0 || nalternatives == 0) return 1; for (c = 0; c < noperands; c++) { constraints[c] = insn_operand_constraint[insn_code_num][c]; matching_operands[c] = -1; op_types[c] = OP_IN; } which_alternative = 0; while (which_alternative < nalternatives) { register int opno; int lose = 0; funny_match_index = 0; for (opno = 0; opno < noperands; opno++) { register rtx op = recog_operand[opno]; enum machine_mode mode = GET_MODE (op); register char *p = constraints[opno]; int offset = 0; int win = 0; int val; earlyclobber[opno] = 0; 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 '%': break; case '=': op_types[opno] = OP_OUT; break; case '+': op_types[opno] = OP_INOUT; break; case '&': earlyclobber[opno] = 1; break; case '0': case '1': case '2': case '3': case '4': /* 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 we are not testing strictly, assume that this constraint will be satisfied. */ if (strict < 0) val = 1; else val = operands_match_p (recog_operand[c - '0'], recog_operand[opno]); matching_operands[opno] = c - '0'; matching_operands[c - '0'] = opno; if (val != 0) win = 1; /* If output is *x and input is *--x, arrange later to change the output to *--x as well, since the output op is the one that will be printed. */ if (val == 2 && strict > 0) { funny_match[funny_match_index].this = opno; funny_match[funny_match_index++].other = c - '0'; } break; case 'p': /* p is used for address_operands. When we are called by gen_input_reload, no one will have checked that the address is strictly valid, i.e., that all pseudos requiring hard regs have gotten them. */ if (strict <= 0 || (strict_memory_address_p (insn_operand_mode[insn_code_num][opno], op))) win = 1; break; /* No need to check general_operand again; it was done in insn-recog.c. */ 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 (strict < 0 || GENERAL_REGS == ALL_REGS || GET_CODE (op) != REG || (reload_in_progress && REGNO (op) >= FIRST_PSEUDO_REGISTER) || reg_fits_class_p (op, GENERAL_REGS, offset, mode)) win = 1; break; case 'r': if (strict < 0 || (strict == 0 && GET_CODE (op) == REG && REGNO (op) >= FIRST_PSEUDO_REGISTER) || (strict == 0 && GET_CODE (op) == SCRATCH) || (GET_CODE (op) == REG && (GENERAL_REGS == ALL_REGS || reg_fits_class_p (op, GENERAL_REGS, offset, mode)))) 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 /* Before reload, accept what reload can turn into mem. */ || (strict < 0 && CONSTANT_P (op)) /* During reload, accept a pseudo */ || (reload_in_progress && GET_CODE (op) == REG && REGNO (op) >= FIRST_PSEUDO_REGISTER)) 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_MODE (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; 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 ((strict > 0 && offsettable_memref_p (op)) || (strict == 0 && offsettable_nonstrict_memref_p (op)) /* Before reload, accept what reload can handle. */ || (strict < 0 && (CONSTANT_P (op) || GET_CODE (op) == MEM)) /* During reload, accept a pseudo */ || (reload_in_progress && GET_CODE (op) == REG && REGNO (op) >= FIRST_PSEUDO_REGISTER)) win = 1; break; default: if (strict < 0 || (strict == 0 && GET_CODE (op) == REG && REGNO (op) >= FIRST_PSEUDO_REGISTER) || (strict == 0 && GET_CODE (op) == SCRATCH) || (GET_CODE (op) == REG && reg_fits_class_p (op, REG_CLASS_FROM_LETTER (c), offset, mode))) win = 1; } constraints[opno] = 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) { int opno, eopno; /* See if any earlyclobber operand conflicts with some other operand. */ if (strict > 0) for (eopno = 0; eopno < noperands; eopno++) /* Ignore earlyclobber operands now in memory, because we would often report failure when we have two memory operands, one of which was formerly a REG. */ if (earlyclobber[eopno] && GET_CODE (recog_operand[eopno]) == REG) for (opno = 0; opno < noperands; opno++) if ((GET_CODE (recog_operand[opno]) == MEM || op_types[opno] != OP_OUT) && opno != eopno && constraints[opno] != 0 && ! (matching_operands[opno] == eopno && rtx_equal_p (recog_operand[opno], recog_operand[eopno])) && ! safe_from_earlyclobber (recog_operand[opno], recog_operand[eopno])) lose = 1; if (! lose) { while (--funny_match_index >= 0) { recog_operand[funny_match[funny_match_index].other] = recog_operand[funny_match[funny_match_index].this]; } return 1; } } which_alternative++; } /* If we are about to reject this, but we are not to test strictly, try a very loose test. Only return failure if it fails also. */ if (strict == 0) return constrain_operands (insn_code_num, -1); else return 0;}/* Return 1 iff OPERAND (assumed to be a REG rtx) is a hard reg in class CLASS when its regno is offsetted by OFFSET and changed to mode MODE. If REG occupies multiple hard regs, all of them must be in CLASS. */intreg_fits_class_p (operand, class, offset, mode) rtx operand; register enum reg_class class; int offset; enum machine_mode mode;{ register int regno = REGNO (operand); if (regno < FIRST_PSEUDO_REGISTER && TEST_HARD_REG_BIT (reg_class_contents[(int) class], regno + offset)) { register int sr; regno += offset; for (sr = HARD_REGNO_NREGS (regno, mode) - 1; sr > 0; sr--) if (! TEST_HARD_REG_BIT (reg_class_contents[(int) class], regno + sr)) break; return sr == 0; } return 0;}#endif /* REGISTER_CONSTRAINTS */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -