Skip to content

Commit

Permalink
[LoongArch] Optimize multiplication with immediates
Browse files Browse the repository at this point in the history
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
  • Loading branch information
benshi001 committed Apr 7, 2023
1 parent d9e884f commit c8a2301
Show file tree
Hide file tree
Showing 2 changed files with 71 additions and 31 deletions.
47 changes: 47 additions & 0 deletions llvm/lib/Target/LoongArch/LoongArchInstrInfo.td
Original file line number Diff line number Diff line change
Expand Up @@ -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
//===----------------------------------------------------------------------===//
Expand Down Expand Up @@ -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));
Expand Down
55 changes: 24 additions & 31 deletions llvm/test/CodeGen/LoongArch/ir-instruction/mul.ll
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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
Expand Down

0 comments on commit c8a2301

Please sign in to comment.