static bool replace_oldest_value_mem (rtx x, rtx insn, struct value_data *vd) { enum reg_class cl; if (DEBUG_INSN_P (insn)) cl = ALL_REGS; else cl = base_reg_class (GET_MODE (x), MEM_ADDR_SPACE (x), MEM, SCRATCH); return replace_oldest_value_addr (&XEXP (x, 0), cl, GET_MODE (x), MEM_ADDR_SPACE (x), insn, vd); }
static void recompute_gain_for_pattern_seq (pattern_seq pseq) { matching_seq mseq; rtx x; int i; int hascall; HARD_REG_SET linkregs; /* Initialize data. */ SET_HARD_REG_SET (linkregs); pseq->link_reg = NULL_RTX; pseq->abstracted_length = 0; pseq->gain = -(seq_call_cost - seq_jump_cost + seq_return_cost); /* Determine ABSTRACTED_LENGTH and COST for matching sequences of PSEQ. ABSTRACTED_LENGTH may be less than MATCHING_LENGTH if sequences in the same block overlap. */ for (mseq = pseq->matching_seqs; mseq; mseq = mseq->next_matching_seq) { /* Determine ABSTRACTED_LENGTH. */ if (mseq->next_matching_seq) mseq->abstracted_length = (int)(mseq->next_matching_seq->idx - mseq->idx); else mseq->abstracted_length = mseq->matching_length; if (mseq->abstracted_length > mseq->matching_length) mseq->abstracted_length = mseq->matching_length; /* Compute the cost of sequence. */ RECOMPUTE_COST (mseq); /* If COST is big enough registers live in this matching sequence should not be used as a link register. Also set ABSTRACTED_LENGTH of PSEQ. */ if (mseq->cost > seq_call_cost) { clear_regs_live_in_seq (&linkregs, mseq->insn, mseq->abstracted_length); if (mseq->abstracted_length > pseq->abstracted_length) pseq->abstracted_length = mseq->abstracted_length; } } /* Modify ABSTRACTED_LENGTH of PSEQ if pattern sequence overlaps with one of the matching sequences. */ for (mseq = pseq->matching_seqs; mseq; mseq = mseq->next_matching_seq) { x = pseq->insn; for (i = 0; (i < pseq->abstracted_length) && (x != mseq->insn); i++) x = prev_insn_in_block (x); pseq->abstracted_length = i; } /* Compute the cost of pattern sequence. */ RECOMPUTE_COST (pseq); /* No gain if COST is too small. */ if (pseq->cost <= seq_call_cost) { pseq->gain = -1; return; } /* Ensure that no matching sequence is longer than the pattern sequence. */ for (mseq = pseq->matching_seqs; mseq; mseq = mseq->next_matching_seq) { if (mseq->abstracted_length > pseq->abstracted_length) { mseq->abstracted_length = pseq->abstracted_length; RECOMPUTE_COST (mseq); } /* Once the length is stabilizing the gain can be calculated. */ if (mseq->cost > seq_call_cost) pseq->gain += mseq->cost - seq_call_cost; } /* No need to do further work if there is no gain. */ if (pseq->gain <= 0) return; /* Should not use registers live in the pattern sequence as link register. */ clear_regs_live_in_seq (&linkregs, pseq->insn, pseq->abstracted_length); /* Determine whether pattern sequence contains a call_insn. */ hascall = 0; x = pseq->insn; for (i = 0; i < pseq->abstracted_length; i++) { if (CALL_P (x)) { hascall = 1; break; } x = prev_insn_in_block (x); } /* Should not use a register as a link register if - it is a fixed register, or - the sequence contains a call insn and the register is a call used register, or - the register needs to be saved if used in a function but was not used before (since saving it can invalidate already computed frame pointer offsets), or - the register cannot be used as a base register. */ for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) if (fixed_regs[i] #ifdef REGNO_OK_FOR_INDIRECT_JUMP_P || (!REGNO_OK_FOR_INDIRECT_JUMP_P (i, Pmode)) #else || (!ok_for_base_p_1 (i, Pmode, MEM, SCRATCH)) || (!reg_class_subset_p (REGNO_REG_CLASS (i), base_reg_class (VOIDmode, MEM, SCRATCH))) #endif || (hascall && call_used_regs[i]) || (!call_used_regs[i] && !df_regs_ever_live_p (i))) CLEAR_HARD_REG_BIT (linkregs, i); /* Find an appropriate register to be used as the link register. */ for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) if (TEST_HARD_REG_BIT (linkregs, i)) { pseq->link_reg = gen_rtx_REG (Pmode, i); break; } /* Abstraction is not possible if no link register is available, so set gain to 0. */ if (!pseq->link_reg) pseq->gain = 0; }
static bool replace_oldest_value_addr (rtx *loc, enum reg_class cl, enum machine_mode mode, addr_space_t as, rtx insn, struct value_data *vd) { rtx x = *loc; RTX_CODE code = GET_CODE (x); const char *fmt; int i, j; bool changed = false; switch (code) { case PLUS: if (DEBUG_INSN_P (insn)) break; { rtx orig_op0 = XEXP (x, 0); rtx orig_op1 = XEXP (x, 1); RTX_CODE code0 = GET_CODE (orig_op0); RTX_CODE code1 = GET_CODE (orig_op1); rtx op0 = orig_op0; rtx op1 = orig_op1; rtx *locI = NULL; rtx *locB = NULL; enum rtx_code index_code = SCRATCH; if (GET_CODE (op0) == SUBREG) { op0 = SUBREG_REG (op0); code0 = GET_CODE (op0); } if (GET_CODE (op1) == SUBREG) { op1 = SUBREG_REG (op1); code1 = GET_CODE (op1); } if (code0 == MULT || code0 == SIGN_EXTEND || code0 == TRUNCATE || code0 == ZERO_EXTEND || code1 == MEM) { locI = &XEXP (x, 0); locB = &XEXP (x, 1); index_code = GET_CODE (*locI); } else if (code1 == MULT || code1 == SIGN_EXTEND || code1 == TRUNCATE || code1 == ZERO_EXTEND || code0 == MEM) { locI = &XEXP (x, 1); locB = &XEXP (x, 0); index_code = GET_CODE (*locI); } else if (code0 == CONST_INT || code0 == CONST || code0 == SYMBOL_REF || code0 == LABEL_REF) { locB = &XEXP (x, 1); index_code = GET_CODE (XEXP (x, 0)); } else if (code1 == CONST_INT || code1 == CONST || code1 == SYMBOL_REF || code1 == LABEL_REF) { locB = &XEXP (x, 0); index_code = GET_CODE (XEXP (x, 1)); } else if (code0 == REG && code1 == REG) { int index_op; unsigned regno0 = REGNO (op0), regno1 = REGNO (op1); if (REGNO_OK_FOR_INDEX_P (regno1) && regno_ok_for_base_p (regno0, mode, as, PLUS, REG)) index_op = 1; else if (REGNO_OK_FOR_INDEX_P (regno0) && regno_ok_for_base_p (regno1, mode, as, PLUS, REG)) index_op = 0; else if (regno_ok_for_base_p (regno0, mode, as, PLUS, REG) || REGNO_OK_FOR_INDEX_P (regno1)) index_op = 1; else if (regno_ok_for_base_p (regno1, mode, as, PLUS, REG)) index_op = 0; else index_op = 1; locI = &XEXP (x, index_op); locB = &XEXP (x, !index_op); index_code = GET_CODE (*locI); } else if (code0 == REG) { locI = &XEXP (x, 0); locB = &XEXP (x, 1); index_code = GET_CODE (*locI); } else if (code1 == REG) { locI = &XEXP (x, 1); locB = &XEXP (x, 0); index_code = GET_CODE (*locI); } if (locI) changed |= replace_oldest_value_addr (locI, INDEX_REG_CLASS, mode, as, insn, vd); if (locB) changed |= replace_oldest_value_addr (locB, base_reg_class (mode, as, PLUS, index_code), mode, as, insn, vd); return changed; } case POST_INC: case POST_DEC: case POST_MODIFY: case PRE_INC: case PRE_DEC: case PRE_MODIFY: return false; case MEM: return replace_oldest_value_mem (x, insn, vd); case REG: return replace_oldest_value_reg (loc, cl, insn, vd); default: break; } fmt = GET_RTX_FORMAT (code); for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) { if (fmt[i] == 'e') changed |= replace_oldest_value_addr (&XEXP (x, i), cl, mode, as, insn, vd); else if (fmt[i] == 'E') for (j = XVECLEN (x, i) - 1; j >= 0; j--) changed |= replace_oldest_value_addr (&XVECEXP (x, i, j), cl, mode, as, insn, vd); } return changed; }