[llvm] [TargetLowering] Add target-independent mul-by-constant expansion algorithm (PR #196728)

Iris Shi via llvm-commits llvm-commits at lists.llvm.org
Sat May 9 07:22:47 PDT 2026


https://github.com/el-ev created https://github.com/llvm/llvm-project/pull/196728

Add a common helper for expanding constant multiplication into sequences of `shl`, `add` and `sub` instructions, which is useful for architectures without hardware multiplication support.

Teach 5 targets to use the new helper:                                                                                              
- RISC-V (!hasStdExtZmmul): replaces the existing NAF expansion
- Lanai: replaces the existing NAF expansion
- MSP430
- Sparc V7                                
- AVR (!supportsMultiplication)

The algorithm used is adopted from Bernstein's algorithm, generating ~45% fewer instructions than the naive shift-and-add algorithm and ~22% fewer instructions than the NAF algorithm used by RISC-V and Lanai, on 1M randomly selected constants.
 
Reference: R. Bernstein, "Multiplication by integer constants", Software: Practice and Experience, 1986.                              
  https://doi.org/10.1002/spe.4380160704

>From f1051b2f456a41a58d781aca8d0dac175da8eaa8 Mon Sep 17 00:00:00 2001
From: Iris Shi <0.0 at owo.li>
Date: Sat, 9 May 2026 21:19:11 +0800
Subject: [PATCH 1/2] pre-commit tests

---
 llvm/test/CodeGen/AVR/constant_multiply.ll    |  99 ++++++
 llvm/test/CodeGen/Lanai/constant_multiply.ll  | 334 ++++++++++++++++++
 llvm/test/CodeGen/MSP430/constant_multiply.ll | 166 +++++++++
 llvm/test/CodeGen/SPARC/constant_multiply.ll  | 148 ++++++++
 4 files changed, 747 insertions(+)
 create mode 100644 llvm/test/CodeGen/AVR/constant_multiply.ll
 create mode 100644 llvm/test/CodeGen/MSP430/constant_multiply.ll
 create mode 100644 llvm/test/CodeGen/SPARC/constant_multiply.ll

diff --git a/llvm/test/CodeGen/AVR/constant_multiply.ll b/llvm/test/CodeGen/AVR/constant_multiply.ll
new file mode 100644
index 0000000000000..c0cf630ac7a88
--- /dev/null
+++ b/llvm/test/CodeGen/AVR/constant_multiply.ll
@@ -0,0 +1,99 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc -mtriple=avr -mcpu=attiny85 < %s | FileCheck %s
+
+; Test mul-by-constant expansion for AVR without hardware multiply.
+; attiny85 has no MUL instruction.
+
+define i8 @mul_i8_by_3(i8 %a) nounwind {
+; CHECK-LABEL: mul_i8_by_3:
+; CHECK:       ; %bb.0:
+; CHECK-NEXT:    ldi r22, 3
+; CHECK-NEXT:    rcall __mulqi3
+; CHECK-NEXT:    ret
+  %1 = mul i8 %a, 3
+  ret i8 %1
+}
+
+define i8 @mul_i8_by_5(i8 %a) nounwind {
+; CHECK-LABEL: mul_i8_by_5:
+; CHECK:       ; %bb.0:
+; CHECK-NEXT:    ldi r22, 5
+; CHECK-NEXT:    rcall __mulqi3
+; CHECK-NEXT:    ret
+  %1 = mul i8 %a, 5
+  ret i8 %1
+}
+
+define i8 @mul_i8_by_7(i8 %a) nounwind {
+; CHECK-LABEL: mul_i8_by_7:
+; CHECK:       ; %bb.0:
+; CHECK-NEXT:    ldi r22, 7
+; CHECK-NEXT:    rcall __mulqi3
+; CHECK-NEXT:    ret
+  %1 = mul i8 %a, 7
+  ret i8 %1
+}
+
+define i8 @mul_i8_by_neg3(i8 %a) nounwind {
+; CHECK-LABEL: mul_i8_by_neg3:
+; CHECK:       ; %bb.0:
+; CHECK-NEXT:    ldi r22, -3
+; CHECK-NEXT:    rcall __mulqi3
+; CHECK-NEXT:    ret
+  %1 = mul i8 %a, -3
+  ret i8 %1
+}
+
+define i16 @mul_i16_by_3(i16 %a) nounwind {
+; CHECK-LABEL: mul_i16_by_3:
+; CHECK:       ; %bb.0:
+; CHECK-NEXT:    ldi r22, 3
+; CHECK-NEXT:    ldi r23, 0
+; CHECK-NEXT:    rcall __mulhi3
+; CHECK-NEXT:    ret
+  %1 = mul i16 %a, 3
+  ret i16 %1
+}
+
+define i16 @mul_i16_by_7(i16 %a) nounwind {
+; CHECK-LABEL: mul_i16_by_7:
+; CHECK:       ; %bb.0:
+; CHECK-NEXT:    ldi r22, 7
+; CHECK-NEXT:    ldi r23, 0
+; CHECK-NEXT:    rcall __mulhi3
+; CHECK-NEXT:    ret
+  %1 = mul i16 %a, 7
+  ret i16 %1
+}
+
+define i16 @mul_i16_by_10(i16 %a) nounwind {
+; CHECK-LABEL: mul_i16_by_10:
+; CHECK:       ; %bb.0:
+; CHECK-NEXT:    ldi r22, 10
+; CHECK-NEXT:    ldi r23, 0
+; CHECK-NEXT:    rcall __mulhi3
+; CHECK-NEXT:    ret
+  %1 = mul i16 %a, 10
+  ret i16 %1
+}
+
+define i16 @mul_i16_by_neg7(i16 %a) nounwind {
+; CHECK-LABEL: mul_i16_by_neg7:
+; CHECK:       ; %bb.0:
+; CHECK-NEXT:    ldi r22, 249
+; CHECK-NEXT:    ldi r23, 255
+; CHECK-NEXT:    rcall __mulhi3
+; CHECK-NEXT:    ret
+  %1 = mul i16 %a, -7
+  ret i16 %1
+}
+
+; Non-constant multiply should still use the libcall.
+define i16 @mul_variable(i16 %a, i16 %b) nounwind {
+; CHECK-LABEL: mul_variable:
+; CHECK:       ; %bb.0:
+; CHECK-NEXT:    rcall __mulhi3
+; CHECK-NEXT:    ret
+  %1 = mul i16 %a, %b
+  ret i16 %1
+}
diff --git a/llvm/test/CodeGen/Lanai/constant_multiply.ll b/llvm/test/CodeGen/Lanai/constant_multiply.ll
index f7ad041b77e97..165ef9d016dbf 100644
--- a/llvm/test/CodeGen/Lanai/constant_multiply.ll
+++ b/llvm/test/CodeGen/Lanai/constant_multiply.ll
@@ -194,3 +194,337 @@ define i32 @h1(i32 inreg %a) #0 {
   %1 = mul i32 %a, -1431655765
   ret i32 %1
 }
+
+define i32 @muli32_p10(i32 inreg %a) #0 {
+; CHECK-LABEL: muli32_p10:
+; CHECK:       ! %bb.0:
+; CHECK-NEXT:    st %fp, [--%sp]
+; CHECK-NEXT:    add %sp, 0x8, %fp
+; CHECK-NEXT:    sub %sp, 0x8, %sp
+; CHECK-NEXT:    sh %r6, 0x1, %r3
+; CHECK-NEXT:    sh %r6, 0x3, %r9
+; CHECK-NEXT:    add %r9, %r3, %rv
+; CHECK-NEXT:    ld -4[%fp], %pc ! return
+; CHECK-NEXT:    add %fp, 0x0, %sp
+; CHECK-NEXT:    ld -8[%fp], %fp
+  %1 = mul i32 %a, 10
+  ret i32 %1
+}
+
+define i32 @muli32_p14(i32 inreg %a) #0 {
+; CHECK-LABEL: muli32_p14:
+; CHECK:       ! %bb.0:
+; CHECK-NEXT:    st %fp, [--%sp]
+; CHECK-NEXT:    add %sp, 0x8, %fp
+; CHECK-NEXT:    sub %sp, 0x8, %sp
+; CHECK-NEXT:    sh %r6, 0x1, %r3
+; CHECK-NEXT:    sh %r6, 0x4, %r9
+; CHECK-NEXT:    sub %r9, %r3, %rv
+; CHECK-NEXT:    ld -4[%fp], %pc ! return
+; CHECK-NEXT:    add %fp, 0x0, %sp
+; CHECK-NEXT:    ld -8[%fp], %fp
+  %1 = mul i32 %a, 14
+  ret i32 %1
+}
+
+define i32 @muli32_p18(i32 inreg %a) #0 {
+; CHECK-LABEL: muli32_p18:
+; CHECK:       ! %bb.0:
+; CHECK-NEXT:    st %fp, [--%sp]
+; CHECK-NEXT:    add %sp, 0x8, %fp
+; CHECK-NEXT:    sub %sp, 0x8, %sp
+; CHECK-NEXT:    sh %r6, 0x1, %r3
+; CHECK-NEXT:    sh %r6, 0x4, %r9
+; CHECK-NEXT:    add %r9, %r3, %rv
+; CHECK-NEXT:    ld -4[%fp], %pc ! return
+; CHECK-NEXT:    add %fp, 0x0, %sp
+; CHECK-NEXT:    ld -8[%fp], %fp
+  %1 = mul i32 %a, 18
+  ret i32 %1
+}
+
+define i32 @muli32_p28(i32 inreg %a) #0 {
+; CHECK-LABEL: muli32_p28:
+; CHECK:       ! %bb.0:
+; CHECK-NEXT:    st %fp, [--%sp]
+; CHECK-NEXT:    add %sp, 0x8, %fp
+; CHECK-NEXT:    sub %sp, 0x8, %sp
+; CHECK-NEXT:    sh %r6, 0x2, %r3
+; CHECK-NEXT:    sh %r6, 0x5, %r9
+; CHECK-NEXT:    sub %r9, %r3, %rv
+; CHECK-NEXT:    ld -4[%fp], %pc ! return
+; CHECK-NEXT:    add %fp, 0x0, %sp
+; CHECK-NEXT:    ld -8[%fp], %fp
+  %1 = mul i32 %a, 28
+  ret i32 %1
+}
+
+define i32 @muli32_p30(i32 inreg %a) #0 {
+; CHECK-LABEL: muli32_p30:
+; CHECK:       ! %bb.0:
+; CHECK-NEXT:    st %fp, [--%sp]
+; CHECK-NEXT:    add %sp, 0x8, %fp
+; CHECK-NEXT:    sub %sp, 0x8, %sp
+; CHECK-NEXT:    sh %r6, 0x1, %r3
+; CHECK-NEXT:    sh %r6, 0x5, %r9
+; CHECK-NEXT:    sub %r9, %r3, %rv
+; CHECK-NEXT:    ld -4[%fp], %pc ! return
+; CHECK-NEXT:    add %fp, 0x0, %sp
+; CHECK-NEXT:    ld -8[%fp], %fp
+  %1 = mul i32 %a, 30
+  ret i32 %1
+}
+
+define i32 @muli32_p34(i32 inreg %a) #0 {
+; CHECK-LABEL: muli32_p34:
+; CHECK:       ! %bb.0:
+; CHECK-NEXT:    st %fp, [--%sp]
+; CHECK-NEXT:    add %sp, 0x8, %fp
+; CHECK-NEXT:    sub %sp, 0x8, %sp
+; CHECK-NEXT:    sh %r6, 0x1, %r3
+; CHECK-NEXT:    sh %r6, 0x5, %r9
+; CHECK-NEXT:    add %r9, %r3, %rv
+; CHECK-NEXT:    ld -4[%fp], %pc ! return
+; CHECK-NEXT:    add %fp, 0x0, %sp
+; CHECK-NEXT:    ld -8[%fp], %fp
+  %1 = mul i32 %a, 34
+  ret i32 %1
+}
+
+define i32 @muli32_p36(i32 inreg %a) #0 {
+; CHECK-LABEL: muli32_p36:
+; CHECK:       ! %bb.0:
+; CHECK-NEXT:    st %fp, [--%sp]
+; CHECK-NEXT:    add %sp, 0x8, %fp
+; CHECK-NEXT:    sub %sp, 0x8, %sp
+; CHECK-NEXT:    sh %r6, 0x2, %r3
+; CHECK-NEXT:    sh %r6, 0x5, %r9
+; CHECK-NEXT:    add %r9, %r3, %rv
+; CHECK-NEXT:    ld -4[%fp], %pc ! return
+; CHECK-NEXT:    add %fp, 0x0, %sp
+; CHECK-NEXT:    ld -8[%fp], %fp
+  %1 = mul i32 %a, 36
+  ret i32 %1
+}
+
+define i32 @muli32_p56(i32 inreg %a) #0 {
+; CHECK-LABEL: muli32_p56:
+; CHECK:       ! %bb.0:
+; CHECK-NEXT:    st %fp, [--%sp]
+; CHECK-NEXT:    add %sp, 0x8, %fp
+; CHECK-NEXT:    sub %sp, 0x8, %sp
+; CHECK-NEXT:    sh %r6, 0x3, %r3
+; CHECK-NEXT:    sh %r6, 0x6, %r9
+; CHECK-NEXT:    sub %r9, %r3, %rv
+; CHECK-NEXT:    ld -4[%fp], %pc ! return
+; CHECK-NEXT:    add %fp, 0x0, %sp
+; CHECK-NEXT:    ld -8[%fp], %fp
+  %1 = mul i32 %a, 56
+  ret i32 %1
+}
+
+define i32 @muli32_p60(i32 inreg %a) #0 {
+; CHECK-LABEL: muli32_p60:
+; CHECK:       ! %bb.0:
+; CHECK-NEXT:    st %fp, [--%sp]
+; CHECK-NEXT:    add %sp, 0x8, %fp
+; CHECK-NEXT:    sub %sp, 0x8, %sp
+; CHECK-NEXT:    sh %r6, 0x2, %r3
+; CHECK-NEXT:    sh %r6, 0x6, %r9
+; CHECK-NEXT:    sub %r9, %r3, %rv
+; CHECK-NEXT:    ld -4[%fp], %pc ! return
+; CHECK-NEXT:    add %fp, 0x0, %sp
+; CHECK-NEXT:    ld -8[%fp], %fp
+  %1 = mul i32 %a, 60
+  ret i32 %1
+}
+
+define i32 @muli32_p62(i32 inreg %a) #0 {
+; CHECK-LABEL: muli32_p62:
+; CHECK:       ! %bb.0:
+; CHECK-NEXT:    st %fp, [--%sp]
+; CHECK-NEXT:    add %sp, 0x8, %fp
+; CHECK-NEXT:    sub %sp, 0x8, %sp
+; CHECK-NEXT:    sh %r6, 0x1, %r3
+; CHECK-NEXT:    sh %r6, 0x6, %r9
+; CHECK-NEXT:    sub %r9, %r3, %rv
+; CHECK-NEXT:    ld -4[%fp], %pc ! return
+; CHECK-NEXT:    add %fp, 0x0, %sp
+; CHECK-NEXT:    ld -8[%fp], %fp
+  %1 = mul i32 %a, 62
+  ret i32 %1
+}
+
+define i32 @muli32_p63(i32 inreg %a) #0 {
+; CHECK-LABEL: muli32_p63:
+; CHECK:       ! %bb.0:
+; CHECK-NEXT:    st %fp, [--%sp]
+; CHECK-NEXT:    add %sp, 0x8, %fp
+; CHECK-NEXT:    sub %sp, 0x8, %sp
+; CHECK-NEXT:    sh %r6, 0x6, %r3
+; CHECK-NEXT:    sub %r3, %r6, %rv
+; CHECK-NEXT:    ld -4[%fp], %pc ! return
+; CHECK-NEXT:    add %fp, 0x0, %sp
+; CHECK-NEXT:    ld -8[%fp], %fp
+  %1 = mul i32 %a, 63
+  ret i32 %1
+}
+
+define i32 @muli32_p65(i32 inreg %a) #0 {
+; CHECK-LABEL: muli32_p65:
+; CHECK:       ! %bb.0:
+; CHECK-NEXT:    st %fp, [--%sp]
+; CHECK-NEXT:    add %sp, 0x8, %fp
+; CHECK-NEXT:    sub %sp, 0x8, %sp
+; CHECK-NEXT:    sh %r6, 0x6, %r3
+; CHECK-NEXT:    add %r3, %r6, %rv
+; CHECK-NEXT:    ld -4[%fp], %pc ! return
+; CHECK-NEXT:    add %fp, 0x0, %sp
+; CHECK-NEXT:    ld -8[%fp], %fp
+  %1 = mul i32 %a, 65
+  ret i32 %1
+}
+
+define i32 @muli32_p66(i32 inreg %a) #0 {
+; CHECK-LABEL: muli32_p66:
+; CHECK:       ! %bb.0:
+; CHECK-NEXT:    st %fp, [--%sp]
+; CHECK-NEXT:    add %sp, 0x8, %fp
+; CHECK-NEXT:    sub %sp, 0x8, %sp
+; CHECK-NEXT:    sh %r6, 0x1, %r3
+; CHECK-NEXT:    sh %r6, 0x6, %r9
+; CHECK-NEXT:    add %r9, %r3, %rv
+; CHECK-NEXT:    ld -4[%fp], %pc ! return
+; CHECK-NEXT:    add %fp, 0x0, %sp
+; CHECK-NEXT:    ld -8[%fp], %fp
+  %1 = mul i32 %a, 66
+  ret i32 %1
+}
+
+define i32 @muli32_m63(i32 inreg %a) #0 {
+; CHECK-LABEL: muli32_m63:
+; CHECK:       ! %bb.0:
+; CHECK-NEXT:    st %fp, [--%sp]
+; CHECK-NEXT:    add %sp, 0x8, %fp
+; CHECK-NEXT:    sub %sp, 0x8, %sp
+; CHECK-NEXT:    sh %r6, 0x6, %r3
+; CHECK-NEXT:    sub %r6, %r3, %rv
+; CHECK-NEXT:    ld -4[%fp], %pc ! return
+; CHECK-NEXT:    add %fp, 0x0, %sp
+; CHECK-NEXT:    ld -8[%fp], %fp
+  %1 = mul i32 %a, -63
+  ret i32 %1
+}
+
+define i32 @muli32_m65(i32 inreg %a) #0 {
+; CHECK-LABEL: muli32_m65:
+; CHECK:       ! %bb.0:
+; CHECK-NEXT:    st %fp, [--%sp]
+; CHECK-NEXT:    add %sp, 0x8, %fp
+; CHECK-NEXT:    sub %sp, 0x8, %sp
+; CHECK-NEXT:    sh %r6, 0x6, %r3
+; CHECK-NEXT:    add %r6, %r3, %r3
+; CHECK-NEXT:    sub %r0, %r3, %rv
+; CHECK-NEXT:    ld -4[%fp], %pc ! return
+; CHECK-NEXT:    add %fp, 0x0, %sp
+; CHECK-NEXT:    ld -8[%fp], %fp
+  %1 = mul i32 %a, -65
+  ret i32 %1
+}
+
+define i32 @muli32_p384(i32 inreg %a) #0 {
+; CHECK-LABEL: muli32_p384:
+; CHECK:       ! %bb.0:
+; CHECK-NEXT:    st %fp, [--%sp]
+; CHECK-NEXT:    add %sp, 0x8, %fp
+; CHECK-NEXT:    sub %sp, 0x8, %sp
+; CHECK-NEXT:    sh %r6, 0x7, %r3
+; CHECK-NEXT:    sh %r6, 0x9, %r9
+; CHECK-NEXT:    sub %r9, %r3, %rv
+; CHECK-NEXT:    ld -4[%fp], %pc ! return
+; CHECK-NEXT:    add %fp, 0x0, %sp
+; CHECK-NEXT:    ld -8[%fp], %fp
+  %1 = mul i32 %a, 384
+  ret i32 %1
+}
+
+define i32 @muli32_p12288(i32 inreg %a) #0 {
+; CHECK-LABEL: muli32_p12288:
+; CHECK:       ! %bb.0:
+; CHECK-NEXT:    st %fp, [--%sp]
+; CHECK-NEXT:    add %sp, 0x8, %fp
+; CHECK-NEXT:    sub %sp, 0x8, %sp
+; CHECK-NEXT:    sh %r6, 0xc, %r3
+; CHECK-NEXT:    sh %r6, 0xe, %r9
+; CHECK-NEXT:    sub %r9, %r3, %rv
+; CHECK-NEXT:    ld -4[%fp], %pc ! return
+; CHECK-NEXT:    add %fp, 0x0, %sp
+; CHECK-NEXT:    ld -8[%fp], %fp
+  %1 = mul i32 %a, 12288
+  ret i32 %1
+}
+
+define i32 @muli32_p4352(i32 inreg %a) #0 {
+; CHECK-LABEL: muli32_p4352:
+; CHECK:       ! %bb.0:
+; CHECK-NEXT:    st %fp, [--%sp]
+; CHECK-NEXT:    add %sp, 0x8, %fp
+; CHECK-NEXT:    sub %sp, 0x8, %sp
+; CHECK-NEXT:    sh %r6, 0x8, %r3
+; CHECK-NEXT:    sh %r6, 0xc, %r9
+; CHECK-NEXT:    add %r9, %r3, %rv
+; CHECK-NEXT:    ld -4[%fp], %pc ! return
+; CHECK-NEXT:    add %fp, 0x0, %sp
+; CHECK-NEXT:    ld -8[%fp], %fp
+  %1 = mul i32 %a, 4352
+  ret i32 %1
+}
+
+define i32 @muli32_p3840(i32 inreg %a) #0 {
+; CHECK-LABEL: muli32_p3840:
+; CHECK:       ! %bb.0:
+; CHECK-NEXT:    st %fp, [--%sp]
+; CHECK-NEXT:    add %sp, 0x8, %fp
+; CHECK-NEXT:    sub %sp, 0x8, %sp
+; CHECK-NEXT:    sh %r6, 0x8, %r3
+; CHECK-NEXT:    sh %r6, 0xc, %r9
+; CHECK-NEXT:    sub %r9, %r3, %rv
+; CHECK-NEXT:    ld -4[%fp], %pc ! return
+; CHECK-NEXT:    add %fp, 0x0, %sp
+; CHECK-NEXT:    ld -8[%fp], %fp
+  %1 = mul i32 %a, 3840
+  ret i32 %1
+}
+
+define i32 @muli32_m3840(i32 inreg %a) #0 {
+; CHECK-LABEL: muli32_m3840:
+; CHECK:       ! %bb.0:
+; CHECK-NEXT:    st %fp, [--%sp]
+; CHECK-NEXT:    add %sp, 0x8, %fp
+; CHECK-NEXT:    sub %sp, 0x8, %sp
+; CHECK-NEXT:    sh %r6, 0xc, %r3
+; CHECK-NEXT:    sh %r6, 0x8, %r9
+; CHECK-NEXT:    sub %r9, %r3, %rv
+; CHECK-NEXT:    ld -4[%fp], %pc ! return
+; CHECK-NEXT:    add %fp, 0x0, %sp
+; CHECK-NEXT:    ld -8[%fp], %fp
+  %1 = mul i32 %a, -3840
+  ret i32 %1
+}
+
+define i32 @muli32_m4352(i32 inreg %a) #0 {
+; CHECK-LABEL: muli32_m4352:
+; CHECK:       ! %bb.0:
+; CHECK-NEXT:    st %fp, [--%sp]
+; CHECK-NEXT:    add %sp, 0x8, %fp
+; CHECK-NEXT:    sub %sp, 0x8, %sp
+; CHECK-NEXT:    sh %r6, 0xc, %r3
+; CHECK-NEXT:    sh %r6, 0x8, %r9
+; CHECK-NEXT:    add %r9, %r3, %r3
+; CHECK-NEXT:    sub %r0, %r3, %rv
+; CHECK-NEXT:    ld -4[%fp], %pc ! return
+; CHECK-NEXT:    add %fp, 0x0, %sp
+; CHECK-NEXT:    ld -8[%fp], %fp
+  %1 = mul i32 %a, -4352
+  ret i32 %1
+}
diff --git a/llvm/test/CodeGen/MSP430/constant_multiply.ll b/llvm/test/CodeGen/MSP430/constant_multiply.ll
new file mode 100644
index 0000000000000..72d7c3311b8a2
--- /dev/null
+++ b/llvm/test/CodeGen/MSP430/constant_multiply.ll
@@ -0,0 +1,166 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc -mtriple=msp430 < %s | FileCheck %s
+
+; Test custom lowering for 16-bit constant multiplication.
+
+define i16 @mul_by_2(i16 %a) nounwind {
+; CHECK-LABEL: mul_by_2:
+; CHECK:       ; %bb.0:
+; CHECK-NEXT:    add r12, r12
+; CHECK-NEXT:    ret
+  %1 = mul i16 %a, 2
+  ret i16 %1
+}
+
+define i16 @mul_by_3(i16 %a) nounwind {
+; CHECK-LABEL: mul_by_3:
+; CHECK:       ; %bb.0:
+; CHECK-NEXT:    mov #3, r13
+; CHECK-NEXT:    call #__mspabi_mpyi
+; CHECK-NEXT:    ret
+  %1 = mul i16 %a, 3
+  ret i16 %1
+}
+
+define i16 @mul_by_5(i16 %a) nounwind {
+; CHECK-LABEL: mul_by_5:
+; CHECK:       ; %bb.0:
+; CHECK-NEXT:    mov #5, r13
+; CHECK-NEXT:    call #__mspabi_mpyi
+; CHECK-NEXT:    ret
+  %1 = mul i16 %a, 5
+  ret i16 %1
+}
+
+define i16 @mul_by_6(i16 %a) nounwind {
+; CHECK-LABEL: mul_by_6:
+; CHECK:       ; %bb.0:
+; CHECK-NEXT:    mov #6, r13
+; CHECK-NEXT:    call #__mspabi_mpyi
+; CHECK-NEXT:    ret
+  %1 = mul i16 %a, 6
+  ret i16 %1
+}
+
+define i16 @mul_by_7(i16 %a) nounwind {
+; CHECK-LABEL: mul_by_7:
+; CHECK:       ; %bb.0:
+; CHECK-NEXT:    mov #7, r13
+; CHECK-NEXT:    call #__mspabi_mpyi
+; CHECK-NEXT:    ret
+  %1 = mul i16 %a, 7
+  ret i16 %1
+}
+
+define i16 @mul_by_8(i16 %a) nounwind {
+; CHECK-LABEL: mul_by_8:
+; CHECK:       ; %bb.0:
+; CHECK-NEXT:    add r12, r12
+; CHECK-NEXT:    add r12, r12
+; CHECK-NEXT:    add r12, r12
+; CHECK-NEXT:    ret
+  %1 = mul i16 %a, 8
+  ret i16 %1
+}
+
+define i16 @mul_by_9(i16 %a) nounwind {
+; CHECK-LABEL: mul_by_9:
+; CHECK:       ; %bb.0:
+; CHECK-NEXT:    mov #9, r13
+; CHECK-NEXT:    call #__mspabi_mpyi
+; CHECK-NEXT:    ret
+  %1 = mul i16 %a, 9
+  ret i16 %1
+}
+
+define i16 @mul_by_10(i16 %a) nounwind {
+; CHECK-LABEL: mul_by_10:
+; CHECK:       ; %bb.0:
+; CHECK-NEXT:    mov #10, r13
+; CHECK-NEXT:    call #__mspabi_mpyi
+; CHECK-NEXT:    ret
+  %1 = mul i16 %a, 10
+  ret i16 %1
+}
+
+define i16 @mul_by_15(i16 %a) nounwind {
+; CHECK-LABEL: mul_by_15:
+; CHECK:       ; %bb.0:
+; CHECK-NEXT:    mov #15, r13
+; CHECK-NEXT:    call #__mspabi_mpyi
+; CHECK-NEXT:    ret
+  %1 = mul i16 %a, 15
+  ret i16 %1
+}
+
+define i16 @mul_by_16(i16 %a) nounwind {
+; CHECK-LABEL: mul_by_16:
+; CHECK:       ; %bb.0:
+; CHECK-NEXT:    add r12, r12
+; CHECK-NEXT:    add r12, r12
+; CHECK-NEXT:    add r12, r12
+; CHECK-NEXT:    add r12, r12
+; CHECK-NEXT:    ret
+  %1 = mul i16 %a, 16
+  ret i16 %1
+}
+
+define i16 @mul_by_17(i16 %a) nounwind {
+; CHECK-LABEL: mul_by_17:
+; CHECK:       ; %bb.0:
+; CHECK-NEXT:    mov #17, r13
+; CHECK-NEXT:    call #__mspabi_mpyi
+; CHECK-NEXT:    ret
+  %1 = mul i16 %a, 17
+  ret i16 %1
+}
+
+define i16 @mul_by_neg3(i16 %a) nounwind {
+; CHECK-LABEL: mul_by_neg3:
+; CHECK:       ; %bb.0:
+; CHECK-NEXT:    mov #-3, r13
+; CHECK-NEXT:    call #__mspabi_mpyi
+; CHECK-NEXT:    ret
+  %1 = mul i16 %a, -3
+  ret i16 %1
+}
+
+define i16 @mul_by_neg7(i16 %a) nounwind {
+; CHECK-LABEL: mul_by_neg7:
+; CHECK:       ; %bb.0:
+; CHECK-NEXT:    mov #-7, r13
+; CHECK-NEXT:    call #__mspabi_mpyi
+; CHECK-NEXT:    ret
+  %1 = mul i16 %a, -7
+  ret i16 %1
+}
+
+define i16 @mul_by_neg9(i16 %a) nounwind {
+; CHECK-LABEL: mul_by_neg9:
+; CHECK:       ; %bb.0:
+; CHECK-NEXT:    mov #-9, r13
+; CHECK-NEXT:    call #__mspabi_mpyi
+; CHECK-NEXT:    ret
+  %1 = mul i16 %a, -9
+  ret i16 %1
+}
+
+define i16 @mul_by_12345(i16 %a) nounwind {
+; CHECK-LABEL: mul_by_12345:
+; CHECK:       ; %bb.0:
+; CHECK-NEXT:    mov #12345, r13
+; CHECK-NEXT:    call #__mspabi_mpyi
+; CHECK-NEXT:    ret
+  %1 = mul i16 %a, 12345
+  ret i16 %1
+}
+
+; Non-constant multiply should still use libcall.
+define i16 @mul_variable(i16 %a, i16 %b) nounwind {
+; CHECK-LABEL: mul_variable:
+; CHECK:       ; %bb.0:
+; CHECK-NEXT:    call #__mspabi_mpyi
+; CHECK-NEXT:    ret
+  %1 = mul i16 %a, %b
+  ret i16 %1
+}
diff --git a/llvm/test/CodeGen/SPARC/constant_multiply.ll b/llvm/test/CodeGen/SPARC/constant_multiply.ll
new file mode 100644
index 0000000000000..e5a1e428f19c4
--- /dev/null
+++ b/llvm/test/CodeGen/SPARC/constant_multiply.ll
@@ -0,0 +1,148 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc -mtriple=sparc -mattr=+soft-mul-div < %s | FileCheck %s
+
+; Test mul-by-constant expansion for SparcV7 (no hardware multiply).
+
+define i32 @mul_by_3(i32 %a) nounwind {
+; CHECK-LABEL: mul_by_3:
+; CHECK:       ! %bb.0:
+; CHECK-NEXT:    save %sp, -96, %sp
+; CHECK-NEXT:    mov %i0, %o0
+; CHECK-NEXT:    call .umul
+; CHECK-NEXT:    mov 3, %o1
+; CHECK-NEXT:    ret
+; CHECK-NEXT:    restore %g0, %o0, %o0
+  %1 = mul i32 %a, 3
+  ret i32 %1
+}
+
+define i32 @mul_by_5(i32 %a) nounwind {
+; CHECK-LABEL: mul_by_5:
+; CHECK:       ! %bb.0:
+; CHECK-NEXT:    save %sp, -96, %sp
+; CHECK-NEXT:    mov %i0, %o0
+; CHECK-NEXT:    call .umul
+; CHECK-NEXT:    mov 5, %o1
+; CHECK-NEXT:    ret
+; CHECK-NEXT:    restore %g0, %o0, %o0
+  %1 = mul i32 %a, 5
+  ret i32 %1
+}
+
+define i32 @mul_by_7(i32 %a) nounwind {
+; CHECK-LABEL: mul_by_7:
+; CHECK:       ! %bb.0:
+; CHECK-NEXT:    save %sp, -96, %sp
+; CHECK-NEXT:    mov %i0, %o0
+; CHECK-NEXT:    call .umul
+; CHECK-NEXT:    mov 7, %o1
+; CHECK-NEXT:    ret
+; CHECK-NEXT:    restore %g0, %o0, %o0
+  %1 = mul i32 %a, 7
+  ret i32 %1
+}
+
+define i32 @mul_by_9(i32 %a) nounwind {
+; CHECK-LABEL: mul_by_9:
+; CHECK:       ! %bb.0:
+; CHECK-NEXT:    save %sp, -96, %sp
+; CHECK-NEXT:    mov %i0, %o0
+; CHECK-NEXT:    call .umul
+; CHECK-NEXT:    mov 9, %o1
+; CHECK-NEXT:    ret
+; CHECK-NEXT:    restore %g0, %o0, %o0
+  %1 = mul i32 %a, 9
+  ret i32 %1
+}
+
+define i32 @mul_by_10(i32 %a) nounwind {
+; CHECK-LABEL: mul_by_10:
+; CHECK:       ! %bb.0:
+; CHECK-NEXT:    save %sp, -96, %sp
+; CHECK-NEXT:    mov %i0, %o0
+; CHECK-NEXT:    call .umul
+; CHECK-NEXT:    mov 10, %o1
+; CHECK-NEXT:    ret
+; CHECK-NEXT:    restore %g0, %o0, %o0
+  %1 = mul i32 %a, 10
+  ret i32 %1
+}
+
+define i32 @mul_by_15(i32 %a) nounwind {
+; CHECK-LABEL: mul_by_15:
+; CHECK:       ! %bb.0:
+; CHECK-NEXT:    save %sp, -96, %sp
+; CHECK-NEXT:    mov %i0, %o0
+; CHECK-NEXT:    call .umul
+; CHECK-NEXT:    mov 15, %o1
+; CHECK-NEXT:    ret
+; CHECK-NEXT:    restore %g0, %o0, %o0
+  %1 = mul i32 %a, 15
+  ret i32 %1
+}
+
+define i32 @mul_by_neg7(i32 %a) nounwind {
+; CHECK-LABEL: mul_by_neg7:
+; CHECK:       ! %bb.0:
+; CHECK-NEXT:    save %sp, -96, %sp
+; CHECK-NEXT:    mov %i0, %o0
+; CHECK-NEXT:    call .umul
+; CHECK-NEXT:    mov -7, %o1
+; CHECK-NEXT:    ret
+; CHECK-NEXT:    restore %g0, %o0, %o0
+  %1 = mul i32 %a, -7
+  ret i32 %1
+}
+
+define i32 @mul_by_neg9(i32 %a) nounwind {
+; CHECK-LABEL: mul_by_neg9:
+; CHECK:       ! %bb.0:
+; CHECK-NEXT:    save %sp, -96, %sp
+; CHECK-NEXT:    mov %i0, %o0
+; CHECK-NEXT:    call .umul
+; CHECK-NEXT:    mov -9, %o1
+; CHECK-NEXT:    ret
+; CHECK-NEXT:    restore %g0, %o0, %o0
+  %1 = mul i32 %a, -9
+  ret i32 %1
+}
+
+define i32 @mul_by_65(i32 %a) nounwind {
+; CHECK-LABEL: mul_by_65:
+; CHECK:       ! %bb.0:
+; CHECK-NEXT:    save %sp, -96, %sp
+; CHECK-NEXT:    mov %i0, %o0
+; CHECK-NEXT:    call .umul
+; CHECK-NEXT:    mov 65, %o1
+; CHECK-NEXT:    ret
+; CHECK-NEXT:    restore %g0, %o0, %o0
+  %1 = mul i32 %a, 65
+  ret i32 %1
+}
+
+define i32 @mul_by_384(i32 %a) nounwind {
+; CHECK-LABEL: mul_by_384:
+; CHECK:       ! %bb.0:
+; CHECK-NEXT:    save %sp, -96, %sp
+; CHECK-NEXT:    mov %i0, %o0
+; CHECK-NEXT:    call .umul
+; CHECK-NEXT:    mov 384, %o1
+; CHECK-NEXT:    ret
+; CHECK-NEXT:    restore %g0, %o0, %o0
+  %1 = mul i32 %a, 384
+  ret i32 %1
+}
+
+; Non-constant multiply should still use the libcall.
+define i32 @mul_variable(i32 %a, i32 %b) nounwind {
+; CHECK-LABEL: mul_variable:
+; CHECK:       ! %bb.0:
+; CHECK-NEXT:    save %sp, -96, %sp
+; CHECK-NEXT:    mov %i1, %o1
+; CHECK-NEXT:    call .umul
+; CHECK-NEXT:    mov %i0, %o0
+; CHECK-NEXT:    ret
+; CHECK-NEXT:    restore %g0, %o0, %o0
+  %1 = mul i32 %a, %b
+  ret i32 %1
+}

