/* RTL dead store elimination.
- Copyright (C) 2005-2020 Free Software Foundation, Inc.
+ Copyright (C) 2005-2021 Free Software Foundation, Inc.
Contributed by Richard Sandiford <rsandifor@codesourcery.com>
and Kenneth Zadeck <zadeck@naturalbridge.com>
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;
}
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_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)
{
scalar_int_mode new_mode;
rtx read_reg = NULL;
+ /* 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)
+ {
+ auto new_mode = smallest_int_mode_for_size (access_size * BITS_PER_UNIT);
+ auto 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,
+ shift_rtx);
+ if (ret && CONSTANT_P (ret))
+ {
+ byte = subreg_lowpart_offset (read_mode, new_mode);
+ ret = simplify_subreg (read_mode, ret, new_mode, byte);
+ if (ret && CONSTANT_P (ret)
+ && (set_src_cost (ret, read_mode, speed)
+ <= COSTS_N_INSNS (1)))
+ return ret;
+ }
+ }
+ }
+
+ if (require_cst)
+ return NULL_RTX;
+
/* 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
shift insns that shift values within 32 or 64 bit registers.
the machine. */
opt_scalar_int_mode new_mode_iter;
- FOR_EACH_MODE_FROM (new_mode_iter,
- smallest_int_mode_for_size (access_size * BITS_PER_UNIT))
+ FOR_EACH_MODE_IN_CLASS (new_mode_iter, MODE_INT)
{
rtx target, new_reg, new_lhs;
rtx_insn *shift_seq, *insn;
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)
- {
- 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, shift_rtx);
- if (ret && CONSTANT_P (ret))
- {
- byte = subreg_lowpart_offset (read_mode, new_mode);
- ret = simplify_subreg (read_mode, ret, new_mode, byte);
- if (ret && CONSTANT_P (ret)
- && (set_src_cost (ret, read_mode, speed)
- <= COSTS_N_INSNS (1)))
- return ret;
- }
- }
- }
-
- if (require_cst)
- return NULL_RTX;
+ if (maybe_lt (GET_MODE_SIZE (new_mode), GET_MODE_SIZE (read_mode)))
+ continue;
/* Try a wider mode if truncating the store mode to NEW_MODE
requires a real instruction. */
&& !targetm.modes_tieable_p (new_mode, store_mode))
continue;
+ if (multiple_p (shift, GET_MODE_BITSIZE (new_mode))
+ && known_le (GET_MODE_SIZE (new_mode), GET_MODE_SIZE (store_mode)))
+ {
+ /* Try to implement the shift using a subreg. */
+ poly_int64 offset
+ = subreg_offset_from_lsb (new_mode, store_mode, shift);
+ rtx rhs_subreg = simplify_gen_subreg (new_mode, store_info->rhs,
+ store_mode, offset);
+ if (rhs_subreg)
+ {
+ read_reg
+ = extract_low_bits (read_mode, new_mode, copy_rtx (rhs_subreg));
+ break;
+ }
+ }
+
+ if (maybe_lt (GET_MODE_SIZE (new_mode), access_size))
+ continue;
+
new_reg = gen_reg_rtx (new_mode);
start_sequence ();
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 (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 ();