/* If INSN can not be used for rematerialization, return negative value. If INSN can be considered as a candidate for rematerialization, return value which is the operand number of the pseudo for which the insn can be used for rematerialization. Here we consider the insns without any memory, spilled pseudo (except for the rematerialization pseudo), or dying or unused regs. */ static int operand_to_remat (rtx_insn *insn) { lra_insn_recog_data_t id = lra_get_insn_recog_data (insn); struct lra_static_insn_data *static_id = id->insn_static_data; struct lra_insn_reg *reg, *found_reg = NULL; /* First find a pseudo which can be rematerialized. */ for (reg = id->regs; reg != NULL; reg = reg->next) /* True FRAME_POINTER_NEEDED might be because we can not follow changing sp offsets, e.g. alloca is used. If the insn contains stack pointer in such case, we can not rematerialize it as we can not know sp offset at a rematerialization place. */ if (reg->regno == STACK_POINTER_REGNUM && frame_pointer_needed) return -1; else if (reg->type == OP_OUT && ! reg->subreg_p && find_regno_note (insn, REG_UNUSED, reg->regno) == NULL) { /* We permits only one spilled reg. */ if (found_reg != NULL) return -1; found_reg = reg; } if (found_reg == NULL) return -1; if (found_reg->regno < FIRST_PSEUDO_REGISTER) return -1; if (bad_for_rematerialization_p (PATTERN (insn))) return -1; /* Check the other regs are not spilled. */ for (reg = id->regs; reg != NULL; reg = reg->next) if (found_reg == reg) continue; else if (reg->type == OP_INOUT) return -1; else if (reg->regno >= FIRST_PSEUDO_REGISTER && reg_renumber[reg->regno] < 0) /* Another spilled reg. */ return -1; else if (reg->type == OP_IN) { if (find_regno_note (insn, REG_DEAD, reg->regno) != NULL) /* We don't want to make live ranges longer. */ return -1; /* Check that there is no output reg as the input one. */ for (struct lra_insn_reg *reg2 = id->regs; reg2 != NULL; reg2 = reg2->next) if (reg2->type == OP_OUT && reg->regno == reg2->regno) return -1; } /* Find the rematerialization operand. */ int nop = static_id->n_operands; for (int i = 0; i < nop; i++) if (REG_P (*id->operand_loc[i]) && (int) REGNO (*id->operand_loc[i]) == found_reg->regno) return i; return -1; }
static bool try_merge (void) { enum gen_form gen_form; rtx mem = *mem_insn.mem_loc; rtx inc_reg = inc_insn.form == FORM_POST_ADD ? inc_insn.reg_res : mem_insn.reg0; /* The width of the mem being accessed. */ int size = GET_MODE_SIZE (GET_MODE (mem)); rtx last_insn = NULL; enum machine_mode reg_mode = GET_MODE (inc_reg); switch (inc_insn.form) { case FORM_PRE_ADD: case FORM_PRE_INC: last_insn = mem_insn.insn; break; case FORM_POST_INC: case FORM_POST_ADD: last_insn = inc_insn.insn; break; case FORM_last: default: gcc_unreachable (); } /* Cannot handle auto inc of the stack. */ if (inc_reg == stack_pointer_rtx) { if (dump_file) fprintf (dump_file, "cannot inc stack %d failure\n", REGNO (inc_reg)); return false; } /* Look to see if the inc register is dead after the memory reference. If it is, do not do the combination. */ if (find_regno_note (last_insn, REG_DEAD, REGNO (inc_reg))) { if (dump_file) fprintf (dump_file, "dead failure %d\n", REGNO (inc_reg)); return false; } mem_insn.reg1_state = (mem_insn.reg1_is_const) ? set_inc_state (mem_insn.reg1_val, size) : INC_REG; inc_insn.reg1_state = (inc_insn.reg1_is_const) ? set_inc_state (inc_insn.reg1_val, size) : INC_REG; /* Now get the form that we are generating. */ gen_form = decision_table [inc_insn.reg1_state][mem_insn.reg1_state][inc_insn.form]; if (dbg_cnt (auto_inc_dec) == false) return false; switch (gen_form) { default: case NOTHING: return false; case SIMPLE_PRE_INC: /* ++size */ if (dump_file) fprintf (dump_file, "trying SIMPLE_PRE_INC\n"); return attempt_change (gen_rtx_PRE_INC (reg_mode, inc_reg), inc_reg); break; case SIMPLE_POST_INC: /* size++ */ if (dump_file) fprintf (dump_file, "trying SIMPLE_POST_INC\n"); return attempt_change (gen_rtx_POST_INC (reg_mode, inc_reg), inc_reg); break; case SIMPLE_PRE_DEC: /* --size */ if (dump_file) fprintf (dump_file, "trying SIMPLE_PRE_DEC\n"); return attempt_change (gen_rtx_PRE_DEC (reg_mode, inc_reg), inc_reg); break; case SIMPLE_POST_DEC: /* size-- */ if (dump_file) fprintf (dump_file, "trying SIMPLE_POST_DEC\n"); return attempt_change (gen_rtx_POST_DEC (reg_mode, inc_reg), inc_reg); break; case DISP_PRE: /* ++con */ if (dump_file) fprintf (dump_file, "trying DISP_PRE\n"); return attempt_change (gen_rtx_PRE_MODIFY (reg_mode, inc_reg, gen_rtx_PLUS (reg_mode, inc_reg, inc_insn.reg1)), inc_reg); break; case DISP_POST: /* con++ */ if (dump_file) fprintf (dump_file, "trying POST_DISP\n"); return attempt_change (gen_rtx_POST_MODIFY (reg_mode, inc_reg, gen_rtx_PLUS (reg_mode, inc_reg, inc_insn.reg1)), inc_reg); break; case REG_PRE: /* ++reg */ if (dump_file) fprintf (dump_file, "trying PRE_REG\n"); return attempt_change (gen_rtx_PRE_MODIFY (reg_mode, inc_reg, gen_rtx_PLUS (reg_mode, inc_reg, inc_insn.reg1)), inc_reg); break; case REG_POST: /* reg++ */ if (dump_file) fprintf (dump_file, "trying POST_REG\n"); return attempt_change (gen_rtx_POST_MODIFY (reg_mode, inc_reg, gen_rtx_PLUS (reg_mode, inc_reg, inc_insn.reg1)), inc_reg); break; } }
/* If INSN can not be used for rematerialization, return negative value. If INSN can be considered as a candidate for rematerialization, return value which is the operand number of the pseudo for which the insn can be used for rematerialization. Here we consider the insns without any memory, spilled pseudo (except for the rematerialization pseudo), or dying or unused regs. */ static int operand_to_remat (rtx_insn *insn) { lra_insn_recog_data_t id = lra_get_insn_recog_data (insn); struct lra_static_insn_data *static_id = id->insn_static_data; struct lra_insn_reg *reg, *found_reg = NULL; /* Don't rematerialize insns which can change PC. */ if (JUMP_P (insn) || CALL_P (insn)) return -1; /* First find a pseudo which can be rematerialized. */ for (reg = id->regs; reg != NULL; reg = reg->next) /* True FRAME_POINTER_NEEDED might be because we can not follow changing sp offsets, e.g. alloca is used. If the insn contains stack pointer in such case, we can not rematerialize it as we can not know sp offset at a rematerialization place. */ if (reg->regno == STACK_POINTER_REGNUM && frame_pointer_needed) return -1; else if (reg->type == OP_OUT && ! reg->subreg_p && find_regno_note (insn, REG_UNUSED, reg->regno) == NULL) { /* We permits only one spilled reg. */ if (found_reg != NULL) return -1; found_reg = reg; } /* IRA calculates conflicts separately for subregs of two words pseudo. Even if the pseudo lives, e.g. one its subreg can be used lately, another subreg hard register can be already used for something else. In such case, it is not safe to rematerialize the insn. */ else if (reg->type == OP_IN && reg->subreg_p && reg->regno >= FIRST_PSEUDO_REGISTER && (GET_MODE_SIZE (PSEUDO_REGNO_MODE (reg->regno)) == 2 * UNITS_PER_WORD)) return -1; if (found_reg == NULL) return -1; if (found_reg->regno < FIRST_PSEUDO_REGISTER) return -1; if (bad_for_rematerialization_p (PATTERN (insn))) return -1; /* Check the other regs are not spilled. */ for (reg = id->regs; reg != NULL; reg = reg->next) if (found_reg == reg) continue; else if (reg->type == OP_INOUT) return -1; else if (reg->regno >= FIRST_PSEUDO_REGISTER && reg_renumber[reg->regno] < 0) /* Another spilled reg. */ return -1; else if (reg->type == OP_IN) { if (find_regno_note (insn, REG_DEAD, reg->regno) != NULL) /* We don't want to make live ranges longer. */ return -1; /* Check that there is no output reg as the input one. */ for (struct lra_insn_reg *reg2 = id->regs; reg2 != NULL; reg2 = reg2->next) if (reg2->type == OP_OUT && reg->regno == reg2->regno) return -1; if (reg->regno < FIRST_PSEUDO_REGISTER) for (struct lra_insn_reg *reg2 = static_id->hard_regs; reg2 != NULL; reg2 = reg2->next) if (reg2->type == OP_OUT && reg->regno <= reg2->regno && (reg2->regno < (reg->regno + hard_regno_nregs[reg->regno][reg->biggest_mode]))) return -1; } /* Find the rematerialization operand. */ int nop = static_id->n_operands; for (int i = 0; i < nop; i++) if (REG_P (*id->operand_loc[i]) && (int) REGNO (*id->operand_loc[i]) == found_reg->regno) return i; return -1; }