[LoongArch] Make use of addu16i.d for adds with suitable immediates
authorWANG Xuerui <git@xen0n.name>
Tue, 14 Feb 2023 00:39:19 +0000 (08:39 +0800)
committerWeining Lu <luweining@loongson.cn>
Wed, 15 Feb 2023 01:16:14 +0000 (09:16 +0800)
Ideally `addu16i.d` could be paired with `{ld,st}ptr` for faster memory
accesses with 32-bit-aligned offsets (it was designed for this purpose),
but it would require more work and the original use case (GP-relative
accesses) does not exist any more with the current LoongArch psABI.

It could still be used for accelerating additions of certain constants
though, which is what this patch intends to do.

Reviewed By: SixWeining, gonglingqin

Differential Revision: https://reviews.llvm.org/D143710

llvm/lib/Target/LoongArch/LoongArchInstrInfo.td
llvm/test/CodeGen/LoongArch/ir-instruction/add.ll

index 0e968e0..0606c65 100644 (file)
@@ -328,6 +328,17 @@ def simm26_symbol : Operand<GRLenVT> {
   let DecoderMethod = "decodeSImmOperand<26, 2>";
 }
 
+// A 32-bit signed immediate with the lowest 16 bits zeroed, suitable for
+// direct use with `addu16i.d`.
+def simm16_lsl16 : Operand<GRLenVT>,
+    ImmLeaf<GRLenVT, [{return isShiftedInt<16, 16>(Imm);}]>;
+
+// A 32-bit signed immediate expressible with a pair of `addu16i.d + addi` for
+// use in additions.
+def simm32_hi16_lo12: Operand<GRLenVT>, ImmLeaf<GRLenVT, [{
+  return isShiftedInt<16, 16>(Imm - SignExtend64<12>(Imm));
+}]>;
+
 def BareSymbol : AsmOperandClass {
   let Name = "BareSymbol";
   let RenderMethod = "addImmOperands";
@@ -363,6 +374,26 @@ def ImmSubFrom32 : SDNodeXForm<imm, [{
                                    N->getValueType(0));
 }]>;
 
+// Return the lowest 12 bits of the signed immediate.
+def LO12: SDNodeXForm<imm, [{
+  return CurDAG->getTargetConstant(SignExtend64<12>(N->getSExtValue()),
+                                   SDLoc(N), N->getValueType(0));
+}]>;
+
+// Return the higher 16 bits of the signed immediate.
+def HI16 : SDNodeXForm<imm, [{
+  return CurDAG->getTargetConstant(N->getSExtValue() >> 16, SDLoc(N),
+                                   N->getValueType(0));
+}]>;
+
+// Return the higher 16 bits of the signed immediate, adjusted for use within an
+// `addu16i.d + addi` pair.
+def HI16ForAddu16idAddiPair: SDNodeXForm<imm, [{
+  auto Imm = N->getSExtValue();
+  return CurDAG->getTargetConstant((Imm - SignExtend64<12>(Imm)) >> 16,
+                                   SDLoc(N), N->getValueType(0));
+}]>;
+
 def BaseAddr : ComplexPattern<iPTR, 1, "SelectBaseAddr">;
 def AddrConstant : ComplexPattern<iPTR, 2, "SelectAddrConstant">;
 def NonFIBaseAddr : ComplexPattern<iPTR, 1, "selectNonFIBaseAddr">;
@@ -851,6 +882,15 @@ def : Pat<(i64 (mul (sext_inreg GPR:$rj, i32), (sext_inreg GPR:$rk, i32))),
 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))>;
+def : Pat<(add GPR:$rj, simm32_hi16_lo12:$imm),
+          (ADDI_D (ADDU16I_D GPR:$rj, (HI16ForAddu16idAddiPair $imm)),
+                  (LO12 $imm))>;
+def : Pat<(sext_inreg (add GPR:$rj, simm32_hi16_lo12:$imm), i32),
+          (ADDI_W (ADDU16I_D GPR:$rj, (HI16ForAddu16idAddiPair $imm)),
+                  (LO12 $imm))>;
 } // Predicates = [IsLA64]
 
 def : PatGprGpr<and, AND>;
