diff --git a/llvm/lib/Target/CSKY/CSKYISelLowering.h b/llvm/lib/Target/CSKY/CSKYISelLowering.h --- a/llvm/lib/Target/CSKY/CSKYISelLowering.h +++ b/llvm/lib/Target/CSKY/CSKYISelLowering.h @@ -173,6 +173,9 @@ CCAssignFn *CCAssignFnForCall(CallingConv::ID CC, bool IsVarArg) const; CCAssignFn *CCAssignFnForReturn(CallingConv::ID CC, bool IsVarArg) const; + + bool decomposeMulByConstant(LLVMContext &Context, EVT VT, + SDValue C) const override; }; } // namespace llvm diff --git a/llvm/lib/Target/CSKY/CSKYISelLowering.cpp b/llvm/lib/Target/CSKY/CSKYISelLowering.cpp --- a/llvm/lib/Target/CSKY/CSKYISelLowering.cpp +++ b/llvm/lib/Target/CSKY/CSKYISelLowering.cpp @@ -1376,3 +1376,24 @@ return V; } + +bool CSKYTargetLowering::decomposeMulByConstant(LLVMContext &Context, EVT VT, + SDValue C) const { + if (!VT.isScalarInteger()) + return false; + + // Omit if data size exceeds. + const unsigned DataSize = Subtarget.hasE2() ? 32 : 16; + if (VT.getSizeInBits() > DataSize) + return false; + + if (auto *ConstNode = dyn_cast(C.getNode())) { + const APInt &Imm = ConstNode->getAPIntValue(); + // Break MULT into LSLI + ADDU/SUBU. + if ((Imm + 1).isPowerOf2() || (Imm - 1).isPowerOf2() || + (1 - Imm).isPowerOf2()) + return true; + } + + return false; +} diff --git a/llvm/test/CodeGen/CSKY/base-i.ll b/llvm/test/CodeGen/CSKY/base-i.ll --- a/llvm/test/CodeGen/CSKY/base-i.ll +++ b/llvm/test/CodeGen/CSKY/base-i.ll @@ -480,8 +480,8 @@ define i32 @mulRI_X(i32 %x) { ; CHECK-LABEL: mulRI_X: ; CHECK: # %bb.0: # %entry -; CHECK-NEXT: movi32 a1, 4097 -; CHECK-NEXT: mult16 a0, a1 +; CHECK-NEXT: lsli16 a1, a0, 12 +; CHECK-NEXT: addu16 a0, a1 ; CHECK-NEXT: rts16 ; ; GENERIC-LABEL: mulRI_X: @@ -509,8 +509,8 @@ define i32 @mulRI_4095(i32 %x) { ; CHECK-LABEL: mulRI_4095: ; CHECK: # %bb.0: # %entry -; CHECK-NEXT: movi32 a1, 4095 -; CHECK-NEXT: mult16 a0, a1 +; CHECK-NEXT: lsli16 a1, a0, 12 +; CHECK-NEXT: subu16 a0, a1, a0 ; CHECK-NEXT: rts16 ; ; GENERIC-LABEL: mulRI_4095: @@ -538,9 +538,8 @@ define i32 @mulRI_minus_4095(i32 %x) { ; CHECK-LABEL: mulRI_minus_4095: ; CHECK: # %bb.0: # %entry -; CHECK-NEXT: movih32 a1, 65535 -; CHECK-NEXT: ori32 a1, a1, 61441 -; CHECK-NEXT: mult16 a0, a1 +; CHECK-NEXT: lsli16 a1, a0, 12 +; CHECK-NEXT: subu16 a0, a1 ; CHECK-NEXT: rts16 ; ; GENERIC-LABEL: mulRI_minus_4095: @@ -616,8 +615,7 @@ define i16 @MUL_SHORT_I(i16 %x) { ; CHECK-LABEL: MUL_SHORT_I: ; CHECK: # %bb.0: # %entry -; CHECK-NEXT: movi16 a1, 3 -; CHECK-NEXT: mult16 a0, a1 +; CHECK-NEXT: ixh32 a0, a0, a0 ; CHECK-NEXT: rts16 ; ; GENERIC-LABEL: MUL_SHORT_I: @@ -625,8 +623,8 @@ ; GENERIC-NEXT: .cfi_def_cfa_offset 0 ; GENERIC-NEXT: subi16 sp, sp, 4 ; GENERIC-NEXT: .cfi_def_cfa_offset 4 -; GENERIC-NEXT: movi16 a1, 3 -; GENERIC-NEXT: mult16 a0, a1 +; GENERIC-NEXT: lsli16 a1, a0, 1 +; GENERIC-NEXT: addu16 a0, a1, a0 ; GENERIC-NEXT: addi16 sp, sp, 4 ; GENERIC-NEXT: rts16 entry: @@ -656,9 +654,9 @@ define i8 @MUL_CHAR_I(i8 %x) { ; CHECK-LABEL: MUL_CHAR_I: ; CHECK: # %bb.0: # %entry -; CHECK-NEXT: movih32 a1, 65535 -; CHECK-NEXT: ori32 a1, a1, 65533 -; CHECK-NEXT: mult16 a0, a1 +; CHECK-NEXT: ixh32 a0, a0, a0 +; CHECK-NEXT: movi16 a1, 0 +; CHECK-NEXT: subu16 a0, a1, a0 ; CHECK-NEXT: rts16 ; ; GENERIC-LABEL: MUL_CHAR_I: @@ -666,15 +664,10 @@ ; GENERIC-NEXT: .cfi_def_cfa_offset 0 ; GENERIC-NEXT: subi16 sp, sp, 4 ; GENERIC-NEXT: .cfi_def_cfa_offset 4 -; GENERIC-NEXT: movi16 a1, 255 -; GENERIC-NEXT: lsli16 a2, a1, 24 -; GENERIC-NEXT: lsli16 a3, a1, 16 -; GENERIC-NEXT: or16 a3, a2 -; GENERIC-NEXT: lsli16 a1, a1, 8 -; GENERIC-NEXT: or16 a1, a3 -; GENERIC-NEXT: movi16 a2, 253 -; GENERIC-NEXT: or16 a2, a1 -; GENERIC-NEXT: mult16 a0, a2 +; GENERIC-NEXT: lsli16 a1, a0, 1 +; GENERIC-NEXT: addu16 a0, a1, a0 +; GENERIC-NEXT: movi16 a1, 0 +; GENERIC-NEXT: subu16 a0, a1, a0 ; GENERIC-NEXT: addi16 sp, sp, 4 ; GENERIC-NEXT: rts16 entry: