https://gcc.gnu.org/g:d382f953805cb06ae0fa396d451d3888322b23ae

commit r17-4656-gd382f953805cb06ae0fa396d451d3888322b23ae
Author: Roger Sayle <[email protected]>
Date:   Fri Sep 25 15:34:48 2026 +0100

    middle-end: [SU]MUL_HIGHPART RTL simplifications
    
    This patch adds some RTL simplifications for SMUL_HIGHPART and
    UMUL_HIGHPART.  Currently, simplify_binary_operation_1 knows
    that highpart multiplication by zero is zero.  This patch
    optimizes unsigned highpart multiplication (UMUL_HIGHPART) by
    1 to zero, and signed highpart multiplication (SMUL_HIGHPART)
    by one to be the repeated signbit, x < 0 ? -1 : 0, i.e.
    x >> PRECISION-1.  Additionally, UMUL_HIGHPART by a power
    of two is transformed into a logical right shift, and
    SMUL_HIGHPART by a positive power of two is transformed into
    an arithmetic right shift.
    
    2026-09-25  Roger Sayle  <[email protected]>
    
    gcc/ChangeLog
            * simplify-rtx.cc (simplify_binary_operation_1) <SMUL_HIGHPART>:
            Add transformations for multiplications by one and powers to two.
            <UMUL_HIGHPART>: Likewise.
    
    gcc/testsuite/ChangeLog
            * gcc.target/nvptx/mul-hi-2.c: New test case.

Diff:
---
 gcc/simplify-rtx.cc                       | 44 ++++++++++++++++++++++++++++++-
 gcc/testsuite/gcc.target/nvptx/mul-hi-2.c | 37 ++++++++++++++++++++++++++
 2 files changed, 80 insertions(+), 1 deletion(-)

diff --git a/gcc/simplify-rtx.cc b/gcc/simplify-rtx.cc
index 38c8abfe3e78..285826a3feda 100644
--- a/gcc/simplify-rtx.cc
+++ b/gcc/simplify-rtx.cc
@@ -5082,11 +5082,53 @@ simplify_ashift:
       return 0;
 
     case SMUL_HIGHPART:
+      /* Simplify x h* 0 to 0, if possible.  */
+      if (trueop1 == CONST0_RTX (mode)
+         && !side_effects_p (op0))
+       return op1;
+      /* Simplify x h* 1 to sign(x).  */
+      if (trueop1 == const1_rtx
+         && is_a <scalar_int_mode> (mode, &int_mode))
+       {
+         HOST_WIDE_INT bits = GET_MODE_PRECISION (int_mode) - 1;
+         return simplify_gen_binary (ASHIFTRT, mode, op0,
+                                     gen_int_shift_amount (mode, bits));
+       }
+      /* Simplify SMUL_HIGHPART by power of two as ASHIFRT.  */
+      if (CONST_INT_P (trueop1)
+         && INTVAL (trueop1) > 1
+         && is_a <scalar_int_mode> (mode, &int_mode))
+       {
+         HOST_WIDE_INT prec = GET_MODE_PRECISION (int_mode);
+         val = wi::exact_log2 (INTVAL (trueop1));
+         if (val > 0 && val < prec)
+           return simplify_gen_binary (ASHIFTRT, mode, op0,
+                                       gen_int_shift_amount (mode,
+                                                             prec - val));
+       }
+      return 0;
+
     case UMUL_HIGHPART:
-      /* Simplify x * 0 to 0, if possible.  */
+      /* Simplify x h* 0 to 0, if possible.  */
       if (trueop1 == CONST0_RTX (mode)
          && !side_effects_p (op0))
        return op1;
+      /* Simplify x h* 1 to 0.  */
+      if (trueop1 == CONST1_RTX (mode)
+         && !side_effects_p (op1))
+       return CONST0_RTX (mode);
+      /* Simplify UMUL_HIGHPART by power of two as LSHIFRT.  */
+      if (CONST_INT_P (trueop1)
+         && UINTVAL (trueop1) > 1
+         && is_a <scalar_int_mode> (mode, &int_mode))
+       {
+         HOST_WIDE_INT prec = GET_MODE_PRECISION (int_mode);
+         val = wi::exact_log2 (UINTVAL (trueop1));
+         if (val > 0 && val < prec)
+           return simplify_gen_binary (LSHIFTRT, mode, op0,
+                                       gen_int_shift_amount (mode,
+                                                             prec - val));
+       }
       return 0;
 
     case SS_DIV:
diff --git a/gcc/testsuite/gcc.target/nvptx/mul-hi-2.c 
b/gcc/testsuite/gcc.target/nvptx/mul-hi-2.c
new file mode 100644
index 000000000000..2f7b578ef221
--- /dev/null
+++ b/gcc/testsuite/gcc.target/nvptx/mul-hi-2.c
@@ -0,0 +1,37 @@
+/* { dg-do assemble } */
+/* { dg-options "-O2 -save-temps" } */
+
+int smul_hi(int x, int y)
+{
+    return ((long)x*(long)y)>>32;
+}
+
+int s2(int x)
+{
+    return smul_hi(x,2);
+}
+
+int s4(int x)
+{
+    return smul_hi(x,4);
+}
+
+unsigned int umul_hi(unsigned int x, unsigned int y)
+{
+    return ((unsigned long)x * (unsigned long)y) >> 32;
+}
+
+unsigned int u2(unsigned int x)
+{
+    return umul_hi(x,2);
+}
+
+unsigned int u4(unsigned int x)
+{
+    return umul_hi(x,4);
+}
+
+/* { dg-final { scan-assembler-times "mul.hi.s32" 1 } } */
+/* { dg-final { scan-assembler-times "shr.s32" 2 } } */
+/* { dg-final { scan-assembler-times "mul.hi.u32" 1 } } */
+/* { dg-final { scan-assembler-times "shr.u32" 2 } } */

Reply via email to