From bd418e7388eefdaf068fd015264639a910f0c5e2 Mon Sep 17 00:00:00 2001 From: Piotr Fusik 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 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 }