[llvm] [RISCV] Expand mul X, C where C=2^N*(3, 5, 9)*(3, 5, 9) (PR #108100)

Philip Reames via llvm-commits llvm-commits at lists.llvm.org
Tue Sep 10 18:42:01 PDT 2024


https://github.com/preames updated https://github.com/llvm/llvm-project/pull/108100

>From 0c04ae99cca7d0a1c085b7b3e112dc534a9ac080 Mon Sep 17 00:00:00 2001
From: Philip Reames <preames at rivosinc.com>
Date: Tue, 10 Sep 2024 14:55:05 -0700
Subject: [PATCH 1/3] [RISCV] Expand mul X, C where C=2^N*(3,5,9)*(3,5,9)

This is a three deep expression which is deeper than we've otherwise
gone for multiple expansions, but I think it's reasonable to do so.
This covers mul by 50, 100, and 200 which are reasonable common
naturally arising numbers.
---
 llvm/lib/Target/RISCV/RISCVISelLowering.cpp |  27 +++
 llvm/test/CodeGen/RISCV/rv64zba.ll          | 200 ++++++++++++++------
 2 files changed, 166 insertions(+), 61 deletions(-)

diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
index 23f2b0e96495e9..32641962ed0a16 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
@@ -14131,6 +14131,33 @@ static SDValue expandMul(SDNode *N, SelectionDAG &DAG,
     return DAG.getNode(ISD::SUB, DL, VT, Shift1, Shift2);
   }
 
+  if (HasShlAdd) {
+    for (uint64_t Divisor : {3, 5, 9}) {
+      if (MulAmt % Divisor != 0)
+        continue;
+      uint64_t MulAmt2 = MulAmt / Divisor;
+      // 3/5/9 * 3/5/9 * 2^N - In particular, this covers multiples
+      // of 25 which happen to be quite common.
+      for (uint64_t Divisor2 : {3, 5, 9}) {
+        if (MulAmt2 % Divisor2 != 0)
+          continue;
+        uint64_t MulAmt3 = MulAmt2 / Divisor;
+        if (isPowerOf2_64(MulAmt3)) {
+          SDLoc DL(N);
+          SDValue Mul359A =
+              DAG.getNode(RISCVISD::SHL_ADD, DL, VT, X,
+                          DAG.getConstant(Log2_64(Divisor - 1), DL, VT), X);
+          SDValue Mul359B =
+              DAG.getNode(RISCVISD::SHL_ADD, DL, VT, Mul359A,
+                          DAG.getConstant(Log2_64(Divisor2 - 1), DL, VT),
+                          Mul359A);
+          return DAG.getNode(ISD::SHL, DL, VT, Mul359B,
+                           DAG.getConstant(Log2_64(MulAmt3), DL, VT));
+        }
+      }
+    }
+  }
+
   return SDValue();
 }
 
