📄 recog.c
字号:
if (GET_MODE (op) != mode && mode != VOIDmode) return 0; if (GET_CODE (op) == SUBREG) { /* Before reload, we can allow (SUBREG (MEM...)) as a register operand because it is guaranteed to be reloaded into one. Just make sure the MEM is valid in itself. (Ideally, (SUBREG (MEM)...) should not exist after reload, but currently it does result from (SUBREG (REG)...) where the reg went on the stack.) */ if (! reload_completed && GET_CODE (SUBREG_REG (op)) == MEM) return general_operand (op, mode); op = SUBREG_REG (op); } /* We don't consider registers whose class is NO_REGS to be a register operand. */ return (GET_CODE (op) == REG && (REGNO (op) >= FIRST_PSEUDO_REGISTER || REGNO_REG_CLASS (REGNO (op)) != NO_REGS));}/* Return 1 if OP is a valid operand that stands for pushing a value of mode MODE onto the stack. The main use of this function is as a predicate in match_operand expressions in the machine description. */intpush_operand (op, mode) rtx op; enum machine_mode mode;{ if (GET_CODE (op) != MEM) return 0; if (GET_MODE (op) != mode) return 0; op = XEXP (op, 0); if (GET_CODE (op) != STACK_PUSH_CODE) return 0; return XEXP (op, 0) == stack_pointer_rtx;}/* Return 1 if ADDR is a valid memory address for mode MODE. */intmemory_address_p (mode, addr) enum machine_mode mode; register rtx addr;{ GO_IF_LEGITIMATE_ADDRESS (mode, addr, win); return 0; win: return 1;}/* Return 1 if OP is a valid memory reference with mode MODE, including a valid address. The main use of this function is as a predicate in match_operand expressions in the machine description. */intmemory_operand (op, mode) register rtx op; enum machine_mode mode;{ rtx inner; if (! reload_completed) /* Note that no SUBREG is a memory operand before end of reload pass, because (SUBREG (MEM...)) forces reloading into a register. */ return GET_CODE (op) == MEM && general_operand (op, mode); if (mode != VOIDmode && GET_MODE (op) != mode) return 0; inner = op; if (GET_CODE (inner) == SUBREG) inner = SUBREG_REG (inner); return (GET_CODE (inner) == MEM && general_operand (op, mode));}/* Return 1 if OP is a valid indirect memory reference with mode MODE; that is, a memory reference whose address is a general_operand. */intindirect_operand (op, mode) register rtx op; enum machine_mode mode;{ /* Before reload, a SUBREG isn't in memory (see memory_operand, above). */ if (! reload_completed && GET_CODE (op) == SUBREG && GET_CODE (SUBREG_REG (op)) == MEM) { register int offset = SUBREG_WORD (op) * UNITS_PER_WORD; rtx inner = SUBREG_REG (op);#if BYTES_BIG_ENDIAN offset -= (MIN (UNITS_PER_WORD, GET_MODE_SIZE (GET_MODE (op))) - MIN (UNITS_PER_WORD, GET_MODE_SIZE (GET_MODE (inner))));#endif /* The only way that we can have a general_operand as the resulting address is if OFFSET is zero and the address already is an operand or if the address is (plus Y (const_int -OFFSET)) and Y is an operand. */ return ((offset == 0 && general_operand (XEXP (inner, 0), Pmode)) || (GET_CODE (XEXP (inner, 0)) == PLUS && GET_CODE (XEXP (XEXP (inner, 0), 1)) == CONST_INT && INTVAL (XEXP (XEXP (inner, 0), 1)) == -offset && general_operand (XEXP (XEXP (inner, 0), 0), Pmode))); } return (GET_CODE (op) == MEM && memory_operand (op, mode) && general_operand (XEXP (op, 0), Pmode));}/* Return 1 if this is a comparison operator. This allows the use of MATCH_OPERATOR to recognize all the branch insns. */intcomparison_operator (op, mode) register rtx op; enum machine_mode mode;{ return ((mode == VOIDmode || GET_MODE (op) == mode) && GET_RTX_CLASS (GET_CODE (op)) == '<');}/* If BODY is an insn body that uses ASM_OPERANDS, return the number of operands (both input and output) in the insn. Otherwise return -1. */intasm_noperands (body) rtx body;{ if (GET_CODE (body) == ASM_OPERANDS) /* No output operands: return number of input operands. */ return ASM_OPERANDS_INPUT_LENGTH (body); if (GET_CODE (body) == SET && GET_CODE (SET_SRC (body)) == ASM_OPERANDS) /* Single output operand: BODY is (set OUTPUT (asm_operands ...)). */ return ASM_OPERANDS_INPUT_LENGTH (SET_SRC (body)) + 1; else if (GET_CODE (body) == PARALLEL && GET_CODE (XVECEXP (body, 0, 0)) == SET && GET_CODE (SET_SRC (XVECEXP (body, 0, 0))) == ASM_OPERANDS) { /* Multiple output operands, or 1 output plus some clobbers: body is [(set OUTPUT (asm_operands ...))... (clobber (reg ...))...]. */ int i; int n_sets; /* Count backwards through CLOBBERs to determine number of SETs. */ for (i = XVECLEN (body, 0); i > 0; i--) { if (GET_CODE (XVECEXP (body, 0, i - 1)) == SET) break; if (GET_CODE (XVECEXP (body, 0, i - 1)) != CLOBBER) return -1; } /* N_SETS is now number of output operands. */ n_sets = i; /* Verify that all the SETs we have came from a single original asm_operands insn (so that invalid combinations are blocked). */ for (i = 0; i < n_sets; i++) { rtx elt = XVECEXP (body, 0, i); if (GET_CODE (elt) != SET) return -1; if (GET_CODE (SET_SRC (elt)) != ASM_OPERANDS) return -1; /* If these ASM_OPERANDS rtx's came from different original insns then they aren't allowed together. */ if (ASM_OPERANDS_INPUT_VEC (SET_SRC (elt)) != ASM_OPERANDS_INPUT_VEC (SET_SRC (XVECEXP (body, 0, 0)))) return -1; } return (ASM_OPERANDS_INPUT_LENGTH (SET_SRC (XVECEXP (body, 0, 0))) + n_sets); } else if (GET_CODE (body) == PARALLEL && GET_CODE (XVECEXP (body, 0, 0)) == ASM_OPERANDS) { /* 0 outputs, but some clobbers: body is [(asm_operands ...) (clobber (reg ...))...]. */ int i; /* Make sure all the other parallel things really are clobbers. */ for (i = XVECLEN (body, 0) - 1; i > 0; i--) if (GET_CODE (XVECEXP (body, 0, i)) != CLOBBER) return -1; return ASM_OPERANDS_INPUT_LENGTH (XVECEXP (body, 0, 0)); } else return -1;}/* Assuming BODY is an insn body that uses ASM_OPERANDS, copy its operands (both input and output) into the vector OPERANDS, the locations of the operands within the insn into the vector OPERAND_LOCS, and the constraints for the operands into CONSTRAINTS. Write the modes of the operands into MODES. Return the assembler-template. If MODES, OPERAND_LOCS, CONSTRAINTS or OPERANDS is 0, we don't store that info. */char *decode_asm_operands (body, operands, operand_locs, constraints, modes) rtx body; rtx *operands; rtx **operand_locs; char **constraints; enum machine_mode *modes;{ register int i; int noperands; char *template = 0; if (GET_CODE (body) == SET && GET_CODE (SET_SRC (body)) == ASM_OPERANDS) { rtx asmop = SET_SRC (body); /* Single output operand: BODY is (set OUTPUT (asm_operands ....)). */ noperands = ASM_OPERANDS_INPUT_LENGTH (asmop) + 1; for (i = 1; i < noperands; i++) { if (operand_locs) operand_locs[i] = &ASM_OPERANDS_INPUT (asmop, i - 1); if (operands) operands[i] = ASM_OPERANDS_INPUT (asmop, i - 1); if (constraints) constraints[i] = ASM_OPERANDS_INPUT_CONSTRAINT (asmop, i - 1); if (modes) modes[i] = ASM_OPERANDS_INPUT_MODE (asmop, i - 1); } /* The output is in the SET. Its constraint is in the ASM_OPERANDS itself. */ if (operands) operands[0] = SET_DEST (body); if (operand_locs) operand_locs[0] = &SET_DEST (body); if (constraints) constraints[0] = ASM_OPERANDS_OUTPUT_CONSTRAINT (asmop); if (modes) modes[0] = GET_MODE (SET_DEST (body)); template = ASM_OPERANDS_TEMPLATE (asmop); } else if (GET_CODE (body) == ASM_OPERANDS) { rtx asmop = body; /* No output operands: BODY is (asm_operands ....). */ noperands = ASM_OPERANDS_INPUT_LENGTH (asmop); /* The input operands are found in the 1st element vector. */ /* Constraints for inputs are in the 2nd element vector. */ for (i = 0; i < noperands; i++) { if (operand_locs) operand_locs[i] = &ASM_OPERANDS_INPUT (asmop, i); if (operands) operands[i] = ASM_OPERANDS_INPUT (asmop, i); if (constraints) constraints[i] = ASM_OPERANDS_INPUT_CONSTRAINT (asmop, i); if (modes) modes[i] = ASM_OPERANDS_INPUT_MODE (asmop, i); } template = ASM_OPERANDS_TEMPLATE (asmop); } else if (GET_CODE (body) == PARALLEL && GET_CODE (XVECEXP (body, 0, 0)) == SET) { rtx asmop = SET_SRC (XVECEXP (body, 0, 0)); int nparallel = XVECLEN (body, 0); /* Includes CLOBBERs. */ int nin = ASM_OPERANDS_INPUT_LENGTH (asmop); int nout = 0; /* Does not include CLOBBERs. */ /* At least one output, plus some CLOBBERs. */ /* The outputs are in the SETs. Their constraints are in the ASM_OPERANDS itself. */ for (i = 0; i < nparallel; i++) { if (GET_CODE (XVECEXP (body, 0, i)) == CLOBBER) break; /* Past last SET */ if (operands) operands[i] = SET_DEST (XVECEXP (body, 0, i)); if (operand_locs) operand_locs[i] = &SET_DEST (XVECEXP (body, 0, i)); if (constraints) constraints[i] = XSTR (SET_SRC (XVECEXP (body, 0, i)), 1); if (modes) modes[i] = GET_MODE (SET_DEST (XVECEXP (body, 0, i))); nout++; } for (i = 0; i < nin; i++) { if (operand_locs) operand_locs[i + nout] = &ASM_OPERANDS_INPUT (asmop, i); if (operands) operands[i + nout] = ASM_OPERANDS_INPUT (asmop, i); if (constraints) constraints[i + nout] = ASM_OPERANDS_INPUT_CONSTRAINT (asmop, i); if (modes) modes[i + nout] = ASM_OPERANDS_INPUT_MODE (asmop, i); } template = ASM_OPERANDS_TEMPLATE (asmop); } else if (GET_CODE (body) == PARALLEL && GET_CODE (XVECEXP (body, 0, 0)) == ASM_OPERANDS) { /* No outputs, but some CLOBBERs. */ rtx asmop = XVECEXP (body, 0, 0); int nin = ASM_OPERANDS_INPUT_LENGTH (asmop); for (i = 0; i < nin; i++) { if (operand_locs) operand_locs[i] = &ASM_OPERANDS_INPUT (asmop, i); if (operands) operands[i] = ASM_OPERANDS_INPUT (asmop, i); if (constraints) constraints[i] = ASM_OPERANDS_INPUT_CONSTRAINT (asmop, i); if (modes) modes[i] = ASM_OPERANDS_INPUT_MODE (asmop, i); } template = ASM_OPERANDS_TEMPLATE (asmop); } return template;}/* Given an rtx *P, if it is a sum containing an integer constant term, return the location (type rtx *) of the pointer to that constant term. Otherwise, return a null pointer. */static rtx *find_constant_term_loc (p) rtx *p;{ register rtx *tem; register enum rtx_code code = GET_CODE (*p); /* If *P IS such a constant term, P is its location. */ if (code == CONST_INT || code == SYMBOL_REF || code == LABEL_REF || code == CONST) return p; /* Otherwise, if not a sum, it has no constant term. */ if (GET_CODE (*p) != PLUS) return 0; /* If one of the summands is constant, return its location. */ if (XEXP (*p, 0) && CONSTANT_P (XEXP (*p, 0)) && XEXP (*p, 1) && CONSTANT_P (XEXP (*p, 1))) return p; /* Otherwise, check each summand for containing a constant term. */ if (XEXP (*p, 0) != 0) { tem = find_constant_term_loc (&XEXP (*p, 0)); if (tem != 0) return tem; } if (XEXP (*p, 1) != 0) { tem = find_constant_term_loc (&XEXP (*p, 1)); if (tem != 0) return tem; } return 0;}/* Return 1 if OP is a memory reference whose address contains no side effects and remains valid after the addition of a positive integer less than the size of the object being referenced. We assume that the original address is valid and do not check it. This uses strict_memory_address_p as a subroutine, so don't use it before reload. */intoffsettable_memref_p (op) rtx op;{ return ((GET_CODE (op) == MEM) && offsettable_address_p (1, GET_MODE (op), XEXP (op, 0)));}/* Similar, but don't require a strictly valid mem ref: consider pseudo-regs valid as index or base regs. */intoffsettable_nonstrict_memref_p (op) rtx op;{ return ((GET_CODE (op) == MEM) && offsettable_address_p (0, GET_MODE (op), XEXP (op, 0)));}/* Return 1 if Y is a memory address which contains no side effects and would remain valid after the addition of a positive integer less than the size of that mode. We assume that the original address is valid and do not check it. We do check that it is valid for narrower modes. If STRICTP is nonzero, we require a strictly valid address, for the sake of use in reload.c. */intoffsettable_address_p (strictp, mode, y) int strictp; enum machine_mode mode; register rtx y;{ register enum rtx_code ycode = GET_CODE (y); register rtx z; rtx y1 = y; rtx *y2; int (*addressp) () = (strictp ? strict_memory_address_p : memory_address_p); if (CONSTANT_ADDRESS_P (y)) return 1; /* Adjusting an offsettable address involves changing to a narrower mode. Make sure that's OK. */ if (mode_dependent_address_p (y)) return 0; /* If the expression contains a constant term, see if it remains valid when max possible offset is added. */ if ((ycode == PLUS) && (y2 = find_constant_term_loc (&y1))) { int good; y1 = *y2; *y2 = plus_constant (*y2, GET_MODE_SIZE (mode) - 1); /* Use QImode because an odd displacement may be automatically invalid for any wider mode. But it should be valid for a single byte. */ good = (*addressp) (QImode, y); /* In any case, restore old contents of memory. */ *y2 = y1; return good; } if (ycode == PRE_DEC || ycode == PRE_INC || ycode == POST_DEC || ycode == POST_INC) return 0; /* The offset added here is chosen as the maximum offset that any instruction could need to add when operating on something of the specified mode. We assume that if Y and Y+c are valid addresses then so is Y+d for all 0<d<c. */ z = plus_constant_for_output (y, GET_MODE_SIZE (mode) - 1);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -