> On 11 Aug 2026, at 00:10, Andrea Pinski <[email protected]>
> wrote:
>
> On Mon, Aug 10, 2026 at 6:23 AM <[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.
>>
>> Bootstrapped and tested on aarch64-none-linux-gnu.
>> Ok for trunk?
>> Thanks,
>> Kyrill
>>
>> gcc/
>>
>> PR middle-end/109832
>> * ccmp.cc (ccmp_tree_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.
>>
>> Signed-off-by: Kyrylo Tkachov <[email protected]>
>> ---
>> gcc/ccmp.cc | 24 ++++++++++++
>> gcc/testsuite/gcc.target/aarch64/ccmp_7.c | 46 +++++++++++++++++++++++
>> 2 files changed, 70 insertions(+)
>> create mode 100644 gcc/testsuite/gcc.target/aarch64/ccmp_7.c
>>
>> diff --git a/gcc/ccmp.cc b/gcc/ccmp.cc
>> index 1c540f641b2..9f7670bf58e 100644
>> --- a/gcc/ccmp.cc
>> +++ b/gcc/ccmp.cc
>> @@ -93,6 +93,25 @@ ccmp_tree_comparison_p (tree t, basic_block bb)
>>
>> typedef hash_map<tree, bool> ccmp_uniform_cache;
>>
>> +/* Return true if AND/IOR tree T contains a comparison in BB. */
>> +
>> +static bool
>> +ccmp_tree_has_comparison_p (tree t, basic_block bb)
>> +{
>> + gimple *g = get_gimple_for_ssa_name (t);
>> + if (!g || !is_gimple_assign (g))
>> + return false;
>> +
>> + tree_code code = gimple_assign_rhs_code (g);
>> + if (TREE_CODE_CLASS (code) == tcc_comparison)
>> + return gimple_bb (g) == bb;
>> + if (code != BIT_AND_EXPR && code != BIT_IOR_EXPR)
>> + return false;
>> +
>> + return (ccmp_tree_has_comparison_p (gimple_assign_rhs1 (g), bb)
>> + || ccmp_tree_has_comparison_p (gimple_assign_rhs2 (g), bb));
>
> Is there a way to do this non recursive (and not with a work list)?
Yes, I’ve implemented that (and your other suggestions in the series) and
will send out the updated version soon.
> I think it might be a good idea to move ccmp away from expand into say isel.
> We already don't really want to depend on TER and your above code does
> not even use ter.
I guess it’s possible. Would we need to create new IFNs like:
_1 = .CCMP (LT_EXPR, a, b)
_2 = .CCMP_NEXT (_1, BIT_AND_EXPR, LT_EXPR, c, d)
?
I’m not attempting it right now though, I’m hoping the current patches in flight
strictly improve ccmp codegen without complicating a possible future move.
Thanks,
Kyrill
>
>> +}
>> +
>> /* Return true if T is a CODE tree in BB whose leaves are comparisons.
>> CACHE records results for logical SSA definitions. */
>>
>> @@ -368,6 +387,11 @@ expand_ccmp_expr (gimple *g, machine_mode mode)
>> if (!ccmp_candidate_p (g, cache, true))
>> return NULL_RTX;
>>
>> + basic_block bb = gimple_bb (g);
>> + if (!ccmp_tree_has_comparison_p (gimple_assign_rhs1 (g), bb)
>> + && !ccmp_tree_has_comparison_p (gimple_assign_rhs2 (g), bb))
>> + 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..29e269b854e
>> --- /dev/null
>> +++ b/gcc/testsuite/gcc.target/aarch64/ccmp_7.c
>> @@ -0,0 +1,46 @@
>> +/* { 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);
>> +}
>> +
>> +/* One explicit comparison is enough to keep each chain profitable. */
>> +
>> +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} 3 } } */
>> +/* { dg-final { scan-assembler-times {\torr\t} 5 } } */
>> --
>> 2.50.1 (Apple Git-155)