-
- /* Initialize last_label_ruid, reload_combine_ruid and reg_state. */
- last_label_ruid = reload_combine_ruid = 0;
- for (r = 0; r < FIRST_PSEUDO_REGISTER; r++)
- {
- reg_state[r].store_ruid = reload_combine_ruid;
- if (fixed_regs[r])
- reg_state[r].use_index = -1;
- else
- reg_state[r].use_index = RELOAD_COMBINE_MAX_USES;
- }
-
- for (insn = get_last_insn (); insn; insn = PREV_INSN (insn))
- {
- rtx note;
-
- /* We cannot do our optimization across labels. Invalidating all the use
- information we have would be costly, so we just note where the label
- is and then later disable any optimization that would cross it. */
- if (GET_CODE (insn) == CODE_LABEL)
- last_label_ruid = reload_combine_ruid;
- else if (GET_CODE (insn) == BARRIER)
- for (r = 0; r < FIRST_PSEUDO_REGISTER; r++)
- if (! fixed_regs[r])
- reg_state[r].use_index = RELOAD_COMBINE_MAX_USES;
-
- if (! INSN_P (insn))
- continue;
-
- reload_combine_ruid++;
-
- /* Look for (set (REGX) (CONST_INT))
- (set (REGX) (PLUS (REGX) (REGY)))
- ...
- ... (MEM (REGX)) ...
- and convert it to
- (set (REGZ) (CONST_INT))
- ...
- ... (MEM (PLUS (REGZ) (REGY)))... .
-
- First, check that we have (set (REGX) (PLUS (REGX) (REGY)))
- and that we know all uses of REGX before it dies. */
- set = single_set (insn);
- if (set != NULL_RTX
- && GET_CODE (SET_DEST (set)) == REG
- && (HARD_REGNO_NREGS (REGNO (SET_DEST (set)),
- GET_MODE (SET_DEST (set)))
- == 1)
- && GET_CODE (SET_SRC (set)) == PLUS
- && GET_CODE (XEXP (SET_SRC (set), 1)) == REG
- && rtx_equal_p (XEXP (SET_SRC (set), 0), SET_DEST (set))
- && last_label_ruid < reg_state[REGNO (SET_DEST (set))].use_ruid)
- {
- rtx reg = SET_DEST (set);
- rtx plus = SET_SRC (set);
- rtx base = XEXP (plus, 1);
- rtx prev = prev_nonnote_insn (insn);
- rtx prev_set = prev ? single_set (prev) : NULL_RTX;
- unsigned int regno = REGNO (reg);
- rtx const_reg = NULL_RTX;
- rtx reg_sum = NULL_RTX;
-
- /* Now, we need an index register.
- We'll set index_reg to this index register, const_reg to the
- register that is to be loaded with the constant
- (denoted as REGZ in the substitution illustration above),
- and reg_sum to the register-register that we want to use to
- substitute uses of REG (typically in MEMs) with.
- First check REG and BASE for being index registers;
- we can use them even if they are not dead. */
- if (TEST_HARD_REG_BIT (reg_class_contents[INDEX_REG_CLASS], regno)
- || TEST_HARD_REG_BIT (reg_class_contents[INDEX_REG_CLASS],
- REGNO (base)))
- {
- const_reg = reg;
- reg_sum = plus;
- }
- else
- {
- /* Otherwise, look for a free index register. Since we have
- checked above that neiter REG nor BASE are index registers,
- if we find anything at all, it will be different from these
- two registers. */
- for (i = first_index_reg; i <= last_index_reg; i++)
- {
- if (TEST_HARD_REG_BIT (reg_class_contents[INDEX_REG_CLASS],
- i)
- && reg_state[i].use_index == RELOAD_COMBINE_MAX_USES
- && reg_state[i].store_ruid <= reg_state[regno].use_ruid
- && HARD_REGNO_NREGS (i, GET_MODE (reg)) == 1)
- {
- rtx index_reg = gen_rtx_REG (GET_MODE (reg), i);
-
- const_reg = index_reg;
- reg_sum = gen_rtx_PLUS (GET_MODE (reg), index_reg, base);
- break;
- }
- }
- }
-
- /* Check that PREV_SET is indeed (set (REGX) (CONST_INT)) and that
- (REGY), i.e. BASE, is not clobbered before the last use we'll
- create. */
- if (prev_set != 0
- && GET_CODE (SET_SRC (prev_set)) == CONST_INT
- && rtx_equal_p (SET_DEST (prev_set), reg)
- && reg_state[regno].use_index >= 0
- && (reg_state[REGNO (base)].store_ruid
- <= reg_state[regno].use_ruid)
- && reg_sum != 0)
- {
- int i;
-
- /* Change destination register and, if necessary, the
- constant value in PREV, the constant loading instruction. */
- validate_change (prev, &SET_DEST (prev_set), const_reg, 1);
- if (reg_state[regno].offset != const0_rtx)
- validate_change (prev,
- &SET_SRC (prev_set),
- GEN_INT (INTVAL (SET_SRC (prev_set))
- + INTVAL (reg_state[regno].offset)),
- 1);
-
- /* Now for every use of REG that we have recorded, replace REG
- with REG_SUM. */
- for (i = reg_state[regno].use_index;
- i < RELOAD_COMBINE_MAX_USES; i++)
- validate_change (reg_state[regno].reg_use[i].insn,
- reg_state[regno].reg_use[i].usep,
- /* Each change must have its own
- replacement. */
- copy_rtx (reg_sum), 1);
-
- if (apply_change_group ())
- {
- rtx *np;
-
- /* Delete the reg-reg addition. */
- delete_insn (insn);
-
- if (reg_state[regno].offset != const0_rtx)
- /* Previous REG_EQUIV / REG_EQUAL notes for PREV
- are now invalid. */
- for (np = ®_NOTES (prev); *np;)
- {
- if (REG_NOTE_KIND (*np) == REG_EQUAL
- || REG_NOTE_KIND (*np) == REG_EQUIV)
- *np = XEXP (*np, 1);
- else
- np = &XEXP (*np, 1);
- }
-
- reg_state[regno].use_index = RELOAD_COMBINE_MAX_USES;
- reg_state[REGNO (const_reg)].store_ruid
- = reload_combine_ruid;
- continue;
- }
- }
- }
-
- note_stores (PATTERN (insn), reload_combine_note_store, NULL);
-
- if (GET_CODE (insn) == CALL_INSN)
- {
- rtx link;
-
- for (r = 0; r < FIRST_PSEUDO_REGISTER; r++)
- if (call_used_regs[r])
- {
- reg_state[r].use_index = RELOAD_COMBINE_MAX_USES;
- reg_state[r].store_ruid = reload_combine_ruid;
- }
-
- for (link = CALL_INSN_FUNCTION_USAGE (insn); link;
- link = XEXP (link, 1))
- {
- rtx usage_rtx = XEXP (XEXP (link, 0), 0);
- if (GET_CODE (usage_rtx) == REG)
- {
- unsigned int i;
- unsigned int start_reg = REGNO (usage_rtx);
- unsigned int num_regs =
- HARD_REGNO_NREGS (start_reg, GET_MODE (usage_rtx));
- unsigned int end_reg = start_reg + num_regs - 1;
- for (i = start_reg; i <= end_reg; i++)
- if (GET_CODE (XEXP (link, 0)) == CLOBBER)
- {
- reg_state[i].use_index = RELOAD_COMBINE_MAX_USES;
- reg_state[i].store_ruid = reload_combine_ruid;
- }
- else
- reg_state[i].use_index = -1;
- }
- }
-
- }
- else if (GET_CODE (insn) == JUMP_INSN
- && GET_CODE (PATTERN (insn)) != RETURN)
- {
- /* Non-spill registers might be used at the call destination in
- some unknown fashion, so we have to mark the unknown use. */
- HARD_REG_SET *live;
-
- if ((condjump_p (insn) || condjump_in_parallel_p (insn))
- && JUMP_LABEL (insn))
- live = &LABEL_LIVE (JUMP_LABEL (insn));
- else
- live = &ever_live_at_start;
-
- for (i = FIRST_PSEUDO_REGISTER - 1; i >= 0; --i)
- if (TEST_HARD_REG_BIT (*live, i))
- reg_state[i].use_index = -1;
- }
-
- reload_combine_note_use (&PATTERN (insn), insn);
- for (note = REG_NOTES (insn); note; note = XEXP (note, 1))
- {
- if (REG_NOTE_KIND (note) == REG_INC
- && GET_CODE (XEXP (note, 0)) == REG)
- {
- int regno = REGNO (XEXP (note, 0));
-
- reg_state[regno].store_ruid = reload_combine_ruid;
- reg_state[regno].use_index = -1;
- }
- }
- }
-
- free (label_live);
-}
-
-/* Check if DST is a register or a subreg of a register; if it is,
- update reg_state[regno].store_ruid and reg_state[regno].use_index
- accordingly. Called via note_stores from reload_combine. */
-
-static void
-reload_combine_note_store (dst, set, data)
- rtx dst, set;
- void *data ATTRIBUTE_UNUSED;
-{
- int regno = 0;
- int i;
- enum machine_mode mode = GET_MODE (dst);
-
- if (GET_CODE (dst) == SUBREG)
- {
- regno = subreg_regno_offset (REGNO (SUBREG_REG (dst)),
- GET_MODE (SUBREG_REG (dst)),
- SUBREG_BYTE (dst),
- GET_MODE (dst));
- dst = SUBREG_REG (dst);
- }
- if (GET_CODE (dst) != REG)
- return;
- regno += REGNO (dst);
-
- /* note_stores might have stripped a STRICT_LOW_PART, so we have to be
- careful with registers / register parts that are not full words.
-
- Similarly for ZERO_EXTRACT and SIGN_EXTRACT. */
- if (GET_CODE (set) != SET
- || GET_CODE (SET_DEST (set)) == ZERO_EXTRACT
- || GET_CODE (SET_DEST (set)) == SIGN_EXTRACT
- || GET_CODE (SET_DEST (set)) == STRICT_LOW_PART)
- {
- for (i = HARD_REGNO_NREGS (regno, mode) - 1 + regno; i >= regno; i--)
- {
- reg_state[i].use_index = -1;
- reg_state[i].store_ruid = reload_combine_ruid;
- }
- }
- else
- {
- for (i = HARD_REGNO_NREGS (regno, mode) - 1 + regno; i >= regno; i--)
- {
- reg_state[i].store_ruid = reload_combine_ruid;
- reg_state[i].use_index = RELOAD_COMBINE_MAX_USES;
- }
- }
-}
-
-/* XP points to a piece of rtl that has to be checked for any uses of
- registers.
- *XP is the pattern of INSN, or a part of it.
- Called from reload_combine, and recursively by itself. */
-static void
-reload_combine_note_use (xp, insn)
- rtx *xp, insn;
-{
- rtx x = *xp;
- enum rtx_code code = x->code;
- const char *fmt;
- int i, j;
- rtx offset = const0_rtx; /* For the REG case below. */
-
- switch (code)
- {
- case SET:
- if (GET_CODE (SET_DEST (x)) == REG)
- {
- reload_combine_note_use (&SET_SRC (x), insn);
- return;
- }
- break;
-
- case USE:
- /* If this is the USE of a return value, we can't change it. */
- if (GET_CODE (XEXP (x, 0)) == REG && REG_FUNCTION_VALUE_P (XEXP (x, 0)))
- {
- /* Mark the return register as used in an unknown fashion. */
- rtx reg = XEXP (x, 0);
- int regno = REGNO (reg);
- int nregs = HARD_REGNO_NREGS (regno, GET_MODE (reg));
-
- while (--nregs >= 0)
- reg_state[regno + nregs].use_index = -1;
- return;
- }
- break;
-
- case CLOBBER:
- if (GET_CODE (SET_DEST (x)) == REG)
- {
- /* No spurious CLOBBERs of pseudo registers may remain. */
- if (REGNO (SET_DEST (x)) >= FIRST_PSEUDO_REGISTER)
- abort ();
- return;
- }
- break;
-
- case PLUS:
- /* We are interested in (plus (reg) (const_int)) . */
- if (GET_CODE (XEXP (x, 0)) != REG
- || GET_CODE (XEXP (x, 1)) != CONST_INT)
- break;
- offset = XEXP (x, 1);
- x = XEXP (x, 0);
- /* Fall through. */
- case REG:
- {
- int regno = REGNO (x);
- int use_index;
- int nregs;
-
- /* No spurious USEs of pseudo registers may remain. */
- if (regno >= FIRST_PSEUDO_REGISTER)
- abort ();
-
- nregs = HARD_REGNO_NREGS (regno, GET_MODE (x));
-
- /* We can't substitute into multi-hard-reg uses. */
- if (nregs > 1)
- {
- while (--nregs >= 0)
- reg_state[regno + nregs].use_index = -1;
- return;
- }
-
- /* If this register is already used in some unknown fashion, we
- can't do anything.
- If we decrement the index from zero to -1, we can't store more
- uses, so this register becomes used in an unknown fashion. */
- use_index = --reg_state[regno].use_index;
- if (use_index < 0)
- return;
-
- if (use_index != RELOAD_COMBINE_MAX_USES - 1)
- {
- /* We have found another use for a register that is already
- used later. Check if the offsets match; if not, mark the
- register as used in an unknown fashion. */
- if (! rtx_equal_p (offset, reg_state[regno].offset))
- {
- reg_state[regno].use_index = -1;
- return;
- }
- }
- else
- {
- /* This is the first use of this register we have seen since we
- marked it as dead. */
- reg_state[regno].offset = offset;
- reg_state[regno].use_ruid = reload_combine_ruid;
- }
- reg_state[regno].reg_use[use_index].insn = insn;
- reg_state[regno].reg_use[use_index].usep = xp;
- return;
- }
-
- default:
- break;
- }
-
- /* Recursively process the components of X. */
- fmt = GET_RTX_FORMAT (code);
- for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
- {
- if (fmt[i] == 'e')
- reload_combine_note_use (&XEXP (x, i), insn);
- else if (fmt[i] == 'E')
- {
- for (j = XVECLEN (x, i) - 1; j >= 0; j--)
- reload_combine_note_use (&XVECEXP (x, i, j), insn);
- }
- }
-}
-\f
-/* See if we can reduce the cost of a constant by replacing a move
- with an add. We track situations in which a register is set to a
- constant or to a register plus a constant. */
-/* We cannot do our optimization across labels. Invalidating all the
- information about register contents we have would be costly, so we
- use move2add_last_label_luid to note where the label is and then
- later disable any optimization that would cross it.
- reg_offset[n] / reg_base_reg[n] / reg_mode[n] are only valid if
- reg_set_luid[n] is greater than last_label_luid[n] . */
-static int reg_set_luid[FIRST_PSEUDO_REGISTER];
-
-/* If reg_base_reg[n] is negative, register n has been set to
- reg_offset[n] in mode reg_mode[n] .
- If reg_base_reg[n] is non-negative, register n has been set to the
- sum of reg_offset[n] and the value of register reg_base_reg[n]
- before reg_set_luid[n], calculated in mode reg_mode[n] . */
-static HOST_WIDE_INT reg_offset[FIRST_PSEUDO_REGISTER];
-static int reg_base_reg[FIRST_PSEUDO_REGISTER];
-static enum machine_mode reg_mode[FIRST_PSEUDO_REGISTER];
-
-/* move2add_luid is linearily increased while scanning the instructions
- from first to last. It is used to set reg_set_luid in
- reload_cse_move2add and move2add_note_store. */
-static int move2add_luid;
-
-/* move2add_last_label_luid is set whenever a label is found. Labels
- invalidate all previously collected reg_offset data. */
-static int move2add_last_label_luid;
-
-/* Generate a CONST_INT and force it in the range of MODE. */
-
-static HOST_WIDE_INT
-sext_for_mode (mode, value)
- enum machine_mode mode;
- HOST_WIDE_INT value;
-{
- HOST_WIDE_INT cval = value & GET_MODE_MASK (mode);
- int width = GET_MODE_BITSIZE (mode);
-
- /* If MODE is narrower than HOST_WIDE_INT and CVAL is a negative number,
- sign extend it. */
- if (width > 0 && width < HOST_BITS_PER_WIDE_INT
- && (cval & ((HOST_WIDE_INT) 1 << (width - 1))) != 0)
- cval |= (HOST_WIDE_INT) -1 << width;
-
- return cval;
-}
-
-/* ??? We don't know how zero / sign extension is handled, hence we
- can't go from a narrower to a wider mode. */
-#define MODES_OK_FOR_MOVE2ADD(OUTMODE, INMODE) \
- (GET_MODE_SIZE (OUTMODE) == GET_MODE_SIZE (INMODE) \
- || (GET_MODE_SIZE (OUTMODE) <= GET_MODE_SIZE (INMODE) \
- && TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (OUTMODE), \
- GET_MODE_BITSIZE (INMODE))))
-
-static void
-reload_cse_move2add (first)
- rtx first;
-{
- int i;
- rtx insn;
-
- for (i = FIRST_PSEUDO_REGISTER - 1; i >= 0; i--)
- reg_set_luid[i] = 0;
-
- move2add_last_label_luid = 0;
- move2add_luid = 2;
- for (insn = first; insn; insn = NEXT_INSN (insn), move2add_luid++)
- {
- rtx pat, note;
-
- if (GET_CODE (insn) == CODE_LABEL)
- {
- move2add_last_label_luid = move2add_luid;
- /* We're going to increment move2add_luid twice after a
- label, so that we can use move2add_last_label_luid + 1 as
- the luid for constants. */
- move2add_luid++;
- continue;
- }
- if (! INSN_P (insn))
- continue;
- pat = PATTERN (insn);
- /* For simplicity, we only perform this optimization on
- straightforward SETs. */
- if (GET_CODE (pat) == SET
- && GET_CODE (SET_DEST (pat)) == REG)
- {
- rtx reg = SET_DEST (pat);
- int regno = REGNO (reg);
- rtx src = SET_SRC (pat);
-
- /* Check if we have valid information on the contents of this
- register in the mode of REG. */
- if (reg_set_luid[regno] > move2add_last_label_luid
- && MODES_OK_FOR_MOVE2ADD (GET_MODE (reg), reg_mode[regno]))
- {
- /* Try to transform (set (REGX) (CONST_INT A))
- ...
- (set (REGX) (CONST_INT B))
- to
- (set (REGX) (CONST_INT A))
- ...
- (set (REGX) (plus (REGX) (CONST_INT B-A))) */
-
- if (GET_CODE (src) == CONST_INT && reg_base_reg[regno] < 0)
- {
- int success = 0;
- rtx new_src = GEN_INT (sext_for_mode (GET_MODE (reg),
- INTVAL (src)
- - reg_offset[regno]));
- /* (set (reg) (plus (reg) (const_int 0))) is not canonical;
- use (set (reg) (reg)) instead.
- We don't delete this insn, nor do we convert it into a
- note, to avoid losing register notes or the return
- value flag. jump2 already knowns how to get rid of
- no-op moves. */
- if (new_src == const0_rtx)
- success = validate_change (insn, &SET_SRC (pat), reg, 0);
- else if (rtx_cost (new_src, PLUS) < rtx_cost (src, SET)
- && have_add2_insn (reg, new_src))
- success = validate_change (insn, &PATTERN (insn),
- gen_add2_insn (reg, new_src), 0);
- reg_set_luid[regno] = move2add_luid;
- reg_mode[regno] = GET_MODE (reg);
- reg_offset[regno] = INTVAL (src);
- continue;
- }
-
- /* Try to transform (set (REGX) (REGY))
- (set (REGX) (PLUS (REGX) (CONST_INT A)))
- ...
- (set (REGX) (REGY))
- (set (REGX) (PLUS (REGX) (CONST_INT B)))
- to
- (REGX) (REGY))
- (set (REGX) (PLUS (REGX) (CONST_INT A)))
- ...
- (set (REGX) (plus (REGX) (CONST_INT B-A))) */
- else if (GET_CODE (src) == REG
- && reg_set_luid[regno] == reg_set_luid[REGNO (src)]
- && reg_base_reg[regno] == reg_base_reg[REGNO (src)]
- && MODES_OK_FOR_MOVE2ADD (GET_MODE (reg),
- reg_mode[REGNO (src)]))
- {
- rtx next = next_nonnote_insn (insn);
- rtx set = NULL_RTX;
- if (next)
- set = single_set (next);
- if (set
- && SET_DEST (set) == reg
- && GET_CODE (SET_SRC (set)) == PLUS
- && XEXP (SET_SRC (set), 0) == reg
- && GET_CODE (XEXP (SET_SRC (set), 1)) == CONST_INT)
- {
- rtx src3 = XEXP (SET_SRC (set), 1);
- HOST_WIDE_INT added_offset = INTVAL (src3);
- HOST_WIDE_INT base_offset = reg_offset[REGNO (src)];
- HOST_WIDE_INT regno_offset = reg_offset[regno];
- rtx new_src = GEN_INT (sext_for_mode (GET_MODE (reg),
- added_offset
- + base_offset
- - regno_offset));
- int success = 0;
-
- if (new_src == const0_rtx)
- /* See above why we create (set (reg) (reg)) here. */
- success
- = validate_change (next, &SET_SRC (set), reg, 0);
- else if ((rtx_cost (new_src, PLUS)
- < COSTS_N_INSNS (1) + rtx_cost (src3, SET))
- && have_add2_insn (reg, new_src))
- success
- = validate_change (next, &PATTERN (next),
- gen_add2_insn (reg, new_src), 0);
- if (success)
- delete_insn (insn);
- insn = next;
- reg_mode[regno] = GET_MODE (reg);
- reg_offset[regno] = sext_for_mode (GET_MODE (reg),
- added_offset
- + base_offset);
- continue;
- }
- }
- }
- }
-
- for (note = REG_NOTES (insn); note; note = XEXP (note, 1))
- {
- if (REG_NOTE_KIND (note) == REG_INC
- && GET_CODE (XEXP (note, 0)) == REG)
- {
- /* Reset the information about this register. */
- int regno = REGNO (XEXP (note, 0));
- if (regno < FIRST_PSEUDO_REGISTER)
- reg_set_luid[regno] = 0;
- }
- }
- note_stores (PATTERN (insn), move2add_note_store, NULL);
- /* If this is a CALL_INSN, all call used registers are stored with
- unknown values. */
- if (GET_CODE (insn) == CALL_INSN)
- {
- for (i = FIRST_PSEUDO_REGISTER - 1; i >= 0; i--)
- {
- if (call_used_regs[i])
- /* Reset the information about this register. */
- reg_set_luid[i] = 0;
- }
- }
- }
-}
-
-/* SET is a SET or CLOBBER that sets DST.
- Update reg_set_luid, reg_offset and reg_base_reg accordingly.
- Called from reload_cse_move2add via note_stores. */
-
-static void
-move2add_note_store (dst, set, data)
- rtx dst, set;
- void *data ATTRIBUTE_UNUSED;
-{
- unsigned int regno = 0;
- unsigned int i;
- enum machine_mode mode = GET_MODE (dst);
-
- if (GET_CODE (dst) == SUBREG)
- {
- regno = subreg_regno_offset (REGNO (SUBREG_REG (dst)),
- GET_MODE (SUBREG_REG (dst)),
- SUBREG_BYTE (dst),
- GET_MODE (dst));
- dst = SUBREG_REG (dst);
- }
-
- /* Some targets do argument pushes without adding REG_INC notes. */
-
- if (GET_CODE (dst) == MEM)
- {
- dst = XEXP (dst, 0);
- if (GET_CODE (dst) == PRE_INC || GET_CODE (dst) == POST_INC
- || GET_CODE (dst) == PRE_DEC || GET_CODE (dst) == POST_DEC)
- reg_set_luid[REGNO (XEXP (dst, 0))] = 0;
- return;
- }
- if (GET_CODE (dst) != REG)
- return;
-
- regno += REGNO (dst);
-
- if (HARD_REGNO_NREGS (regno, mode) == 1 && GET_CODE (set) == SET
- && GET_CODE (SET_DEST (set)) != ZERO_EXTRACT
- && GET_CODE (SET_DEST (set)) != SIGN_EXTRACT
- && GET_CODE (SET_DEST (set)) != STRICT_LOW_PART)
- {
- rtx src = SET_SRC (set);
- rtx base_reg;
- HOST_WIDE_INT offset;
- int base_regno;
- /* This may be different from mode, if SET_DEST (set) is a
- SUBREG. */
- enum machine_mode dst_mode = GET_MODE (dst);
-
- switch (GET_CODE (src))
- {
- case PLUS:
- if (GET_CODE (XEXP (src, 0)) == REG)
- {
- base_reg = XEXP (src, 0);
-
- if (GET_CODE (XEXP (src, 1)) == CONST_INT)
- offset = INTVAL (XEXP (src, 1));
- else if (GET_CODE (XEXP (src, 1)) == REG
- && (reg_set_luid[REGNO (XEXP (src, 1))]
- > move2add_last_label_luid)
- && (MODES_OK_FOR_MOVE2ADD
- (dst_mode, reg_mode[REGNO (XEXP (src, 1))])))
- {
- if (reg_base_reg[REGNO (XEXP (src, 1))] < 0)
- offset = reg_offset[REGNO (XEXP (src, 1))];
- /* Maybe the first register is known to be a
- constant. */
- else if (reg_set_luid[REGNO (base_reg)]
- > move2add_last_label_luid
- && (MODES_OK_FOR_MOVE2ADD
- (dst_mode, reg_mode[REGNO (XEXP (src, 1))]))
- && reg_base_reg[REGNO (base_reg)] < 0)
- {
- offset = reg_offset[REGNO (base_reg)];
- base_reg = XEXP (src, 1);
- }
- else
- goto invalidate;
- }
- else
- goto invalidate;
-
- break;
- }
-
- goto invalidate;
-
- case REG:
- base_reg = src;
- offset = 0;
- break;
-
- case CONST_INT:
- /* Start tracking the register as a constant. */
- reg_base_reg[regno] = -1;
- reg_offset[regno] = INTVAL (SET_SRC (set));
- /* We assign the same luid to all registers set to constants. */
- reg_set_luid[regno] = move2add_last_label_luid + 1;
- reg_mode[regno] = mode;
- return;
-
- default:
- invalidate:
- /* Invalidate the contents of the register. */
- reg_set_luid[regno] = 0;
- return;
- }
-
- base_regno = REGNO (base_reg);
- /* If information about the base register is not valid, set it
- up as a new base register, pretending its value is known
- starting from the current insn. */
- if (reg_set_luid[base_regno] <= move2add_last_label_luid)
- {
- reg_base_reg[base_regno] = base_regno;
- reg_offset[base_regno] = 0;
- reg_set_luid[base_regno] = move2add_luid;
- reg_mode[base_regno] = mode;
- }
- else if (! MODES_OK_FOR_MOVE2ADD (dst_mode,
- reg_mode[base_regno]))
- goto invalidate;
-
- reg_mode[regno] = mode;
-
- /* Copy base information from our base register. */
- reg_set_luid[regno] = reg_set_luid[base_regno];
- reg_base_reg[regno] = reg_base_reg[base_regno];
-
- /* Compute the sum of the offsets or constants. */
- reg_offset[regno] = sext_for_mode (dst_mode,
- offset
- + reg_offset[base_regno]);
- }
- else
- {
- unsigned int endregno = regno + HARD_REGNO_NREGS (regno, mode);
-
- for (i = regno; i < endregno; i++)
- /* Reset the information about this register. */
- reg_set_luid[i] = 0;
- }
-}
-
-#ifdef AUTO_INC_DEC
-static void
-add_auto_inc_notes (insn, x)
- rtx insn;
- rtx x;
-{
- enum rtx_code code = GET_CODE (x);
- const char *fmt;
- int i, j;
-
- if (code == MEM && auto_inc_p (XEXP (x, 0)))
- {
- REG_NOTES (insn)
- = gen_rtx_EXPR_LIST (REG_INC, XEXP (XEXP (x, 0), 0), REG_NOTES (insn));
- return;
- }
-
- /* Scan all the operand sub-expressions. */
- fmt = GET_RTX_FORMAT (code);
- for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
- {
- if (fmt[i] == 'e')
- add_auto_inc_notes (insn, XEXP (x, i));
- else if (fmt[i] == 'E')
- for (j = XVECLEN (x, i) - 1; j >= 0; j--)
- add_auto_inc_notes (insn, XVECEXP (x, i, j));
- }
-}
-#endif
-
-/* Copy EH notes from an insn to its reloads. */
-static void
-copy_eh_notes (insn, x)
- rtx insn;
- rtx x;
-{
- rtx eh_note = find_reg_note (insn, REG_EH_REGION, NULL_RTX);
- if (eh_note)
- {
- for (; x != 0; x = NEXT_INSN (x))
- {
- if (may_trap_p (PATTERN (x)))
- REG_NOTES (x)
- = gen_rtx_EXPR_LIST (REG_EH_REGION, XEXP (eh_note, 0),
- REG_NOTES (x));
- }
- }
-}
-
-/* This is used by reload pass, that does emit some instructions after
- abnormal calls moving basic block end, but in fact it wants to emit
- them on the edge. Looks for abnormal call edges, find backward the
- proper call and fix the damage.
-
- Similar handle instructions throwing exceptions internally. */
-void
-fixup_abnormal_edges ()
-{
- bool inserted = false;
- basic_block bb;
-
- FOR_EACH_BB (bb)