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,14 +739,14 @@ define signext i32 @add_i32_2048(i32 %x) { ; LA32-LABEL: add_i32_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: ret ; ; LA64-LABEL: add_i32_2048: ; LA64: # %bb.0: -; LA64-NEXT: ori $a1, $zero, 2048 -; LA64-NEXT: add.w $a0, $a0, $a1 +; LA64-NEXT: addi.w $a0, $a0, 2047 +; LA64-NEXT: addi.w $a0, $a0, 1 ; LA64-NEXT: ret %add = add i32 %x, 2048 ret i32 %add @@ -757,14 +755,14 @@ define signext i32 @add_i32_4094(i32 %x) { ; LA32-LABEL: add_i32_4094: ; LA32: # %bb.0: -; LA32-NEXT: ori $a1, $zero, 4094 -; LA32-NEXT: add.w $a0, $a0, $a1 +; LA32-NEXT: addi.w $a0, $a0, 2047 +; LA32-NEXT: addi.w $a0, $a0, 2047 ; LA32-NEXT: ret ; ; LA64-LABEL: add_i32_4094: ; LA64: # %bb.0: -; LA64-NEXT: ori $a1, $zero, 4094 -; LA64-NEXT: add.w $a0, $a0, $a1 +; LA64-NEXT: addi.w $a0, $a0, 2047 +; LA64-NEXT: addi.w $a0, $a0, 2047 ; LA64-NEXT: ret %add = add i32 %x, 4094 ret i32 %add @@ -773,16 +771,14 @@ define signext i32 @add_i32_minus_2049(i32 %x) { ; LA32-LABEL: add_i32_minus_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: ret ; ; LA64-LABEL: add_i32_minus_2049: ; LA64: # %bb.0: -; LA64-NEXT: lu12i.w $a1, -1 -; LA64-NEXT: ori $a1, $a1, 2047 -; LA64-NEXT: add.w $a0, $a0, $a1 +; LA64-NEXT: addi.w $a0, $a0, -2048 +; LA64-NEXT: addi.w $a0, $a0, -1 ; LA64-NEXT: ret %add = add i32 %x, -2049 ret i32 %add @@ -791,14 +787,14 @@ define signext i32 @add_i32_minus_4096(i32 %x) { ; LA32-LABEL: add_i32_minus_4096: ; LA32: # %bb.0: -; LA32-NEXT: lu12i.w $a1, -1 -; LA32-NEXT: add.w $a0, $a0, $a1 +; LA32-NEXT: addi.w $a0, $a0, -2048 +; LA32-NEXT: addi.w $a0, $a0, -2048 ; LA32-NEXT: ret ; ; LA64-LABEL: add_i32_minus_4096: ; LA64: # %bb.0: -; LA64-NEXT: lu12i.w $a1, -1 -; LA64-NEXT: add.w $a0, $a0, $a1 +; LA64-NEXT: addi.w $a0, $a0, -2048 +; LA64-NEXT: addi.w $a0, $a0, -2048 ; LA64-NEXT: ret %add = add i32 %x, -4096 ret i32 %add @@ -807,8 +803,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 @@ -816,8 +812,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 @@ -826,9 +822,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 @@ -837,9 +832,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 @@ -848,8 +842,8 @@ define i64 @add_i64_2048(i64 %x) { ; LA32-LABEL: add_i64_2048: ; LA32: # %bb.0: -; LA32-NEXT: ori $a2, $zero, 2048 -; LA32-NEXT: add.w $a2, $a0, $a2 +; LA32-NEXT: addi.w $a2, $a0, 2047 +; LA32-NEXT: addi.w $a2, $a2, 1 ; LA32-NEXT: sltu $a0, $a2, $a0 ; LA32-NEXT: add.w $a1, $a1, $a0 ; LA32-NEXT: move $a0, $a2 @@ -857,8 +851,8 @@ ; ; LA64-LABEL: add_i64_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: ret %add = add i64 %x, 2048 ret i64 %add @@ -867,8 +861,8 @@ define i64 @add_i64_4094(i64 %x) { ; LA32-LABEL: add_i64_4094: ; LA32: # %bb.0: -; LA32-NEXT: ori $a2, $zero, 4094 -; LA32-NEXT: add.w $a2, $a0, $a2 +; LA32-NEXT: addi.w $a2, $a0, 2047 +; LA32-NEXT: addi.w $a2, $a2, 2047 ; LA32-NEXT: sltu $a0, $a2, $a0 ; LA32-NEXT: add.w $a1, $a1, $a0 ; LA32-NEXT: move $a0, $a2 @@ -876,8 +870,8 @@ ; ; LA64-LABEL: add_i64_4094: ; LA64: # %bb.0: -; LA64-NEXT: ori $a1, $zero, 4094 -; LA64-NEXT: add.d $a0, $a0, $a1 +; LA64-NEXT: addi.d $a0, $a0, 2047 +; LA64-NEXT: addi.d $a0, $a0, 2047 ; LA64-NEXT: ret %add = add i64 %x, 4094 ret i64 %add @@ -886,9 +880,8 @@ define i64 @add_i64_minus_2049(i64 %x) { ; LA32-LABEL: add_i64_minus_2049: ; LA32: # %bb.0: -; LA32-NEXT: lu12i.w $a2, -1 -; LA32-NEXT: ori $a2, $a2, 2047 -; LA32-NEXT: add.w $a2, $a0, $a2 +; LA32-NEXT: addi.w $a2, $a0, -2048 +; LA32-NEXT: addi.w $a2, $a2, -1 ; LA32-NEXT: sltu $a0, $a2, $a0 ; LA32-NEXT: add.w $a0, $a1, $a0 ; LA32-NEXT: addi.w $a1, $a0, -1 @@ -897,9 +890,8 @@ ; ; LA64-LABEL: add_i64_minus_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: ret %add = add i64 %x, -2049 ret i64 %add @@ -908,8 +900,8 @@ define i64 @add_i64_minus_4096(i64 %x) { ; LA32-LABEL: add_i64_minus_4096: ; LA32: # %bb.0: -; LA32-NEXT: lu12i.w $a2, -1 -; LA32-NEXT: add.w $a2, $a0, $a2 +; LA32-NEXT: addi.w $a2, $a0, -2048 +; LA32-NEXT: addi.w $a2, $a2, -2048 ; LA32-NEXT: sltu $a0, $a2, $a0 ; LA32-NEXT: add.w $a0, $a1, $a0 ; LA32-NEXT: addi.w $a1, $a0, -1 @@ -918,8 +910,8 @@ ; ; LA64-LABEL: add_i64_minus_4096: ; LA64: # %bb.0: -; LA64-NEXT: lu12i.w $a1, -1 -; LA64-NEXT: add.d $a0, $a0, $a1 +; LA64-NEXT: addi.d $a0, $a0, -2048 +; LA64-NEXT: addi.d $a0, $a0, -2048 ; LA64-NEXT: ret %add = add i64 %x, -4096 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