From: Philipp Tomsich <[email protected]>

lower_long_mul_high_chain lowered every recognized high-part chain the
target cannot form a narrow high part for, including chains whose wide
multiply expands just fine. On AVR without hardware multiply this turned
a single __mulsi3 call into four __mulhi3 calls plus carry propagation
at -Os.

Lower only where the inline longhand is the better code. Optimizing for
size a single wide multiply is smaller either way, so never lower. With
a multiply insn for the wide mode the target has asked for the wide form
even when optimizing for speed: targets without a hardware multiply
expose call-bundle patterns (AVR's mulsi3) precisely to route such
multiplies to their hand-written helpers. What is left is a libcall at
speed, where inlining saves only the call, since the callee performs the
same longhand.

A wide mode with no expansion path at all is unaffected: such a chain
has to be lowered at every optimization level, or it reaches expand as
a multiply the target cannot expand.

Bootstrapped and regtested on AArch64, x86-64 and ARM.
Regtested on AVR.

        PR tree-optimization/127028

gcc/ChangeLog:

        * tree-ssa-math-opts.cc (long_mul_lowering_profitable_p): New.
        (lower_long_mul_high_chain): Call it when the wide mode can
        expand.

gcc/testsuite/ChangeLog:

        * gcc.target/avr/pr127028.c: New test.

Co-authored-by: Konstantinos Eleftheriou <[email protected]>
---
 gcc/testsuite/gcc.target/avr/pr127028.c | 12 ++++++++++
 gcc/tree-ssa-math-opts.cc               | 29 +++++++++++++++++++++++++
 2 files changed, 41 insertions(+)
 create mode 100644 gcc/testsuite/gcc.target/avr/pr127028.c

diff --git a/gcc/testsuite/gcc.target/avr/pr127028.c 
b/gcc/testsuite/gcc.target/avr/pr127028.c
new file mode 100644
index 000000000000..e183d02f052d
--- /dev/null
+++ b/gcc/testsuite/gcc.target/avr/pr127028.c
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* { dg-options "-Os" } */
+
+typedef __UINT16_TYPE__ uint16_t;
+typedef __UINT32_TYPE__ uint32_t;
+
+uint16_t wmul16 (uint16_t x)
+{
+  return ((uint32_t) x * 0xaaab) >> 16;
+}
+
+/* { dg-final { scan-assembler-not "__mulhi3" } } */
diff --git a/gcc/tree-ssa-math-opts.cc b/gcc/tree-ssa-math-opts.cc
index ebc3300ae332..8288fbead751 100644
--- a/gcc/tree-ssa-math-opts.cc
+++ b/gcc/tree-ssa-math-opts.cc
@@ -7101,6 +7101,18 @@ narrow_long_mul_halves (gimple *stmt)
   return true;
 }
 
+/* True when the inline longhand beats expanding the WIDE_MODE multiply.
+   At size the wide multiply is smaller either way.  At speed, a multiply
+   pattern is the target's own expansion -- AVR defines mulsi3 even on
+   cores with no multiply at all -- while a libcall is the generic fallback
+   whose body is that same longhand, so inlining saves only the call.  */
+
+static bool
+long_mul_lowering_profitable_p (scalar_int_mode wide_mode, bool speed)
+{
+  return speed && optab_handler (smul_optab, wide_mode) == CODE_FOR_nothing;
+}
+
 /* Match.pd recognizer for the long-multiply recognizer's high-part
    emit chain.  */
 
@@ -7148,6 +7160,23 @@ lower_long_mul_high_chain (gimple_stmt_iterator *gsi)
   if (can_mult_highpart_p (narrow_mode, true))
     return false;
 
+  /* Where the 2N multiply expands, lowering is a trade, not a rescue, so
+     leave the chain alone unless the longhand is the better code.  A 2N
+     mode with no expansion path must be lowered regardless.  */
+  tree wide_type = TREE_TYPE (gimple_assign_lhs (mult_stmt));
+  scalar_int_mode wide_mode;
+  bool speed = optimize_bb_for_speed_p (gimple_bb (trunc_stmt));
+  if (is_a <scalar_int_mode> (TYPE_MODE (wide_type), &wide_mode)
+      && targetm.scalar_mode_supported_p (wide_mode)
+      && !long_mul_lowering_profitable_p (wide_mode, speed))
+    {
+      if (dump_file && (dump_flags & TDF_DETAILS))
+       fprintf (dump_file, "Not lowering long-mul chain: %s.\n",
+                speed ? "the target expands the wide multiply"
+                      : "the wide multiply is smaller");
+      return false;
+    }
+
   location_t loc = gimple_location (trunc_stmt);
   gimple_seq seq = NULL;
 
-- 
2.43.0

Reply via email to