On 05/23/2016 05:15 PM, Kyrill Tkachov wrote: > > expand_simple_binop may fail. I think you should add a check that diff_rtx is > non-NULL > and bail out early if it is. > Fixed.
-- Regards, Mikhail Maltsev
diff --git a/gcc/ifcvt.c b/gcc/ifcvt.c index a9c146b..e1473eb 100644 --- a/gcc/ifcvt.c +++ b/gcc/ifcvt.c @@ -1260,6 +1260,7 @@ noce_try_store_flag_constants (struct noce_if_info *if_info) { ST_ADD_FLAG, ST_SHIFT_FLAG, + ST_SHIFT_ADD_FLAG, ST_IOR_FLAG }; @@ -1384,6 +1385,12 @@ noce_try_store_flag_constants (struct noce_if_info *if_info) normalize = -1; reversep = true; } + else if (exact_log2 (abs_hwi (diff)) >= 0 + && (STORE_FLAG_VALUE == 1 || if_info->branch_cost >= 2)) + { + strategy = ST_SHIFT_ADD_FLAG; + normalize = 1; + } else return FALSE; @@ -1453,6 +1460,24 @@ noce_try_store_flag_constants (struct noce_if_info *if_info) gen_int_mode (ifalse, mode), if_info->x, 0, OPTAB_WIDEN); break; + case ST_SHIFT_ADD_FLAG: + { + /* if (test) x = 5; else x = 1; + => x = (test != 0) << 2 + 1; */ + HOST_WIDE_INT diff_log = exact_log2 (abs_hwi (diff)); + rtx diff_rtx + = expand_simple_binop (mode, ASHIFT, target, GEN_INT (diff_log), + if_info->x, 0, OPTAB_WIDEN); + if (!diff_rtx) + { + end_sequence (); + return false; + } + target = expand_simple_binop (mode, (diff < 0) ? MINUS : PLUS, + gen_int_mode (ifalse, mode), diff_rtx, + if_info->x, 0, OPTAB_WIDEN); + break; + } } if (! target) diff --git a/gcc/testsuite/gcc.dg/ifcvt-6.c b/gcc/testsuite/gcc.dg/ifcvt-6.c new file mode 100644 index 0000000..c2cfb17 --- /dev/null +++ b/gcc/testsuite/gcc.dg/ifcvt-6.c @@ -0,0 +1,11 @@ +/* { dg-do compile { target x86_64-*-* } } */ +/* { dg-options "-fdump-rtl-ce1 -O2" } */ + +int +test1 (int a) +{ + return a % 2 != 0 ? 7 : 3; +} + +/* { dg-final { scan-rtl-dump "3 true changes made" "ce1" } } */ +/* { dg-final { scan-assembler-not "sbbl" } } */