index 2bf6c31..3763cc2 100644 (file)
@@ -183,7 +183,7 @@ define i64 @add_i64_3(i64 %x) {
   ret i64 %add
 }
 
-;; TODO: emit `addu16i.d` for these cases.
+;; Check that `addu16i.d` is emitted for these cases.
 
 define i32 @add_i32_0x12340000(i32 %x) {
 ; LA32-LABEL: add_i32_0x12340000:
@@ -194,8 +194,7 @@ define i32 @add_i32_0x12340000(i32 %x) {
 ;
 ; LA64-LABEL: add_i32_0x12340000:
 ; LA64:       # %bb.0:
-; LA64-NEXT:    lu12i.w $a1, 74560
-; LA64-NEXT:    add.d $a0, $a0, $a1
+; LA64-NEXT:    addu16i.d $a0, $a0, 4660
 ; LA64-NEXT:    ret
   %add = add i32 %x, 305397760
   ret i32 %add
@@ -210,8 +209,8 @@ define signext i32 @add_i32_0x12340000_sext(i32 %x) {
 ;
 ; LA64-LABEL: add_i32_0x12340000_sext:
 ; LA64:       # %bb.0:
-; LA64-NEXT:    lu12i.w $a1, 74560
-; LA64-NEXT:    add.w $a0, $a0, $a1
+; LA64-NEXT:    addu16i.d $a0, $a0, 4660
+; LA64-NEXT:    addi.w $a0, $a0, 0
 ; LA64-NEXT:    ret
   %add = add i32 %x, 305397760
   ret i32 %add
@@ -229,8 +228,7 @@ define i64 @add_i64_0x12340000(i64 %x) {
 ;
 ; LA64-LABEL: add_i64_0x12340000:
 ; LA64:       # %bb.0:
-; LA64-NEXT:    lu12i.w $a1, 74560
-; LA64-NEXT:    add.d $a0, $a0, $a1
+; LA64-NEXT:    addu16i.d $a0, $a0, 4660
 ; LA64-NEXT:    ret
   %add = add i64 %x, 305397760
   ret i64 %add
@@ -245,8 +243,7 @@ define i32 @add_i32_0x7fff0000(i32 %x) {
 ;
 ; LA64-LABEL: add_i32_0x7fff0000:
 ; LA64:       # %bb.0:
-; LA64-NEXT:    lu12i.w $a1, 524272
-; LA64-NEXT:    add.d $a0, $a0, $a1
+; LA64-NEXT:    addu16i.d $a0, $a0, 32767
 ; LA64-NEXT:    ret
   %add = add i32 %x, 2147418112
   ret i32 %add
@@ -261,8 +258,8 @@ define signext i32 @add_i32_0x7fff0000_sext(i32 %x) {
 ;
 ; LA64-LABEL: add_i32_0x7fff0000_sext:
 ; LA64:       # %bb.0:
-; LA64-NEXT:    lu12i.w $a1, 524272
-; LA64-NEXT:    add.w $a0, $a0, $a1
+; LA64-NEXT:    addu16i.d $a0, $a0, 32767
+; LA64-NEXT:    addi.w $a0, $a0, 0
 ; LA64-NEXT:    ret
   %add = add i32 %x, 2147418112
   ret i32 %add
@@ -280,8 +277,7 @@ define i64 @add_i64_0x7fff0000(i64 %x) {
 ;
 ; LA64-LABEL: add_i64_0x7fff0000:
 ; LA64:       # %bb.0:
-; LA64-NEXT:    lu12i.w $a1, 524272
-; LA64-NEXT:    add.d $a0, $a0, $a1
+; LA64-NEXT:    addu16i.d $a0, $a0, 32767
 ; LA64-NEXT:    ret
   %add = add i64 %x, 2147418112
   ret i64 %add
@@ -296,8 +292,7 @@ define i32 @add_i32_minus_0x80000000(i32 %x) {
 ;
 ; LA64-LABEL: add_i32_minus_0x80000000:
 ; LA64:       # %bb.0:
-; LA64-NEXT:    lu12i.w $a1, -524288
-; LA64-NEXT:    add.d $a0, $a0, $a1
+; LA64-NEXT:    addu16i.d $a0, $a0, -32768
 ; LA64-NEXT:    ret
   %add = add i32 %x, -2147483648
   ret i32 %add
@@ -312,8 +307,8 @@ define signext i32 @add_i32_minus_0x80000000_sext(i32 %x) {
 ;
 ; LA64-LABEL: add_i32_minus_0x80000000_sext:
 ; LA64:       # %bb.0:
-; LA64-NEXT:    lu12i.w $a1, -524288
-; LA64-NEXT:    add.w $a0, $a0, $a1
+; LA64-NEXT:    addu16i.d $a0, $a0, -32768
+; LA64-NEXT:    addi.w $a0, $a0, 0
 ; LA64-NEXT:    ret
   %add = add i32 %x, -2147483648
   ret i32 %add
@@ -332,8 +327,7 @@ define i64 @add_i64_minus_0x80000000(i64 %x) {
 ;
 ; LA64-LABEL: add_i64_minus_0x80000000:
 ; LA64:       # %bb.0:
-; LA64-NEXT:    lu12i.w $a1, -524288
-; LA64-NEXT:    add.d $a0, $a0, $a1
+; LA64-NEXT:    addu16i.d $a0, $a0, -32768
 ; LA64-NEXT:    ret
   %add = add i64 %x, -2147483648
   ret i64 %add
@@ -348,8 +342,7 @@ define i32 @add_i32_minus_0x10000(i32 %x) {
 ;
 ; LA64-LABEL: add_i32_minus_0x10000:
 ; LA64:       # %bb.0:
-; LA64-NEXT:    lu12i.w $a1, -16
-; LA64-NEXT:    add.d $a0, $a0, $a1
+; LA64-NEXT:    addu16i.d $a0, $a0, -1
 ; LA64-NEXT:    ret
   %add = add i32 %x, -65536
   ret i32 %add
@@ -364,8 +357,8 @@ define signext i32 @add_i32_minus_0x10000_sext(i32 %x) {
 ;
 ; LA64-LABEL: add_i32_minus_0x10000_sext:
 ; LA64:       # %bb.0:
-; LA64-NEXT:    lu12i.w $a1, -16
-; LA64-NEXT:    add.w $a0, $a0, $a1
+; LA64-NEXT:    addu16i.d $a0, $a0, -1
+; LA64-NEXT:    addi.w $a0, $a0, 0
 ; LA64-NEXT:    ret
   %add = add i32 %x, -65536
   ret i32 %add
@@ -384,14 +377,13 @@ define i64 @add_i64_minus_0x10000(i64 %x) {
 ;
 ; LA64-LABEL: add_i64_minus_0x10000:
 ; LA64:       # %bb.0:
-; LA64-NEXT:    lu12i.w $a1, -16
-; LA64-NEXT:    add.d $a0, $a0, $a1
+; LA64-NEXT:    addu16i.d $a0, $a0, -1
 ; LA64-NEXT:    ret
   %add = add i64 %x, -65536
   ret i64 %add
 }
 
-;; TODO: use `addu16i.d + addi` for these cases.
+;; Check that `addu16i.d + addi` is emitted for these cases.
 
 define i32 @add_i32_0x7fff07ff(i32 %x) {
 ; LA32-LABEL: add_i32_0x7fff07ff:
@@ -403,9 +395,8 @@ define i32 @add_i32_0x7fff07ff(i32 %x) {
 ;
 ; LA64-LABEL: add_i32_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:    addu16i.d $a0, $a0, 32767
+; LA64-NEXT:    addi.d $a0, $a0, 2047
 ; LA64-NEXT:    ret
   %add = add i32 %x, 2147420159
   ret i32 %add
@@ -421,9 +412,8 @@ define signext i32 @add_i32_0x7fff07ff_sext(i32 %x) {
 ;
 ; LA64-LABEL: add_i32_0x7fff07ff_sext:
 ; LA64:       # %bb.0:
-; LA64-NEXT:    lu12i.w $a1, 524272
-; LA64-NEXT:    ori $a1, $a1, 2047
-; LA64-NEXT:    add.w $a0, $a0, $a1
+; LA64-NEXT:    addu16i.d $a0, $a0, 32767
+; LA64-NEXT:    addi.w $a0, $a0, 2047
 ; LA64-NEXT:    ret
   %add = add i32 %x, 2147420159
   ret i32 %add
@@ -442,9 +432,8 @@ define i64 @add_i64_0x7fff07ff(i64 %x) {
 ;
 ; 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:    addu16i.d $a0, $a0, 32767
+; LA64-NEXT:    addi.d $a0, $a0, 2047
 ; LA64-NEXT:    ret
   %add = add i64 %x, 2147420159
   ret i64 %add
@@ -460,9 +449,8 @@ define i32 @add_i32_0x7ffef800(i32 %x) {
 ;
 ; LA64-LABEL: add_i32_0x7ffef800:
 ; LA64:       # %bb.0:
-; LA64-NEXT:    lu12i.w $a1, 524271
-; LA64-NEXT:    ori $a1, $a1, 2048
-; LA64-NEXT:    add.d $a0, $a0, $a1
+; LA64-NEXT:    addu16i.d $a0, $a0, 32767
+; LA64-NEXT:    addi.d $a0, $a0, -2048
 ; LA64-NEXT:    ret
   %add = add i32 %x, 2147416064
   ret i32 %add
@@ -478,9 +466,8 @@ define signext i32 @add_i32_0x7ffef800_sext(i32 %x) {
 ;
 ; LA64-LABEL: add_i32_0x7ffef800_sext:
 ; LA64:       # %bb.0:
-; LA64-NEXT:    lu12i.w $a1, 524271
-; LA64-NEXT:    ori $a1, $a1, 2048
-; LA64-NEXT:    add.w $a0, $a0, $a1
+; LA64-NEXT:    addu16i.d $a0, $a0, 32767
+; LA64-NEXT:    addi.w $a0, $a0, -2048
 ; LA64-NEXT:    ret
   %add = add i32 %x, 2147416064
   ret i32 %add
@@ -499,9 +486,8 @@ define i64 @add_i64_0x7ffef800(i64 %x) {
 ;
 ; LA64-LABEL: add_i64_0x7ffef800:
 ; LA64:       # %bb.0:
-; LA64-NEXT:    lu12i.w $a1, 524271
-; LA64-NEXT:    ori $a1, $a1, 2048
-; LA64-NEXT:    add.d $a0, $a0, $a1
+; LA64-NEXT:    addu16i.d $a0, $a0, 32767
+; LA64-NEXT:    addi.d $a0, $a0, -2048
 ; LA64-NEXT:    ret
   %add = add i64 %x, 2147416064
   ret i64 %add
@@ -521,10 +507,8 @@ define i64 @add_i64_minus_0x80000800(i64 %x) {
 ;
 ; LA64-LABEL: add_i64_minus_0x80000800:
 ; LA64:       # %bb.0:
-; LA64-NEXT:    lu12i.w $a1, 524287
-; LA64-NEXT:    ori $a1, $a1, 2048
-; LA64-NEXT:    lu32i.d $a1, -1
-; LA64-NEXT:    add.d $a0, $a0, $a1
+; LA64-NEXT:    addu16i.d $a0, $a0, -32768
+; LA64-NEXT:    addi.d $a0, $a0, -2048
 ; LA64-NEXT:    ret
   %add = add i64 %x, -2147485696
   ret i64 %add
@@ -540,9 +524,8 @@ define i32 @add_i32_minus_0x23450679(i32 %x) {
 ;
 ; LA64-LABEL: add_i32_minus_0x23450679:
 ; LA64:       # %bb.0:
-; LA64-NEXT:    lu12i.w $a1, -144465
-; LA64-NEXT:    ori $a1, $a1, 2439
-; LA64-NEXT:    add.d $a0, $a0, $a1
+; LA64-NEXT:    addu16i.d $a0, $a0, -9029
+; LA64-NEXT:    addi.d $a0, $a0, -1657
 ; LA64-NEXT:    ret
   %add = add i32 %x, -591726201
   ret i32 %add
@@ -558,9 +541,8 @@ define signext i32 @add_i32_minus_0x23450679_sext(i32 %x) {
 ;
 ; LA64-LABEL: add_i32_minus_0x23450679_sext:
 ; LA64:       # %bb.0:
-; LA64-NEXT:    lu12i.w $a1, -144465
-; LA64-NEXT:    ori $a1, $a1, 2439
-; LA64-NEXT:    add.w $a0, $a0, $a1
+; LA64-NEXT:    addu16i.d $a0, $a0, -9029
+; LA64-NEXT:    addi.w $a0, $a0, -1657
 ; LA64-NEXT:    ret
   %add = add i32 %x, -591726201
   ret i32 %add
@@ -580,9 +562,8 @@ define i64 @add_i64_minus_0x23450679(i64 %x) {
 ;
 ; LA64-LABEL: add_i64_minus_0x23450679:
 ; LA64:       # %bb.0:
-; LA64-NEXT:    lu12i.w $a1, -144465
-; LA64-NEXT:    ori $a1, $a1, 2439
-; LA64-NEXT:    add.d $a0, $a0, $a1
+; LA64-NEXT:    addu16i.d $a0, $a0, -9029
+; LA64-NEXT:    addi.d $a0, $a0, -1657
 ; LA64-NEXT:    ret
   %add = add i64 %x, -591726201
   ret i64 %add
@@ -598,9 +579,8 @@ define i32 @add_i32_minus_0x2345fedd(i32 %x) {
 ;
 ; LA64-LABEL: add_i32_minus_0x2345fedd:
 ; LA64:       # %bb.0:
-; LA64-NEXT:    lu12i.w $a1, -144480
-; LA64-NEXT:    ori $a1, $a1, 291
-; LA64-NEXT:    add.d $a0, $a0, $a1
+; LA64-NEXT:    addu16i.d $a0, $a0, -9030
+; LA64-NEXT:    addi.d $a0, $a0, 291
 ; LA64-NEXT:    ret
   %add = add i32 %x, -591789789
   ret i32 %add
@@ -616,9 +596,8 @@ define signext i32 @add_i32_minus_0x2345fedd_sext(i32 %x) {
 ;
 ; LA64-LABEL: add_i32_minus_0x2345fedd_sext:
 ; LA64:       # %bb.0:
-; LA64-NEXT:    lu12i.w $a1, -144480
-; LA64-NEXT:    ori $a1, $a1, 291
-; LA64-NEXT:    add.w $a0, $a0, $a1
+; LA64-NEXT:    addu16i.d $a0, $a0, -9030
+; LA64-NEXT:    addi.w $a0, $a0, 291
 ; LA64-NEXT:    ret
   %add = add i32 %x, -591789789
   ret i32 %add
@@ -638,9 +617,8 @@ define i64 @add_i64_minus_0x2345fedd(i64 %x) {
 ;
 ; LA64-LABEL: add_i64_minus_0x2345fedd:
 ; LA64:       # %bb.0:
-; LA64-NEXT:    lu12i.w $a1, -144480
-; LA64-NEXT:    ori $a1, $a1, 291
-; LA64-NEXT:    add.d $a0, $a0, $a1
+; LA64-NEXT:    addu16i.d $a0, $a0, -9030
+; LA64-NEXT:    addi.d $a0, $a0, 291
 ; LA64-NEXT:    ret
   %add = add i64 %x, -591789789
   ret i64 %add