]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
2014-06-23 Zhenqiang Chen <zhenqiang.chen@linaro.org>
authorzqchen <zqchen@138bc75d-0d04-0410-961f-82ee72b054a4>
Mon, 23 Jun 2014 02:47:54 +0000 (02:47 +0000)
committerzqchen <zqchen@138bc75d-0d04-0410-961f-82ee72b054a4>
Mon, 23 Jun 2014 02:47:54 +0000 (02:47 +0000)
* loop-invariant.c (pre_check_invariant_p): New function.
(find_invariant_insn): Call pre_check_invariant_p.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@211885 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/ChangeLog
gcc/loop-invariant.c

index bc72a7fa7e60e6cdcf48f02c7d4cd498f6c0bdac..105f4ac3ac1805c23fa20c81505e497e856a2cec 100644 (file)
@@ -1,3 +1,8 @@
+2014-06-23  Zhenqiang Chen  <zhenqiang.chen@linaro.org>
+
+       * loop-invariant.c (pre_check_invariant_p): New function.
+       (find_invariant_insn): Call pre_check_invariant_p.
+
 2014-06-22  Richard Henderson  <rth@redhat.com>
 
        PR target/61565
index f683d8ccfe9e8889bfdad4c472ed78e7d42f511c..25e63e442725dd228d33e72af9cbb923087049d4 100644 (file)
@@ -839,6 +839,39 @@ check_dependencies (rtx insn, bitmap depends_on)
   return true;
 }
 
+/* Pre-check candidate DEST to skip the one which can not make a valid insn
+   during move_invariant_reg.  SIMPLE is to skip HARD_REGISTER.  */
+static bool
+pre_check_invariant_p (bool simple, rtx dest)
+{
+  if (simple && REG_P (dest) && DF_REG_DEF_COUNT (REGNO (dest)) > 1)
+    {
+      df_ref use;
+      rtx ref;
+      unsigned int i = REGNO (dest);
+      struct df_insn_info *insn_info;
+      df_ref def_rec;
+
+      for (use = DF_REG_USE_CHAIN (i); use; use = DF_REF_NEXT_REG (use))
+       {
+         ref = DF_REF_INSN (use);
+         insn_info = DF_INSN_INFO_GET (ref);
+
+         FOR_EACH_INSN_INFO_DEF (def_rec, insn_info)
+           if (DF_REF_REGNO (def_rec) == i)
+             {
+               /* Multi definitions at this stage, most likely are due to
+                  instruction constraints, which requires both read and write
+                  on the same register.  Since move_invariant_reg is not
+                  powerful enough to handle such cases, just ignore the INV
+                  and leave the chance to others.  */
+               return false;
+             }
+       }
+    }
+  return true;
+}
+
 /* Finds invariant in INSN.  ALWAYS_REACHED is true if the insn is always
    executed.  ALWAYS_EXECUTED is true if the insn is always executed,
    unless the program ends due to a function call.  */
@@ -868,7 +901,8 @@ find_invariant_insn (rtx insn, bool always_reached, bool always_executed)
       || HARD_REGISTER_P (dest))
     simple = false;
 
-  if (!may_assign_reg_p (SET_DEST (set))
+  if (!may_assign_reg_p (dest)
+      || !pre_check_invariant_p (simple, dest)
       || !check_maybe_invariant (SET_SRC (set)))
     return;