Re: [PATCH v8 0/7] Recognize and fold longhand wide-multiplication idioms [PR107090]

Philipp Tomsich <[email protected]> Tue, 4 Aug 2026 19:01:09 +0200
Newsgroups gmane.comp.gcc.patches
Message-ID <CAAeLtUBJRovnmbFd9r3xhaZ_VHSgiG2YuLwXpxqpkNZ5s7T2BQ@mail.gmail.com>
--000000000000a26aed06583b9ab9
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

Reverted.

On Tue, 4 Aug 2026 at 18:58, Andrea Pinski <[email protected]>
wrote:

> On Mon, Aug 3, 2026 at 8:57=E2=80=AFAM Konstantinos Eleftheriou
> <[email protected]> wrote:
> >
> >
> > This patch series teaches GCC to recognize longhand 64x64->128
> > wide-multiplication idioms and replace them with native multiply
> > instructions: a widening multiply followed by a right shift for the
> > high part, and a plain MULT_EXPR for the low part.
> >
> > Portable C/C++ code that needs a 128-bit product on a 64-bit target
> > often resorts to a longhand decomposition: split operands into 32-bit
> > halves, compute four partial products, and propagate carries manually.
> > This pattern appears in a number of real-world codebases, including
> > SPEC2026's 750.sealcrypto_r (seal/util/uintarith.h) and several
> > examples from Hacker's Delight. Targets like AArch64 (mul/umulh) and
> > x86-64 can compute the full 128-bit product in one or two instructions,
> > but GCC does not currently fold the longhand sequence back to these.
> >
> > The recognizer emits the canonical widening shape
> >
> >   (N)(((2N) a * (2N) b) >> N)
> >
> > for the high part and a plain MULT_EXPR for the low part. The high
> > part is emitted as a shift of the wide product, not as a bare
> > (2N) a * (2N) b: the `>> N' form is the MULT_HIGHPART idiom, so
> > pass_optimize_widening_mul rewrites it to the target's native high-part
> > multiply (e.g. umulh) without ever forming the full 2N product. A bare
> > widening product would also compute the unwanted low half, and where 2N
> > has no native multiply -- the 128x128 case, 2N =3D OImode, which the mo=
de
> > table carries but the target cannot expand -- there is no way to form
> > it at all. For that case the final patch resynthesizes the longhand at
> > narrow precision from (N/2)-wide partial products, so the fold never
> > depends on a 2N multiply the target lacks.
> >
> > The series is split into seven patches:
>
> Two things, this breaks bootstrap on x86_64-linux-gnu.
> I filed https://gcc.gnu.org/bugzilla/show_bug.cgi?id=3D126642 .
> Can we revert this until that is fixed?
>
> Second please don't squash the patches into one commit next time. If
> you do please send a full updated patch to the list of what you
> committed.  This has been GCC's policy.
>
> Thanks,
> Andrea
>
>
> >
> >   1/7  forwprop: Match and fold the long-multiply carry form
> >        [PR107090]
> >
> >        Adds the match.pd atom patterns and the forwprop framework:
> >        linearize the outer add/ior chain, classify each summand, and
> >        match the multiset against a table of decomposed variants.
> >        Carries the base carry form, a single overflow comparison on
> >        the cross-sum. Matching starts only at the end of a chain, and
> >        leaves that are not long-multiply summands are preserved and
> >        re-applied on top of the fold, so a chain that mixes the idiom
> >        with unrelated addends still folds.
> >
> >   2/7 - 5/7  Add the remaining recognized variants: carry-low-sum,
> >              two-carry, ladder, and low-plus.
> >
> >   6/7  match.pd, forwprop: Recognize long-multiply carries written as
> >        2-arg PHI
> >
> >        Hand-written code often writes the carry as a 2-arg PHI
> >        (`if (overflow) result +=3D pow2;`) with no top-level + at the
> >        result. Adds cond_carry_add / cond_carry_add_neg recognizers
> >        for that shape and a match_long_mul_phi entry that synthesizes
> >        the carry summand from the PHI bindings and reuses the table
> >        walk and emit path.
> >
> >   7/7  widening_mul: Lower long-multiply chains to inline longhand
> >
> >        Lowers the high-part chain to a longhand high-part at narrow
> >        precision when the target has no expansion path for the 2N
> >        form, using (N/2)-by-(N/2)->N widening multiplies where the
> >        optab exists and plain N-bit multiplies otherwise. Operands
> >        that are themselves wider than N are split into N-bit halves
> >        rather than truncated, and a 2N product left with only low-half
> >        uses is narrowed to an N-bit multiply rather than reaching
> >        expansion. When an operand holds a product's high N bits, those
> >        come from the product's own operands instead of the 2N shift.
> >        Paired with pass_optimize_widening_mul so the chain is emitted
> >        only when the pass will run to rescue an unsupported 2N shape.
> >
> > On SPEC2026's 750.sealcrypto_r:
> >
> >   - AArch64 Neoverse-N1: 25% improvement
> >   - x86-64 Zen4:         59% improvement
> >
> > Compile-time impact is negligible: recompiling gcc/*.cc
> > (checking=3Dyes,extra) with the series compiler versus its base adds
> > about 0.1% overall, confined to forwprop, where the recognizer runs
> > and grows the pass by a few percent.
> >
> > Bootstrapped/regtested on AArch64, x86-64, ARM and PowerPC.
> >
> > Changes in v8:
> > - 1/7 starts matching only at chain ends and sets aside leaves that are
> >   not long-multiply summands, re-applying them on top of the fold. The
> >   two go together. Either alone regresses a foldable chain. Now folds
> >   shapes such as `acc +=3D mulh (x, y)`.
> > - 1/7 factors out build_mul_high_seq, long_mul_classify_match and
> >   long_mul_classify_chain for the PHI entry in 6/7 to reuse, and takes
> >   a gassign * in the matcher and the emitters.
> > - The long_mul_high_chain atom binds each mult operand through
> >   `(convert? @X)`, so a PRE-hoisted cast into a PHI still matches. An
> >   operand wider than N is now split into N-bit halves rather than
> >   rejected, which previously left the 2N multiply for expansion.
> > - optimize_widening_mul_active_p returns false for optimize_debug: -Og
> >   runs no widening_mul pass to lower the emitted chain, so the
> >   unexpandable multiply reached expand.
> > - Add narrow_long_mul_low_half: when a 2N `res =3D a * b` has uses only=
 in
> >   its low N bits and the target cannot expand 2N, rewrite it to
> >   `res =3D (2N) ((N)a * (N)b)`. The split-based lowering covers a chain=
ed
> >   2N operand by recursing into it, but not a shared 2N product left wit=
h
> >   only low-half uses, which is what ICEs libgo's p521_fiat64.go on ARM3=
2.
> > - long_mul_split_operand resolves a 2N value shifted down by N to the
> >   high half of what was shifted, instead of truncating the shift. The
> >   truncation read the shift and so kept a chained product live past its
> >   own lowering, aborting expand_mult on a target without a 2N multiply.
> >   Reachable from Go on ARM32 as bits.Mul64 (bits.Mul64 (x, y), z), wher=
e
> >   the unexpandable mode is TImode, and on aarch64 and x86-64 from a
> >   chained __int128 longhand, where it is OImode.
> > - New coverage: near misses of the idiom, checked at runtime against
> >   their literal meaning, a signed narrow-cast operand on Thumb-1, and
> >   chained longhands through both halves on ARM32.
> >
> > Changes in v7:
> > - Split the single long-multiply fold (was 1/2) into five patches: a
> >   base patch carrying the framework and the carry form, then one
> >   patch each for the carry-low-sum, two-carry, ladder and low-plus
> >   variants.  Easier to review and to bisect a variant in isolation.
> >   The PHI-form recognition follows as 6/7, unchanged from v6's 2/2.
> > - New 7/7: lower the emitted high-part chain to inline longhand at
> >   narrow precision when the target has no expansion path for the 2N
> >   form.  v6 only emitted a HIGH_PART when the 2N scalar mode existed
> >   and skipped it otherwise; v7 emits it and pairs the recognizer with
> >   lower_long_mul_high_chain via optimize_widening_mul_active_p, so a
> >   128x128 high part on a target whose mode table has OImode but no
> >   scalar OImode support is now built from (N/2)-wide partial products
> >   instead of a 2N multiply the target cannot expand.
> > - Refuse the HIGH_PART emit and the chain lowering for BITINT_TYPE,
> >   keeping the recognizer and the lowering gate symmetric.
> > - Add per-variant tree-ssa tests, 128-bit torture and runtime tests,
> >   arm thumb1 / umull inline tests, and a check_effective_target
> >   _oi_mode helper.
> >
> > Changes in v6:
> > - Reorder so the long-multiply fold (was 2/2) is now 1/2 and a new
> >   PHI-form recognition pass is 2/2.  Reverting 2/2 leaves a working
> >   long-multiply fold for the flat-shifted-compare carry form.
> > - Drop v5's standalone flatten_cond_carry_add driver.  The same
> >   cond_carry_add / cond_carry_add_neg match.pd recognizers now feed
> >   a match_long_mul_phi entry inside the long-multiply fold, so a
> >   PHI-shaped carry folds straight to the wide-multiply output.
> > - Factor long_mul_classify_chain, long_mul_classify_match and
> >   build_mul_high_seq for sharing between match_long_mul and the new
> >   match_long_mul_phi.
> > - cond_carry_add_neg uses le / ge instead of gt / lt to encode the
> >   carry condition strictly.  v5 inverted the compare via
> >   invert_tree_comparison in the flatten driver; v6 synthesises the
> >   carry summand directly inside match_long_mul_phi and so requires
> >   the recogniser to encode the strict form.
> > - Delete forwprop-44/45/46.c; add PHI-form coverage in
> >   long-mul-carry.c, long-mul-two-carry.c, long-mul-boundary.c
> >   and long-mul-boundary-64.c.
> > - Add PHI-form near-miss tests in long-mul-partial.c and
> >   operand-swap polarity coverage in long-mul-boundary{,-64}.c.
> > - Refresh stale long-mul comment references (check_hilo_and_ops,
> >   fold_mul_low_plus) and reword mul_carry_low's :c-on-gt note to
> >   the correct LT form (a + b < a).
> >
> > Changes in v5:
> > - 1/2:
> >   - Replace the match.pd simplify on COND_EXPR with cond_carry_add
> >     / cond_carry_add_neg match recognizers (cond^), split by gcond
> >     polarity, plus a flatten_cond_carry_add driver in
> >     tree-ssa-forwprop.cc.  The driver inverts the gcond's
> >     comparison for the _neg form.  Modelled on match_saturation_add.
> >   - Remove fold_cond_carry_add_profitable_p and the tm_p.h /
> >     predict.h includes from gimple-match-head.cc.  The width >
> >     MAX_FIXED_MODE_SIZE and width % 2 !=3D 0 guards were
> >     prerequisites for the can_mult_highpart_p fallback path, not
> >     soundness checks.  type_has_mode_precision_p subsumes them.
> >   - Retarget the test scans from phiopt2 to forwprop1.  Add
> >     forwprop-46.c covering all four arm/comparison polarities.
> >   - forwprop-45.c uses __UINT64_TYPE__ instead of unsigned long
> >     and drops the lp64 restriction, covering the type > word_mode
> >     regime on 32-bit targets.
> > - 2/2:
> >   - Lower the high-part as (N)(((2N) op1 * (2N) op2) >> N).
> >     pass_optimize_widening_mul rewrites this to WIDEN_MULT_EXPR /
> >     MULT_HIGHPART_EXPR on supporting targets.  Removes
> >     can_mult_highpart_p queries from forwprop.
> >   - Replace the can_mult_highpart_p prefilter in match_long_mul
> >     with a targetm.scalar_mode_supported_p check on the 2N mode.
> >     Test scans select on int128, mirroring the gate, instead of
> >     lp64.
> >   - Drop the m_long_mul_fold_p pass parameter and its passes.def
> >     arguments.  The long-mul fold runs in every forwprop instance.
> >     Test scans retargeted from forwprop2 to forwprop1.
> >   - Stop restricting forwprop-44.c to lp64.  With the
> >     can_mult_highpart_p gating gone, the fold is target-independent
> >     and the test passes on ilp32 targets too.
> >
> > Changes in v4:
> > - 1/2:
> >   - Rebuild the guard with per-conjunct reasoning: require both
> >     operands to be SSA names (drops degenerate one-side-constant
> >     cases that fold trivially elsewhere), require the type to
> >     have_mode_precision_p (excludes BITINT_TYPE precision !=3D mode
> >     and similar oddities), drop the explicit MAX_FIXED_MODE_SIZE
> >     width cap (subsumed by have_mode_precision_p), and gate on the
> >     flat optab via can_mult_highpart_p of the 2N mode.
> >   - Retain BRANCH_COST >=3D 2: keep the flatten conditional on a
> >     target where the branchless form is generally cheaper.
> >   - Rewrite the cover letter to describe the gate as the
> >     composition of these conjuncts and to clarify that the
> >     transformation now only ever introduces a (mul_hi-like)
> >     can_mult_highpart_p shape, not a libgcc multi-precision call.
> > - 2/2:
> >   - Convert per-variant fold_mul_* functions into a
> >     table-driven long_mul fold framework.
> >   - Migrate each variant into a row in long_mul_table (six
> >     HIGH_PART, six LOW_PART rows) keyed by (kind, extract).
> >   - Add cross-summand consistency checks
> >     (long_mul_check_consistency, long_mul_check_two_carries,
> >     long_mul_check_low_plus_defer) shared across rows.
> >   - Drop emission to a libgcc multi-precision call from RTL
> >     expansion; defer to pass_optimize_widening_mul / RTL
> >     expansion to pick native umul_highpart, a widening multiply, or
> >     a synthesised sequence.  Emission is gated on
> >     can_mult_highpart_p.
> >   - Structural redesign: per-variant fold_mul_* functions
> >     consolidated into a single linearise + classify + table-lookup
> >     framework (long_mul_table, match_long_mul,
> >     long_mul_classify_summand, long_mul_check_consistency).  Each
> >     variant is now a row in long_mul_table; consistency checks are
> >     shared across rows.
> >   - Fast-fail prefilters in match_long_mul: LHS-type prefilter at
> >     entry (no legitimate long-mul leaf has a signed / pointer /
> >     float / odd-width type) and a can_mult_highpart_p probe before
> >     the row loop to skip HIGH_PART rows on unsupported targets.
> >   - Bound long_mul_linearize_chain mid-walk by LONG_MUL_MAX_SUMMANDS
> >     so an overlong addition / BIT_IOR chain bails immediately rather
> >     than after a full traversal.
> >   - Emit a dump-file hint pointing at the shared inner addition when
> >     long-mul folding rejects a chain because of a multi-used
> >     intermediate (caching the partial sum into a single-use SSA
> >     name normally enables the fold).
> >
> > Changes in v3:
> > - Moved carry-diamond flattening from forwprop to match.pd,
> > replacing ~460 lines of C++ with a 17-line match.pd pattern.
> > - Two-carry test scans forwprop3 (the first forwprop after phiopt2,
> > since early phiopt restricts which tree codes are allowed).
> > - Set location for new sequences.
> > - Updated mul_carry_low pattern.
> > - Added the `mul_low_plus` pattern.
> > - Fixed formatting issues.
> >
> > Changes in v2:
> > - Fixed the testcases by separating the high part's fold count for
> > 32-bit and 64-bit targets.
> >
> > Konstantinos Eleftheriou (7):
> >   forwprop: Match and fold the long-multiply carry form [PR107090]
> >   forwprop: Add long-multiply carry-low-sum variant
> >   forwprop: Add long-multiply two-carry variant
> >   forwprop: Add long-multiply ladder variants
> >   forwprop: Add long-multiply low-plus variant
> >   match.pd, forwprop: Recognize long-multiply carries written as 2-arg
> >     PHI
> >   widening_mul: Lower long-multiply chains to inline longhand
> >
> >  gcc/match.pd                                  |  198 +++
> >  gcc/testsuite/gcc.dg/long-mul-128-Og.c        |   26 +
> >  gcc/testsuite/gcc.dg/torture/long-mul-128.c   |  121 ++
> >  .../gcc.dg/torture/long-mul-64-run.c          |  180 +++
> >  .../gcc.dg/tree-ssa/long-mul-boundary-64.c    |  417 ++++++
> >  .../gcc.dg/tree-ssa/long-mul-boundary.c       |  394 ++++++
> >  .../gcc.dg/tree-ssa/long-mul-carry.c          |  385 ++++++
> >  .../gcc.dg/tree-ssa/long-mul-chain-cse-128.c  |   52 +
> >  .../tree-ssa/long-mul-chain-trunc-128.c       |   80 ++
> >  .../gcc.dg/tree-ssa/long-mul-extra-addend.c   |   63 +
> >  .../gcc.dg/tree-ssa/long-mul-ladder.c         |  333 +++++
> >  .../gcc.dg/tree-ssa/long-mul-low-plus.c       |   54 +
> >  .../gcc.dg/tree-ssa/long-mul-partial.c        |  193 +++
> >  .../gcc.dg/tree-ssa/long-mul-two-carry.c      |  140 ++
> >  gcc/testsuite/gcc.target/aarch64/long_mul.c   |  100 ++
> >  .../gcc.target/arm/long-mul-thumb1-inline.c   |   47 +
> >  gcc/testsuite/gcc.target/arm/long-mul-umull.c |   73 +
> >  gcc/testsuite/gcc.target/i386/long_mul.c      |  100 ++
> >  .../gcc.target/i386/widen_mult_high_chain.c   |   32 +
> >  gcc/testsuite/lib/target-supports.exp         |   20 +
> >  gcc/tree-ssa-forwprop.cc                      | 1197 ++++++++++++++++-
> >  gcc/tree-ssa-math-opts.cc                     |  492 ++++++-
> >  gcc/tree-ssa-math-opts.h                      |    2 +
> >  23 files changed, 4690 insertions(+), 9 deletions(-)
> >  create mode 100644 gcc/testsuite/gcc.dg/long-mul-128-Og.c
> >  create mode 100644 gcc/testsuite/gcc.dg/torture/long-mul-128.c
> >  create mode 100644 gcc/testsuite/gcc.dg/torture/long-mul-64-run.c
> >  create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/long-mul-boundary-64.=
c
> >  create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/long-mul-boundary.c
> >  create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/long-mul-carry.c
> >  create mode 100644
> gcc/testsuite/gcc.dg/tree-ssa/long-mul-chain-cse-128.c
> >  create mode 100644
> gcc/testsuite/gcc.dg/tree-ssa/long-mul-chain-trunc-128.c
> >  create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/long-mul-extra-addend=
.c
> >  create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/long-mul-ladder.c
> >  create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/long-mul-low-plus.c
> >  create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/long-mul-partial.c
> >  create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/long-mul-two-carry.c
> >  create mode 100644 gcc/testsuite/gcc.target/aarch64/long_mul.c
> >  create mode 100644 gcc/testsuite/gcc.target/arm/long-mul-thumb1-inline=
.c
> >  create mode 100644 gcc/testsuite/gcc.target/arm/long-mul-umull.c
> >  create mode 100644 gcc/testsuite/gcc.target/i386/long_mul.c
> >  create mode 100644 gcc/testsuite/gcc.target/i386/widen_mult_high_chain=
.c
> >
> > --
> > 2.55.0
>

--000000000000a26aed06583b9ab9
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr">Reverted.</div><br><div class=3D"gmail_quote gmail_quote_c=
ontainer"><div dir=3D"ltr" class=3D"gmail_attr">On Tue, 4 Aug 2026 at 18:58=
, Andrea Pinski &lt;<a href=3D"mailto:[email protected]">andre=
[email protected]</a>&gt; wrote:<br></div><blockquote class=3D"gmai=
l_quote" style=3D"margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,20=
4,204);padding-left:1ex">On Mon, Aug 3, 2026 at 8:57=E2=80=AFAM Konstantino=
s Eleftheriou<br>
&lt;<a href=3D"mailto:[email protected]" target=3D"_blank">=
[email protected]</a>&gt; wrote:<br>
&gt;<br>
&gt;<br>
&gt; This patch series teaches GCC to recognize longhand 64x64-&gt;128<br>
&gt; wide-multiplication idioms and replace them with native multiply<br>
&gt; instructions: a widening multiply followed by a right shift for the<br=
>
&gt; high part, and a plain MULT_EXPR for the low part.<br>
&gt;<br>
&gt; Portable C/C++ code that needs a 128-bit product on a 64-bit target<br=
>
&gt; often resorts to a longhand decomposition: split operands into 32-bit<=
br>
&gt; halves, compute four partial products, and propagate carries manually.=
<br>
&gt; This pattern appears in a number of real-world codebases, including<br=
>
&gt; SPEC2026&#39;s 750.sealcrypto_r (seal/util/uintarith.h) and several<br=
>
&gt; examples from Hacker&#39;s Delight. Targets like AArch64 (mul/umulh) a=
nd<br>
&gt; x86-64 can compute the full 128-bit product in one or two instructions=
,<br>
&gt; but GCC does not currently fold the longhand sequence back to these.<b=
r>
&gt;<br>
&gt; The recognizer emits the canonical widening shape<br>
&gt;<br>
&gt;=C2=A0 =C2=A0(N)(((2N) a * (2N) b) &gt;&gt; N)<br>
&gt;<br>
&gt; for the high part and a plain MULT_EXPR for the low part. The high<br>
&gt; part is emitted as a shift of the wide product, not as a bare<br>
&gt; (2N) a * (2N) b: the `&gt;&gt; N&#39; form is the MULT_HIGHPART idiom,=
 so<br>
