[llvm] [RISCV] Expand multiplication by `2^N * 3/5/9 + 1` with SHL_ADD (PR #166933)
Piotr Fusik via llvm-commits
llvm-commits at lists.llvm.org
Fri Nov 7 04:58:25 PST 2025
https://github.com/pfusik created https://github.com/llvm/llvm-project/pull/166933
None
>From bd418e7388eefdaf068fd015264639a910f0c5e2 Mon Sep 17 00:00:00 2001
From: Piotr Fusik <p.fusik at samsung.com>
Date: Fri, 7 Nov 2025 13:42:27 +0100
Subject: [PATCH 1/2] [RISCV][test] Multiplication by `2^N * 3/5/9 + 1` with
SHL_ADD
---
llvm/test/CodeGen/RISCV/rv64zba.ll | 58 ++++++++++++++++++++++++++++++
1 file changed, 58 insertions(+)
diff --git a/llvm/test/CodeGen/RISCV/rv64zba.ll b/llvm/test/CodeGen/RISCV/rv64zba.ll
index e56c7b41d43ce..994b1b324e880 100644
--- a/llvm/test/CodeGen/RISCV/rv64zba.ll
+++ b/llvm/test/CodeGen/RISCV/rv64zba.ll
@@ -944,6 +944,44 @@ define i64 @addmul146(i64 %a, i64 %b) {
ret i64 %d
}
+define i64 @mul49(i64 %a) {
+; CHECK-LABEL: mul49:
+; CHECK: # %bb.0:
+; CHECK-NEXT: li a1, 49
+; CHECK-NEXT: mul a0, a0, a1
+; CHECK-NEXT: ret
+ %c = mul i64 %a, 49
+ ret i64 %c
+}
+
+define i64 @zext_mul49(i32 signext %a) {
+; RV64I-LABEL: zext_mul49:
+; RV64I: # %bb.0:
+; RV64I-NEXT: li a1, 49
+; RV64I-NEXT: slli a1, a1, 32
+; RV64I-NEXT: slli a0, a0, 32
+; RV64I-NEXT: mulhu a0, a0, a1
+; RV64I-NEXT: ret
+;
+; RV64ZBA-LABEL: zext_mul49:
+; RV64ZBA: # %bb.0:
+; RV64ZBA-NEXT: zext.w a0, a0
+; RV64ZBA-NEXT: li a1, 49
+; RV64ZBA-NEXT: mul a0, a0, a1
+; RV64ZBA-NEXT: ret
+;
+; RV64XANDESPERF-LABEL: zext_mul49:
+; RV64XANDESPERF: # %bb.0:
+; RV64XANDESPERF-NEXT: li a1, 49
+; RV64XANDESPERF-NEXT: slli a1, a1, 32
+; RV64XANDESPERF-NEXT: slli a0, a0, 32
+; RV64XANDESPERF-NEXT: mulhu a0, a0, a1
+; RV64XANDESPERF-NEXT: ret
+ %b = zext i32 %a to i64
+ %c = mul i64 %b, 49
+ ret i64 %c
+}
+
define i64 @mul50(i64 %a) {
; RV64I-LABEL: mul50:
; RV64I: # %bb.0:
@@ -1044,6 +1082,26 @@ define i64 @addmul100(i64 %a, i64 %b) {
ret i64 %d
}
+define i64 @mul145(i64 %a) {
+; CHECK-LABEL: mul145:
+; CHECK: # %bb.0:
+; CHECK-NEXT: li a1, 145
+; CHECK-NEXT: mul a0, a0, a1
+; CHECK-NEXT: ret
+ %c = mul i64 %a, 145
+ ret i64 %c
+}
+
+define i64 @mul161(i64 %a) {
+; CHECK-LABEL: mul161:
+; CHECK: # %bb.0:
+; CHECK-NEXT: li a1, 161
+; CHECK-NEXT: mul a0, a0, a1
+; CHECK-NEXT: ret
+ %c = mul i64 %a, 161
+ ret i64 %c
+}
+
define i64 @mul162(i64 %a) {
; RV64I-LABEL: mul162:
; RV64I: # %bb.0:
>From c973f63b7f396bf52fe04ab30466501f398909a2 Mon Sep 17 00:00:00 2001
From: Piotr Fusik <p.fusik at samsung.com>
Date: Fri, 7 Nov 2025 13:43:22 +0100
Subject: [PATCH 2/2] [RISCV] Expand multiplication by `2^N * 3/5/9 + 1` with
SHL_ADD
---
llvm/lib/Target/RISCV/RISCVISelLowering.cpp | 15 +++-
llvm/test/CodeGen/RISCV/rv64zba.ll | 86 +++++++++++++++------
2 files changed, 77 insertions(+), 24 deletions(-)
diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
index c1d38419992b1..637a46c508c1f 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
@@ -16544,12 +16544,23 @@ static SDValue expandMulToShlAddShlAdd(SDNode *N, SelectionDAG &DAG,
break;
}
- // 2/4/8 * 3/5/9 + 1 -> (shXadd (shYadd X, X), X)
int ShX;
if (int ShY = isShifted359(MulAmt - 1, ShX)) {
assert(ShX != 0 && "MulAmt=4,6,10 handled before");
+ // 2/4/8 * 3/5/9 + 1 -> (shXadd (shYadd X, X), X)
if (ShX <= 3)
return getShlAddShlAdd(N, DAG, ShX, ShY, /*AddX=*/true, Shift);
+ // 2^N * 3/5/9 + 1 -> (add (shYadd (shl X, N), (shl X, N)), X)
+ if (Shift == 0) {
+ SDLoc DL(N);
+ EVT VT = N->getValueType(0);
+ SDValue X = N->getOperand(0);
+ SDValue Shl =
+ DAG.getNode(ISD::SHL, DL, VT, X, DAG.getConstant(ShX, DL, VT));
+ SDValue ShlAdd = DAG.getNode(RISCVISD::SHL_ADD, DL, VT, Shl,
+ DAG.getTargetConstant(ShY, DL, VT), Shl);
+ return DAG.getNode(ISD::ADD, DL, VT, ShlAdd, X);
+ }
}
return SDValue();
}
@@ -16610,7 +16621,7 @@ static SDValue expandMul(SDNode *N, SelectionDAG &DAG,
DAG.getTargetConstant(Shift, DL, VT), Shift1);
}
- // TODO: 2^(C1>3) * 3,5,9 +/- 1
+ // TODO: 2^(C1>3) * 3/5/9 - 1
// 2^n + 2/4/8 + 1 -> (add (shl X, C1), (shXadd X, X))
if (MulAmt > 2 && isPowerOf2_64((MulAmt - 1) & (MulAmt - 2))) {
diff --git a/llvm/test/CodeGen/RISCV/rv64zba.ll b/llvm/test/CodeGen/RISCV/rv64zba.ll
index 994b1b324e880..156599fb72877 100644
--- a/llvm/test/CodeGen/RISCV/rv64zba.ll
+++ b/llvm/test/CodeGen/RISCV/rv64zba.ll
@@ -945,11 +945,25 @@ define i64 @addmul146(i64 %a, i64 %b) {
}
define i64 @mul49(i64 %a) {
-; CHECK-LABEL: mul49:
-; CHECK: # %bb.0:
-; CHECK-NEXT: li a1, 49
-; CHECK-NEXT: mul a0, a0, a1
-; CHECK-NEXT: ret
+; RV64I-LABEL: mul49:
+; RV64I: # %bb.0:
+; RV64I-NEXT: li a1, 49
+; RV64I-NEXT: mul a0, a0, a1
+; RV64I-NEXT: ret
+;
+; RV64ZBA-LABEL: mul49:
+; RV64ZBA: # %bb.0:
+; RV64ZBA-NEXT: slli a1, a0, 4
+; RV64ZBA-NEXT: sh1add a1, a1, a1
+; RV64ZBA-NEXT: add a0, a1, a0
+; RV64ZBA-NEXT: ret
+;
+; RV64XANDESPERF-LABEL: mul49:
+; RV64XANDESPERF: # %bb.0:
+; RV64XANDESPERF-NEXT: slli a1, a0, 4
+; RV64XANDESPERF-NEXT: nds.lea.h a1, a1, a1
+; RV64XANDESPERF-NEXT: add a0, a1, a0
+; RV64XANDESPERF-NEXT: ret
%c = mul i64 %a, 49
ret i64 %c
}
@@ -965,17 +979,17 @@ define i64 @zext_mul49(i32 signext %a) {
;
; RV64ZBA-LABEL: zext_mul49:
; RV64ZBA: # %bb.0:
-; RV64ZBA-NEXT: zext.w a0, a0
-; RV64ZBA-NEXT: li a1, 49
-; RV64ZBA-NEXT: mul a0, a0, a1
+; RV64ZBA-NEXT: slli.uw a1, a0, 4
+; RV64ZBA-NEXT: sh1add a1, a1, a1
+; RV64ZBA-NEXT: add.uw a0, a0, a1
; RV64ZBA-NEXT: ret
;
; RV64XANDESPERF-LABEL: zext_mul49:
; RV64XANDESPERF: # %bb.0:
-; RV64XANDESPERF-NEXT: li a1, 49
-; RV64XANDESPERF-NEXT: slli a1, a1, 32
-; RV64XANDESPERF-NEXT: slli a0, a0, 32
-; RV64XANDESPERF-NEXT: mulhu a0, a0, a1
+; RV64XANDESPERF-NEXT: slli a1, a0, 32
+; RV64XANDESPERF-NEXT: srli a1, a1, 28
+; RV64XANDESPERF-NEXT: nds.lea.h a1, a1, a1
+; RV64XANDESPERF-NEXT: nds.lea.b.ze a0, a1, a0
; RV64XANDESPERF-NEXT: ret
%b = zext i32 %a to i64
%c = mul i64 %b, 49
@@ -1083,21 +1097,49 @@ define i64 @addmul100(i64 %a, i64 %b) {
}
define i64 @mul145(i64 %a) {
-; CHECK-LABEL: mul145:
-; CHECK: # %bb.0:
-; CHECK-NEXT: li a1, 145
-; CHECK-NEXT: mul a0, a0, a1
-; CHECK-NEXT: ret
+; RV64I-LABEL: mul145:
+; RV64I: # %bb.0:
+; RV64I-NEXT: li a1, 145
+; RV64I-NEXT: mul a0, a0, a1
+; RV64I-NEXT: ret
+;
+; RV64ZBA-LABEL: mul145:
+; RV64ZBA: # %bb.0:
+; RV64ZBA-NEXT: slli a1, a0, 4
+; RV64ZBA-NEXT: sh3add a1, a1, a1
+; RV64ZBA-NEXT: add a0, a1, a0
+; RV64ZBA-NEXT: ret
+;
+; RV64XANDESPERF-LABEL: mul145:
+; RV64XANDESPERF: # %bb.0:
+; RV64XANDESPERF-NEXT: slli a1, a0, 4
+; RV64XANDESPERF-NEXT: nds.lea.d a1, a1, a1
+; RV64XANDESPERF-NEXT: add a0, a1, a0
+; RV64XANDESPERF-NEXT: ret
%c = mul i64 %a, 145
ret i64 %c
}
define i64 @mul161(i64 %a) {
-; CHECK-LABEL: mul161:
-; CHECK: # %bb.0:
-; CHECK-NEXT: li a1, 161
-; CHECK-NEXT: mul a0, a0, a1
-; CHECK-NEXT: ret
+; RV64I-LABEL: mul161:
+; RV64I: # %bb.0:
+; RV64I-NEXT: li a1, 161
+; RV64I-NEXT: mul a0, a0, a1
+; RV64I-NEXT: ret
+;
+; RV64ZBA-LABEL: mul161:
+; RV64ZBA: # %bb.0:
+; RV64ZBA-NEXT: slli a1, a0, 5
+; RV64ZBA-NEXT: sh2add a1, a1, a1
+; RV64ZBA-NEXT: add a0, a1, a0
+; RV64ZBA-NEXT: ret
+;
+; RV64XANDESPERF-LABEL: mul161:
+; RV64XANDESPERF: # %bb.0:
+; RV64XANDESPERF-NEXT: slli a1, a0, 5
+; RV64XANDESPERF-NEXT: nds.lea.w a1, a1, a1
+; RV64XANDESPERF-NEXT: add a0, a1, a0
+; RV64XANDESPERF-NEXT: ret
%c = mul i64 %a, 161
ret i64 %c
}
More information about the llvm-commits
mailing list