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 } } */