&gt; pass_optimize_widening_mul rewrites it to the target&#39;s native high=
-part<br>
&gt; multiply (e.g. umulh) without ever forming the full 2N product. A bare=
<br>
&gt; widening product would also compute the unwanted low half, and where 2=
N<br>
&gt; has no native multiply -- the 128x128 case, 2N =3D OImode, which the m=
ode<br>
&gt; table carries but the target cannot expand -- there is no way to form<=
br>
&gt; it at all. For that case the final patch resynthesizes the longhand at=
<br>
&gt; narrow precision from (N/2)-wide partial products, so the fold never<b=
r>
&gt; depends on a 2N multiply the target lacks.<br>
&gt;<br>
&gt; The series is split into seven patches:<br>
<br>
Two things, this breaks bootstrap on x86_64-linux-gnu.<br>
I filed <a href=3D"https://gcc.gnu.org/bugzilla/show_bug.cgi?id=3D126642" r=
el=3D"noreferrer" target=3D"_blank">https://gcc.gnu.org/bugzilla/show_bug.c=
gi?id=3D126642</a> .<br>
Can we revert this until that is fixed?<br>
<br>
Second please don&#39;t squash the patches into one commit next time. If<br=
>
you do please send a full updated patch to the list of what you<br>
committed.=C2=A0 This has been GCC&#39;s policy.<br>
<br>
Thanks,<br>
Andrea<br>
<br>
<br>
&gt;<br>
&gt;=C2=A0 =C2=A01/7=C2=A0 forwprop: Match and fold the long-multiply carry=
 form<br>
&gt;=C2=A0 =C2=A0 =C2=A0 =C2=A0 [PR107090]<br>
&gt;<br>
&gt;=C2=A0 =C2=A0 =C2=A0 =C2=A0 Adds the match.pd atom patterns and the for=
wprop framework:<br>
&gt;=C2=A0 =C2=A0 =C2=A0 =C2=A0 linearize the outer add/ior chain, classify=
 each summand, and<br>
&gt;=C2=A0 =C2=A0 =C2=A0 =C2=A0 match the multiset against a table of decom=
posed variants.<br>
&gt;=C2=A0 =C2=A0 =C2=A0 =C2=A0 Carries the base carry form, a single overf=
low comparison on<br>
&gt;=C2=A0 =C2=A0 =C2=A0 =C2=A0 the cross-sum. Matching starts only at the =
end of a chain, and<br>
&gt;=C2=A0 =C2=A0 =C2=A0 =C2=A0 leaves that are not long-multiply summands =
are preserved and<br>
&gt;=C2=A0 =C2=A0 =C2=A0 =C2=A0 re-applied on top of the fold, so a chain t=
hat mixes the idiom<br>
&gt;=C2=A0 =C2=A0 =C2=A0 =C2=A0 with unrelated addends still folds.<br>
&gt;<br>
&gt;=C2=A0 =C2=A02/7 - 5/7=C2=A0 Add the remaining recognized variants: car=
ry-low-sum,<br>
&gt;=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 two-carry, ladder, and=
 low-plus.<br>
