diff --git a/llvm/lib/Target/LoongArch/LoongArchInstrInfo.td b/llvm/lib/Target/LoongArch/LoongArchInstrInfo.td --- a/llvm/lib/Target/LoongArch/LoongArchInstrInfo.td +++ b/llvm/lib/Target/LoongArch/LoongArchInstrInfo.td @@ -403,6 +403,31 @@ return N->getFlags().hasNoSignedZeros(); }]>; +// Check if (add r, imm) can be optimized to (ADDI (ADDI r, imm0), imm1), +// in which imm = imm0 + imm1, and both imm0 & imm1 are simm12. +def AddiPair : PatLeaf<(imm), [{ + if (!N->hasOneUse()) + return false; + // The immediate operand must be in range [-4096,-2049] or [2048,4094]. + int64_t Imm = N->getSExtValue(); + return (-4096 <= Imm && Imm <= -2049) || (2048 <= Imm && Imm <= 4094); +}]>; + +// Return -2048 if immediate is negative or 2047 if positive. +def AddiPairImmLarge : SDNodeXFormgetSExtValue() < 0 ? -2048 : 2047; + return CurDAG->getTargetConstant(Imm, SDLoc(N), + N->getValueType(0)); +}]>; + +// Return imm - (imm < 0 ? -2048 : 2047). +def AddiPairImmSmall : SDNodeXFormgetSExtValue(); + int64_t Adj = Imm < 0 ? -2048 : 2047; + return CurDAG->getTargetConstant(Imm - Adj, SDLoc(N), + N->getValueType(0)); +}]>; + //===----------------------------------------------------------------------===// // Instruction Formats //===----------------------------------------------------------------------===// @@ -899,6 +924,21 @@ (ADDI_W (ADDU16I_D GPR:$rj, (HI16ForAddu16idAddiPair $imm)), (LO12 $imm))>; +let Predicates = [IsLA32] in { +def : Pat<(add GPR:$rj, (AddiPair:$im)), + (ADDI_W (ADDI_W GPR:$rj, (AddiPairImmLarge AddiPair:$im)), + (AddiPairImmSmall AddiPair:$im))>; +} // Predicates = [IsLA32] + +let Predicates = [IsLA64] in { +def : Pat<(add GPR:$rj, (AddiPair:$im)), + (ADDI_D (ADDI_D GPR:$rj, (AddiPairImmLarge AddiPair:$im)), + (AddiPairImmSmall AddiPair:$im))>; +def : Pat<(sext_inreg (add GPR:$rj, (AddiPair:$im)), i32), + (ADDI_W (ADDI_W GPR:$rj, (AddiPairImmLarge AddiPair:$im)), + (AddiPairImmSmall AddiPair:$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/inline-asm-constraint-m.ll b/llvm/test/CodeGen/LoongArch/inline-asm-constraint-m.ll --- a/llvm/test/CodeGen/LoongArch/inline-asm-constraint-m.ll +++ b/llvm/test/CodeGen/LoongArch/inline-asm-constraint-m.ll @@ -5,9 +5,8 @@ define i32 @m_offset_neg_2049(ptr %p) nounwind { ; LA32-LABEL: m_offset_neg_2049: ; LA32: # %bb.0: -; LA32-NEXT: lu12i.w $a1, -1 -; LA32-NEXT: ori $a1, $a1, 2047 -; LA32-NEXT: add.w $a0, $a0, $a1 +; LA32-NEXT: addi.w $a0, $a0, -2048 +; LA32-NEXT: addi.w $a0, $a0, -1 ; LA32-NEXT: #APP ; LA32-NEXT: ld.w $a0, $a0, 0 ; LA32-NEXT: #NO_APP @@ -15,9 +14,8 @@ ; ; LA64-LABEL: m_offset_neg_2049: ; LA64: # %bb.0: -; LA64-NEXT: lu12i.w $a1, -1 -; LA64-NEXT: ori $a1, $a1, 2047 -; LA64-NEXT: add.d $a0, $a0, $a1 +; LA64-NEXT: addi.d $a0, $a0, -2048 +; LA64-NEXT: addi.d $a0, $a0, -1 ; LA64-NEXT: #APP ; LA64-NEXT: ld.w $a0, $a0, 0 ; LA64-NEXT: #NO_APP @@ -124,8 +122,8 @@ define i32 @m_offset_2048(ptr %p) nounwind { ; LA32-LABEL: m_offset_2048: ; LA32: # %bb.0: -; LA32-NEXT: ori $a1, $zero, 2048 -; LA32-NEXT: add.w $a0, $a0, $a1 +; LA32-NEXT: addi.w $a0, $a0, 2047 +; LA32-NEXT: addi.w $a0, $a0, 1 ; LA32-NEXT: #APP ; LA32-NEXT: ld.w $a0, $a0, 0 ; LA32-NEXT: #NO_APP @@ -133,8 +131,8 @@ ; ; LA64-LABEL: m_offset_2048: ; LA64: # %bb.0: -; LA64-NEXT: ori $a1, $zero, 2048 -; LA64-NEXT: add.d $a0, $a0, $a1 +; LA64-NEXT: addi.d $a0, $a0, 2047 +; LA64-NEXT: addi.d $a0, $a0, 1 ; LA64-NEXT: #APP ; LA64-NEXT: ld.w $a0, $a0, 0 ; LA64-NEXT: #NO_APP diff --git a/llvm/test/CodeGen/LoongArch/ir-instruction/add.ll b/llvm/test/CodeGen/LoongArch/ir-instruction/add.ll --- a/llvm/test/CodeGen/LoongArch/ir-instruction/add.ll +++ b/llvm/test/CodeGen/LoongArch/ir-instruction/add.ll @@ -707,14 +707,14 @@ define signext i32 @add_i32_4080(i32 %x) { ; LA32-LABEL: add_i32_4080: ; LA32: # %bb.0: -; LA32-NEXT: ori $a1, $zero, 4080 -; LA32-NEXT: add.w $a0, $a0, $a1 +; LA32-NEXT: addi.w $a0, $a0, 2047 +; LA32-NEXT: addi.w $a0, $a0, 2033 ; LA32-NEXT: ret ; ; LA64-LABEL: add_i32_4080: ; LA64: # %bb.0: -; LA64-NEXT: ori $a1, $zero, 4080 -; LA64-NEXT: add.w $a0, $a0, $a1 +; LA64-NEXT: addi.w $a0, $a0, 2047 +; LA64-NEXT: addi.w $a0, $a0, 2033 ; LA64-NEXT: ret %add = add i32 %x, 4080 ret i32 %add @@ -723,16 +723,14 @@ define signext i32 @add_i32_minus_4080(i32 %x) { ; LA32-LABEL: add_i32_minus_4080: ; LA32: # %bb.0: -; LA32-NEXT: lu12i.w $a1, -1 -; LA32-NEXT: ori $a1, $a1, 16 -; LA32-NEXT: add.w $a0, $a0, $a1 +; LA32-NEXT: addi.w $a0, $a0, -2048 +; LA32-NEXT: addi.w $a0, $a0, -2032 ; LA32-NEXT: ret ; ; LA64-LABEL: add_i32_minus_4080: ; LA64: # %bb.0: -; LA64-NEXT: lu12i.w $a1, -1 -; LA64-NEXT: ori $a1, $a1, 16 -; LA64-NEXT: add.w $a0, $a0, $a1 +; LA64-NEXT: addi.w $a0, $a0, -2048 +; LA64-NEXT: addi.w $a0, $a0, -2032 ; LA64-NEXT: ret %add = add i32 %x, -4080 ret i32 %add @@ -741,8 +739,8 @@ define i64 @add_i64_4080(i64 %x) { ; LA32-LABEL: add_i64_4080: ; LA32: # %bb.0: -; LA32-NEXT: ori $a2, $zero, 4080 -; LA32-NEXT: add.w $a2, $a0, $a2 +; LA32-NEXT: addi.w $a2, $a0, 2047 +; LA32-NEXT: addi.w $a2, $a2, 2033 ; LA32-NEXT: sltu $a0, $a2, $a0 ; LA32-NEXT: add.w $a1, $a1, $a0 ; LA32-NEXT: move $a0, $a2 @@ -750,8 +748,8 @@ ; ; LA64-LABEL: add_i64_4080: ; LA64: # %bb.0: -; LA64-NEXT: ori $a1, $zero, 4080 -; LA64-NEXT: add.d $a0, $a0, $a1 +; LA64-NEXT: addi.d $a0, $a0, 2047 +; LA64-NEXT: addi.d $a0, $a0, 2033 ; LA64-NEXT: ret %add = add i64 %x, 4080 ret i64 %add @@ -760,9 +758,8 @@ define i64 @add_i64_minus_4080(i64 %x) { ; LA32-LABEL: add_i64_minus_4080: ; LA32: # %bb.0: -; LA32-NEXT: lu12i.w $a2, -1 -; LA32-NEXT: ori $a2, $a2, 16 -; LA32-NEXT: add.w $a2, $a0, $a2 +; LA32-NEXT: addi.w $a2, $a0, -2048 +; LA32-NEXT: addi.w $a2, $a2, -2032 ; LA32-NEXT: sltu $a0, $a2, $a0 ; LA32-NEXT: add.w $a0, $a1, $a0 ; LA32-NEXT: addi.w $a1, $a0, -1 @@ -771,9 +768,8 @@ ; ; LA64-LABEL: add_i64_minus_4080: ; LA64: # %bb.0: -; LA64-NEXT: lu12i.w $a1, -1 -; LA64-NEXT: ori $a1, $a1, 16 -; LA64-NEXT: add.d $a0, $a0, $a1 +; LA64-NEXT: addi.d $a0, $a0, -2048 +; LA64-NEXT: addi.d $a0, $a0, -2032 ; LA64-NEXT: ret %add = add i64 %x, -4080 ret i64 %add diff --git a/llvm/test/CodeGen/LoongArch/ldptr.ll b/llvm/test/CodeGen/LoongArch/ldptr.ll --- a/llvm/test/CodeGen/LoongArch/ldptr.ll +++ b/llvm/test/CodeGen/LoongArch/ldptr.ll @@ -23,8 +23,8 @@ define signext i32 @ldptr_w(ptr %p) nounwind { ; LA32-LABEL: ldptr_w: ; LA32: # %bb.0: # %entry -; LA32-NEXT: ori $a1, $zero, 2048 -; LA32-NEXT: add.w $a0, $a0, $a1 +; LA32-NEXT: addi.w $a0, $a0, 2047 +; LA32-NEXT: addi.w $a0, $a0, 1 ; LA32-NEXT: ld.w $a0, $a0, 0 ; LA32-NEXT: ret ; @@ -81,8 +81,8 @@ define i64 @ldptr_d(ptr %p) nounwind { ; LA32-LABEL: ldptr_d: ; LA32: # %bb.0: # %entry -; LA32-NEXT: ori $a1, $zero, 2048 -; LA32-NEXT: add.w $a1, $a0, $a1 +; LA32-NEXT: addi.w $a0, $a0, 2047 +; LA32-NEXT: addi.w $a1, $a0, 1 ; LA32-NEXT: ld.w $a0, $a1, 0 ; LA32-NEXT: ld.w $a1, $a1, 4 ; LA32-NEXT: ret diff --git a/llvm/test/CodeGen/LoongArch/stptr.ll b/llvm/test/CodeGen/LoongArch/stptr.ll --- a/llvm/test/CodeGen/LoongArch/stptr.ll +++ b/llvm/test/CodeGen/LoongArch/stptr.ll @@ -22,8 +22,8 @@ define void @stptr_w(ptr %p, i32 signext %val) nounwind { ; LA32-LABEL: stptr_w: ; LA32: # %bb.0: -; LA32-NEXT: ori $a2, $zero, 2048 -; LA32-NEXT: add.w $a0, $a0, $a2 +; LA32-NEXT: addi.w $a0, $a0, 2047 +; LA32-NEXT: addi.w $a0, $a0, 1 ; LA32-NEXT: st.w $a1, $a0, 0 ; LA32-NEXT: ret ; @@ -76,8 +76,8 @@ define void @stptr_d(ptr %p, i64 %val) nounwind { ; LA32-LABEL: stptr_d: ; LA32: # %bb.0: -; LA32-NEXT: ori $a3, $zero, 2048 -; LA32-NEXT: add.w $a0, $a0, $a3 +; LA32-NEXT: addi.w $a0, $a0, 2047 +; LA32-NEXT: addi.w $a0, $a0, 1 ; LA32-NEXT: st.w $a2, $a0, 4 ; LA32-NEXT: st.w $a1, $a0, 0 ; LA32-NEXT: ret