diff --git a/gcc/testsuite/g++.dg/tree-ssa/ifcombine-ccmp-1.C b/gcc/testsuite/g++.dg/tree-ssa/ifcombine-ccmp-1.C new file mode 100644 index 00000000000..282cec8c628 --- /dev/null +++ b/gcc/testsuite/g++.dg/tree-ssa/ifcombine-ccmp-1.C @@ -0,0 +1,27 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -g -fdump-tree-optimized --param logical-op-non-short-circuit=1" } */ + +/* PR tree-optimization/85605 */ +#include + +template +inline bool cmp(T a, T2 b) { + return a<0 ? true : T2(a) < b; +} + +template +inline bool cmp2(T a, T2 b) { + return (a<0) | (T2(a) < b); +} + +bool f(int a, int b) { + return cmp(int64_t(a), unsigned(b)); +} + +bool f2(int a, int b) { + return cmp2(int64_t(a), unsigned(b)); +} + + +/* Both of these functions should be optimized to the same, and have an | in them. */ +/* { dg-final { scan-tree-dump-times " \\\| " 2 "optimized" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-ifcombine-ccmp-7.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-ifcombine-ccmp-7.c new file mode 100644 index 00000000000..1bdbb9358b4 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-ifcombine-ccmp-7.c @@ -0,0 +1,18 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -g -fdump-tree-optimized --param logical-op-non-short-circuit=1" } */ + +/* PR tree-optimization/85605 */ +/* Like ssa-ifcombine-ccmp-1.c but with conversion from unsigned to signed in the + inner bb which should be able to move too. */ + +int t (int a, unsigned b) +{ + if (a > 0) + { + signed t = b; + if (t > 0) + return 0; + } + return 1; +} +/* { dg-final { scan-tree-dump "\&" "optimized" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-ifcombine-ccmp-8.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-ifcombine-ccmp-8.c new file mode 100644 index 00000000000..8d74b4932c5 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-ifcombine-ccmp-8.c @@ -0,0 +1,19 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -g -fdump-tree-optimized --param logical-op-non-short-circuit=1" } */ + +/* PR tree-optimization/85605 */ +/* Like ssa-ifcombine-ccmp-2.c but with conversion from unsigned to signed in the + inner bb which should be able to move too. */ + +int t (int a, unsigned b) +{ + if (a > 0) + goto L1; + signed t = b; + if (t > 0) + goto L1; + return 0; +L1: + return 1; +} +/* { dg-final { scan-tree-dump "\|" "optimized" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-ifcombine-ccmp-9.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-ifcombine-ccmp-9.c new file mode 100644 index 00000000000..4e8350fad41 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-ifcombine-ccmp-9.c @@ -0,0 +1,17 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -g -fdump-tree-optimized --param logical-op-non-short-circuit=1" } */ + +/* PR tree-optimization/85605 */ +/* Like ssa-ifcombine-ccmp-1.c but with conversion from short to int in the + inner bb which should be able to move too. */ + +int t (int a, short b, int c) +{ + if (a > 0) + { + if (c == b) + return 0; + } + return 1; +} +/* { dg-final { scan-tree-dump "\&" "optimized" } } */ diff --git a/gcc/tree-ssa-ifcombine.cc b/gcc/tree-ssa-ifcombine.cc index b87ed1189df..9b9dc10cd22 100644 --- a/gcc/tree-ssa-ifcombine.cc +++ b/gcc/tree-ssa-ifcombine.cc @@ -776,6 +776,36 @@ ifcombine_replace_cond (gcond *inner_cond, bool inner_inv, return true; } +/* Returns true if inner_cond_bb contains just the condition or 1/2 statements + that define lhs or rhs with an integer conversion. */ + +static bool +can_combine_bbs_with_short_circuit (basic_block inner_cond_bb, tree lhs, tree rhs) +{ + gimple_stmt_iterator gsi; + gsi = gsi_start_nondebug_after_labels_bb (inner_cond_bb); + /* If only the condition, this should be allowed. */ + if (gsi_one_before_end_p (gsi)) + return true; + /* Can have up to 2 statements defining each of lhs/rhs. */ + for (int i = 0; i < 2; i++) + { + gimple *stmt = gsi_stmt (gsi); + if (!is_gimple_assign (stmt) + || !CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (stmt))) + return false; + /* The defining statement needs to match either the lhs or rhs of + the condition. */ + if (lhs != gimple_assign_lhs (stmt) + && rhs != gimple_assign_lhs (stmt)) + return false; + gsi_next_nondebug (&gsi); + if (gsi_one_before_end_p (gsi)) + return true; + } + return false; +} + /* If-convert on a and pattern with a common else block. The inner if is specified by its INNER_COND_BB, the outer by OUTER_COND_BB. inner_inv, outer_inv indicate whether the conditions are inverted. @@ -951,8 +981,11 @@ ifcombine_ifandif (basic_block inner_cond_bb, bool inner_inv, = param_logical_op_non_short_circuit; if (!logical_op_non_short_circuit || sanitize_coverage_p ()) return false; - /* Only do this optimization if the inner bb contains only the conditional. */ - if (!gsi_one_before_end_p (gsi_start_nondebug_after_labels_bb (inner_cond_bb))) + /* Only do this optimization if the inner bb contains only the conditional + or there is one or 2 statements which are nop conversion for the comparison. */ + if (!can_combine_bbs_with_short_circuit (inner_cond_bb, + gimple_cond_lhs (inner_cond), + gimple_cond_rhs (inner_cond))) return false; t1 = fold_build2_loc (gimple_location (inner_cond), inner_cond_code,