&gt;<br>
&gt;=C2=A0 =C2=A06/7=C2=A0 match.pd, forwprop: Recognize long-multiply carr=
ies written as<br>
&gt;=C2=A0 =C2=A0 =C2=A0 =C2=A0 2-arg PHI<br>
&gt;<br>
&gt;=C2=A0 =C2=A0 =C2=A0 =C2=A0 Hand-written code often writes the carry as=
 a 2-arg PHI<br>
&gt;=C2=A0 =C2=A0 =C2=A0 =C2=A0 (`if (overflow) result +=3D pow2;`) with no=
 top-level + at the<br>
&gt;=C2=A0 =C2=A0 =C2=A0 =C2=A0 result. Adds cond_carry_add / cond_carry_ad=
d_neg recognizers<br>
&gt;=C2=A0 =C2=A0 =C2=A0 =C2=A0 for that shape and a match_long_mul_phi ent=
ry that synthesizes<br>
&gt;=C2=A0 =C2=A0 =C2=A0 =C2=A0 the carry summand from the PHI bindings and=
 reuses the table<br>
&gt;=C2=A0 =C2=A0 =C2=A0 =C2=A0 walk and emit path.<br>
&gt;<br>
&gt;=C2=A0 =C2=A07/7=C2=A0 widening_mul: Lower long-multiply chains to inli=
ne longhand<br>
&gt;<br>
&gt;=C2=A0 =C2=A0 =C2=A0 =C2=A0 Lowers the high-part chain to a longhand hi=
gh-part at narrow<br>
&gt;=C2=A0 =C2=A0 =C2=A0 =C2=A0 precision when the target has no expansion =
path for the 2N<br>
&gt;=C2=A0 =C2=A0 =C2=A0 =C2=A0 form, using (N/2)-by-(N/2)-&gt;N widening m=
ultiplies where the<br>
&gt;=C2=A0 =C2=A0 =C2=A0 =C2=A0 optab exists and plain N-bit multiplies oth=
erwise. Operands<br>
&gt;=C2=A0 =C2=A0 =C2=A0 =C2=A0 that are themselves wider than N are split =
into N-bit halves<br>
&gt;=C2=A0 =C2=A0 =C2=A0 =C2=A0 rather than truncated, and a 2N product lef=
t with only low-half<br>
&gt;=C2=A0 =C2=A0 =C2=A0 =C2=A0 uses is narrowed to an N-bit multiply rathe=
r than reaching<br>
&gt;=C2=A0 =C2=A0 =C2=A0 =C2=A0 expansion. When an operand holds a product&=
#39;s high N bits, those<br>
&gt;=C2=A0 =C2=A0 =C2=A0 =C2=A0 come from the product&#39;s own operands in=
stead of the 2N shift.<br>
&gt;=C2=A0 =C2=A0 =C2=A0 =C2=A0 Paired with pass_optimize_widening_mul so t=
he chain is emitted<br>
&gt;=C2=A0 =C2=A0 =C2=A0 =C2=A0 only when the pass will run to rescue an un=
supported 2N shape.<br>
&gt;<br>
&gt; On SPEC2026&#39;s 750.sealcrypto_r:<br>
&gt;<br>
&gt;=C2=A0 =C2=A0- AArch64 Neoverse-N1: 25% improvement<br>
&gt;=C2=A0 =C2=A0- x86-64 Zen4:=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A059% improv=
ement<br>
&gt;<br>
&gt; Compile-time impact is negligible: recompiling gcc/*.cc<br>
&gt; (checking=3Dyes,extra) with the series compiler versus its base adds<b=
r>
&gt; about 0.1% overall, confined to forwprop, where the recognizer runs<br=
>
&gt; and grows the pass by a few percent.<br>
&gt;<br>
&gt; Bootstrapped/regtested on AArch64, x86-64, ARM and PowerPC.<br>
&gt;<br>
&gt; Changes in v8:<br>
&gt; - 1/7 starts matching only at chain ends and sets aside leaves that ar=
e<br>
&gt;=C2=A0 =C2=A0not long-multiply summands, re-applying them on top of the=
 fold. The<br>
&gt;=C2=A0 =C2=A0two go together. Either alone regresses a foldable chain. =
Now folds<br>
&gt;=C2=A0 =C2=A0shapes such as `acc +=3D mulh (x, y)`.<br>
&gt; - 1/7 factors out build_mul_high_seq, long_mul_classify_match and<br>
&gt;=C2=A0 =C2=A0long_mul_classify_chain for the PHI entry in 6/7 to reuse,=
 and takes<br>
&gt;=C2=A0 =C2=A0a gassign * in the matcher and the emitters.<br>
&gt; - The long_mul_high_chain atom binds each mult operand through<br>
&gt;=C2=A0 =C2=A0`(convert? @X)`, so a PRE-hoisted cast into a PHI still ma=
tches. An<br>
&gt;=C2=A0 =C2=A0operand wider than N is now split into N-bit halves rather=
 than<br>
&gt;=C2=A0 =C2=A0rejected, which previously left the 2N multiply for expans=
ion.<br>
&gt; - optimize_widening_mul_active_p returns false for optimize_debug: -Og=
<br>
&gt;=C2=A0 =C2=A0runs no widening_mul pass to lower the emitted chain, so t=
he<br>
&gt;=C2=A0 =C2=A0unexpandable multiply reached expand.<br>
&gt; - Add narrow_long_mul_low_half: when a 2N `res =3D a * b` has uses onl=
y in<br>
&gt;=C2=A0 =C2=A0its low N bits and the target cannot expand 2N, rewrite it=
 to<br>
&gt;=C2=A0 =C2=A0`res =3D (2N) ((N)a * (N)b)`. The split-based lowering cov=
ers a chained<br>
&gt;=C2=A0 =C2=A02N operand by recursing into it, but not a shared 2N produ=
ct left with<br>
&gt;=C2=A0 =C2=A0only low-half uses, which is what ICEs libgo&#39;s p521_fi=
at64.go on ARM32.<br>
&gt; - long_mul_split_operand resolves a 2N value shifted down by N to the<=
br>
&gt;=C2=A0 =C2=A0high half of what was shifted, instead of truncating the s=
hift. The<br>
&gt;=C2=A0 =C2=A0truncation read the shift and so kept a chained product li=
ve past its<br>
&gt;=C2=A0 =C2=A0own lowering, aborting expand_mult on a target without a 2=
N multiply.<br>
&gt;=C2=A0 =C2=A0Reachable from Go on ARM32 as bits.Mul64 (bits.Mul64 (x, y=
), z), where<br>
&gt;=C2=A0 =C2=A0the unexpandable mode is TImode, and on aarch64 and x86-64=
 from a<br>
&gt;=C2=A0 =C2=A0chained __int128 longhand, where it is OImode.<br>
&gt; - New coverage: near misses of the idiom, checked at runtime against<b=
r>
&gt;=C2=A0 =C2=A0their literal meaning, a signed narrow-cast operand on Thu=
mb-1, and<br>
&gt;=C2=A0 =C2=A0chained longhands through both halves on ARM32.<br>
&gt;<br>
&gt; Changes in v7:<br>
&gt; - Split the single long-multiply fold (was 1/2) into five patches: a<b=
r>
&gt;=C2=A0 =C2=A0base patch carrying the framework and the carry form, then=
 one<br>
&gt;=C2=A0 =C2=A0patch each for the carry-low-sum, two-carry, ladder and lo=
w-plus<br>
&gt;=C2=A0 =C2=A0variants.=C2=A0 Easier to review and to bisect a variant i=
n isolation.<br>
&gt;=C2=A0 =C2=A0The PHI-form recognition follows as 6/7, unchanged from v6=
&#39;s 2/2.<br>
&gt; - New 7/7: lower the emitted high-part chain to inline longhand at<br>
&gt;=C2=A0 =C2=A0narrow precision when the target has no expansion path for=
 the 2N<br>
&gt;=C2=A0 =C2=A0form.=C2=A0 v6 only emitted a HIGH_PART when the 2N scalar=
 mode existed<br>
&gt;=C2=A0 =C2=A0and skipped it otherwise; v7 emits it and pairs the recogn=
izer with<br>
&gt;=C2=A0 =C2=A0lower_long_mul_high_chain via optimize_widening_mul_active=
_p, so a<br>
&gt;=C2=A0 =C2=A0128x128 high part on a target whose mode table has OImode =
but no<br>
&gt;=C2=A0 =C2=A0scalar OImode support is now built from (N/2)-wide partial=
 products<br>
&gt;=C2=A0 =C2=A0instead of a 2N multiply the target cannot expand.<br>
&gt; - Refuse the HIGH_PART emit and the chain lowering for BITINT_TYPE,<br=
>
&gt;=C2=A0 =C2=A0keeping the recognizer and the lowering gate symmetric.<br=
>
&gt; - Add per-variant tree-ssa tests, 128-bit torture and runtime tests,<b=
r>
&gt;=C2=A0 =C2=A0arm thumb1 / umull inline tests, and a check_effective_tar=
get<br>
&gt;=C2=A0 =C2=A0_oi_mode helper.<br>
&gt;<br>
&gt; Changes in v6:<br>
&gt; - Reorder so the long-multiply fold (was 2/2) is now 1/2 and a new<br>
&gt;=C2=A0 =C2=A0PHI-form recognition pass is 2/2.=C2=A0 Reverting 2/2 leav=
es a working<br>
&gt;=C2=A0 =C2=A0long-multiply fold for the flat-shifted-compare carry form=
.<br>
&gt; - Drop v5&#39;s standalone flatten_cond_carry_add driver.=C2=A0 The sa=
me<br>
&gt;=C2=A0 =C2=A0cond_carry_add / cond_carry_add_neg match.pd recognizers n=
ow feed<br>
&gt;=C2=A0 =C2=A0a match_long_mul_phi entry inside the long-multiply fold, =
so a<br>
&gt;=C2=A0 =C2=A0PHI-shaped carry folds straight to the wide-multiply outpu=
t.<br>
&gt; - Factor long_mul_classify_chain, long_mul_classify_match and<br>
&gt;=C2=A0 =C2=A0build_mul_high_seq for sharing between match_long_mul and =
the new<br>
&gt;=C2=A0 =C2=A0match_long_mul_phi.<br>
&gt; - cond_carry_add_neg uses le / ge instead of gt / lt to encode the<br>
&gt;=C2=A0 =C2=A0carry condition strictly.=C2=A0 v5 inverted the compare vi=
a<br>
&gt;=C2=A0 =C2=A0invert_tree_comparison in the flatten driver; v6 synthesis=
es the<br>
&gt;=C2=A0 =C2=A0carry summand directly inside match_long_mul_phi and so re=
quires<br>
&gt;=C2=A0 =C2=A0the recogniser to encode the strict form.<br>
&gt; - Delete forwprop-44/45/46.c; add PHI-form coverage in<br>
&gt;=C2=A0 =C2=A0long-mul-carry.c, long-mul-two-carry.c, long-mul-boundary.=
c<br>
&gt;=C2=A0 =C2=A0and long-mul-boundary-64.c.<br>
&gt; - Add PHI-form near-miss tests in long-mul-partial.c and<br>
&gt;=C2=A0 =C2=A0operand-swap polarity coverage in long-mul-boundary{,-64}.=
c.<br>
&gt; - Refresh stale long-mul comment references (check_hilo_and_ops,<br>
&gt;=C2=A0 =C2=A0fold_mul_low_plus) and reword mul_carry_low&#39;s :c-on-gt=
 note to<br>
&gt;=C2=A0 =C2=A0the correct LT form (a + b &lt; a).<br>
&gt;<br>
&gt; Changes in v5:<br>
&gt; - 1/2:<br>
&gt;=C2=A0 =C2=A0- Replace the match.pd simplify on COND_EXPR with cond_car=
ry_add<br>
&gt;=C2=A0 =C2=A0 =C2=A0/ cond_carry_add_neg match recognizers (cond^), spl=
it by gcond<br>
&gt;=C2=A0 =C2=A0 =C2=A0polarity, plus a flatten_cond_carry_add driver in<b=
r>
&gt;=C2=A0 =C2=A0 =C2=A0tree-ssa-forwprop.cc.=C2=A0 The driver inverts the =
gcond&#39;s<br>
&gt;=C2=A0 =C2=A0 =C2=A0comparison for the _neg form.=C2=A0 Modelled on mat=
ch_saturation_add.<br>
&gt;=C2=A0 =C2=A0- Remove fold_cond_carry_add_profitable_p and the tm_p.h /=
<br>
&gt;=C2=A0 =C2=A0 =C2=A0predict.h includes from gimple-match-head.cc.=C2=A0=
 The width &gt;<br>
&gt;=C2=A0 =C2=A0 =C2=A0MAX_FIXED_MODE_SIZE and width % 2 !=3D 0 guards wer=
e<br>
&gt;=C2=A0 =C2=A0 =C2=A0prerequisites for the can_mult_highpart_p fallback =
path, not<br>
&gt;=C2=A0 =C2=A0 =C2=A0soundness checks.=C2=A0 type_has_mode_precision_p s=
ubsumes them.<br>
&gt;=C2=A0 =C2=A0- Retarget the test scans from phiopt2 to forwprop1.=C2=A0=
 Add<br>
&gt;=C2=A0 =C2=A0 =C2=A0forwprop-46.c covering all four arm/comparison pola=
rities.<br>
&gt;=C2=A0 =C2=A0- forwprop-45.c uses __UINT64_TYPE__ instead of unsigned l=
ong<br>
&gt;=C2=A0 =C2=A0 =C2=A0and drops the lp64 restriction, covering the type &=
gt; word_mode<br>
&gt;=C2=A0 =C2=A0 =C2=A0regime on 32-bit targets.<br>
&gt; - 2/2:<br>
&gt;=C2=A0 =C2=A0- Lower the high-part as (N)(((2N) op1 * (2N) op2) &gt;&gt=
; N).<br>
&gt;=C2=A0 =C2=A0 =C2=A0pass_optimize_widening_mul rewrites this to WIDEN_M=
ULT_EXPR /<br>
&gt;=C2=A0 =C2=A0 =C2=A0MULT_HIGHPART_EXPR on supporting targets.=C2=A0 Rem=
oves<br>
&gt;=C2=A0 =C2=A0 =C2=A0can_mult_highpart_p queries from forwprop.<br>
&gt;=C2=A0 =C2=A0- Replace the can_mult_highpart_p prefilter in match_long_=
mul<br>
&gt;=C2=A0 =C2=A0 =C2=A0with a targetm.scalar_mode_supported_p check on the=
 2N mode.<br>
&gt;=C2=A0 =C2=A0 =C2=A0Test scans select on int128, mirroring the gate, in=
stead of<br>
&gt;=C2=A0 =C2=A0 =C2=A0lp64.<br>
&gt;=C2=A0 =C2=A0- Drop the m_long_mul_fold_p pass parameter and its passes=
.def<br>
&gt;=C2=A0 =C2=A0 =C2=A0arguments.=C2=A0 The long-mul fold runs in every fo=
rwprop instance.<br>
&gt;=C2=A0 =C2=A0 =C2=A0Test scans retargeted from forwprop2 to forwprop1.<=
br>
&gt;=C2=A0 =C2=A0- Stop restricting forwprop-44.c to lp64.=C2=A0 With the<b=
r>
&gt;=C2=A0 =C2=A0 =C2=A0can_mult_highpart_p gating gone, the fold is target=
-independent<br>
&gt;=C2=A0 =C2=A0 =C2=A0and the test passes on ilp32 targets too.<br>
&gt;<br>
&gt; Changes in v4:<br>
&gt; - 1/2:<br>
&gt;=C2=A0 =C2=A0- Rebuild the guard with per-conjunct reasoning: require b=
oth<br>
&gt;=C2=A0 =C2=A0 =C2=A0operands to be SSA names (drops degenerate one-side=
-constant<br>
&gt;=C2=A0 =C2=A0 =C2=A0cases that fold trivially elsewhere), require the t=
ype to<br>
&gt;=C2=A0 =C2=A0 =C2=A0have_mode_precision_p (excludes BITINT_TYPE precisi=
on !=3D mode<br>
&gt;=C2=A0 =C2=A0 =C2=A0and similar oddities), drop the explicit MAX_FIXED_=
MODE_SIZE<br>
&gt;=C2=A0 =C2=A0 =C2=A0width cap (subsumed by have_mode_precision_p), and =
gate on the<br>
&gt;=C2=A0 =C2=A0 =C2=A0flat optab via can_mult_highpart_p of the 2N mode.<=
br>
&gt;=C2=A0 =C2=A0- Retain BRANCH_COST &gt;=3D 2: keep the flatten condition=
al on a<br>
&gt;=C2=A0 =C2=A0 =C2=A0target where the branchless form is generally cheap=
er.<br>
&gt;=C2=A0 =C2=A0- Rewrite the cover letter to describe the gate as the<br>
&gt;=C2=A0 =C2=A0 =C2=A0composition of these conjuncts and to clarify that =
the<br>
&gt;=C2=A0 =C2=A0 =C2=A0transformation now only ever introduces a (mul_hi-l=
ike)<br>
&gt;=C2=A0 =C2=A0 =C2=A0can_mult_highpart_p shape, not a libgcc multi-preci=
sion call.<br>
&gt; - 2/2:<br>
&gt;=C2=A0 =C2=A0- Convert per-variant fold_mul_* functions into a<br>
&gt;=C2=A0 =C2=A0 =C2=A0table-driven long_mul fold framework.<br>
&gt;=C2=A0 =C2=A0- Migrate each variant into a row in long_mul_table (six<b=
r>
&gt;=C2=A0 =C2=A0 =C2=A0HIGH_PART, six LOW_PART rows) keyed by (kind, extra=
ct).<br>
&gt;=C2=A0 =C2=A0- Add cross-summand consistency checks<br>
&gt;=C2=A0 =C2=A0 =C2=A0(long_mul_check_consistency, long_mul_check_two_car=
ries,<br>
&gt;=C2=A0 =C2=A0 =C2=A0long_mul_check_low_plus_defer) shared across rows.<=
br>
&gt;=C2=A0 =C2=A0- Drop emission to a libgcc multi-precision call from RTL<=
br>
&gt;=C2=A0 =C2=A0 =C2=A0expansion; defer to pass_optimize_widening_mul / RT=
L<br>
&gt;=C2=A0 =C2=A0 =C2=A0expansion to pick native umul_highpart, a widening =
multiply, or<br>
&gt;=C2=A0 =C2=A0 =C2=A0a synthesised sequence.=C2=A0 Emission is gated on<=
br>
&gt;=C2=A0 =C2=A0 =C2=A0can_mult_highpart_p.<br>
&gt;=C2=A0 =C2=A0- Structural redesign: per-variant fold_mul_* functions<br=
>
&gt;=C2=A0 =C2=A0 =C2=A0consolidated into a single linearise + classify + t=
able-lookup<br>
&gt;=C2=A0 =C2=A0 =C2=A0framework (long_mul_table, match_long_mul,<br>
&gt;=C2=A0 =C2=A0 =C2=A0long_mul_classify_summand, long_mul_check_consisten=
cy).=C2=A0 Each<br>
&gt;=C2=A0 =C2=A0 =C2=A0variant is now a row in long_mul_table; consistency=
 checks are<br>
&gt;=C2=A0 =C2=A0 =C2=A0shared across rows.<br>
&gt;=C2=A0 =C2=A0- Fast-fail prefilters in match_long_mul: LHS-type prefilt=
er at<br>
&gt;=C2=A0 =C2=A0 =C2=A0entry (no legitimate long-mul leaf has a signed / p=
ointer /<br>
&gt;=C2=A0 =C2=A0 =C2=A0float / odd-width type) and a can_mult_highpart_p p=
robe before<br>
&gt;=C2=A0 =C2=A0 =C2=A0the row loop to skip HIGH_PART rows on unsupported =
targets.<br>
&gt;=C2=A0 =C2=A0- Bound long_mul_linearize_chain mid-walk by LONG_MUL_MAX_=
SUMMANDS<br>
&gt;=C2=A0 =C2=A0 =C2=A0so an overlong addition / BIT_IOR chain bails immed=
iately rather<br>
&gt;=C2=A0 =C2=A0 =C2=A0than after a full traversal.<br>
&gt;=C2=A0 =C2=A0- Emit a dump-file hint pointing at the shared inner addit=
ion when<br>
&gt;=C2=A0 =C2=A0 =C2=A0long-mul folding rejects a chain because of a multi=
-used<br>
&gt;=C2=A0 =C2=A0 =C2=A0intermediate (caching the partial sum into a single=
-use SSA<br>
&gt;=C2=A0 =C2=A0 =C2=A0name normally enables the fold).<br>
&gt;<br>
&gt; Changes in v3:<br>
&gt; - Moved carry-diamond flattening from forwprop to match.pd,<br>
&gt; replacing ~460 lines of C++ with a 17-line match.pd pattern.<br>
&gt; - Two-carry test scans forwprop3 (the first forwprop after phiopt2,<br=
>
&gt; since early phiopt restricts which tree codes are allowed).<br>
&gt; - Set location for new sequences.<br>
&gt; - Updated mul_carry_low pattern.<br>
&gt; - Added the `mul_low_plus` pattern.<br>
&gt; - Fixed formatting issues.<br>
&gt;<br>
&gt; Changes in v2:<br>
&gt; - Fixed the testcases by separating the high part&#39;s fold count for=
<br>
&gt; 32-bit and 64-bit targets.<br>
&gt;<br>
&gt; Konstantinos Eleftheriou (7):<br>
&gt;=C2=A0 =C2=A0forwprop: Match and fold the long-multiply carry form [PR1=
07090]<br>
&gt;=C2=A0 =C2=A0forwprop: Add long-multiply carry-low-sum variant<br>
&gt;=C2=A0 =C2=A0forwprop: Add long-multiply two-carry variant<br>
&gt;=C2=A0 =C2=A0forwprop: Add long-multiply ladder variants<br>
&gt;=C2=A0 =C2=A0forwprop: Add long-multiply low-plus variant<br>
&gt;=C2=A0 =C2=A0match.pd, forwprop: Recognize long-multiply carries writte=
n as 2-arg<br>
&gt;=C2=A0 =C2=A0 =C2=A0PHI<br>
&gt;=C2=A0 =C2=A0widening_mul: Lower long-multiply chains to inline longhan=
d<br>
&gt;<br>
&gt;=C2=A0 gcc/match.pd=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=
=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 |=C2=A0 =
198 +++<br>
&gt;=C2=A0 gcc/testsuite/gcc.dg/long-mul-128-Og.c=C2=A0 =C2=A0 =C2=A0 =C2=
=A0 |=C2=A0 =C2=A026 +<br>
&gt;=C2=A0 gcc/testsuite/gcc.dg/torture/long-mul-128.c=C2=A0 =C2=A0|=C2=A0 =
121 ++<br>
&gt;=C2=A0 .../gcc.dg/torture/long-mul-64-run.c=C2=A0 =C2=A0 =C2=A0 =C2=A0 =
=C2=A0 |=C2=A0 180 +++<br>
&gt;=C2=A0 .../gcc.dg/tree-ssa/long-mul-boundary-64.c=C2=A0 =C2=A0 |=C2=A0 =
417 ++++++<br>
&gt;=C2=A0 .../gcc.dg/tree-ssa/long-mul-boundary.c=C2=A0 =C2=A0 =C2=A0 =C2=
=A0|=C2=A0 394 ++++++<br>
&gt;=C2=A0 .../gcc.dg/tree-ssa/long-mul-carry.c=C2=A0 =C2=A0 =C2=A0 =C2=A0 =
=C2=A0 |=C2=A0 385 ++++++<br>
&gt;=C2=A0 .../gcc.dg/tree-ssa/long-mul-chain-cse-128.c=C2=A0 |=C2=A0 =C2=
=A052 +<br>
&gt;=C2=A0 .../tree-ssa/long-mul-chain-trunc-128.c=C2=A0 =C2=A0 =C2=A0 =C2=
=A0|=C2=A0 =C2=A080 ++<br>
&gt;=C2=A0 .../gcc.dg/tree-ssa/long-mul-extra-addend.c=C2=A0 =C2=A0|=C2=A0 =
=C2=A063 +<br>
&gt;=C2=A0 .../gcc.dg/tree-ssa/long-mul-ladder.c=C2=A0 =C2=A0 =C2=A0 =C2=A0=
 =C2=A0|=C2=A0 333 +++++<br>
&gt;=C2=A0 .../gcc.dg/tree-ssa/long-mul-low-plus.c=C2=A0 =C2=A0 =C2=A0 =C2=
=A0|=C2=A0 =C2=A054 +<br>
&gt;=C2=A0 .../gcc.dg/tree-ssa/long-mul-partial.c=C2=A0 =C2=A0 =C2=A0 =C2=
=A0 |=C2=A0 193 +++<br>
&gt;=C2=A0 .../gcc.dg/tree-ssa/long-mul-two-carry.c=C2=A0 =C2=A0 =C2=A0 |=
=C2=A0 140 ++<br>
&gt;=C2=A0 gcc/testsuite/gcc.target/aarch64/long_mul.c=C2=A0 =C2=A0|=C2=A0 =
100 ++<br>
&gt;=C2=A0 .../gcc.target/arm/long-mul-thumb1-inline.c=C2=A0 =C2=A0|=C2=A0 =
=C2=A047 +<br>
&gt;=C2=A0 gcc/testsuite/gcc.target/arm/long-mul-umull.c |=C2=A0 =C2=A073 +=
<br>
&gt;=C2=A0 gcc/testsuite/gcc.target/i386/long_mul.c=C2=A0 =C2=A0 =C2=A0 |=
=C2=A0 100 ++<br>
&gt;=C2=A0 .../gcc.target/i386/widen_mult_high_chain.c=C2=A0 =C2=A0|=C2=A0 =
=C2=A032 +<br>
&gt;=C2=A0 gcc/testsuite/lib/target-supports.exp=C2=A0 =C2=A0 =C2=A0 =C2=A0=
 =C2=A0|=C2=A0 =C2=A020 +<br>
&gt;=C2=A0 gcc/tree-ssa-forwprop.cc=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=
=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 | 1197 ++++++++++++++++-<br>
&gt;=C2=A0 gcc/tree-ssa-math-opts.cc=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=
=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0|=C2=A0 492 ++++++-<br>
&gt;=C2=A0 gcc/tree-ssa-math-opts.h=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=
=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 |=C2=A0 =C2=A0 2 +<br>
&gt;=C2=A0 23 files changed, 4690 insertions(+), 9 deletions(-)<br>
&gt;=C2=A0 create mode 100644 gcc/testsuite/gcc.dg/long-mul-128-Og.c<br>
&gt;=C2=A0 create mode 100644 gcc/testsuite/gcc.dg/torture/long-mul-128.c<b=
r>
&gt;=C2=A0 create mode 100644 gcc/testsuite/gcc.dg/torture/long-mul-64-run.=
c<br>
&gt;=C2=A0 create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/long-mul-bounda=
ry-64.c<br>
&gt;=C2=A0 create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/long-mul-bounda=
ry.c<br>
&gt;=C2=A0 create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/long-mul-carry.=
c<br>
&gt;=C2=A0 create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/long-mul-chain-=
cse-128.c<br>
&gt;=C2=A0 create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/long-mul-chain-=
trunc-128.c<br>
&gt;=C2=A0 create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/long-mul-extra-=
addend.c<br>
&gt;=C2=A0 create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/long-mul-ladder=
.c<br>
&gt;=C2=A0 create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/long-mul-low-pl=
us.c<br>
&gt;=C2=A0 create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/long-mul-partia=
l.c<br>
&gt;=C2=A0 create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/long-mul-two-ca=
rry.c<br>
&gt;=C2=A0 create mode 100644 gcc/testsuite/gcc.target/aarch64/long_mul.c<b=
r>
&gt;=C2=A0 create mode 100644 gcc/testsuite/gcc.target/arm/long-mul-thumb1-=
inline.c<br>
&gt;=C2=A0 create mode 100644 gcc/testsuite/gcc.target/arm/long-mul-umull.c=
<br>
&gt;=C2=A0 create mode 100644 gcc/testsuite/gcc.target/i386/long_mul.c<br>
&gt;=C2=A0 create mode 100644 gcc/testsuite/gcc.target/i386/widen_mult_high=
_chain.c<br>
&gt;<br>
&gt; --<br>
&gt; 2.55.0<br>
</blockquote></div>

--000000000000a26aed06583b9ab9--