[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