[llvm] [RISCV] Expand `X * (2^N - 2^M)` where `N < M` (PR #168843)

via llvm-commits llvm-commits at lists.llvm.org
Thu Nov 20 02:01:50 PST 2025


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-backend-risc-v

Author: Piotr Fusik (pfusik)

<details>
<summary>Changes</summary>



---
Full diff: https://github.com/llvm/llvm-project/pull/168843.diff


5 Files Affected:

- (modified) llvm/lib/Target/RISCV/RISCVISelLowering.cpp (+16-10) 
- (modified) llvm/test/CodeGen/RISCV/mul.ll (+9-5) 
- (modified) llvm/test/CodeGen/RISCV/rv64xtheadba.ll (+3-2) 
- (modified) llvm/test/CodeGen/RISCV/rv64zba.ll (+3-2) 
- (modified) llvm/test/CodeGen/RISCV/srem-vector-lkk.ll (+11-10) 


``````````diff
diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
index 6020fb6ca16ce..3a0755d6af31d 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
@@ -16854,35 +16854,41 @@ static SDValue expandMulToNAFSequence(SDNode *N, SelectionDAG &DAG,
 // X * (2^N +/- 2^M) -> (add/sub (shl X, C1), (shl X, C2))
 static SDValue expandMulToAddOrSubOfShl(SDNode *N, SelectionDAG &DAG,
                                         uint64_t MulAmt) {
-  uint64_t MulAmtLowBit = MulAmt & (-MulAmt);
+  uint64_t MulAmtBit2 = MulAmt & (-MulAmt); // lowest set bit
   SDValue X = N->getOperand(0);
   ISD::NodeType Op;
-  uint64_t ShiftAmt1;
-  bool CanSub = isPowerOf2_64(MulAmt + MulAmtLowBit);
-  auto PreferSub = [X, MulAmtLowBit]() {
+  uint64_t MulAmtBit1;
+  bool CanSub = isPowerOf2_64(MulAmt + MulAmtBit2);
+  auto PreferSub = [X, MulAmtBit2]() {
     // For MulAmt == 3 << M both (X << M + 2) - (X << M)
     // and (X << M + 1) + (X << M) are valid expansions.
     // Prefer SUB if we can get (X << M + 2) for free,
     // because X is exact (Y >> M + 2).
-    uint64_t ShAmt = Log2_64(MulAmtLowBit) + 2;
+    uint64_t ShAmt = Log2_64(MulAmtBit2) + 2;
     using namespace SDPatternMatch;
     return sd_match(X, m_ExactSr(m_Value(), m_SpecificInt(ShAmt)));
   };
-  if (isPowerOf2_64(MulAmt - MulAmtLowBit) && !(CanSub && PreferSub())) {
+  if (isPowerOf2_64(MulAmt - MulAmtBit2) && !(CanSub && PreferSub())) {
     Op = ISD::ADD;
-    ShiftAmt1 = MulAmt - MulAmtLowBit;
+    MulAmtBit1 = MulAmt - MulAmtBit2;
   } else if (CanSub) {
+    // N > M
     Op = ISD::SUB;
-    ShiftAmt1 = MulAmt + MulAmtLowBit;
+    MulAmtBit1 = MulAmt + MulAmtBit2;
+  } else if (isPowerOf2_64(MulAmtBit2 - MulAmt)) {
+    // N < M
+    Op = ISD::SUB;
+    MulAmtBit1 = MulAmtBit2;
+    MulAmtBit2 -= MulAmt;
   } else {
     return SDValue();
   }
   EVT VT = N->getValueType(0);
   SDLoc DL(N);
   SDValue Shift1 = DAG.getNode(ISD::SHL, DL, VT, X,
-                               DAG.getConstant(Log2_64(ShiftAmt1), DL, VT));
+                               DAG.getConstant(Log2_64(MulAmtBit1), DL, VT));
   SDValue Shift2 = DAG.getNode(ISD::SHL, DL, VT, X,
-                               DAG.getConstant(Log2_64(MulAmtLowBit), DL, VT));
+                               DAG.getConstant(Log2_64(MulAmtBit2), DL, VT));
   return DAG.getNode(Op, DL, VT, Shift1, Shift2);
 }
 
diff --git a/llvm/test/CodeGen/RISCV/mul.ll b/llvm/test/CodeGen/RISCV/mul.ll
index 4533e14c672e7..940fe598fc0f0 100644
--- a/llvm/test/CodeGen/RISCV/mul.ll
+++ b/llvm/test/CodeGen/RISCV/mul.ll
@@ -1679,13 +1679,17 @@ define i128 @muli128_m3840(i128 %a) nounwind {
 ;
 ; RV64IM-LABEL: muli128_m3840:
 ; RV64IM:       # %bb.0:
+; RV64IM-NEXT:    slli a2, a1, 12
+; RV64IM-NEXT:    slli a1, a1, 8
+; RV64IM-NEXT:    sub a1, a1, a2
 ; RV64IM-NEXT:    li a2, -15
 ; RV64IM-NEXT:    slli a2, a2, 8
-; RV64IM-NEXT:    mul a1, a1, a2
-; RV64IM-NEXT:    mulhu a3, a0, a2
-; RV64IM-NEXT:    sub a3, a3, a0
-; RV64IM-NEXT:    add a1, a3, a1
-; RV64IM-NEXT:    mul a0, a0, a2
+; RV64IM-NEXT:    mulhu a2, a0, a2
+; RV64IM-NEXT:    sub a1, a0, a1
+; RV64IM-NEXT:    sub a1, a2, a1
+; RV64IM-NEXT:    slli a2, a0, 12
+; RV64IM-NEXT:    slli a0, a0, 8
+; RV64IM-NEXT:    sub a0, a0, a2
 ; RV64IM-NEXT:    ret
   %1 = mul i128 %a, -3840
   ret i128 %1
diff --git a/llvm/test/CodeGen/RISCV/rv64xtheadba.ll b/llvm/test/CodeGen/RISCV/rv64xtheadba.ll
index c57dfca1389b6..b4de214250b22 100644
--- a/llvm/test/CodeGen/RISCV/rv64xtheadba.ll
+++ b/llvm/test/CodeGen/RISCV/rv64xtheadba.ll
@@ -2024,8 +2024,9 @@ define i64 @mul_neg5(i64 %a) {
 define i64 @mul_neg6(i64 %a) {
 ; CHECK-LABEL: mul_neg6:
 ; CHECK:       # %bb.0:
-; CHECK-NEXT:    li a1, -6
-; CHECK-NEXT:    mul a0, a0, a1
+; CHECK-NEXT:    slli a1, a0, 3
+; CHECK-NEXT:    slli a0, a0, 1
+; CHECK-NEXT:    sub a0, a0, a1
 ; CHECK-NEXT:    ret
   %c = mul i64 %a, -6
   ret i64 %c
diff --git a/llvm/test/CodeGen/RISCV/rv64zba.ll b/llvm/test/CodeGen/RISCV/rv64zba.ll
index fb26b8b16a290..73a886f6d7c60 100644
--- a/llvm/test/CodeGen/RISCV/rv64zba.ll
+++ b/llvm/test/CodeGen/RISCV/rv64zba.ll
@@ -4157,8 +4157,9 @@ define i64 @mul_neg5(i64 %a) {
 define i64 @mul_neg6(i64 %a) {
 ; CHECK-LABEL: mul_neg6:
 ; CHECK:       # %bb.0:
-; CHECK-NEXT:    li a1, -6
-; CHECK-NEXT:    mul a0, a0, a1
+; CHECK-NEXT:    slli a1, a0, 3
+; CHECK-NEXT:    slli a0, a0, 1
+; CHECK-NEXT:    sub a0, a0, a1
 ; CHECK-NEXT:    ret
   %c = mul i64 %a, -6
   ret i64 %c
diff --git a/llvm/test/CodeGen/RISCV/srem-vector-lkk.ll b/llvm/test/CodeGen/RISCV/srem-vector-lkk.ll
index 7548885f8405b..0a1946b5978f5 100644
--- a/llvm/test/CodeGen/RISCV/srem-vector-lkk.ll
+++ b/llvm/test/CodeGen/RISCV/srem-vector-lkk.ll
@@ -145,8 +145,8 @@ define <4 x i16> @fold_srem_vec_1(<4 x i16> %x) nounwind {
 ;
 ; RV64IM-LABEL: fold_srem_vec_1:
 ; RV64IM:       # %bb.0:
-; RV64IM-NEXT:    lh a3, 0(a1)
-; RV64IM-NEXT:    lh a2, 8(a1)
+; RV64IM-NEXT:    lh a2, 0(a1)
+; RV64IM-NEXT:    lh a3, 8(a1)
 ; RV64IM-NEXT:    lh a4, 16(a1)
 ; RV64IM-NEXT:    lh a1, 24(a1)
 ; RV64IM-NEXT:    lui a5, %hi(.LCPI0_0)
@@ -161,8 +161,8 @@ define <4 x i16> @fold_srem_vec_1(<4 x i16> %x) nounwind {
 ; RV64IM-NEXT:    mulh a6, a2, a6
 ; RV64IM-NEXT:    mulh a7, a4, a7
 ; RV64IM-NEXT:    mulh t0, a1, t0
-; RV64IM-NEXT:    add a5, a5, a3
-; RV64IM-NEXT:    sub a6, a6, a2
+; RV64IM-NEXT:    sub a5, a5, a3
+; RV64IM-NEXT:    add a6, a6, a2
 ; RV64IM-NEXT:    srli t1, a7, 63
 ; RV64IM-NEXT:    srli a7, a7, 5
 ; RV64IM-NEXT:    add a7, a7, t1
@@ -170,7 +170,7 @@ define <4 x i16> @fold_srem_vec_1(<4 x i16> %x) nounwind {
 ; RV64IM-NEXT:    srli t0, t0, 7
 ; RV64IM-NEXT:    add t0, t0, t1
 ; RV64IM-NEXT:    srli t1, a5, 63
-; RV64IM-NEXT:    srli a5, a5, 6
+; RV64IM-NEXT:    srai a5, a5, 6
 ; RV64IM-NEXT:    add a5, a5, t1
 ; RV64IM-NEXT:    srli t1, a6, 63
 ; RV64IM-NEXT:    srli a6, a6, 6
@@ -180,15 +180,16 @@ define <4 x i16> @fold_srem_vec_1(<4 x i16> %x) nounwind {
 ; RV64IM-NEXT:    li t1, -1003
 ; RV64IM-NEXT:    mul t0, t0, t1
 ; RV64IM-NEXT:    li t1, 95
-; RV64IM-NEXT:    mul a5, a5, t1
-; RV64IM-NEXT:    li t1, -124
 ; RV64IM-NEXT:    mul a6, a6, t1
 ; RV64IM-NEXT:    sub a4, a4, a7
 ; RV64IM-NEXT:    sub a1, a1, t0
-; RV64IM-NEXT:    sub a3, a3, a5
+; RV64IM-NEXT:    slli a7, a5, 2
+; RV64IM-NEXT:    slli a5, a5, 7
+; RV64IM-NEXT:    sub a5, a5, a7
 ; RV64IM-NEXT:    sub a2, a2, a6
-; RV64IM-NEXT:    sh a3, 0(a0)
-; RV64IM-NEXT:    sh a2, 2(a0)
+; RV64IM-NEXT:    add a3, a3, a5
+; RV64IM-NEXT:    sh a2, 0(a0)
+; RV64IM-NEXT:    sh a3, 2(a0)
 ; RV64IM-NEXT:    sh a4, 4(a0)
 ; RV64IM-NEXT:    sh a1, 6(a0)
 ; RV64IM-NEXT:    ret

``````````

</details>


https://github.com/llvm/llvm-project/pull/168843


More information about the llvm-commits mailing list