[RTL ifcvt] PR rtl-optimization/71594: ICE in noce_emit_cmove due to mismatched sourc...
authorKyrylo Tkachov <kyrylo.tkachov@arm.com>
Tue, 5 Jul 2016 16:37:40 +0000 (16:37 +0000)
committerKyrylo Tkachov <ktkachov@gcc.gnu.org>
Tue, 5 Jul 2016 16:37:40 +0000 (16:37 +0000)
PR rtl-optimization/71594
* ifcvt.c (noce_convert_multiple_sets): Wrap new_val or old_val
into subregs of appropriate mode before trying to emit a conditional
move.

* gcc.dg/torture/pr71594.c: New test.

From-SVN: r238013

gcc/ChangeLog
gcc/ifcvt.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/torture/pr71594.c [new file with mode: 0644]

index c746866..f189d6a 100644 (file)
@@ -1,3 +1,10 @@
+2016-07-05  Kyrylo Tkachov  <kyrylo.tkachov@arm.com>
+
+       PR rtl-optimization/71594
+       * ifcvt.c (noce_convert_multiple_sets): Wrap new_val or old_val
+       into subregs of appropriate mode before trying to emit a conditional
+       move.
+
 2016-07-05  Jan Hubicka  <jh@suse.cz>
 
        * tree-scalar-evolution.c (iv_can_overflow_p): New function.
index fd29516..f7f120e 100644 (file)
@@ -3228,6 +3228,41 @@ noce_convert_multiple_sets (struct noce_if_info *if_info)
       if (if_info->then_else_reversed)
        std::swap (old_val, new_val);
 
+
+      /* We allow simple lowpart register subreg SET sources in
+        bb_ok_for_noce_convert_multiple_sets.  Be careful when processing
+        sequences like:
+        (set (reg:SI r1) (reg:SI r2))
+        (set (reg:HI r3) (subreg:HI (r1)))
+        For the second insn new_val or old_val (r1 in this example) will be
+        taken from the temporaries and have the wider mode which will not
+        match with the mode of the other source of the conditional move, so
+        we'll end up trying to emit r4:HI = cond ? (r1:SI) : (r3:HI).
+        Wrap the two cmove operands into subregs if appropriate to prevent
+        that.  */
+      if (GET_MODE (new_val) != GET_MODE (temp))
+       {
+         machine_mode src_mode = GET_MODE (new_val);
+         machine_mode dst_mode = GET_MODE (temp);
+         if (GET_MODE_SIZE (src_mode) <= GET_MODE_SIZE (dst_mode))
+           {
+             end_sequence ();
+             return FALSE;
+           }
+         new_val = lowpart_subreg (dst_mode, new_val, src_mode);
+       }
+      if (GET_MODE (old_val) != GET_MODE (temp))
+       {
+         machine_mode src_mode = GET_MODE (old_val);
+         machine_mode dst_mode = GET_MODE (temp);
+         if (GET_MODE_SIZE (src_mode) <= GET_MODE_SIZE (dst_mode))
+           {
+             end_sequence ();
+             return FALSE;
+           }
+         old_val = lowpart_subreg (dst_mode, old_val, src_mode);
+       }
+
       /* Actually emit the conditional move.  */
       rtx temp_dest = noce_emit_cmove (if_info, temp, cond_code,
                                       x, y, new_val, old_val);
index d57f9c3..13e3d68 100644 (file)
@@ -1,3 +1,8 @@
+2016-07-05  Kyrylo Tkachov  <kyrylo.tkachov@arm.com>
+
+       PR rtl-optimization/71594
+       * gcc.dg/torture/pr71594.c: New test.
+
 2016-07-05  Jan Hubicka  <jh@suse.cz>
 
        * gcc.dg/tree-ssa/scev-14.c: new testcase.
diff --git a/gcc/testsuite/gcc.dg/torture/pr71594.c b/gcc/testsuite/gcc.dg/torture/pr71594.c
new file mode 100644 (file)
index 0000000..468a9f6
--- /dev/null
@@ -0,0 +1,15 @@
+/* { dg-do compile } */
+/* { dg-options "--param max-rtl-if-conversion-insns=2" } */
+
+unsigned short a;
+int b, c;
+int *d;
+void fn1() {
+  *d = 24;
+  for (; *d <= 65;) {
+    unsigned short *e = &a;
+    b = (a &= 0 <= 0) < (c ?: (*e %= *d));
+    for (; *d <= 83;)
+      ;
+  }
+}