Hi all, This is the second attempt to fix the PRs. The first one at https://gcc.gnu.org/ml/gcc-patches/2015-09/msg00449.html does the trick, but is overly restrictive.
This one allows for cases when one block is complex and the other one is simple or empty. Earlier, this case would bypass the bbs_ok_for_cmove_arith and we would end up if-converting cases where the 'else' part (x := b) was pulled from the test block earlier in the call chain. If the reg 'b' in this case was also written to by the 'then' block, then we would miscompile. With this patch we move the original 'b' value into a pseudo before potentially clobbering it, so all is wired up properly. With this patch the PRs work for me and the restriction on if-conversion is not overly aggressive. Rainer, could you please check that this patch still fixes the SPARC regressions? I've bootstrapped and tested this on x86_64 and aarch64. Ok for trunk if SPARC testing is fine? Thanks, Kyrill 2015-09-10 Kyrylo Tkachov <kyrylo.tkac...@arm.com> PR rtl-optimization/67456 PR rtl-optimization/67464 PR rtl-optimization/67465 PR rtl-optimization/67481 * ifcvt.c (noce_try_cmove_arith): Bail out if cannot conditionally move in the mode of x. Handle combination of complex and simple block pairs as well as the case when one is empty. 2015-09-10 Kyrylo Tkachov <kyrylo.tkac...@arm.com> * gcc.dg/pr67465.c: New test.
commit ca25fa7000dd9d086b78bf9a02126f83fbab8073 Author: Kyrylo Tkachov <kyrylo.tkac...@arm.com> Date: Mon Sep 7 14:58:01 2015 +0100 [RTL-ifcvt] PR rtl-optimization/67465: Do not ifcvt complex blocks if the else block is empty diff --git a/gcc/ifcvt.c b/gcc/ifcvt.c index d2f5b66..9adce60 100644 --- a/gcc/ifcvt.c +++ b/gcc/ifcvt.c @@ -1997,6 +1997,7 @@ noce_try_cmove_arith (struct noce_if_info *if_info) rtx a = if_info->a; rtx b = if_info->b; rtx x = if_info->x; + machine_mode x_mode = GET_MODE (x); rtx orig_a, orig_b; rtx_insn *insn_a, *insn_b; bool a_simple = if_info->then_simple; @@ -2008,6 +2009,9 @@ noce_try_cmove_arith (struct noce_if_info *if_info) enum rtx_code code; rtx_insn *ifcvt_seq; + if (!can_conditionally_move_p (x_mode)) + return FALSE; + /* A conditional move from two memory sources is equivalent to a conditional on their addresses followed by a load. Don't do this early because it'll screw alias analysis. Note that we've @@ -2079,13 +2083,32 @@ noce_try_cmove_arith (struct noce_if_info *if_info) } } - if (!a_simple && then_bb && !b_simple && else_bb + if (then_bb && else_bb && !a_simple && !b_simple && (!bbs_ok_for_cmove_arith (then_bb, else_bb) || !bbs_ok_for_cmove_arith (else_bb, then_bb))) return FALSE; start_sequence (); + /* If one of the blocks is empty then the corresponding B or A value + came from the test block. The non-empty complex block that we will + emit might clobber the register used by B or A, so move it to a pseudo + first. */ + + if (b_simple || !else_bb) + { + rtx tmp_b = gen_reg_rtx (x_mode); + noce_emit_move_insn (tmp_b, b); + b = tmp_b; + } + + if (a_simple || !then_bb) + { + rtx tmp_a = gen_reg_rtx (x_mode); + noce_emit_move_insn (tmp_a, a); + a = tmp_a; + } + orig_a = a; orig_b = b; diff --git a/gcc/testsuite/gcc.dg/pr67465.c b/gcc/testsuite/gcc.dg/pr67465.c new file mode 100644 index 0000000..321fd38 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr67465.c @@ -0,0 +1,53 @@ +/* { dg-do run } */ +/* { dg-options "-O3 -std=gnu99" } */ + +int a, b, c, d, e, h; + +int +fn1 (int p1) +{ + { + int g[2]; + for (int i = 0; i < 1; i++) + g[i] = 0; + if (g[0] < c) + { + a = (unsigned) (1 ^ p1) % 2; + return 0; + } + } + return 0; +} + +void +fn2 () +{ + for (h = 0; h < 1; h++) + { + for (int j = 0; j < 2; j++) + { + for (b = 1; b; b = 0) + a = 1; + for (; b < 1; b++) + ; + if (e) + continue; + a = 2; + } + fn1 (h); + short k = -16; + d = k > a; + } +} + +int +main () +{ + fn2 (); + + if (a != 2) + __builtin_abort (); + + return 0; +} +