On 9/4/26 6:35 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

Make candidate recognition report whether it found an explicit comparison.
It already validates every statement before it follows the next definition.
Reject a candidate without an explicit comparison.

TER fallback starts a new conditional-compare recognition call for each
forwarded suffix.  Cache accepted all-boolean subchains in the existing
per-function ssaexpand state so that these calls inspect a linear chain in
linear time.  The state is shared by cfgexpand and expression expansion and
is released when RTL expansion finishes.

The example then emits:

        orr     w0, w0, w1

Tests cover all-boolean and mixed chains, a non-binary boolean definition,
and a long rejected chain.

Changes since v1:
- Report explicit comparisons during candidate recognition.
- Cache all-boolean subchains so TER fallback stays linear.
- Add non-binary definition and long-chain tests.

gcc/

        PR middle-end/109832
        * ccmp.cc (ccmp_tree_comparison_p): Report whether an accepted leaf
        is a comparison.
        (ccmp_candidate_p): Propagate the result and cache all-boolean
        candidates.
        (expand_ccmp_expr): Reject an all-boolean candidate.
        * tree-outof-ssa.h (ssaexpand::ccmp_no_comparison): New member.
        * tree-outof-ssa.cc (finish_out_of_ssa): Free it.

gcc/testsuite/

        PR middle-end/109832
        * gcc.target/aarch64/ccmp_7.c: New test.
        * gcc.target/aarch64/ccmp_9.c: Likewise.
        * gcc.target/aarch64/ccmp_11.c: Likewise.
        * gcc.target/aarch64/ccmp_13.c: Likewise.

Signed-off-by: Kyrylo Tkachov<[email protected]>
I must be missing something here.  On both RISC-V and AArch64 we get this coming out of gimple:

bool f (bool x, bool y)
{
 bool _3;

;;   basic block 2, loop depth 0
;;    pred:       ENTRY
 _3 = x_1(D) | y_2(D);
 return _3;
;;    succ:       EXIT

}

So that's sensible.  On RISC-V that then expands into:

(insn 7 4 8 2 (set (reg:DI 138)
       (ior:DI (reg/v:DI 135 [ x ])
           (reg/v:DI 136 [ y ]))) "j.c":4:14 -1
    (nil))
(insn 8 7 9 2 (set (reg:DI 139)
(zero_extend:DI (subreg:QI (reg:DI 138) 0))) "j.c":4:14 discrim 1 -1
    (nil))


We later are able to track the nonzero bits in r135 and r136 and compute nonzero bits for r138.  That in turn allows removal of the zero extension resulting in:

:
ora0,a0,a1# 13[c=4 l=4]  *iordi3/0
ret# 27[c=0 l=4]  simple_return


aarch64 on the other hand generates this:

(insn 7 4 8 2 (set (reg:CC 66 cc)
(compare:CC (reg/v:SI 103 [ x ])
(const_int 0 [0]))) "j.c":4:14 -1
(nil))
(insn 8 7 11 2 (set (reg:CC 66 cc)
(if_then_else:CC (eq (reg:CC 66 cc)
(const_int 0 [0]))
(compare:CC (reg/v:SI 104 [ y ])
(const_int 0 [0]))
(unspec:CC [
(const_int 0 [0])
] UNSPEC_NZCV))) "j.c":4:14 -1
(nil))
(insn 11 8 12 2 (set (reg:SI 107)
(ne:SI (reg:CC 66 cc)
(const_int 0 [0]))) "j.c":4:14 -1
(nil))

Which is in the WTH space.    I suspect sensible initial code generation would really help here.

Not objecting to the patchkit right now as there may be a good reason for the initial RTL in the AArch port, but it's also the case that if we can arrange for clean code early, it's often better to do so.

jeff

Reply via email to