📄 cse.c
字号:
fix up the table later, but doing this here eliminates the need to call that expensive function in the most common case where the only use of the register is in the comparison. */ if (code == COMPARE || GET_RTX_CLASS (code) == '<') { if (GET_CODE (XEXP (x, 0)) == REG && ! REGNO_QTY_VALID_P (REGNO (XEXP (x, 0)))) if (insert_regs (XEXP (x, 0), NULL_PTR, 0)) { rehash_using_reg (XEXP (x, 0)); changed = 1; } if (GET_CODE (XEXP (x, 1)) == REG && ! REGNO_QTY_VALID_P (REGNO (XEXP (x, 1)))) if (insert_regs (XEXP (x, 1), NULL_PTR, 0)) { rehash_using_reg (XEXP (x, 1)); changed = 1; } } fmt = GET_RTX_FORMAT (code); for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) if (fmt[i] == 'e') changed |= mention_regs (XEXP (x, i)); else if (fmt[i] == 'E') for (j = 0; j < XVECLEN (x, i); j++) changed |= mention_regs (XVECEXP (x, i, j)); return changed;}/* Update the register quantities for inserting X into the hash table with a value equivalent to CLASSP. (If the class does not contain a REG, it is irrelevant.) If MODIFIED is nonzero, X is a destination; it is being modified. Note that delete_reg_equiv should be called on a register before insert_regs is done on that register with MODIFIED != 0. Nonzero value means that elements of reg_qty have changed so X's hash code may be different. */static intinsert_regs (x, classp, modified) rtx x; struct table_elt *classp; int modified;{ if (GET_CODE (x) == REG) { register int regno = REGNO (x); if (modified || ! (REGNO_QTY_VALID_P (regno) && qty_mode[reg_qty[regno]] == GET_MODE (x))) { if (classp) for (classp = classp->first_same_value; classp != 0; classp = classp->next_same_value) if (GET_CODE (classp->exp) == REG && GET_MODE (classp->exp) == GET_MODE (x)) { make_regs_eqv (regno, REGNO (classp->exp)); return 1; } make_new_qty (regno); qty_mode[reg_qty[regno]] = GET_MODE (x); return 1; } } /* If X is a SUBREG, we will likely be inserting the inner register in the table. If that register doesn't have an assigned quantity number at this point but does later, the insertion that we will be doing now will not be accessible because its hash code will have changed. So assign a quantity number now. */ else if (GET_CODE (x) == SUBREG && GET_CODE (SUBREG_REG (x)) == REG && ! REGNO_QTY_VALID_P (REGNO (SUBREG_REG (x)))) { insert_regs (SUBREG_REG (x), NULL_PTR, 0); mention_regs (SUBREG_REG (x)); return 1; } else return mention_regs (x);}/* Look in or update the hash table. *//* Put the element ELT on the list of free elements. */static voidfree_element (elt) struct table_elt *elt;{ elt->next_same_hash = free_element_chain; free_element_chain = elt;}/* Return an element that is free for use. */static struct table_elt *get_element (){ struct table_elt *elt = free_element_chain; if (elt) { free_element_chain = elt->next_same_hash; return elt; } n_elements_made++; return (struct table_elt *) oballoc (sizeof (struct table_elt));}/* Remove table element ELT from use in the table. HASH is its hash code, made using the HASH macro. It's an argument because often that is known in advance and we save much time not recomputing it. */static voidremove_from_table (elt, hash) register struct table_elt *elt; int hash;{ if (elt == 0) return; /* Mark this element as removed. See cse_insn. */ elt->first_same_value = 0; /* Remove the table element from its equivalence class. */ { register struct table_elt *prev = elt->prev_same_value; register struct table_elt *next = elt->next_same_value; if (next) next->prev_same_value = prev; if (prev) prev->next_same_value = next; else { register struct table_elt *newfirst = next; while (next) { next->first_same_value = newfirst; next = next->next_same_value; } } } /* Remove the table element from its hash bucket. */ { register struct table_elt *prev = elt->prev_same_hash; register struct table_elt *next = elt->next_same_hash; if (next) next->prev_same_hash = prev; if (prev) prev->next_same_hash = next; else if (table[hash] == elt) table[hash] = next; else { /* This entry is not in the proper hash bucket. This can happen when two classes were merged by `merge_equiv_classes'. Search for the hash bucket that it heads. This happens only very rarely, so the cost is acceptable. */ for (hash = 0; hash < NBUCKETS; hash++) if (table[hash] == elt) table[hash] = next; } } /* Remove the table element from its related-value circular chain. */ if (elt->related_value != 0 && elt->related_value != elt) { register struct table_elt *p = elt->related_value; while (p->related_value != elt) p = p->related_value; p->related_value = elt->related_value; if (p->related_value == p) p->related_value = 0; } free_element (elt);}/* Look up X in the hash table and return its table element, or 0 if X is not in the table. MODE is the machine-mode of X, or if X is an integer constant with VOIDmode then MODE is the mode with which X will be used. Here we are satisfied to find an expression whose tree structure looks like X. */static struct table_elt *lookup (x, hash, mode) rtx x; int hash; enum machine_mode mode;{ register struct table_elt *p; for (p = table[hash]; p; p = p->next_same_hash) if (mode == p->mode && ((x == p->exp && GET_CODE (x) == REG) || exp_equiv_p (x, p->exp, GET_CODE (x) != REG, 0))) return p; return 0;}/* Like `lookup' but don't care whether the table element uses invalid regs. Also ignore discrepancies in the machine mode of a register. */static struct table_elt *lookup_for_remove (x, hash, mode) rtx x; int hash; enum machine_mode mode;{ register struct table_elt *p; if (GET_CODE (x) == REG) { int regno = REGNO (x); /* Don't check the machine mode when comparing registers; invalidating (REG:SI 0) also invalidates (REG:DF 0). */ for (p = table[hash]; p; p = p->next_same_hash) if (GET_CODE (p->exp) == REG && REGNO (p->exp) == regno) return p; } else { for (p = table[hash]; p; p = p->next_same_hash) if (mode == p->mode && (x == p->exp || exp_equiv_p (x, p->exp, 0, 0))) return p; } return 0;}/* Look for an expression equivalent to X and with code CODE. If one is found, return that expression. */static rtxlookup_as_function (x, code) rtx x; enum rtx_code code;{ register struct table_elt *p = lookup (x, safe_hash (x, VOIDmode) % NBUCKETS, GET_MODE (x)); if (p == 0) return 0; for (p = p->first_same_value; p; p = p->next_same_value) { if (GET_CODE (p->exp) == code /* Make sure this is a valid entry in the table. */ && exp_equiv_p (p->exp, p->exp, 1, 0)) return p->exp; } return 0;}/* Insert X in the hash table, assuming HASH is its hash code and CLASSP is an element of the class it should go in (or 0 if a new class should be made). It is inserted at the proper position to keep the class in the order cheapest first. MODE is the machine-mode of X, or if X is an integer constant with VOIDmode then MODE is the mode with which X will be used. For elements of equal cheapness, the most recent one goes in front, except that the first element in the list remains first unless a cheaper element is added. The order of pseudo-registers does not matter, as canon_reg will be called to find the cheapest when a register is retrieved from the table. The in_memory field in the hash table element is set to 0. The caller must set it nonzero if appropriate. You should call insert_regs (X, CLASSP, MODIFY) before calling here, and if insert_regs returns a nonzero value you must then recompute its hash code before calling here. If necessary, update table showing constant values of quantities. */#define CHEAPER(X,Y) ((X)->cost < (Y)->cost)static struct table_elt *insert (x, classp, hash, mode) register rtx x; register struct table_elt *classp; int hash; enum machine_mode mode;{ register struct table_elt *elt; /* If X is a register and we haven't made a quantity for it, something is wrong. */ if (GET_CODE (x) == REG && ! REGNO_QTY_VALID_P (REGNO (x))) abort (); /* If X is a hard register, show it is being put in the table. */ if (GET_CODE (x) == REG && REGNO (x) < FIRST_PSEUDO_REGISTER) { int regno = REGNO (x); int endregno = regno + HARD_REGNO_NREGS (regno, GET_MODE (x)); int i; for (i = regno; i < endregno; i++) SET_HARD_REG_BIT (hard_regs_in_table, i); } /* Put an element for X into the right hash bucket. */ elt = get_element (); elt->exp = x; elt->cost = COST (x); elt->next_same_value = 0; elt->prev_same_value = 0; elt->next_same_hash = table[hash]; elt->prev_same_hash = 0; elt->related_value = 0; elt->in_memory = 0; elt->mode = mode; elt->is_const = (CONSTANT_P (x) /* GNU C++ takes advantage of this for `this' (and other const values). */ || (RTX_UNCHANGING_P (x) && GET_CODE (x) == REG && REGNO (x) >= FIRST_PSEUDO_REGISTER) || FIXED_BASE_PLUS_P (x)); if (table[hash]) table[hash]->prev_same_hash = elt; table[hash] = elt; /* Put it into the proper value-class. */ if (classp) { classp = classp->first_same_value; if (CHEAPER (elt, classp)) /* Insert at the head of the class */ { register struct table_elt *p; elt->next_same_value = classp; classp->prev_same_value = elt; elt->first_same_value = elt; for (p = classp; p; p = p->next_same_value) p->first_same_value = elt; } else { /* Insert not at head of the class. */ /* Put it after the last element cheaper than X. */ register struct table_elt *p, *next; for (p = classp; (next = p->next_same_value) && CHEAPER (next, elt); p = next); /* Put it after P and before NEXT. */ elt->next_same_value = next; if (next) next->prev_same_value = elt; elt->prev_same_value = p; p->next_same_value = elt; elt->first_same_value = classp; } } else elt->first_same_value = elt; /* If this is a constant being set equivalent to a register or a register being set equivalent to a constant, note the constant equivalence. If this is a constant, it cannot be equivalent to a different constant, and a constant is the only thing that can be cheaper than a register. So we know the register is the head of the class (before the constant was inserted). If this is a register that is not already known equivalent to a constant, we must check the entire class. If this is a register that is already known equivalent to an insn, update `qty_const_insn' to show that `this_insn' is the latest insn making that quantity equivalent to the constant. */ if (elt->is_const && classp && GET_CODE (classp->exp) == REG) { qty_const[reg_qty[REGNO (classp->exp)]] = gen_lowpart_if_possible (qty_mode[reg_qty[REGNO (classp->exp)]], x); qty_const_insn[reg_qty[REGNO (classp->exp)]] = this_insn; } else if (GET_CODE (x) == REG && classp && ! qty_const[reg_qty[REGNO (x)]]) { register struct table_elt *p; for (p = classp; p != 0; p = p->next_same_value) { if (p->is_const) { qty_const[reg_qty[REGNO (x)]] = gen_lowpart_if_possible (GET_MODE (x), p->exp); qty_const_insn[reg_qty[REGNO (x)]] = this_insn; break; } } } else if (GET_CODE (x) == REG && qty_const[reg_qty[REGNO (x)]] && GET_MODE (x) == qty_mode[reg_qty[REGNO (x)]]) qty_const_insn[reg_qty[REGNO (x)]] = this_insn; /* If this is a constant with symbolic value, and it has a term with an explicit integer value, link it up with related expressions. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -