From fa16a27195c8862806f1483026fa1fbba8315afb Mon Sep 17 00:00:00 2001 From: Kyrylo Tkachov Date: Fri, 30 Sep 2016 08:28:09 +0000 Subject: [PATCH] [RTL ifcvt] Transform (X == CST) ? -CST : Y into (X == CST) ? -X : Y when conditional negation is available * ifcvt.c (noce_try_avoid_const_materialization): New function. (noce_process_if_block): Use it. * gcc.target/aarch64/ifcvt_avoid_const_materialization_1.c: New test. From-SVN: r240649 --- gcc/ChangeLog | 5 ++ gcc/ifcvt.c | 80 +++++++++++++++++++ gcc/testsuite/ChangeLog | 4 + .../ifcvt_avoid_const_materialization_1.c | 22 +++++ 4 files changed, 111 insertions(+) create mode 100644 gcc/testsuite/gcc.target/aarch64/ifcvt_avoid_const_materialization_1.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 9be02e1d322..8265a45f3cf 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,8 @@ +2016-09-30 Kyrylo Tkachov + + * ifcvt.c (noce_try_avoid_const_materialization): New function. + (noce_process_if_block): Use it. + 2016-09-30 Martin Liska * doc/invoke.texi: Document asan-use-after-return that diff --git a/gcc/ifcvt.c b/gcc/ifcvt.c index 24542f00848..203cfe98f82 100644 --- a/gcc/ifcvt.c +++ b/gcc/ifcvt.c @@ -1313,6 +1313,84 @@ noce_try_inverse_constants (struct noce_if_info *if_info) return false; } +/* Try to avoid materializing a constant if we know it's in one of the + registers. For example: + (X == CST) ? -CST : Y --> (X == CST) ? -X : Y. + Do this only if conditional negation is available. + Similar for bitwise NOT. */ + +static bool +noce_try_avoid_const_materialization (struct noce_if_info *if_info) +{ + if (!noce_simple_bbs (if_info)) + return false; + + rtx cond = if_info->cond; + rtx a = if_info->a; + rtx b = if_info->b; + rtx_code code = GET_CODE (cond); + machine_mode mode = GET_MODE (if_info->x); + + if (!(code == EQ || code == NE) + || !REG_P (XEXP (cond, 0)) + || !REG_P (if_info->x) + || GET_MODE (XEXP (cond, 0)) != mode + || !CONST_INT_P (XEXP (cond, 1))) + return false; + + rtx cst = XEXP (cond, 1); + if (cst == CONST0_RTX (mode)) + return false; + + rtx non_cst = XEXP (cond, 0); + rtx eq_side = code == EQ ? b : a; + if (!CONST_INT_P (eq_side)) + return false; + + HOST_WIDE_INT cstval = INTVAL (cst); + HOST_WIDE_INT eq_side_val = INTVAL (eq_side); + + rtx_code op_code; + if (eq_side_val == ~cstval) + op_code = NOT; + else if (eq_side_val != HOST_WIDE_INT_MIN && (cstval == -eq_side_val)) + op_code = NEG; + else + return false; + + /* By the rules of the negcc/notcc optabs must happen when the COND is true, + in this case when register in COND is equal to CST so always set the + comparison to EQ. */ + if (code == NE) + { + a = non_cst; + cond = gen_rtx_fmt_ee (EQ, GET_MODE (cond), non_cst, cst); + } + else + b = non_cst; + + start_sequence (); + rtx target + = emit_conditional_neg_or_complement (if_info->x, op_code, mode, + cond, a, b); + if (!target) + { + end_sequence (); + return false; + } + + if (target != if_info->x) + noce_emit_move_insn (if_info->x, target); + + rtx_insn *seq = end_ifcvt_sequence (if_info); + if (!seq) + return false; + + emit_insn_before_setloc (seq, if_info->jump, + INSN_LOCATION (if_info->insn_a)); + if_info->transform_name = "noce_try_avoid_const_materialization"; + return true; +} /* Convert "if (test) x = a; else x = b", for A and B constant. Also allow A = y + c1, B = y + c2, with a common y between A @@ -3606,6 +3684,8 @@ noce_process_if_block (struct noce_if_info *if_info) goto success; if (noce_try_inverse_constants (if_info)) goto success; + if (noce_try_avoid_const_materialization (if_info)) + goto success; if (!targetm.have_conditional_execution () && noce_try_store_flag_constants (if_info)) goto success; diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 7ea99619546..11fc7a8de85 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2016-09-30 Kyrylo Tkachov + + * gcc.target/aarch64/ifcvt_avoid_const_materialization_1.c: New test. + 2016-09-30 Richard Biener PR tree-optimization/77399 diff --git a/gcc/testsuite/gcc.target/aarch64/ifcvt_avoid_const_materialization_1.c b/gcc/testsuite/gcc.target/aarch64/ifcvt_avoid_const_materialization_1.c new file mode 100644 index 00000000000..b2a05eaff60 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/ifcvt_avoid_const_materialization_1.c @@ -0,0 +1,22 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +/* Check that we avoid moving the immediate into a register + if comparison has shown that the inverse or negated form is + already in one of the registers. */ + +int +foo (int a, int b) +{ + return a == 5 ? -5 : b; +} + +int +bar (int a, int b) +{ + return a != 5 ? b : ~5; +} + +/* { dg-final { scan-assembler-not "mov\\tw\[0-9\]+" } } */ +/* { dg-final { scan-assembler-times "csneg\\tw\[0-9\]+" 1 } } */ +/* { dg-final { scan-assembler-times "csinv\\tw\[0-9\]+" 1 } } */ -- 2.30.2