@@ -473,7 +473,8 @@ get_defs (rtx_insn *insn, rtx reg, vec<rtx_insn *> *dest)
break;
}
- gcc_assert (use != NULL);
+ if (use == NULL)
+ return NULL;
ref_chain = DF_REF_CHAIN (use);
@@ -514,7 +515,8 @@ get_uses (rtx_insn *insn, rtx reg)
if (REGNO (DF_REF_REG (def)) == REGNO (reg))
break;
- gcc_assert (def != NULL);
+ if (def == NULL)
+ return NULL;
ref_chain = DF_REF_CHAIN (def);
@@ -771,6 +773,58 @@ combine_reaching_defs (ext_cand *cand, const_rtx set_pat, ext_state *state)
state->defs_list.truncate (0);
state->copies_list.truncate (0);
+ if (cand->code == ZERO_EXTEND)
+ {
+ rtx orig_src = XEXP (SET_SRC (cand->expr),0);
+ rtx set = single_set (cand->insn);
+
+ if (!set)
+ return false;
+
+ machine_mode ext_dst_mode = GET_MODE (SET_DEST (set));
+
+ if (!get_defs (cand->insn, orig_src, NULL))
+ {
+ bool copy_needed
+ = (REGNO (SET_DEST (cand->expr)) != REGNO (XEXP (SET_SRC (cand->expr), 0)));
+
+ if (!copy_needed && ext_dst_mode != GET_MODE (orig_src)
+ && FUNCTION_ARG_REGNO_P (REGNO (orig_src))
+ && !FUNCTION_VALUE_REGNO_P (REGNO (orig_src)))
+ {
+ if (side_effects_p (PATTERN (cand->insn)))
+ return false;
+
+ struct df_link *uses
+ = get_uses (cand->insn, SET_DEST (PATTERN (cand->insn)));
+
+ if (!uses) return false;
+
+ for (df_link *use = uses; use; use = use->next)
+ {
+ if (!use->ref)
+ return false;
+
+ if (BLOCK_FOR_INSN (cand->insn)
+ != BLOCK_FOR_INSN (DF_REF_INSN (use->ref)))
+ return false;
+
+ rtx_insn *insn = DF_REF_INSN (use->ref);
+
+ if (GET_CODE (PATTERN (insn)) == SET)
+ {
+ rtx_code code = GET_CODE (SET_SRC (PATTERN (insn)));
+ if (GET_RTX_CLASS (code) == RTX_BIN_ARITH
+ || GET_RTX_CLASS (code) == RTX_COMM_ARITH
+ || GET_RTX_CLASS (code) == RTX_UNARY)
+ return false;
+ }
+ }
+ return true;
+ }
+ }
+ }
+
outcome = make_defs_and_copies_lists (cand->insn, set_pat, state);
if (!outcome)
@@ -1112,26 +1166,35 @@ add_removable_extension (const_rtx expr, rtx_insn *insn,
rtx reg = XEXP (src, 0);
struct df_link *defs, *def;
ext_cand *cand;
+ defs = get_defs (insn, reg, NULL);
/* Zero-extension of an undefined value is partly defined (it's
completely undefined for sign-extension, though). So if there exists
a path from the entry to this zero-extension that leaves this register
uninitialized, removing the extension could change the behavior of
correct programs. So first, check it is not the case. */
- if (code == ZERO_EXTEND && !bitmap_bit_p (init_regs, REGNO (reg)))
+ if (!defs && code == ZERO_EXTEND && FUNCTION_ARG_REGNO_P (REGNO (reg)))
{
- if (dump_file)
- {
- fprintf (dump_file, "Cannot eliminate extension:\n");
- print_rtl_single (dump_file, insn);
- fprintf (dump_file, " because it can operate on uninitialized"
- " data\n");
- }
+ ext_cand e = {expr, code, mode, insn};
+ insn_list->safe_push (e);
return;
}
+
+ if ((code == ZERO_EXTEND
+ && !bitmap_bit_p (init_regs, REGNO (reg))))
+ {
+ if (dump_file)
+ {
+ fprintf (dump_file, "Cannot eliminate extension:\n");
+ print_rtl_single (dump_file, insn);
+ fprintf (dump_file, " because it can operate on uninitialized"
+ " data\n");
+ }
+ return;
+ }
+
/* Second, make sure we can get all the reaching definitions. */
- defs = get_defs (insn, reg, NULL);
if (!defs)
{
if (dump_file)
@@ -1321,7 +1384,8 @@ find_and_remove_re (void)
&& (REGNO (SET_DEST (set)) != REGNO (XEXP (SET_SRC (set), 0))))
{
reinsn_copy_list.safe_push (curr_cand->insn);
- reinsn_copy_list.safe_push (state.defs_list[0]);
+ if (state.defs_list.length() != 0)
+ reinsn_copy_list.safe_push (state.defs_list[0]);
}
reinsn_del_list.safe_push (curr_cand->insn);
state.modified[INSN_UID (curr_cand->insn)].deleted = 1;
@@ -1342,24 +1406,27 @@ find_and_remove_re (void)
Remember that the memory reference will be changed to refer to the
destination of the extention. So we're actually emitting a copy
from the new destination to the old destination. */
- for (unsigned int i = 0; i < reinsn_copy_list.length (); i += 2)
- {
- rtx_insn *curr_insn = reinsn_copy_list[i];
- rtx_insn *def_insn = reinsn_copy_list[i + 1];
-
- /* Use the mode of the destination of the defining insn
- for the mode of the copy. This is necessary if the
- defining insn was used to eliminate a second extension
- that was wider than the first. */
- rtx sub_rtx = *get_sub_rtx (def_insn);
- rtx set = single_set (curr_insn);
- rtx new_dst = gen_rtx_REG (GET_MODE (SET_DEST (sub_rtx)),
- REGNO (XEXP (SET_SRC (set), 0)));
- rtx new_src = gen_rtx_REG (GET_MODE (SET_DEST (sub_rtx)),
- REGNO (SET_DEST (set)));
- rtx new_set = gen_rtx_SET (new_dst, new_src);
- emit_insn_after (new_set, def_insn);
- }
+ for (unsigned int i = 0; i < reinsn_copy_list.length (); i += 2)
+ {
+ rtx_insn *curr_insn = reinsn_copy_list[i];
+
+ if ((i+1) < reinsn_copy_list.length())
+ {
+ rtx_insn *def_insn = reinsn_copy_list[i + 1];
+ /* Use the mode of the destination of the defining insn
+ for the mode of the copy. This is necessary if the
+ defining insn was used to eliminate a second extension
+ that was wider than the first. */
+ rtx sub_rtx = *get_sub_rtx (def_insn);
+ rtx set = single_set (curr_insn);
+ rtx new_dst = gen_rtx_REG (GET_MODE (SET_DEST (sub_rtx)),
+ REGNO (XEXP (SET_SRC (set), 0)));
+ rtx new_src = gen_rtx_REG (GET_MODE (SET_DEST (sub_rtx)),
+ REGNO (SET_DEST (set)));
+ rtx new_set = gen_rtx_SET (new_dst, new_src);
+ emit_insn_after (new_set, def_insn);
+ }
+ }
/* Delete all useless extensions here in one sweep. */
FOR_EACH_VEC_ELT (reinsn_del_list, i, curr_insn)
new file mode 100644
@@ -0,0 +1,16 @@
+/* { dg-do compile { target { powerpc*-*-* } } } */
+/* { dg-require-effective-target lp64 } */
+/* { dg-require-effective-target powerpc_p9vector_ok } */
+/* { dg-options "-mcpu=power9 -O2 -free" } */
+
+void *memset(void *b, int c, unsigned long len)
+{
+ unsigned long i;
+
+ for (i = 0; i < len; i++)
+ ((unsigned char *)b)[i] = c;
+
+ return b;
+}
+
+/* { dg-final { scan-assembler-not "rlwinm" } } */