|| alias_set_subset_of (later_base_set, earlier_base_set));
}
+/* Similar to refs_same_for_tbaa_p() but for use on MEM rtxs. */
+bool
+mems_same_for_tbaa_p (rtx earlier, rtx later)
+{
+ gcc_assert (MEM_P (earlier));
+ gcc_assert (MEM_P (later));
+
+ return ((MEM_ALIAS_SET (earlier) == MEM_ALIAS_SET (later)
+ || alias_set_subset_of (MEM_ALIAS_SET (later),
+ MEM_ALIAS_SET (earlier)))
+ && (!MEM_EXPR (earlier)
+ || refs_same_for_tbaa_p (MEM_EXPR (earlier), MEM_EXPR (later))));
+}
+
/* Returns a pointer to the alias set entry for ALIAS_SET, if there is
such an entry, or NULL otherwise. */
bool alias_ptr_types_compatible_p (tree, tree);
int compare_base_decls (tree, tree);
bool refs_same_for_tbaa_p (tree, tree);
+bool mems_same_for_tbaa_p (rtx, rtx);
/* This alias set can be used to force a memory to conflict with all
other memories, creating a barrier across which no memory reference
return false;
case SET:
- if (rtx_equal_for_cselib_p (SET_DEST (exp), SET_SRC (exp)))
+ if (cselib_redundant_set_p (exp))
return false;
dest = SET_DEST (exp);
if (dest == pc_rtx)
#include "dumpfile.h"
#include "cselib.h"
#include "function-abi.h"
+#include "alias.h"
/* A list of cselib_val structures. */
struct elt_list
return 1;
}
+/* Wrapper for rtx_equal_for_cselib_p to determine whether a SET is
+ truly redundant, taking into account aliasing information. */
+bool
+cselib_redundant_set_p (rtx set)
+{
+ gcc_assert (GET_CODE (set) == SET);
+ rtx dest = SET_DEST (set);
+ if (cselib_reg_set_mode (dest) != GET_MODE (dest))
+ return false;
+
+ if (!rtx_equal_for_cselib_p (dest, SET_SRC (set)))
+ return false;
+
+ while (GET_CODE (dest) == SUBREG
+ || GET_CODE (dest) == ZERO_EXTRACT
+ || GET_CODE (dest) == STRICT_LOW_PART)
+ dest = XEXP (dest, 0);
+
+ if (!flag_strict_aliasing || !MEM_P (dest))
+ return true;
+
+ /* For a store we need to check that suppressing it will not change
+ the effective alias set. */
+ rtx dest_addr = XEXP (dest, 0);
+
+ /* Lookup the equivalents to the original dest (rather than just the
+ MEM). */
+ cselib_val *src_val = cselib_lookup (SET_DEST (set),
+ GET_MODE (SET_DEST (set)),
+ 0, VOIDmode);
+
+ if (src_val)
+ {
+ /* Walk the list of source equivalents to find the MEM accessing
+ the same location. */
+ for (elt_loc_list *l = src_val->locs; l; l = l->next)
+ {
+ rtx src_equiv = l->loc;
+ while (GET_CODE (src_equiv) == SUBREG
+ || GET_CODE (src_equiv) == ZERO_EXTRACT
+ || GET_CODE (src_equiv) == STRICT_LOW_PART)
+ src_equiv = XEXP (src_equiv, 0);
+
+ if (MEM_P (src_equiv))
+ {
+ /* Match the MEMs by comparing the addresses. We can
+ only remove the later store if the earlier aliases at
+ least all the accesses of the later one. */
+ if (rtx_equal_for_cselib_1 (dest_addr, XEXP (src_equiv, 0),
+ GET_MODE (dest), 0))
+ return mems_same_for_tbaa_p (src_equiv, dest);
+ }
+ }
+ }
+
+ /* We failed to find a recorded value in the cselib history, so try
+ the source of this set; this catches cases such as *p = *q when p
+ and q have the same value. */
+ rtx src = SET_SRC (set);
+ while (GET_CODE (src) == SUBREG)
+ src = XEXP (src, 0);
+
+ if (MEM_P (src)
+ && rtx_equal_for_cselib_1 (dest_addr, XEXP (src, 0), GET_MODE (dest), 0))
+ return mems_same_for_tbaa_p (src, dest);
+
+ return false;
+}
+
/* Helper function for cselib_hash_rtx. Arguments like for cselib_hash_rtx,
except that it hashes (plus:P x c). */
extern bool fp_setter_insn (rtx_insn *);
extern machine_mode cselib_reg_set_mode (const_rtx);
extern int rtx_equal_for_cselib_1 (rtx, rtx, machine_mode, int);
+extern bool cselib_redundant_set_p (rtx);
extern int references_value_p (const_rtx, int);
extern rtx cselib_expand_value_rtx (rtx, bitmap, int);
typedef rtx (*cselib_expand_callback)(rtx, bitmap, int, void *);
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)))))
+ && mems_same_for_tbaa_p (s_info->mem, mem))
{
if (GET_MODE (mem) == BLKmode)
{
#include "function-abi.h"
#include "rtl-iter.h"
-static int reload_cse_noop_set_p (rtx);
static bool reload_cse_simplify (rtx_insn *, rtx);
static void reload_cse_regs_1 (void);
static int reload_cse_simplify_set (rtx, rtx_insn *);
}
}
-/* See whether a single set SET is a noop. */
-static int
-reload_cse_noop_set_p (rtx set)
-{
- if (cselib_reg_set_mode (SET_DEST (set)) != GET_MODE (SET_DEST (set)))
- return 0;
-
- return rtx_equal_for_cselib_p (SET_DEST (set), SET_SRC (set));
-}
-
/* Try to simplify INSN. Return true if the CFG may have changed. */
static bool
reload_cse_simplify (rtx_insn *insn, rtx testreg)
this out, so it's safer to simplify before we delete. */
count += reload_cse_simplify_set (body, insn);
- if (!count && reload_cse_noop_set_p (body))
+ if (!count && cselib_redundant_set_p (body))
{
if (check_for_inc_dec (insn))
delete_insn_and_edges (insn);
rtx part = XVECEXP (body, 0, i);
if (GET_CODE (part) == SET)
{
- if (! reload_cse_noop_set_p (part))
+ if (! cselib_redundant_set_p (part))
break;
if (REG_P (SET_DEST (part))
&& REG_FUNCTION_VALUE_P (SET_DEST (part)))