/* RTL-based forward propagation pass for GNU compiler.
- Copyright (C) 2005-2015 Free Software Foundation, Inc.
+ Copyright (C) 2005-2018 Free Software Foundation, Inc.
Contributed by Paolo Bonzini and Steven Bosscher.
This file is part of GCC.
#include "rtl.h"
#include "predict.h"
#include "df.h"
+#include "memmodel.h"
#include "tm_p.h"
#include "insn-config.h"
#include "emit-rtl.h"
static vec<df_ref> reg_defs;
static vec<df_ref> reg_defs_stack;
+/* The maximum number of propagations that are still allowed. If we do
+ more propagations than originally we had uses, we must have ended up
+ in a propagation loop, as in PR79405. Until the algorithm fwprop
+ uses can obviously not get into such loops we need a workaround like
+ this. */
+static int propagations_left;
+
/* The MD bitmaps are trimmed to include only live registers to cut
memory usage on testcases like insn-recog.c. Track live registers
in the basic block and do not perform forward propagation if the
public:
single_def_use_dom_walker (cdi_direction direction)
: dom_walker (direction) {}
- virtual void before_dom_children (basic_block);
+ virtual edge before_dom_children (basic_block);
virtual void after_dom_children (basic_block);
};
-void
+edge
single_def_use_dom_walker::before_dom_children (basic_block bb)
{
int bb_index = bb->index;
process_uses (df_get_artificial_uses (bb_index), 0);
process_defs (df_get_artificial_defs (bb_index), 0);
+
+ return NULL;
}
/* Pop the definitions created in this basic block when leaving its
{
case ASHIFT:
if (CONST_INT_P (XEXP (x, 1))
- && INTVAL (XEXP (x, 1)) < GET_MODE_BITSIZE (GET_MODE (x))
- && INTVAL (XEXP (x, 1)) >= 0)
+ && INTVAL (XEXP (x, 1)) < GET_MODE_UNIT_BITSIZE (GET_MODE (x))
+ && INTVAL (XEXP (x, 1)) >= 0)
{
HOST_WIDE_INT shift = INTVAL (XEXP (x, 1));
PUT_CODE (x, MULT);
- XEXP (x, 1) = gen_int_mode ((HOST_WIDE_INT) 1 << shift,
+ XEXP (x, 1) = gen_int_mode (HOST_WIDE_INT_1 << shift,
GET_MODE (x));
}
*px = tem;
+ /* Allow replacements that simplify operations on a vector or complex
+ value to a component. The most prominent case is
+ (subreg ([vec_]concat ...)). */
+ if (REG_P (tem) && !HARD_REGISTER_P (tem)
+ && (VECTOR_MODE_P (GET_MODE (new_rtx))
+ || COMPLEX_MODE_P (GET_MODE (new_rtx)))
+ && GET_MODE (tem) == GET_MODE_INNER (GET_MODE (new_rtx)))
+ return true;
+
/* The replacement we made so far is valid, if all of the recursive
replacements were valid, or we could simplify everything to
a constant. */
|| CONSTANT_P (new_rtx)
|| (GET_CODE (new_rtx) == SUBREG
&& REG_P (SUBREG_REG (new_rtx))
- && (GET_MODE_SIZE (mode)
- <= GET_MODE_SIZE (GET_MODE (SUBREG_REG (new_rtx))))))
+ && !paradoxical_subreg_p (mode, GET_MODE (SUBREG_REG (new_rtx)))))
flags |= PR_CAN_APPEAR;
if (!varying_mem_p (new_rtx))
flags |= PR_HANDLE_MEM;
if (DF_REF_ID (use) >= (int) use_def_ref.length ())
use_def_ref.safe_grow_cleared (DF_REF_ID (use) + 1);
- gcc_checking_assert (sparseset_bit_p (active_defs_check, regno));
+ if (flag_checking)
+ gcc_assert (sparseset_bit_p (active_defs_check, regno));
use_def_ref[DF_REF_ID (use)] = active_defs[regno];
}
}
making a new one if one does not already exist. */
if (set_reg_equal)
{
- if (dump_file)
- fprintf (dump_file, " Setting REG_EQUAL note\n");
+ /* If there are any paradoxical SUBREGs, don't add REG_EQUAL note,
+ because the bits in there can be anything and so might not
+ match the REG_EQUAL note content. See PR70574. */
+ subrtx_var_iterator::array_type array;
+ FOR_EACH_SUBRTX_VAR (iter, array, *loc, NONCONST)
+ {
+ rtx x = *iter;
+ if (SUBREG_P (x) && paradoxical_subreg_p (x))
+ {
+ set_reg_equal = false;
+ break;
+ }
+ }
- note = set_unique_reg_note (insn, REG_EQUAL, copy_rtx (new_rtx));
+ if (set_reg_equal)
+ {
+ if (dump_file)
+ fprintf (dump_file, " Setting REG_EQUAL note\n");
+
+ note = set_unique_reg_note (insn, REG_EQUAL, copy_rtx (new_rtx));
+ }
}
}
df_ref def, use;
reg = XEXP (src, 0);
-#ifdef LOAD_EXTEND_OP
- if (LOAD_EXTEND_OP (GET_MODE (reg)) != GET_CODE (src))
-#endif
+ if (load_extend_op (GET_MODE (reg)) != GET_CODE (src))
return false;
FOR_EACH_INSN_USE (use, insn)
rtx use_reg = DF_REF_REG (use);
rtx_insn *use_insn;
rtx src;
+ scalar_int_mode int_use_mode, src_mode;
/* Only consider subregs... */
machine_mode use_mode = GET_MODE (use_reg);
|| !REG_P (SET_DEST (def_set)))
return false;
- /* If this is a paradoxical SUBREG... */
- if (GET_MODE_SIZE (use_mode)
- > GET_MODE_SIZE (GET_MODE (SUBREG_REG (use_reg))))
+ if (paradoxical_subreg_p (use_reg))
{
/* If this is a paradoxical SUBREG, we have no idea what value the
extra bits would have. However, if the operand is equivalent to
definition of Y or, failing that, allow A to be deleted after
reload through register tying. Introducing more uses of Y
prevents both optimisations. */
- else if (subreg_lowpart_p (use_reg))
+ else if (is_a <scalar_int_mode> (use_mode, &int_use_mode)
+ && subreg_lowpart_p (use_reg))
{
use_insn = DF_REF_INSN (use);
src = SET_SRC (def_set);
if ((GET_CODE (src) == ZERO_EXTEND
|| GET_CODE (src) == SIGN_EXTEND)
+ && is_a <scalar_int_mode> (GET_MODE (src), &src_mode)
&& REG_P (XEXP (src, 0))
&& REGNO (XEXP (src, 0)) >= FIRST_PSEUDO_REGISTER
&& GET_MODE (XEXP (src, 0)) == use_mode
&& !free_load_extend (src, def_insn)
- && (targetm.mode_rep_extended (use_mode, GET_MODE (src))
+ && (targetm.mode_rep_extended (int_use_mode, src_mode)
!= (int) GET_CODE (src))
&& all_uses_available_at (def_insn, use_insn))
return try_fwprop_subst (use, DF_REF_LOC (use), XEXP (src, 0),
reg = DF_REF_REG (use);
if (GET_CODE (reg) == SUBREG && GET_CODE (SET_DEST (def_set)) == SUBREG)
{
- if (SUBREG_BYTE (SET_DEST (def_set)) != SUBREG_BYTE (reg))
+ if (maybe_ne (SUBREG_BYTE (SET_DEST (def_set)), SUBREG_BYTE (reg)))
return false;
}
/* Check if the def had a subreg, but the use has the whole reg. */
that isn't mentioned in USE_SET, as the note would be invalid
otherwise. We also don't want to install a note if we are merely
propagating a pseudo since verifying that this pseudo isn't dead
- is a pain; moreover such a note won't help anything. */
+ is a pain; moreover such a note won't help anything.
+ If the use is a paradoxical subreg, make sure we don't add a
+ REG_EQUAL note for it, because it is not equivalent, it is one
+ possible value for it, but we can't rely on it holding that value.
+ See PR70574. */
set_reg_equal = (note == NULL_RTX
&& REG_P (SET_DEST (use_set))
&& !REG_P (src)
&& !(GET_CODE (src) == SUBREG
&& REG_P (SUBREG_REG (src)))
&& !reg_mentioned_p (SET_DEST (use_set),
- SET_SRC (use_set)));
+ SET_SRC (use_set))
+ && !paradoxical_subreg_p (DF_REF_REG (use)));
}
if (GET_MODE (*loc) == VOIDmode)
if (forward_propagate_and_simplify (use, def_insn, def_set)
|| forward_propagate_subreg (use, def_insn, def_set))
{
+ propagations_left--;
+
if (cfun->can_throw_non_call_exceptions
&& find_reg_note (use_insn, REG_EH_REGION, NULL_RTX)
&& purge_dead_edges (DF_REF_BB (use)))
active_defs = XNEWVEC (df_ref, max_reg_num ());
if (flag_checking)
active_defs_check = sparseset_alloc (max_reg_num ());
+
+ propagations_left = DF_USES_TABLE_SIZE ();
}
static void
fwprop (void)
{
unsigned i;
- bool need_cleanup = false;
fwprop_init ();
for (i = 0; i < DF_USES_TABLE_SIZE (); i++)
{
+ if (!propagations_left)
+ break;
+
df_ref use = DF_USES_GET (i);
if (use)
if (DF_REF_TYPE (use) == DF_REF_REG_USE
|| DF_REF_BB (use)->loop_father == NULL
/* The outer most loop is not really a loop. */
|| loop_outer (DF_REF_BB (use)->loop_father) == NULL)
- need_cleanup |= forward_propagate_into (use);
+ forward_propagate_into (use);
}
fwprop_done ();
- if (need_cleanup)
- cleanup_cfg (0);
return 0;
}
fwprop_addr (void)
{
unsigned i;
- bool need_cleanup = false;
fwprop_init ();
end, and we'll go through them as well. */
for (i = 0; i < DF_USES_TABLE_SIZE (); i++)
{
+ if (!propagations_left)
+ break;
+
df_ref use = DF_USES_GET (i);
if (use)
if (DF_REF_TYPE (use) != DF_REF_REG_USE
&& DF_REF_BB (use)->loop_father != NULL
/* The outer most loop is not really a loop. */
&& loop_outer (DF_REF_BB (use)->loop_father) != NULL)
- need_cleanup |= forward_propagate_into (use);
+ forward_propagate_into (use);
}
fwprop_done ();
-
- if (need_cleanup)
- cleanup_cfg (0);
return 0;
}