rtlanal.c
来自「GCC编译器源代码」· C语言 代码 · 共 1,983 行 · 第 1/4 页
C
1,983 行
/* case TRAP_IF: This isn't clear yet. */ return 1; case MEM: case ASM_OPERANDS: if (MEM_VOLATILE_P (x)) return 1; default: break; } /* Recursively scan the operands of this expression. */ { register char *fmt = GET_RTX_FORMAT (code); register int i; for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) { if (fmt[i] == 'e') { if (volatile_refs_p (XEXP (x, i))) return 1; } if (fmt[i] == 'E') { register int j; for (j = 0; j < XVECLEN (x, i); j++) if (volatile_refs_p (XVECEXP (x, i, j))) return 1; } } } return 0;}/* Similar to above, except that it also rejects register pre- and post- incrementing. */intside_effects_p (x) rtx x;{ register RTX_CODE code; code = GET_CODE (x); switch (code) { case LABEL_REF: case SYMBOL_REF: case CONST_INT: case CONST: case CONST_DOUBLE: case CC0: case PC: case REG: case SCRATCH: case ASM_INPUT: case ADDR_VEC: case ADDR_DIFF_VEC: return 0; case CLOBBER: /* Reject CLOBBER with a non-VOID mode. These are made by combine.c when some combination can't be done. If we see one, don't think that we can simplify the expression. */ return (GET_MODE (x) != VOIDmode); case PRE_INC: case PRE_DEC: case POST_INC: case POST_DEC: case CALL: case UNSPEC_VOLATILE: /* case TRAP_IF: This isn't clear yet. */ return 1; case MEM: case ASM_OPERANDS: if (MEM_VOLATILE_P (x)) return 1; default: break; } /* Recursively scan the operands of this expression. */ { register char *fmt = GET_RTX_FORMAT (code); register int i; for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) { if (fmt[i] == 'e') { if (side_effects_p (XEXP (x, i))) return 1; } if (fmt[i] == 'E') { register int j; for (j = 0; j < XVECLEN (x, i); j++) if (side_effects_p (XVECEXP (x, i, j))) return 1; } } } return 0;}/* Return nonzero if evaluating rtx X might cause a trap. */intmay_trap_p (x) rtx x;{ int i; enum rtx_code code; char *fmt; if (x == 0) return 0; code = GET_CODE (x); switch (code) { /* Handle these cases quickly. */ case CONST_INT: case CONST_DOUBLE: case SYMBOL_REF: case LABEL_REF: case CONST: case PC: case CC0: case REG: case SCRATCH: return 0; /* Conditional trap can trap! */ case UNSPEC_VOLATILE: case TRAP_IF: return 1; /* Memory ref can trap unless it's a static var or a stack slot. */ case MEM: return rtx_addr_can_trap_p (XEXP (x, 0)); /* Division by a non-constant might trap. */ case DIV: case MOD: case UDIV: case UMOD: if (! CONSTANT_P (XEXP (x, 1)) || GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT) return 1; /* This was const0_rtx, but by not using that, we can link this file into other programs. */ if (GET_CODE (XEXP (x, 1)) == CONST_INT && INTVAL (XEXP (x, 1)) == 0) return 1; break; case EXPR_LIST: /* An EXPR_LIST is used to represent a function call. This certainly may trap. */ return 1; default: /* Any floating arithmetic may trap. */ if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT) return 1; } fmt = GET_RTX_FORMAT (code); for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) { if (fmt[i] == 'e') { if (may_trap_p (XEXP (x, i))) return 1; } else if (fmt[i] == 'E') { register int j; for (j = 0; j < XVECLEN (x, i); j++) if (may_trap_p (XVECEXP (x, i, j))) return 1; } } return 0;}/* Return nonzero if X contains a comparison that is not either EQ or NE, i.e., an inequality. */intinequality_comparisons_p (x) rtx x;{ register char *fmt; register int len, i; register enum rtx_code code = GET_CODE (x); switch (code) { case REG: case SCRATCH: case PC: case CC0: case CONST_INT: case CONST_DOUBLE: case CONST: case LABEL_REF: case SYMBOL_REF: return 0; case LT: case LTU: case GT: case GTU: case LE: case LEU: case GE: case GEU: return 1; default: break; } len = GET_RTX_LENGTH (code); fmt = GET_RTX_FORMAT (code); for (i = 0; i < len; i++) { if (fmt[i] == 'e') { if (inequality_comparisons_p (XEXP (x, i))) return 1; } else if (fmt[i] == 'E') { register int j; for (j = XVECLEN (x, i) - 1; j >= 0; j--) if (inequality_comparisons_p (XVECEXP (x, i, j))) return 1; } } return 0;}/* Replace any occurrence of FROM in X with TO. Note that copying is not done so X must not be shared unless all copies are to be modified. */rtxreplace_rtx (x, from, to) rtx x, from, to;{ register int i, j; register char *fmt; if (x == from) return to; /* Allow this function to make replacements in EXPR_LISTs. */ if (x == 0) return 0; fmt = GET_RTX_FORMAT (GET_CODE (x)); for (i = GET_RTX_LENGTH (GET_CODE (x)) - 1; i >= 0; i--) { if (fmt[i] == 'e') XEXP (x, i) = replace_rtx (XEXP (x, i), from, to); else if (fmt[i] == 'E') for (j = XVECLEN (x, i) - 1; j >= 0; j--) XVECEXP (x, i, j) = replace_rtx (XVECEXP (x, i, j), from, to); } return x;} /* Throughout the rtx X, replace many registers according to REG_MAP. Return the replacement for X (which may be X with altered contents). REG_MAP[R] is the replacement for register R, or 0 for don't replace. NREGS is the length of REG_MAP; regs >= NREGS are not mapped. We only support REG_MAP entries of REG or SUBREG. Also, hard registers should not be mapped to pseudos or vice versa since validate_change is not called. If REPLACE_DEST is 1, replacements are also done in destinations; otherwise, only sources are replaced. */rtxreplace_regs (x, reg_map, nregs, replace_dest) rtx x; rtx *reg_map; int nregs; int replace_dest;{ register enum rtx_code code; register int i; register char *fmt; if (x == 0) return x; code = GET_CODE (x); switch (code) { case SCRATCH: case PC: case CC0: case CONST_INT: case CONST_DOUBLE: case CONST: case SYMBOL_REF: case LABEL_REF: return x; case REG: /* Verify that the register has an entry before trying to access it. */ if (REGNO (x) < nregs && reg_map[REGNO (x)] != 0) { /* SUBREGs can't be shared. Always return a copy to ensure that if this replacement occurs more than once then each instance will get distinct rtx. */ if (GET_CODE (reg_map[REGNO (x)]) == SUBREG) return copy_rtx (reg_map[REGNO (x)]); return reg_map[REGNO (x)]; } return x; case SUBREG: /* Prevent making nested SUBREGs. */ if (GET_CODE (SUBREG_REG (x)) == REG && REGNO (SUBREG_REG (x)) < nregs && reg_map[REGNO (SUBREG_REG (x))] != 0 && GET_CODE (reg_map[REGNO (SUBREG_REG (x))]) == SUBREG) { rtx map_val = reg_map[REGNO (SUBREG_REG (x))]; rtx map_inner = SUBREG_REG (map_val); if (GET_MODE (x) == GET_MODE (map_inner)) return map_inner; else { /* We cannot call gen_rtx here since we may be linked with genattrtab.c. */ /* Let's try clobbering the incoming SUBREG and see if this is really safe. */ SUBREG_REG (x) = map_inner; SUBREG_WORD (x) += SUBREG_WORD (map_val); return x;#if 0 rtx new = rtx_alloc (SUBREG); PUT_MODE (new, GET_MODE (x)); SUBREG_REG (new) = map_inner; SUBREG_WORD (new) = SUBREG_WORD (x) + SUBREG_WORD (map_val);#endif } } break; case SET: if (replace_dest) SET_DEST (x) = replace_regs (SET_DEST (x), reg_map, nregs, 0); else if (GET_CODE (SET_DEST (x)) == MEM || GET_CODE (SET_DEST (x)) == STRICT_LOW_PART) /* Even if we are not to replace destinations, replace register if it is CONTAINED in destination (destination is memory or STRICT_LOW_PART). */ XEXP (SET_DEST (x), 0) = replace_regs (XEXP (SET_DEST (x), 0), reg_map, nregs, 0); else if (GET_CODE (SET_DEST (x)) == ZERO_EXTRACT) /* Similarly, for ZERO_EXTRACT we replace all operands. */ break; SET_SRC (x) = replace_regs (SET_SRC (x), reg_map, nregs, 0); return x; default: break; } fmt = GET_RTX_FORMAT (code); for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) { if (fmt[i] == 'e') XEXP (x, i) = replace_regs (XEXP (x, i), reg_map, nregs, replace_dest); if (fmt[i] == 'E') { register int j; for (j = 0; j < XVECLEN (x, i); j++) XVECEXP (x, i, j) = replace_regs (XVECEXP (x, i, j), reg_map, nregs, replace_dest); } } return x;}/* Return 1 if X, the SRC_SRC of SET of (pc) contain a REG or MEM that is not in the constant pool and not in the condition of an IF_THEN_ELSE. */static intjmp_uses_reg_or_mem (x) rtx x;{ enum rtx_code code = GET_CODE (x); int i, j; char *fmt; switch (code) { case CONST: case LABEL_REF: case PC: return 0; case REG: return 1; case MEM: return ! (GET_CODE (XEXP (x, 0)) == SYMBOL_REF && CONSTANT_POOL_ADDRESS_P (XEXP (x, 0))); case IF_THEN_ELSE: return (jmp_uses_reg_or_mem (XEXP (x, 1)) || jmp_uses_reg_or_mem (XEXP (x, 2))); case PLUS: case MINUS: case MULT: return (jmp_uses_reg_or_mem (XEXP (x, 0)) || jmp_uses_reg_or_mem (XEXP (x, 1))); } fmt = GET_RTX_FORMAT (code); for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) { if (fmt[i] == 'e' && jmp_uses_reg_or_mem (XEXP (x, i))) return 1; if (fmt[i] == 'E') for (j = 0; j < XVECLEN (x, i); j++) if (jmp_uses_reg_or_mem (XVECEXP (x, i, j))) return 1; } return 0;}/* Return nonzero if INSN is an indirect jump (aka computed jump). Tablejumps and casesi insns are not considered indirect jumps; we can recognize them by a (use (lael_ref)). */intcomputed_jump_p (insn) rtx insn;{ int i; if (GET_CODE (insn) == JUMP_INSN) { rtx pat = PATTERN (insn); int computed_jump = 0; if (GET_CODE (pat) == PARALLEL) { int len = XVECLEN (pat, 0); int has_use_labelref = 0; for (i = len - 1; i >= 0; i--) if (GET_CODE (XVECEXP (pat, 0, i)) == USE && (GET_CODE (XEXP (XVECEXP (pat, 0, i), 0)) == LABEL_REF)) has_use_labelref = 1; if (! has_use_labelref) for (i = len - 1; i >= 0; i--) if (GET_CODE (XVECEXP (pat, 0, i)) == SET && SET_DEST (XVECEXP (pat, 0, i)) == pc_rtx && jmp_uses_reg_or_mem (SET_SRC (XVECEXP (pat, 0, i)))) return 1; } else if (GET_CODE (pat) == SET && SET_DEST (pat) == pc_rtx && jmp_uses_reg_or_mem (SET_SRC (pat))) return 1; } return 0;}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?