diff options
Diffstat (limited to 'gcc/dse.c')
-rw-r--r-- | gcc/dse.c | 153 |
1 files changed, 66 insertions, 87 deletions
diff --git a/gcc/dse.c b/gcc/dse.c index fea7afaca04..696b2d84ff3 100644 --- a/gcc/dse.c +++ b/gcc/dse.c @@ -29,6 +29,7 @@ along with GCC; see the file COPYING3. If not see #include "tm.h" #include "rtl.h" #include "tree.h" +#include "tm_p.h" #include "regs.h" #include "hard-reg-set.h" #include "flags.h" @@ -1383,9 +1384,9 @@ record_store (rtx body, bb_info_t bb_info) if (store_info->is_set /* No place to keep the value after ra. */ && !reload_completed - /* The careful reviewer may wish to comment my checking that the - rhs of a store is always a reg. */ - && REG_P (SET_SRC (body)) + && (REG_P (SET_SRC (body)) + || GET_CODE (SET_SRC (body)) == SUBREG + || CONSTANT_P (SET_SRC (body))) /* Sometimes the store and reload is used for truncation and rounding. */ && !(FLOAT_MODE_P (GET_MODE (mem)) && (flag_float_store))) @@ -1418,15 +1419,15 @@ dump_insn_info (const char * start, insn_info_t insn_info) shift. */ static rtx -find_shift_sequence (rtx read_reg, - int access_size, +find_shift_sequence (int access_size, store_info_t store_info, read_info_t read_info, int shift) { enum machine_mode store_mode = GET_MODE (store_info->mem); enum machine_mode read_mode = GET_MODE (read_info->mem); - rtx chosen_seq = NULL; + enum machine_mode new_mode; + rtx read_reg = NULL; /* Some machines like the x86 have shift insns for each size of operand. Other machines like the ppc or the ia-64 may only have @@ -1435,21 +1436,31 @@ find_shift_sequence (rtx read_reg, justify the value we want to read but is available in one insn on the machine. */ - for (; access_size <= UNITS_PER_WORD; access_size *= 2) + for (new_mode = smallest_mode_for_size (access_size * BITS_PER_UNIT, + MODE_INT); + GET_MODE_BITSIZE (new_mode) <= BITS_PER_WORD; + new_mode = GET_MODE_WIDER_MODE (new_mode)) { - rtx target, new_reg, shift_seq, insn; - enum machine_mode new_mode; + rtx target, new_reg, shift_seq, insn, new_lhs; int cost; - /* Try a wider mode if truncating the store mode to ACCESS_SIZE - bytes requires a real instruction. */ - if (access_size < GET_MODE_SIZE (store_mode) - && !TRULY_NOOP_TRUNCATION (access_size * BITS_PER_UNIT, + /* Try a wider mode if truncating the store mode to NEW_MODE + requires a real instruction. */ + if (GET_MODE_BITSIZE (new_mode) < GET_MODE_BITSIZE (store_mode) + && !TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (new_mode), GET_MODE_BITSIZE (store_mode))) continue; - new_mode = smallest_mode_for_size (access_size * BITS_PER_UNIT, - MODE_INT); + /* Also try a wider mode if the necessary punning is either not + desirable or not possible. */ + if (!CONSTANT_P (store_info->rhs) + && !MODES_TIEABLE_P (new_mode, store_mode)) + continue; + new_lhs = simplify_gen_subreg (new_mode, copy_rtx (store_info->rhs), + store_mode, 0); + if (new_lhs == NULL_RTX) + continue; + new_reg = gen_reg_rtx (new_mode); start_sequence (); @@ -1485,31 +1496,13 @@ find_shift_sequence (rtx read_reg, take the value from the store and put it into the shift pseudo, then shift it, then generate another move to put in into the target of the read. */ - start_sequence (); - emit_move_insn (new_reg, gen_lowpart (new_mode, store_info->rhs)); + emit_move_insn (new_reg, new_lhs); emit_insn (shift_seq); - convert_move (read_reg, new_reg, 1); - - if (dump_file) - { - fprintf (dump_file, " -- adding extract insn r%d:%s = r%d:%s\n", - REGNO (new_reg), GET_MODE_NAME (new_mode), - REGNO (store_info->rhs), GET_MODE_NAME (store_mode)); - - fprintf (dump_file, " -- with shift of r%d by %d\n", - REGNO(new_reg), shift); - fprintf (dump_file, " -- and second extract insn r%d:%s = r%d:%s\n", - REGNO (read_reg), GET_MODE_NAME (read_mode), - REGNO (new_reg), GET_MODE_NAME (new_mode)); - } - - /* Get the three insn sequence and return it. */ - chosen_seq = get_insns (); - end_sequence (); + read_reg = extract_low_bits (read_mode, new_mode, new_reg); break; } - return chosen_seq; + return read_reg; } @@ -1552,16 +1545,11 @@ replace_read (store_info_t store_info, insn_info_t store_insn, enum machine_mode read_mode = GET_MODE (read_info->mem); int shift; int access_size; /* In bytes. */ - rtx read_reg = gen_reg_rtx (read_mode); - rtx shift_seq = NULL; + rtx insns, read_reg; if (!dbg_cnt (dse)) return false; - if (GET_MODE_CLASS (read_mode) != MODE_INT - || GET_MODE_CLASS (store_mode) != MODE_INT) - return false; - /* To get here the read is within the boundaries of the write so shift will never be negative. Start out with the shift being in bytes. */ @@ -1575,62 +1563,43 @@ replace_read (store_info_t store_info, insn_info_t store_insn, /* From now on it is bits. */ shift *= BITS_PER_UNIT; - /* We need to keep this in perspective. We are replacing a read + /* Create a sequence of instructions to set up the read register. + This sequence goes immediately before the store and its result + is read by the load. + + We need to keep this in perspective. We are replacing a read with a sequence of insns, but the read will almost certainly be in cache, so it is not going to be an expensive one. Thus, we are not willing to do a multi insn shift or worse a subroutine call to get rid of the read. */ + if (dump_file) + fprintf (dump_file, "trying to replace %smode load in insn %d" + " from %smode store in insn %d\n", + GET_MODE_NAME (read_mode), INSN_UID (read_insn->insn), + GET_MODE_NAME (store_mode), INSN_UID (store_insn->insn)); + start_sequence (); if (shift) + read_reg = find_shift_sequence (access_size, store_info, read_info, shift); + else + read_reg = extract_low_bits (read_mode, store_mode, + copy_rtx (store_info->rhs)); + if (read_reg == NULL_RTX) { - if (access_size > UNITS_PER_WORD) - return false; - - shift_seq = find_shift_sequence (read_reg, access_size, store_info, - read_info, shift); - if (!shift_seq) - return false; + end_sequence (); + if (dump_file) + fprintf (dump_file, " -- could not extract bits of stored value\n"); + return false; } - - if (dump_file) - fprintf (dump_file, "replacing load at %d from store at %d\n", - INSN_UID (read_insn->insn), INSN_UID (store_insn->insn)); + /* Force the value into a new register so that it won't be clobbered + between the store and the load. */ + read_reg = copy_to_mode_reg (read_mode, read_reg); + insns = get_insns (); + end_sequence (); if (validate_change (read_insn->insn, loc, read_reg, 0)) { - rtx insns; deferred_change_t deferred_change = pool_alloc (deferred_change_pool); - if (read_mode == store_mode) - { - start_sequence (); - - /* The modes are the same and everything lines up. Just - generate a simple move. */ - emit_move_insn (read_reg, store_info->rhs); - if (dump_file) - fprintf (dump_file, " -- adding move insn r%d = r%d\n", - REGNO (read_reg), REGNO (store_info->rhs)); - insns = get_insns (); - end_sequence (); - } - else if (shift) - insns = shift_seq; - else - { - /* The modes are different but the lsb are in the same - place, we need to extract the value in the right from the - rhs of the store. */ - start_sequence (); - convert_move (read_reg, store_info->rhs, 1); - - if (dump_file) - fprintf (dump_file, " -- adding extract insn r%d:%s = r%d:%s\n", - REGNO (read_reg), GET_MODE_NAME (read_mode), - REGNO (store_info->rhs), GET_MODE_NAME (store_mode)); - insns = get_insns (); - end_sequence (); - } - /* Insert this right before the store insn where it will be safe from later insns that might change it before the read. */ emit_insn_before (insns, store_insn->insn); @@ -1668,12 +1637,22 @@ replace_read (store_info_t store_info, insn_info_t store_insn, rest of dse, play like this read never happened. */ read_insn->read_rec = read_info->next; pool_free (read_info_pool, read_info); + if (dump_file) + { + fprintf (dump_file, " -- replaced the loaded MEM with "); + print_simple_rtl (dump_file, read_reg); + fprintf (dump_file, "\n"); + } return true; } else { if (dump_file) - fprintf (dump_file, " -- validation failure\n"); + { + fprintf (dump_file, " -- replacing the loaded MEM with "); + print_simple_rtl (dump_file, read_reg); + fprintf (dump_file, " led to an invalid instruction\n"); + } return false; } } |