Ping. https://gcc.gnu.org/pipermail/gcc-patches/2026-August/727174.html Thanks, Kyrill
> On 11 Aug 2026, at 12:42, Kyrylo Tkachov <[email protected]> wrote: > > From: Kyrylo Tkachov <[email protected]> > > The conditional-compare expander accepts a plain boolean as a comparison > against zero. This is useful when a chain also contains an explicit > comparison. It is harmful when every leaf is a boolean. For example: > > _Bool > f (_Bool x, _Bool y) > { > return x || y; > } > > AArch64 emitted: > > and w1, w1, 255 > tst w0, 255 > ccmp w1, 0, 0, eq > cset w0, ne > > After this patch it emits one bitwise operation: > > orr w0, w0, w1 > > Require at least one explicit comparison in a conditional-compare tree. > Mixed boolean and comparison chains remain accepted. Every statement of a > candidate has a leaf operand, so the candidate is a chain and the check > walks it with a loop. > > Bootstrapped and tested on aarch64-none-linux-gnu. > Ok for trunk? > Thanks, > Kyrill > > gcc/ > > PR middle-end/109832 > * ccmp.cc (ccmp_has_comparison_p): New function. > (expand_ccmp_expr): Reject an all-boolean tree. > > gcc/testsuite/ > > PR middle-end/109832 > * gcc.target/aarch64/ccmp_7.c: New test. > * gcc.target/aarch64/ccmp_9.c: Likewise. > > Signed-off-by: Kyrylo Tkachov <[email protected]> > --- > gcc/ccmp.cc | 34 ++++++++++++++++++++ > gcc/testsuite/gcc.target/aarch64/ccmp_7.c | 38 +++++++++++++++++++++++ > gcc/testsuite/gcc.target/aarch64/ccmp_9.c | 14 +++++++++ > 3 files changed, 86 insertions(+) > create mode 100644 gcc/testsuite/gcc.target/aarch64/ccmp_7.c > create mode 100644 gcc/testsuite/gcc.target/aarch64/ccmp_9.c > > diff --git a/gcc/ccmp.cc b/gcc/ccmp.cc > index 0564ccf34bf..d35e05ec375 100644 > --- a/gcc/ccmp.cc > +++ b/gcc/ccmp.cc > @@ -90,6 +90,35 @@ ccmp_tree_comparison_p (tree t, basic_block bb) > If all checks OK in expand_ccmp_expr, it emits insns in prep_seq, then > insns in gen_seq. */ > > +/* Return true if candidate G in BB has a comparison to fold into the > + condition flags. Every statement of a candidate has a leaf operand, so > + the candidate is a chain and this walks it down to its innermost > + statement. A leaf that has a defining statement is a comparison, the > + other leaves are booleans that expand to a comparison against zero. */ > + > +static bool > +ccmp_has_comparison_p (gimple *g, basic_block bb) > +{ > + do > + { > + tree op0 = gimple_assign_rhs1 (g); > + tree op1 = gimple_assign_rhs2 (g); > + bool leaf0 = ccmp_tree_comparison_p (op0, bb); > + bool leaf1 = ccmp_tree_comparison_p (op1, bb); > + > + gcc_checking_assert (leaf0 || leaf1); > + > + if ((leaf0 && get_gimple_for_ssa_name (op0)) > + || (leaf1 && get_gimple_for_ssa_name (op1))) > + return true; > + > + g = get_gimple_for_ssa_name (leaf0 ? op1 : op0); > + } > + while (g); > + > + return false; > +} > + > /* Check whether G is a potential conditional compare candidate; OUTER is > true if > G is the outer most AND/IOR. */ > static bool > @@ -294,6 +323,11 @@ expand_ccmp_expr (gimple *g, machine_mode mode) > if (!ccmp_candidate_p (g, true)) > return NULL_RTX; > > + /* A conditional compare folds a comparison into the flags. Without a > + comparison to fold the bitwise operation is cheaper. */ > + if (!ccmp_has_comparison_p (g, gimple_bb (g))) > + return NULL_RTX; > + > last = get_last_insn (); > > rtx_insn *prep_seq = NULL, *gen_seq = NULL; > diff --git a/gcc/testsuite/gcc.target/aarch64/ccmp_7.c > b/gcc/testsuite/gcc.target/aarch64/ccmp_7.c > new file mode 100644 > index 00000000000..d9c75eb6b0b > --- /dev/null > +++ b/gcc/testsuite/gcc.target/aarch64/ccmp_7.c > @@ -0,0 +1,38 @@ > +/* { dg-do compile } */ > +/* { dg-options "-O2" } */ > +/* PR middle-end/109832 */ > + > +/* A conditional compare folds a comparison into the flags. When the > operands > + are plain booleans there is no comparison to fold and the bitwise > operation > + is cheaper, so no conditional compare should be formed. */ > + > +_Bool > +bool_ior (_Bool x, _Bool y) > +{ > + return x || y; > +} > + > +_Bool > +bool_and (_Bool x, _Bool y) > +{ > + return x && y; > +} > + > +extern _Bool t (void); > + > +_Bool > +bool_call_ior (void) > +{ > + _Bool x = t (); > + _Bool y = t (); > + return x | y; > +} > + > +_Bool > +bool_ior_tree (_Bool a, _Bool b, _Bool c, _Bool d) > +{ > + return (a | b) | (c | d); > +} > + > +/* { dg-final { scan-assembler-not {\tccmp\t} } } */ > +/* { dg-final { scan-assembler-times {\torr\tw[0-9]+, w[0-9]+, w[0-9]+} 5 } > } */ > diff --git a/gcc/testsuite/gcc.target/aarch64/ccmp_9.c > b/gcc/testsuite/gcc.target/aarch64/ccmp_9.c > new file mode 100644 > index 00000000000..4f95ddf53c1 > --- /dev/null > +++ b/gcc/testsuite/gcc.target/aarch64/ccmp_9.c > @@ -0,0 +1,14 @@ > +/* { dg-do compile } */ > +/* { dg-options "-O2" } */ > +/* PR middle-end/109832 */ > + > +/* One explicit comparison is enough for a chain to be worth a conditional > + compare, so the boolean operands become a compare against zero. */ > + > +int > +bool_and_cmp_tree (_Bool a, _Bool b, _Bool c, int x, int y) > +{ > + return ((a & b) & c) & (x < y); > +} > + > +/* { dg-final { scan-assembler-times {\tccmp\t} 1 } } */ > -- > 2.50.1 (Apple Git-155) >
