re PR rtl-optimization/78437 (invalid sign-extend conversion in REE pass)
authorEric Botcazou <ebotcazou@adacore.com>
Thu, 24 Nov 2016 15:01:32 +0000 (15:01 +0000)
committerEric Botcazou <ebotcazou@gcc.gnu.org>
Thu, 24 Nov 2016 15:01:32 +0000 (15:01 +0000)
PR rtl-optimization/78437
* ree.c (get_uses): New function.
(combine_reaching_defs): When a copy is needed, return false if any
reaching use of the source register reads it in a mode larger than
the mode it is set in and WORD_REGISTER_OPERATIONS is true.

From-SVN: r242839

gcc/ChangeLog
gcc/ree.c

index e11426babcf67e81877909c923dcb0476ed236fc..4e83a4810254ef7fddc48573a661ab98cf9055fb 100644 (file)
@@ -1,3 +1,11 @@
+2016-11-24  Eric Botcazou  <ebotcazou@adacore.com>
+
+       PR rtl-optimization/78437
+       * ree.c (get_uses): New function.
+       (combine_reaching_defs): When a copy is needed, return false if any
+       reaching use of the source register reads it in a mode larger than
+       the mode it is set in and WORD_REGISTER_OPERATIONS is true.
+
 2016-11-24  Martin Liska  <mliska@suse.cz>
 
        * gimple-pretty-print.c (dump_edge_probability): New function.
index 6bac17ef7fd0b18ff0f342671c603fb85ad8cdb1..a7a6526c98087c59c6883e2e0c481a99083c90ca 100644 (file)
--- a/gcc/ree.c
+++ b/gcc/ree.c
@@ -499,6 +499,35 @@ get_defs (rtx_insn *insn, rtx reg, vec<rtx_insn *> *dest)
   return ref_chain;
 }
 
+/* Get all the reaching uses of an instruction.  The uses are desired for REG
+   set in INSN.  Return use list or NULL if a use is missing or irregular.  */
+
+static struct df_link *
+get_uses (rtx_insn *insn, rtx reg)
+{
+  df_ref def;
+  struct df_link *ref_chain, *ref_link;
+
+  FOR_EACH_INSN_DEF (def, insn)
+    if (REGNO (DF_REF_REG (def)) == REGNO (reg))
+      break;
+
+  gcc_assert (def != NULL);
+
+  ref_chain = DF_REF_CHAIN (def);
+
+  for (ref_link = ref_chain; ref_link; ref_link = ref_link->next)
+    {
+      /* Problem getting some use for this instruction.  */
+      if (ref_link->ref == NULL)
+        return NULL;
+      if (DF_REF_CLASS (ref_link->ref) != DF_REF_REGULAR)
+       return NULL;
+    }
+
+  return ref_chain;
+}
+
 /* Return true if INSN is
      (SET (reg REGNO (def_reg)) (if_then_else (cond) (REG x1) (REG x2)))
    and store x1 and x2 in REG_1 and REG_2.  */
@@ -827,6 +856,23 @@ combine_reaching_defs (ext_cand *cand, const_rtx set_pat, ext_state *state)
       if (reg_overlap_mentioned_p (tmp_reg, SET_DEST (PATTERN (cand->insn))))
        return false;
 
+      /* On RISC machines we must make sure that changing the mode of SRC_REG
+        as destination register will not affect its reaching uses, which may
+        read its value in a larger mode because DEF_INSN implicitly sets it
+        in word mode.  */
+      const unsigned int prec
+       = GET_MODE_PRECISION (GET_MODE (SET_DEST (*dest_sub_rtx)));
+      if (WORD_REGISTER_OPERATIONS && prec < BITS_PER_WORD)
+       {
+         struct df_link *uses = get_uses (def_insn, src_reg);
+         if (!uses)
+           return false;
+
+         for (df_link *use = uses; use; use = use->next)
+           if (GET_MODE_PRECISION (GET_MODE (*DF_REF_LOC (use->ref))) > prec)
+             return false;
+       }
+
       /* The destination register of the extension insn must not be
         used or set between the def_insn and cand->insn exclusive.  */
       if (reg_used_between_p (SET_DEST (PATTERN (cand->insn)),