This patch series teaches forwprop to recognize longhand 64x64->128
wide-multiplication idioms and replace them with native multiply
instructions (MULT_HIGHPART_EXPR / widening multiply for the high part,
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 series is split into two patches:

  1/2  forwprop: Flatten carry-diamond patterns to straight-line code

       A carry diamond implements unsigned overflow detection with
       conditional carry propagation:

         sum = a + b;
         if (addend > sum) result = base + C;

       This patch converts such conditional branches into branchless
       straight-line code, exposing the carry as a comparison
       expression.  This is a prerequisite for the long-multiply
       pattern matching, which expects carries in the form
       (lshift (convert? (gt ...)) INTEGER_CST).

  2/2  forwprop: Match and fold long-multiply patterns [PR107090]

       Adds match.pd patterns that recognize six decomposed variants
       of the longhand multiplication:

         - carry:       single overflow comparison on the cross-sum
         - carry-long:  cross-carry with separate high/low accumulation
         - two-carry:   both cross-carry and low-carry as separate
                        comparisons
         - ladder:      sequential accumulation without explicit carry
                        comparison
         - ladder-long: ladder with separate high/low accumulation
         - low-plus:    low part as a direct sum of partial products

       The actual folding is performed in forwprop after verifying
       target support for umul_highpart or widening multiply.

On SPEC2026's 750.sealcrypto_r:

  - AArch64 Neoverse-N1: 25% improvement
  - x86-64 Zen4:         59% improvement


Konstantinos Eleftheriou (2):
  forwprop: Flatten carry-diamond patterns to straight-line code
  forwprop: Match and fold long-multiply patterns [PR107090]

 gcc/match.pd                                  |  221 +++
 gcc/testsuite/gcc.dg/tree-ssa/forwprop-44.c   |   21 +
 gcc/testsuite/gcc.dg/tree-ssa/forwprop-45.c   |   44 +
 .../gcc.dg/tree-ssa/long-mul-boundary-64.c    |  274 ++++
 .../gcc.dg/tree-ssa/long-mul-boundary.c       |  270 ++++
 .../gcc.dg/tree-ssa/long-mul-carry.c          |  310 ++++
 .../gcc.dg/tree-ssa/long-mul-ladder.c         |  328 ++++
 .../gcc.dg/tree-ssa/long-mul-low-plus.c       |   54 +
 .../gcc.dg/tree-ssa/long-mul-partial.c        |  119 ++
 .../gcc.dg/tree-ssa/long-mul-two-carry.c      |  109 ++
 gcc/testsuite/gcc.target/aarch64/long_mul.c   |  100 ++
 gcc/testsuite/gcc.target/i386/long_mul.c      |  100 ++
 gcc/tree-ssa-forwprop.cc                      | 1367 ++++++++++++++++-
 13 files changed, 3312 insertions(+), 5 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/forwprop-44.c
 create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/forwprop-45.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-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/i386/long_mul.c

Reply via email to