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 @@ -328,6 +328,10 @@ let DecoderMethod = "decodeSImmOperand<26, 2>"; } +// A 32-bit signed immediate with the lowest 16 bits zeroed. +def simm16_lsl16 : Operand, + ImmLeaf(Imm);}]>; + def BareSymbol : AsmOperandClass { let Name = "BareSymbol"; let RenderMethod = "addImmOperands"; @@ -363,6 +367,12 @@ N->getValueType(0)); }]>; +// Transformation Function - get the higher 16 bits. +def HI16 : SDNodeXFormgetTargetConstant(N->getSExtValue() >> 16, SDLoc(N), + N->getValueType(0)); +}]>; + def BaseAddr : ComplexPattern; def AddrConstant : ComplexPattern; def NonFIBaseAddr : ComplexPattern; @@ -851,6 +861,9 @@ def : Pat<(i64 (mul (loongarch_bstrpick GPR:$rj, (i64 31), (i64 0)), (loongarch_bstrpick GPR:$rk, (i64 31), (i64 0)))), (MULW_D_WU GPR:$rj, GPR:$rk)>; + +def : Pat<(add GPR:$rj, simm16_lsl16:$imm), + (ADDU16I_D GPR:$rj, (HI16 $imm))>; } // Predicates = [IsLA64] def : PatGprGpr; 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 @@ -182,3 +182,155 @@ %add = add i64 %x, 3 ret i64 %add } + +define i32 @add_i32_0x12340000(i32 %x) { +; LA32-LABEL: add_i32_0x12340000: +; LA32: # %bb.0: +; LA32-NEXT: lu12i.w $a1, 74560 +; LA32-NEXT: add.w $a0, $a0, $a1 +; LA32-NEXT: ret +; +; LA64-LABEL: add_i32_0x12340000: +; LA64: # %bb.0: +; LA64-NEXT: addu16i.d $a0, $a0, 4660 +; LA64-NEXT: ret + %add = add i32 %x, 305397760 + ret i32 %add +} + +define i64 @add_i64_0x12340000(i64 %x) { +; LA32-LABEL: add_i64_0x12340000: +; LA32: # %bb.0: +; LA32-NEXT: lu12i.w $a2, 74560 +; LA32-NEXT: add.w $a2, $a0, $a2 +; LA32-NEXT: sltu $a0, $a2, $a0 +; LA32-NEXT: add.w $a1, $a1, $a0 +; LA32-NEXT: move $a0, $a2 +; LA32-NEXT: ret +; +; LA64-LABEL: add_i64_0x12340000: +; LA64: # %bb.0: +; LA64-NEXT: addu16i.d $a0, $a0, 4660 +; LA64-NEXT: ret + %add = add i64 %x, 305397760 + ret i64 %add +} + +define i64 @add_i64_0x7fff0000(i64 %x) { +; LA32-LABEL: add_i64_0x7fff0000: +; LA32: # %bb.0: +; LA32-NEXT: lu12i.w $a2, 524272 +; LA32-NEXT: add.w $a2, $a0, $a2 +; LA32-NEXT: sltu $a0, $a2, $a0 +; LA32-NEXT: add.w $a1, $a1, $a0 +; LA32-NEXT: move $a0, $a2 +; LA32-NEXT: ret +; +; LA64-LABEL: add_i64_0x7fff0000: +; LA64: # %bb.0: +; LA64-NEXT: addu16i.d $a0, $a0, 32767 +; LA64-NEXT: ret + %add = add i64 %x, 2147418112 + ret i64 %add +} + +define i64 @add_i64_0x80000000(i64 %x) { +; LA32-LABEL: add_i64_0x80000000: +; LA32: # %bb.0: +; LA32-NEXT: lu12i.w $a2, -524288 +; LA32-NEXT: add.w $a2, $a0, $a2 +; LA32-NEXT: sltu $a0, $a2, $a0 +; LA32-NEXT: add.w $a1, $a1, $a0 +; LA32-NEXT: move $a0, $a2 +; LA32-NEXT: ret +; +; LA64-LABEL: add_i64_0x80000000: +; LA64: # %bb.0: +; LA64-NEXT: lu12i.w $a1, -524288 +; LA64-NEXT: lu32i.d $a1, 0 +; LA64-NEXT: add.d $a0, $a0, $a1 +; LA64-NEXT: ret + %add = add i64 %x, 2147483648 + ret i64 %add +} + +define i64 @add_i64_minus_0x80000000(i64 %x) { +; LA32-LABEL: add_i64_minus_0x80000000: +; LA32: # %bb.0: +; LA32-NEXT: lu12i.w $a2, -524288 +; LA32-NEXT: add.w $a2, $a0, $a2 +; LA32-NEXT: sltu $a0, $a2, $a0 +; LA32-NEXT: add.w $a0, $a1, $a0 +; LA32-NEXT: addi.w $a1, $a0, -1 +; LA32-NEXT: move $a0, $a2 +; LA32-NEXT: ret +; +; LA64-LABEL: add_i64_minus_0x80000000: +; LA64: # %bb.0: +; LA64-NEXT: addu16i.d $a0, $a0, -32768 +; LA64-NEXT: ret + %add = add i64 %x, -2147483648 + ret i64 %add +} + +define i64 @add_i64_0xffff0000(i64 %x) { +; LA32-LABEL: add_i64_0xffff0000: +; LA32: # %bb.0: +; LA32-NEXT: lu12i.w $a2, -16 +; LA32-NEXT: add.w $a2, $a0, $a2 +; LA32-NEXT: sltu $a0, $a2, $a0 +; LA32-NEXT: add.w $a1, $a1, $a0 +; LA32-NEXT: move $a0, $a2 +; LA32-NEXT: ret +; +; LA64-LABEL: add_i64_0xffff0000: +; LA64: # %bb.0: +; LA64-NEXT: lu12i.w $a1, -16 +; LA64-NEXT: lu32i.d $a1, 0 +; LA64-NEXT: add.d $a0, $a0, $a1 +; LA64-NEXT: ret + %add = add i64 %x, 4294901760 + ret i64 %add +} + +define i64 @add_i64_minus_0x10000(i64 %x) { +; LA32-LABEL: add_i64_minus_0x10000: +; LA32: # %bb.0: +; LA32-NEXT: lu12i.w $a2, -16 +; LA32-NEXT: add.w $a2, $a0, $a2 +; LA32-NEXT: sltu $a0, $a2, $a0 +; LA32-NEXT: add.w $a0, $a1, $a0 +; LA32-NEXT: addi.w $a1, $a0, -1 +; LA32-NEXT: move $a0, $a2 +; LA32-NEXT: ret +; +; LA64-LABEL: add_i64_minus_0x10000: +; LA64: # %bb.0: +; LA64-NEXT: addu16i.d $a0, $a0, -1 +; LA64-NEXT: ret + %add = add i64 %x, -65536 + ret i64 %add +} + +;; TODO: perform the addition with just addu16i.d + addi.d, without having to +;; first materialize the constant. +define i64 @add_i64_0x7fff07ff(i64 %x) { +; LA32-LABEL: add_i64_0x7fff07ff: +; LA32: # %bb.0: +; LA32-NEXT: lu12i.w $a2, 524272 +; LA32-NEXT: ori $a2, $a2, 2047 +; LA32-NEXT: add.w $a2, $a0, $a2 +; LA32-NEXT: sltu $a0, $a2, $a0 +; LA32-NEXT: add.w $a1, $a1, $a0 +; LA32-NEXT: move $a0, $a2 +; LA32-NEXT: ret +; +; LA64-LABEL: add_i64_0x7fff07ff: +; LA64: # %bb.0: +; LA64-NEXT: lu12i.w $a1, 524272 +; LA64-NEXT: ori $a1, $a1, 2047 +; LA64-NEXT: add.d $a0, $a0, $a1 +; LA64-NEXT: ret + %add = add i64 %x, 2147420159 + ret i64 %add +}