[Bug tree-optimization/107090] [aarch64] sequence logic should be combined with mul and umulh

"cvs-commit at gcc dot gnu.org via Gcc-bugs" <[email protected]>
Newsgroups gmane.comp.gcc.bugs
Message-ID <[email protected]/bugzilla/>
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=107090

--- Comment #20 from GCC Commits <cvs-commit at gcc dot gnu.org> ---
The master branch has been updated by Philipp Tomsich <[email protected]>:

https://gcc.gnu.org/g:806feb8e017b243de37e4502a6fc01fb76dd1529

commit r17-3437-g806feb8e017b243de37e4502a6fc01fb76dd1529
Author: Konstantinos Eleftheriou <[email protected]>
Date:   Wed Jul 8 06:58:21 2026 -0700

    forwprop: Match and fold the long-multiply carry form [PR107090]

    Recognize the schoolbook expansion of a 2N-bit unsigned multiply --
    four NxN partial products plus one overflow-compare carry, summed in a
    top-level + chain:

      xh*yh + (cross_sum >> N) + (low_accum >> N) + ((hilo > cross_sum) << N)
      cross_sum = xh*yl + xl*yh
      low_accum = (xl*yl >> N) + (cross_sum & mask)

    and fold it to a widening multiply plus right shift for the high part
    and a plain MULT_EXPR for the low part.  On AArch64 this reduces the
    16-instruction longhand in SPEC2026's 750.sealcrypto_r to
    umulh + mul + stp.

    The summands are matched by match.pd atoms; forwprop linearizes the
    outer chain, classifies each summand and looks the multiset up in a
    table of variants, guarded by cross-summand consistency checks (one
    operand pair, half-width shifts, hilo cross-half products).

    The high part is emitted as (N)(((2N) op1 * (2N) op2) >> N), for
    pass_optimize_widening_mul to lower to WIDEN_MULT_EXPR or
    MULT_HIGHPART_EXPR, and only when the target can multiply at 2N bits.
    The low part is a plain MULT_EXPR.

    Matching starts only at the end of a chain; folding at a use in
    another block could sink a loop-invariant multiply into a loop.  Up to
    LONG_MUL_MAX_EXTRAS leaves that are no long-multiply summand are set
    aside and re-applied on top of the fold, so a chain feeding a wider
    sum (acc += mulh (x, y)) still folds.  A leaf that does classify is
    always consumed; a subset search would be exponential.

            PR tree-optimization/107090

    gcc/ChangeLog:

            * match.pd: Add atom match recognizers for long-multiply
            (mul_hi, mul_lo, mul_hilo, mul_lolo, mul_hihi, mul_cross_sum,
            mul_low_accum, mul_carry_cross_sum).
            * tree-ssa-forwprop.cc (gimple_mul_hi): Declare.
            (gimple_mul_lo): Likewise.
            (gimple_mul_hilo): Likewise.
            (gimple_mul_lolo): Likewise.
            (gimple_mul_hihi): Likewise.
            (gimple_mul_cross_sum): Likewise.
            (gimple_mul_low_accum): Likewise.
            (gimple_mul_carry_cross_sum): Likewise.
            (build_mul_high_seq): New, emits (N)(((2N) op1 * (2N) op2) >> N)
            into a caller-supplied destination.
            (long_mul_apply_extras): New, combines the preserved addends back
            on top of the folded multiply.
            (create_mul_high_seq): New, replaces the statement with the
            high-part multiply plus any extras.
            (create_mul_low_seq): New, likewise for the low part.
            (enum long_mul_kind): New.
            (enum long_mul_extract): New.
            (struct long_mul_summand): New.
            (long_mul_linearize_chain): New, walks the outer add/ior chain
            into a multiset of leaves.
            (long_mul_is_lshift_def): New.
            (long_mul_set_summand): New.
            (long_mul_classify_carry): New.
            (long_mul_classify_plus_kinds): New.
            (long_mul_classify_hi_extract): New.
            (long_mul_classify_lo_extract): New.
            (long_mul_classify_shl_extract): New.
            (long_mul_classify_bare): New.
            (long_mul_classify_summand): New, classify each summand via the
            match.pd atoms.
            (long_mul_summand_compare): New.
            (struct long_mul_row): New.
            (long_mul_same_ops): New.
            (long_mul_is_cross_half): New.
            (long_mul_hilo_orientation): New, orientation of a mul_hilo
            capture relative to (op0, op1).
            (long_mul_canonical_ops): New.
            (long_mul_check_consistency): New, cross-summand consistency
            check (operand pairing, half-width shifts, hilo cross-half).
            (long_mul_signature_matches): New.
            (long_mul_hint_shared_intermediate): New, dump-file hint
            pointing at a shared inner addition.
            (long_mul_classify_match): New, looks a summand multiset up in
            long_mul_table and runs the per-row checks.
            (long_mul_classify_chain): New, linearize plus classify plus
            table lookup; sets aside leaves that classify as no summand.
            (match_long_mul): New, top-level entry: starts only at a chain
            end, classifies the chain, and dispatches to create_mul_high_seq
            / create_mul_low_seq with any preserved addends.
            (pass_forwprop::execute): Call match_long_mul on PLUS_EXPR and
            BIT_IOR_EXPR statements.

    gcc/testsuite/ChangeLog:

            * gcc.dg/torture/long-mul-64-run.c: New test.
            * gcc.dg/tree-ssa/long-mul-carry.c: New test.
            * gcc.dg/tree-ssa/long-mul-extra-addend.c: New test.
            * gcc.target/aarch64/long_mul.c: New test.
            * gcc.target/i386/long_mul.c: New test.

    Co-authored-by: Philipp Tomsich <[email protected]>
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.