>From 05567966804aa907f502aecb423300f289408e02 Mon Sep 17 00:00:00 2001
From: Iris Shi <0.0 at owo.li>
Date: Sat, 9 May 2026 21:53:56 +0800
Subject: [PATCH 2/2] [TargetLowering] Add target-independent mul-by-constant
 expansion algorithm

---
 llvm/include/llvm/CodeGen/TargetLowering.h    |  16 +
 llvm/lib/CodeGen/SelectionDAG/CMakeLists.txt  |   1 +
 .../SelectionDAG/ExpandMulByConstant.cpp      | 307 ++++++++++
 llvm/lib/Target/AVR/AVRISelLowering.cpp       |  22 +-
 llvm/lib/Target/AVR/AVRISelLowering.h         |   1 +
 llvm/lib/Target/Lanai/LanaiISelLowering.cpp   |  79 +--
 llvm/lib/Target/MSP430/MSP430ISelLowering.cpp |  28 +-
 llvm/lib/Target/MSP430/MSP430ISelLowering.h   |   1 +
 llvm/lib/Target/RISCV/RISCVISelLowering.cpp   |  35 +-
 llvm/lib/Target/Sparc/SparcISelLowering.cpp   |  19 +-
 llvm/lib/Target/Sparc/SparcISelLowering.h     |   1 +
 llvm/test/CodeGen/AVR/constant_multiply.ll    |  70 ++-
 llvm/test/CodeGen/Lanai/constant_multiply.ll  | 160 ++---
 llvm/test/CodeGen/Lanai/multiply.ll           |  94 ++-
 llvm/test/CodeGen/MSP430/constant_multiply.ll |  97 ++-
 llvm/test/CodeGen/RISCV/ctlz-cttz-ctpop.ll    |  60 +-
 .../CodeGen/RISCV/ctz_zero_return_test.ll     | 240 +++-----
 llvm/test/CodeGen/RISCV/mul-expand.ll         | 555 ++++++------------
 llvm/test/CodeGen/RISCV/mul.ll                | 106 ++--
 llvm/test/CodeGen/RISCV/rv64xtheadbb.ll       | 126 ++--
 llvm/test/CodeGen/RISCV/rv64zbb.ll            | 126 ++--
 .../CodeGen/RISCV/rvv/known-never-zero.ll     |  34 +-
 .../CodeGen/RISCV/srem-seteq-illegal-types.ll | 199 +++----
 .../CodeGen/RISCV/urem-seteq-illegal-types.ll | 288 ++++-----
 llvm/test/CodeGen/SPARC/constant_multiply.ll  |  93 ++-
 25 files changed, 1353 insertions(+), 1405 deletions(-)
 create mode 100644 llvm/lib/CodeGen/SelectionDAG/ExpandMulByConstant.cpp

diff --git a/llvm/include/llvm/CodeGen/TargetLowering.h b/llvm/include/llvm/CodeGen/TargetLowering.h
index f1119e4acce58..bb2d3f78cb506 100644
--- a/llvm/include/llvm/CodeGen/TargetLowering.h
+++ b/llvm/include/llvm/CodeGen/TargetLowering.h
@@ -5503,6 +5503,22 @@ class LLVM_ABI TargetLowering : public TargetLoweringBase {
     return DAG.getConstantFP(0.0, SDLoc(Operand), Operand.getValueType());
   }
 
+  //===--------------------------------------------------------------------===//
+  // Mul utility functions
+  //
+
+  /// Expand X * C into shifts and adds/subs using Bernstein's algorithm.
+  /// \param ShlAddCost maps shift amount to the cost of a fused shift-add step.
+  /// \param InstrCount if non-null, contains the number of instructions after
+  /// expansion.
+  /// Returns SDValue() if expansion is not profitable.
+  SDValue buildMulByConstant(
+      SDNode *N, SelectionDAG &DAG, const APInt &MulAmt,
+      unsigned *InstrCount = nullptr,
+      function_ref<unsigned(unsigned)> ShlAddCost = [](unsigned) {
+        return 2u;
+      }) const;
+
   //===--------------------------------------------------------------------===//
   // Legalization utility functions
   //
