From 5adf6da0eb8b7cf355e5db02e8266637e24a5d25 Mon Sep 17 00:00:00 2001 From: "J\"orn Rennecke" Date: Thu, 24 Sep 1998 13:27:20 +0000 Subject: reload1.c (reload_cse_regs_1): Renamed from reload_cse_regs. * reload1.c (reload_cse_regs_1): Renamed from reload_cse_regs. (reload_cse_regs): New function body: call reload_cse_regs_1, reload_combine, reload_cse_move2add. When doing expensive_optimizations, call reload_cse_regs_1 a second time after reload_cse_move2add. (reload_combine, reload_combine_note_store): New functions. (reload_combine_note_use): New function. (reload_cse_move2add, move2add_note_store): New functions. From-SVN: r22570 --- gcc/ChangeLog | 11 + gcc/reload1.c | 690 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 699 insertions(+), 2 deletions(-) (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index de76637..c462638 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,14 @@ +Thu Sep 24 21:22:39 1998 J"orn Rennecke + + * reload1.c (reload_cse_regs_1): Renamed from reload_cse_regs. + (reload_cse_regs): New function body: call reload_cse_regs_1, + reload_combine, reload_cse_move2add. + When doing expensive_optimizations, call reload_cse_regs_1 a + second time after reload_cse_move2add. + (reload_combine, reload_combine_note_store): New functions. + (reload_combine_note_use): New function. + (reload_cse_move2add, move2add_note_store): New functions. + Thu Sep 24 18:48:43 1998 J"orn Rennecke * reload.c (find_reloads): In code to promote RELOAD_FOR_X_ADDR_ADDR diff --git a/gcc/reload1.c b/gcc/reload1.c index d8eb326..91b7294 100644 --- a/gcc/reload1.c +++ b/gcc/reload1.c @@ -391,6 +391,7 @@ static void emit_reload_insns PROTO((rtx, int)); static void delete_output_reload PROTO((rtx, int, rtx)); static void inc_for_reload PROTO((rtx, rtx, int)); static int constraint_accepts_reg_p PROTO((char *, rtx)); +static void reload_cse_regs_1 PROTO((rtx)); static void reload_cse_invalidate_regno PROTO((int, enum machine_mode, int)); static int reload_cse_mem_conflict_p PROTO((rtx, rtx)); static void reload_cse_invalidate_mem PROTO((rtx)); @@ -403,6 +404,11 @@ static void reload_cse_check_clobber PROTO((rtx, rtx)); static void reload_cse_record_set PROTO((rtx, rtx)); static void reload_cse_delete_death_notes PROTO((rtx)); static void reload_cse_no_longer_dead PROTO((int, enum machine_mode)); +static void reload_combine PROTO((void)); +static void reload_combine_note_use PROTO((rtx *, rtx)); +static void reload_combine_note_store PROTO((rtx, rtx)); +static void reload_cse_move2add PROTO((rtx)); +static void move2add_note_store PROTO((rtx, rtx)); /* Initialize the reload pass once per compilation. */ @@ -8330,8 +8336,8 @@ reload_cse_no_longer_dead (regno, mode) hard register. It then replaces the operand with the hard register if possible, much like an optional reload would. */ -void -reload_cse_regs (first) +static void +reload_cse_regs_1 (first) rtx first; { char *firstobj; @@ -8547,6 +8553,19 @@ reload_cse_regs (first) pop_obstacks (); } +/* Call cse / combine like post-reload optimization phases. + FIRST is the first instruction. */ +void +reload_cse_regs (first) + rtx first; +{ + reload_cse_regs_1 (first); + reload_combine (); + reload_cse_move2add (first); + if (flag_expensive_optimizations) + reload_cse_regs_1 (first); +} + /* Return whether the values known for REGNO are equal to VAL. MODE is the mode of the object that VAL is being copied to; this matters if VAL is a CONST_INT. */ @@ -9144,3 +9163,670 @@ reload_cse_record_set (set, body) abort (); } } + +/* If reload couldn't use reg+reg+offset addressing, try to use reg+reg + addressing now. + This code might also be useful when reload gave up on reg+reg addresssing + because of clashes between the return register and INDEX_REG_CLASS. */ + +/* The maximum number of uses of a register we can keep track of to + replace them with reg+reg addressing. */ +#define RELOAD_COMBINE_MAX_USES 6 + +/* INSN is the insn where a register has ben used, and USEP points to the + location of the register within the rtl. */ +struct reg_use { rtx insn, *usep; }; + +/* If the register is used in some unknown fashion, USE_INDEX is negative. + If it is dead, USE_INDEX is RELOAD_COMBINE_MAX_USES, and STORE_RUID + indicates where it becomes live again. + Otherwise, USE_INDEX is the index of the last encountered use of the + register (which is first among these we have seen since we scan backwards), + OFFSET contains the constant offset that is added to the register in + all encountered uses, and USE_RUID indicates the first encountered, i.e. + last, of these uses. */ +static struct + { + struct reg_use reg_use[RELOAD_COMBINE_MAX_USES]; + int use_index; + rtx offset; + int store_ruid; + int use_ruid; + } reg_state[FIRST_PSEUDO_REGISTER]; + +/* Reverse linear uid. This is increased in reload_combine while scanning + the instructions from last to first. It is used to set last_label_ruid + and the store_ruid / use_ruid fields in reg_state. */ +static int reload_combine_ruid; + +static void +reload_combine () +{ + rtx insn, set; + int first_index_reg = 1, last_index_reg = 0; + int i; + int last_label_ruid; + + /* If reg+reg can be used in offsetable memory adresses, the main chunk of + reload has already used it where appropriate, so there is no use in + trying to generate it now. */ + if (double_reg_address_ok && reload_address_index_reg_class != NO_REGS) + return; + + /* To avoid wasting too much time later searching for an index register, + determine the minimum and maximum index register numbers. */ + for (i = FIRST_PSEUDO_REGISTER - 1; i >= 0; --i) + { + if (TEST_HARD_REG_BIT (reg_class_contents[INDEX_REG_CLASS], i)) + { + if (! last_index_reg) + last_index_reg = i; + first_index_reg = i; + } + } + /* If no index register is available, we can quit now. */ + if (first_index_reg > last_index_reg) + return; + + /* Initialize last_label_ruid, reload_combine_ruid and reg_state. */ + last_label_ruid = reload_combine_ruid = 0; + for (i = FIRST_PSEUDO_REGISTER - 1; i >= 0; --i) + { + if (fixed_regs[i]) + reg_state[i].use_index = -1; + else + { + reg_state[i].use_index = RELOAD_COMBINE_MAX_USES; + reg_state[i].store_ruid = reload_combine_ruid; + } + } + + 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; + if (GET_RTX_CLASS (GET_CODE (insn)) != 'i') + 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. */ + if (set + && 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; + int regno = REGNO (reg); + rtx const_reg; + 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; + } + } + } + if (prev_set + && GET_CODE (SET_SRC (prev_set)) == CONST_INT + && rtx_equal_p (SET_DEST (prev_set), reg) + && reg_state[regno].use_index >= 0 + && reg_sum) + { + 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, + reg_sum, 1); + + if (apply_change_group ()) + { + rtx *np; + + /* Delete the reg-reg addition. */ + PUT_CODE (insn, NOTE); + NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED; + NOTE_SOURCE_FILE (insn) = 0; + + 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); + if (GET_CODE (insn) == CALL_INSN) + { + rtx link; + + for (i = FIRST_PSEUDO_REGISTER - 1; i >= 0; --i) + { + if (call_used_regs[i]) + { + reg_state[i].use_index = RELOAD_COMBINE_MAX_USES; + reg_state[i].store_ruid = reload_combine_ruid; + } + } + for (link = CALL_INSN_FUNCTION_USAGE (insn); link; + link = XEXP (link, 1)) + { + rtx use = XEXP (link, 0); + int regno = REGNO (XEXP (use, 0)); + if (GET_CODE (use) == CLOBBER) + { + reg_state[regno].use_index = RELOAD_COMBINE_MAX_USES; + reg_state[regno].store_ruid = reload_combine_ruid; + } + else + reg_state[regno].use_index = -1; + } + } + if (GET_CODE (insn) == JUMP_INSN) + { + /* Non-spill registers might be used at the call destination in + some unknown fashion, so we have to mark the unknown use. */ + for (i = FIRST_PSEUDO_REGISTER - 1; i >= 0; --i) + { + if (! TEST_HARD_REG_BIT (used_spill_regs, 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) + reg_state[REGNO (XEXP (note, 0))].use_index = -1; + } + } +} + +/* 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. + The second argument, SET, is ignored. */ +static void +reload_combine_note_store (dst, set) + rtx dst, set; +{ + int regno = 0; + int i; + unsigned size = GET_MODE_SIZE (GET_MODE (dst)); + + if (GET_CODE (dst) == SUBREG) + { + regno = SUBREG_WORD (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. */ + if (size < UNITS_PER_WORD) + reg_state[regno].use_index = -1; + else + { + for (i = size / UNITS_PER_WORD - 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; + 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 CLOBBER: + if (GET_CODE (SET_DEST (x)) == REG) + 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; + + /* Some spurious USEs of pseudo registers might remain. + Just ignore them. */ + if (regno >= FIRST_PSEUDO_REGISTER) + 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); + } + } +} + +/* See if we can reduce the cost of a constant by replacing a move with + an add. */ +/* We cannot do our optimization across labels. Invalidating all the + information about register contents we have would be costly, so we + use last_label_luid (local variable of reload_cse_move2add) 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 larger than last_label_luid[n] . */ +static int reg_set_luid[FIRST_PSEUDO_REGISTER]; +/* reg_offset[n] has to be CONST_INT for it and reg_base_reg[n] / + reg_mode[n] to be valid. + If reg_offset[n] is a CONST_INT and reg_base_reg[n] is negative, register n + has been set to reg_offset[n] in mode reg_mode[n] . + If reg_offset[n] is a CONST_INT and reg_base_reg[n] is non-negative, + register n has been set to the sum of reg_offset[n] and register + reg_base_reg[n], calculated in mode reg_mode[n] . */ +static rtx 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, and to set reg_death_luid + (local variable of reload_cse_move2add) . */ +static int move2add_luid; + +static void +reload_cse_move2add (first) + rtx first; +{ + int i; + rtx insn; + int last_label_luid; + /* reg_death and reg_death_luid are solely used to remove stale REG_DEAD + notes. */ + int reg_death_luid[FIRST_PSEUDO_REGISTER]; + rtx reg_death[FIRST_PSEUDO_REGISTER]; + + for (i = FIRST_PSEUDO_REGISTER-1; i >= 0; i--) + { + reg_set_luid[i] = 0; + reg_death_luid[i] = 0; + } + last_label_luid = 0; + move2add_luid = 1; + for (insn = first; insn; insn = NEXT_INSN (insn), move2add_luid++) + { + rtx pat, note; + + if (GET_CODE (insn) == CODE_LABEL) + last_label_luid = move2add_luid; + if (GET_RTX_CLASS (GET_CODE (insn)) != 'i') + 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. */ + /* ??? We don't know how zero / sign extension is handled, hence + we can't go from a narrower to a wider mode. */ + if (reg_set_luid[regno] > last_label_luid + && (GET_MODE_SIZE (GET_MODE (reg)) + <= GET_MODE_SIZE (reg_mode[regno])) + && GET_CODE (reg_offset[regno]) == CONST_INT) + { + /* 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 (INTVAL (src) + - INTVAL (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 (GET_MODE (reg))) + success = validate_change (insn, &PATTERN (insn), + gen_add2_insn (reg, new_src), 0); + if (success && reg_death_luid[regno] > reg_set_luid[regno]) + remove_death (regno, reg_death[regno]); + reg_set_luid[regno] = move2add_luid; + reg_mode[regno] = GET_MODE (reg); + reg_offset[regno] = 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_base_reg[regno] == REGNO (src) + && reg_set_luid[regno] > reg_set_luid[REGNO (src)]) + { + rtx next = next_nonnote_insn (insn); + rtx set; + if (next) + set = single_set (next); + if (next + && 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 src2 = SET_SRC (set); + rtx src3 = XEXP (SET_SRC (set), 1); + rtx new_src = GEN_INT (INTVAL (src3) + - INTVAL (reg_offset[regno])); + 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) + < 2 + rtx_cost (src3, SET)) + && have_add2_insn (GET_MODE (reg))) + success + = validate_change (next, &PATTERN (next), + gen_add2_insn (reg, new_src), 0); + if (success) + { + if (reg_death_luid[regno] > reg_set_luid[regno]) + remove_death (regno, reg_death[regno]); + /* INSN might be the first insn in a basic block + if the preceding insn is a conditional jump + or a possible-throwing call. */ + PUT_CODE (insn, NOTE); + NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED; + NOTE_SOURCE_FILE (insn) = 0; + } + insn = next; + reg_set_luid[regno] = move2add_luid; + reg_mode[regno] = GET_MODE (reg); + reg_offset[regno] = src3; + continue; + } + } + } + } + + for (note = REG_NOTES (insn); note; note = XEXP (note, 1)) + { + if (REG_NOTE_KIND (note) == REG_INC + && GET_CODE (XEXP (note, 0)) == REG) + { + /* Indicate that this register has been recently written to, + but the exact contents are not available. */ + int regno = REGNO (XEXP (note, 0)); + if (regno < FIRST_PSEUDO_REGISTER) + { + reg_set_luid[regno] = move2add_luid; + reg_offset[regno] = note; + } + } + /* Remember any REG_DEAD notes so that we can remove them + later if necessary. */ + else if (REG_NOTE_KIND (note) == REG_DEAD + && GET_CODE (XEXP (note, 0)) == REG) + { + int regno = REGNO (XEXP (note, 0)); + if (regno < FIRST_PSEUDO_REGISTER) + { + reg_death[regno] = insn; + reg_death_luid[regno] = move2add_luid; + } + } + } + note_stores (PATTERN (insn), move2add_note_store); + /* 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]) + { + reg_set_luid[i] = move2add_luid; + reg_offset[i] = insn; /* Invalidate contents. */ + } + } + } + } +} + +/* 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) + rtx dst, set; +{ + int regno = 0; + int i; + + enum machine_mode mode = GET_MODE (dst); + if (GET_CODE (dst) == SUBREG) + { + regno = SUBREG_WORD (dst); + dst = SUBREG_REG (dst); + } + if (GET_CODE (dst) != REG) + return; + + regno += REGNO (dst); + + if (HARD_REGNO_NREGS (regno, mode) == 1 && GET_CODE (set) == SET) + { + rtx src = SET_SRC (set); + + reg_mode[regno] = mode; + switch (GET_CODE (src)) + { + case PLUS: + { + rtx src0 = XEXP (src, 0); + if (GET_CODE (src0) == REG) + { + if (REGNO (src0) != regno + || reg_offset[regno] != const0_rtx) + { + reg_base_reg[regno] = REGNO (src0); + reg_set_luid[regno] = move2add_luid; + } + reg_offset[regno] = XEXP (src, 1); + break; + } + reg_set_luid[regno] = move2add_luid; + reg_offset[regno] = set; /* Invalidate contents. */ + break; + } + + case REG: + reg_base_reg[regno] = REGNO (SET_SRC (set)); + reg_offset[regno] = const0_rtx; + reg_set_luid[regno] = move2add_luid; + break; + + default: + reg_base_reg[regno] = -1; + reg_offset[regno] = SET_SRC (set); + reg_set_luid[regno] = move2add_luid; + break; + } + } + else + { + for (i = regno + HARD_REGNO_NREGS (regno, mode) - 1; i >= regno; i--) + { + /* Indicate that this register has been recently written to, + but the exact contents are not available. */ + reg_set_luid[i] = move2add_luid; + reg_offset[i] = dst; + } + } +} -- cgit v1.1