📄 cse.c
字号:
x = XEXP (x, 0); goto repeat; case PRE_DEC: case PRE_INC: case POST_DEC: case POST_INC: case PC: case CC0: case CALL: do_not_record = 1; return 0; case ASM_OPERANDS: if (MEM_VOLATILE_P (x)) { do_not_record = 1; return 0; } } i = GET_RTX_LENGTH (code) - 1; hash += (int) code + (int) GET_MODE (x); fmt = GET_RTX_FORMAT (code); for (; i >= 0; i--) { if (fmt[i] == 'e') { /* If we are about to do the last recursive call needed at this level, change it into iteration. This function is called enough to be worth it. */ if (i == 0) { x = XEXP (x, 0); goto repeat; } hash += canon_hash (XEXP (x, i), 0); } else if (fmt[i] == 'E') for (j = 0; j < XVECLEN (x, i); j++) hash += canon_hash (XVECEXP (x, i, j), 0); else if (fmt[i] == 's') { register char *p = XSTR (x, i); if (p) while (*p) { register int tem = *p++; hash += ((1 << HASHBITS) - 1) & (tem + (tem >> HASHBITS)); } } else { register int tem = XINT (x, i); hash += ((1 << HASHBITS) - 1) & (tem + (tem >> HASHBITS)); } } return hash;}/* Like canon_hash but with no side effects. */static intsafe_hash (x, mode) rtx x; enum machine_mode mode;{ int save_do_not_record = do_not_record; int save_hash_arg_in_memory = hash_arg_in_memory; int save_hash_arg_in_struct = hash_arg_in_struct; int hash = canon_hash (x, mode); hash_arg_in_memory = save_hash_arg_in_memory; hash_arg_in_struct = save_hash_arg_in_struct; do_not_record = save_do_not_record; return hash;}/* Return 1 iff X and Y would canonicalize into the same thing, without actually constructing the canonicalization of either one. If VALIDATE is nonzero, we assume X is an expression being processed from the rtl and Y was found in the hash table. We check register refs in Y for being marked as valid. */static intexp_equiv_p (x, y, validate) rtx x, y; int validate;{ register int i; register enum rtx_code code; register char *fmt; /* Note: it is incorrect to assume an expression is equivalent to itself if VALIDATE is nonzero. */ if (x == y && !validate) return 1; if (x == 0 || y == 0) return x == y; code = GET_CODE (x); if (code != GET_CODE (y)) return 0; switch (code) { case PC: case CC0: return x == y; case CONST_INT: return XINT (x, 0) == XINT (y, 0); case LABEL_REF: case SYMBOL_REF: return XEXP (x, 0) == XEXP (y, 0); case REG: return (reg_qty[REGNO (x)] == reg_qty[REGNO (y)] && (!validate || reg_in_table[REGNO (y)] == reg_tick[REGNO (y)])); } /* (MULT:SI x y) and (MULT:HI x y) are NOT equivalent. */ if (GET_MODE (x) != GET_MODE (y)) return 0; /* Compare the elements. If any pair of corresponding elements fail to match, return 0 for the whole things. */ fmt = GET_RTX_FORMAT (code); for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) { if (fmt[i] == 'e') { if (! exp_equiv_p (XEXP (x, i), XEXP (y, i), validate)) return 0; } else if (fmt[i] == 'E') { int j; if (XVECLEN (x, i) != XVECLEN (y, i)) return 0; for (j = 0; j < XVECLEN (x, i); j++) if (! exp_equiv_p (XVECEXP (x, i, j), XVECEXP (y, i, j), validate)) return 0; } else if (fmt[i] == 's') { if (strcmp (XSTR (x, i), XSTR (y, i))) return 0; } else { if (XINT (x, i) != XINT (y, i)) return 0; } } return 1;}/* Return 1 iff any subexpression of X matches Y. Here we do not require that X or Y be valid (for registers referred to) for being in the hash table. */intrefers_to_p (x, y) rtx x, y;{ register int i; register enum rtx_code code; register char *fmt; repeat: if (x == y) return 1; if (x == 0 || y == 0) return 0; code = GET_CODE (x); /* If X as a whole has the same code as Y, they may match. If so, return 1. */ if (code == GET_CODE (y)) { if (exp_equiv_p (x, y, 0)) return 1; } /* X does not match, so try its subexpressions. */ fmt = GET_RTX_FORMAT (code); for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) if (fmt[i] == 'e') { if (i == 0) { x = XEXP (x, 0); goto repeat; } else if (refers_to_p (XEXP (x, i), y)) return 1; } else if (fmt[i] == 'E') { int j; for (j = 0; j < XVECLEN (x, i); j++) if (refers_to_p (XVECEXP (x, i, j), y)) return 1; } return 0;}/* Return 1 iff any subexpression of X refers to memory at an address of REG plus some offset such that any of the bytes' offsets fall between START (inclusive) and END (exclusive). The value is undefined if X is a varying address. This function is not used in such cases. When used in the cse pass, `qty_const' is nonzero, and it is used to treat an address that is a register with a known constant value as if it were that constant value. In the loop pass, `qty_const' is zero, so this is not done. */intrefers_to_mem_p (x, reg, start, end) rtx x, reg; int start, end;{ register int i; register enum rtx_code code; register char *fmt; if (GET_CODE (reg) == CONST_INT) { start += INTVAL (reg); end += INTVAL (reg); reg = const0_rtx; } repeat: if (x == 0) return 0; code = GET_CODE (x); if (code == MEM) { register rtx addr = XEXP (x, 0); /* Get the address. */ int myend; if (GET_CODE (addr) == REG /* qty_const is 0 when outside the cse pass; at such times, this info is not available. */ && qty_const != 0 && qty_const[reg_qty[REGNO (addr)]] != 0) addr = qty_const[reg_qty[REGNO (addr)]]; if (GET_CODE (addr) == CONST) addr = XEXP (addr, 0); /* If ADDR is BASE, or BASE plus an integer, put the integer in I. */ if (addr == reg) i = 0; else if (GET_CODE (addr) == PLUS && XEXP (addr, 0) == reg && GET_CODE (XEXP (addr, 1)) == CONST_INT) i = INTVAL (XEXP (addr, 1)); else if (GET_CODE (addr) == CONST_INT && reg == const0_rtx) i = INTVAL (addr); else return 0; myend = i + GET_MODE_SIZE (GET_MODE (x)); return myend > start && i < end; } /* X does not match, so try its subexpressions. */ fmt = GET_RTX_FORMAT (code); for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) if (fmt[i] == 'e') { if (i == 0) { x = XEXP (x, 0); goto repeat; } else if (refers_to_mem_p (XEXP (x, i), reg, start, end)) return 1; } else if (fmt[i] == 'E') { int j; for (j = 0; j < XVECLEN (x, i); j++) if (refers_to_mem_p (XVECEXP (x, i, j), reg, start, end)) return 1; } return 0;}/* Nonzero if X refers to memory at a varying address; except that a register which has at the moment a known constant value isn't considered variable. */static intcse_rtx_addr_varies_p (x) rtx x;{ if (GET_CODE (x) == MEM && GET_CODE (XEXP (x, 0)) == REG && qty_const[reg_qty[REGNO (XEXP (x, 0))]] != 0) return 0; return rtx_addr_varies_p (x);}/* Canonicalize an expression: replace each register reference inside it with the "oldest" equivalent register. */static rtxcanon_reg (x) rtx x;{ register int i; register enum rtx_code code; register char *fmt; if (x == 0) return x; code = GET_CODE (x); switch (code) { case PC: case CC0: case CONST: case CONST_INT: case CONST_DOUBLE: case SYMBOL_REF: case LABEL_REF: case ADDR_VEC: case ADDR_DIFF_VEC: return x; case REG: { register rtx new; /* Never replace a hard reg, because hard regs can appear in more than one machine mode, and we must preserve the mode of each occurrence. Also, some hard regs appear in MEMs that are shared and mustn't be altered. */ if (REGNO (x) < FIRST_PSEUDO_REGISTER) return x; new = reg_rtx[qty_first_reg[reg_qty[REGNO (x)]]]; return new ? new : x; } } fmt = GET_RTX_FORMAT (code); for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) { register int j; if (fmt[i] == 'e') XEXP (x, i) = canon_reg (XEXP (x, i)); else if (fmt[i] == 'E') for (j = 0; j < XVECLEN (x, i); j++) XVECEXP (x, i, j) = canon_reg (XVECEXP (x, i, j)); } return x;}/* If X is a nontrivial arithmetic operation on an argument for which a constant value can be determined, return the result of operating on that value, as a constant. Otherwise, return X, possibly with one or more operands modified by recursive calls to this function. If X is a register whose contents are known, we do NOT return those contents. This is because an instruction that uses a register is usually faster than one that uses a constant. COPYFLAG is nonzero for memory addresses and subexpressions thereof. If COPYFLAG is nonzero, we avoid altering X itself by creating new structure when necessary. In this case we can risk creating invalid structure because it will be tested. If COPYFLAG is zero, be careful not to substitute constants into expressions that cannot be simplified. */static rtxfold_rtx (x, copyflag) rtx x; int copyflag;{ register enum rtx_code code; register char *fmt; register int i, val; rtx new = 0; int copied = ! copyflag; int width; /* Constant equivalents of first three operands of X; 0 when no such equivalent is known. */ rtx const_arg0; rtx const_arg1; rtx const_arg2; if (x == 0) return x; width = GET_MODE_BITSIZE (GET_MODE (x)); code = GET_CODE (x); switch (code) { case CONST: case CONST_INT: case CONST_DOUBLE: case SYMBOL_REF: case LABEL_REF: case PC: case CC0: case REG: /* No use simplifying an EXPR_LIST since they are used only for lists of args in a function call's REG_EQUAL note. */ case EXPR_LIST: return x; /* We must be careful when folding a memory address to avoid making it invalid. So fold nondestructively and use the result only if it's valid. */ case MEM: { rtx newaddr = fold_rtx (XEXP (x, 0), 1); /* Save time if no change was made. */ if (XEXP (x, 0) == newaddr) return x; if (! memory_address_p (GET_MODE (x), newaddr) && memory_address_p (GET_MODE (x), XEXP (x, 0))) return x; /* Don't replace a value with a more expensive one. */ if (rtx_cost (XEXP (x, 0)) < rtx_cost (newaddr)) return x; if (copyflag) return gen_rtx (MEM, GET_MODE (x), newaddr); XEXP (x, 0) = newaddr; return x; } } const_arg0 = 0; const_arg1 = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -