[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 #26 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:aac02c9666184d19334a0527ec444b5e55fbd113

commit r17-3443-gaac02c9666184d19334a0527ec444b5e55fbd113
Author: Konstantinos Eleftheriou <[email protected]>
Date:   Thu Jul 9 02:22:54 2026 -0700

    widening_mul: Lower long-multiply chains to inline longhand

    The forwprop long-multiply recognizer canonicalizes longhand
    high-part multiplies into

      lhs = (N) (((2N) op1 * (2N) op2) >> N)

    When the target cannot expand the wide form, lower the chain back to
    a longhand at N precision: (N/2)x(N/2)->N WIDEN_MULT_EXPR partial
    products where the optab exists, plain N-bit MULT_EXPR otherwise
    (value-equivalent, the halves being < 2^(N/2)).  No 2N value is
    materialized in gimple, so the lowering also covers modes with no
    expansion path at all (e.g. the high 128 bits of a 128x128 product
    with OImode in the mode table but no scalar OImode support).

    The longhand is built at narrow precision and converted once to the
    outer convert's lhs type, which conversion merging may have combined
    with a later user cast ((u64) mulh128 (x, y)); value-preserving for
    any integral lhs as the high part is < 2^N.

    An operand wider than N bits (a shared wide product, a sign-extended
    cast) is split into N-bit halves rather than truncated.  The split
    recurses through a chained wide product, reads a widening cast's
    halves from its source, and resolves a 2N value shifted down by N to
    the high half of what was shifted.  An operand that provably fits N
    bits yields a zero high half.  An operand PHI (left by PRE hoisting
    a (T_2N) cast) is split through its arguments and re-merged with two
    new PHIs; one split is shared by all chains reaching the PHI
    (PR126642).

    A 2N product also read outside the chain survives the split.  If
    every use takes only its low N bits it is narrowed to
    (2N) ((N) a * (N) b); a product surviving every lowering is rewritten
    by a closing sweep into the halves its uses read, the high one
    synthesized in longhand (PR126642).  Multiplies for which the target
    has a widening or high-part multiply are left to
    convert_mult_to_widen / convert_mult_to_highpart.

    The recognizer's HIGH_PART emit is gated on
    optimize_widening_mul_active_p, so the chain is emitted only when
    this pass will run to lower an unsupported 2N form; this replaces the
    recognizer's test for an expandable 2N multiply and extends the fold
    to targets without one.  The predicate is false for optimize_debug:
    -Og runs no widening_mul pass.

    Bootstrapped and regression-tested on AArch64, x86-64, i686, ARM and
    PowerPC.

            PR tree-optimization/107090
            PR tree-optimization/126642

    gcc/ChangeLog:

            * match.pd (long_mul_high_chain): New atom for the emitted
high-part chain.
            * tree-ssa-forwprop.cc (long_mul_classify_match): Gate the
            HIGH_PART wide-chain emit on optimize_widening_mul_active_p
            rather than on the target having a 2N multiply.
            * tree-ssa-math-opts.cc (can_widen_to_narrow_p): New.
            (build_long_mul_partials): New; emits the four partial products
            using widening or plain multiplies.
            (emit_long_mul_highpart): New; the high N bits of an N-bit
            product, as a longhand over (N/2)-bit partials.
            (combine_long_mul_halves): New; the high N bits of a product of
            two 2N-bit values given as N-bit halves.
            (long_mul_op_fits_p): New; true when an operand is provably
            representable in narrow_prec unsigned bits.
            (long_mul_split_operand): New; splits an operand into N-bit
            halves using only N-bit operations.
            (struct long_mul_halves): New; the halves an operand PHI was
            split into.
            (struct long_mul_arg_split): New; an argument of an operand PHI
            with the statements that split it.
            (long_mul_split_phi): New; splits an operand PHI by splitting its
            arguments and merging the halves with two new PHIs. Record the
            halves and reuse them for the next consumer of the same PHI.
            (long_mul_high_half_uses): New; collects the `>> N' uses forming
            a product's high half.
            (long_mul_only_low_half_used_p): New.
            (unexpandable_long_mul_p): New; true for a 2N multiply in a mode
            the target cannot multiply.
            (narrow_long_mul_low_half): New; narrow a 2N low-half-only mult
            the target cannot expand to an N-bit mult.
            (narrow_long_mul_operands): New; recurse into chained wide
            products after a narrowing/lowering.
            (finish_long_mul_low_half): New; narrows or removes a 2N mult
            whose high half is synthesized elsewhere.
            (narrow_long_mul_halves): New; rewrites a 2N multiply into the
            N-bit halves its uses read.
            (gimple_long_mul_high_chain): Declare.
            (lower_long_mul_high_chain): New; lowers the high-part chain to a
            longhand at narrow precision. Split each operand into N-bit
            halves and combine, handling an operand wider than narrow_prec
            instead of rejecting it. Narrow or drop the residual 2N mult via
            the helpers and recurse into its operands.
            (optimize_widening_mul_active_p): New; shared gate used by
            pass_optimize_widening_mul::gate and by the forwprop long-multiply
            recognizer. Return false when optimize_debug.
            (math_opts_dom_walker::after_dom_children): Dispatch to
            lower_long_mul_high_chain on the outer convert. Run
            narrow_long_mul_low_half on MULT_EXPR before the widen/fma
            conversion attempts.
            (pass_optimize_widening_mul::execute): Sweep the function for
            multiplies left in a mode the target cannot expand. Scope the
            record of split operand PHIs to one run of the pass.
            * tree-ssa-math-opts.h (optimize_widening_mul_active_p): Declare.

    gcc/testsuite/ChangeLog:

            * gcc.dg/torture/long-mul-64-run.c: Add near-miss variants of the
            idiom, cross-checked against their literal meaning.
            * gcc.dg/tree-ssa/long-mul-carry.c: Add scans for the high-part
            chain lowering and its dump message. Exclude sparc/hppa from
            the chain-lowering scan.
            * gcc.dg/tree-ssa/long-mul-ladder.c: Likewise.
            * lib/target-supports.exp (check_effective_target_oi_mode): New;
            enumerates targets whose mode table declares OImode.
            * gcc.dg/long-mul-128-Og.c: New test.
            * gcc.dg/torture/long-mul-128.c: New test.
            * gcc.dg/tree-ssa/long-mul-chain-cse-128.c: New test.
            * gcc.dg/tree-ssa/long-mul-chain-trunc-128.c: New test.
            * gcc.target/arm/long-mul-thumb1-inline.c: New test.
            * gcc.target/arm/long-mul-umull.c: New test.
            * gcc.target/i386/long-mul-phi-split.c: New test.
            * gcc.target/i386/long-mul-sweep.c: New test.
            * gcc.target/i386/widen_mult_high_chain.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.