diff --git a/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp b/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp --- a/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp +++ b/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp @@ -3131,12 +3131,17 @@ if (VT.getSizeInBits() > Subtarget.getGRLen()) return false; - // Break MUL into (SLLI + ADD/SUB) or ALSL. if (auto *ConstNode = dyn_cast(C.getNode())) { const APInt &Imm = ConstNode->getAPIntValue(); + // Break MUL into (SLLI + ADD/SUB) or ALSL. if ((Imm + 1).isPowerOf2() || (Imm - 1).isPowerOf2() || (1 - Imm).isPowerOf2() || (-1 - Imm).isPowerOf2()) return true; + // Break MUL to (ALSL x, (SLLI x, imm0), imm1). + if (ConstNode->hasOneUse() && + ((Imm - 2).isPowerOf2() || (Imm - 4).isPowerOf2() || + (Imm - 4).isPowerOf2() || (Imm - 8).isPowerOf2())) + return true; } return false; diff --git a/llvm/test/CodeGen/LoongArch/ir-instruction/mul.ll b/llvm/test/CodeGen/LoongArch/ir-instruction/mul.ll --- a/llvm/test/CodeGen/LoongArch/ir-instruction/mul.ll +++ b/llvm/test/CodeGen/LoongArch/ir-instruction/mul.ll @@ -1029,17 +1029,15 @@ define signext i32 @mul_i32_4098(i32 %a) { ; LA32-LABEL: mul_i32_4098: ; LA32: # %bb.0: -; LA32-NEXT: lu12i.w $a1, 1 -; LA32-NEXT: ori $a1, $a1, 2 -; LA32-NEXT: mul.w $a0, $a0, $a1 +; LA32-NEXT: slli.w $a1, $a0, 12 +; LA32-NEXT: alsl.w $a0, $a0, $a1, 1 ; LA32-NEXT: ret ; ; LA64-LABEL: mul_i32_4098: ; LA64: # %bb.0: -; LA64-NEXT: lu12i.w $a1, 1 -; LA64-NEXT: ori $a1, $a1, 2 -; LA64-NEXT: mul.d $a0, $a0, $a1 -; LA64-NEXT: addi.w $a0, $a0, 0 +; LA64-NEXT: slli.d $a1, $a0, 1 +; LA64-NEXT: slli.d $a0, $a0, 12 +; LA64-NEXT: add.w $a0, $a0, $a1 ; LA64-NEXT: ret %b = mul i32 %a, 4098 ret i32 %b @@ -1048,17 +1046,15 @@ define signext i32 @mul_i32_4100(i32 %a) { ; LA32-LABEL: mul_i32_4100: ; LA32: # %bb.0: -; LA32-NEXT: lu12i.w $a1, 1 -; LA32-NEXT: ori $a1, $a1, 4 -; LA32-NEXT: mul.w $a0, $a0, $a1 +; LA32-NEXT: slli.w $a1, $a0, 12 +; LA32-NEXT: alsl.w $a0, $a0, $a1, 2 ; LA32-NEXT: ret ; ; LA64-LABEL: mul_i32_4100: ; LA64: # %bb.0: -; LA64-NEXT: lu12i.w $a1, 1 -; LA64-NEXT: ori $a1, $a1, 4 -; LA64-NEXT: mul.d $a0, $a0, $a1 -; LA64-NEXT: addi.w $a0, $a0, 0 +; LA64-NEXT: slli.d $a1, $a0, 2 +; LA64-NEXT: slli.d $a0, $a0, 12 +; LA64-NEXT: add.w $a0, $a0, $a1 ; LA64-NEXT: ret %b = mul i32 %a, 4100 ret i32 %b @@ -1067,17 +1063,15 @@ define signext i32 @mul_i32_4104(i32 %a) { ; LA32-LABEL: mul_i32_4104: ; LA32: # %bb.0: -; LA32-NEXT: lu12i.w $a1, 1 -; LA32-NEXT: ori $a1, $a1, 8 -; LA32-NEXT: mul.w $a0, $a0, $a1 +; LA32-NEXT: slli.w $a1, $a0, 12 +; LA32-NEXT: alsl.w $a0, $a0, $a1, 3 ; LA32-NEXT: ret ; ; LA64-LABEL: mul_i32_4104: ; LA64: # %bb.0: -; LA64-NEXT: lu12i.w $a1, 1 -; LA64-NEXT: ori $a1, $a1, 8 -; LA64-NEXT: mul.d $a0, $a0, $a1 -; LA64-NEXT: addi.w $a0, $a0, 0 +; LA64-NEXT: slli.d $a1, $a0, 3 +; LA64-NEXT: slli.d $a0, $a0, 12 +; LA64-NEXT: add.w $a0, $a0, $a1 ; LA64-NEXT: ret %b = mul i32 %a, 4104 ret i32 %b @@ -1115,9 +1109,8 @@ ; ; LA64-LABEL: mul_i64_4098: ; LA64: # %bb.0: -; LA64-NEXT: lu12i.w $a1, 1 -; LA64-NEXT: ori $a1, $a1, 2 -; LA64-NEXT: mul.d $a0, $a0, $a1 +; LA64-NEXT: slli.d $a1, $a0, 12 +; LA64-NEXT: alsl.d $a0, $a0, $a1, 1 ; LA64-NEXT: ret %b = mul i64 %a, 4098 ret i64 %b @@ -1136,9 +1129,8 @@ ; ; LA64-LABEL: mul_i64_4100: ; LA64: # %bb.0: -; LA64-NEXT: lu12i.w $a1, 1 -; LA64-NEXT: ori $a1, $a1, 4 -; LA64-NEXT: mul.d $a0, $a0, $a1 +; LA64-NEXT: slli.d $a1, $a0, 12 +; LA64-NEXT: alsl.d $a0, $a0, $a1, 2 ; LA64-NEXT: ret %b = mul i64 %a, 4100 ret i64 %b @@ -1157,9 +1149,8 @@ ; ; LA64-LABEL: mul_i64_4104: ; LA64: # %bb.0: -; LA64-NEXT: lu12i.w $a1, 1 -; LA64-NEXT: ori $a1, $a1, 8 -; LA64-NEXT: mul.d $a0, $a0, $a1 +; LA64-NEXT: slli.d $a1, $a0, 12 +; LA64-NEXT: alsl.d $a0, $a0, $a1, 3 ; LA64-NEXT: ret %b = mul i64 %a, 4104 ret i64 %b