From 2c0a9b7fb7902522fb8484342fcc19fd44df53e6 Mon Sep 17 00:00:00 2001 From: Jeff Law <jlaw@ventanamicro.com> Date: Fri, 31 Jan 2025 16:59:35 -0700 Subject: [PATCH] [committed][PR tree-optimization/114277] Fix missed optimization for multiplication against boolean value Andrew, Raphael and I have all poked at it in various ways over the last year or so. I think when Raphael and I first looked at it I sent us down a bit of rathole. In particular it's odd that we're using a multiply to implement a select and it seemed like recognizing the idiom and rewriting into a conditional move was the right path. That looked reasonably good for the test, but runs into problems with min/max detection elsewhere. I think that initial investigation somewhat polluted our thinking. The regression can be fixed with a fairly simple match.pd pattern. Essentially we want to handle x * (x || b) -> x x * !(x || b) -> 0 There's simplifications that can be made for "&&" cases, but I haven't seen them in practice. Rather than drop in untested patterns, I'm leaving that as a future todo. My original was two match.pd patterns. Andrew combined them into a single pattern. I've made this conditional on GIMPLE as an earlier version that simplified to a conditional move showed that when applied on GENERIC we could drop an operand with a side effect which is clearly not good. I've bootstrapped and regression tested this on x86. I've also tested on the various embedded targets in my tester. PR tree-optimization/114277 gcc/ * match.pd (a * (a || b) -> a): New pattern. (a * !(a || b) -> 0): Likewise. gcc/testsuite * gcc.target/i386/pr114277.c: New test. * gcc.target/riscv/pr114277.c: Likewise. Co-author: Andrew Pinski <quic_apinski@quicinc.com> --- gcc/match.pd | 17 +++++++++++++++++ gcc/testsuite/gcc.target/i386/pr114277.c | 10 ++++++++++ gcc/testsuite/gcc.target/riscv/pr114277.c | 9 +++++++++ 3 files changed, 36 insertions(+) create mode 100644 gcc/testsuite/gcc.target/i386/pr114277.c create mode 100644 gcc/testsuite/gcc.target/riscv/pr114277.c diff --git a/gcc/match.pd b/gcc/match.pd index 6991868fbe29..97e0bafdda4b 100644 --- a/gcc/match.pd +++ b/gcc/match.pd @@ -303,6 +303,23 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) (mult @0 integer_zerop@1) @1) +#if GIMPLE +/* When multiplying a value by a boolean involving the value, we may + be able to simplify further. + a * ((a || b) != 0) -> a + a * ((a || b) == 0) -> 0 + + There are also bit-and cases which don't show up in practice yet. + a * ((a && b) != 0) -> a * b + a * ((a && b) == 0) -> b != 0 ? a : b */ +(for neeq (ne eq) + (simplify + (mult:c (convert? (neeq (bit_ior:c @0 @1) integer_zerop@2)) @0) + (if (neeq == EQ_EXPR) + { build_zero_cst (type); } + @0))) +#endif + /* -x == x -> x == 0 */ (for cmp (eq ne) (simplify diff --git a/gcc/testsuite/gcc.target/i386/pr114277.c b/gcc/testsuite/gcc.target/i386/pr114277.c new file mode 100644 index 000000000000..eb611d26d6af --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr114277.c @@ -0,0 +1,10 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +int a,b; +void func0(int x) { a=x * (x || b); } +void func1(int x) { a=x * !(x || b); } + +/* { dg-final { scan-assembler-not "or" } } */ +/* { dg-final { scan-assembler-not "cmove" } } */ + diff --git a/gcc/testsuite/gcc.target/riscv/pr114277.c b/gcc/testsuite/gcc.target/riscv/pr114277.c new file mode 100644 index 000000000000..cc1db19ee4c5 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/pr114277.c @@ -0,0 +1,9 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -march=rv64gc_zicond -mabi=lp64d" { target rv64 } } */ +/* { dg-options "-O2 -march=rv32gc_zicond -mabi=ilp32" { target rv32 } } */ +/* { dg-skip-if "" { *-*-* } { "-O0" "-O1" "-Os" "-Oz" "-O3" "-Og" } } */ + +#include "../i386/pr114277.c" + +/* { dg-final { scan-assembler-not "czero" } } */ + -- GitLab