diff --git a/llvm/test/CodeGen/RISCV/rv64zba.ll b/llvm/test/CodeGen/RISCV/rv64zba.ll
index 19d7324eeff4a1..f1a01f0a2a3a09 100644
--- a/llvm/test/CodeGen/RISCV/rv64zba.ll
+++ b/llvm/test/CodeGen/RISCV/rv64zba.ll
@@ -570,122 +570,200 @@ define i64 @addmul72(i64 %a, i64 %b) {
 }
 
 define i64 @mul50(i64 %a) {
-; CHECK-LABEL: mul50:
-; CHECK:       # %bb.0:
-; CHECK-NEXT:    li a1, 50
-; CHECK-NEXT:    mul a0, a0, a1
-; CHECK-NEXT:    ret
+; RV64I-LABEL: mul50:
+; RV64I:       # %bb.0:
+; RV64I-NEXT:    li a1, 50
+; RV64I-NEXT:    mul a0, a0, a1
+; RV64I-NEXT:    ret
+;
+; RV64ZBA-LABEL: mul50:
+; RV64ZBA:       # %bb.0:
+; RV64ZBA-NEXT:    sh2add a0, a0, a0
+; RV64ZBA-NEXT:    sh2add a0, a0, a0
+; RV64ZBA-NEXT:    slli a0, a0, 1
+; RV64ZBA-NEXT:    ret
   %c = mul i64 %a, 50
   ret i64 %c
 }
 
 define i64 @addmul50(i64 %a, i64 %b) {
-; CHECK-LABEL: addmul50:
-; CHECK:       # %bb.0:
-; CHECK-NEXT:    li a2, 50
-; CHECK-NEXT:    mul a0, a0, a2
-; CHECK-NEXT:    add a0, a0, a1
-; CHECK-NEXT:    ret
+; RV64I-LABEL: addmul50:
+; RV64I:       # %bb.0:
+; RV64I-NEXT:    li a2, 50
+; RV64I-NEXT:    mul a0, a0, a2
+; RV64I-NEXT:    add a0, a0, a1
+; RV64I-NEXT:    ret
+;
+; RV64ZBA-LABEL: addmul50:
+; RV64ZBA:       # %bb.0:
+; RV64ZBA-NEXT:    sh2add a0, a0, a0
+; RV64ZBA-NEXT:    sh2add a0, a0, a0
+; RV64ZBA-NEXT:    sh1add a0, a0, a1
+; RV64ZBA-NEXT:    ret
   %c = mul i64 %a, 50
   %d = add i64 %c, %b
   ret i64 %d
 }
 
 define i64 @mul100(i64 %a) {
-; CHECK-LABEL: mul100:
-; CHECK:       # %bb.0:
-; CHECK-NEXT:    li a1, 100
-; CHECK-NEXT:    mul a0, a0, a1
-; CHECK-NEXT:    ret
+; RV64I-LABEL: mul100:
+; RV64I:       # %bb.0:
+; RV64I-NEXT:    li a1, 100
+; RV64I-NEXT:    mul a0, a0, a1
+; RV64I-NEXT:    ret
+;
+; RV64ZBA-LABEL: mul100:
+; RV64ZBA:       # %bb.0:
+; RV64ZBA-NEXT:    sh2add a0, a0, a0
+; RV64ZBA-NEXT:    sh2add a0, a0, a0
+; RV64ZBA-NEXT:    slli a0, a0, 2
+; RV64ZBA-NEXT:    ret
   %c = mul i64 %a, 100
   ret i64 %c
 }
 
 define i64 @addmul100(i64 %a, i64 %b) {
-; CHECK-LABEL: addmul100:
-; CHECK:       # %bb.0:
-; CHECK-NEXT:    li a2, 100
-; CHECK-NEXT:    mul a0, a0, a2
-; CHECK-NEXT:    add a0, a0, a1
-; CHECK-NEXT:    ret
+; RV64I-LABEL: addmul100:
+; RV64I:       # %bb.0:
+; RV64I-NEXT:    li a2, 100
+; RV64I-NEXT:    mul a0, a0, a2
+; RV64I-NEXT:    add a0, a0, a1
+; RV64I-NEXT:    ret
+;
+; RV64ZBA-LABEL: addmul100:
+; RV64ZBA:       # %bb.0:
+; RV64ZBA-NEXT:    sh2add a0, a0, a0
+; RV64ZBA-NEXT:    sh2add a0, a0, a0
+; RV64ZBA-NEXT:    sh2add a0, a0, a1
+; RV64ZBA-NEXT:    ret
   %c = mul i64 %a, 100
   %d = add i64 %c, %b
   ret i64 %d
 }
 
 define i64 @mul162(i64 %a) {
-; CHECK-LABEL: mul162:
-; CHECK:       # %bb.0:
-; CHECK-NEXT:    li a1, 162
-; CHECK-NEXT:    mul a0, a0, a1
-; CHECK-NEXT:    ret
+; RV64I-LABEL: mul162:
+; RV64I:       # %bb.0:
+; RV64I-NEXT:    li a1, 162
+; RV64I-NEXT:    mul a0, a0, a1
+; RV64I-NEXT:    ret
+;
+; RV64ZBA-LABEL: mul162:
+; RV64ZBA:       # %bb.0:
+; RV64ZBA-NEXT:    sh3add a0, a0, a0
+; RV64ZBA-NEXT:    sh1add a0, a0, a0
+; RV64ZBA-NEXT:    slli a0, a0, 1
+; RV64ZBA-NEXT:    ret
   %c = mul i64 %a, 162
   ret i64 %c
 }
 
 define i64 @addmul162(i64 %a, i64 %b) {
-; CHECK-LABEL: addmul162:
-; CHECK:       # %bb.0:
-; CHECK-NEXT:    li a2, 162
-; CHECK-NEXT:    mul a0, a0, a2
-; CHECK-NEXT:    add a0, a0, a1
-; CHECK-NEXT:    ret
+; RV64I-LABEL: addmul162:
+; RV64I:       # %bb.0:
+; RV64I-NEXT:    li a2, 162
+; RV64I-NEXT:    mul a0, a0, a2
+; RV64I-NEXT:    add a0, a0, a1
+; RV64I-NEXT:    ret
+;
+; RV64ZBA-LABEL: addmul162:
+; RV64ZBA:       # %bb.0:
+; RV64ZBA-NEXT:    sh3add a0, a0, a0
+; RV64ZBA-NEXT:    sh1add a0, a0, a0
+; RV64ZBA-NEXT:    sh1add a0, a0, a1
+; RV64ZBA-NEXT:    ret
   %c = mul i64 %a, 162
   %d = add i64 %c, %b
   ret i64 %d
 }
 
 define i64 @mul180(i64 %a) {
-; CHECK-LABEL: mul180:
-; CHECK:       # %bb.0:
-; CHECK-NEXT:    li a1, 180
-; CHECK-NEXT:    mul a0, a0, a1
-; CHECK-NEXT:    ret
+; RV64I-LABEL: mul180:
+; RV64I:       # %bb.0:
+; RV64I-NEXT:    li a1, 180
+; RV64I-NEXT:    mul a0, a0, a1
+; RV64I-NEXT:    ret
+;
+; RV64ZBA-LABEL: mul180:
+; RV64ZBA:       # %bb.0:
+; RV64ZBA-NEXT:    sh3add a0, a0, a0
+; RV64ZBA-NEXT:    sh2add a0, a0, a0
+; RV64ZBA-NEXT:    slli a0, a0, 1
+; RV64ZBA-NEXT:    ret
   %c = mul i64 %a, 180
   ret i64 %c
 }
 
 define i64 @addmul180(i64 %a, i64 %b) {
-; CHECK-LABEL: addmul180:
-; CHECK:       # %bb.0:
-; CHECK-NEXT:    li a2, 180
-; CHECK-NEXT:    mul a0, a0, a2
-; CHECK-NEXT:    add a0, a0, a1
-; CHECK-NEXT:    ret
+; RV64I-LABEL: addmul180:
+; RV64I:       # %bb.0:
+; RV64I-NEXT:    li a2, 180
+; RV64I-NEXT:    mul a0, a0, a2
+; RV64I-NEXT:    add a0, a0, a1
+; RV64I-NEXT:    ret
+;
+; RV64ZBA-LABEL: addmul180:
+; RV64ZBA:       # %bb.0:
+; RV64ZBA-NEXT:    sh3add a0, a0, a0
+; RV64ZBA-NEXT:    sh2add a0, a0, a0
+; RV64ZBA-NEXT:    sh1add a0, a0, a1
+; RV64ZBA-NEXT:    ret
   %c = mul i64 %a, 180
   %d = add i64 %c, %b
   ret i64 %d
 }
 
 define i64 @add255mul180(i64 %a) {
-; CHECK-LABEL: add255mul180:
-; CHECK:       # %bb.0:
-; CHECK-NEXT:    li a1, 180
-; CHECK-NEXT:    mul a0, a0, a1
-; CHECK-NEXT:    addi a0, a0, 255
-; CHECK-NEXT:    ret
+; RV64I-LABEL: add255mul180:
+; RV64I:       # %bb.0:
+; RV64I-NEXT:    li a1, 180
+; RV64I-NEXT:    mul a0, a0, a1
+; RV64I-NEXT:    addi a0, a0, 255
+; RV64I-NEXT:    ret
+;
+; RV64ZBA-LABEL: add255mul180:
+; RV64ZBA:       # %bb.0:
+; RV64ZBA-NEXT:    sh3add a0, a0, a0
+; RV64ZBA-NEXT:    sh2add a0, a0, a0
+; RV64ZBA-NEXT:    slli a0, a0, 1
+; RV64ZBA-NEXT:    addi a0, a0, 255
+; RV64ZBA-NEXT:    ret
   %c = mul i64 %a, 180
   %d = add i64 %c, 255
   ret i64 %d
 }
 
 define i64 @mul200(i64 %a) {
-; CHECK-LABEL: mul200:
-; CHECK:       # %bb.0:
-; CHECK-NEXT:    li a1, 200
-; CHECK-NEXT:    mul a0, a0, a1
-; CHECK-NEXT:    ret
+; RV64I-LABEL: mul200:
+; RV64I:       # %bb.0:
+; RV64I-NEXT:    li a1, 200
+; RV64I-NEXT:    mul a0, a0, a1
+; RV64I-NEXT:    ret
+;
+; RV64ZBA-LABEL: mul200:
+; RV64ZBA:       # %bb.0:
+; RV64ZBA-NEXT:    sh2add a0, a0, a0
+; RV64ZBA-NEXT:    sh2add a0, a0, a0
+; RV64ZBA-NEXT:    slli a0, a0, 3
+; RV64ZBA-NEXT:    ret
   %c = mul i64 %a, 200
   ret i64 %c
 }
 
 define i64 @addmul200(i64 %a, i64 %b) {
-; CHECK-LABEL: addmul200:
-; CHECK:       # %bb.0:
-; CHECK-NEXT:    li a2, 200
-; CHECK-NEXT:    mul a0, a0, a2
-; CHECK-NEXT:    add a0, a0, a1
-; CHECK-NEXT:    ret
+; RV64I-LABEL: addmul200:
+; RV64I:       # %bb.0:
+; RV64I-NEXT:    li a2, 200
+; RV64I-NEXT:    mul a0, a0, a2
+; RV64I-NEXT:    add a0, a0, a1
+; RV64I-NEXT:    ret
+;
+; RV64ZBA-LABEL: addmul200:
+; RV64ZBA:       # %bb.0:
+; RV64ZBA-NEXT:    sh2add a0, a0, a0
+; RV64ZBA-NEXT:    sh2add a0, a0, a0
+; RV64ZBA-NEXT:    sh3add a0, a0, a1
+; RV64ZBA-NEXT:    ret
   %c = mul i64 %a, 200
   %d = add i64 %c, %b
   ret i64 %d

>From 57dd58f5e5907ee55b8d1227cb61ffea8badbef1 Mon Sep 17 00:00:00 2001
From: Philip Reames <preames at rivosinc.com>
Date: Tue, 10 Sep 2024 16:25:23 -0700
Subject: [PATCH 2/3] Clang format

---
 llvm/lib/Target/RISCV/RISCVISelLowering.cpp | 9 ++++-----
 1 file changed, 4 insertions(+), 5 deletions(-)

diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
index 32641962ed0a16..d69223a92c7602 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
@@ -14147,12 +14147,11 @@ static SDValue expandMul(SDNode *N, SelectionDAG &DAG,
           SDValue Mul359A =
               DAG.getNode(RISCVISD::SHL_ADD, DL, VT, X,
                           DAG.getConstant(Log2_64(Divisor - 1), DL, VT), X);
-          SDValue Mul359B =
-              DAG.getNode(RISCVISD::SHL_ADD, DL, VT, Mul359A,
-                          DAG.getConstant(Log2_64(Divisor2 - 1), DL, VT),
-                          Mul359A);
+          SDValue Mul359B = DAG.getNode(
+              RISCVISD::SHL_ADD, DL, VT, Mul359A,
+              DAG.getConstant(Log2_64(Divisor2 - 1), DL, VT), Mul359A);
           return DAG.getNode(ISD::SHL, DL, VT, Mul359B,
-                           DAG.getConstant(Log2_64(MulAmt3), DL, VT));
+                             DAG.getConstant(Log2_64(MulAmt3), DL, VT));
         }
       }
     }

