/* RTL dead store elimination.
- Copyright (C) 2005-2016 Free Software Foundation, Inc.
+ Copyright (C) 2005-2020 Free Software Foundation, Inc.
Contributed by Richard Sandiford <rsandifor@codesourcery.com>
and Kenneth Zadeck <zadeck@naturalbridge.com>
#include "gimple.h"
#include "predict.h"
#include "df.h"
+#include "memmodel.h"
#include "tm_p.h"
#include "gimple-ssa.h"
#include "expmed.h"
#include "explow.h"
#include "expr.h"
#include "dbgcnt.h"
-#include "params.h"
#include "rtl-iter.h"
#include "cfgcleanup.h"
+#include "calls.h"
/* This file contains three techniques for performing Dead Store
Elimination (dse).
struct insn_info_type;
/* This structure holds information about a candidate store. */
-struct store_info
+class store_info
{
+public:
/* False means this is a clobber. */
bool is_set;
/* Canonized MEM address for use by canon_true_dependence. */
rtx mem_addr;
- /* If this is non-zero, it is the alias set of a spill location. */
- alias_set_type alias_set;
+ /* The offset of the first byte associated with the operation. */
+ poly_int64 offset;
- /* The offset of the first and byte before the last byte associated
- with the operation. */
- HOST_WIDE_INT begin, end;
+ /* The number of bytes covered by the operation. This is always exact
+ and known (rather than -1). */
+ poly_int64 width;
union
{
struct
{
- /* A bitmap with one bit per byte. Cleared bit means the position
- is needed. Used if IS_LARGE is false. */
+ /* A bitmap with one bit per byte, or null if the number of
+ bytes isn't known at compile time. A cleared bit means
+ the position is needed. Used if IS_LARGE is true. */
bitmap bmap;
- /* Number of set bits (i.e. unneeded bytes) in BITMAP. If it is
- equal to END - BEGIN, the whole store is unused. */
+ /* When BITMAP is nonnull, this counts the number of set bits
+ (i.e. unneeded bytes) in the bitmap. If it is equal to
+ WIDTH, the whole store is unused.
+
+ When BITMAP is null:
+ - the store is definitely not needed when COUNT == 1
+ - all the store is needed when COUNT == 0 and RHS is nonnull
+ - otherwise we don't know which parts of the store are needed. */
int count;
} large;
} positions_needed;
/* The next store info for this insn. */
- struct store_info *next;
+ class store_info *next;
/* The right hand side of the store. This is used if there is a
subsequent reload of the mems address somewhere later in the
static unsigned HOST_WIDE_INT
lowpart_bitmask (int n)
{
- unsigned HOST_WIDE_INT mask = ~(unsigned HOST_WIDE_INT) 0;
+ unsigned HOST_WIDE_INT mask = HOST_WIDE_INT_M1U;
return mask >> (HOST_BITS_PER_WIDE_INT - n);
}
/* This structure holds information about a load. These are only
built for rtx bases. */
-struct read_info_type
+class read_info_type
{
+public:
/* The id of the mem group of the base address. */
int group_id;
- /* If this is non-zero, it is the alias set of a spill location. */
- alias_set_type alias_set;
+ /* The offset of the first byte associated with the operation. */
+ poly_int64 offset;
- /* The offset of the first and byte after the last byte associated
- with the operation. If begin == end == 0, the read did not have
- a constant offset. */
- int begin, end;
+ /* The number of bytes covered by the operation, or -1 if not known. */
+ poly_int64 width;
/* The mem being read. */
rtx mem;
/* The next read_info for this insn. */
- struct read_info_type *next;
+ class read_info_type *next;
};
-typedef struct read_info_type *read_info_t;
+typedef class read_info_type *read_info_t;
static object_allocator<read_info_type> read_info_type_pool ("read_info_pool");
static deferred_change *deferred_change_list = NULL;
-/* The group that holds all of the clear_alias_sets. */
-static group_info *clear_alias_group;
-
-/* The modes of the clear_alias_sets. */
-static htab_t clear_alias_mode_table;
-
-/* Hash table element to look up the mode for an alias set. */
-struct clear_alias_mode_holder
-{
- alias_set_type alias_set;
- machine_mode mode;
-};
-
/* This is true except if cfun->stdarg -- i.e. we cannot do
this for vararg functions because they play games with the frame. */
static bool stores_off_frame_dead_at_return;
/* Counter for stats. */
static int globally_deleted;
static int locally_deleted;
-static int spill_deleted;
static bitmap all_blocks;
/* The number of bits used in the global bitmaps. */
static unsigned int current_position;
+
+/* Print offset range [OFFSET, OFFSET + WIDTH) to FILE. */
+
+static void
+print_range (FILE *file, poly_int64 offset, poly_int64 width)
+{
+ fprintf (file, "[");
+ print_dec (offset, file, SIGNED);
+ fprintf (file, "..");
+ print_dec (offset + width, file, SIGNED);
+ fprintf (file, ")");
+}
\f
/*----------------------------------------------------------------------------
Zeroth step.
----------------------------------------------------------------------------*/
-/* Find the entry associated with ALIAS_SET. */
-
-static struct clear_alias_mode_holder *
-clear_alias_set_lookup (alias_set_type alias_set)
-{
- struct clear_alias_mode_holder tmp_holder;
- void **slot;
-
- tmp_holder.alias_set = alias_set;
- slot = htab_find_slot (clear_alias_mode_table, &tmp_holder, NO_INSERT);
- gcc_assert (*slot);
-
- return (struct clear_alias_mode_holder *) *slot;
-}
-
-
/* Hashtable callbacks for maintaining the "bases" field of
store_group_info, given that the addresses are function invariants. */
group_info *gi;
group_info **slot;
- if (base)
- {
- /* Find the store_base_info structure for BASE, creating a new one
- if necessary. */
- tmp_gi.rtx_base = base;
- slot = rtx_group_table->find_slot (&tmp_gi, INSERT);
- gi = *slot;
- }
- else
- {
- if (!clear_alias_group)
- {
- clear_alias_group = gi = group_info_pool.allocate ();
- memset (gi, 0, sizeof (struct group_info));
- gi->id = rtx_group_next_id++;
- gi->store1_n = BITMAP_ALLOC (&dse_bitmap_obstack);
- gi->store1_p = BITMAP_ALLOC (&dse_bitmap_obstack);
- gi->store2_n = BITMAP_ALLOC (&dse_bitmap_obstack);
- gi->store2_p = BITMAP_ALLOC (&dse_bitmap_obstack);
- gi->escaped_p = BITMAP_ALLOC (&dse_bitmap_obstack);
- gi->escaped_n = BITMAP_ALLOC (&dse_bitmap_obstack);
- gi->group_kill = BITMAP_ALLOC (&dse_bitmap_obstack);
- gi->process_globally = false;
- gi->offset_map_size_n = 0;
- gi->offset_map_size_p = 0;
- gi->offset_map_n = NULL;
- gi->offset_map_p = NULL;
- rtx_group_vec.safe_push (gi);
- }
- return clear_alias_group;
- }
+ gcc_assert (base != NULL_RTX);
+
+ /* Find the store_base_info structure for BASE, creating a new one
+ if necessary. */
+ tmp_gi.rtx_base = base;
+ slot = rtx_group_table->find_slot (&tmp_gi, INSERT);
+ gi = *slot;
if (gi == NULL)
{
{
locally_deleted = 0;
globally_deleted = 0;
- spill_deleted = 0;
bitmap_obstack_initialize (&dse_bitmap_obstack);
gcc_obstack_init (&dse_obstack);
stores_off_frame_dead_at_return = !cfun->stdarg;
init_alias_analysis ();
-
- clear_alias_group = NULL;
}
for (cur = new_insn; cur; cur = NEXT_INSN (cur))
{
info.current = cur;
- note_stores (PATTERN (cur), note_add_store, &info);
+ note_stores (cur, note_add_store, &info);
}
/* If a failure was flagged above, return 1 so that for_each_inc_dec will
if (note)
return for_each_inc_dec (PATTERN (insn), emit_inc_dec_insn_before,
insn_info) == 0;
+
+ /* Punt on stack pushes, those don't have REG_INC notes and we are
+ unprepared to deal with distribution of REG_ARGS_SIZE notes etc. */
+ subrtx_iterator::array_type array;
+ FOR_EACH_SUBRTX (iter, array, PATTERN (insn), NONCONST)
+ {
+ const_rtx x = *iter;
+ if (GET_RTX_CLASS (GET_CODE (x)) == RTX_AUTOINC)
+ return false;
+ }
+
return true;
}
if (note)
return for_each_inc_dec (PATTERN (insn), emit_inc_dec_insn_before,
&insn_info) == 0;
+
+ /* Punt on stack pushes, those don't have REG_INC notes and we are
+ unprepared to deal with distribution of REG_ARGS_SIZE notes etc. */
+ subrtx_iterator::array_type array;
+ FOR_EACH_SUBRTX (iter, array, PATTERN (insn), NONCONST)
+ {
+ const_rtx x = *iter;
+ if (GET_RTX_CLASS (GET_CODE (x)) == RTX_AUTOINC)
+ return false;
+ }
+
return true;
}
if (!check_for_inc_dec_1 (insn_info))
return;
if (dump_file && (dump_flags & TDF_DETAILS))
- {
- fprintf (dump_file, "Locally deleting insn %d ",
- INSN_UID (insn_info->insn));
- if (insn_info->store_rec->alias_set)
- fprintf (dump_file, "alias set %d\n",
- (int) insn_info->store_rec->alias_set);
- else
- fprintf (dump_file, "\n");
- }
+ fprintf (dump_file, "Locally deleting insn %d\n",
+ INSN_UID (insn_info->insn));
free_store_info (insn_info);
read_info = insn_info->read_rec;
base = get_base_address (expr);
if (DECL_P (base)
&& !may_be_aliased (base)
- && !(TREE_CODE (base) == VAR_DECL
+ && !(VAR_P (base)
&& !DECL_EXTERNAL (base)
&& !TREE_STATIC (base)
&& local_variable_can_escape (base)))
OFFSET and WIDTH. */
static void
-set_usage_bits (group_info *group, HOST_WIDE_INT offset, HOST_WIDE_INT width,
+set_usage_bits (group_info *group, poly_int64 offset, poly_int64 width,
tree expr)
{
- HOST_WIDE_INT i;
+ /* Non-constant offsets and widths act as global kills, so there's no point
+ trying to use them to derive global DSE candidates. */
+ HOST_WIDE_INT i, const_offset, const_width;
bool expr_escapes = can_escape (expr);
- if (offset > -MAX_OFFSET && offset + width < MAX_OFFSET)
- for (i=offset; i<offset+width; i++)
+ if (offset.is_constant (&const_offset)
+ && width.is_constant (&const_width)
+ && const_offset > -MAX_OFFSET
+ && const_offset + const_width < MAX_OFFSET)
+ for (i = const_offset; i < const_offset + const_width; ++i)
{
bitmap store1;
bitmap store2;
while (*ptr)
{
read_info_t next = (*ptr)->next;
- if ((*ptr)->alias_set == 0)
- {
- read_info_type_pool.remove (*ptr);
- *ptr = next;
- }
- else
- ptr = &(*ptr)->next;
+ read_info_type_pool.remove (*ptr);
+ *ptr = next;
}
}
static bool
canon_address (rtx mem,
- alias_set_type *alias_set_out,
int *group_id,
- HOST_WIDE_INT *offset,
+ poly_int64 *offset,
cselib_val **base)
{
machine_mode address_mode = get_address_mode (mem);
rtx expanded_address, address;
int expanded;
- *alias_set_out = 0;
-
cselib_lookup (mem_address, address_mode, 1, GET_MODE (mem));
if (dump_file && (dump_flags & TDF_DETAILS))
if (GET_CODE (address) == CONST)
address = XEXP (address, 0);
- if (GET_CODE (address) == PLUS
- && CONST_INT_P (XEXP (address, 1)))
- {
- *offset = INTVAL (XEXP (address, 1));
- address = XEXP (address, 0);
- }
+ address = strip_offset_and_add (address, offset);
if (ADDR_SPACE_GENERIC_P (MEM_ADDR_SPACE (mem))
&& const_or_frame_p (address))
group_info *group = get_group_info (address);
if (dump_file && (dump_flags & TDF_DETAILS))
- fprintf (dump_file, " gid=%d offset=%d \n",
- group->id, (int)*offset);
+ {
+ fprintf (dump_file, " gid=%d offset=", group->id);
+ print_dec (*offset, dump_file);
+ fprintf (dump_file, "\n");
+ }
*base = NULL;
*group_id = group->id;
return true;
return false;
}
if (dump_file && (dump_flags & TDF_DETAILS))
- fprintf (dump_file, " varying cselib base=%u:%u offset = %d\n",
- (*base)->uid, (*base)->hash, (int)*offset);
+ {
+ fprintf (dump_file, " varying cselib base=%u:%u offset = ",
+ (*base)->uid, (*base)->hash);
+ print_dec (*offset, dump_file);
+ fprintf (dump_file, "\n");
+ }
return true;
}
}
else
s_info->positions_needed.small_bitmask
- &= ~(((unsigned HOST_WIDE_INT) 1) << pos);
+ &= ~(HOST_WIDE_INT_1U << pos);
}
/* Mark the whole store S_INFO as unneeded. */
{
if (__builtin_expect (s_info->is_large, false))
{
- int pos, end = s_info->end - s_info->begin;
- for (pos = 0; pos < end; pos++)
- bitmap_set_bit (s_info->positions_needed.large.bmap, pos);
- s_info->positions_needed.large.count = end;
+ HOST_WIDE_INT width;
+ if (s_info->width.is_constant (&width))
+ {
+ bitmap_set_range (s_info->positions_needed.large.bmap, 0, width);
+ s_info->positions_needed.large.count = width;
+ }
+ else
+ {
+ gcc_checking_assert (!s_info->positions_needed.large.bmap);
+ s_info->positions_needed.large.count = 1;
+ }
}
else
- s_info->positions_needed.small_bitmask = (unsigned HOST_WIDE_INT) 0;
+ s_info->positions_needed.small_bitmask = HOST_WIDE_INT_0U;
}
/* Return TRUE if any bytes from S_INFO store are needed. */
any_positions_needed_p (store_info *s_info)
{
if (__builtin_expect (s_info->is_large, false))
- return (s_info->positions_needed.large.count
- < s_info->end - s_info->begin);
+ {
+ HOST_WIDE_INT width;
+ if (s_info->width.is_constant (&width))
+ {
+ gcc_checking_assert (s_info->positions_needed.large.bmap);
+ return s_info->positions_needed.large.count < width;
+ }
+ else
+ {
+ gcc_checking_assert (!s_info->positions_needed.large.bmap);
+ return s_info->positions_needed.large.count == 0;
+ }
+ }
else
- return (s_info->positions_needed.small_bitmask
- != (unsigned HOST_WIDE_INT) 0);
+ return (s_info->positions_needed.small_bitmask != HOST_WIDE_INT_0U);
}
/* Return TRUE if all bytes START through START+WIDTH-1 from S_INFO
- store are needed. */
+ store are known to be needed. */
static inline bool
-all_positions_needed_p (store_info *s_info, int start, int width)
+all_positions_needed_p (store_info *s_info, poly_int64 start,
+ poly_int64 width)
{
+ gcc_assert (s_info->rhs);
+ if (!s_info->width.is_constant ())
+ {
+ gcc_assert (s_info->is_large
+ && !s_info->positions_needed.large.bmap);
+ return s_info->positions_needed.large.count == 0;
+ }
+
+ /* Otherwise, if START and WIDTH are non-constant, we're asking about
+ a non-constant region of a constant-sized store. We can't say for
+ sure that all positions are needed. */
+ HOST_WIDE_INT const_start, const_width;
+ if (!start.is_constant (&const_start)
+ || !width.is_constant (&const_width))
+ return false;
+
if (__builtin_expect (s_info->is_large, false))
{
- int end = start + width;
- while (start < end)
- if (bitmap_bit_p (s_info->positions_needed.large.bmap, start++))
+ for (HOST_WIDE_INT i = const_start; i < const_start + const_width; ++i)
+ if (bitmap_bit_p (s_info->positions_needed.large.bmap, i))
return false;
return true;
}
else
{
- unsigned HOST_WIDE_INT mask = lowpart_bitmask (width) << start;
+ unsigned HOST_WIDE_INT mask
+ = lowpart_bitmask (const_width) << const_start;
return (s_info->positions_needed.small_bitmask & mask) == mask;
}
}
-static rtx get_stored_val (store_info *, machine_mode, HOST_WIDE_INT,
- HOST_WIDE_INT, basic_block, bool);
+static rtx get_stored_val (store_info *, machine_mode, poly_int64,
+ poly_int64, basic_block, bool);
/* BODY is an instruction pattern that belongs to INSN. Return 1 if
record_store (rtx body, bb_info_t bb_info)
{
rtx mem, rhs, const_rhs, mem_addr;
- HOST_WIDE_INT offset = 0;
- HOST_WIDE_INT width = 0;
- alias_set_type spill_alias_set;
+ poly_int64 offset = 0;
+ poly_int64 width = 0;
insn_info_t insn_info = bb_info->last_insn;
store_info *store_info = NULL;
int group_id;
/* At this point we know mem is a mem. */
if (GET_MODE (mem) == BLKmode)
{
+ HOST_WIDE_INT const_size;
if (GET_CODE (XEXP (mem, 0)) == SCRATCH)
{
if (dump_file && (dump_flags & TDF_DETAILS))
/* Handle (set (mem:BLK (addr) [... S36 ...]) (const_int 0))
as memset (addr, 0, 36); */
else if (!MEM_SIZE_KNOWN_P (mem)
- || MEM_SIZE (mem) <= 0
- || MEM_SIZE (mem) > MAX_OFFSET
+ || maybe_le (MEM_SIZE (mem), 0)
+ /* This is a limit on the bitmap size, which is only relevant
+ for constant-sized MEMs. */
+ || (MEM_SIZE (mem).is_constant (&const_size)
+ && const_size > MAX_OFFSET)
|| GET_CODE (body) != SET
|| !CONST_INT_P (SET_SRC (body)))
{
if (MEM_VOLATILE_P (mem))
insn_info->cannot_delete = true;
- if (!canon_address (mem, &spill_alias_set, &group_id, &offset, &base))
+ if (!canon_address (mem, &group_id, &offset, &base))
{
clear_rhs_from_active_local_stores ();
return 0;
else
width = GET_MODE_SIZE (GET_MODE (mem));
- if (spill_alias_set)
+ if (!endpoint_representable_p (offset, width))
{
- bitmap store1 = clear_alias_group->store1_p;
- bitmap store2 = clear_alias_group->store2_p;
-
- gcc_assert (GET_MODE (mem) != BLKmode);
-
- if (!bitmap_set_bit (store1, spill_alias_set))
- bitmap_set_bit (store2, spill_alias_set);
-
- if (clear_alias_group->offset_map_size_p < spill_alias_set)
- clear_alias_group->offset_map_size_p = spill_alias_set;
+ clear_rhs_from_active_local_stores ();
+ return 0;
+ }
- store_info = rtx_store_info_pool.allocate ();
+ if (known_eq (width, 0))
+ return 0;
- if (dump_file && (dump_flags & TDF_DETAILS))
- fprintf (dump_file, " processing spill store %d(%s)\n",
- (int) spill_alias_set, GET_MODE_NAME (GET_MODE (mem)));
- }
- else if (group_id >= 0)
+ if (group_id >= 0)
{
/* In the restrictive case where the base is a constant or the
frame pointer we can do global analysis. */
set_usage_bits (group, offset, width, expr);
if (dump_file && (dump_flags & TDF_DETAILS))
- fprintf (dump_file, " processing const base store gid=%d[%d..%d)\n",
- group_id, (int)offset, (int)(offset+width));
+ {
+ fprintf (dump_file, " processing const base store gid=%d",
+ group_id);
+ print_range (dump_file, offset, width);
+ fprintf (dump_file, "\n");
+ }
}
else
{
group_id = -1;
if (dump_file && (dump_flags & TDF_DETAILS))
- fprintf (dump_file, " processing cselib store [%d..%d)\n",
- (int)offset, (int)(offset+width));
+ {
+ fprintf (dump_file, " processing cselib store ");
+ print_range (dump_file, offset, width);
+ fprintf (dump_file, "\n");
+ }
}
const_rhs = rhs = NULL_RTX;
last = NULL;
redundant_reason = NULL;
mem = canon_rtx (mem);
- /* For alias_set != 0 canon_true_dependence should be never called. */
- if (spill_alias_set)
- mem_addr = NULL_RTX;
+
+ if (group_id < 0)
+ mem_addr = base->val_rtx;
else
{
- if (group_id < 0)
- mem_addr = base->val_rtx;
- else
- {
- group_info *group = rtx_group_vec[group_id];
- mem_addr = group->canon_base_addr;
- }
- if (offset)
- mem_addr = plus_constant (get_address_mode (mem), mem_addr, offset);
+ group_info *group = rtx_group_vec[group_id];
+ mem_addr = group->canon_base_addr;
}
+ if (maybe_ne (offset, 0))
+ mem_addr = plus_constant (get_address_mode (mem), mem_addr, offset);
while (ptr)
{
insn_info_t next = ptr->next_local_store;
- struct store_info *s_info = ptr->store_rec;
+ class store_info *s_info = ptr->store_rec;
bool del = true;
/* Skip the clobbers. We delete the active insn if this insn
while (!s_info->is_set)
s_info = s_info->next;
- if (s_info->alias_set != spill_alias_set)
- del = false;
- else if (s_info->alias_set)
- {
- struct clear_alias_mode_holder *entry
- = clear_alias_set_lookup (s_info->alias_set);
- /* Generally, spills cannot be processed if and of the
- references to the slot have a different mode. But if
- we are in the same block and mode is exactly the same
- between this store and one before in the same block,
- we can still delete it. */
- if ((GET_MODE (mem) == GET_MODE (s_info->mem))
- && (GET_MODE (mem) == entry->mode))
- {
- del = true;
- set_all_positions_unneeded (s_info);
- }
- if (dump_file && (dump_flags & TDF_DETAILS))
- fprintf (dump_file, " trying spill store in insn=%d alias_set=%d\n",
- INSN_UID (ptr->insn), (int) s_info->alias_set);
- }
- else if ((s_info->group_id == group_id)
- && (s_info->cse_base == base))
+ if (s_info->group_id == group_id && s_info->cse_base == base)
{
HOST_WIDE_INT i;
if (dump_file && (dump_flags & TDF_DETAILS))
- fprintf (dump_file, " trying store in insn=%d gid=%d[%d..%d)\n",
- INSN_UID (ptr->insn), s_info->group_id,
- (int)s_info->begin, (int)s_info->end);
+ {
+ fprintf (dump_file, " trying store in insn=%d gid=%d",
+ INSN_UID (ptr->insn), s_info->group_id);
+ print_range (dump_file, s_info->offset, s_info->width);
+ fprintf (dump_file, "\n");
+ }
/* Even if PTR won't be eliminated as unneeded, if both
PTR and this insn store the same constant value, we might
eliminate this insn instead. */
if (s_info->const_rhs
&& const_rhs
- && offset >= s_info->begin
- && offset + width <= s_info->end
- && all_positions_needed_p (s_info, offset - s_info->begin,
- width))
+ && known_subrange_p (offset, width,
+ s_info->offset, s_info->width)
+ && all_positions_needed_p (s_info, offset - s_info->offset,
+ width)
+ /* We can only remove the later store if the earlier aliases
+ at least all accesses the later one. */
+ && ((MEM_ALIAS_SET (mem) == MEM_ALIAS_SET (s_info->mem)
+ || alias_set_subset_of (MEM_ALIAS_SET (mem),
+ MEM_ALIAS_SET (s_info->mem)))
+ && (!MEM_EXPR (s_info->mem)
+ || refs_same_for_tbaa_p (MEM_EXPR (s_info->mem),
+ MEM_EXPR (mem)))))
{
if (GET_MODE (mem) == BLKmode)
{
{
rtx val;
start_sequence ();
- val = get_stored_val (s_info, GET_MODE (mem),
- offset, offset + width,
+ val = get_stored_val (s_info, GET_MODE (mem), offset, width,
BLOCK_FOR_INSN (insn_info->insn),
true);
if (get_insns () != NULL)
}
}
- for (i = MAX (offset, s_info->begin);
- i < offset + width && i < s_info->end;
- i++)
- set_position_unneeded (s_info, i - s_info->begin);
+ HOST_WIDE_INT begin_unneeded, const_s_width, const_width;
+ if (known_subrange_p (s_info->offset, s_info->width, offset, width))
+ /* The new store touches every byte that S_INFO does. */
+ set_all_positions_unneeded (s_info);
+ else if ((offset - s_info->offset).is_constant (&begin_unneeded)
+ && s_info->width.is_constant (&const_s_width)
+ && width.is_constant (&const_width))
+ {
+ HOST_WIDE_INT end_unneeded = begin_unneeded + const_width;
+ begin_unneeded = MAX (begin_unneeded, 0);
+ end_unneeded = MIN (end_unneeded, const_s_width);
+ for (i = begin_unneeded; i < end_unneeded; ++i)
+ set_position_unneeded (s_info, i);
+ }
+ else
+ {
+ /* We don't know which parts of S_INFO are needed and
+ which aren't, so invalidate the RHS. */
+ s_info->rhs = NULL;
+ s_info->const_rhs = NULL;
+ }
}
else if (s_info->rhs)
/* Need to see if it is possible for this store to overwrite
store_info->next = insn_info->store_rec;
insn_info->store_rec = store_info;
store_info->mem = mem;
- store_info->alias_set = spill_alias_set;
store_info->mem_addr = mem_addr;
store_info->cse_base = base;
- if (width > HOST_BITS_PER_WIDE_INT)
+ HOST_WIDE_INT const_width;
+ if (!width.is_constant (&const_width))
+ {
+ store_info->is_large = true;
+ store_info->positions_needed.large.count = 0;
+ store_info->positions_needed.large.bmap = NULL;
+ }
+ else if (const_width > HOST_BITS_PER_WIDE_INT)
{
store_info->is_large = true;
store_info->positions_needed.large.count = 0;
else
{
store_info->is_large = false;
- store_info->positions_needed.small_bitmask = lowpart_bitmask (width);
+ store_info->positions_needed.small_bitmask
+ = lowpart_bitmask (const_width);
}
store_info->group_id = group_id;
- store_info->begin = offset;
- store_info->end = offset + width;
+ store_info->offset = offset;
+ store_info->width = width;
store_info->is_set = GET_CODE (body) == SET;
store_info->rhs = rhs;
store_info->const_rhs = const_rhs;
shift. */
static rtx
-find_shift_sequence (int access_size,
+find_shift_sequence (poly_int64 access_size,
store_info *store_info,
machine_mode read_mode,
- int shift, bool speed, bool require_cst)
+ poly_int64 shift, bool speed, bool require_cst)
{
machine_mode store_mode = GET_MODE (store_info->mem);
- machine_mode new_mode;
+ scalar_int_mode new_mode;
rtx read_reg = NULL;
/* Some machines like the x86 have shift insns for each size of
justify the value we want to read but is available in one insn on
the machine. */
- 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))
+ opt_scalar_int_mode new_mode_iter;
+ FOR_EACH_MODE_FROM (new_mode_iter,
+ smallest_int_mode_for_size (access_size * BITS_PER_UNIT))
{
rtx target, new_reg, new_lhs;
rtx_insn *shift_seq, *insn;
int cost;
+ new_mode = new_mode_iter.require ();
+ if (GET_MODE_BITSIZE (new_mode) > BITS_PER_WORD)
+ break;
+
/* If a constant was stored into memory, try to simplify it here,
otherwise the cost of the shift might preclude this optimization
e.g. at -Os, even when no actual shift will be needed. */
if (store_info->const_rhs)
{
- unsigned int byte = subreg_lowpart_offset (new_mode, store_mode);
+ poly_uint64 byte = subreg_lowpart_offset (new_mode, store_mode);
rtx ret = simplify_subreg (new_mode, store_info->const_rhs,
store_mode, byte);
if (ret && CONSTANT_P (ret))
{
+ rtx shift_rtx = gen_int_shift_amount (new_mode, shift);
ret = simplify_const_binary_operation (LSHIFTRT, new_mode,
- ret, GEN_INT (shift));
+ ret, shift_rtx);
if (ret && CONSTANT_P (ret))
{
byte = subreg_lowpart_offset (read_mode, new_mode);
/* 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)
+ if (maybe_lt (GET_MODE_SIZE (new_mode), GET_MODE_SIZE (store_mode))
&& !TRULY_NOOP_TRUNCATION_MODES_P (new_mode, store_mode))
continue;
/* 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))
+ && !targetm.modes_tieable_p (new_mode, store_mode))
continue;
new_reg = gen_reg_rtx (new_mode);
of one dsp where the cost of these two was not the same. But
this really is a rare case anyway. */
target = expand_binop (new_mode, lshr_optab, new_reg,
- GEN_INT (shift), new_reg, 1, OPTAB_DIRECT);
+ gen_int_shift_amount (new_mode, shift),
+ new_reg, 1, OPTAB_DIRECT);
shift_seq = get_insns ();
end_sequence ();
cost = 0;
for (insn = shift_seq; insn != NULL_RTX; insn = NEXT_INSN (insn))
if (INSN_P (insn))
- cost += insn_rtx_cost (PATTERN (insn), speed);
+ cost += insn_cost (insn, speed);
/* The computation up to here is essentially independent
of the arguments and could be precomputed. It may
}
/* Helper function for replace_read and record_store.
- Attempt to return a value stored in STORE_INFO, from READ_BEGIN
- to one before READ_END bytes read in READ_MODE. Return NULL
+ Attempt to return a value of mode READ_MODE stored in STORE_INFO,
+ consisting of READ_WIDTH bytes starting from READ_OFFSET. Return NULL
if not successful. If REQUIRE_CST is true, return always constant. */
static rtx
get_stored_val (store_info *store_info, machine_mode read_mode,
- HOST_WIDE_INT read_begin, HOST_WIDE_INT read_end,
+ poly_int64 read_offset, poly_int64 read_width,
basic_block bb, bool require_cst)
{
machine_mode store_mode = GET_MODE (store_info->mem);
- int shift;
- int access_size; /* In bytes. */
+ poly_int64 gap;
rtx read_reg;
/* 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. */
if (store_mode == BLKmode)
- shift = 0;
+ gap = 0;
else if (BYTES_BIG_ENDIAN)
- shift = store_info->end - read_end;
+ gap = ((store_info->offset + store_info->width)
+ - (read_offset + read_width));
else
- shift = read_begin - store_info->begin;
-
- access_size = shift + GET_MODE_SIZE (read_mode);
+ gap = read_offset - store_info->offset;
- /* From now on it is bits. */
- shift *= BITS_PER_UNIT;
-
- if (shift)
- read_reg = find_shift_sequence (access_size, store_info, read_mode, shift,
- optimize_bb_for_speed_p (bb),
- require_cst);
+ if (gap.is_constant () && maybe_ne (gap, 0))
+ {
+ poly_int64 shift = gap * BITS_PER_UNIT;
+ poly_int64 access_size = GET_MODE_SIZE (read_mode) + gap;
+ read_reg = find_shift_sequence (access_size, store_info, read_mode,
+ shift, optimize_bb_for_speed_p (bb),
+ require_cst);
+ }
else if (store_mode == BLKmode)
{
/* The store is a memset (addr, const_val, const_size). */
gcc_assert (CONST_INT_P (store_info->rhs));
- store_mode = int_mode_for_mode (read_mode);
- if (store_mode == BLKmode)
+ scalar_int_mode int_store_mode;
+ if (!int_mode_for_mode (read_mode).exists (&int_store_mode))
read_reg = NULL_RTX;
else if (store_info->rhs == const0_rtx)
- read_reg = extract_low_bits (read_mode, store_mode, const0_rtx);
- else if (GET_MODE_BITSIZE (store_mode) > HOST_BITS_PER_WIDE_INT
+ read_reg = extract_low_bits (read_mode, int_store_mode, const0_rtx);
+ else if (GET_MODE_BITSIZE (int_store_mode) > HOST_BITS_PER_WIDE_INT
|| BITS_PER_UNIT >= HOST_BITS_PER_WIDE_INT)
read_reg = NULL_RTX;
else
{
unsigned HOST_WIDE_INT c
= INTVAL (store_info->rhs)
- & (((HOST_WIDE_INT) 1 << BITS_PER_UNIT) - 1);
+ & ((HOST_WIDE_INT_1 << BITS_PER_UNIT) - 1);
int shift = BITS_PER_UNIT;
while (shift < HOST_BITS_PER_WIDE_INT)
{
c |= (c << shift);
shift <<= 1;
}
- read_reg = gen_int_mode (c, store_mode);
- read_reg = extract_low_bits (read_mode, store_mode, read_reg);
+ read_reg = gen_int_mode (c, int_store_mode);
+ read_reg = extract_low_bits (read_mode, int_store_mode, read_reg);
}
}
else if (store_info->const_rhs
start_sequence ();
bb = BLOCK_FOR_INSN (read_insn->insn);
read_reg = get_stored_val (store_info,
- read_mode, read_info->begin, read_info->end,
+ read_mode, read_info->offset, read_info->width,
bb, false);
if (read_reg == NULL_RTX)
{
point. This does occasionally happen, see PR 37922. */
bitmap regs_set = BITMAP_ALLOC (®_obstack);
- for (this_insn = insns; this_insn != NULL_RTX; this_insn = NEXT_INSN (this_insn))
- note_stores (PATTERN (this_insn), look_for_hardregs, regs_set);
+ for (this_insn = insns;
+ this_insn != NULL_RTX; this_insn = NEXT_INSN (this_insn))
+ {
+ if (insn_invalid_p (this_insn, false))
+ {
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ fprintf (dump_file, " -- replacing the loaded MEM with ");
+ print_simple_rtl (dump_file, read_reg);
+ fprintf (dump_file, " led to an invalid instruction\n");
+ }
+ BITMAP_FREE (regs_set);
+ return false;
+ }
+ note_stores (this_insn, look_for_hardregs, regs_set);
+ }
bitmap_and_into (regs_set, regs_live);
if (!bitmap_empty_p (regs_set))
{
if (dump_file && (dump_flags & TDF_DETAILS))
{
- fprintf (dump_file,
- "abandoning replacement because sequence clobbers live hardregs:");
+ fprintf (dump_file, "abandoning replacement because sequence "
+ "clobbers live hardregs:");
df_print_regset (dump_file, regs_set);
}
BITMAP_FREE (regs_set);
}
+ subrtx_iterator::array_type array;
+ FOR_EACH_SUBRTX (iter, array, *loc, NONCONST)
+ {
+ const_rtx x = *iter;
+ if (GET_RTX_CLASS (GET_CODE (x)) == RTX_AUTOINC)
+ {
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ fprintf (dump_file, " -- replacing the MEM failed due to address "
+ "side-effects\n");
+ return false;
+ }
+ }
+
if (validate_change (read_insn->insn, loc, read_reg, 0))
{
deferred_change *change = deferred_change_pool.allocate ();
{
rtx mem = *loc, mem_addr;
insn_info_t insn_info;
- HOST_WIDE_INT offset = 0;
- HOST_WIDE_INT width = 0;
- alias_set_type spill_alias_set = 0;
+ poly_int64 offset = 0;
+ poly_int64 width = 0;
cselib_val *base = NULL;
int group_id;
read_info_t read_info;
insn_info = bb_info->last_insn;
if ((MEM_ALIAS_SET (mem) == ALIAS_SET_MEMORY_BARRIER)
- || (MEM_VOLATILE_P (mem)))
+ || MEM_VOLATILE_P (mem))
{
+ if (crtl->stack_protect_guard
+ && (MEM_EXPR (mem) == crtl->stack_protect_guard
+ || (crtl->stack_protect_guard_decl
+ && MEM_EXPR (mem) == crtl->stack_protect_guard_decl))
+ && MEM_VOLATILE_P (mem))
+ {
+ /* This is either the stack protector canary on the stack,
+ which ought to be written by a MEM_VOLATILE_P store and
+ thus shouldn't be deleted and is read at the very end of
+ function, but shouldn't conflict with any other store.
+ Or it is __stack_chk_guard variable or TLS or whatever else
+ MEM holding the canary value, which really shouldn't be
+ ever modified in -fstack-protector* protected functions,
+ otherwise the prologue store wouldn't match the epilogue
+ check. */
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ fprintf (dump_file, " stack protector canary read ignored.\n");
+ insn_info->cannot_delete = true;
+ return;
+ }
+
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, " adding wild read, volatile or barrier.\n");
add_wild_read (bb_info);
if (MEM_READONLY_P (mem))
return;
- if (!canon_address (mem, &spill_alias_set, &group_id, &offset, &base))
+ if (!canon_address (mem, &group_id, &offset, &base))
{
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, " adding wild read, canon_address failure.\n");
else
width = GET_MODE_SIZE (GET_MODE (mem));
+ if (!endpoint_representable_p (offset, known_eq (width, -1) ? 1 : width))
+ {
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ fprintf (dump_file, " adding wild read, due to overflow.\n");
+ add_wild_read (bb_info);
+ return;
+ }
+
read_info = read_info_type_pool.allocate ();
read_info->group_id = group_id;
read_info->mem = mem;
- read_info->alias_set = spill_alias_set;
- read_info->begin = offset;
- read_info->end = offset + width;
+ read_info->offset = offset;
+ read_info->width = width;
read_info->next = insn_info->read_rec;
insn_info->read_rec = read_info;
- /* For alias_set != 0 canon_true_dependence should be never called. */
- if (spill_alias_set)
- mem_addr = NULL_RTX;
+ if (group_id < 0)
+ mem_addr = base->val_rtx;
else
{
- if (group_id < 0)
- mem_addr = base->val_rtx;
- else
- {
- group_info *group = rtx_group_vec[group_id];
- mem_addr = group->canon_base_addr;
- }
- if (offset)
- mem_addr = plus_constant (get_address_mode (mem), mem_addr, offset);
+ group_info *group = rtx_group_vec[group_id];
+ mem_addr = group->canon_base_addr;
}
+ if (maybe_ne (offset, 0))
+ mem_addr = plus_constant (get_address_mode (mem), mem_addr, offset);
- /* We ignore the clobbers in store_info. The is mildly aggressive,
- but there really should not be a clobber followed by a read. */
-
- if (spill_alias_set)
- {
- insn_info_t i_ptr = active_local_stores;
- insn_info_t last = NULL;
-
- if (dump_file && (dump_flags & TDF_DETAILS))
- fprintf (dump_file, " processing spill load %d\n",
- (int) spill_alias_set);
-
- while (i_ptr)
- {
- store_info *store_info = i_ptr->store_rec;
-
- /* Skip the clobbers. */
- while (!store_info->is_set)
- store_info = store_info->next;
-
- if (store_info->alias_set == spill_alias_set)
- {
- if (dump_file && (dump_flags & TDF_DETAILS))
- dump_insn_info ("removing from active", i_ptr);
-
- active_local_stores_len--;
- if (last)
- last->next_local_store = i_ptr->next_local_store;
- else
- active_local_stores = i_ptr->next_local_store;
- }
- else
- last = i_ptr;
- i_ptr = i_ptr->next_local_store;
- }
- }
- else if (group_id >= 0)
+ if (group_id >= 0)
{
/* This is the restricted case where the base is a constant or
the frame pointer and offset is a constant. */
if (dump_file && (dump_flags & TDF_DETAILS))
{
- if (width == -1)
+ if (!known_size_p (width))
fprintf (dump_file, " processing const load gid=%d[BLK]\n",
group_id);
else
- fprintf (dump_file, " processing const load gid=%d[%d..%d)\n",
- group_id, (int)offset, (int)(offset+width));
+ {
+ fprintf (dump_file, " processing const load gid=%d", group_id);
+ print_range (dump_file, offset, width);
+ fprintf (dump_file, "\n");
+ }
}
while (i_ptr)
{
/* This is a block mode load. We may get lucky and
canon_true_dependence may save the day. */
- if (width == -1)
+ if (!known_size_p (width))
remove
= canon_true_dependence (store_info->mem,
GET_MODE (store_info->mem),
else
{
if (store_info->rhs
- && offset >= store_info->begin
- && offset + width <= store_info->end
+ && known_subrange_p (offset, width, store_info->offset,
+ store_info->width)
&& all_positions_needed_p (store_info,
- offset - store_info->begin,
+ offset - store_info->offset,
width)
&& replace_read (store_info, i_ptr, read_info,
insn_info, loc, bb_info->regs_live))
return;
/* The bases are the same, just see if the offsets
- overlap. */
- if ((offset < store_info->end)
- && (offset + width > store_info->begin))
+ could overlap. */
+ if (ranges_maybe_overlap_p (offset, width,
+ store_info->offset,
+ store_info->width))
remove = true;
}
}
if (store_info->rhs
&& store_info->group_id == -1
&& store_info->cse_base == base
- && width != -1
- && offset >= store_info->begin
- && offset + width <= store_info->end
+ && known_subrange_p (offset, width, store_info->offset,
+ store_info->width)
&& all_positions_needed_p (store_info,
- offset - store_info->begin, width)
+ offset - store_info->offset, width)
&& replace_read (store_info, i_ptr, read_info, insn_info, loc,
bb_info->regs_live))
return;
- if (!store_info->alias_set)
- remove = canon_true_dependence (store_info->mem,
- GET_MODE (store_info->mem),
- store_info->mem_addr,
- mem, mem_addr);
+ remove = canon_true_dependence (store_info->mem,
+ GET_MODE (store_info->mem),
+ store_info->mem_addr,
+ mem, mem_addr);
if (remove)
{
arg != void_list_node && idx < nargs;
arg = TREE_CHAIN (arg), idx++)
{
- machine_mode mode = TYPE_MODE (TREE_VALUE (arg));
+ scalar_int_mode mode;
rtx reg, link, tmp;
- reg = targetm.calls.function_arg (args_so_far, mode, NULL_TREE, true);
- if (!reg || !REG_P (reg) || GET_MODE (reg) != mode
- || GET_MODE_CLASS (mode) != MODE_INT)
+
+ if (!is_int_mode (TYPE_MODE (TREE_VALUE (arg)), &mode))
+ return false;
+
+ function_arg_info arg (mode, /*named=*/true);
+ reg = targetm.calls.function_arg (args_so_far, arg);
+ if (!reg || !REG_P (reg) || GET_MODE (reg) != mode)
return false;
for (link = CALL_INSN_FUNCTION_USAGE (call_insn);
link = XEXP (link, 1))
if (GET_CODE (XEXP (link, 0)) == USE)
{
+ scalar_int_mode arg_mode;
args[idx] = XEXP (XEXP (link, 0), 0);
if (REG_P (args[idx])
&& REGNO (args[idx]) == REGNO (reg)
&& (GET_MODE (args[idx]) == mode
- || (GET_MODE_CLASS (GET_MODE (args[idx])) == MODE_INT
- && (GET_MODE_SIZE (GET_MODE (args[idx]))
- <= UNITS_PER_WORD)
- && (GET_MODE_SIZE (GET_MODE (args[idx]))
- > GET_MODE_SIZE (mode)))))
+ || (is_int_mode (GET_MODE (args[idx]), &arg_mode)
+ && (GET_MODE_SIZE (arg_mode) <= UNITS_PER_WORD)
+ && (GET_MODE_SIZE (arg_mode) > GET_MODE_SIZE (mode)))))
break;
}
if (!link)
if (tmp)
args[idx] = tmp;
- targetm.calls.function_arg_advance (args_so_far, mode, NULL_TREE, true);
+ targetm.calls.function_arg_advance (args_so_far, arg);
}
if (arg != void_list_node || idx != nargs)
return false;
bitmap ret;
ret = ALLOC_REG_SET (NULL);
- bitmap_and (ret, in, fixed_reg_set_regset);
+ bitmap_and (ret, in, bitmap_view<HARD_REG_SET> (fixed_reg_set));
return ret;
}
non-register target. */
static void
-scan_insn (bb_info_t bb_info, rtx_insn *insn)
+scan_insn (bb_info_t bb_info, rtx_insn *insn, int max_active_local_stores)
{
rtx body;
insn_info_type *insn_info = insn_info_type_pool.allocate ();
if (CALL_P (insn))
{
bool const_call;
+ rtx call, sym;
tree memset_call = NULL_TREE;
insn_info->cannot_delete = true;
been pushed onto the stack.
memset and bzero don't read memory either. */
const_call = RTL_CONST_CALL_P (insn);
- if (!const_call)
- {
- rtx call = get_call_rtx_from (insn);
- if (call && GET_CODE (XEXP (XEXP (call, 0), 0)) == SYMBOL_REF)
- {
- rtx symbol = XEXP (XEXP (call, 0), 0);
- if (SYMBOL_REF_DECL (symbol)
- && TREE_CODE (SYMBOL_REF_DECL (symbol)) == FUNCTION_DECL)
- {
- if ((DECL_BUILT_IN_CLASS (SYMBOL_REF_DECL (symbol))
- == BUILT_IN_NORMAL
- && (DECL_FUNCTION_CODE (SYMBOL_REF_DECL (symbol))
- == BUILT_IN_MEMSET))
- || SYMBOL_REF_DECL (symbol) == block_clear_fn)
- memset_call = SYMBOL_REF_DECL (symbol);
- }
- }
- }
+ if (!const_call
+ && (call = get_call_rtx_from (insn))
+ && (sym = XEXP (XEXP (call, 0), 0))
+ && GET_CODE (sym) == SYMBOL_REF
+ && SYMBOL_REF_DECL (sym)
+ && TREE_CODE (SYMBOL_REF_DECL (sym)) == FUNCTION_DECL
+ && fndecl_built_in_p (SYMBOL_REF_DECL (sym), BUILT_IN_MEMSET))
+ memset_call = SYMBOL_REF_DECL (sym);
+
if (const_call || memset_call)
{
insn_info_t i_ptr = active_local_stores;
fprintf (dump_file, "handling memset as BLKmode store\n");
if (mems_found == 1)
{
- if (active_local_stores_len++
- >= PARAM_VALUE (PARAM_MAX_DSE_ACTIVE_LOCAL_STORES))
+ if (active_local_stores_len++ >= max_active_local_stores)
{
active_local_stores_len = 1;
active_local_stores = NULL;
clear_rhs_from_active_local_stores ();
}
}
- else if (SIBLING_CALL_P (insn) && reload_completed)
+ else if (SIBLING_CALL_P (insn)
+ && (reload_completed || HARD_FRAME_POINTER_IS_ARG_POINTER))
/* Arguments for a sibling call that are pushed to memory are passed
using the incoming argument pointer of the current function. After
- reload that might be (and likely is) frame pointer based. */
+ reload that might be (and likely is) frame pointer based. And, if
+ it is a frame pointer on the target, even before reload we need to
+ kill frame pointer based stores. */
add_wild_read (bb_info);
else
/* Every other call, including pure functions, may read any memory
it as cannot delete. This simplifies the processing later. */
if (mems_found == 1)
{
- if (active_local_stores_len++
- >= PARAM_VALUE (PARAM_MAX_DSE_ACTIVE_LOCAL_STORES))
+ if (active_local_stores_len++ >= max_active_local_stores)
{
active_local_stores_len = 1;
active_local_stores = NULL;
bool del = false;
/* If ANY of the store_infos match the cselib group that is
- being deleted, then the insn can not be deleted. */
+ being deleted, then the insn cannot be deleted. */
while (store_info)
{
if ((store_info->group_id == -1)
bitmap_set_bit (all_blocks, ENTRY_BLOCK);
bitmap_set_bit (all_blocks, EXIT_BLOCK);
+ /* For -O1 reduce the maximum number of active local stores for RTL DSE
+ since this can consume huge amounts of memory (PR89115). */
+ int max_active_local_stores = param_max_dse_active_local_stores;
+ if (optimize < 2)
+ max_active_local_stores /= 10;
+
FOR_ALL_BB_FN (bb, cfun)
{
insn_info_t ptr;
FOR_BB_INSNS (bb, insn)
{
if (INSN_P (insn))
- scan_insn (bb_info, insn);
+ scan_insn (bb_info, insn, max_active_local_stores);
cselib_process_insn (insn);
if (INSN_P (insn))
df_simulate_one_insn_forwards (bb, insn, regs_live);
/* Skip the clobbers. */
while (!store_info->is_set)
store_info = store_info->next;
- if (store_info->alias_set && !i_ptr->cannot_delete)
- delete_dead_store_insn (i_ptr);
- else
- if (store_info->group_id >= 0)
- {
- group_info *group
- = rtx_group_vec[store_info->group_id];
- if (group->frame_related && !i_ptr->cannot_delete)
- delete_dead_store_insn (i_ptr);
- }
+ if (store_info->group_id >= 0)
+ {
+ group_info *group = rtx_group_vec[store_info->group_id];
+ if (group->frame_related && !i_ptr->cannot_delete)
+ delete_dead_store_insn (i_ptr);
+ }
i_ptr = i_ptr->next_local_store;
}
}
-/* Init the offset tables for the normal case. */
+/* Init the offset tables. */
static bool
-dse_step2_nospill (void)
+dse_step2 (void)
{
unsigned int i;
group_info *group;
bitmap_iterator bi;
unsigned int j;
- if (group == clear_alias_group)
- continue;
-
memset (group->offset_map_n, 0, sizeof (int) * group->offset_map_size_n);
memset (group->offset_map_p, 0, sizeof (int) * group->offset_map_size_p);
bitmap_clear (group->group_kill);
may be NULL. */
static void
-scan_stores_nospill (store_info *store_info, bitmap gen, bitmap kill)
+scan_stores (store_info *store_info, bitmap gen, bitmap kill)
{
while (store_info)
{
- HOST_WIDE_INT i;
+ HOST_WIDE_INT i, offset, width;
group_info *group_info
= rtx_group_vec[store_info->group_id];
- if (group_info->process_globally)
- for (i = store_info->begin; i < store_info->end; i++)
- {
- int index = get_bitmap_index (group_info, i);
- if (index != 0)
- {
- bitmap_set_bit (gen, index);
- if (kill)
- bitmap_clear_bit (kill, index);
- }
- }
- store_info = store_info->next;
- }
-}
-
-
-/* Process the STORE_INFOs into the bitmaps into GEN and KILL. KILL
- may be NULL. */
-
-static void
-scan_stores_spill (store_info *store_info, bitmap gen, bitmap kill)
-{
- while (store_info)
- {
- if (store_info->alias_set)
+ /* We can (conservatively) ignore stores whose bounds aren't known;
+ they simply don't generate new global dse opportunities. */
+ if (group_info->process_globally
+ && store_info->offset.is_constant (&offset)
+ && store_info->width.is_constant (&width))
{
- int index = get_bitmap_index (clear_alias_group,
- store_info->alias_set);
- if (index != 0)
+ HOST_WIDE_INT end = offset + width;
+ for (i = offset; i < end; i++)
{
- bitmap_set_bit (gen, index);
- if (kill)
- bitmap_clear_bit (kill, index);
+ int index = get_bitmap_index (group_info, i);
+ if (index != 0)
+ {
+ bitmap_set_bit (gen, index);
+ if (kill)
+ bitmap_clear_bit (kill, index);
+ }
}
}
store_info = store_info->next;
may be NULL. */
static void
-scan_reads_nospill (insn_info_t insn_info, bitmap gen, bitmap kill)
+scan_reads (insn_info_t insn_info, bitmap gen, bitmap kill)
{
read_info_t read_info = insn_info->read_rec;
int i;
{
if (i == read_info->group_id)
{
- if (read_info->begin > read_info->end)
+ HOST_WIDE_INT offset, width;
+ /* Reads with non-constant size kill all DSE opportunities
+ in the group. */
+ if (!read_info->offset.is_constant (&offset)
+ || !read_info->width.is_constant (&width)
+ || !known_size_p (width))
{
- /* Begin > end for block mode reads. */
+ /* Handle block mode reads. */
if (kill)
bitmap_ior_into (kill, group->group_kill);
bitmap_and_compl_into (gen, group->group_kill);
/* The groups are the same, just process the
offsets. */
HOST_WIDE_INT j;
- for (j = read_info->begin; j < read_info->end; j++)
+ HOST_WIDE_INT end = offset + width;
+ for (j = offset; j < end; j++)
{
int index = get_bitmap_index (group, j);
if (index != 0)
}
}
-/* Process the READ_INFOs into the bitmaps into GEN and KILL. KILL
- may be NULL. */
-
-static void
-scan_reads_spill (read_info_t read_info, bitmap gen, bitmap kill)
-{
- while (read_info)
- {
- if (read_info->alias_set)
- {
- int index = get_bitmap_index (clear_alias_group,
- read_info->alias_set);
- if (index != 0)
- {
- if (kill)
- bitmap_set_bit (kill, index);
- bitmap_clear_bit (gen, index);
- }
- }
-
- read_info = read_info->next;
- }
-}
-
/* Return the insn in BB_INFO before the first wild read or if there
are no wild reads in the block, return the last insn. */
anything that happens is hidden by the wild read. */
static void
-dse_step3_scan (bool for_spills, basic_block bb)
+dse_step3_scan (basic_block bb)
{
bb_info_t bb_info = bb_table[bb->index];
insn_info_t insn_info;
- if (for_spills)
- /* There are no wild reads in the spill case. */
- insn_info = bb_info->last_insn;
- else
- insn_info = find_insn_before_first_wild_read (bb_info);
+ insn_info = find_insn_before_first_wild_read (bb_info);
/* In the spill case or in the no_spill case if there is no wild
read in the block, we will need a kill set. */
this phase. */
if (insn_info->insn && INSN_P (insn_info->insn))
{
- /* Process the read(s) last. */
- if (for_spills)
- {
- scan_stores_spill (insn_info->store_rec, bb_info->gen, bb_info->kill);
- scan_reads_spill (insn_info->read_rec, bb_info->gen, bb_info->kill);
- }
- else
- {
- scan_stores_nospill (insn_info->store_rec, bb_info->gen, bb_info->kill);
- scan_reads_nospill (insn_info, bb_info->gen, bb_info->kill);
- }
+ scan_stores (insn_info->store_rec, bb_info->gen, bb_info->kill);
+ scan_reads (insn_info, bb_info->gen, bb_info->kill);
}
insn_info = insn_info->prev_insn;
/* Build the transfer functions for the function. */
static void
-dse_step3 (bool for_spills)
+dse_step3 ()
{
basic_block bb;
- sbitmap unreachable_blocks = sbitmap_alloc (last_basic_block_for_fn (cfun));
sbitmap_iterator sbi;
bitmap all_ones = NULL;
unsigned int i;
+ auto_sbitmap unreachable_blocks (last_basic_block_for_fn (cfun));
bitmap_ones (unreachable_blocks);
FOR_ALL_BB_FN (bb, cfun)
else if (bb->index == EXIT_BLOCK)
dse_step3_exit_block_scan (bb_info);
else
- dse_step3_scan (for_spills, bb);
+ dse_step3_scan (bb);
if (EDGE_COUNT (bb->succs) == 0)
mark_reachable_blocks (unreachable_blocks, bb);
if (all_ones)
BITMAP_FREE (all_ones);
- sbitmap_free (unreachable_blocks);
}
static void
-dse_step5_nospill (void)
+dse_step5 (void)
{
basic_block bb;
FOR_EACH_BB_FN (bb, cfun)
while (!store_info->is_set)
store_info = store_info->next;
- if (store_info->alias_set)
+ HOST_WIDE_INT i, offset, width;
+ group_info *group_info = rtx_group_vec[store_info->group_id];
+
+ if (!store_info->offset.is_constant (&offset)
+ || !store_info->width.is_constant (&width))
deleted = false;
else
{
- HOST_WIDE_INT i;
- group_info *group_info
- = rtx_group_vec[store_info->group_id];
-
- for (i = store_info->begin; i < store_info->end; i++)
+ HOST_WIDE_INT end = offset + width;
+ for (i = offset; i < end; i++)
{
int index = get_bitmap_index (group_info, i);
if (dump_file && (dump_flags & TDF_DETAILS))
- fprintf (dump_file, "i = %d, index = %d\n", (int)i, index);
+ fprintf (dump_file, "i = %d, index = %d\n",
+ (int) i, index);
if (index == 0 || !bitmap_bit_p (v, index))
{
if (dump_file && (dump_flags & TDF_DETAILS))
- fprintf (dump_file, "failing at i = %d\n", (int)i);
+ fprintf (dump_file, "failing at i = %d\n",
+ (int) i);
deleted = false;
break;
}
&& INSN_P (insn_info->insn)
&& (!deleted))
{
- scan_stores_nospill (insn_info->store_rec, v, NULL);
+ scan_stores (insn_info->store_rec, v, NULL);
if (insn_info->wild_read)
{
if (dump_file && (dump_flags & TDF_DETAILS))
bitmap_clear (v);
}
else if (insn_info->read_rec
- || insn_info->non_frame_wild_read)
+ || insn_info->non_frame_wild_read
+ || insn_info->frame_read)
{
- if (dump_file && !insn_info->non_frame_wild_read)
- fprintf (dump_file, "regular read\n");
- else if (dump_file && (dump_flags & TDF_DETAILS))
- fprintf (dump_file, "non-frame wild read\n");
- scan_reads_nospill (insn_info, v, NULL);
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ if (!insn_info->non_frame_wild_read
+ && !insn_info->frame_read)
+ fprintf (dump_file, "regular read\n");
+ if (insn_info->non_frame_wild_read)
+ fprintf (dump_file, "non-frame wild read\n");
+ if (insn_info->frame_read)
+ fprintf (dump_file, "frame read\n");
+ }
+ scan_reads (insn_info, v, NULL);
}
}
dse_step0 ();
dse_step1 ();
dse_step2_init ();
- if (dse_step2_nospill ())
+ if (dse_step2 ())
{
df_set_flags (DF_LR_RUN_DCE);
df_analyze ();
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "doing global processing\n");
- dse_step3 (false);
+ dse_step3 ();
dse_step4 ();
- dse_step5_nospill ();
+ dse_step5 ();
}
dse_step6 ();
dse_step7 ();
if (dump_file)
- fprintf (dump_file, "dse: local deletions = %d, global deletions = %d, spill deletions = %d\n",
- locally_deleted, globally_deleted, spill_deleted);
+ fprintf (dump_file, "dse: local deletions = %d, global deletions = %d\n",
+ locally_deleted, globally_deleted);
/* DSE can eliminate potentially-trapping MEMs.
Remove any EH edges associated with them. */
if ((locally_deleted || globally_deleted)
&& cfun->can_throw_non_call_exceptions
&& purge_all_dead_edges ())
- cleanup_cfg (0);
+ {
+ free_dominance_info (CDI_DOMINATORS);
+ cleanup_cfg (0);
+ }
return 0;
}