aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYvan Roux <yvan.roux@linaro.org>2016-09-05 19:00:39 +0200
committerYvan Roux <yvan.roux@linaro.org>2016-09-07 22:08:53 +0200
commita948d918d75bbcc1a5a97d297d3a71494eeeafc8 (patch)
treead31256374cfe8e5fa7d52d505ffc26f2dd67000
parent33d29b1c6ba8dcddc080d842aafefa9bfb6982d0 (diff)
gcc/
Backport from trunk r238013. 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. gcc/testsuite/ Backport from trunk r238013. 2016-07-05 Kyrylo Tkachov <kyrylo.tkachov@arm.com> PR rtl-optimization/71594 * gcc.dg/torture/pr71594.c: New test. Change-Id: I0ee49c3987adc7ee7ef5d4d6baf9712e3659f885
-rw-r--r--gcc/ifcvt.c35
-rw-r--r--gcc/testsuite/gcc.dg/torture/pr71594.c15
2 files changed, 50 insertions, 0 deletions
diff --git a/gcc/ifcvt.c b/gcc/ifcvt.c
index 4a277db7dcc..95d38107b86 100644
--- a/gcc/ifcvt.c
+++ b/gcc/ifcvt.c
@@ -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);
diff --git a/gcc/testsuite/gcc.dg/torture/pr71594.c b/gcc/testsuite/gcc.dg/torture/pr71594.c
new file mode 100644
index 00000000000..468a9f6891c
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/torture/pr71594.c
@@ -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;)
+ ;
+ }
+}