>From d5ed985f72201b4dd37007a728e8d2cd768a5783 Mon Sep 17 00:00:00 2001
From: Philip Reames <preames at rivosinc.com>
Date: Tue, 10 Sep 2024 18:41:36 -0700
Subject: [PATCH 3/3] Fix bug noted in review comment

---
 llvm/lib/Target/RISCV/RISCVISelLowering.cpp |  2 +-
 llvm/test/CodeGen/RISCV/rv64zba.ll          | 16 ++++++++--------
 2 files changed, 9 insertions(+), 9 deletions(-)

diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
index d69223a92c7602..d2e62579bbddfc 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
@@ -14141,7 +14141,7 @@ static SDValue expandMul(SDNode *N, SelectionDAG &DAG,
       for (uint64_t Divisor2 : {3, 5, 9}) {
         if (MulAmt2 % Divisor2 != 0)
           continue;
-        uint64_t MulAmt3 = MulAmt2 / Divisor;
+        uint64_t MulAmt3 = MulAmt2 / Divisor2;
         if (isPowerOf2_64(MulAmt3)) {
           SDLoc DL(N);
           SDValue Mul359A =
diff --git a/llvm/test/CodeGen/RISCV/rv64zba.ll b/llvm/test/CodeGen/RISCV/rv64zba.ll
index f1a01f0a2a3a09..a381ee67354b32 100644
--- a/llvm/test/CodeGen/RISCV/rv64zba.ll
+++ b/llvm/test/CodeGen/RISCV/rv64zba.ll
@@ -651,7 +651,7 @@ define i64 @mul162(i64 %a) {
 ; RV64ZBA-LABEL: mul162:
 ; RV64ZBA:       # %bb.0:
 ; RV64ZBA-NEXT:    sh3add a0, a0, a0
-; RV64ZBA-NEXT:    sh1add a0, a0, a0
+; RV64ZBA-NEXT:    sh3add a0, a0, a0
 ; RV64ZBA-NEXT:    slli a0, a0, 1
 ; RV64ZBA-NEXT:    ret
   %c = mul i64 %a, 162
@@ -669,7 +669,7 @@ define i64 @addmul162(i64 %a, i64 %b) {
 ; RV64ZBA-LABEL: addmul162:
 ; RV64ZBA:       # %bb.0:
 ; RV64ZBA-NEXT:    sh3add a0, a0, a0
-; RV64ZBA-NEXT:    sh1add a0, a0, a0
+; RV64ZBA-NEXT:    sh3add a0, a0, a0
 ; RV64ZBA-NEXT:    sh1add a0, a0, a1
 ; RV64ZBA-NEXT:    ret
   %c = mul i64 %a, 162
@@ -686,9 +686,9 @@ define i64 @mul180(i64 %a) {
 ;
 ; RV64ZBA-LABEL: mul180:
 ; RV64ZBA:       # %bb.0:
-; RV64ZBA-NEXT:    sh3add a0, a0, a0
 ; RV64ZBA-NEXT:    sh2add a0, a0, a0
-; RV64ZBA-NEXT:    slli a0, a0, 1
+; RV64ZBA-NEXT:    sh3add a0, a0, a0
+; RV64ZBA-NEXT:    slli a0, a0, 2
 ; RV64ZBA-NEXT:    ret
   %c = mul i64 %a, 180
   ret i64 %c
@@ -704,9 +704,9 @@ define i64 @addmul180(i64 %a, i64 %b) {
 ;
 ; RV64ZBA-LABEL: addmul180:
 ; RV64ZBA:       # %bb.0:
-; RV64ZBA-NEXT:    sh3add a0, a0, a0
 ; RV64ZBA-NEXT:    sh2add a0, a0, a0
-; RV64ZBA-NEXT:    sh1add a0, a0, a1
+; RV64ZBA-NEXT:    sh3add a0, a0, a0
+; RV64ZBA-NEXT:    sh2add a0, a0, a1
 ; RV64ZBA-NEXT:    ret
   %c = mul i64 %a, 180
   %d = add i64 %c, %b
@@ -723,9 +723,9 @@ define i64 @add255mul180(i64 %a) {
 ;
 ; RV64ZBA-LABEL: add255mul180:
 ; RV64ZBA:       # %bb.0:
-; RV64ZBA-NEXT:    sh3add a0, a0, a0
 ; RV64ZBA-NEXT:    sh2add a0, a0, a0
-; RV64ZBA-NEXT:    slli a0, a0, 1
+; RV64ZBA-NEXT:    sh3add a0, a0, a0
+; RV64ZBA-NEXT:    slli a0, a0, 2
 ; RV64ZBA-NEXT:    addi a0, a0, 255
 ; RV64ZBA-NEXT:    ret
   %c = mul i64 %a, 180



More information about the llvm-commits mailing list