diff --git a/llvm/lib/CodeGen/SelectionDAG/CMakeLists.txt b/llvm/lib/CodeGen/SelectionDAG/CMakeLists.txt
index 93a742a19aa79..b560b57c7c540 100644
--- a/llvm/lib/CodeGen/SelectionDAG/CMakeLists.txt
+++ b/llvm/lib/CodeGen/SelectionDAG/CMakeLists.txt
@@ -1,5 +1,6 @@
 add_llvm_component_library(LLVMSelectionDAG
   DAGCombiner.cpp
+  ExpandMulByConstant.cpp
   FastISel.cpp
   FunctionLoweringInfo.cpp
   InstrEmitter.cpp
diff --git a/llvm/lib/CodeGen/SelectionDAG/ExpandMulByConstant.cpp b/llvm/lib/CodeGen/SelectionDAG/ExpandMulByConstant.cpp
new file mode 100644
index 0000000000000..25a9512b55348
--- /dev/null
+++ b/llvm/lib/CodeGen/SelectionDAG/ExpandMulByConstant.cpp
@@ -0,0 +1,307 @@
+//===- ExpandMulByConstant.cpp --------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements Bernstein's algorithm for decomposing multiplication
+// by a constant into a sequence of shifts and adds/subs.
+// Reference: https://doi.org/10.1002/spe.4380160704
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/CodeGen/SelectionDAG.h"
+#include "llvm/CodeGen/TargetLowering.h"
+#include <unordered_map>
+
+using namespace llvm;
+
+namespace {
+
+struct MulNode {
+  enum Op : uint8_t {
+    Unset,
+    One,
+    Neg,
+    ShiftAdd,
+    ShiftSub,
+    ShiftRev,
+    FactorAdd,
+    FactorSub,
+    FactorRev
+  };
+  Op Opcode = Unset;
+  int64_t Parent = 0;
+  int Cost = 1;
+  bool Valid = false;
+};
+
+class MulDecomposer {
+public:
+  explicit MulDecomposer(function_ref<unsigned(unsigned)> ShlAddCost)
+      : ShlAddCost(ShlAddCost) {
+    auto &One = Nodes[1];
+    One.Opcode = MulNode::One;
+    One.Cost = 0;
+    One.Valid = true;
+
+    auto &Neg = Nodes[-1];
+    Neg.Opcode = MulNode::Neg;
+    Neg.Cost = 1;
+    Neg.Valid = true;
+  }
+
+  int computeCost(int64_t N);
+  SDValue build(SelectionDAG &DAG, const SDLoc &DL, EVT VT, SDValue X,
+                int64_t N);
+
+private:
+  function_ref<unsigned(unsigned)> ShlAddCost;
+  // DenseMap would invalidate references on rehash
+  std::unordered_map<int64_t, MulNode> Nodes;
+
+  static int64_t makeOdd(int64_t N) {
+    if (N == 0)
+      return 0;
+    assert(N != INT64_MIN && "makeOdd cannot handle INT64_MIN");
+    return N >> llvm::countr_zero(static_cast<uint64_t>(N));
+  }
+
+  static unsigned estimate(int64_t N) {
+    assert(N != 0 && "estimate does not handle zero");
+    uint64_t Abs = N < 0 ? static_cast<uint64_t>(-N) : static_cast<uint64_t>(N);
+    unsigned C = 2 * llvm::popcount(Abs) - 1;
+    if (N < 0)
+      C++;
+    return C;
+  }
+
+  static unsigned shiftBetween(int64_t From, int64_t To) {
+    assert(From != 0 && "shiftBetween called with From==0");
+    unsigned S = llvm::countr_zero(static_cast<uint64_t>(To)) -
+                 llvm::countr_zero(static_cast<uint64_t>(From));
+    assert((static_cast<uint64_t>(From) << S) == static_cast<uint64_t>(To) &&
+           "From is not a right-shift of To");
+    return S;
+  }
+
+  void tryOp(MulNode::Op Op, int StepCost, int &Cost, int64_t Target, int Lower,
+             int &Upper, MulNode &P) {
+    MulNode &Parent = Nodes[Target];
+    int K = oddCost(Parent, Target, Lower + StepCost, Upper);
+    bool Better = K < Cost;
+    if (Better || !P.Valid) {
+      if (Better || K < Upper || P.Opcode == MulNode::Unset) {
+        P.Parent = Target;
+        P.Opcode = Op;
+        P.Cost = Parent.Cost + StepCost;
+        if (Better || K < Upper)
+          P.Valid = true;
+      }
+      Cost = K;
+      Upper = K;
+    }
+  }
+
+  int oddCost(MulNode &P, int64_t N, int Lower, int Upper) {
+    int Cost = P.Cost + Lower;
+    if (Cost >= Upper)
+      return Cost;
+    if (P.Valid)
+      return Cost;
+
+    if (N > 0) {
+      int64_t I = 4;
+      int64_t Half = N >> 1;
+      while (I < Half) {
+        // FactorSub: N = Q * (I-1), decompose as (Q << log2(I)) - Q.
+        if (N % (I - 1) == 0)
+          tryOp(MulNode::FactorSub, 2, Cost, N / (I - 1), Lower, Upper, P);
+        // FactorAdd: N = Q * (I+1), decompose as (Q << log2(I)) + Q.
+        if (N % (I + 1) == 0) {
+          unsigned ShAmt = llvm::countr_zero(static_cast<uint64_t>(I));
+          tryOp(MulNode::FactorAdd, ShlAddCost(ShAmt), Cost, N / (I + 1), Lower,
+                Upper, P);
+        }
+        I <<= 1;
+      }
+      // ShiftAdd: N = (make_odd(N-1) << s) + 1.
+      {
+        int64_t Odd = makeOdd(N - 1);
+        unsigned ShAmt = shiftBetween(Odd, N - 1);
+        tryOp(MulNode::ShiftAdd, ShlAddCost(ShAmt), Cost, Odd, Lower, Upper, P);
+      }
+    } else {
+      int64_t I = 4;
+      int64_t Half = (-N) >> 1;
+      while (I < Half) {
+        if (N % (1 - I) == 0)
+          tryOp(MulNode::FactorRev, 2, Cost, N / (1 - I), Lower, Upper, P);
+        if (N % (I + 1) == 0) {
+          unsigned ShAmt = llvm::countr_zero(static_cast<uint64_t>(I));
+          tryOp(MulNode::FactorAdd, ShlAddCost(ShAmt), Cost, N / (I + 1), Lower,
+                Upper, P);
+        }
+        I <<= 1;
+      }
+      tryOp(MulNode::ShiftRev, 2, Cost, makeOdd(1 - N), Lower, Upper, P);
+    }
+    tryOp(MulNode::ShiftSub, 2, Cost, makeOdd(N + 1), Lower, Upper, P);
+    return Cost;
+  }
+
+  SDValue emitOdd(SelectionDAG &DAG, const SDLoc &DL, EVT VT, SDValue X,
+                  int64_t N);
+  SDValue emitEven(SelectionDAG &DAG, const SDLoc &DL, EVT VT, SDValue X,
+                   int64_t N);
+
+  SDValue shl(SelectionDAG &DAG, const SDLoc &DL, EVT VT, SDValue V,
+              unsigned S) {
+    if (S == 0)
+      return V;
+    return DAG.getNode(ISD::SHL, DL, VT, V,
+                       DAG.getShiftAmountConstant(S, VT, DL));
+  }
+};
+
+int MulDecomposer::computeCost(int64_t N) {
+  if (N == 0)
+    return 0;
+
+  if (N & 1) {
+    MulNode &P = Nodes[N];
+    return oddCost(P, N, 0, estimate(N));
+  }
+
+  // Even: same three-way split as emitEven.
+  MulNode &P1 = Nodes[N + 1];
+  int C1 = oddCost(P1, N + 1, 0, estimate(N + 1));
+
+  int64_t Odd = makeOdd(N);
+  MulNode &P2 = Nodes[Odd];
+  int C2 = oddCost(P2, Odd, 0, C1);
+
+  int64_t Delta = N > 0 ? N - 1 : 1 - N;
+  MulNode &P3 = Nodes[Delta];
+  int C3 = oddCost(P3, Delta, 0, C2);
+
+  int Best = std::min({C1, C2, C3});
+  // +1 for the extra add/sub or shift that wraps the odd kernel.
+  return Best + 1;
+}
+
+SDValue MulDecomposer::build(SelectionDAG &DAG, const SDLoc &DL, EVT VT,
+                             SDValue X, int64_t N) {
+  if (N == 0)
+    return DAG.getConstant(0, DL, VT);
+
+  if (N & 1) {
+    MulNode &P = Nodes[N];
+    oddCost(P, N, 0, estimate(N));
+    return emitOdd(DAG, DL, VT, X, N);
+  }
+  return emitEven(DAG, DL, VT, X, N);
+}
+
+SDValue MulDecomposer::emitOdd(SelectionDAG &DAG, const SDLoc &DL, EVT VT,
+                               SDValue X, int64_t N) {
+  MulNode &P = Nodes[N];
+  switch (P.Opcode) {
+  case MulNode::One:
+    return X;
+  case MulNode::Neg:
+    return DAG.getNegative(X, DL, VT);
+  case MulNode::ShiftAdd: {
+    SDValue V = emitOdd(DAG, DL, VT, X, P.Parent);
+    unsigned S = shiftBetween(P.Parent, N - 1);
+    SDValue Shifted = shl(DAG, DL, VT, V, S);
+    return DAG.getNode(ISD::ADD, DL, VT, Shifted, X);
+  }
+  case MulNode::ShiftSub: {
+    SDValue V = emitOdd(DAG, DL, VT, X, P.Parent);
+    unsigned S = shiftBetween(P.Parent, N + 1);
+    SDValue Shifted = shl(DAG, DL, VT, V, S);
+    return DAG.getNode(ISD::SUB, DL, VT, Shifted, X);
+  }
+  case MulNode::ShiftRev: {
+    SDValue V = emitOdd(DAG, DL, VT, X, P.Parent);
+    unsigned S = shiftBetween(P.Parent, 1 - N);
+    SDValue Shifted = shl(DAG, DL, VT, V, S);
+    return DAG.getNode(ISD::SUB, DL, VT, X, Shifted);
+  }
+  case MulNode::FactorAdd: {
+    SDValue V = emitOdd(DAG, DL, VT, X, P.Parent);
+    unsigned S = shiftBetween(P.Parent, N - P.Parent);
+    SDValue Shifted = shl(DAG, DL, VT, V, S);
+    return DAG.getNode(ISD::ADD, DL, VT, Shifted, V);
+  }
+  case MulNode::FactorSub: {
+    SDValue V = emitOdd(DAG, DL, VT, X, P.Parent);
+    unsigned S = shiftBetween(P.Parent, N + P.Parent);
+    SDValue Shifted = shl(DAG, DL, VT, V, S);
+    return DAG.getNode(ISD::SUB, DL, VT, Shifted, V);
+  }
+  case MulNode::FactorRev: {
+    SDValue V = emitOdd(DAG, DL, VT, X, P.Parent);
+    unsigned S = shiftBetween(P.Parent, P.Parent - N);
+    SDValue Shifted = shl(DAG, DL, VT, V, S);
+    return DAG.getNode(ISD::SUB, DL, VT, V, Shifted);
+  }
+  default:
+    llvm_unreachable("unset MulNode op");
+  }
+}
+
+SDValue MulDecomposer::emitEven(SelectionDAG &DAG, const SDLoc &DL, EVT VT,
+                                SDValue X, int64_t N) {
+  // Pick the cheapest:
+  //   1) N+1 is odd: build (N+1)*X then subtract X.
+  //   2) Factor out trailing zeros: build make_odd(N)*X then shift.
+  //   3) N-1 (or 1-N) is odd: build that, then add X.
+  MulNode &P1 = Nodes[N + 1];
+  int C1 = oddCost(P1, N + 1, 0, estimate(N + 1));
+
+  int64_t Odd = makeOdd(N);
+  MulNode &P2 = Nodes[Odd];
+  int C2 = oddCost(P2, Odd, 0, C1);
+
+  int64_t Delta = N > 0 ? N - 1 : 1 - N;
+  MulNode &P3 = Nodes[Delta];
+  int C3 = oddCost(P3, Delta, 0, C2);
+
+  int C23 = std::min(C2, C3);
+  if (C1 <= C23) {
+    SDValue V = emitOdd(DAG, DL, VT, X, N + 1);
+    return DAG.getNode(ISD::SUB, DL, VT, V, X);
+  }
+  if (C2 <= C3) {
+    SDValue V = emitOdd(DAG, DL, VT, X, Odd);
+    unsigned S = shiftBetween(Odd, N);
+    return shl(DAG, DL, VT, V, S);
+  }
+  SDValue V = emitOdd(DAG, DL, VT, X, Delta);
+  if (N > 0)
+    return DAG.getNode(ISD::ADD, DL, VT, V, X);
+  return DAG.getNode(ISD::SUB, DL, VT, X, V);
+}
+
+} // end anonymous namespace
+
+SDValue TargetLowering::buildMulByConstant(
+    SDNode *N, SelectionDAG &DAG, const APInt &MulAmt, unsigned *InstrCount,
+    function_ref<unsigned(unsigned)> ShlAddCost) const {
+  if (!MulAmt.isSignedIntN(64))
+    return SDValue();
+
+  int64_t Val = MulAmt.getSExtValue();
+  // INT64_MIN cannot be handled (negation/makeOdd would overflow).
+  if (Val == INT64_MIN)
+    return SDValue();
+
+  MulDecomposer D(ShlAddCost);
+  if (InstrCount)
+    *InstrCount = D.computeCost(Val);
+  return D.build(DAG, SDLoc(N), N->getValueType(0), N->getOperand(0), Val);
+}
diff --git a/llvm/lib/Target/AVR/AVRISelLowering.cpp b/llvm/lib/Target/AVR/AVRISelLowering.cpp
index 89389f7da827b..9d66d819e1beb 100644
--- a/llvm/lib/Target/AVR/AVRISelLowering.cpp
+++ b/llvm/lib/Target/AVR/AVRISelLowering.cpp
@@ -164,19 +164,19 @@ AVRTargetLowering::AVRTargetLowering(const AVRTargetMachine &TM,
   setOperationAction(ISD::SDIVREM, MVT::i16, Custom);
   setOperationAction(ISD::SDIVREM, MVT::i32, Custom);
 
-  // Do not use MUL. The AVR instructions are closer to SMUL_LOHI &co.
-  setOperationAction(ISD::MUL, MVT::i8, Expand);
-  setOperationAction(ISD::MUL, MVT::i16, Expand);
-
   // Expand 16 bit multiplications.
   setOperationAction(ISD::SMUL_LOHI, MVT::i16, Expand);
   setOperationAction(ISD::UMUL_LOHI, MVT::i16, Expand);
 
-  // Expand multiplications to libcalls when there is
-  // no hardware MUL.
   if (!Subtarget.supportsMultiplication()) {
+    setOperationAction(ISD::MUL, MVT::i8, Custom);
+    setOperationAction(ISD::MUL, MVT::i16, Custom);
     setOperationAction(ISD::SMUL_LOHI, MVT::i8, Expand);
     setOperationAction(ISD::UMUL_LOHI, MVT::i8, Expand);
+  } else {
+    // Do not use MUL. The AVR instructions are closer to SMUL_LOHI &co.
+    setOperationAction(ISD::MUL, MVT::i8, Expand);
+    setOperationAction(ISD::MUL, MVT::i16, Expand);
   }
 
   for (MVT VT : MVT::integer_valuetypes()) {
@@ -925,10 +925,20 @@ SDValue AVRTargetLowering::LowerINLINEASM(SDValue Op, SelectionDAG &DAG) const {
   return New;
 }
 
+SDValue AVRTargetLowering::LowerMUL(SDValue Op, SelectionDAG &DAG) const {
+  ConstantSDNode *C = dyn_cast<ConstantSDNode>(Op->getOperand(1));
+  if (!C)
+    return SDValue();
+
+  return buildMulByConstant(Op.getNode(), DAG, C->getAPIntValue());
+}
+
 SDValue AVRTargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) const {
   switch (Op.getOpcode()) {
   default:
     llvm_unreachable("Don't know how to custom lower this!");
+  case ISD::MUL:
+    return LowerMUL(Op, DAG);
   case ISD::SHL:
   case ISD::SRA:
   case ISD::SRL:
diff --git a/llvm/lib/Target/AVR/AVRISelLowering.h b/llvm/lib/Target/AVR/AVRISelLowering.h
index 2ae22b2d8af6c..fc9def930e0ea 100644
--- a/llvm/lib/Target/AVR/AVRISelLowering.h
+++ b/llvm/lib/Target/AVR/AVRISelLowering.h
@@ -99,6 +99,7 @@ class AVRTargetLowering : public TargetLowering {
                     SelectionDAG &DAG, SDLoc dl) const;
   SDValue getAVRCmp(SDValue LHS, SDValue RHS, SelectionDAG &DAG,
                     SDLoc dl) const;
+  SDValue LowerMUL(SDValue Op, SelectionDAG &DAG) const;
   SDValue LowerShifts(SDValue Op, SelectionDAG &DAG) const;
   SDValue LowerDivRem(SDValue Op, SelectionDAG &DAG) const;
   SDValue LowerGlobalAddress(SDValue Op, SelectionDAG &DAG) const;
diff --git a/llvm/lib/Target/Lanai/LanaiISelLowering.cpp b/llvm/lib/Target/Lanai/LanaiISelLowering.cpp
index 631a8de035ac2..2ddf8a1a49378 100644
--- a/llvm/lib/Target/Lanai/LanaiISelLowering.cpp
+++ b/llvm/lib/Target/Lanai/LanaiISelLowering.cpp
@@ -872,80 +872,13 @@ SDValue LanaiTargetLowering::LowerMUL(SDValue Op, SelectionDAG &DAG) const {
   if (!C)
     return SDValue();
 
-  int64_t MulAmt = C->getSExtValue();
-  int32_t HighestOne = -1;
-  uint32_t NonzeroEntries = 0;
-  int SignedDigit[32] = {0};
-
-  // Convert to non-adjacent form (NAF) signed-digit representation.
-  // NAF is a signed-digit form where no adjacent digits are non-zero. It is the
-  // minimal Hamming weight representation of a number (on average 1/3 of the
-  // digits will be non-zero vs 1/2 for regular binary representation). And as
-  // the non-zero digits will be the only digits contributing to the instruction
-  // count, this is desirable. The next loop converts it to NAF (following the
-  // approach in 'Guide to Elliptic Curve Cryptography' [ISBN: 038795273X]) by
-  // choosing the non-zero coefficients such that the resulting quotient is
-  // divisible by 2 which will cause the next coefficient to be zero.
-  int64_t E = std::abs(MulAmt);
-  int S = (MulAmt < 0 ? -1 : 1);
-  int I = 0;
-  while (E > 0) {
-    int ZI = 0;
-    if (E % 2 == 1) {
-      ZI = 2 - (E % 4);
-      if (ZI != 0)
-        ++NonzeroEntries;
-    }
-    SignedDigit[I] = S * ZI;
-    if (SignedDigit[I] == 1)
-      HighestOne = I;
-    E = (E - ZI) / 2;
-    ++I;
-  }
-
-  // Compute number of instructions required. Due to differences in lowering
-  // between the different processors this count is not exact.
-  // Start by assuming a shift and a add/sub for every non-zero entry (hence
-  // every non-zero entry requires 1 shift and 1 add/sub except for the first
-  // entry).
-  int32_t InstrRequired = 2 * NonzeroEntries - 1;
-  // Correct possible over-adding due to shift by 0 (which is not emitted).
-  if (std::abs(MulAmt) % 2 == 1)
-    --InstrRequired;
-  // Return if the form generated would exceed the instruction threshold.
-  if (InstrRequired > LanaiLowerConstantMulThreshold)
+  unsigned InstrCount = 0;
+  SDValue Result =
+      buildMulByConstant(Op.getNode(), DAG, C->getAPIntValue(), &InstrCount);
+  if (!Result ||
+      InstrCount > static_cast<unsigned>(LanaiLowerConstantMulThreshold))
     return SDValue();
-
-  SDValue Res;
-  SDLoc DL(Op);
-  SDValue V = Op->getOperand(0);
-
-  // Initialize the running sum. Set the running sum to the maximal shifted
-  // positive value (i.e., largest i such that zi == 1 and MulAmt has V<<i as a
-  // term NAF).
-  if (HighestOne == -1)
-    Res = DAG.getConstant(0, DL, MVT::i32);
-  else {
-    Res = DAG.getNode(ISD::SHL, DL, VT, V,
-                      DAG.getConstant(HighestOne, DL, MVT::i32));
-    SignedDigit[HighestOne] = 0;
-  }
-
-  // Assemble multiplication from shift, add, sub using NAF form and running
-  // sum.
-  for (unsigned int I = 0; I < std::size(SignedDigit); ++I) {
-    if (SignedDigit[I] == 0)
-      continue;
-
-    // Shifted multiplicand (v<<i).
-    SDValue Op =
-        DAG.getNode(ISD::SHL, DL, VT, V, DAG.getConstant(I, DL, MVT::i32));
-    if (SignedDigit[I] == 1)
-      Res = DAG.getNode(ISD::ADD, DL, VT, Res, Op);
-    else if (SignedDigit[I] == -1)
-      Res = DAG.getNode(ISD::SUB, DL, VT, Res, Op);
-  }
-  return Res;
+  return Result;
 }
 
 SDValue LanaiTargetLowering::LowerSETCC(SDValue Op, SelectionDAG &DAG) const {
diff --git a/llvm/lib/Target/MSP430/MSP430ISelLowering.cpp b/llvm/lib/Target/MSP430/MSP430ISelLowering.cpp
index d915969630966..8dc53a827ce58 100644
--- a/llvm/lib/Target/MSP430/MSP430ISelLowering.cpp
+++ b/llvm/lib/Target/MSP430/MSP430ISelLowering.cpp
@@ -116,13 +116,12 @@ MSP430TargetLowering::MSP430TargetLowering(const TargetMachine &TM,
 
   setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i1,   Expand);
 
-  // FIXME: Implement efficiently multiplication by a constant
   setOperationAction(ISD::MUL,              MVT::i8,    Promote);
   setOperationAction(ISD::MULHS,            MVT::i8,    Promote);
   setOperationAction(ISD::MULHU,            MVT::i8,    Promote);
   setOperationAction(ISD::SMUL_LOHI,        MVT::i8,    Promote);
   setOperationAction(ISD::UMUL_LOHI,        MVT::i8,    Promote);
-  setOperationAction(ISD::MUL,              MVT::i16,   LibCall);
+  setOperationAction(ISD::MUL,              MVT::i16,   Custom);
   setOperationAction(ISD::MULHS,            MVT::i16,   Expand);
   setOperationAction(ISD::MULHU,            MVT::i16,   Expand);
   setOperationAction(ISD::SMUL_LOHI,        MVT::i16,   Expand);
@@ -156,6 +155,7 @@ MSP430TargetLowering::MSP430TargetLowering(const TargetMachine &TM,
 SDValue MSP430TargetLowering::LowerOperation(SDValue Op,
                                              SelectionDAG &DAG) const {
   switch (Op.getOpcode()) {
+  case ISD::MUL:              return LowerMUL(Op, DAG);
   case ISD::SHL: // FALLTHROUGH
   case ISD::SRL:
   case ISD::SRA:              return LowerShifts(Op, DAG);
@@ -774,6 +774,30 @@ SDValue MSP430TargetLowering::LowerCallResult(
   return Chain;
 }
 
+SDValue MSP430TargetLowering::LowerMUL(SDValue Op, SelectionDAG &DAG) const {
+  EVT VT = Op->getValueType(0);
+  if (VT != MVT::i16)
+    return SDValue();
+
+  ConstantSDNode *C = dyn_cast<ConstantSDNode>(Op->getOperand(1));
+  if (!C)
+    return SDValue();
+
+  unsigned InstrCount = 0;
+  SDValue Result =
+      buildMulByConstant(Op.getNode(), DAG, C->getAPIntValue(), &InstrCount,
+                         [](unsigned ShAmt) -> unsigned {
+                           if (ShAmt == 8)
+                             return 2; // swpb + add
+                           if (ShAmt == 9)
+                             return 3; // swpb + shift-by-1 + add
+                           return ShAmt + 1; // ShAmt individual shifts + add
+                         });
+  if (!Result || InstrCount > 12)
+    return SDValue();
+  return Result;
+}
+
 SDValue MSP430TargetLowering::LowerShifts(SDValue Op,
                                           SelectionDAG &DAG) const {
   unsigned Opc = Op.getOpcode();
diff --git a/llvm/lib/Target/MSP430/MSP430ISelLowering.h b/llvm/lib/Target/MSP430/MSP430ISelLowering.h
index d906c3817bbe5..eedfc32b361a1 100644
--- a/llvm/lib/Target/MSP430/MSP430ISelLowering.h
+++ b/llvm/lib/Target/MSP430/MSP430ISelLowering.h
@@ -36,6 +36,7 @@ namespace llvm {
     /// LowerOperation - Provide custom lowering hooks for some operations.
     SDValue LowerOperation(SDValue Op, SelectionDAG &DAG) const override;
 
+    SDValue LowerMUL(SDValue Op, SelectionDAG &DAG) const;
     SDValue LowerShifts(SDValue Op, SelectionDAG &DAG) const;
     SDValue LowerGlobalAddress(SDValue Op, SelectionDAG &DAG) const;
     SDValue LowerBlockAddress(SDValue Op, SelectionDAG &DAG) const;
diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
index 2191d189fea49..64964dc5a310c 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
@@ -17017,32 +17017,6 @@ static SDValue performXORCombine(SDNode *N, SelectionDAG &DAG,
   return combineSelectAndUseCommutative(N, DAG, /*AllOnes*/ false, Subtarget);
 }
 
-// Try to expand a multiply to a sequence of shifts and add/subs,
-// for a machine without native mul instruction.
-static SDValue expandMulToNAFSequence(SDNode *N, SelectionDAG &DAG,
-                                      uint64_t MulAmt) {
-  SDLoc DL(N);
-  EVT VT = N->getValueType(0);
-  const uint64_t BitWidth = VT.getFixedSizeInBits();
-
-  SDValue Result = DAG.getConstant(0, DL, N->getValueType(0));
-  SDValue N0 = N->getOperand(0);
-
-  // Find the Non-adjacent form of the multiplier.
-  for (uint64_t E = MulAmt, I = 0; E && I < BitWidth; ++I, E >>= 1) {
-    if (E & 1) {
-      bool IsAdd = (E & 3) == 1;
-      E -= IsAdd ? 1 : -1;
-      SDValue ShiftVal = DAG.getNode(ISD::SHL, DL, VT, N0,
-                                     DAG.getShiftAmountConstant(I, VT, DL));
-      ISD::NodeType AddSubOp = IsAdd ? ISD::ADD : ISD::SUB;
-      Result = DAG.getNode(AddSubOp, DL, VT, Result, ShiftVal);
-    }
-  }
-
-  return Result;
-}
-
 // X * (2^N +/- 2^M) -> (add/sub (shl X, C1), (shl X, C2))
 static SDValue expandMulToAddOrSubOfShl(SDNode *N, SelectionDAG &DAG,
                                         uint64_t MulAmt) {
@@ -17244,8 +17218,13 @@ static SDValue expandMul(SDNode *N, SelectionDAG &DAG,
   if (SDValue V = expandMulToAddOrSubOfShl(N, DAG, MulAmt))
     return V;
 
-  if (!Subtarget.hasStdExtZmmul())
-    return expandMulToNAFSequence(N, DAG, MulAmt);
+  if (!Subtarget.hasStdExtZmmul()) {
+    const TargetLowering &TLI = DAG.getTargetLoweringInfo();
+    return TLI.buildMulByConstant(
+        N, DAG, APInt(64, MulAmt), nullptr,
+        // sh[123]add fuses shift+add into one instruction when available.
+        [&](unsigned ShAmt) { return Subtarget.hasShlAdd(ShAmt) ? 1u : 2u; });
+  }
 
   return SDValue();
 }
diff --git a/llvm/lib/Target/Sparc/SparcISelLowering.cpp b/llvm/lib/Target/Sparc/SparcISelLowering.cpp
index bfca95c9b1a38..81ea316d3f563 100644
--- a/llvm/lib/Target/Sparc/SparcISelLowering.cpp
+++ b/llvm/lib/Target/Sparc/SparcISelLowering.cpp
@@ -1885,15 +1885,17 @@ SparcTargetLowering::SparcTargetLowering(const TargetMachine &TM,
 
   // Expands to [SU]MUL_LOHI.
   setOperationAction(ISD::MULHU,     MVT::i32, Expand);
-  setOperationAction(ISD::MULHS,     MVT::i32, Expand);
-  setOperationAction(ISD::MUL,       MVT::i32, Expand);
+  setOperationAction(ISD::MULHS, MVT::i32, Expand);
 
   if (Subtarget->useSoftMulDiv()) {
+    setOperationAction(ISD::MUL, MVT::i32, Custom);
     // .umul works for both signed and unsigned
     setOperationAction(ISD::SMUL_LOHI, MVT::i32, Expand);
     setOperationAction(ISD::UMUL_LOHI, MVT::i32, Expand);
     setOperationAction(ISD::SDIV, MVT::i32, Expand);
     setOperationAction(ISD::UDIV, MVT::i32, Expand);
+  } else {
+    setOperationAction(ISD::MUL, MVT::i32, Expand);
   }
 
   if (Subtarget->is64Bit()) {
@@ -3136,6 +3138,18 @@ SDValue SparcTargetLowering::LowerINTRINSIC_WO_CHAIN(SDValue Op,
   }
 }
 
+SDValue SparcTargetLowering::LowerMUL(SDValue Op, SelectionDAG &DAG) const {
+  EVT VT = Op->getValueType(0);
+  if (VT != MVT::i32)
+    return SDValue();
+
+  ConstantSDNode *C = dyn_cast<ConstantSDNode>(Op->getOperand(1));
+  if (!C)
+    return SDValue();
+
+  return buildMulByConstant(Op.getNode(), DAG, C->getAPIntValue());
+}
+
 SDValue SparcTargetLowering::
 LowerOperation(SDValue Op, SelectionDAG &DAG) const {
 
@@ -3146,6 +3160,7 @@ LowerOperation(SDValue Op, SelectionDAG &DAG) const {
   switch (Op.getOpcode()) {
   default: llvm_unreachable("Should not custom lower this!");
 
+  case ISD::MUL:                return LowerMUL(Op, DAG);
   case ISD::RETURNADDR:         return LowerRETURNADDR(Op, DAG, *this,
                                                        Subtarget);
   case ISD::FRAMEADDR:          return LowerFRAMEADDR(Op, DAG,
diff --git a/llvm/lib/Target/Sparc/SparcISelLowering.h b/llvm/lib/Target/Sparc/SparcISelLowering.h
index f97b0ab9edd93..3ad59b0f8ef3b 100644
--- a/llvm/lib/Target/Sparc/SparcISelLowering.h
+++ b/llvm/lib/Target/Sparc/SparcISelLowering.h
@@ -143,6 +143,7 @@ namespace llvm {
     SDValue LowerF128Compare(SDValue LHS, SDValue RHS, unsigned &SPCC,
                              const SDLoc &DL, SelectionDAG &DAG) const;
 
+    SDValue LowerMUL(SDValue Op, SelectionDAG &DAG) const;
     SDValue LowerINTRINSIC_WO_CHAIN(SDValue Op, SelectionDAG &DAG) const;
 
     SDValue PerformBITCASTCombine(SDNode *N, DAGCombinerInfo &DCI) const;
diff --git a/llvm/test/CodeGen/AVR/constant_multiply.ll b/llvm/test/CodeGen/AVR/constant_multiply.ll
index c0cf630ac7a88..87d9925046620 100644
--- a/llvm/test/CodeGen/AVR/constant_multiply.ll
+++ b/llvm/test/CodeGen/AVR/constant_multiply.ll
@@ -7,8 +7,9 @@
 define i8 @mul_i8_by_3(i8 %a) nounwind {
 ; CHECK-LABEL: mul_i8_by_3:
 ; CHECK:       ; %bb.0:
-; CHECK-NEXT:    ldi r22, 3
-; CHECK-NEXT:    rcall __mulqi3
+; CHECK-NEXT:    mov r25, r24
+; CHECK-NEXT:    lsl r25
+; CHECK-NEXT:    add r24, r25
 ; CHECK-NEXT:    ret
   %1 = mul i8 %a, 3
   ret i8 %1
@@ -17,8 +18,10 @@ define i8 @mul_i8_by_3(i8 %a) nounwind {
 define i8 @mul_i8_by_5(i8 %a) nounwind {
 ; CHECK-LABEL: mul_i8_by_5:
 ; CHECK:       ; %bb.0:
-; CHECK-NEXT:    ldi r22, 5
-; CHECK-NEXT:    rcall __mulqi3
+; CHECK-NEXT:    mov r25, r24
+; CHECK-NEXT:    lsl r25
+; CHECK-NEXT:    lsl r25
+; CHECK-NEXT:    add r24, r25
 ; CHECK-NEXT:    ret
   %1 = mul i8 %a, 5
   ret i8 %1
@@ -27,8 +30,12 @@ define i8 @mul_i8_by_5(i8 %a) nounwind {
 define i8 @mul_i8_by_7(i8 %a) nounwind {
 ; CHECK-LABEL: mul_i8_by_7:
 ; CHECK:       ; %bb.0:
-; CHECK-NEXT:    ldi r22, 7
-; CHECK-NEXT:    rcall __mulqi3
+; CHECK-NEXT:    mov r25, r24
+; CHECK-NEXT:    lsl r25
+; CHECK-NEXT:    lsl r25
+; CHECK-NEXT:    lsl r25
+; CHECK-NEXT:    sub r25, r24
+; CHECK-NEXT:    mov r24, r25
 ; CHECK-NEXT:    ret
   %1 = mul i8 %a, 7
   ret i8 %1
@@ -37,8 +44,10 @@ define i8 @mul_i8_by_7(i8 %a) nounwind {
 define i8 @mul_i8_by_neg3(i8 %a) nounwind {
 ; CHECK-LABEL: mul_i8_by_neg3:
 ; CHECK:       ; %bb.0:
-; CHECK-NEXT:    ldi r22, -3
-; CHECK-NEXT:    rcall __mulqi3
+; CHECK-NEXT:    mov r25, r24
+; CHECK-NEXT:    lsl r25
+; CHECK-NEXT:    lsl r25
+; CHECK-NEXT:    sub r24, r25
 ; CHECK-NEXT:    ret
   %1 = mul i8 %a, -3
   ret i8 %1
@@ -47,9 +56,11 @@ define i8 @mul_i8_by_neg3(i8 %a) nounwind {
 define i16 @mul_i16_by_3(i16 %a) nounwind {
 ; CHECK-LABEL: mul_i16_by_3:
 ; CHECK:       ; %bb.0:
-; CHECK-NEXT:    ldi r22, 3
-; CHECK-NEXT:    ldi r23, 0
-; CHECK-NEXT:    rcall __mulhi3
+; CHECK-NEXT:    movw r18, r24
+; CHECK-NEXT:    lsl r18
+; CHECK-NEXT:    rol r19
+; CHECK-NEXT:    add r24, r18
+; CHECK-NEXT:    adc r25, r19
 ; CHECK-NEXT:    ret
   %1 = mul i16 %a, 3
   ret i16 %1
@@ -58,9 +69,16 @@ define i16 @mul_i16_by_3(i16 %a) nounwind {
 define i16 @mul_i16_by_7(i16 %a) nounwind {
 ; CHECK-LABEL: mul_i16_by_7:
 ; CHECK:       ; %bb.0:
-; CHECK-NEXT:    ldi r22, 7
-; CHECK-NEXT:    ldi r23, 0
-; CHECK-NEXT:    rcall __mulhi3
+; CHECK-NEXT:    movw r18, r24
+; CHECK-NEXT:    lsl r18
+; CHECK-NEXT:    rol r19
+; CHECK-NEXT:    lsl r18
+; CHECK-NEXT:    rol r19
+; CHECK-NEXT:    lsl r18
+; CHECK-NEXT:    rol r19
+; CHECK-NEXT:    sub r18, r24
+; CHECK-NEXT:    sbc r19, r25
+; CHECK-NEXT:    movw r24, r18
 ; CHECK-NEXT:    ret
   %1 = mul i16 %a, 7
   ret i16 %1
@@ -69,9 +87,15 @@ define i16 @mul_i16_by_7(i16 %a) nounwind {
 define i16 @mul_i16_by_10(i16 %a) nounwind {
 ; CHECK-LABEL: mul_i16_by_10:
 ; CHECK:       ; %bb.0:
-; CHECK-NEXT:    ldi r22, 10
-; CHECK-NEXT:    ldi r23, 0
-; CHECK-NEXT:    rcall __mulhi3
+; CHECK-NEXT:    movw r18, r24
+; CHECK-NEXT:    lsl r18
+; CHECK-NEXT:    rol r19
+; CHECK-NEXT:    lsl r18
+; CHECK-NEXT:    rol r19
+; CHECK-NEXT:    add r24, r18
+; CHECK-NEXT:    adc r25, r19
+; CHECK-NEXT:    lsl r24
+; CHECK-NEXT:    rol r25
 ; CHECK-NEXT:    ret
   %1 = mul i16 %a, 10
   ret i16 %1
@@ -80,9 +104,15 @@ define i16 @mul_i16_by_10(i16 %a) nounwind {
 define i16 @mul_i16_by_neg7(i16 %a) nounwind {
 ; CHECK-LABEL: mul_i16_by_neg7:
 ; CHECK:       ; %bb.0:
-; CHECK-NEXT:    ldi r22, 249
-; CHECK-NEXT:    ldi r23, 255
-; CHECK-NEXT:    rcall __mulhi3
+; CHECK-NEXT:    movw r18, r24
+; CHECK-NEXT:    lsl r18
+; CHECK-NEXT:    rol r19
+; CHECK-NEXT:    lsl r18
+; CHECK-NEXT:    rol r19
+; CHECK-NEXT:    lsl r18
+; CHECK-NEXT:    rol r19
+; CHECK-NEXT:    sub r24, r18
+; CHECK-NEXT:    sbc r25, r19
 ; CHECK-NEXT:    ret
   %1 = mul i16 %a, -7
   ret i16 %1
diff --git a/llvm/test/CodeGen/Lanai/constant_multiply.ll b/llvm/test/CodeGen/Lanai/constant_multiply.ll
index 165ef9d016dbf..31d5a48a465c1 100644
--- a/llvm/test/CodeGen/Lanai/constant_multiply.ll
+++ b/llvm/test/CodeGen/Lanai/constant_multiply.ll
@@ -12,9 +12,9 @@ define i32 @f6(i32 inreg %a) #0 {
 ; CHECK-NEXT:    st %fp, [--%sp]
 ; CHECK-NEXT:    add %sp, 0x8, %fp
 ; CHECK-NEXT:    sub %sp, 0x8, %sp
-; CHECK-NEXT:    sh %r6, 0x1, %r3
-; CHECK-NEXT:    sh %r6, 0x3, %r9
-; CHECK-NEXT:    sub %r9, %r3, %rv
+; CHECK-NEXT:    sh %r6, 0x3, %r3
+; CHECK-NEXT:    sub %r3, %r6, %r3
+; CHECK-NEXT:    sub %r3, %r6, %rv
 ; CHECK-NEXT:    ld -4[%fp], %pc ! return
 ; CHECK-NEXT:    add %fp, 0x0, %sp
 ; CHECK-NEXT:    ld -8[%fp], %fp
@@ -72,9 +72,9 @@ define i32 @f10(i32 inreg %a) #0 {
 ; CHECK-NEXT:    st %fp, [--%sp]
 ; CHECK-NEXT:    add %sp, 0x8, %fp
 ; CHECK-NEXT:    sub %sp, 0x8, %sp
-; CHECK-NEXT:    sh %r6, 0x1, %r3
-; CHECK-NEXT:    sh %r6, 0x3, %r9
-; CHECK-NEXT:    add %r9, %r3, %rv
+; CHECK-NEXT:    sh %r6, 0x2, %r3
+; CHECK-NEXT:    add %r3, %r6, %r3
+; CHECK-NEXT:    sh %r3, 0x1, %rv
 ; CHECK-NEXT:    ld -4[%fp], %pc ! return
 ; CHECK-NEXT:    add %fp, 0x0, %sp
 ; CHECK-NEXT:    ld -8[%fp], %fp
@@ -88,9 +88,9 @@ define i32 @f1280(i32 inreg %a) #0 {
 ; CHECK-NEXT:    st %fp, [--%sp]
 ; CHECK-NEXT:    add %sp, 0x8, %fp
 ; CHECK-NEXT:    sub %sp, 0x8, %sp
-; CHECK-NEXT:    sh %r6, 0x8, %r3
-; CHECK-NEXT:    sh %r6, 0xa, %r9
-; CHECK-NEXT:    add %r9, %r3, %rv
+; CHECK-NEXT:    sh %r6, 0x2, %r3
+; CHECK-NEXT:    add %r3, %r6, %r3
+; CHECK-NEXT:    sh %r3, 0x8, %rv
 ; CHECK-NEXT:    ld -4[%fp], %pc ! return
 ; CHECK-NEXT:    add %fp, 0x0, %sp
 ; CHECK-NEXT:    ld -8[%fp], %fp
@@ -104,9 +104,9 @@ define i32 @fm6(i32 inreg %a) #0 {
 ; CHECK-NEXT:    st %fp, [--%sp]
 ; CHECK-NEXT:    add %sp, 0x8, %fp
 ; CHECK-NEXT:    sub %sp, 0x8, %sp
-; CHECK-NEXT:    sh %r6, 0x3, %r3
-; CHECK-NEXT:    sh %r6, 0x1, %r9
-; CHECK-NEXT:    sub %r9, %r3, %rv
+; CHECK-NEXT:    sh %r6, 0x2, %r3
+; CHECK-NEXT:    sub %r6, %r3, %r3
+; CHECK-NEXT:    sh %r3, 0x1, %rv
 ; CHECK-NEXT:    ld -4[%fp], %pc ! return
 ; CHECK-NEXT:    add %fp, 0x0, %sp
 ; CHECK-NEXT:    ld -8[%fp], %fp
@@ -150,9 +150,9 @@ define i32 @fm9(i32 inreg %a) #0 {
 ; CHECK-NEXT:    st %fp, [--%sp]
 ; CHECK-NEXT:    add %sp, 0x8, %fp
 ; CHECK-NEXT:    sub %sp, 0x8, %sp
-; CHECK-NEXT:    sh %r6, 0x3, %r3
-; CHECK-NEXT:    add %r6, %r3, %r3
-; CHECK-NEXT:    sub %r0, %r3, %rv
+; CHECK-NEXT:    sub %r0, %r6, %r3
+; CHECK-NEXT:    sh %r3, 0x3, %r3
+; CHECK-NEXT:    sub %r3, %r6, %rv
 ; CHECK-NEXT:    ld -4[%fp], %pc ! return
 ; CHECK-NEXT:    add %fp, 0x0, %sp
 ; CHECK-NEXT:    ld -8[%fp], %fp
@@ -166,10 +166,10 @@ define i32 @fm10(i32 inreg %a) #0 {
 ; CHECK-NEXT:    st %fp, [--%sp]
 ; CHECK-NEXT:    add %sp, 0x8, %fp
 ; CHECK-NEXT:    sub %sp, 0x8, %sp
-; CHECK-NEXT:    sh %r6, 0x3, %r3
-; CHECK-NEXT:    sh %r6, 0x1, %r9
-; CHECK-NEXT:    add %r9, %r3, %r3
-; CHECK-NEXT:    sub %r0, %r3, %rv
+; CHECK-NEXT:    sub %r0, %r6, %r3
+; CHECK-NEXT:    sh %r3, 0x3, %r3
+; CHECK-NEXT:    sub %r3, %r6, %r3
+; CHECK-NEXT:    sub %r3, %r6, %rv
 ; CHECK-NEXT:    ld -4[%fp], %pc ! return
 ; CHECK-NEXT:    add %fp, 0x0, %sp
 ; CHECK-NEXT:    ld -8[%fp], %fp
@@ -183,11 +183,15 @@ define i32 @h1(i32 inreg %a) #0 {
 ; CHECK-NEXT:    st %fp, [--%sp]
 ; CHECK-NEXT:    add %sp, 0x8, %fp
 ; CHECK-NEXT:    sub %sp, 0x8, %sp
-; CHECK-NEXT:    mov 0xaaaa0000, %r3
-; CHECK-NEXT:    add %pc, 0x10, %rca
-; CHECK-NEXT:    st %rca, [--%sp]
-; CHECK-NEXT:    bt __mulsi3
-; CHECK-NEXT:    or %r3, 0xaaab, %r7
+; CHECK-NEXT:    sub %r0, %r6, %r3
+; CHECK-NEXT:    sh %r3, 0x10, %r3
+; CHECK-NEXT:    sub %r3, %r6, %r3
+; CHECK-NEXT:    sh %r3, 0x8, %r9
+; CHECK-NEXT:    add %r9, %r3, %r3
+; CHECK-NEXT:    sh %r3, 0x4, %r9
+; CHECK-NEXT:    add %r9, %r3, %r3
+; CHECK-NEXT:    sh %r3, 0x2, %r9
+; CHECK-NEXT:    add %r9, %r3, %rv
 ; CHECK-NEXT:    ld -4[%fp], %pc ! return
 ; CHECK-NEXT:    add %fp, 0x0, %sp
 ; CHECK-NEXT:    ld -8[%fp], %fp
@@ -201,9 +205,9 @@ define i32 @muli32_p10(i32 inreg %a) #0 {
 ; CHECK-NEXT:    st %fp, [--%sp]
 ; CHECK-NEXT:    add %sp, 0x8, %fp
 ; CHECK-NEXT:    sub %sp, 0x8, %sp
-; CHECK-NEXT:    sh %r6, 0x1, %r3
-; CHECK-NEXT:    sh %r6, 0x3, %r9
-; CHECK-NEXT:    add %r9, %r3, %rv
+; CHECK-NEXT:    sh %r6, 0x2, %r3
+; CHECK-NEXT:    add %r3, %r6, %r3
+; CHECK-NEXT:    sh %r3, 0x1, %rv
 ; CHECK-NEXT:    ld -4[%fp], %pc ! return
 ; CHECK-NEXT:    add %fp, 0x0, %sp
 ; CHECK-NEXT:    ld -8[%fp], %fp
@@ -217,9 +221,9 @@ define i32 @muli32_p14(i32 inreg %a) #0 {
 ; CHECK-NEXT:    st %fp, [--%sp]
 ; CHECK-NEXT:    add %sp, 0x8, %fp
 ; CHECK-NEXT:    sub %sp, 0x8, %sp
-; CHECK-NEXT:    sh %r6, 0x1, %r3
-; CHECK-NEXT:    sh %r6, 0x4, %r9
-; CHECK-NEXT:    sub %r9, %r3, %rv
+; CHECK-NEXT:    sh %r6, 0x4, %r3
+; CHECK-NEXT:    sub %r3, %r6, %r3
+; CHECK-NEXT:    sub %r3, %r6, %rv
 ; CHECK-NEXT:    ld -4[%fp], %pc ! return
 ; CHECK-NEXT:    add %fp, 0x0, %sp
 ; CHECK-NEXT:    ld -8[%fp], %fp
@@ -233,9 +237,9 @@ define i32 @muli32_p18(i32 inreg %a) #0 {
 ; CHECK-NEXT:    st %fp, [--%sp]
 ; CHECK-NEXT:    add %sp, 0x8, %fp
 ; CHECK-NEXT:    sub %sp, 0x8, %sp
-; CHECK-NEXT:    sh %r6, 0x1, %r3
-; CHECK-NEXT:    sh %r6, 0x4, %r9
-; CHECK-NEXT:    add %r9, %r3, %rv
+; CHECK-NEXT:    sh %r6, 0x3, %r3
+; CHECK-NEXT:    add %r3, %r6, %r3
+; CHECK-NEXT:    sh %r3, 0x1, %rv
 ; CHECK-NEXT:    ld -4[%fp], %pc ! return
 ; CHECK-NEXT:    add %fp, 0x0, %sp
 ; CHECK-NEXT:    ld -8[%fp], %fp
@@ -249,9 +253,9 @@ define i32 @muli32_p28(i32 inreg %a) #0 {
 ; CHECK-NEXT:    st %fp, [--%sp]
 ; CHECK-NEXT:    add %sp, 0x8, %fp
 ; CHECK-NEXT:    sub %sp, 0x8, %sp
-; CHECK-NEXT:    sh %r6, 0x2, %r3
-; CHECK-NEXT:    sh %r6, 0x5, %r9
-; CHECK-NEXT:    sub %r9, %r3, %rv
+; CHECK-NEXT:    sh %r6, 0x3, %r3
+; CHECK-NEXT:    sub %r3, %r6, %r3
+; CHECK-NEXT:    sh %r3, 0x2, %rv
 ; CHECK-NEXT:    ld -4[%fp], %pc ! return
 ; CHECK-NEXT:    add %fp, 0x0, %sp
 ; CHECK-NEXT:    ld -8[%fp], %fp
@@ -265,9 +269,9 @@ define i32 @muli32_p30(i32 inreg %a) #0 {
 ; CHECK-NEXT:    st %fp, [--%sp]
 ; CHECK-NEXT:    add %sp, 0x8, %fp
 ; CHECK-NEXT:    sub %sp, 0x8, %sp
-; CHECK-NEXT:    sh %r6, 0x1, %r3
-; CHECK-NEXT:    sh %r6, 0x5, %r9
-; CHECK-NEXT:    sub %r9, %r3, %rv
+; CHECK-NEXT:    sh %r6, 0x5, %r3
+; CHECK-NEXT:    sub %r3, %r6, %r3
+; CHECK-NEXT:    sub %r3, %r6, %rv
 ; CHECK-NEXT:    ld -4[%fp], %pc ! return
 ; CHECK-NEXT:    add %fp, 0x0, %sp
 ; CHECK-NEXT:    ld -8[%fp], %fp
@@ -281,9 +285,9 @@ define i32 @muli32_p34(i32 inreg %a) #0 {
 ; CHECK-NEXT:    st %fp, [--%sp]
 ; CHECK-NEXT:    add %sp, 0x8, %fp
 ; CHECK-NEXT:    sub %sp, 0x8, %sp
-; CHECK-NEXT:    sh %r6, 0x1, %r3
-; CHECK-NEXT:    sh %r6, 0x5, %r9
-; CHECK-NEXT:    add %r9, %r3, %rv
+; CHECK-NEXT:    sh %r6, 0x4, %r3
+; CHECK-NEXT:    add %r3, %r6, %r3
+; CHECK-NEXT:    sh %r3, 0x1, %rv
 ; CHECK-NEXT:    ld -4[%fp], %pc ! return
 ; CHECK-NEXT:    add %fp, 0x0, %sp
 ; CHECK-NEXT:    ld -8[%fp], %fp
@@ -297,9 +301,9 @@ define i32 @muli32_p36(i32 inreg %a) #0 {
 ; CHECK-NEXT:    st %fp, [--%sp]
 ; CHECK-NEXT:    add %sp, 0x8, %fp
 ; CHECK-NEXT:    sub %sp, 0x8, %sp
-; CHECK-NEXT:    sh %r6, 0x2, %r3
-; CHECK-NEXT:    sh %r6, 0x5, %r9
-; CHECK-NEXT:    add %r9, %r3, %rv
+; CHECK-NEXT:    sh %r6, 0x3, %r3
+; CHECK-NEXT:    add %r3, %r6, %r3
+; CHECK-NEXT:    sh %r3, 0x2, %rv
 ; CHECK-NEXT:    ld -4[%fp], %pc ! return
 ; CHECK-NEXT:    add %fp, 0x0, %sp
 ; CHECK-NEXT:    ld -8[%fp], %fp
@@ -314,8 +318,8 @@ define i32 @muli32_p56(i32 inreg %a) #0 {
 ; CHECK-NEXT:    add %sp, 0x8, %fp
 ; CHECK-NEXT:    sub %sp, 0x8, %sp
 ; CHECK-NEXT:    sh %r6, 0x3, %r3
-; CHECK-NEXT:    sh %r6, 0x6, %r9
-; CHECK-NEXT:    sub %r9, %r3, %rv
+; CHECK-NEXT:    sub %r3, %r6, %r3
+; CHECK-NEXT:    sh %r3, 0x3, %rv
 ; CHECK-NEXT:    ld -4[%fp], %pc ! return
 ; CHECK-NEXT:    add %fp, 0x0, %sp
 ; CHECK-NEXT:    ld -8[%fp], %fp
@@ -329,9 +333,9 @@ define i32 @muli32_p60(i32 inreg %a) #0 {
 ; CHECK-NEXT:    st %fp, [--%sp]
 ; CHECK-NEXT:    add %sp, 0x8, %fp
 ; CHECK-NEXT:    sub %sp, 0x8, %sp
-; CHECK-NEXT:    sh %r6, 0x2, %r3
-; CHECK-NEXT:    sh %r6, 0x6, %r9
-; CHECK-NEXT:    sub %r9, %r3, %rv
+; CHECK-NEXT:    sh %r6, 0x4, %r3
+; CHECK-NEXT:    sub %r3, %r6, %r3
+; CHECK-NEXT:    sh %r3, 0x2, %rv
 ; CHECK-NEXT:    ld -4[%fp], %pc ! return
 ; CHECK-NEXT:    add %fp, 0x0, %sp
 ; CHECK-NEXT:    ld -8[%fp], %fp
@@ -345,9 +349,9 @@ define i32 @muli32_p62(i32 inreg %a) #0 {
 ; CHECK-NEXT:    st %fp, [--%sp]
 ; CHECK-NEXT:    add %sp, 0x8, %fp
 ; CHECK-NEXT:    sub %sp, 0x8, %sp
-; CHECK-NEXT:    sh %r6, 0x1, %r3
-; CHECK-NEXT:    sh %r6, 0x6, %r9
-; CHECK-NEXT:    sub %r9, %r3, %rv
+; CHECK-NEXT:    sh %r6, 0x6, %r3
+; CHECK-NEXT:    sub %r3, %r6, %r3
+; CHECK-NEXT:    sub %r3, %r6, %rv
 ; CHECK-NEXT:    ld -4[%fp], %pc ! return
 ; CHECK-NEXT:    add %fp, 0x0, %sp
 ; CHECK-NEXT:    ld -8[%fp], %fp
@@ -391,9 +395,9 @@ define i32 @muli32_p66(i32 inreg %a) #0 {
 ; CHECK-NEXT:    st %fp, [--%sp]
 ; CHECK-NEXT:    add %sp, 0x8, %fp
 ; CHECK-NEXT:    sub %sp, 0x8, %sp
-; CHECK-NEXT:    sh %r6, 0x1, %r3
-; CHECK-NEXT:    sh %r6, 0x6, %r9
-; CHECK-NEXT:    add %r9, %r3, %rv
+; CHECK-NEXT:    sh %r6, 0x5, %r3
+; CHECK-NEXT:    add %r3, %r6, %r3
+; CHECK-NEXT:    sh %r3, 0x1, %rv
 ; CHECK-NEXT:    ld -4[%fp], %pc ! return
 ; CHECK-NEXT:    add %fp, 0x0, %sp
 ; CHECK-NEXT:    ld -8[%fp], %fp
@@ -422,9 +426,9 @@ define i32 @muli32_m65(i32 inreg %a) #0 {
 ; CHECK-NEXT:    st %fp, [--%sp]
 ; CHECK-NEXT:    add %sp, 0x8, %fp
 ; CHECK-NEXT:    sub %sp, 0x8, %sp
-; CHECK-NEXT:    sh %r6, 0x6, %r3
-; CHECK-NEXT:    add %r6, %r3, %r3
-; CHECK-NEXT:    sub %r0, %r3, %rv
+; CHECK-NEXT:    sub %r0, %r6, %r3
+; CHECK-NEXT:    sh %r3, 0x6, %r3
+; CHECK-NEXT:    sub %r3, %r6, %rv
 ; CHECK-NEXT:    ld -4[%fp], %pc ! return
 ; CHECK-NEXT:    add %fp, 0x0, %sp
 ; CHECK-NEXT:    ld -8[%fp], %fp
@@ -438,9 +442,9 @@ define i32 @muli32_p384(i32 inreg %a) #0 {
 ; CHECK-NEXT:    st %fp, [--%sp]
 ; CHECK-NEXT:    add %sp, 0x8, %fp
 ; CHECK-NEXT:    sub %sp, 0x8, %sp
-; CHECK-NEXT:    sh %r6, 0x7, %r3
-; CHECK-NEXT:    sh %r6, 0x9, %r9
-; CHECK-NEXT:    sub %r9, %r3, %rv
+; CHECK-NEXT:    sh %r6, 0x1, %r3
+; CHECK-NEXT:    add %r3, %r6, %r3
+; CHECK-NEXT:    sh %r3, 0x7, %rv
 ; CHECK-NEXT:    ld -4[%fp], %pc ! return
 ; CHECK-NEXT:    add %fp, 0x0, %sp
 ; CHECK-NEXT:    ld -8[%fp], %fp
@@ -454,9 +458,9 @@ define i32 @muli32_p12288(i32 inreg %a) #0 {
 ; CHECK-NEXT:    st %fp, [--%sp]
 ; CHECK-NEXT:    add %sp, 0x8, %fp
 ; CHECK-NEXT:    sub %sp, 0x8, %sp
-; CHECK-NEXT:    sh %r6, 0xc, %r3
-; CHECK-NEXT:    sh %r6, 0xe, %r9
-; CHECK-NEXT:    sub %r9, %r3, %rv
+; CHECK-NEXT:    sh %r6, 0x1, %r3
+; CHECK-NEXT:    add %r3, %r6, %r3
+; CHECK-NEXT:    sh %r3, 0xc, %rv
 ; CHECK-NEXT:    ld -4[%fp], %pc ! return
 ; CHECK-NEXT:    add %fp, 0x0, %sp
 ; CHECK-NEXT:    ld -8[%fp], %fp
@@ -470,9 +474,9 @@ define i32 @muli32_p4352(i32 inreg %a) #0 {
 ; CHECK-NEXT:    st %fp, [--%sp]
 ; CHECK-NEXT:    add %sp, 0x8, %fp
 ; CHECK-NEXT:    sub %sp, 0x8, %sp
-; CHECK-NEXT:    sh %r6, 0x8, %r3
-; CHECK-NEXT:    sh %r6, 0xc, %r9
-; CHECK-NEXT:    add %r9, %r3, %rv
+; CHECK-NEXT:    sh %r6, 0x4, %r3
+; CHECK-NEXT:    add %r3, %r6, %r3
+; CHECK-NEXT:    sh %r3, 0x8, %rv
 ; CHECK-NEXT:    ld -4[%fp], %pc ! return
 ; CHECK-NEXT:    add %fp, 0x0, %sp
 ; CHECK-NEXT:    ld -8[%fp], %fp
@@ -486,9 +490,9 @@ define i32 @muli32_p3840(i32 inreg %a) #0 {
 ; CHECK-NEXT:    st %fp, [--%sp]
 ; CHECK-NEXT:    add %sp, 0x8, %fp
 ; CHECK-NEXT:    sub %sp, 0x8, %sp
-; CHECK-NEXT:    sh %r6, 0x8, %r3
-; CHECK-NEXT:    sh %r6, 0xc, %r9
-; CHECK-NEXT:    sub %r9, %r3, %rv
+; CHECK-NEXT:    sh %r6, 0x4, %r3
+; CHECK-NEXT:    sub %r3, %r6, %r3
+; CHECK-NEXT:    sh %r3, 0x8, %rv
 ; CHECK-NEXT:    ld -4[%fp], %pc ! return
 ; CHECK-NEXT:    add %fp, 0x0, %sp
 ; CHECK-NEXT:    ld -8[%fp], %fp
@@ -502,9 +506,9 @@ define i32 @muli32_m3840(i32 inreg %a) #0 {
 ; CHECK-NEXT:    st %fp, [--%sp]
 ; CHECK-NEXT:    add %sp, 0x8, %fp
 ; CHECK-NEXT:    sub %sp, 0x8, %sp
-; CHECK-NEXT:    sh %r6, 0xc, %r3
-; CHECK-NEXT:    sh %r6, 0x8, %r9
-; CHECK-NEXT:    sub %r9, %r3, %rv
+; CHECK-NEXT:    sh %r6, 0x4, %r3
+; CHECK-NEXT:    sub %r6, %r3, %r3
+; CHECK-NEXT:    sh %r3, 0x8, %rv
 ; CHECK-NEXT:    ld -4[%fp], %pc ! return
 ; CHECK-NEXT:    add %fp, 0x0, %sp
 ; CHECK-NEXT:    ld -8[%fp], %fp
@@ -518,10 +522,10 @@ define i32 @muli32_m4352(i32 inreg %a) #0 {
 ; CHECK-NEXT:    st %fp, [--%sp]
 ; CHECK-NEXT:    add %sp, 0x8, %fp
 ; CHECK-NEXT:    sub %sp, 0x8, %sp
-; CHECK-NEXT:    sh %r6, 0xc, %r3
-; CHECK-NEXT:    sh %r6, 0x8, %r9
-; CHECK-NEXT:    add %r9, %r3, %r3
-; CHECK-NEXT:    sub %r0, %r3, %rv
+; CHECK-NEXT:    sub %r0, %r6, %r3
+; CHECK-NEXT:    sh %r3, 0x4, %r3
+; CHECK-NEXT:    sub %r3, %r6, %r3
+; CHECK-NEXT:    sh %r3, 0x8, %rv
 ; CHECK-NEXT:    ld -4[%fp], %pc ! return
 ; CHECK-NEXT:    add %fp, 0x0, %sp
 ; CHECK-NEXT:    ld -8[%fp], %fp
diff --git a/llvm/test/CodeGen/Lanai/multiply.ll b/llvm/test/CodeGen/Lanai/multiply.ll
index dd6e70f28636b..38ef2701cc8c7 100644
--- a/llvm/test/CodeGen/Lanai/multiply.ll
+++ b/llvm/test/CodeGen/Lanai/multiply.ll
@@ -1,60 +1,124 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
 ; RUN: llc -mtriple=lanai < %s | FileCheck %s
 
 ; Test the in place lowering of mul i32.
 
 define i32 @f6(i32 inreg %a) #0 {
+; CHECK-LABEL: f6:
+; CHECK:       ! %bb.0: ! %entry
+; CHECK-NEXT:    st %fp, [--%sp]
+; CHECK-NEXT:    add %sp, 0x8, %fp
+; CHECK-NEXT:    sub %sp, 0x8, %sp
+; CHECK-NEXT:    sh %r6, 0x3, %r3
+; CHECK-NEXT:    sub %r3, %r6, %r3
+; CHECK-NEXT:    sub %r3, %r6, %rv
+; CHECK-NEXT:    ld -4[%fp], %pc ! return
+; CHECK-NEXT:    add %fp, 0x0, %sp
+; CHECK-NEXT:    ld -8[%fp], %fp
 entry:
   %mul = mul nsw i32 %a, 6
   ret i32 %mul
 }
-; CHECK: sh %r6, 0x1, %r{{[0-9]+}}
-; CHECK: sh %r6, 0x3, %r{{[0-9]+}}
-; CHECK: sub %r{{[0-9]+}}, %r{{[0-9]+}}, %rv
 
 define i32 @f7(i32 inreg %a) #0 {
+; CHECK-LABEL: f7:
+; CHECK:       ! %bb.0: ! %entry
+; CHECK-NEXT:    st %fp, [--%sp]
+; CHECK-NEXT:    add %sp, 0x8, %fp
+; CHECK-NEXT:    sub %sp, 0x8, %sp
+; CHECK-NEXT:    sh %r6, 0x3, %r3
+; CHECK-NEXT:    sub %r3, %r6, %rv
+; CHECK-NEXT:    ld -4[%fp], %pc ! return
+; CHECK-NEXT:    add %fp, 0x0, %sp
+; CHECK-NEXT:    ld -8[%fp], %fp
 entry:
   %mul = mul nsw i32 %a, 7
   ret i32 %mul
 }
-; CHECK: sh %r6, 0x3, %r{{[0-9]+}}
-; CHECK: sub %r{{[0-9]+}}, %r6, %rv
 
 define i32 @f8(i32 inreg %a) #0 {
+; CHECK-LABEL: f8:
+; CHECK:       ! %bb.0: ! %entry
+; CHECK-NEXT:    st %fp, [--%sp]
+; CHECK-NEXT:    add %sp, 0x8, %fp
+; CHECK-NEXT:    sub %sp, 0x8, %sp
+; CHECK-NEXT:    sh %r6, 0x3, %rv
+; CHECK-NEXT:    ld -4[%fp], %pc ! return
+; CHECK-NEXT:    add %fp, 0x0, %sp
+; CHECK-NEXT:    ld -8[%fp], %fp
 entry:
   %mul = shl nsw i32 %a, 3
   ret i32 %mul
 }
-; CHECK: sh %r6, 0x3, %rv
 
 define i32 @fm6(i32 inreg %a) #0 {
+; CHECK-LABEL: fm6:
+; CHECK:       ! %bb.0: ! %entry
+; CHECK-NEXT:    st %fp, [--%sp]
+; CHECK-NEXT:    add %sp, 0x8, %fp
+; CHECK-NEXT:    sub %sp, 0x8, %sp
+; CHECK-NEXT:    sh %r6, 0x2, %r3
+; CHECK-NEXT:    sub %r6, %r3, %r3
+; CHECK-NEXT:    sh %r3, 0x1, %rv
+; CHECK-NEXT:    ld -4[%fp], %pc ! return
+; CHECK-NEXT:    add %fp, 0x0, %sp
+; CHECK-NEXT:    ld -8[%fp], %fp
 entry:
   %mul = mul nsw i32 %a, -6
   ret i32 %mul
 }
-; CHECK: sh %r6, 0x3, %r{{[0-9]+}}
-; CHECK: sh %r6, 0x1, %r{{[0-9]+}}
-; CHECK: sub %r{{[0-9]+}}, %r{{[0-9]+}}, %rv
 
 define i32 @fm7(i32 inreg %a) #0 {
+; CHECK-LABEL: fm7:
+; CHECK:       ! %bb.0: ! %entry
+; CHECK-NEXT:    st %fp, [--%sp]
+; CHECK-NEXT:    add %sp, 0x8, %fp
+; CHECK-NEXT:    sub %sp, 0x8, %sp
+; CHECK-NEXT:    sh %r6, 0x3, %r3
+; CHECK-NEXT:    sub %r6, %r3, %rv
+; CHECK-NEXT:    ld -4[%fp], %pc ! return
+; CHECK-NEXT:    add %fp, 0x0, %sp
+; CHECK-NEXT:    ld -8[%fp], %fp
 entry:
   %mul = mul nsw i32 %a, -7
   ret i32 %mul
 }
-; CHECK: sh %r6, 0x3, %r{{[0-9]+}}
-; CHECK: sub %r6, %r{{[0-9]+}}, %rv
 
 define i32 @fm8(i32 inreg %a) #0 {
+; CHECK-LABEL: fm8:
+; CHECK:       ! %bb.0: ! %entry
+; CHECK-NEXT:    st %fp, [--%sp]
+; CHECK-NEXT:    add %sp, 0x8, %fp
+; CHECK-NEXT:    sub %sp, 0x8, %sp
+; CHECK-NEXT:    sh %r6, 0x3, %r3
+; CHECK-NEXT:    sub %r0, %r3, %rv
+; CHECK-NEXT:    ld -4[%fp], %pc ! return
+; CHECK-NEXT:    add %fp, 0x0, %sp
+; CHECK-NEXT:    ld -8[%fp], %fp
 entry:
   %mul = mul nsw i32 %a, -8
   ret i32 %mul
 }
-; CHECK: sh %r6, 0x3, %r{{[0-9]+}}
-; CHECK: sub %r{{[0-9]+}}, %r{{[0-9]+}}, %rv
 
 define i32 @h1(i32 inreg %a) #0 {
+; CHECK-LABEL: h1:
+; CHECK:       ! %bb.0: ! %entry
+; CHECK-NEXT:    st %fp, [--%sp]
+; CHECK-NEXT:    add %sp, 0x8, %fp
+; CHECK-NEXT:    sub %sp, 0x8, %sp
+; CHECK-NEXT:    sub %r0, %r6, %r3
+; CHECK-NEXT:    sh %r3, 0x10, %r3
+; CHECK-NEXT:    sub %r3, %r6, %r3
+; CHECK-NEXT:    sh %r3, 0x8, %r9
+; CHECK-NEXT:    add %r9, %r3, %r3
+; CHECK-NEXT:    sh %r3, 0x4, %r9
+; CHECK-NEXT:    add %r9, %r3, %r3
+; CHECK-NEXT:    sh %r3, 0x2, %r9
+; CHECK-NEXT:    add %r9, %r3, %rv
+; CHECK-NEXT:    ld -4[%fp], %pc ! return
+; CHECK-NEXT:    add %fp, 0x0, %sp
+; CHECK-NEXT:    ld -8[%fp], %fp
 entry:
   %mul = mul i32 %a, -1431655765
   ret i32 %mul
 }
-; CHECK: h1
-; CHECK: mulsi3
diff --git a/llvm/test/CodeGen/MSP430/constant_multiply.ll b/llvm/test/CodeGen/MSP430/constant_multiply.ll
index 72d7c3311b8a2..edbb0436a5e11 100644
--- a/llvm/test/CodeGen/MSP430/constant_multiply.ll
+++ b/llvm/test/CodeGen/MSP430/constant_multiply.ll
@@ -15,8 +15,9 @@ define i16 @mul_by_2(i16 %a) nounwind {
 define i16 @mul_by_3(i16 %a) nounwind {
 ; CHECK-LABEL: mul_by_3:
 ; CHECK:       ; %bb.0:
-; CHECK-NEXT:    mov #3, r13
-; CHECK-NEXT:    call #__mspabi_mpyi
+; CHECK-NEXT:    mov r12, r13
+; CHECK-NEXT:    add r13, r13
+; CHECK-NEXT:    add r13, r12
 ; CHECK-NEXT:    ret
   %1 = mul i16 %a, 3
   ret i16 %1
@@ -25,8 +26,10 @@ define i16 @mul_by_3(i16 %a) nounwind {
 define i16 @mul_by_5(i16 %a) nounwind {
 ; CHECK-LABEL: mul_by_5:
 ; CHECK:       ; %bb.0:
-; CHECK-NEXT:    mov #5, r13
-; CHECK-NEXT:    call #__mspabi_mpyi
+; CHECK-NEXT:    mov r12, r13
+; CHECK-NEXT:    add r13, r13
+; CHECK-NEXT:    add r13, r13
+; CHECK-NEXT:    add r13, r12
 ; CHECK-NEXT:    ret
   %1 = mul i16 %a, 5
   ret i16 %1
@@ -35,8 +38,13 @@ define i16 @mul_by_5(i16 %a) nounwind {
 define i16 @mul_by_6(i16 %a) nounwind {
 ; CHECK-LABEL: mul_by_6:
 ; CHECK:       ; %bb.0:
-; CHECK-NEXT:    mov #6, r13
-; CHECK-NEXT:    call #__mspabi_mpyi
+; CHECK-NEXT:    mov r12, r13
+; CHECK-NEXT:    add r13, r13
+; CHECK-NEXT:    add r13, r13
+; CHECK-NEXT:    add r13, r13
+; CHECK-NEXT:    sub r12, r13
+; CHECK-NEXT:    sub r12, r13
+; CHECK-NEXT:    mov r13, r12
 ; CHECK-NEXT:    ret
   %1 = mul i16 %a, 6
   ret i16 %1
@@ -45,8 +53,12 @@ define i16 @mul_by_6(i16 %a) nounwind {
 define i16 @mul_by_7(i16 %a) nounwind {
 ; CHECK-LABEL: mul_by_7:
 ; CHECK:       ; %bb.0:
-; CHECK-NEXT:    mov #7, r13
-; CHECK-NEXT:    call #__mspabi_mpyi
+; CHECK-NEXT:    mov r12, r13
+; CHECK-NEXT:    add r13, r13
+; CHECK-NEXT:    add r13, r13
+; CHECK-NEXT:    add r13, r13
+; CHECK-NEXT:    sub r12, r13
+; CHECK-NEXT:    mov r13, r12
 ; CHECK-NEXT:    ret
   %1 = mul i16 %a, 7
   ret i16 %1
@@ -66,8 +78,11 @@ define i16 @mul_by_8(i16 %a) nounwind {
 define i16 @mul_by_9(i16 %a) nounwind {
 ; CHECK-LABEL: mul_by_9:
 ; CHECK:       ; %bb.0:
-; CHECK-NEXT:    mov #9, r13
-; CHECK-NEXT:    call #__mspabi_mpyi
+; CHECK-NEXT:    mov r12, r13
+; CHECK-NEXT:    add r13, r13
+; CHECK-NEXT:    add r13, r13
+; CHECK-NEXT:    add r13, r13
+; CHECK-NEXT:    add r13, r12
 ; CHECK-NEXT:    ret
   %1 = mul i16 %a, 9
   ret i16 %1
@@ -76,8 +91,11 @@ define i16 @mul_by_9(i16 %a) nounwind {
 define i16 @mul_by_10(i16 %a) nounwind {
 ; CHECK-LABEL: mul_by_10:
 ; CHECK:       ; %bb.0:
-; CHECK-NEXT:    mov #10, r13
-; CHECK-NEXT:    call #__mspabi_mpyi
+; CHECK-NEXT:    mov r12, r13
+; CHECK-NEXT:    add r13, r13
+; CHECK-NEXT:    add r13, r13
+; CHECK-NEXT:    add r13, r12
+; CHECK-NEXT:    add r12, r12
 ; CHECK-NEXT:    ret
   %1 = mul i16 %a, 10
   ret i16 %1
@@ -86,8 +104,13 @@ define i16 @mul_by_10(i16 %a) nounwind {
 define i16 @mul_by_15(i16 %a) nounwind {
 ; CHECK-LABEL: mul_by_15:
 ; CHECK:       ; %bb.0:
-; CHECK-NEXT:    mov #15, r13
-; CHECK-NEXT:    call #__mspabi_mpyi
+; CHECK-NEXT:    mov r12, r13
+; CHECK-NEXT:    add r13, r13
+; CHECK-NEXT:    add r13, r13
+; CHECK-NEXT:    add r13, r13
+; CHECK-NEXT:    add r13, r13
+; CHECK-NEXT:    sub r12, r13
+; CHECK-NEXT:    mov r13, r12
 ; CHECK-NEXT:    ret
   %1 = mul i16 %a, 15
   ret i16 %1
@@ -108,8 +131,12 @@ define i16 @mul_by_16(i16 %a) nounwind {
 define i16 @mul_by_17(i16 %a) nounwind {
 ; CHECK-LABEL: mul_by_17:
 ; CHECK:       ; %bb.0:
-; CHECK-NEXT:    mov #17, r13
-; CHECK-NEXT:    call #__mspabi_mpyi
+; CHECK-NEXT:    mov r12, r13
+; CHECK-NEXT:    add r13, r13
+; CHECK-NEXT:    add r13, r13
+; CHECK-NEXT:    add r13, r13
+; CHECK-NEXT:    add r13, r13
+; CHECK-NEXT:    add r13, r12
 ; CHECK-NEXT:    ret
   %1 = mul i16 %a, 17
   ret i16 %1
@@ -118,8 +145,10 @@ define i16 @mul_by_17(i16 %a) nounwind {
 define i16 @mul_by_neg3(i16 %a) nounwind {
 ; CHECK-LABEL: mul_by_neg3:
 ; CHECK:       ; %bb.0:
-; CHECK-NEXT:    mov #-3, r13
-; CHECK-NEXT:    call #__mspabi_mpyi
+; CHECK-NEXT:    mov r12, r13
+; CHECK-NEXT:    add r13, r13
+; CHECK-NEXT:    add r13, r13
+; CHECK-NEXT:    sub r13, r12
 ; CHECK-NEXT:    ret
   %1 = mul i16 %a, -3
   ret i16 %1
@@ -128,8 +157,11 @@ define i16 @mul_by_neg3(i16 %a) nounwind {
 define i16 @mul_by_neg7(i16 %a) nounwind {
 ; CHECK-LABEL: mul_by_neg7:
 ; CHECK:       ; %bb.0:
-; CHECK-NEXT:    mov #-7, r13
-; CHECK-NEXT:    call #__mspabi_mpyi
+; CHECK-NEXT:    mov r12, r13
+; CHECK-NEXT:    add r13, r13
+; CHECK-NEXT:    add r13, r13
+; CHECK-NEXT:    add r13, r13
+; CHECK-NEXT:    sub r13, r12
 ; CHECK-NEXT:    ret
   %1 = mul i16 %a, -7
   ret i16 %1
@@ -138,8 +170,13 @@ define i16 @mul_by_neg7(i16 %a) nounwind {
 define i16 @mul_by_neg9(i16 %a) nounwind {
 ; CHECK-LABEL: mul_by_neg9:
 ; CHECK:       ; %bb.0:
-; CHECK-NEXT:    mov #-9, r13
-; CHECK-NEXT:    call #__mspabi_mpyi
+; CHECK-NEXT:    clr r13
+; CHECK-NEXT:    sub r12, r13
+; CHECK-NEXT:    add r13, r13
+; CHECK-NEXT:    add r13, r13
+; CHECK-NEXT:    add r13, r13
+; CHECK-NEXT:    sub r12, r13
+; CHECK-NEXT:    mov r13, r12
 ; CHECK-NEXT:    ret
   %1 = mul i16 %a, -9
   ret i16 %1
@@ -148,8 +185,20 @@ define i16 @mul_by_neg9(i16 %a) nounwind {
 define i16 @mul_by_12345(i16 %a) nounwind {
 ; CHECK-LABEL: mul_by_12345:
 ; CHECK:       ; %bb.0:
-; CHECK-NEXT:    mov #12345, r13
-; CHECK-NEXT:    call #__mspabi_mpyi
+; CHECK-NEXT:    mov r12, r13
+; CHECK-NEXT:    mov.b r13, r13
+; CHECK-NEXT:    swpb r13
+; CHECK-NEXT:    add r12, r13
+; CHECK-NEXT:    add r13, r13
+; CHECK-NEXT:    add r13, r13
+; CHECK-NEXT:    add r12, r13
+; CHECK-NEXT:    add r13, r13
+; CHECK-NEXT:    add r13, r13
+; CHECK-NEXT:    sub r12, r13
+; CHECK-NEXT:    mov r13, r12
+; CHECK-NEXT:    add r12, r12
+; CHECK-NEXT:    add r12, r12
+; CHECK-NEXT:    sub r13, r12
 ; CHECK-NEXT:    ret
   %1 = mul i16 %a, 12345
   ret i16 %1
diff --git a/llvm/test/CodeGen/RISCV/ctlz-cttz-ctpop.ll b/llvm/test/CodeGen/RISCV/ctlz-cttz-ctpop.ll
index 7f089782d87e0..dc1c4d66edecd 100644
--- a/llvm/test/CodeGen/RISCV/ctlz-cttz-ctpop.ll
+++ b/llvm/test/CodeGen/RISCV/ctlz-cttz-ctpop.ll
@@ -251,26 +251,18 @@ define i32 @test_cttz_i32(i32 %a) nounwind {
 ; RV64I-NEXT:  # %bb.1: # %cond.false
 ; RV64I-NEXT:    neg a1, a0
 ; RV64I-NEXT:    and a0, a0, a1
-; RV64I-NEXT:    slli a1, a0, 6
-; RV64I-NEXT:    slli a2, a0, 8
-; RV64I-NEXT:    slli a3, a0, 10
-; RV64I-NEXT:    slli a4, a0, 12
-; RV64I-NEXT:    add a1, a1, a2
-; RV64I-NEXT:    slli a2, a0, 16
-; RV64I-NEXT:    sub a3, a3, a4
-; RV64I-NEXT:    slli a4, a0, 18
-; RV64I-NEXT:    sub a2, a2, a4
-; RV64I-NEXT:    slli a4, a0, 4
-; RV64I-NEXT:    sub a4, a0, a4
-; RV64I-NEXT:    add a1, a4, a1
-; RV64I-NEXT:    slli a4, a0, 14
-; RV64I-NEXT:    sub a3, a3, a4
-; RV64I-NEXT:    slli a4, a0, 23
-; RV64I-NEXT:    sub a2, a2, a4
-; RV64I-NEXT:    slli a0, a0, 27
-; RV64I-NEXT:    add a1, a1, a3
+; RV64I-NEXT:    slli a1, a0, 9
+; RV64I-NEXT:    sub a1, a1, a0
+; RV64I-NEXT:    slli a1, a1, 3
+; RV64I-NEXT:    add a1, a1, a0
+; RV64I-NEXT:    slli a1, a1, 5
+; RV64I-NEXT:    sub a1, a1, a0
+; RV64I-NEXT:    slli a1, a1, 2
+; RV64I-NEXT:    add a1, a1, a0
+; RV64I-NEXT:    slli a2, a1, 4
+; RV64I-NEXT:    sub a2, a2, a1
+; RV64I-NEXT:    slli a2, a2, 4
 ; RV64I-NEXT:    add a0, a2, a0
-; RV64I-NEXT:    add a0, a1, a0
 ; RV64I-NEXT:    srliw a0, a0, 27
 ; RV64I-NEXT:    lui a1, %hi(.LCPI2_0)
 ; RV64I-NEXT:    addi a1, a1, %lo(.LCPI2_0)
@@ -731,26 +723,18 @@ define i32 @test_cttz_i32_zero_undef(i32 %a) nounwind {
 ; RV64I:       # %bb.0:
 ; RV64I-NEXT:    neg a1, a0
 ; RV64I-NEXT:    and a0, a0, a1
-; RV64I-NEXT:    slli a1, a0, 6
-; RV64I-NEXT:    slli a2, a0, 8
-; RV64I-NEXT:    slli a3, a0, 10
-; RV64I-NEXT:    slli a4, a0, 12
-; RV64I-NEXT:    add a1, a1, a2
-; RV64I-NEXT:    slli a2, a0, 16
-; RV64I-NEXT:    sub a3, a3, a4
-; RV64I-NEXT:    slli a4, a0, 18
-; RV64I-NEXT:    sub a2, a2, a4
-; RV64I-NEXT:    slli a4, a0, 4
-; RV64I-NEXT:    sub a4, a0, a4
-; RV64I-NEXT:    add a1, a4, a1
-; RV64I-NEXT:    slli a4, a0, 14
-; RV64I-NEXT:    sub a3, a3, a4
-; RV64I-NEXT:    slli a4, a0, 23
-; RV64I-NEXT:    sub a2, a2, a4
-; RV64I-NEXT:    slli a0, a0, 27
-; RV64I-NEXT:    add a1, a1, a3
+; RV64I-NEXT:    slli a1, a0, 9
+; RV64I-NEXT:    sub a1, a1, a0
+; RV64I-NEXT:    slli a1, a1, 3
+; RV64I-NEXT:    add a1, a1, a0
+; RV64I-NEXT:    slli a1, a1, 5
+; RV64I-NEXT:    sub a1, a1, a0
+; RV64I-NEXT:    slli a1, a1, 2
+; RV64I-NEXT:    add a1, a1, a0
+; RV64I-NEXT:    slli a2, a1, 4
+; RV64I-NEXT:    sub a2, a2, a1
+; RV64I-NEXT:    slli a2, a2, 4
 ; RV64I-NEXT:    add a0, a2, a0
-; RV64I-NEXT:    add a0, a1, a0
 ; RV64I-NEXT:    srliw a0, a0, 27
 ; RV64I-NEXT:    lui a1, %hi(.LCPI6_0)
 ; RV64I-NEXT:    addi a1, a1, %lo(.LCPI6_0)
diff --git a/llvm/test/CodeGen/RISCV/ctz_zero_return_test.ll b/llvm/test/CodeGen/RISCV/ctz_zero_return_test.ll
index e92ff1a1b1b40..36b878ff09d25 100644
--- a/llvm/test/CodeGen/RISCV/ctz_zero_return_test.ll
+++ b/llvm/test/CodeGen/RISCV/ctz_zero_return_test.ll
@@ -162,26 +162,18 @@ define i64 @ctz_dereferencing_pointer_zext(ptr %b) nounwind {
 ; RV64I-NEXT:    lw a0, 0(a0)
 ; RV64I-NEXT:    neg a1, a0
 ; RV64I-NEXT:    and a1, a0, a1
-; RV64I-NEXT:    slli a2, a1, 6
-; RV64I-NEXT:    slli a3, a1, 8
-; RV64I-NEXT:    slli a4, a1, 10
-; RV64I-NEXT:    slli a5, a1, 12
-; RV64I-NEXT:    add a2, a2, a3
-; RV64I-NEXT:    slli a3, a1, 16
-; RV64I-NEXT:    sub a4, a4, a5
-; RV64I-NEXT:    slli a5, a1, 18
-; RV64I-NEXT:    sub a3, a3, a5
-; RV64I-NEXT:    slli a5, a1, 4
-; RV64I-NEXT:    sub a5, a1, a5
-; RV64I-NEXT:    add a2, a5, a2
-; RV64I-NEXT:    slli a5, a1, 14
-; RV64I-NEXT:    sub a4, a4, a5
-; RV64I-NEXT:    slli a5, a1, 23
-; RV64I-NEXT:    sub a3, a3, a5
-; RV64I-NEXT:    slli a1, a1, 27
-; RV64I-NEXT:    add a2, a2, a4
+; RV64I-NEXT:    slli a2, a1, 9
+; RV64I-NEXT:    sub a2, a2, a1
+; RV64I-NEXT:    slli a2, a2, 3
+; RV64I-NEXT:    add a2, a2, a1
+; RV64I-NEXT:    slli a2, a2, 5
+; RV64I-NEXT:    sub a2, a2, a1
+; RV64I-NEXT:    slli a2, a2, 2
+; RV64I-NEXT:    add a2, a2, a1
+; RV64I-NEXT:    slli a3, a2, 4
+; RV64I-NEXT:    sub a3, a3, a2
+; RV64I-NEXT:    slli a3, a3, 4
 ; RV64I-NEXT:    add a1, a3, a1
-; RV64I-NEXT:    add a1, a2, a1
 ; RV64I-NEXT:    srliw a1, a1, 27
 ; RV64I-NEXT:    lui a2, %hi(.LCPI1_0)
 ; RV64I-NEXT:    addi a2, a2, %lo(.LCPI1_0)
@@ -244,26 +236,18 @@ define signext i32 @ctz1(i32 signext %x) nounwind {
 ; RV64I:       # %bb.0: # %entry
 ; RV64I-NEXT:    neg a1, a0
 ; RV64I-NEXT:    and a1, a0, a1
-; RV64I-NEXT:    slli a2, a1, 6
-; RV64I-NEXT:    slli a3, a1, 8
-; RV64I-NEXT:    slli a4, a1, 10
-; RV64I-NEXT:    slli a5, a1, 12
-; RV64I-NEXT:    add a2, a2, a3
-; RV64I-NEXT:    slli a3, a1, 16
-; RV64I-NEXT:    sub a4, a4, a5
-; RV64I-NEXT:    slli a5, a1, 18
-; RV64I-NEXT:    sub a3, a3, a5
-; RV64I-NEXT:    slli a5, a1, 4
-; RV64I-NEXT:    sub a5, a1, a5
-; RV64I-NEXT:    add a2, a5, a2
-; RV64I-NEXT:    slli a5, a1, 14
-; RV64I-NEXT:    sub a4, a4, a5
-; RV64I-NEXT:    slli a5, a1, 23
-; RV64I-NEXT:    sub a3, a3, a5
-; RV64I-NEXT:    slli a1, a1, 27
-; RV64I-NEXT:    add a2, a2, a4
+; RV64I-NEXT:    slli a2, a1, 9
+; RV64I-NEXT:    sub a2, a2, a1
+; RV64I-NEXT:    slli a2, a2, 3
+; RV64I-NEXT:    add a2, a2, a1
+; RV64I-NEXT:    slli a2, a2, 5
+; RV64I-NEXT:    sub a2, a2, a1
+; RV64I-NEXT:    slli a2, a2, 2
+; RV64I-NEXT:    add a2, a2, a1
+; RV64I-NEXT:    slli a3, a2, 4
+; RV64I-NEXT:    sub a3, a3, a2
+; RV64I-NEXT:    slli a3, a3, 4
 ; RV64I-NEXT:    add a1, a3, a1
-; RV64I-NEXT:    add a1, a2, a1
 ; RV64I-NEXT:    srliw a1, a1, 27
 ; RV64I-NEXT:    lui a2, %hi(.LCPI2_0)
 ; RV64I-NEXT:    addi a2, a2, %lo(.LCPI2_0)
@@ -324,26 +308,18 @@ define signext i32 @ctz1_flipped(i32 signext %x) nounwind {
 ; RV64I:       # %bb.0: # %entry
 ; RV64I-NEXT:    neg a1, a0
 ; RV64I-NEXT:    and a1, a0, a1
-; RV64I-NEXT:    slli a2, a1, 6
-; RV64I-NEXT:    slli a3, a1, 8
-; RV64I-NEXT:    slli a4, a1, 10
-; RV64I-NEXT:    slli a5, a1, 12
-; RV64I-NEXT:    add a2, a2, a3
-; RV64I-NEXT:    slli a3, a1, 16
-; RV64I-NEXT:    sub a4, a4, a5
-; RV64I-NEXT:    slli a5, a1, 18
-; RV64I-NEXT:    sub a3, a3, a5
-; RV64I-NEXT:    slli a5, a1, 4
-; RV64I-NEXT:    sub a5, a1, a5
-; RV64I-NEXT:    add a2, a5, a2
-; RV64I-NEXT:    slli a5, a1, 14
-; RV64I-NEXT:    sub a4, a4, a5
-; RV64I-NEXT:    slli a5, a1, 23
-; RV64I-NEXT:    sub a3, a3, a5
-; RV64I-NEXT:    slli a1, a1, 27
-; RV64I-NEXT:    add a2, a2, a4
+; RV64I-NEXT:    slli a2, a1, 9
+; RV64I-NEXT:    sub a2, a2, a1
+; RV64I-NEXT:    slli a2, a2, 3
+; RV64I-NEXT:    add a2, a2, a1
+; RV64I-NEXT:    slli a2, a2, 5
+; RV64I-NEXT:    sub a2, a2, a1
+; RV64I-NEXT:    slli a2, a2, 2
+; RV64I-NEXT:    add a2, a2, a1
+; RV64I-NEXT:    slli a3, a2, 4
+; RV64I-NEXT:    sub a3, a3, a2
+; RV64I-NEXT:    slli a3, a3, 4
 ; RV64I-NEXT:    add a1, a3, a1
-; RV64I-NEXT:    add a1, a2, a1
 ; RV64I-NEXT:    srliw a1, a1, 27
 ; RV64I-NEXT:    lui a2, %hi(.LCPI3_0)
 ; RV64I-NEXT:    addi a2, a2, %lo(.LCPI3_0)
@@ -402,26 +378,18 @@ define signext i32 @ctz2(i32 signext %x) nounwind {
 ; RV64I-NEXT:  # %bb.1: # %cond.false
 ; RV64I-NEXT:    neg a1, a0
 ; RV64I-NEXT:    and a0, a0, a1
-; RV64I-NEXT:    slli a1, a0, 6
-; RV64I-NEXT:    slli a2, a0, 8
-; RV64I-NEXT:    slli a3, a0, 10
-; RV64I-NEXT:    slli a4, a0, 12
-; RV64I-NEXT:    add a1, a1, a2
-; RV64I-NEXT:    slli a2, a0, 16
-; RV64I-NEXT:    sub a3, a3, a4
-; RV64I-NEXT:    slli a4, a0, 18
-; RV64I-NEXT:    sub a2, a2, a4
-; RV64I-NEXT:    slli a4, a0, 4
-; RV64I-NEXT:    sub a4, a0, a4
-; RV64I-NEXT:    add a1, a4, a1
-; RV64I-NEXT:    slli a4, a0, 14
-; RV64I-NEXT:    sub a3, a3, a4
-; RV64I-NEXT:    slli a4, a0, 23
-; RV64I-NEXT:    sub a2, a2, a4
-; RV64I-NEXT:    slli a0, a0, 27
-; RV64I-NEXT:    add a1, a1, a3
+; RV64I-NEXT:    slli a1, a0, 9
+; RV64I-NEXT:    sub a1, a1, a0
+; RV64I-NEXT:    slli a1, a1, 3
+; RV64I-NEXT:    add a1, a1, a0
+; RV64I-NEXT:    slli a1, a1, 5
+; RV64I-NEXT:    sub a1, a1, a0
+; RV64I-NEXT:    slli a1, a1, 2
+; RV64I-NEXT:    add a1, a1, a0
+; RV64I-NEXT:    slli a2, a1, 4
+; RV64I-NEXT:    sub a2, a2, a1
+; RV64I-NEXT:    slli a2, a2, 4
 ; RV64I-NEXT:    add a0, a2, a0
-; RV64I-NEXT:    add a0, a1, a0
 ; RV64I-NEXT:    srliw a0, a0, 27
 ; RV64I-NEXT:    lui a1, %hi(.LCPI4_0)
 ; RV64I-NEXT:    addi a1, a1, %lo(.LCPI4_0)
@@ -477,26 +445,18 @@ define signext i32 @ctz3(i32 signext %x) nounwind {
 ; RV64I-NEXT:  # %bb.1: # %cond.false
 ; RV64I-NEXT:    neg a1, a0
 ; RV64I-NEXT:    and a0, a0, a1
-; RV64I-NEXT:    slli a1, a0, 6
-; RV64I-NEXT:    slli a2, a0, 8
-; RV64I-NEXT:    slli a3, a0, 10
-; RV64I-NEXT:    slli a4, a0, 12
-; RV64I-NEXT:    add a1, a1, a2
-; RV64I-NEXT:    slli a2, a0, 16
-; RV64I-NEXT:    sub a3, a3, a4
-; RV64I-NEXT:    slli a4, a0, 18
-; RV64I-NEXT:    sub a2, a2, a4
-; RV64I-NEXT:    slli a4, a0, 4
-; RV64I-NEXT:    sub a4, a0, a4
-; RV64I-NEXT:    add a1, a4, a1
-; RV64I-NEXT:    slli a4, a0, 14
-; RV64I-NEXT:    sub a3, a3, a4
-; RV64I-NEXT:    slli a4, a0, 23
-; RV64I-NEXT:    sub a2, a2, a4
-; RV64I-NEXT:    slli a0, a0, 27
-; RV64I-NEXT:    add a1, a1, a3
+; RV64I-NEXT:    slli a1, a0, 9
+; RV64I-NEXT:    sub a1, a1, a0
+; RV64I-NEXT:    slli a1, a1, 3
+; RV64I-NEXT:    add a1, a1, a0
+; RV64I-NEXT:    slli a1, a1, 5
+; RV64I-NEXT:    sub a1, a1, a0
+; RV64I-NEXT:    slli a1, a1, 2
+; RV64I-NEXT:    add a1, a1, a0
+; RV64I-NEXT:    slli a2, a1, 4
+; RV64I-NEXT:    sub a2, a2, a1
+; RV64I-NEXT:    slli a2, a2, 4
 ; RV64I-NEXT:    add a0, a2, a0
-; RV64I-NEXT:    add a0, a1, a0
 ; RV64I-NEXT:    srliw a0, a0, 27
 ; RV64I-NEXT:    lui a1, %hi(.LCPI5_0)
 ; RV64I-NEXT:    addi a1, a1, %lo(.LCPI5_0)
@@ -802,26 +762,18 @@ define signext i32 @ctz5(i32 signext %x) nounwind {
 ; RV64I:       # %bb.0: # %entry
 ; RV64I-NEXT:    neg a1, a0
 ; RV64I-NEXT:    and a1, a0, a1
-; RV64I-NEXT:    slli a2, a1, 6
-; RV64I-NEXT:    slli a3, a1, 8
-; RV64I-NEXT:    slli a4, a1, 10
-; RV64I-NEXT:    slli a5, a1, 12
-; RV64I-NEXT:    add a2, a2, a3
-; RV64I-NEXT:    slli a3, a1, 16
-; RV64I-NEXT:    sub a4, a4, a5
-; RV64I-NEXT:    slli a5, a1, 18
-; RV64I-NEXT:    sub a3, a3, a5
-; RV64I-NEXT:    slli a5, a1, 4
-; RV64I-NEXT:    sub a5, a1, a5
-; RV64I-NEXT:    add a2, a5, a2
-; RV64I-NEXT:    slli a5, a1, 14
-; RV64I-NEXT:    sub a4, a4, a5
-; RV64I-NEXT:    slli a5, a1, 23
-; RV64I-NEXT:    sub a3, a3, a5
-; RV64I-NEXT:    slli a1, a1, 27
-; RV64I-NEXT:    add a2, a2, a4
+; RV64I-NEXT:    slli a2, a1, 9
+; RV64I-NEXT:    sub a2, a2, a1
+; RV64I-NEXT:    slli a2, a2, 3
+; RV64I-NEXT:    add a2, a2, a1
+; RV64I-NEXT:    slli a2, a2, 5
+; RV64I-NEXT:    sub a2, a2, a1
+; RV64I-NEXT:    slli a2, a2, 2
+; RV64I-NEXT:    add a2, a2, a1
+; RV64I-NEXT:    slli a3, a2, 4
+; RV64I-NEXT:    sub a3, a3, a2
+; RV64I-NEXT:    slli a3, a3, 4
 ; RV64I-NEXT:    add a1, a3, a1
-; RV64I-NEXT:    add a1, a2, a1
 ; RV64I-NEXT:    srliw a1, a1, 27
 ; RV64I-NEXT:    lui a2, %hi(.LCPI8_0)
 ; RV64I-NEXT:    addi a2, a2, %lo(.LCPI8_0)
@@ -882,26 +834,18 @@ define signext i32 @ctz6(i32 signext %x) nounwind {
 ; RV64I:       # %bb.0: # %entry
 ; RV64I-NEXT:    neg a1, a0
 ; RV64I-NEXT:    and a1, a0, a1
-; RV64I-NEXT:    slli a2, a1, 6
-; RV64I-NEXT:    slli a3, a1, 8
-; RV64I-NEXT:    slli a4, a1, 10
-; RV64I-NEXT:    slli a5, a1, 12
-; RV64I-NEXT:    add a2, a2, a3
-; RV64I-NEXT:    slli a3, a1, 16
-; RV64I-NEXT:    sub a4, a4, a5
-; RV64I-NEXT:    slli a5, a1, 18
-; RV64I-NEXT:    sub a3, a3, a5
-; RV64I-NEXT:    slli a5, a1, 4
-; RV64I-NEXT:    sub a5, a1, a5
-; RV64I-NEXT:    add a2, a5, a2
-; RV64I-NEXT:    slli a5, a1, 14
-; RV64I-NEXT:    sub a4, a4, a5
-; RV64I-NEXT:    slli a5, a1, 23
-; RV64I-NEXT:    sub a3, a3, a5
-; RV64I-NEXT:    slli a1, a1, 27
-; RV64I-NEXT:    add a2, a2, a4
+; RV64I-NEXT:    slli a2, a1, 9
+; RV64I-NEXT:    sub a2, a2, a1
+; RV64I-NEXT:    slli a2, a2, 3
+; RV64I-NEXT:    add a2, a2, a1
+; RV64I-NEXT:    slli a2, a2, 5
+; RV64I-NEXT:    sub a2, a2, a1
+; RV64I-NEXT:    slli a2, a2, 2
+; RV64I-NEXT:    add a2, a2, a1
+; RV64I-NEXT:    slli a3, a2, 4
+; RV64I-NEXT:    sub a3, a3, a2
+; RV64I-NEXT:    slli a3, a3, 4
 ; RV64I-NEXT:    add a1, a3, a1
-; RV64I-NEXT:    add a1, a2, a1
 ; RV64I-NEXT:    srliw a1, a1, 27
 ; RV64I-NEXT:    lui a2, %hi(.LCPI9_0)
 ; RV64I-NEXT:    addi a2, a2, %lo(.LCPI9_0)
@@ -969,26 +913,18 @@ define signext i32 @globalVar() nounwind {
 ; RV64I-NEXT:    lw a0, %lo(global_x)(a0)
 ; RV64I-NEXT:    neg a1, a0
 ; RV64I-NEXT:    and a1, a0, a1
-; RV64I-NEXT:    slli a2, a1, 6
-; RV64I-NEXT:    slli a3, a1, 8
-; RV64I-NEXT:    slli a4, a1, 10
-; RV64I-NEXT:    slli a5, a1, 12
-; RV64I-NEXT:    add a2, a2, a3
-; RV64I-NEXT:    slli a3, a1, 16
-; RV64I-NEXT:    sub a4, a4, a5
-; RV64I-NEXT:    slli a5, a1, 18
-; RV64I-NEXT:    sub a3, a3, a5
-; RV64I-NEXT:    slli a5, a1, 4
-; RV64I-NEXT:    sub a5, a1, a5
-; RV64I-NEXT:    add a2, a5, a2
-; RV64I-NEXT:    slli a5, a1, 14
-; RV64I-NEXT:    sub a4, a4, a5
-; RV64I-NEXT:    slli a5, a1, 23
-; RV64I-NEXT:    sub a3, a3, a5
-; RV64I-NEXT:    slli a1, a1, 27
-; RV64I-NEXT:    add a2, a2, a4
+; RV64I-NEXT:    slli a2, a1, 9
+; RV64I-NEXT:    sub a2, a2, a1
+; RV64I-NEXT:    slli a2, a2, 3
+; RV64I-NEXT:    add a2, a2, a1
+; RV64I-NEXT:    slli a2, a2, 5
+; RV64I-NEXT:    sub a2, a2, a1
+; RV64I-NEXT:    slli a2, a2, 2
+; RV64I-NEXT:    add a2, a2, a1
+; RV64I-NEXT:    slli a3, a2, 4
+; RV64I-NEXT:    sub a3, a3, a2
+; RV64I-NEXT:    slli a3, a3, 4
 ; RV64I-NEXT:    add a1, a3, a1
-; RV64I-NEXT:    add a1, a2, a1
 ; RV64I-NEXT:    srliw a1, a1, 27
 ; RV64I-NEXT:    lui a2, %hi(.LCPI10_0)
 ; RV64I-NEXT:    addi a2, a2, %lo(.LCPI10_0)
diff --git a/llvm/test/CodeGen/RISCV/mul-expand.ll b/llvm/test/CodeGen/RISCV/mul-expand.ll
index a75a7355fa407..8b8d33c676ea0 100644
--- a/llvm/test/CodeGen/RISCV/mul-expand.ll
+++ b/llvm/test/CodeGen/RISCV/mul-expand.ll
@@ -7,30 +7,22 @@
 define i32 @muli32_0x555(i32 %a) nounwind {
 ; RV32I-LABEL: muli32_0x555:
 ; RV32I:       # %bb.0:
-; RV32I-NEXT:    slli a1, a0, 2
-; RV32I-NEXT:    slli a2, a0, 4
-; RV32I-NEXT:    slli a3, a0, 6
-; RV32I-NEXT:    add a2, a2, a3
-; RV32I-NEXT:    slli a3, a0, 8
-; RV32I-NEXT:    add a1, a0, a1
-; RV32I-NEXT:    slli a0, a0, 10
-; RV32I-NEXT:    add a1, a1, a2
-; RV32I-NEXT:    add a0, a3, a0
+; RV32I-NEXT:    slli a1, a0, 6
 ; RV32I-NEXT:    add a0, a1, a0
+; RV32I-NEXT:    slli a1, a0, 3
+; RV32I-NEXT:    sub a1, a1, a0
+; RV32I-NEXT:    slli a0, a1, 2
+; RV32I-NEXT:    sub a0, a0, a1
 ; RV32I-NEXT:    ret
 ;
 ; RV64I-LABEL: muli32_0x555:
 ; RV64I:       # %bb.0:
-; RV64I-NEXT:    slli a1, a0, 2
-; RV64I-NEXT:    slli a2, a0, 4
-; RV64I-NEXT:    slli a3, a0, 6
-; RV64I-NEXT:    add a2, a2, a3
-; RV64I-NEXT:    slli a3, a0, 8
-; RV64I-NEXT:    add a1, a0, a1
-; RV64I-NEXT:    slli a0, a0, 10
-; RV64I-NEXT:    add a1, a1, a2
-; RV64I-NEXT:    add a0, a3, a0
+; RV64I-NEXT:    slli a1, a0, 6
 ; RV64I-NEXT:    add a0, a1, a0
+; RV64I-NEXT:    slli a1, a0, 3
+; RV64I-NEXT:    sub a1, a1, a0
+; RV64I-NEXT:    slli a0, a1, 2
+; RV64I-NEXT:    sub a0, a0, a1
 ; RV64I-NEXT:    ret
   %a1 = mul i32 %a, 1365
   ret i32 %a1
@@ -50,16 +42,12 @@ define i64 @muli64_0x555(i64 %a) nounwind {
 ;
 ; RV64I-LABEL: muli64_0x555:
 ; RV64I:       # %bb.0:
-; RV64I-NEXT:    slli a1, a0, 2
-; RV64I-NEXT:    slli a2, a0, 4
-; RV64I-NEXT:    slli a3, a0, 6
-; RV64I-NEXT:    add a2, a2, a3
-; RV64I-NEXT:    slli a3, a0, 8
-; RV64I-NEXT:    add a1, a0, a1
-; RV64I-NEXT:    slli a0, a0, 10
-; RV64I-NEXT:    add a1, a1, a2
-; RV64I-NEXT:    add a0, a3, a0
+; RV64I-NEXT:    slli a1, a0, 6
 ; RV64I-NEXT:    add a0, a1, a0
+; RV64I-NEXT:    slli a1, a0, 3
+; RV64I-NEXT:    sub a1, a1, a0
+; RV64I-NEXT:    slli a0, a1, 2
+; RV64I-NEXT:    sub a0, a0, a1
 ; RV64I-NEXT:    ret
   %a1 = mul i64 %a, 1365
   ret i64 %a1
@@ -68,70 +56,26 @@ define i64 @muli64_0x555(i64 %a) nounwind {
 define i32 @muli32_0x33333333(i32 %a) nounwind {
 ; RV32I-LABEL: muli32_0x33333333:
 ; RV32I:       # %bb.0:
+; RV32I-NEXT:    slli a1, a0, 16
+; RV32I-NEXT:    add a0, a1, a0
+; RV32I-NEXT:    slli a1, a0, 8
+; RV32I-NEXT:    add a0, a1, a0
 ; RV32I-NEXT:    slli a1, a0, 4
-; RV32I-NEXT:    slli a2, a0, 6
-; RV32I-NEXT:    slli a3, a0, 8
-; RV32I-NEXT:    slli a4, a0, 10
-; RV32I-NEXT:    slli a5, a0, 14
-; RV32I-NEXT:    sub a1, a1, a2
-; RV32I-NEXT:    slli a2, a0, 16
-; RV32I-NEXT:    sub a3, a3, a4
-; RV32I-NEXT:    slli a4, a0, 22
-; RV32I-NEXT:    sub a5, a5, a2
-; RV32I-NEXT:    slli a2, a0, 24
-; RV32I-NEXT:    sub a4, a4, a2
-; RV32I-NEXT:    slli a2, a0, 2
-; RV32I-NEXT:    sub a2, a2, a0
-; RV32I-NEXT:    sub a2, a2, a1
-; RV32I-NEXT:    slli a1, a0, 12
-; RV32I-NEXT:    add a1, a3, a1
-; RV32I-NEXT:    slli a3, a0, 18
-; RV32I-NEXT:    add a3, a5, a3
-; RV32I-NEXT:    slli a5, a0, 26
-; RV32I-NEXT:    add a4, a4, a5
-; RV32I-NEXT:    sub a2, a2, a1
-; RV32I-NEXT:    slli a1, a0, 20
-; RV32I-NEXT:    sub a3, a3, a1
-; RV32I-NEXT:    slli a1, a0, 28
-; RV32I-NEXT:    sub a4, a4, a1
-; RV32I-NEXT:    slli a0, a0, 30
-; RV32I-NEXT:    add a2, a2, a3
-; RV32I-NEXT:    add a0, a4, a0
-; RV32I-NEXT:    add a0, a2, a0
+; RV32I-NEXT:    add a0, a1, a0
+; RV32I-NEXT:    slli a1, a0, 2
+; RV32I-NEXT:    sub a0, a1, a0
 ; RV32I-NEXT:    ret
 ;
 ; RV64I-LABEL: muli32_0x33333333:
 ; RV64I:       # %bb.0:
+; RV64I-NEXT:    slli a1, a0, 16
+; RV64I-NEXT:    add a0, a1, a0
+; RV64I-NEXT:    slli a1, a0, 8
+; RV64I-NEXT:    add a0, a1, a0
 ; RV64I-NEXT:    slli a1, a0, 4
-; RV64I-NEXT:    slli a2, a0, 6
-; RV64I-NEXT:    slli a3, a0, 8
-; RV64I-NEXT:    slli a4, a0, 10
-; RV64I-NEXT:    slli a5, a0, 14
-; RV64I-NEXT:    sub a1, a1, a2
-; RV64I-NEXT:    slli a2, a0, 16
-; RV64I-NEXT:    sub a3, a3, a4
-; RV64I-NEXT:    slli a4, a0, 22
-; RV64I-NEXT:    sub a5, a5, a2
-; RV64I-NEXT:    slli a2, a0, 24
-; RV64I-NEXT:    sub a4, a4, a2
-; RV64I-NEXT:    slli a2, a0, 2
-; RV64I-NEXT:    sub a2, a2, a0
-; RV64I-NEXT:    sub a2, a2, a1
-; RV64I-NEXT:    slli a1, a0, 12
-; RV64I-NEXT:    add a1, a3, a1
-; RV64I-NEXT:    slli a3, a0, 18
-; RV64I-NEXT:    add a3, a5, a3
-; RV64I-NEXT:    slli a5, a0, 26
-; RV64I-NEXT:    add a4, a4, a5
-; RV64I-NEXT:    sub a2, a2, a1
-; RV64I-NEXT:    slli a1, a0, 20
-; RV64I-NEXT:    sub a3, a3, a1
-; RV64I-NEXT:    slli a1, a0, 28
-; RV64I-NEXT:    sub a4, a4, a1
-; RV64I-NEXT:    slli a0, a0, 30
-; RV64I-NEXT:    add a2, a2, a3
-; RV64I-NEXT:    add a0, a4, a0
-; RV64I-NEXT:    add a0, a2, a0
+; RV64I-NEXT:    add a0, a1, a0
+; RV64I-NEXT:    slli a1, a0, 2
+; RV64I-NEXT:    sub a0, a1, a0
 ; RV64I-NEXT:    ret
   %a1 = mul i32 %a, 858993459
   ret i32 %a1
@@ -152,36 +96,14 @@ define i64 @muli64_0x33333333(i64 %a) nounwind {
 ;
 ; RV64I-LABEL: muli64_0x33333333:
 ; RV64I:       # %bb.0:
+; RV64I-NEXT:    slli a1, a0, 16
+; RV64I-NEXT:    add a0, a1, a0
+; RV64I-NEXT:    slli a1, a0, 8
+; RV64I-NEXT:    add a0, a1, a0
 ; RV64I-NEXT:    slli a1, a0, 4
-; RV64I-NEXT:    slli a2, a0, 6
-; RV64I-NEXT:    slli a3, a0, 8
-; RV64I-NEXT:    slli a4, a0, 10
-; RV64I-NEXT:    slli a5, a0, 14
-; RV64I-NEXT:    sub a1, a1, a2
-; RV64I-NEXT:    slli a2, a0, 16
-; RV64I-NEXT:    sub a3, a3, a4
-; RV64I-NEXT:    slli a4, a0, 22
-; RV64I-NEXT:    sub a5, a5, a2
-; RV64I-NEXT:    slli a2, a0, 24
-; RV64I-NEXT:    sub a4, a4, a2
-; RV64I-NEXT:    slli a2, a0, 2
-; RV64I-NEXT:    sub a2, a2, a0
-; RV64I-NEXT:    sub a2, a2, a1
-; RV64I-NEXT:    slli a1, a0, 12
-; RV64I-NEXT:    add a1, a3, a1
-; RV64I-NEXT:    slli a3, a0, 18
-; RV64I-NEXT:    add a3, a5, a3
-; RV64I-NEXT:    slli a5, a0, 26
-; RV64I-NEXT:    add a4, a4, a5
-; RV64I-NEXT:    sub a2, a2, a1
-; RV64I-NEXT:    slli a1, a0, 20
-; RV64I-NEXT:    sub a3, a3, a1
-; RV64I-NEXT:    slli a1, a0, 28
-; RV64I-NEXT:    sub a4, a4, a1
-; RV64I-NEXT:    slli a0, a0, 30
-; RV64I-NEXT:    add a2, a2, a3
-; RV64I-NEXT:    add a0, a4, a0
-; RV64I-NEXT:    add a0, a2, a0
+; RV64I-NEXT:    add a0, a1, a0
+; RV64I-NEXT:    slli a1, a0, 2
+; RV64I-NEXT:    sub a0, a1, a0
 ; RV64I-NEXT:    ret
   %a1 = mul i64 %a, 858993459
   ret i64 %a1
@@ -190,72 +112,29 @@ define i64 @muli64_0x33333333(i64 %a) nounwind {
 define i32 @muli32_0xaaaaaaaa(i32 %a) nounwind {
 ; RV32I-LABEL: muli32_0xaaaaaaaa:
 ; RV32I:       # %bb.0:
-; RV32I-NEXT:    slli a1, a0, 3
-; RV32I-NEXT:    slli a2, a0, 1
-; RV32I-NEXT:    slli a3, a0, 5
-; RV32I-NEXT:    slli a4, a0, 7
-; RV32I-NEXT:    slli a5, a0, 9
-; RV32I-NEXT:    slli a6, a0, 11
-; RV32I-NEXT:    add a1, a2, a1
-; RV32I-NEXT:    slli a2, a0, 15
-; RV32I-NEXT:    add a3, a3, a4
-; RV32I-NEXT:    slli a4, a0, 17
-; RV32I-NEXT:    add a5, a5, a6
-; RV32I-NEXT:    slli a6, a0, 23
-; RV32I-NEXT:    add a2, a2, a4
-; RV32I-NEXT:    slli a4, a0, 25
-; RV32I-NEXT:    add a4, a6, a4
-; RV32I-NEXT:    add a1, a1, a3
-; RV32I-NEXT:    slli a3, a0, 13
-; RV32I-NEXT:    add a3, a5, a3
-; RV32I-NEXT:    slli a5, a0, 19
-; RV32I-NEXT:    add a2, a2, a5
-; RV32I-NEXT:    slli a5, a0, 27
-; RV32I-NEXT:    add a4, a4, a5
-; RV32I-NEXT:    add a1, a1, a3
-; RV32I-NEXT:    slli a3, a0, 21
-; RV32I-NEXT:    add a2, a2, a3
-; RV32I-NEXT:    slli a3, a0, 29
-; RV32I-NEXT:    add a3, a4, a3
-; RV32I-NEXT:    slli a0, a0, 31
-; RV32I-NEXT:    add a1, a1, a2
-; RV32I-NEXT:    add a0, a3, a0
+; RV32I-NEXT:    slli a1, a0, 16
 ; RV32I-NEXT:    add a0, a1, a0
+; RV32I-NEXT:    slli a1, a0, 8
+; RV32I-NEXT:    add a0, a1, a0
+; RV32I-NEXT:    slli a1, a0, 4
+; RV32I-NEXT:    add a0, a1, a0
+; RV32I-NEXT:    slli a1, a0, 2
+; RV32I-NEXT:    add a0, a1, a0
+; RV32I-NEXT:    slli a0, a0, 1
 ; RV32I-NEXT:    ret
 ;
 ; RV64I-LABEL: muli32_0xaaaaaaaa:
 ; RV64I:       # %bb.0:
-; RV64I-NEXT:    slli a1, a0, 3
-; RV64I-NEXT:    slli a2, a0, 1
-; RV64I-NEXT:    slli a3, a0, 5
-; RV64I-NEXT:    slli a4, a0, 7
-; RV64I-NEXT:    slli a5, a0, 9
-; RV64I-NEXT:    slli a6, a0, 11
+; RV64I-NEXT:    neg a1, a0
+; RV64I-NEXT:    slli a1, a1, 16
+; RV64I-NEXT:    sub a1, a1, a0
+; RV64I-NEXT:    slli a2, a1, 8
 ; RV64I-NEXT:    add a1, a2, a1
-; RV64I-NEXT:    slli a2, a0, 15
-; RV64I-NEXT:    add a3, a3, a4
-; RV64I-NEXT:    slli a4, a0, 17
-; RV64I-NEXT:    add a5, a5, a6
-; RV64I-NEXT:    slli a6, a0, 23
-; RV64I-NEXT:    add a2, a2, a4
-; RV64I-NEXT:    slli a4, a0, 25
-; RV64I-NEXT:    add a4, a6, a4
-; RV64I-NEXT:    add a1, a1, a3
-; RV64I-NEXT:    slli a3, a0, 13
-; RV64I-NEXT:    add a3, a5, a3
-; RV64I-NEXT:    slli a5, a0, 19
-; RV64I-NEXT:    add a2, a2, a5
-; RV64I-NEXT:    slli a5, a0, 27
-; RV64I-NEXT:    add a4, a4, a5
-; RV64I-NEXT:    add a1, a1, a3
-; RV64I-NEXT:    slli a3, a0, 21
-; RV64I-NEXT:    add a2, a2, a3
-; RV64I-NEXT:    slli a3, a0, 29
-; RV64I-NEXT:    add a3, a4, a3
-; RV64I-NEXT:    slli a0, a0, 31
-; RV64I-NEXT:    add a1, a1, a2
-; RV64I-NEXT:    sub a0, a3, a0
-; RV64I-NEXT:    add a0, a1, a0
+; RV64I-NEXT:    slli a2, a1, 4
+; RV64I-NEXT:    add a1, a2, a1
+; RV64I-NEXT:    slli a2, a1, 2
+; RV64I-NEXT:    sub a0, a1, a0
+; RV64I-NEXT:    add a0, a2, a0
 ; RV64I-NEXT:    ret
   %a1 = mul i32 %a, -1431655766
   ret i32 %a1
@@ -276,37 +155,15 @@ define i64 @muli64_0xaaaaaaaa(i64 %a) nounwind {
 ;
 ; RV64I-LABEL: muli64_0xaaaaaaaa:
 ; RV64I:       # %bb.0:
-; RV64I-NEXT:    slli a1, a0, 3
-; RV64I-NEXT:    slli a2, a0, 1
-; RV64I-NEXT:    slli a3, a0, 5
-; RV64I-NEXT:    slli a4, a0, 7
-; RV64I-NEXT:    slli a5, a0, 9
-; RV64I-NEXT:    slli a6, a0, 11
-; RV64I-NEXT:    add a1, a2, a1
-; RV64I-NEXT:    slli a2, a0, 15
-; RV64I-NEXT:    add a3, a3, a4
-; RV64I-NEXT:    slli a4, a0, 17
-; RV64I-NEXT:    add a5, a5, a6
-; RV64I-NEXT:    slli a6, a0, 23
-; RV64I-NEXT:    add a2, a2, a4
-; RV64I-NEXT:    slli a4, a0, 25
-; RV64I-NEXT:    add a4, a6, a4
-; RV64I-NEXT:    add a1, a1, a3
-; RV64I-NEXT:    slli a3, a0, 13
-; RV64I-NEXT:    add a3, a5, a3
-; RV64I-NEXT:    slli a5, a0, 19
-; RV64I-NEXT:    add a2, a2, a5
-; RV64I-NEXT:    slli a5, a0, 27
-; RV64I-NEXT:    add a4, a4, a5
-; RV64I-NEXT:    add a1, a1, a3
-; RV64I-NEXT:    slli a3, a0, 21
-; RV64I-NEXT:    add a2, a2, a3
-; RV64I-NEXT:    slli a3, a0, 29
-; RV64I-NEXT:    add a3, a4, a3
-; RV64I-NEXT:    slli a0, a0, 31
-; RV64I-NEXT:    add a1, a1, a2
-; RV64I-NEXT:    add a0, a3, a0
+; RV64I-NEXT:    slli a1, a0, 16
+; RV64I-NEXT:    add a0, a1, a0
+; RV64I-NEXT:    slli a1, a0, 8
+; RV64I-NEXT:    add a0, a1, a0
+; RV64I-NEXT:    slli a1, a0, 4
+; RV64I-NEXT:    add a0, a1, a0
+; RV64I-NEXT:    slli a1, a0, 2
 ; RV64I-NEXT:    add a0, a1, a0
+; RV64I-NEXT:    slli a0, a0, 1
 ; RV64I-NEXT:    ret
   %a1 = mul i64 %a, 2863311530
   ret i64 %a1
@@ -353,36 +210,24 @@ define i64 @muli64_0x0fffffff(i64 %a) nounwind {
 define i32 @muli32_0xf0f0f0f0(i32 %a) nounwind {
 ; RV32I-LABEL: muli32_0xf0f0f0f0:
 ; RV32I:       # %bb.0:
-; RV32I-NEXT:    slli a1, a0, 4
-; RV32I-NEXT:    slli a2, a0, 8
-; RV32I-NEXT:    slli a3, a0, 12
-; RV32I-NEXT:    slli a4, a0, 16
-; RV32I-NEXT:    sub a2, a2, a1
-; RV32I-NEXT:    slli a1, a0, 20
-; RV32I-NEXT:    sub a3, a3, a4
-; RV32I-NEXT:    slli a4, a0, 24
-; RV32I-NEXT:    sub a1, a1, a4
-; RV32I-NEXT:    slli a0, a0, 28
-; RV32I-NEXT:    sub a2, a2, a3
+; RV32I-NEXT:    slli a1, a0, 16
 ; RV32I-NEXT:    add a0, a1, a0
-; RV32I-NEXT:    sub a0, a2, a0
+; RV32I-NEXT:    slli a1, a0, 8
+; RV32I-NEXT:    add a0, a1, a0
+; RV32I-NEXT:    slli a1, a0, 4
+; RV32I-NEXT:    sub a0, a1, a0
+; RV32I-NEXT:    slli a0, a0, 4
 ; RV32I-NEXT:    ret
 ;
 ; RV64I-LABEL: muli32_0xf0f0f0f0:
 ; RV64I:       # %bb.0:
-; RV64I-NEXT:    slli a1, a0, 4
-; RV64I-NEXT:    slli a2, a0, 8
-; RV64I-NEXT:    slli a3, a0, 12
-; RV64I-NEXT:    slli a4, a0, 16
-; RV64I-NEXT:    sub a2, a2, a1
-; RV64I-NEXT:    slli a1, a0, 20
-; RV64I-NEXT:    sub a3, a3, a4
-; RV64I-NEXT:    slli a4, a0, 24
-; RV64I-NEXT:    sub a1, a1, a4
-; RV64I-NEXT:    slli a0, a0, 28
-; RV64I-NEXT:    sub a2, a2, a3
-; RV64I-NEXT:    add a0, a1, a0
-; RV64I-NEXT:    sub a0, a2, a0
+; RV64I-NEXT:    slli a1, a0, 16
+; RV64I-NEXT:    add a1, a1, a0
+; RV64I-NEXT:    slli a2, a1, 8
+; RV64I-NEXT:    add a1, a2, a1
+; RV64I-NEXT:    slli a2, a1, 4
+; RV64I-NEXT:    sub a0, a1, a0
+; RV64I-NEXT:    sub a0, a0, a2
 ; RV64I-NEXT:    ret
   %a1 = mul i32 %a, -252645136
   ret i32 %a1
@@ -403,21 +248,13 @@ define i64 @muli64_0xf0f0f0f0(i64 %a) nounwind {
 ;
 ; RV64I-LABEL: muli64_0xf0f0f0f0:
 ; RV64I:       # %bb.0:
+; RV64I-NEXT:    slli a1, a0, 16
+; RV64I-NEXT:    add a0, a1, a0
+; RV64I-NEXT:    slli a1, a0, 8
+; RV64I-NEXT:    add a0, a1, a0
 ; RV64I-NEXT:    slli a1, a0, 4
-; RV64I-NEXT:    slli a2, a0, 8
-; RV64I-NEXT:    slli a3, a0, 12
-; RV64I-NEXT:    slli a4, a0, 16
-; RV64I-NEXT:    sub a2, a2, a1
-; RV64I-NEXT:    slli a1, a0, 20
-; RV64I-NEXT:    sub a3, a3, a4
-; RV64I-NEXT:    slli a4, a0, 24
-; RV64I-NEXT:    sub a1, a1, a4
-; RV64I-NEXT:    sub a2, a2, a3
-; RV64I-NEXT:    slli a3, a0, 28
-; RV64I-NEXT:    add a1, a1, a3
-; RV64I-NEXT:    sub a2, a2, a1
-; RV64I-NEXT:    slli a0, a0, 32
-; RV64I-NEXT:    add a0, a2, a0
+; RV64I-NEXT:    sub a0, a1, a0
+; RV64I-NEXT:    slli a0, a0, 4
 ; RV64I-NEXT:    ret
   %a1 = mul i64 %a, 4042322160
   ret i64 %a1
@@ -426,28 +263,25 @@ define i64 @muli64_0xf0f0f0f0(i64 %a) nounwind {
 define i32 @muli32_0xf7f7f7f7(i32 %a) nounwind {
 ; RV32I-LABEL: muli32_0xf7f7f7f7:
 ; RV32I:       # %bb.0:
-; RV32I-NEXT:    slli a1, a0, 3
-; RV32I-NEXT:    slli a2, a0, 11
-; RV32I-NEXT:    slli a3, a0, 19
-; RV32I-NEXT:    add a1, a0, a1
-; RV32I-NEXT:    slli a0, a0, 27
-; RV32I-NEXT:    add a2, a2, a3
-; RV32I-NEXT:    add a1, a1, a2
-; RV32I-NEXT:    neg a0, a0
-; RV32I-NEXT:    sub a0, a0, a1
+; RV32I-NEXT:    slli a1, a0, 5
+; RV32I-NEXT:    sub a1, a1, a0
+; RV32I-NEXT:    slli a1, a1, 3
+; RV32I-NEXT:    sub a1, a1, a0
+; RV32I-NEXT:    slli a0, a1, 16
+; RV32I-NEXT:    add a0, a0, a1
+; RV32I-NEXT:    slli a1, a0, 8
+; RV32I-NEXT:    add a0, a1, a0
 ; RV32I-NEXT:    ret
 ;
 ; RV64I-LABEL: muli32_0xf7f7f7f7:
 ; RV64I:       # %bb.0:
-; RV64I-NEXT:    slli a1, a0, 3
-; RV64I-NEXT:    slli a2, a0, 11
-; RV64I-NEXT:    slli a3, a0, 19
-; RV64I-NEXT:    add a1, a0, a1
-; RV64I-NEXT:    slli a0, a0, 27
-; RV64I-NEXT:    add a2, a2, a3
-; RV64I-NEXT:    add a1, a1, a2
-; RV64I-NEXT:    neg a0, a0
-; RV64I-NEXT:    sub a0, a0, a1
+; RV64I-NEXT:    neg a1, a0
+; RV64I-NEXT:    slli a1, a1, 16
+; RV64I-NEXT:    sub a1, a1, a0
+; RV64I-NEXT:    slli a2, a1, 8
+; RV64I-NEXT:    add a1, a2, a1
+; RV64I-NEXT:    slli a1, a1, 3
+; RV64I-NEXT:    sub a0, a1, a0
 ; RV64I-NEXT:    ret
   %a1 = mul i32 %a, -134744073
   ret i32 %a1
@@ -468,16 +302,14 @@ define i64 @muli64_0xf7f7f7f7(i64 %a) nounwind {
 ;
 ; RV64I-LABEL: muli64_0xf7f7f7f7:
 ; RV64I:       # %bb.0:
-; RV64I-NEXT:    slli a1, a0, 3
-; RV64I-NEXT:    slli a2, a0, 11
-; RV64I-NEXT:    slli a3, a0, 19
-; RV64I-NEXT:    add a2, a2, a3
-; RV64I-NEXT:    slli a3, a0, 27
-; RV64I-NEXT:    add a1, a0, a1
-; RV64I-NEXT:    slli a0, a0, 32
-; RV64I-NEXT:    add a1, a1, a2
-; RV64I-NEXT:    sub a0, a0, a3
-; RV64I-NEXT:    sub a0, a0, a1
+; RV64I-NEXT:    slli a1, a0, 5
+; RV64I-NEXT:    sub a1, a1, a0
+; RV64I-NEXT:    slli a1, a1, 3
+; RV64I-NEXT:    sub a1, a1, a0
+; RV64I-NEXT:    slli a0, a1, 16
+; RV64I-NEXT:    add a0, a0, a1
+; RV64I-NEXT:    slli a1, a0, 8
+; RV64I-NEXT:    add a0, a1, a0
 ; RV64I-NEXT:    ret
   %a1 = mul i64 %a, 4160223223
   ret i64 %a1
@@ -631,43 +463,32 @@ define i64 @muli64_0x7fffffff(i64 %a) nounwind {
 define i32 @muli32_0xdeadbeef(i32 %a) nounwind {
 ; RV32I-LABEL: muli32_0xdeadbeef:
 ; RV32I:       # %bb.0:
+; RV32I-NEXT:    slli a1, a0, 7
+; RV32I-NEXT:    sub a1, a1, a0
+; RV32I-NEXT:    slli a1, a1, 2
+; RV32I-NEXT:    sub a1, a1, a0
+; RV32I-NEXT:    slli a2, a1, 3
+; RV32I-NEXT:    sub a2, a2, a1
+; RV32I-NEXT:    slli a2, a2, 8
+; RV32I-NEXT:    sub a2, a2, a0
+; RV32I-NEXT:    slli a2, a2, 4
+; RV32I-NEXT:    sub a0, a2, a0
 ; RV32I-NEXT:    slli a1, a0, 8
-; RV32I-NEXT:    slli a2, a0, 14
-; RV32I-NEXT:    slli a3, a0, 17
-; RV32I-NEXT:    slli a4, a0, 20
-; RV32I-NEXT:    add a1, a1, a2
-; RV32I-NEXT:    slli a2, a0, 24
-; RV32I-NEXT:    add a3, a3, a4
-; RV32I-NEXT:    slli a4, a0, 29
-; RV32I-NEXT:    add a2, a2, a4
-; RV32I-NEXT:    slli a4, a0, 4
-; RV32I-NEXT:    add a4, a0, a4
-; RV32I-NEXT:    add a1, a4, a1
-; RV32I-NEXT:    slli a0, a0, 22
-; RV32I-NEXT:    add a0, a3, a0
 ; RV32I-NEXT:    add a0, a1, a0
-; RV32I-NEXT:    neg a1, a2
-; RV32I-NEXT:    sub a0, a1, a0
 ; RV32I-NEXT:    ret
 ;
 ; RV64I-LABEL: muli32_0xdeadbeef:
 ; RV64I:       # %bb.0:
-; RV64I-NEXT:    slli a1, a0, 8
-; RV64I-NEXT:    slli a2, a0, 14
-; RV64I-NEXT:    slli a3, a0, 17
-; RV64I-NEXT:    slli a4, a0, 20
-; RV64I-NEXT:    add a1, a1, a2
-; RV64I-NEXT:    slli a2, a0, 24
-; RV64I-NEXT:    add a3, a3, a4
-; RV64I-NEXT:    slli a4, a0, 29
-; RV64I-NEXT:    add a2, a2, a4
-; RV64I-NEXT:    slli a4, a0, 4
-; RV64I-NEXT:    add a4, a0, a4
-; RV64I-NEXT:    add a1, a4, a1
-; RV64I-NEXT:    slli a0, a0, 22
-; RV64I-NEXT:    add a0, a3, a0
-; RV64I-NEXT:    add a0, a1, a0
-; RV64I-NEXT:    neg a1, a2
+; RV64I-NEXT:    neg a1, a0
+; RV64I-NEXT:    slli a1, a1, 5
+; RV64I-NEXT:    sub a1, a1, a0
+; RV64I-NEXT:    slli a1, a1, 4
+; RV64I-NEXT:    sub a1, a1, a0
+; RV64I-NEXT:    slli a2, a1, 8
+; RV64I-NEXT:    add a1, a2, a1
+; RV64I-NEXT:    slli a2, a1, 8
+; RV64I-NEXT:    add a1, a2, a1
+; RV64I-NEXT:    slli a1, a1, 4
 ; RV64I-NEXT:    sub a0, a1, a0
 ; RV64I-NEXT:    ret
   %a1 = mul i32 %a, -559038737
@@ -689,24 +510,18 @@ define i64 @muli64_0xdeadbeef(i64 %a) nounwind {
 ;
 ; RV64I-LABEL: muli64_0xdeadbeef:
 ; RV64I:       # %bb.0:
+; RV64I-NEXT:    slli a1, a0, 7
+; RV64I-NEXT:    sub a1, a1, a0
+; RV64I-NEXT:    slli a1, a1, 2
+; RV64I-NEXT:    sub a1, a1, a0
+; RV64I-NEXT:    slli a2, a1, 3
+; RV64I-NEXT:    sub a2, a2, a1
+; RV64I-NEXT:    slli a2, a2, 8
+; RV64I-NEXT:    sub a2, a2, a0
+; RV64I-NEXT:    slli a2, a2, 4
+; RV64I-NEXT:    sub a0, a2, a0
 ; RV64I-NEXT:    slli a1, a0, 8
-; RV64I-NEXT:    slli a2, a0, 14
-; RV64I-NEXT:    slli a3, a0, 17
-; RV64I-NEXT:    slli a4, a0, 20
-; RV64I-NEXT:    add a1, a1, a2
-; RV64I-NEXT:    slli a2, a0, 24
-; RV64I-NEXT:    add a3, a3, a4
-; RV64I-NEXT:    slli a4, a0, 29
-; RV64I-NEXT:    add a2, a2, a4
-; RV64I-NEXT:    slli a4, a0, 4
-; RV64I-NEXT:    add a4, a0, a4
-; RV64I-NEXT:    add a1, a4, a1
-; RV64I-NEXT:    slli a4, a0, 22
-; RV64I-NEXT:    add a3, a3, a4
-; RV64I-NEXT:    slli a0, a0, 32
-; RV64I-NEXT:    add a1, a1, a3
-; RV64I-NEXT:    sub a0, a0, a2
-; RV64I-NEXT:    sub a0, a0, a1
+; RV64I-NEXT:    add a0, a1, a0
 ; RV64I-NEXT:    ret
   %a1 = mul i64 %a, 3735928559
   ret i64 %a1
@@ -715,52 +530,40 @@ define i64 @muli64_0xdeadbeef(i64 %a) nounwind {
 define i32 @muli32_0x12345678(i32 %a) nounwind {
 ; RV32I-LABEL: muli32_0x12345678:
 ; RV32I:       # %bb.0:
-; RV32I-NEXT:    slli a1, a0, 3
-; RV32I-NEXT:    slli a2, a0, 7
-; RV32I-NEXT:    slli a3, a0, 9
-; RV32I-NEXT:    slli a4, a0, 11
-; RV32I-NEXT:    slli a5, a0, 13
+; RV32I-NEXT:    slli a1, a0, 5
+; RV32I-NEXT:    add a1, a1, a0
+; RV32I-NEXT:    slli a1, a1, 3
+; RV32I-NEXT:    sub a1, a1, a0
+; RV32I-NEXT:    slli a2, a1, 3
 ; RV32I-NEXT:    sub a2, a2, a1
-; RV32I-NEXT:    slli a1, a0, 15
-; RV32I-NEXT:    add a3, a3, a4
-; RV32I-NEXT:    slli a4, a0, 20
-; RV32I-NEXT:    sub a5, a5, a1
-; RV32I-NEXT:    slli a1, a0, 22
-; RV32I-NEXT:    sub a4, a4, a1
-; RV32I-NEXT:    sub a2, a2, a3
-; RV32I-NEXT:    slli a1, a0, 18
-; RV32I-NEXT:    sub a5, a5, a1
-; RV32I-NEXT:    slli a1, a0, 25
-; RV32I-NEXT:    sub a4, a4, a1
-; RV32I-NEXT:    slli a0, a0, 28
-; RV32I-NEXT:    sub a2, a2, a5
-; RV32I-NEXT:    sub a4, a4, a0
-; RV32I-NEXT:    sub a0, a2, a4
+; RV32I-NEXT:    slli a2, a2, 3
+; RV32I-NEXT:    add a2, a2, a0
+; RV32I-NEXT:    slli a2, a2, 5
+; RV32I-NEXT:    sub a2, a2, a0
+; RV32I-NEXT:    slli a0, a2, 3
+; RV32I-NEXT:    add a0, a0, a2
+; RV32I-NEXT:    slli a1, a0, 3
+; RV32I-NEXT:    add a0, a1, a0
+; RV32I-NEXT:    slli a0, a0, 3
 ; RV32I-NEXT:    ret
 ;
 ; RV64I-LABEL: muli32_0x12345678:
 ; RV64I:       # %bb.0:
-; RV64I-NEXT:    slli a1, a0, 3
-; RV64I-NEXT:    slli a2, a0, 7
-; RV64I-NEXT:    slli a3, a0, 9
-; RV64I-NEXT:    slli a4, a0, 11
-; RV64I-NEXT:    slli a5, a0, 13
+; RV64I-NEXT:    slli a1, a0, 5
+; RV64I-NEXT:    add a1, a1, a0
+; RV64I-NEXT:    slli a1, a1, 3
+; RV64I-NEXT:    sub a1, a1, a0
+; RV64I-NEXT:    slli a2, a1, 3
 ; RV64I-NEXT:    sub a2, a2, a1
-; RV64I-NEXT:    slli a1, a0, 15
-; RV64I-NEXT:    add a3, a3, a4
-; RV64I-NEXT:    slli a4, a0, 20
-; RV64I-NEXT:    sub a5, a5, a1
-; RV64I-NEXT:    slli a1, a0, 22
-; RV64I-NEXT:    sub a4, a4, a1
-; RV64I-NEXT:    sub a2, a2, a3
-; RV64I-NEXT:    slli a1, a0, 18
-; RV64I-NEXT:    sub a5, a5, a1
-; RV64I-NEXT:    slli a1, a0, 25
-; RV64I-NEXT:    sub a4, a4, a1
-; RV64I-NEXT:    slli a0, a0, 28
-; RV64I-NEXT:    sub a2, a2, a5
-; RV64I-NEXT:    sub a4, a4, a0
-; RV64I-NEXT:    sub a0, a2, a4
+; RV64I-NEXT:    slli a2, a2, 3
+; RV64I-NEXT:    add a2, a2, a0
+; RV64I-NEXT:    slli a2, a2, 5
+; RV64I-NEXT:    sub a2, a2, a0
+; RV64I-NEXT:    slli a0, a2, 3
+; RV64I-NEXT:    add a0, a0, a2
+; RV64I-NEXT:    slli a1, a0, 3
+; RV64I-NEXT:    add a0, a1, a0
+; RV64I-NEXT:    slli a0, a0, 3
 ; RV64I-NEXT:    ret
   %a1 = mul i32 %a, 305419896
   ret i32 %a1
@@ -781,27 +584,21 @@ define i64 @muli64_0x12345678(i64 %a) nounwind {
 ;
 ; RV64I-LABEL: muli64_0x12345678:
 ; RV64I:       # %bb.0:
-; RV64I-NEXT:    slli a1, a0, 3
-; RV64I-NEXT:    slli a2, a0, 7
-; RV64I-NEXT:    slli a3, a0, 9
-; RV64I-NEXT:    slli a4, a0, 11
-; RV64I-NEXT:    slli a5, a0, 13
+; RV64I-NEXT:    slli a1, a0, 5
+; RV64I-NEXT:    add a1, a1, a0
+; RV64I-NEXT:    slli a1, a1, 3
+; RV64I-NEXT:    sub a1, a1, a0
+; RV64I-NEXT:    slli a2, a1, 3
 ; RV64I-NEXT:    sub a2, a2, a1
-; RV64I-NEXT:    slli a1, a0, 15
-; RV64I-NEXT:    add a3, a3, a4
-; RV64I-NEXT:    slli a4, a0, 20
-; RV64I-NEXT:    sub a5, a5, a1
-; RV64I-NEXT:    slli a1, a0, 22
-; RV64I-NEXT:    sub a4, a4, a1
-; RV64I-NEXT:    sub a2, a2, a3
-; RV64I-NEXT:    slli a1, a0, 18
-; RV64I-NEXT:    sub a5, a5, a1
-; RV64I-NEXT:    slli a1, a0, 25
-; RV64I-NEXT:    sub a4, a4, a1
-; RV64I-NEXT:    slli a0, a0, 28
-; RV64I-NEXT:    sub a2, a2, a5
-; RV64I-NEXT:    sub a4, a4, a0
-; RV64I-NEXT:    sub a0, a2, a4
+; RV64I-NEXT:    slli a2, a2, 3
+; RV64I-NEXT:    add a2, a2, a0
+; RV64I-NEXT:    slli a2, a2, 5
+; RV64I-NEXT:    sub a2, a2, a0
+; RV64I-NEXT:    slli a0, a2, 3
+; RV64I-NEXT:    add a0, a0, a2
+; RV64I-NEXT:    slli a1, a0, 3
+; RV64I-NEXT:    add a0, a1, a0
+; RV64I-NEXT:    slli a0, a0, 3
 ; RV64I-NEXT:    ret
   %a1 = mul i64 %a, 305419896
   ret i64 %a1
diff --git a/llvm/test/CodeGen/RISCV/mul.ll b/llvm/test/CodeGen/RISCV/mul.ll
index 263eeec1289b2..ca06cae6243e7 100644
--- a/llvm/test/CodeGen/RISCV/mul.ll
+++ b/llvm/test/CodeGen/RISCV/mul.ll
@@ -1344,10 +1344,10 @@ define i32 @muli32_m3840(i32 %a) nounwind {
 define i32 @muli32_m4352(i32 %a) nounwind {
 ; RV32I-LABEL: muli32_m4352:
 ; RV32I:       # %bb.0:
-; RV32I-NEXT:    slli a1, a0, 12
+; RV32I-NEXT:    neg a1, a0
+; RV32I-NEXT:    slli a1, a1, 4
+; RV32I-NEXT:    sub a0, a1, a0
 ; RV32I-NEXT:    slli a0, a0, 8
-; RV32I-NEXT:    add a0, a0, a1
-; RV32I-NEXT:    neg a0, a0
 ; RV32I-NEXT:    ret
 ;
 ; RV32IM-LABEL: muli32_m4352:
@@ -1359,10 +1359,10 @@ define i32 @muli32_m4352(i32 %a) nounwind {
 ;
 ; RV64I-LABEL: muli32_m4352:
 ; RV64I:       # %bb.0:
-; RV64I-NEXT:    slli a1, a0, 12
+; RV64I-NEXT:    neg a1, a0
+; RV64I-NEXT:    slli a1, a1, 4
+; RV64I-NEXT:    sub a0, a1, a0
 ; RV64I-NEXT:    slli a0, a0, 8
-; RV64I-NEXT:    add a0, a0, a1
-; RV64I-NEXT:    neg a0, a0
 ; RV64I-NEXT:    ret
 ;
 ; RV64IM-LABEL: muli32_m4352:
@@ -1497,10 +1497,10 @@ define i64 @muli64_m4352(i64 %a) nounwind {
 ;
 ; RV64I-LABEL: muli64_m4352:
 ; RV64I:       # %bb.0:
-; RV64I-NEXT:    slli a1, a0, 12
+; RV64I-NEXT:    neg a1, a0
+; RV64I-NEXT:    slli a1, a1, 4
+; RV64I-NEXT:    sub a0, a1, a0
 ; RV64I-NEXT:    slli a0, a0, 8
-; RV64I-NEXT:    add a0, a0, a1
-; RV64I-NEXT:    neg a0, a0
 ; RV64I-NEXT:    ret
 ;
 ; RV64IM-LABEL: muli64_m4352:
@@ -2174,19 +2174,15 @@ define i32 @mulfshl_demand(i32 signext %x) nounwind {
 ; RV32I-LABEL: mulfshl_demand:
 ; RV32I:       # %bb.0:
 ; RV32I-NEXT:    srli a0, a0, 11
-; RV32I-NEXT:    slli a1, a0, 19
-; RV32I-NEXT:    slli a2, a0, 15
-; RV32I-NEXT:    slli a3, a0, 21
-; RV32I-NEXT:    slli a4, a0, 23
-; RV32I-NEXT:    add a1, a2, a1
-; RV32I-NEXT:    slli a2, a0, 25
-; RV32I-NEXT:    add a3, a3, a4
-; RV32I-NEXT:    slli a4, a0, 27
-; RV32I-NEXT:    add a2, a2, a4
-; RV32I-NEXT:    slli a0, a0, 29
-; RV32I-NEXT:    add a1, a1, a3
-; RV32I-NEXT:    sub a2, a2, a0
-; RV32I-NEXT:    sub a0, a1, a2
+; RV32I-NEXT:    slli a1, a0, 2
+; RV32I-NEXT:    add a1, a1, a0
+; RV32I-NEXT:    slli a1, a1, 5
+; RV32I-NEXT:    add a1, a1, a0
+; RV32I-NEXT:    slli a1, a1, 3
+; RV32I-NEXT:    add a0, a1, a0
+; RV32I-NEXT:    slli a1, a0, 3
+; RV32I-NEXT:    add a0, a1, a0
+; RV32I-NEXT:    slli a0, a0, 15
 ; RV32I-NEXT:    ret
 ;
 ; RV32IM-LABEL: mulfshl_demand:
@@ -2199,19 +2195,15 @@ define i32 @mulfshl_demand(i32 signext %x) nounwind {
 ; RV64I-LABEL: mulfshl_demand:
 ; RV64I:       # %bb.0:
 ; RV64I-NEXT:    srliw a0, a0, 11
-; RV64I-NEXT:    slli a1, a0, 19
-; RV64I-NEXT:    slli a2, a0, 15
-; RV64I-NEXT:    slli a3, a0, 21
-; RV64I-NEXT:    slli a4, a0, 23
-; RV64I-NEXT:    add a1, a2, a1
-; RV64I-NEXT:    slli a2, a0, 25
-; RV64I-NEXT:    add a3, a3, a4
-; RV64I-NEXT:    slli a4, a0, 27
-; RV64I-NEXT:    add a2, a2, a4
-; RV64I-NEXT:    slli a0, a0, 29
-; RV64I-NEXT:    add a1, a1, a3
-; RV64I-NEXT:    sub a2, a2, a0
-; RV64I-NEXT:    sub a0, a1, a2
+; RV64I-NEXT:    slli a1, a0, 2
+; RV64I-NEXT:    add a1, a1, a0
+; RV64I-NEXT:    slli a1, a1, 5
+; RV64I-NEXT:    add a1, a1, a0
+; RV64I-NEXT:    slli a1, a1, 3
+; RV64I-NEXT:    add a0, a1, a0
+; RV64I-NEXT:    slli a1, a0, 3
+; RV64I-NEXT:    add a0, a1, a0
+; RV64I-NEXT:    slli a0, a0, 15
 ; RV64I-NEXT:    ret
 ;
 ; RV64IM-LABEL: mulfshl_demand:
@@ -2228,19 +2220,15 @@ define i32 @mulfshl_demand(i32 signext %x) nounwind {
 define i32 @mulor_demand(i32 signext %x, i32 signext %y) nounwind {
 ; RV32I-LABEL: mulor_demand:
 ; RV32I:       # %bb.0:
-; RV32I-NEXT:    slli a1, a0, 19
-; RV32I-NEXT:    slli a2, a0, 15
-; RV32I-NEXT:    slli a3, a0, 21
-; RV32I-NEXT:    slli a4, a0, 23
-; RV32I-NEXT:    add a1, a2, a1
-; RV32I-NEXT:    slli a2, a0, 25
-; RV32I-NEXT:    add a3, a3, a4
-; RV32I-NEXT:    slli a4, a0, 27
-; RV32I-NEXT:    add a2, a2, a4
-; RV32I-NEXT:    slli a0, a0, 29
-; RV32I-NEXT:    add a1, a1, a3
-; RV32I-NEXT:    sub a2, a2, a0
-; RV32I-NEXT:    sub a0, a1, a2
+; RV32I-NEXT:    slli a1, a0, 2
+; RV32I-NEXT:    add a1, a1, a0
+; RV32I-NEXT:    slli a1, a1, 5
+; RV32I-NEXT:    add a1, a1, a0
+; RV32I-NEXT:    slli a1, a1, 3
+; RV32I-NEXT:    add a0, a1, a0
+; RV32I-NEXT:    slli a1, a0, 3
+; RV32I-NEXT:    add a0, a1, a0
+; RV32I-NEXT:    slli a0, a0, 15
 ; RV32I-NEXT:    ret
 ;
 ; RV32IM-LABEL: mulor_demand:
@@ -2251,19 +2239,15 @@ define i32 @mulor_demand(i32 signext %x, i32 signext %y) nounwind {
 ;
 ; RV64I-LABEL: mulor_demand:
 ; RV64I:       # %bb.0:
-; RV64I-NEXT:    slli a1, a0, 19
-; RV64I-NEXT:    slli a2, a0, 15
-; RV64I-NEXT:    slli a3, a0, 21
-; RV64I-NEXT:    slli a4, a0, 23
-; RV64I-NEXT:    add a1, a2, a1
-; RV64I-NEXT:    slli a2, a0, 25
-; RV64I-NEXT:    add a3, a3, a4
-; RV64I-NEXT:    slli a4, a0, 27
-; RV64I-NEXT:    add a2, a2, a4
-; RV64I-NEXT:    slli a0, a0, 29
-; RV64I-NEXT:    add a1, a1, a3
-; RV64I-NEXT:    sub a2, a2, a0
-; RV64I-NEXT:    sub a0, a1, a2
+; RV64I-NEXT:    slli a1, a0, 2
+; RV64I-NEXT:    add a1, a1, a0
+; RV64I-NEXT:    slli a1, a1, 5
+; RV64I-NEXT:    add a1, a1, a0
+; RV64I-NEXT:    slli a1, a1, 3
+; RV64I-NEXT:    add a0, a1, a0
+; RV64I-NEXT:    slli a1, a0, 3
+; RV64I-NEXT:    add a0, a1, a0
+; RV64I-NEXT:    slli a0, a0, 15
 ; RV64I-NEXT:    ret
 ;
 ; RV64IM-LABEL: mulor_demand:
diff --git a/llvm/test/CodeGen/RISCV/rv64xtheadbb.ll b/llvm/test/CodeGen/RISCV/rv64xtheadbb.ll
index c62fb0ae63555..0821311f0e0e0 100644
--- a/llvm/test/CodeGen/RISCV/rv64xtheadbb.ll
+++ b/llvm/test/CodeGen/RISCV/rv64xtheadbb.ll
@@ -391,26 +391,18 @@ define signext i32 @cttz_i32(i32 signext %a) nounwind {
 ; RV64I-NEXT:  # %bb.1: # %cond.false
 ; RV64I-NEXT:    neg a1, a0
 ; RV64I-NEXT:    and a0, a0, a1
-; RV64I-NEXT:    slli a1, a0, 6
-; RV64I-NEXT:    slli a2, a0, 8
-; RV64I-NEXT:    slli a3, a0, 10
-; RV64I-NEXT:    slli a4, a0, 12
-; RV64I-NEXT:    add a1, a1, a2
-; RV64I-NEXT:    slli a2, a0, 16
-; RV64I-NEXT:    sub a3, a3, a4
-; RV64I-NEXT:    slli a4, a0, 18
-; RV64I-NEXT:    sub a2, a2, a4
-; RV64I-NEXT:    slli a4, a0, 4
-; RV64I-NEXT:    sub a4, a0, a4
-; RV64I-NEXT:    add a1, a4, a1
-; RV64I-NEXT:    slli a4, a0, 14
-; RV64I-NEXT:    sub a3, a3, a4
-; RV64I-NEXT:    slli a4, a0, 23
-; RV64I-NEXT:    sub a2, a2, a4
-; RV64I-NEXT:    slli a0, a0, 27
-; RV64I-NEXT:    add a1, a1, a3
+; RV64I-NEXT:    slli a1, a0, 9
+; RV64I-NEXT:    sub a1, a1, a0
+; RV64I-NEXT:    slli a1, a1, 3
+; RV64I-NEXT:    add a1, a1, a0
+; RV64I-NEXT:    slli a1, a1, 5
+; RV64I-NEXT:    sub a1, a1, a0
+; RV64I-NEXT:    slli a1, a1, 2
+; RV64I-NEXT:    add a1, a1, a0
+; RV64I-NEXT:    slli a2, a1, 4
+; RV64I-NEXT:    sub a2, a2, a1
+; RV64I-NEXT:    slli a2, a2, 4
 ; RV64I-NEXT:    add a0, a2, a0
-; RV64I-NEXT:    add a0, a1, a0
 ; RV64I-NEXT:    srliw a0, a0, 27
 ; RV64I-NEXT:    lui a1, %hi(.LCPI6_0)
 ; RV64I-NEXT:    addi a1, a1, %lo(.LCPI6_0)
@@ -449,26 +441,18 @@ define signext i32 @cttz_zero_undef_i32(i32 signext %a) nounwind {
 ; RV64I:       # %bb.0:
 ; RV64I-NEXT:    neg a1, a0
 ; RV64I-NEXT:    and a0, a0, a1
-; RV64I-NEXT:    slli a1, a0, 6
-; RV64I-NEXT:    slli a2, a0, 8
-; RV64I-NEXT:    slli a3, a0, 10
-; RV64I-NEXT:    slli a4, a0, 12
-; RV64I-NEXT:    add a1, a1, a2
-; RV64I-NEXT:    slli a2, a0, 16
-; RV64I-NEXT:    sub a3, a3, a4
-; RV64I-NEXT:    slli a4, a0, 18
-; RV64I-NEXT:    sub a2, a2, a4
-; RV64I-NEXT:    slli a4, a0, 4
-; RV64I-NEXT:    sub a4, a0, a4
-; RV64I-NEXT:    add a1, a4, a1
-; RV64I-NEXT:    slli a4, a0, 14
-; RV64I-NEXT:    sub a3, a3, a4
-; RV64I-NEXT:    slli a4, a0, 23
-; RV64I-NEXT:    sub a2, a2, a4
-; RV64I-NEXT:    slli a0, a0, 27
-; RV64I-NEXT:    add a1, a1, a3
+; RV64I-NEXT:    slli a1, a0, 9
+; RV64I-NEXT:    sub a1, a1, a0
+; RV64I-NEXT:    slli a1, a1, 3
+; RV64I-NEXT:    add a1, a1, a0
+; RV64I-NEXT:    slli a1, a1, 5
+; RV64I-NEXT:    sub a1, a1, a0
+; RV64I-NEXT:    slli a1, a1, 2
+; RV64I-NEXT:    add a1, a1, a0
+; RV64I-NEXT:    slli a2, a1, 4
+; RV64I-NEXT:    sub a2, a2, a1
+; RV64I-NEXT:    slli a2, a2, 4
 ; RV64I-NEXT:    add a0, a2, a0
-; RV64I-NEXT:    add a0, a1, a0
 ; RV64I-NEXT:    srliw a0, a0, 27
 ; RV64I-NEXT:    lui a1, %hi(.LCPI7_0)
 ; RV64I-NEXT:    addi a1, a1, %lo(.LCPI7_0)
@@ -499,26 +483,18 @@ define signext i32 @findFirstSet_i32(i32 signext %a) nounwind {
 ; RV64I:       # %bb.0:
 ; RV64I-NEXT:    neg a1, a0
 ; RV64I-NEXT:    and a1, a0, a1
-; RV64I-NEXT:    slli a2, a1, 6
-; RV64I-NEXT:    slli a3, a1, 8
-; RV64I-NEXT:    slli a4, a1, 10
-; RV64I-NEXT:    slli a5, a1, 12
-; RV64I-NEXT:    add a2, a2, a3
-; RV64I-NEXT:    slli a3, a1, 16
-; RV64I-NEXT:    sub a4, a4, a5
-; RV64I-NEXT:    slli a5, a1, 18
-; RV64I-NEXT:    sub a3, a3, a5
-; RV64I-NEXT:    slli a5, a1, 4
-; RV64I-NEXT:    sub a5, a1, a5
-; RV64I-NEXT:    add a2, a5, a2
-; RV64I-NEXT:    slli a5, a1, 14
-; RV64I-NEXT:    sub a4, a4, a5
-; RV64I-NEXT:    slli a5, a1, 23
-; RV64I-NEXT:    sub a3, a3, a5
-; RV64I-NEXT:    slli a1, a1, 27
-; RV64I-NEXT:    add a2, a2, a4
+; RV64I-NEXT:    slli a2, a1, 9
+; RV64I-NEXT:    sub a2, a2, a1
+; RV64I-NEXT:    slli a2, a2, 3
+; RV64I-NEXT:    add a2, a2, a1
+; RV64I-NEXT:    slli a2, a2, 5
+; RV64I-NEXT:    sub a2, a2, a1
+; RV64I-NEXT:    slli a2, a2, 2
+; RV64I-NEXT:    add a2, a2, a1
+; RV64I-NEXT:    slli a3, a2, 4
+; RV64I-NEXT:    sub a3, a3, a2
+; RV64I-NEXT:    slli a3, a3, 4
 ; RV64I-NEXT:    add a1, a3, a1
-; RV64I-NEXT:    add a1, a2, a1
 ; RV64I-NEXT:    srliw a1, a1, 27
 ; RV64I-NEXT:    lui a2, %hi(.LCPI8_0)
 ; RV64I-NEXT:    addi a2, a2, %lo(.LCPI8_0)
@@ -560,30 +536,22 @@ define signext i32 @ffs_i32(i32 signext %a) nounwind {
 ; RV64I:       # %bb.0:
 ; RV64I-NEXT:    neg a1, a0
 ; RV64I-NEXT:    and a1, a0, a1
-; RV64I-NEXT:    slli a2, a1, 6
-; RV64I-NEXT:    slli a3, a1, 8
-; RV64I-NEXT:    slli a4, a1, 10
-; RV64I-NEXT:    slli a5, a1, 12
-; RV64I-NEXT:    add a2, a2, a3
-; RV64I-NEXT:    slli a3, a1, 16
-; RV64I-NEXT:    sub a4, a4, a5
-; RV64I-NEXT:    slli a5, a1, 18
-; RV64I-NEXT:    sub a3, a3, a5
-; RV64I-NEXT:    slli a5, a1, 4
-; RV64I-NEXT:    sub a5, a1, a5
-; RV64I-NEXT:    add a2, a5, a2
-; RV64I-NEXT:    slli a5, a1, 14
-; RV64I-NEXT:    sub a4, a4, a5
-; RV64I-NEXT:    slli a5, a1, 23
-; RV64I-NEXT:    sub a3, a3, a5
-; RV64I-NEXT:    add a2, a2, a4
-; RV64I-NEXT:    lui a4, %hi(.LCPI9_0)
-; RV64I-NEXT:    addi a4, a4, %lo(.LCPI9_0)
-; RV64I-NEXT:    slli a1, a1, 27
+; RV64I-NEXT:    slli a2, a1, 9
+; RV64I-NEXT:    sub a2, a2, a1
+; RV64I-NEXT:    slli a2, a2, 3
+; RV64I-NEXT:    add a2, a2, a1
+; RV64I-NEXT:    slli a2, a2, 5
+; RV64I-NEXT:    sub a2, a2, a1
+; RV64I-NEXT:    slli a2, a2, 2
+; RV64I-NEXT:    add a2, a2, a1
+; RV64I-NEXT:    slli a3, a2, 4
+; RV64I-NEXT:    sub a3, a3, a2
+; RV64I-NEXT:    lui a2, %hi(.LCPI9_0)
+; RV64I-NEXT:    addi a2, a2, %lo(.LCPI9_0)
+; RV64I-NEXT:    slli a3, a3, 4
 ; RV64I-NEXT:    add a1, a3, a1
-; RV64I-NEXT:    add a1, a2, a1
 ; RV64I-NEXT:    srliw a1, a1, 27
-; RV64I-NEXT:    add a1, a4, a1
+; RV64I-NEXT:    add a1, a2, a1
 ; RV64I-NEXT:    lbu a1, 0(a1)
 ; RV64I-NEXT:    seqz a0, a0
 ; RV64I-NEXT:    addi a1, a1, 1
diff --git a/llvm/test/CodeGen/RISCV/rv64zbb.ll b/llvm/test/CodeGen/RISCV/rv64zbb.ll
index e840605710f21..5daeef344a4ef 100644
--- a/llvm/test/CodeGen/RISCV/rv64zbb.ll
+++ b/llvm/test/CodeGen/RISCV/rv64zbb.ll
@@ -343,26 +343,18 @@ define signext i32 @cttz_i32(i32 signext %a) nounwind {
 ; RV64I-NEXT:  # %bb.1: # %cond.false
 ; RV64I-NEXT:    neg a1, a0
 ; RV64I-NEXT:    and a0, a0, a1
-; RV64I-NEXT:    slli a1, a0, 6
-; RV64I-NEXT:    slli a2, a0, 8
-; RV64I-NEXT:    slli a3, a0, 10
-; RV64I-NEXT:    slli a4, a0, 12
-; RV64I-NEXT:    add a1, a1, a2
-; RV64I-NEXT:    slli a2, a0, 16
-; RV64I-NEXT:    sub a3, a3, a4
-; RV64I-NEXT:    slli a4, a0, 18
-; RV64I-NEXT:    sub a2, a2, a4
-; RV64I-NEXT:    slli a4, a0, 4
-; RV64I-NEXT:    sub a4, a0, a4
-; RV64I-NEXT:    add a1, a4, a1
-; RV64I-NEXT:    slli a4, a0, 14
-; RV64I-NEXT:    sub a3, a3, a4
-; RV64I-NEXT:    slli a4, a0, 23
-; RV64I-NEXT:    sub a2, a2, a4
-; RV64I-NEXT:    slli a0, a0, 27
-; RV64I-NEXT:    add a1, a1, a3
+; RV64I-NEXT:    slli a1, a0, 9
+; RV64I-NEXT:    sub a1, a1, a0
+; RV64I-NEXT:    slli a1, a1, 3
+; RV64I-NEXT:    add a1, a1, a0
+; RV64I-NEXT:    slli a1, a1, 5
+; RV64I-NEXT:    sub a1, a1, a0
+; RV64I-NEXT:    slli a1, a1, 2
+; RV64I-NEXT:    add a1, a1, a0
+; RV64I-NEXT:    slli a2, a1, 4
+; RV64I-NEXT:    sub a2, a2, a1
+; RV64I-NEXT:    slli a2, a2, 4
 ; RV64I-NEXT:    add a0, a2, a0
-; RV64I-NEXT:    add a0, a1, a0
 ; RV64I-NEXT:    srliw a0, a0, 27
 ; RV64I-NEXT:    lui a1, %hi(.LCPI6_0)
 ; RV64I-NEXT:    addi a1, a1, %lo(.LCPI6_0)
@@ -386,26 +378,18 @@ define signext i32 @cttz_zero_undef_i32(i32 signext %a) nounwind {
 ; RV64I:       # %bb.0:
 ; RV64I-NEXT:    neg a1, a0
 ; RV64I-NEXT:    and a0, a0, a1
-; RV64I-NEXT:    slli a1, a0, 6
-; RV64I-NEXT:    slli a2, a0, 8
-; RV64I-NEXT:    slli a3, a0, 10
-; RV64I-NEXT:    slli a4, a0, 12
-; RV64I-NEXT:    add a1, a1, a2
-; RV64I-NEXT:    slli a2, a0, 16
-; RV64I-NEXT:    sub a3, a3, a4
-; RV64I-NEXT:    slli a4, a0, 18
-; RV64I-NEXT:    sub a2, a2, a4
-; RV64I-NEXT:    slli a4, a0, 4
-; RV64I-NEXT:    sub a4, a0, a4
-; RV64I-NEXT:    add a1, a4, a1
-; RV64I-NEXT:    slli a4, a0, 14
-; RV64I-NEXT:    sub a3, a3, a4
-; RV64I-NEXT:    slli a4, a0, 23
-; RV64I-NEXT:    sub a2, a2, a4
-; RV64I-NEXT:    slli a0, a0, 27
-; RV64I-NEXT:    add a1, a1, a3
+; RV64I-NEXT:    slli a1, a0, 9
+; RV64I-NEXT:    sub a1, a1, a0
+; RV64I-NEXT:    slli a1, a1, 3
+; RV64I-NEXT:    add a1, a1, a0
+; RV64I-NEXT:    slli a1, a1, 5
+; RV64I-NEXT:    sub a1, a1, a0
+; RV64I-NEXT:    slli a1, a1, 2
+; RV64I-NEXT:    add a1, a1, a0
+; RV64I-NEXT:    slli a2, a1, 4
+; RV64I-NEXT:    sub a2, a2, a1
+; RV64I-NEXT:    slli a2, a2, 4
 ; RV64I-NEXT:    add a0, a2, a0
-; RV64I-NEXT:    add a0, a1, a0
 ; RV64I-NEXT:    srliw a0, a0, 27
 ; RV64I-NEXT:    lui a1, %hi(.LCPI7_0)
 ; RV64I-NEXT:    addi a1, a1, %lo(.LCPI7_0)
@@ -426,26 +410,18 @@ define signext i32 @findFirstSet_i32(i32 signext %a) nounwind {
 ; RV64I:       # %bb.0:
 ; RV64I-NEXT:    neg a1, a0
 ; RV64I-NEXT:    and a1, a0, a1
-; RV64I-NEXT:    slli a2, a1, 6
-; RV64I-NEXT:    slli a3, a1, 8
-; RV64I-NEXT:    slli a4, a1, 10
-; RV64I-NEXT:    slli a5, a1, 12
-; RV64I-NEXT:    add a2, a2, a3
-; RV64I-NEXT:    slli a3, a1, 16
-; RV64I-NEXT:    sub a4, a4, a5
-; RV64I-NEXT:    slli a5, a1, 18
-; RV64I-NEXT:    sub a3, a3, a5
-; RV64I-NEXT:    slli a5, a1, 4
-; RV64I-NEXT:    sub a5, a1, a5
-; RV64I-NEXT:    add a2, a5, a2
-; RV64I-NEXT:    slli a5, a1, 14
-; RV64I-NEXT:    sub a4, a4, a5
-; RV64I-NEXT:    slli a5, a1, 23
-; RV64I-NEXT:    sub a3, a3, a5
-; RV64I-NEXT:    slli a1, a1, 27
-; RV64I-NEXT:    add a2, a2, a4
+; RV64I-NEXT:    slli a2, a1, 9
+; RV64I-NEXT:    sub a2, a2, a1
+; RV64I-NEXT:    slli a2, a2, 3
+; RV64I-NEXT:    add a2, a2, a1
+; RV64I-NEXT:    slli a2, a2, 5
+; RV64I-NEXT:    sub a2, a2, a1
+; RV64I-NEXT:    slli a2, a2, 2
+; RV64I-NEXT:    add a2, a2, a1
+; RV64I-NEXT:    slli a3, a2, 4
+; RV64I-NEXT:    sub a3, a3, a2
+; RV64I-NEXT:    slli a3, a3, 4
 ; RV64I-NEXT:    add a1, a3, a1
-; RV64I-NEXT:    add a1, a2, a1
 ; RV64I-NEXT:    srliw a1, a1, 27
 ; RV64I-NEXT:    lui a2, %hi(.LCPI8_0)
 ; RV64I-NEXT:    addi a2, a2, %lo(.LCPI8_0)
@@ -474,30 +450,22 @@ define signext i32 @ffs_i32(i32 signext %a) nounwind {
 ; RV64I:       # %bb.0:
 ; RV64I-NEXT:    neg a1, a0
 ; RV64I-NEXT:    and a1, a0, a1
-; RV64I-NEXT:    slli a2, a1, 6
-; RV64I-NEXT:    slli a3, a1, 8
-; RV64I-NEXT:    slli a4, a1, 10
-; RV64I-NEXT:    slli a5, a1, 12
-; RV64I-NEXT:    add a2, a2, a3
-; RV64I-NEXT:    slli a3, a1, 16
-; RV64I-NEXT:    sub a4, a4, a5
-; RV64I-NEXT:    slli a5, a1, 18
-; RV64I-NEXT:    sub a3, a3, a5
-; RV64I-NEXT:    slli a5, a1, 4
-; RV64I-NEXT:    sub a5, a1, a5
-; RV64I-NEXT:    add a2, a5, a2
-; RV64I-NEXT:    slli a5, a1, 14
-; RV64I-NEXT:    sub a4, a4, a5
-; RV64I-NEXT:    slli a5, a1, 23
-; RV64I-NEXT:    sub a3, a3, a5
-; RV64I-NEXT:    add a2, a2, a4
-; RV64I-NEXT:    lui a4, %hi(.LCPI9_0)
-; RV64I-NEXT:    addi a4, a4, %lo(.LCPI9_0)
-; RV64I-NEXT:    slli a1, a1, 27
+; RV64I-NEXT:    slli a2, a1, 9
+; RV64I-NEXT:    sub a2, a2, a1
+; RV64I-NEXT:    slli a2, a2, 3
+; RV64I-NEXT:    add a2, a2, a1
+; RV64I-NEXT:    slli a2, a2, 5
+; RV64I-NEXT:    sub a2, a2, a1
+; RV64I-NEXT:    slli a2, a2, 2
+; RV64I-NEXT:    add a2, a2, a1
+; RV64I-NEXT:    slli a3, a2, 4
+; RV64I-NEXT:    sub a3, a3, a2
+; RV64I-NEXT:    lui a2, %hi(.LCPI9_0)
+; RV64I-NEXT:    addi a2, a2, %lo(.LCPI9_0)
+; RV64I-NEXT:    slli a3, a3, 4
 ; RV64I-NEXT:    add a1, a3, a1
-; RV64I-NEXT:    add a1, a2, a1
 ; RV64I-NEXT:    srliw a1, a1, 27
-; RV64I-NEXT:    add a1, a4, a1
+; RV64I-NEXT:    add a1, a2, a1
 ; RV64I-NEXT:    lbu a1, 0(a1)
 ; RV64I-NEXT:    seqz a0, a0
 ; RV64I-NEXT:    addi a1, a1, 1
diff --git a/llvm/test/CodeGen/RISCV/rvv/known-never-zero.ll b/llvm/test/CodeGen/RISCV/rvv/known-never-zero.ll
index 9687dced7eb2e..9d8ba1081328e 100644
--- a/llvm/test/CodeGen/RISCV/rvv/known-never-zero.ll
+++ b/llvm/test/CodeGen/RISCV/rvv/known-never-zero.ll
@@ -11,27 +11,19 @@ define i32 @vscale_known_nonzero() {
 ; CHECK:       # %bb.0:
 ; CHECK-NEXT:    csrr a0, vlenb
 ; CHECK-NEXT:    srli a1, a0, 3
-; CHECK-NEXT:    slli a2, a0, 1
-; CHECK-NEXT:    slli a3, a0, 3
-; CHECK-NEXT:    slli a4, a0, 5
-; CHECK-NEXT:    slli a5, a0, 7
-; CHECK-NEXT:    sub a1, a1, a2
-; CHECK-NEXT:    slli a2, a0, 9
-; CHECK-NEXT:    add a3, a3, a4
-; CHECK-NEXT:    slli a4, a0, 13
-; CHECK-NEXT:    sub a5, a5, a2
-; CHECK-NEXT:    slli a2, a0, 15
-; CHECK-NEXT:    sub a4, a4, a2
-; CHECK-NEXT:    add a1, a1, a3
-; CHECK-NEXT:    slli a2, a0, 11
-; CHECK-NEXT:    sub a5, a5, a2
-; CHECK-NEXT:    slli a2, a0, 20
-; CHECK-NEXT:    sub a4, a4, a2
-; CHECK-NEXT:    slli a0, a0, 24
-; CHECK-NEXT:    add a1, a1, a5
-; CHECK-NEXT:    add a0, a4, a0
-; CHECK-NEXT:    add a0, a1, a0
-; CHECK-NEXT:    srliw a0, a0, 27
+; CHECK-NEXT:    slli a0, a0, 6
+; CHECK-NEXT:    sub a0, a0, a1
+; CHECK-NEXT:    slli a0, a0, 3
+; CHECK-NEXT:    add a0, a0, a1
+; CHECK-NEXT:    slli a0, a0, 5
+; CHECK-NEXT:    sub a0, a0, a1
+; CHECK-NEXT:    slli a0, a0, 2
+; CHECK-NEXT:    add a0, a0, a1
+; CHECK-NEXT:    slli a2, a0, 4
+; CHECK-NEXT:    sub a2, a2, a0
+; CHECK-NEXT:    slli a2, a2, 4
+; CHECK-NEXT:    add a1, a2, a1
+; CHECK-NEXT:    srliw a0, a1, 27
 ; CHECK-NEXT:    lui a1, %hi(.LCPI0_0)
 ; CHECK-NEXT:    addi a1, a1, %lo(.LCPI0_0)
 ; CHECK-NEXT:    add a0, a1, a0
diff --git a/llvm/test/CodeGen/RISCV/srem-seteq-illegal-types.ll b/llvm/test/CodeGen/RISCV/srem-seteq-illegal-types.ll
index 06bbe5209df35..cb19de2eb7da6 100644
--- a/llvm/test/CodeGen/RISCV/srem-seteq-illegal-types.ll
+++ b/llvm/test/CodeGen/RISCV/srem-seteq-illegal-types.ll
@@ -9,62 +9,58 @@
 define i1 @test_srem_odd(i29 %X) nounwind {
 ; RV32-LABEL: test_srem_odd:
 ; RV32:       # %bb.0:
-; RV32-NEXT:    slli a1, a0, 4
-; RV32-NEXT:    slli a2, a0, 6
-; RV32-NEXT:    slli a3, a0, 8
-; RV32-NEXT:    slli a4, a0, 15
-; RV32-NEXT:    add a1, a1, a2
-; RV32-NEXT:    slli a2, a0, 19
-; RV32-NEXT:    add a3, a3, a4
-; RV32-NEXT:    slli a4, a0, 21
-; RV32-NEXT:    add a2, a2, a4
-; RV32-NEXT:    slli a4, a0, 2
-; RV32-NEXT:    add a4, a0, a4
-; RV32-NEXT:    sub a1, a1, a4
-; RV32-NEXT:    slli a4, a0, 17
-; RV32-NEXT:    add a3, a3, a4
-; RV32-NEXT:    slli a0, a0, 23
-; RV32-NEXT:    add a0, a2, a0
-; RV32-NEXT:    lui a2, 662
-; RV32-NEXT:    add a1, a1, a3
-; RV32-NEXT:    lui a3, 1324
-; RV32-NEXT:    addi a2, a2, -83
-; RV32-NEXT:    sub a0, a0, a2
+; RV32-NEXT:    slli a1, a0, 1
+; RV32-NEXT:    add a1, a1, a0
+; RV32-NEXT:    slli a1, a1, 4
 ; RV32-NEXT:    sub a1, a1, a0
+; RV32-NEXT:    slli a1, a1, 5
+; RV32-NEXT:    add a1, a1, a0
+; RV32-NEXT:    slli a2, a1, 4
+; RV32-NEXT:    add a1, a2, a1
 ; RV32-NEXT:    slli a1, a1, 3
-; RV32-NEXT:    srli a1, a1, 3
-; RV32-NEXT:    addi a0, a3, -165
-; RV32-NEXT:    sltu a0, a1, a0
+; RV32-NEXT:    sub a1, a1, a0
+; RV32-NEXT:    slli a2, a1, 8
+; RV32-NEXT:    add a1, a2, a1
+; RV32-NEXT:    lui a2, 662
+; RV32-NEXT:    slli a1, a1, 1
+; RV32-NEXT:    add a0, a1, a0
+; RV32-NEXT:    lui a1, 1324
+; RV32-NEXT:    addi a2, a2, -83
+; RV32-NEXT:    add a2, a0, a2
+; RV32-NEXT:    slli a0, a0, 2
+; RV32-NEXT:    add a0, a0, a2
+; RV32-NEXT:    slli a0, a0, 3
+; RV32-NEXT:    srli a0, a0, 3
+; RV32-NEXT:    addi a1, a1, -165
+; RV32-NEXT:    sltu a0, a0, a1
 ; RV32-NEXT:    ret
 ;
 ; RV64-LABEL: test_srem_odd:
 ; RV64:       # %bb.0:
-; RV64-NEXT:    slli a1, a0, 4
-; RV64-NEXT:    slli a2, a0, 6
-; RV64-NEXT:    slli a3, a0, 8
-; RV64-NEXT:    slli a4, a0, 15
-; RV64-NEXT:    add a1, a1, a2
-; RV64-NEXT:    slli a2, a0, 19
-; RV64-NEXT:    add a3, a3, a4
-; RV64-NEXT:    slli a4, a0, 21
-; RV64-NEXT:    add a2, a2, a4
-; RV64-NEXT:    slli a4, a0, 2
-; RV64-NEXT:    add a4, a0, a4
-; RV64-NEXT:    sub a1, a1, a4
-; RV64-NEXT:    slli a4, a0, 17
-; RV64-NEXT:    add a3, a3, a4
-; RV64-NEXT:    slli a0, a0, 23
-; RV64-NEXT:    add a0, a2, a0
+; RV64-NEXT:    slli a1, a0, 1
+; RV64-NEXT:    add a1, a1, a0
+; RV64-NEXT:    slli a1, a1, 4
+; RV64-NEXT:    sub a1, a1, a0
+; RV64-NEXT:    slli a1, a1, 5
+; RV64-NEXT:    add a1, a1, a0
+; RV64-NEXT:    slli a2, a1, 4
+; RV64-NEXT:    add a1, a2, a1
+; RV64-NEXT:    slli a1, a1, 3
+; RV64-NEXT:    sub a1, a1, a0
+; RV64-NEXT:    slli a2, a1, 8
+; RV64-NEXT:    add a1, a2, a1
 ; RV64-NEXT:    lui a2, 662
-; RV64-NEXT:    add a1, a1, a3
-; RV64-NEXT:    lui a3, 1324
+; RV64-NEXT:    slli a1, a1, 1
+; RV64-NEXT:    add a0, a1, a0
+; RV64-NEXT:    lui a1, 1324
 ; RV64-NEXT:    addi a2, a2, -83
-; RV64-NEXT:    sub a0, a0, a2
-; RV64-NEXT:    sub a1, a1, a0
-; RV64-NEXT:    slli a1, a1, 35
-; RV64-NEXT:    srli a1, a1, 35
-; RV64-NEXT:    addi a0, a3, -165
-; RV64-NEXT:    sltu a0, a1, a0
+; RV64-NEXT:    add a2, a0, a2
+; RV64-NEXT:    slli a0, a0, 2
+; RV64-NEXT:    add a0, a0, a2
+; RV64-NEXT:    slli a0, a0, 35
+; RV64-NEXT:    srli a0, a0, 35
+; RV64-NEXT:    addi a1, a1, -165
+; RV64-NEXT:    sltu a0, a0, a1
 ; RV64-NEXT:    ret
 ;
 ; RV32M-LABEL: test_srem_odd:
@@ -415,102 +411,51 @@ define void @test_srem_vec(ptr %X) nounwind {
 ; RV64-NEXT:    slli a1, a1, 62
 ; RV64-NEXT:    or a1, a1, a2
 ; RV64-NEXT:    slli a2, s3, 31
-; RV64-NEXT:    slli a3, a0, 29
+; RV64-NEXT:    slli s1, a0, 29
 ; RV64-NEXT:    srai a0, a1, 31
-; RV64-NEXT:    srai s2, a3, 31
+; RV64-NEXT:    srai s1, s1, 31
 ; RV64-NEXT:    srai s4, a2, 31
 ; RV64-NEXT:    li a1, 7
 ; RV64-NEXT:    call __moddi3
-; RV64-NEXT:    mv s1, a0
+; RV64-NEXT:    mv s2, a0
 ; RV64-NEXT:    li a1, -5
-; RV64-NEXT:    mv a0, s2
+; RV64-NEXT:    mv a0, s1
 ; RV64-NEXT:    call __moddi3
-; RV64-NEXT:    slli a1, s4, 4
-; RV64-NEXT:    slli a2, s4, 6
-; RV64-NEXT:    slli a3, s4, 8
-; RV64-NEXT:    slli a4, s4, 10
-; RV64-NEXT:    slli a5, s4, 14
-; RV64-NEXT:    slli a6, s4, 16
-; RV64-NEXT:    slli a7, s4, 22
-; RV64-NEXT:    add a1, a1, a2
-; RV64-NEXT:    slli a2, s4, 24
-; RV64-NEXT:    add a3, a3, a4
-; RV64-NEXT:    slli a4, s3, 32
-; RV64-NEXT:    add a5, a5, a6
-; RV64-NEXT:    slli a6, s3, 34
-; RV64-NEXT:    add a2, a7, a2
-; RV64-NEXT:    slli a7, s3, 48
-; RV64-NEXT:    add a4, a4, a6
-; RV64-NEXT:    slli a6, s3, 50
-; RV64-NEXT:    add a6, a7, a6
-; RV64-NEXT:    slli a7, s4, 2
-; RV64-NEXT:    add a7, s4, a7
-; RV64-NEXT:    add a1, a7, a1
-; RV64-NEXT:    slli a7, s4, 12
-; RV64-NEXT:    add a3, a3, a7
-; RV64-NEXT:    slli a7, s4, 18
-; RV64-NEXT:    add a5, a5, a7
-; RV64-NEXT:    slli a7, s4, 26
-; RV64-NEXT:    add a2, a2, a7
-; RV64-NEXT:    slli a7, s3, 36
-; RV64-NEXT:    add a4, a4, a7
-; RV64-NEXT:    slli a7, s3, 52
-; RV64-NEXT:    add a6, a6, a7
-; RV64-NEXT:    add a1, a1, a3
-; RV64-NEXT:    slli a3, s4, 20
-; RV64-NEXT:    add a3, a5, a3
-; RV64-NEXT:    slli a5, s4, 28
-; RV64-NEXT:    add a2, a2, a5
-; RV64-NEXT:    slli a5, s3, 38
-; RV64-NEXT:    add a4, a4, a5
-; RV64-NEXT:    slli a5, s3, 54
-; RV64-NEXT:    add a5, a6, a5
-; RV64-NEXT:    add a1, a1, a3
-; RV64-NEXT:    slli s4, s4, 30
-; RV64-NEXT:    add a2, a2, s4
-; RV64-NEXT:    slli a3, s3, 40
-; RV64-NEXT:    add a3, a4, a3
-; RV64-NEXT:    slli a4, s3, 56
-; RV64-NEXT:    add a4, a5, a4
-; RV64-NEXT:    slli a5, s3, 42
-; RV64-NEXT:    add a1, a1, a2
-; RV64-NEXT:    slli a2, s3, 58
+; RV64-NEXT:    neg a1, s3
+; RV64-NEXT:    lui a2, %hi(.LCPI3_0)
 ; RV64-NEXT:    addi a0, a0, -2
-; RV64-NEXT:    addi s1, s1, -1
+; RV64-NEXT:    addi s2, s2, -1
+; RV64-NEXT:    slli a1, a1, 32
+; RV64-NEXT:    ld a2, %lo(.LCPI3_0)(a2)
 ; RV64-NEXT:    seqz a0, a0
-; RV64-NEXT:    seqz a6, s1
-; RV64-NEXT:    addi a6, a6, -1
+; RV64-NEXT:    seqz a3, s2
+; RV64-NEXT:    sub a1, a1, s4
+; RV64-NEXT:    addi a3, a3, -1
 ; RV64-NEXT:    addi a0, a0, -1
-; RV64-NEXT:    add a3, a3, a5
+; RV64-NEXT:    slli a4, a1, 16
 ; RV64-NEXT:    slli a5, a0, 2
-; RV64-NEXT:    add a2, a4, a2
-; RV64-NEXT:    slli a4, a6, 31
+; RV64-NEXT:    add a1, a4, a1
+; RV64-NEXT:    slli a4, a3, 31
 ; RV64-NEXT:    srli a4, a4, 62
 ; RV64-NEXT:    or a4, a4, a5
-; RV64-NEXT:    slli a5, s3, 44
-; RV64-NEXT:    add a3, a3, a5
-; RV64-NEXT:    slli a5, s3, 60
-; RV64-NEXT:    add a2, a2, a5
-; RV64-NEXT:    slli a5, s3, 46
-; RV64-NEXT:    add a3, a3, a5
-; RV64-NEXT:    slli s3, s3, 62
-; RV64-NEXT:    add a2, a2, s3
-; RV64-NEXT:    lui a5, %hi(.LCPI3_0)
-; RV64-NEXT:    ld a5, %lo(.LCPI3_0)(a5)
+; RV64-NEXT:    slli a5, a1, 8
+; RV64-NEXT:    add a1, a5, a1
+; RV64-NEXT:    slli a5, a1, 4
+; RV64-NEXT:    add a1, a5, a1
+; RV64-NEXT:    slli a5, a1, 2
+; RV64-NEXT:    add a1, a1, a2
+; RV64-NEXT:    add a1, a5, a1
+; RV64-NEXT:    slli a5, a1, 63
+; RV64-NEXT:    srli a1, a1, 1
+; RV64-NEXT:    or a1, a1, a5
 ; RV64-NEXT:    slli a0, a0, 29
-; RV64-NEXT:    slli a6, a6, 33
+; RV64-NEXT:    slli a3, a3, 33
 ; RV64-NEXT:    srli a0, a0, 61
-; RV64-NEXT:    add a1, a1, a3
-; RV64-NEXT:    sub a2, a5, a2
-; RV64-NEXT:    sub a2, a2, a1
-; RV64-NEXT:    slli a1, a2, 63
-; RV64-NEXT:    srli a2, a2, 1
-; RV64-NEXT:    or a1, a2, a1
-; RV64-NEXT:    sltu a1, a5, a1
+; RV64-NEXT:    sltu a1, a2, a1
 ; RV64-NEXT:    neg a1, a1
 ; RV64-NEXT:    slli a1, a1, 31
 ; RV64-NEXT:    srli a1, a1, 31
-; RV64-NEXT:    or a1, a1, a6
+; RV64-NEXT:    or a1, a1, a3
 ; RV64-NEXT:    sd a1, 0(s0)
 ; RV64-NEXT:    sw a4, 8(s0)
 ; RV64-NEXT:    sb a0, 12(s0)
diff --git a/llvm/test/CodeGen/RISCV/urem-seteq-illegal-types.ll b/llvm/test/CodeGen/RISCV/urem-seteq-illegal-types.ll
index ba9c926c57152..73f2644159c6a 100644
--- a/llvm/test/CodeGen/RISCV/urem-seteq-illegal-types.ll
+++ b/llvm/test/CodeGen/RISCV/urem-seteq-illegal-types.ll
@@ -10,17 +10,13 @@ define i1 @test_urem_odd(i13 %X) nounwind {
 ; RV32-LABEL: test_urem_odd:
 ; RV32:       # %bb.0:
 ; RV32-NEXT:    slli a1, a0, 4
-; RV32-NEXT:    slli a2, a0, 6
-; RV32-NEXT:    slli a3, a0, 8
-; RV32-NEXT:    sub a1, a1, a2
-; RV32-NEXT:    slli a2, a0, 10
-; RV32-NEXT:    sub a3, a3, a2
-; RV32-NEXT:    slli a2, a0, 2
-; RV32-NEXT:    sub a2, a0, a2
-; RV32-NEXT:    slli a0, a0, 12
-; RV32-NEXT:    add a1, a2, a1
-; RV32-NEXT:    add a0, a3, a0
-; RV32-NEXT:    add a0, a1, a0
+; RV32-NEXT:    add a1, a1, a0
+; RV32-NEXT:    slli a1, a1, 4
+; RV32-NEXT:    add a1, a1, a0
+; RV32-NEXT:    slli a2, a1, 2
+; RV32-NEXT:    sub a2, a2, a1
+; RV32-NEXT:    slli a2, a2, 2
+; RV32-NEXT:    add a0, a2, a0
 ; RV32-NEXT:    slli a0, a0, 19
 ; RV32-NEXT:    srli a0, a0, 19
 ; RV32-NEXT:    sltiu a0, a0, 1639
@@ -29,17 +25,13 @@ define i1 @test_urem_odd(i13 %X) nounwind {
 ; RV64-LABEL: test_urem_odd:
 ; RV64:       # %bb.0:
 ; RV64-NEXT:    slli a1, a0, 4
-; RV64-NEXT:    slli a2, a0, 6
-; RV64-NEXT:    slli a3, a0, 8
-; RV64-NEXT:    sub a1, a1, a2
-; RV64-NEXT:    slli a2, a0, 10
-; RV64-NEXT:    sub a3, a3, a2
-; RV64-NEXT:    slli a2, a0, 2
-; RV64-NEXT:    sub a2, a0, a2
-; RV64-NEXT:    slli a0, a0, 12
-; RV64-NEXT:    add a1, a2, a1
-; RV64-NEXT:    add a0, a3, a0
-; RV64-NEXT:    add a0, a1, a0
+; RV64-NEXT:    add a1, a1, a0
+; RV64-NEXT:    slli a1, a1, 4
+; RV64-NEXT:    add a1, a1, a0
+; RV64-NEXT:    slli a2, a1, 2
+; RV64-NEXT:    sub a2, a2, a1
+; RV64-NEXT:    slli a2, a2, 2
+; RV64-NEXT:    add a0, a2, a0
 ; RV64-NEXT:    slli a0, a0, 51
 ; RV64-NEXT:    srli a0, a0, 51
 ; RV64-NEXT:    sltiu a0, a0, 1639
@@ -92,63 +84,51 @@ define i1 @test_urem_odd(i13 %X) nounwind {
 define i1 @test_urem_even(i27 %X) nounwind {
 ; RV32-LABEL: test_urem_even:
 ; RV32:       # %bb.0:
-; RV32-NEXT:    slli a1, a0, 6
-; RV32-NEXT:    slli a2, a0, 9
-; RV32-NEXT:    slli a3, a0, 12
-; RV32-NEXT:    slli a4, a0, 15
-; RV32-NEXT:    add a1, a1, a2
-; RV32-NEXT:    slli a2, a0, 21
-; RV32-NEXT:    add a3, a3, a4
-; RV32-NEXT:    slli a4, a0, 24
-; RV32-NEXT:    add a2, a2, a4
-; RV32-NEXT:    slli a4, a0, 3
-; RV32-NEXT:    add a4, a0, a4
-; RV32-NEXT:    add a1, a4, a1
-; RV32-NEXT:    slli a4, a0, 18
-; RV32-NEXT:    add a3, a3, a4
-; RV32-NEXT:    slli a0, a0, 27
-; RV32-NEXT:    sub a0, a0, a2
-; RV32-NEXT:    lui a2, 2341
-; RV32-NEXT:    add a1, a1, a3
-; RV32-NEXT:    sub a0, a0, a1
-; RV32-NEXT:    slli a1, a0, 26
+; RV32-NEXT:    slli a1, a0, 12
+; RV32-NEXT:    add a1, a1, a0
+; RV32-NEXT:    slli a2, a1, 6
+; RV32-NEXT:    add a1, a2, a1
+; RV32-NEXT:    slli a2, a1, 3
+; RV32-NEXT:    add a1, a2, a1
+; RV32-NEXT:    slli a1, a1, 3
+; RV32-NEXT:    add a1, a1, a0
+; RV32-NEXT:    slli a2, a1, 2
+; RV32-NEXT:    sub a2, a2, a1
+; RV32-NEXT:    lui a1, 2341
+; RV32-NEXT:    slli a2, a2, 1
+; RV32-NEXT:    add a0, a2, a0
+; RV32-NEXT:    slli a2, a0, 26
 ; RV32-NEXT:    slli a0, a0, 5
 ; RV32-NEXT:    srli a0, a0, 6
-; RV32-NEXT:    or a0, a0, a1
+; RV32-NEXT:    or a0, a0, a2
 ; RV32-NEXT:    slli a0, a0, 5
 ; RV32-NEXT:    srli a0, a0, 5
-; RV32-NEXT:    addi a1, a2, -1755
+; RV32-NEXT:    addi a1, a1, -1755
 ; RV32-NEXT:    sltu a0, a0, a1
 ; RV32-NEXT:    ret
 ;
 ; RV64-LABEL: test_urem_even:
 ; RV64:       # %bb.0:
-; RV64-NEXT:    slli a1, a0, 6
-; RV64-NEXT:    slli a2, a0, 9
-; RV64-NEXT:    slli a3, a0, 12
-; RV64-NEXT:    slli a4, a0, 15
-; RV64-NEXT:    add a1, a1, a2
-; RV64-NEXT:    slli a2, a0, 21
-; RV64-NEXT:    add a3, a3, a4
-; RV64-NEXT:    slli a4, a0, 24
-; RV64-NEXT:    add a2, a2, a4
-; RV64-NEXT:    slli a4, a0, 3
-; RV64-NEXT:    add a4, a0, a4
-; RV64-NEXT:    add a1, a4, a1
-; RV64-NEXT:    slli a4, a0, 18
-; RV64-NEXT:    add a3, a3, a4
-; RV64-NEXT:    slli a0, a0, 27
-; RV64-NEXT:    sub a0, a0, a2
-; RV64-NEXT:    lui a2, 2341
-; RV64-NEXT:    add a1, a1, a3
-; RV64-NEXT:    sub a0, a0, a1
-; RV64-NEXT:    slli a1, a0, 26
+; RV64-NEXT:    slli a1, a0, 12
+; RV64-NEXT:    add a1, a1, a0
+; RV64-NEXT:    slli a2, a1, 6
+; RV64-NEXT:    add a1, a2, a1
+; RV64-NEXT:    slli a2, a1, 3
+; RV64-NEXT:    add a1, a2, a1
+; RV64-NEXT:    slli a1, a1, 3
+; RV64-NEXT:    add a1, a1, a0
+; RV64-NEXT:    slli a2, a1, 2
+; RV64-NEXT:    sub a2, a2, a1
+; RV64-NEXT:    lui a1, 2341
+; RV64-NEXT:    slli a2, a2, 1
+; RV64-NEXT:    add a0, a2, a0
+; RV64-NEXT:    slli a2, a0, 26
 ; RV64-NEXT:    slli a0, a0, 37
 ; RV64-NEXT:    srli a0, a0, 38
-; RV64-NEXT:    or a0, a0, a1
+; RV64-NEXT:    or a0, a0, a2
 ; RV64-NEXT:    slli a0, a0, 37
 ; RV64-NEXT:    srli a0, a0, 37
-; RV64-NEXT:    addi a1, a2, -1755
+; RV64-NEXT:    addi a1, a1, -1755
 ; RV64-NEXT:    sltu a0, a0, a1
 ; RV64-NEXT:    ret
 ;
@@ -288,13 +268,11 @@ define i1 @test_urem_odd_setne(i4 %X) nounwind {
 define i1 @test_urem_negative_odd(i9 %X) nounwind {
 ; RV32-LABEL: test_urem_negative_odd:
 ; RV32:       # %bb.0:
-; RV32-NEXT:    slli a1, a0, 2
-; RV32-NEXT:    slli a2, a0, 4
-; RV32-NEXT:    slli a3, a0, 6
-; RV32-NEXT:    sub a1, a1, a0
-; RV32-NEXT:    sub a2, a2, a3
-; RV32-NEXT:    sub a1, a1, a2
-; RV32-NEXT:    slli a0, a0, 8
+; RV32-NEXT:    slli a1, a0, 4
+; RV32-NEXT:    add a1, a1, a0
+; RV32-NEXT:    slli a2, a1, 3
+; RV32-NEXT:    add a1, a2, a1
+; RV32-NEXT:    slli a1, a1, 1
 ; RV32-NEXT:    add a0, a1, a0
 ; RV32-NEXT:    andi a0, a0, 511
 ; RV32-NEXT:    sltiu a0, a0, 2
@@ -303,13 +281,11 @@ define i1 @test_urem_negative_odd(i9 %X) nounwind {
 ;
 ; RV64-LABEL: test_urem_negative_odd:
 ; RV64:       # %bb.0:
-; RV64-NEXT:    slli a1, a0, 2
-; RV64-NEXT:    slli a2, a0, 4
-; RV64-NEXT:    slli a3, a0, 6
-; RV64-NEXT:    sub a1, a1, a0
-; RV64-NEXT:    sub a2, a2, a3
-; RV64-NEXT:    sub a1, a1, a2
-; RV64-NEXT:    slli a0, a0, 8
+; RV64-NEXT:    slli a1, a0, 4
+; RV64-NEXT:    add a1, a1, a0
+; RV64-NEXT:    slli a2, a1, 3
+; RV64-NEXT:    add a1, a2, a1
+; RV64-NEXT:    slli a1, a1, 1
 ; RV64-NEXT:    add a0, a1, a0
 ; RV64-NEXT:    andi a0, a0, 511
 ; RV64-NEXT:    sltiu a0, a0, 2
@@ -367,54 +343,49 @@ define void @test_urem_vec(ptr %X) nounwind {
 ; RV32-NEXT:    andi a2, a2, 2047
 ; RV32-NEXT:    or a1, a3, a1
 ; RV32-NEXT:    slli a3, a2, 2
-; RV32-NEXT:    slli a5, a2, 4
-; RV32-NEXT:    slli a6, a2, 6
-; RV32-NEXT:    slli a7, a2, 8
-; RV32-NEXT:    slli t0, a2, 10
 ; RV32-NEXT:    addi a4, a4, -1
 ; RV32-NEXT:    addi a1, a1, -2
-; RV32-NEXT:    add a2, a2, a3
-; RV32-NEXT:    add a5, a5, a6
-; RV32-NEXT:    sub a3, t0, a7
-; RV32-NEXT:    slli a6, a4, 3
-; RV32-NEXT:    slli a7, a4, 6
-; RV32-NEXT:    slli t0, a4, 9
-; RV32-NEXT:    add a2, a2, a5
-; RV32-NEXT:    slli a5, a1, 2
-; RV32-NEXT:    add a4, a4, a6
+; RV32-NEXT:    add a3, a3, a2
+; RV32-NEXT:    slli a5, a4, 1
 ; RV32-NEXT:    slli a6, a1, 4
-; RV32-NEXT:    add a7, a7, t0
-; RV32-NEXT:    slli t0, a1, 6
-; RV32-NEXT:    sub a6, a6, t0
-; RV32-NEXT:    slli t0, a1, 8
-; RV32-NEXT:    sub a5, a5, a1
-; RV32-NEXT:    slli a1, a1, 10
-; RV32-NEXT:    sub a1, t0, a1
-; RV32-NEXT:    sub a3, a3, a2
-; RV32-NEXT:    add a4, a4, a7
-; RV32-NEXT:    sub a2, a5, a6
-; RV32-NEXT:    slli a5, a3, 10
-; RV32-NEXT:    slli a3, a3, 21
-; RV32-NEXT:    neg a4, a4
-; RV32-NEXT:    sub a2, a2, a1
-; RV32-NEXT:    srli a3, a3, 22
-; RV32-NEXT:    andi a1, a4, 2047
-; RV32-NEXT:    andi a2, a2, 2047
-; RV32-NEXT:    or a3, a3, a5
-; RV32-NEXT:    sltiu a1, a1, 293
-; RV32-NEXT:    sltiu a2, a2, 2
+; RV32-NEXT:    slli a3, a3, 1
+; RV32-NEXT:    add a5, a5, a4
+; RV32-NEXT:    add a6, a6, a1
+; RV32-NEXT:    add a3, a3, a2
+; RV32-NEXT:    slli a5, a5, 2
+; RV32-NEXT:    slli a6, a6, 4
+; RV32-NEXT:    add a1, a6, a1
+; RV32-NEXT:    slli a6, a3, 5
+; RV32-NEXT:    add a5, a5, a4
+; RV32-NEXT:    sub a3, a6, a3
+; RV32-NEXT:    slli a5, a5, 4
+; RV32-NEXT:    slli a6, a1, 2
+; RV32-NEXT:    slli a3, a3, 1
+; RV32-NEXT:    add a4, a5, a4
+; RV32-NEXT:    sub a1, a6, a1
+; RV32-NEXT:    add a2, a3, a2
+; RV32-NEXT:    slli a3, a4, 3
+; RV32-NEXT:    andi a1, a1, 2047
+; RV32-NEXT:    slli a5, a2, 10
+; RV32-NEXT:    slli a2, a2, 21
+; RV32-NEXT:    sub a3, a3, a4
+; RV32-NEXT:    sltiu a1, a1, 2
+; RV32-NEXT:    srli a2, a2, 22
 ; RV32-NEXT:    andi a3, a3, 2047
+; RV32-NEXT:    xori a4, a1, 1
+; RV32-NEXT:    or a2, a2, a5
+; RV32-NEXT:    sltiu a3, a3, 293
 ; RV32-NEXT:    addi a1, a1, -1
-; RV32-NEXT:    xori a4, a2, 1
-; RV32-NEXT:    sltiu a3, a3, 342
-; RV32-NEXT:    addi a2, a2, -1
-; RV32-NEXT:    andi a1, a1, 2047
+; RV32-NEXT:    andi a2, a2, 2047
 ; RV32-NEXT:    addi a3, a3, -1
-; RV32-NEXT:    slli a1, a1, 11
-; RV32-NEXT:    slli a2, a2, 22
+; RV32-NEXT:    slli a1, a1, 22
+; RV32-NEXT:    sltiu a2, a2, 342
 ; RV32-NEXT:    andi a3, a3, 2047
-; RV32-NEXT:    or a1, a1, a2
+; RV32-NEXT:    addi a2, a2, -1
+; RV32-NEXT:    slli a3, a3, 11
+; RV32-NEXT:    andi a2, a2, 2047
 ; RV32-NEXT:    or a1, a3, a1
+; RV32-NEXT:    or a1, a2, a1
 ; RV32-NEXT:    sw a1, 0(a0)
 ; RV32-NEXT:    sb a4, 4(a0)
 ; RV32-NEXT:    ret
@@ -429,53 +400,48 @@ define void @test_urem_vec(ptr %X) nounwind {
 ; RV64-NEXT:    srli a3, a1, 11
 ; RV64-NEXT:    andi a1, a1, 2047
 ; RV64-NEXT:    slli a4, a1, 2
-; RV64-NEXT:    slli a5, a1, 4
-; RV64-NEXT:    slli a6, a1, 6
-; RV64-NEXT:    slli a7, a1, 8
-; RV64-NEXT:    slli t0, a1, 10
 ; RV64-NEXT:    addi a3, a3, -1
 ; RV64-NEXT:    addi a2, a2, -2
-; RV64-NEXT:    add a1, a1, a4
-; RV64-NEXT:    add a5, a5, a6
-; RV64-NEXT:    sub a4, t0, a7
-; RV64-NEXT:    slli a6, a3, 3
-; RV64-NEXT:    slli a7, a3, 6
-; RV64-NEXT:    slli t0, a3, 9
-; RV64-NEXT:    add a1, a1, a5
-; RV64-NEXT:    slli a5, a2, 2
-; RV64-NEXT:    add a3, a3, a6
-; RV64-NEXT:    slli a6, a2, 4
-; RV64-NEXT:    add a7, a7, t0
-; RV64-NEXT:    slli t0, a2, 6
-; RV64-NEXT:    sub a6, a6, t0
-; RV64-NEXT:    slli t0, a2, 8
-; RV64-NEXT:    sub a5, a5, a2
-; RV64-NEXT:    slli a2, a2, 10
-; RV64-NEXT:    sub a2, t0, a2
-; RV64-NEXT:    sub a4, a4, a1
-; RV64-NEXT:    add a3, a3, a7
-; RV64-NEXT:    sub a1, a5, a6
-; RV64-NEXT:    slli a5, a4, 10
-; RV64-NEXT:    slli a4, a4, 53
-; RV64-NEXT:    neg a3, a3
-; RV64-NEXT:    sub a1, a1, a2
-; RV64-NEXT:    srli a4, a4, 54
-; RV64-NEXT:    andi a2, a3, 2047
-; RV64-NEXT:    andi a1, a1, 2047
-; RV64-NEXT:    or a4, a4, a5
+; RV64-NEXT:    add a4, a4, a1
+; RV64-NEXT:    slli a5, a2, 4
+; RV64-NEXT:    slli a4, a4, 1
+; RV64-NEXT:    add a5, a5, a2
+; RV64-NEXT:    add a4, a4, a1
+; RV64-NEXT:    slli a5, a5, 4
+; RV64-NEXT:    add a2, a5, a2
+; RV64-NEXT:    slli a5, a4, 5
+; RV64-NEXT:    sub a5, a5, a4
+; RV64-NEXT:    slli a4, a3, 1
+; RV64-NEXT:    add a4, a4, a3
+; RV64-NEXT:    slli a4, a4, 2
+; RV64-NEXT:    add a4, a4, a3
+; RV64-NEXT:    slli a4, a4, 4
+; RV64-NEXT:    add a3, a4, a3
+; RV64-NEXT:    slli a4, a2, 2
+; RV64-NEXT:    slli a5, a5, 1
+; RV64-NEXT:    sub a4, a4, a2
+; RV64-NEXT:    add a1, a5, a1
+; RV64-NEXT:    slli a2, a3, 3
+; RV64-NEXT:    andi a4, a4, 2047
+; RV64-NEXT:    slli a5, a1, 10
+; RV64-NEXT:    slli a1, a1, 53
+; RV64-NEXT:    sub a2, a2, a3
+; RV64-NEXT:    sltiu a3, a4, 2
+; RV64-NEXT:    srli a1, a1, 54
+; RV64-NEXT:    andi a2, a2, 2047
+; RV64-NEXT:    addi a3, a3, -1
+; RV64-NEXT:    or a1, a1, a5
 ; RV64-NEXT:    sltiu a2, a2, 293
-; RV64-NEXT:    sltiu a1, a1, 2
-; RV64-NEXT:    andi a3, a4, 2047
-; RV64-NEXT:    addi a1, a1, -1
+; RV64-NEXT:    slli a3, a3, 22
+; RV64-NEXT:    andi a1, a1, 2047
 ; RV64-NEXT:    addi a2, a2, -1
-; RV64-NEXT:    sltiu a3, a3, 342
+; RV64-NEXT:    sltiu a1, a1, 342
 ; RV64-NEXT:    andi a2, a2, 2047
-; RV64-NEXT:    slli a1, a1, 22
-; RV64-NEXT:    addi a3, a3, -1
+; RV64-NEXT:    addi a1, a1, -1
 ; RV64-NEXT:    slli a2, a2, 11
-; RV64-NEXT:    andi a3, a3, 2047
-; RV64-NEXT:    or a1, a2, a1
-; RV64-NEXT:    or a1, a3, a1
+; RV64-NEXT:    andi a1, a1, 2047
+; RV64-NEXT:    or a2, a2, a3
+; RV64-NEXT:    or a1, a1, a2
 ; RV64-NEXT:    slli a2, a1, 31
 ; RV64-NEXT:    srli a2, a2, 63
 ; RV64-NEXT:    sw a1, 0(a0)
diff --git a/llvm/test/CodeGen/SPARC/constant_multiply.ll b/llvm/test/CodeGen/SPARC/constant_multiply.ll
index e5a1e428f19c4..89c66b2f161b7 100644
--- a/llvm/test/CodeGen/SPARC/constant_multiply.ll
+++ b/llvm/test/CodeGen/SPARC/constant_multiply.ll
@@ -6,12 +6,9 @@
 define i32 @mul_by_3(i32 %a) nounwind {
 ; CHECK-LABEL: mul_by_3:
 ; CHECK:       ! %bb.0:
-; CHECK-NEXT:    save %sp, -96, %sp
-; CHECK-NEXT:    mov %i0, %o0
-; CHECK-NEXT:    call .umul
-; CHECK-NEXT:    mov 3, %o1
-; CHECK-NEXT:    ret
-; CHECK-NEXT:    restore %g0, %o0, %o0
+; CHECK-NEXT:    sll %o0, 1, %o1
+; CHECK-NEXT:    retl
+; CHECK-NEXT:    add %o1, %o0, %o0
   %1 = mul i32 %a, 3
   ret i32 %1
 }
@@ -19,12 +16,9 @@ define i32 @mul_by_3(i32 %a) nounwind {
 define i32 @mul_by_5(i32 %a) nounwind {
 ; CHECK-LABEL: mul_by_5:
 ; CHECK:       ! %bb.0:
-; CHECK-NEXT:    save %sp, -96, %sp
-; CHECK-NEXT:    mov %i0, %o0
-; CHECK-NEXT:    call .umul
-; CHECK-NEXT:    mov 5, %o1
-; CHECK-NEXT:    ret
-; CHECK-NEXT:    restore %g0, %o0, %o0
+; CHECK-NEXT:    sll %o0, 2, %o1
+; CHECK-NEXT:    retl
+; CHECK-NEXT:    add %o1, %o0, %o0
   %1 = mul i32 %a, 5
   ret i32 %1
 }
@@ -32,12 +26,9 @@ define i32 @mul_by_5(i32 %a) nounwind {
 define i32 @mul_by_7(i32 %a) nounwind {
 ; CHECK-LABEL: mul_by_7:
 ; CHECK:       ! %bb.0:
-; CHECK-NEXT:    save %sp, -96, %sp
-; CHECK-NEXT:    mov %i0, %o0
-; CHECK-NEXT:    call .umul
-; CHECK-NEXT:    mov 7, %o1
-; CHECK-NEXT:    ret
-; CHECK-NEXT:    restore %g0, %o0, %o0
+; CHECK-NEXT:    sll %o0, 3, %o1
+; CHECK-NEXT:    retl
+; CHECK-NEXT:    sub %o1, %o0, %o0
   %1 = mul i32 %a, 7
   ret i32 %1
 }
@@ -45,12 +36,9 @@ define i32 @mul_by_7(i32 %a) nounwind {
 define i32 @mul_by_9(i32 %a) nounwind {
 ; CHECK-LABEL: mul_by_9:
 ; CHECK:       ! %bb.0:
-; CHECK-NEXT:    save %sp, -96, %sp
-; CHECK-NEXT:    mov %i0, %o0
-; CHECK-NEXT:    call .umul
-; CHECK-NEXT:    mov 9, %o1
-; CHECK-NEXT:    ret
-; CHECK-NEXT:    restore %g0, %o0, %o0
+; CHECK-NEXT:    sll %o0, 3, %o1
+; CHECK-NEXT:    retl
+; CHECK-NEXT:    add %o1, %o0, %o0
   %1 = mul i32 %a, 9
   ret i32 %1
 }
@@ -58,12 +46,10 @@ define i32 @mul_by_9(i32 %a) nounwind {
 define i32 @mul_by_10(i32 %a) nounwind {
 ; CHECK-LABEL: mul_by_10:
 ; CHECK:       ! %bb.0:
-; CHECK-NEXT:    save %sp, -96, %sp
-; CHECK-NEXT:    mov %i0, %o0
-; CHECK-NEXT:    call .umul
-; CHECK-NEXT:    mov 10, %o1
-; CHECK-NEXT:    ret
-; CHECK-NEXT:    restore %g0, %o0, %o0
+; CHECK-NEXT:    sll %o0, 2, %o1
+; CHECK-NEXT:    add %o1, %o0, %o0
+; CHECK-NEXT:    retl
+; CHECK-NEXT:    sll %o0, 1, %o0
   %1 = mul i32 %a, 10
   ret i32 %1
 }
@@ -71,12 +57,9 @@ define i32 @mul_by_10(i32 %a) nounwind {
 define i32 @mul_by_15(i32 %a) nounwind {
 ; CHECK-LABEL: mul_by_15:
 ; CHECK:       ! %bb.0:
-; CHECK-NEXT:    save %sp, -96, %sp
-; CHECK-NEXT:    mov %i0, %o0
-; CHECK-NEXT:    call .umul
-; CHECK-NEXT:    mov 15, %o1
-; CHECK-NEXT:    ret
-; CHECK-NEXT:    restore %g0, %o0, %o0
+; CHECK-NEXT:    sll %o0, 4, %o1
+; CHECK-NEXT:    retl
+; CHECK-NEXT:    sub %o1, %o0, %o0
   %1 = mul i32 %a, 15
   ret i32 %1
 }
@@ -84,12 +67,9 @@ define i32 @mul_by_15(i32 %a) nounwind {
 define i32 @mul_by_neg7(i32 %a) nounwind {
 ; CHECK-LABEL: mul_by_neg7:
 ; CHECK:       ! %bb.0:
-; CHECK-NEXT:    save %sp, -96, %sp
-; CHECK-NEXT:    mov %i0, %o0
-; CHECK-NEXT:    call .umul
-; CHECK-NEXT:    mov -7, %o1
-; CHECK-NEXT:    ret
-; CHECK-NEXT:    restore %g0, %o0, %o0
+; CHECK-NEXT:    sll %o0, 3, %o1
+; CHECK-NEXT:    retl
+; CHECK-NEXT:    sub %o0, %o1, %o0
   %1 = mul i32 %a, -7
   ret i32 %1
 }
@@ -97,12 +77,10 @@ define i32 @mul_by_neg7(i32 %a) nounwind {
 define i32 @mul_by_neg9(i32 %a) nounwind {
 ; CHECK-LABEL: mul_by_neg9:
 ; CHECK:       ! %bb.0:
-; CHECK-NEXT:    save %sp, -96, %sp
-; CHECK-NEXT:    mov %i0, %o0
-; CHECK-NEXT:    call .umul
-; CHECK-NEXT:    mov -9, %o1
-; CHECK-NEXT:    ret
-; CHECK-NEXT:    restore %g0, %o0, %o0
+; CHECK-NEXT:    sub %g0, %o0, %o1
+; CHECK-NEXT:    sll %o1, 3, %o1
+; CHECK-NEXT:    retl
+; CHECK-NEXT:    sub %o1, %o0, %o0
   %1 = mul i32 %a, -9
   ret i32 %1
 }
@@ -110,12 +88,9 @@ define i32 @mul_by_neg9(i32 %a) nounwind {
 define i32 @mul_by_65(i32 %a) nounwind {
 ; CHECK-LABEL: mul_by_65:
 ; CHECK:       ! %bb.0:
-; CHECK-NEXT:    save %sp, -96, %sp
-; CHECK-NEXT:    mov %i0, %o0
-; CHECK-NEXT:    call .umul
-; CHECK-NEXT:    mov 65, %o1
-; CHECK-NEXT:    ret
-; CHECK-NEXT:    restore %g0, %o0, %o0
+; CHECK-NEXT:    sll %o0, 6, %o1
+; CHECK-NEXT:    retl
+; CHECK-NEXT:    add %o1, %o0, %o0
   %1 = mul i32 %a, 65
   ret i32 %1
 }
@@ -123,12 +98,10 @@ define i32 @mul_by_65(i32 %a) nounwind {
 define i32 @mul_by_384(i32 %a) nounwind {
 ; CHECK-LABEL: mul_by_384:
 ; CHECK:       ! %bb.0:
-; CHECK-NEXT:    save %sp, -96, %sp
-; CHECK-NEXT:    mov %i0, %o0
-; CHECK-NEXT:    call .umul
-; CHECK-NEXT:    mov 384, %o1
-; CHECK-NEXT:    ret
-; CHECK-NEXT:    restore %g0, %o0, %o0
+; CHECK-NEXT:    sll %o0, 1, %o1
+; CHECK-NEXT:    add %o1, %o0, %o0
+; CHECK-NEXT:    retl
+; CHECK-NEXT:    sll %o0, 7, %o0
   %1 = mul i32 %a, 384
   ret i32 %1
 }



More information about the llvm-commits mailing list