[llvm] c8a2301 - [LoongArch] Optimize multiplication with immediates

Ben Shi via llvm-commits llvm-commits at lists.llvm.org
Thu Apr 6 17:47:05 PDT 2023


Author: Ben Shi
Date: 2023-04-07T08:46:49+08:00
New Revision: c8a2301555a2ce7fb2e0b8a0e3ad080c77403735

URL: https://github.com/llvm/llvm-project/commit/c8a2301555a2ce7fb2e0b8a0e3ad080c77403735
DIFF: https://github.com/llvm/llvm-project/commit/c8a2301555a2ce7fb2e0b8a0e3ad080c77403735.diff

LOG: [LoongArch] Optimize multiplication with immediates

Optimize "(mul r, c)" to "(SLLI (ALSL r, r, i0), i1)", in which
"c = (1 + (1 << i0)) << i1".

Reviewed By: SixWeining

Differential Revision: https://reviews.llvm.org/D147428

Added: 
    

Modified: 
    llvm/lib/Target/LoongArch/LoongArchInstrInfo.td
    llvm/test/CodeGen/LoongArch/ir-instruction/mul.ll

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Target/LoongArch/LoongArchInstrInfo.td b/llvm/lib/Target/LoongArch/LoongArchInstrInfo.td
index 31145ceeb9ab8..8ea8b76f6797c 100644
--- a/llvm/lib/Target/LoongArch/LoongArchInstrInfo.td
+++ b/llvm/lib/Target/LoongArch/LoongArchInstrInfo.td
@@ -428,6 +428,38 @@ def AddiPairImmSmall : SDNodeXForm<imm, [{
                                    N->getValueType(0));
 }]>;
 
+// Check if (mul r, imm) can be optimized to (SLLI (ALSL r, r, i0), i1),
+// in which imm = (1 + (1 << i0)) << i1.
+def AlslSlliImm : PatLeaf<(imm), [{
+  if (!N->hasOneUse())
+    return false;
+  uint64_t Imm = N->getZExtValue();
+  unsigned I1 = llvm::countr_zero(Imm);
+  uint64_t Rem = Imm >> I1;
+  return Rem == 3 || Rem == 5 || Rem == 9 || Rem == 17;
+}]>;
+
+def AlslSlliImmI1 : SDNodeXForm<imm, [{
+  uint64_t Imm = N->getZExtValue();
+  unsigned I1 = llvm::countr_zero(Imm);
+  return CurDAG->getTargetConstant(I1, SDLoc(N),
+                                   N->getValueType(0));
+}]>;
+
+def AlslSlliImmI0 : SDNodeXForm<imm, [{
+  uint64_t Imm = N->getZExtValue();
+  unsigned I1 = llvm::countr_zero(Imm);
+  uint64_t I0;
+  switch (Imm >> I1) {
+  case 3:  I0 = 1; break;
+  case 5:  I0 = 2; break;
+  case 9:  I0 = 3; break;
+  default: I0 = 4; break;
+  }
+  return CurDAG->getTargetConstant(I0, SDLoc(N),
+                                   N->getValueType(0));
+}]>;
+
 //===----------------------------------------------------------------------===//
 // Instruction Formats
 //===----------------------------------------------------------------------===//
@@ -992,6 +1024,21 @@ foreach Idx0 = 1...4 in {
 }
 } // Predicates = [IsLA64]
 
+let Predicates = [IsLA32] in {
+def : Pat<(mul GPR:$rj, (AlslSlliImm:$im)),
+          (SLLI_W (ALSL_W GPR:$rj, GPR:$rj, (AlslSlliImmI0 AlslSlliImm:$im)),
+                  (AlslSlliImmI1 AlslSlliImm:$im))>;
+} // Predicates = [IsLA32]
+
+let Predicates = [IsLA64] in {
+def : Pat<(sext_inreg (mul GPR:$rj, (AlslSlliImm:$im)), i32),
+          (SLLI_W (ALSL_W GPR:$rj, GPR:$rj, (AlslSlliImmI0 AlslSlliImm:$im)),
+                  (AlslSlliImmI1 AlslSlliImm:$im))>;
+def : Pat<(mul GPR:$rj, (AlslSlliImm:$im)),
+          (SLLI_D (ALSL_D GPR:$rj, GPR:$rj, (AlslSlliImmI0 AlslSlliImm:$im)),
+                  (AlslSlliImmI1 AlslSlliImm:$im))>;
+} // Predicates = [IsLA64]
+
 foreach Idx = 1...7 in {
   defvar ShamtA = !mul(8, Idx);
   defvar ShamtB = !mul(8, !sub(8, Idx));

diff  --git a/llvm/test/CodeGen/LoongArch/ir-instruction/mul.ll b/llvm/test/CodeGen/LoongArch/ir-instruction/mul.ll
index c4a4bc310ddd7..8e18ec578f5fa 100644
--- a/llvm/test/CodeGen/LoongArch/ir-instruction/mul.ll
+++ b/llvm/test/CodeGen/LoongArch/ir-instruction/mul.ll
@@ -1167,15 +1167,14 @@ define i64 @mul_i64_4112(i64 %a) {
 define signext i32 @mul_i32_768(i32 %a) {
 ; LA32-LABEL: mul_i32_768:
 ; LA32:       # %bb.0:
-; LA32-NEXT:    ori $a1, $zero, 768
-; LA32-NEXT:    mul.w $a0, $a0, $a1
+; LA32-NEXT:    alsl.w $a0, $a0, $a0, 1
+; LA32-NEXT:    slli.w $a0, $a0, 8
 ; LA32-NEXT:    ret
 ;
 ; LA64-LABEL: mul_i32_768:
 ; LA64:       # %bb.0:
-; LA64-NEXT:    ori $a1, $zero, 768
-; LA64-NEXT:    mul.d $a0, $a0, $a1
-; LA64-NEXT:    addi.w $a0, $a0, 0
+; LA64-NEXT:    alsl.w $a0, $a0, $a0, 1
+; LA64-NEXT:    slli.w $a0, $a0, 8
 ; LA64-NEXT:    ret
   %b = mul i32 %a, 768
   ret i32 %b
@@ -1184,15 +1183,14 @@ define signext i32 @mul_i32_768(i32 %a) {
 define signext i32 @mul_i32_1280(i32 %a) {
 ; LA32-LABEL: mul_i32_1280:
 ; LA32:       # %bb.0:
-; LA32-NEXT:    ori $a1, $zero, 1280
-; LA32-NEXT:    mul.w $a0, $a0, $a1
+; LA32-NEXT:    alsl.w $a0, $a0, $a0, 2
+; LA32-NEXT:    slli.w $a0, $a0, 8
 ; LA32-NEXT:    ret
 ;
 ; LA64-LABEL: mul_i32_1280:
 ; LA64:       # %bb.0:
-; LA64-NEXT:    ori $a1, $zero, 1280
-; LA64-NEXT:    mul.d $a0, $a0, $a1
-; LA64-NEXT:    addi.w $a0, $a0, 0
+; LA64-NEXT:    alsl.w $a0, $a0, $a0, 2
+; LA64-NEXT:    slli.w $a0, $a0, 8
 ; LA64-NEXT:    ret
   %b = mul i32 %a, 1280
   ret i32 %b
@@ -1201,15 +1199,14 @@ define signext i32 @mul_i32_1280(i32 %a) {
 define signext i32 @mul_i32_2304(i32 %a) {
 ; LA32-LABEL: mul_i32_2304:
 ; LA32:       # %bb.0:
-; LA32-NEXT:    ori $a1, $zero, 2304
-; LA32-NEXT:    mul.w $a0, $a0, $a1
+; LA32-NEXT:    alsl.w $a0, $a0, $a0, 3
+; LA32-NEXT:    slli.w $a0, $a0, 8
 ; LA32-NEXT:    ret
 ;
 ; LA64-LABEL: mul_i32_2304:
 ; LA64:       # %bb.0:
-; LA64-NEXT:    ori $a1, $zero, 2304
-; LA64-NEXT:    mul.d $a0, $a0, $a1
-; LA64-NEXT:    addi.w $a0, $a0, 0
+; LA64-NEXT:    alsl.w $a0, $a0, $a0, 3
+; LA64-NEXT:    slli.w $a0, $a0, 8
 ; LA64-NEXT:    ret
   %b = mul i32 %a, 2304
   ret i32 %b
@@ -1218,17 +1215,14 @@ define signext i32 @mul_i32_2304(i32 %a) {
 define signext i32 @mul_i32_4352(i32 %a) {
 ; LA32-LABEL: mul_i32_4352:
 ; LA32:       # %bb.0:
-; LA32-NEXT:    lu12i.w $a1, 1
-; LA32-NEXT:    ori $a1, $a1, 256
-; LA32-NEXT:    mul.w $a0, $a0, $a1
+; LA32-NEXT:    alsl.w $a0, $a0, $a0, 4
+; LA32-NEXT:    slli.w $a0, $a0, 8
 ; LA32-NEXT:    ret
 ;
 ; LA64-LABEL: mul_i32_4352:
 ; LA64:       # %bb.0:
-; LA64-NEXT:    lu12i.w $a1, 1
-; LA64-NEXT:    ori $a1, $a1, 256
-; LA64-NEXT:    mul.d $a0, $a0, $a1
-; LA64-NEXT:    addi.w $a0, $a0, 0
+; LA64-NEXT:    alsl.w $a0, $a0, $a0, 4
+; LA64-NEXT:    slli.w $a0, $a0, 8
 ; LA64-NEXT:    ret
   %b = mul i32 %a, 4352
   ret i32 %b
@@ -1246,8 +1240,8 @@ define i64 @mul_i64_768(i64 %a) {
 ;
 ; LA64-LABEL: mul_i64_768:
 ; LA64:       # %bb.0:
-; LA64-NEXT:    ori $a1, $zero, 768
-; LA64-NEXT:    mul.d $a0, $a0, $a1
+; LA64-NEXT:    alsl.d $a0, $a0, $a0, 1
+; LA64-NEXT:    slli.d $a0, $a0, 8
 ; LA64-NEXT:    ret
   %b = mul i64 %a, 768
   ret i64 %b
@@ -1265,8 +1259,8 @@ define i64 @mul_i64_1280(i64 %a) {
 ;
 ; LA64-LABEL: mul_i64_1280:
 ; LA64:       # %bb.0:
-; LA64-NEXT:    ori $a1, $zero, 1280
-; LA64-NEXT:    mul.d $a0, $a0, $a1
+; LA64-NEXT:    alsl.d $a0, $a0, $a0, 2
+; LA64-NEXT:    slli.d $a0, $a0, 8
 ; LA64-NEXT:    ret
   %b = mul i64 %a, 1280
   ret i64 %b
@@ -1284,8 +1278,8 @@ define i64 @mul_i64_2304(i64 %a) {
 ;
 ; LA64-LABEL: mul_i64_2304:
 ; LA64:       # %bb.0:
-; LA64-NEXT:    ori $a1, $zero, 2304
-; LA64-NEXT:    mul.d $a0, $a0, $a1
+; LA64-NEXT:    alsl.d $a0, $a0, $a0, 3
+; LA64-NEXT:    slli.d $a0, $a0, 8
 ; LA64-NEXT:    ret
   %b = mul i64 %a, 2304
   ret i64 %b
@@ -1304,9 +1298,8 @@ define i64 @mul_i64_4352(i64 %a) {
 ;
 ; LA64-LABEL: mul_i64_4352:
 ; LA64:       # %bb.0:
-; LA64-NEXT:    lu12i.w $a1, 1
-; LA64-NEXT:    ori $a1, $a1, 256
-; LA64-NEXT:    mul.d $a0, $a0, $a1
+; LA64-NEXT:    alsl.d $a0, $a0, $a0, 4
+; LA64-NEXT:    slli.d $a0, $a0, 8
 ; LA64-NEXT:    ret
   %b = mul i64 %a, 4352
   ret i64 %b


        


More information about the llvm-commits mailing list