summaryrefslogtreecommitdiff
path: root/gcc/dse.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/dse.c')
-rw-r--r--gcc/dse.c153
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;
}
}