================
@@ -0,0 +1,1116 @@
+//=- PISACombine.td - Define PISA Combine Rules --------------*- tablegen 
-*-=//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This file defines GlobalISel combine rules for the PISA target.
+///
+//===----------------------------------------------------------------------===//
+
+include "llvm/Target/GlobalISel/Combine.td"
+
+def extra_commute_iconstant_to_rhs : GICombineRule<
+  (defs root:$root),
+  (match (wip_match_opcode G_SMIN, G_SMAX, G_UMIN, G_UMAX, G_UADDO, G_SADDO,
+                           G_UMULO, G_SMULO, G_UMULH, G_SMULH, G_UADDSAT,
+                           G_SADDSAT, G_SMULFIX, G_UMULFIX, G_SMULFIXSAT,
+                           G_UMULFIXSAT):$root, [{
+    return getIConstantVRegVal(${root}->getOperand(1).getReg(), 
MRI).has_value() &&
+        !getIConstantVRegVal(${root}->getOperand(2).getReg(), MRI).has_value();
+  }]),
+  (apply [{
+    Observer.changingInstr(*${root});
+    Register LHSReg = ${root}->getOperand(1).getReg();
+    Register RHSReg = ${root}->getOperand(2).getReg();
+    ${root}->getOperand(1).setReg(RHSReg);
+    ${root}->getOperand(2).setReg(LHSReg);
+    Observer.changedInstr(*${root});
+  }])
+>;
+
+def extra_commute_fconstant_to_rhs : GICombineRule<
+  (defs root:$root),
+  (match (wip_match_opcode G_FMINNUM, G_FMAXNUM, G_FMINNUM_IEEE,
+                           G_FMAXNUM_IEEE, G_FMINIMUM, G_FMAXIMUM,
+                           G_FADD, G_FMUL):$root, [{
+    return getFConstantVRegValWithLookThrough(${root}->getOperand(1).getReg(), 
MRI).has_value() &&
+           
!getFConstantVRegValWithLookThrough(${root}->getOperand(2).getReg(), 
MRI).has_value();
+  }]),
+  (apply [{
+    Observer.changingInstr(*${root});
+    Register LHSReg = ${root}->getOperand(1).getReg();
+    Register RHSReg = ${root}->getOperand(2).getReg();
+    ${root}->getOperand(1).setReg(RHSReg);
+    ${root}->getOperand(2).setReg(LHSReg);
+    Observer.changedInstr(*${root});
+  }])
+>;
+
+def extra_commute_intrinsic_iconstant_to_rhs : GICombineRule<
+  (defs root:$root),
+  (match (wip_match_opcode G_INTRINSIC):$root, [{
+    Intrinsic::ID IntrinsicID = cast<GIntrinsic>(*${root}).getIntrinsicID();
+    bool IsFloatArg = false;
+    switch (IntrinsicID) {
+      default:
+        return false;
+      case Intrinsic::pisa_fadd:
+      case Intrinsic::pisa_fmul:
+        IsFloatArg = true;
+        break;
+    }
+    return IsFloatArg ?
+          (getFConstantVRegValWithLookThrough(${root}->getOperand(2).getReg(), 
MRI).has_value() &&
+            
!getFConstantVRegValWithLookThrough(${root}->getOperand(3).getReg(), 
MRI).has_value()) :
+          (getIConstantVRegVal(${root}->getOperand(2).getReg(), 
MRI).has_value() &&
+            !getIConstantVRegVal(${root}->getOperand(3).getReg(), 
MRI).has_value());
+  }]),
+  (apply [{
+    Observer.changingInstr(*${root});
+    Register LHSReg = ${root}->getOperand(2).getReg();
+    Register RHSReg = ${root}->getOperand(3).getReg();
+    ${root}->getOperand(2).setReg(RHSReg);
+    ${root}->getOperand(3).setReg(LHSReg);
+    Observer.changedInstr(*${root});
+  }])
+>;
+
+// AND rd1, rs1, C1
+//   AND rd2, rd1, C1 - remove copy
+def extra_remove_redundant_constant : GICombineRule<
+  (defs root:$root, register_matchinfo:$matchinfo),
+  (match (wip_match_opcode G_AND, G_OR):$root,
+    [{
+      std::optional<ValueAndVReg> C1 =
+          getIConstantVRegValWithLookThrough(
+              ${root}->getOperand(2).getReg(), MRI);
+      if (C1.has_value()) {
+        MachineInstr *DefMI =
+            getDefIgnoringCopies(${root}->getOperand(1).getReg(), MRI);
+        if (DefMI && (${root}->getOpcode() == DefMI->getOpcode())) {
+          std::optional<ValueAndVReg> C2 =
+              getIConstantVRegValWithLookThrough(
+                  DefMI->getOperand(2).getReg(), MRI);
+          if (C2.has_value()) {
+            ${matchinfo} = DefMI->getOperand(0).getReg();
+            return C1->Value == C2->Value;
+          }
+        }
+      }
+      return false;
+    }]),
+  (apply
+    [{
+      Helper.replaceSingleDefInstWithReg(*${root}, ${matchinfo});
+    }])
+>;
+
+// G_[F]CONSTANT i16 x
+// G_[F]CONSTANT i16 y
+// G_[F]CONSTANT i16 z
+// G_[F]CONSTANT i16 w
+// G_BUILD_VECTOR x, y, z, w
+// => G_CONSTANT i64 [wzyx]
+// => G_BITCAST
+def build_vector_with_constants : GICombineRule<
+  (defs root:$root),
+  (match (wip_match_opcode G_BUILD_VECTOR):$root,
+    [{
+      LLT Type = MRI.getType(${root}->getOperand(0).getReg());
+      if (Type.isPointerVector())
+        return false;
+      TypeSize Size = Type.getSizeInBits();
+      if ((Size <= 64) && isPowerOf2_32(Size)) {
+        for (unsigned I=1; I < ${root}->getNumOperands(); I++) {
+          std::optional<ValueAndVReg> C =
+              getAnyConstantVRegValWithLookThrough(
+                  ${root}->getOperand(I).getReg(), MRI);
+          if (!C.has_value()) {
+              return false;
+          }
+        }
+        return true;
+      }
+      return false;
+    }]),
+  (apply
+    [{
+      applyBuildVectorWithConstants(*${root});
+    }])
+>;
+
+// i56 = G_LOAD x
+// i32 = G_TRUNC i56
+// => i32 = G_LOAD x
+def truncated_load : GICombineRule<
+  (defs root:$root),
+  (match (wip_match_opcode G_TRUNC):$root,
+    [{
+      MachineInstr *DefMI =
+          getDefIgnoringCopies(${root}->getOperand(1).getReg(), MRI);
+      LLT Type = MRI.getType(DefMI->getOperand(0).getReg());
+      TypeSize Size = Type.getSizeInBits();
+      bool IsVector = Type.isVector();
+      return !isPowerOf2_32(Size) && !IsVector && (DefMI->getOpcode() == 
TargetOpcode::G_LOAD);
+    }]),
+  (apply
+    [{
+      applyTruncatedLoad(*${root});
+    }])
+>;
+
+// i24 x = G_TRUNC i32
+// G_STORE i24 x
+// => <4 x i8> y = BITCAST x
+// <3 x i8> z = SHUFFLE_VECTOR y, <0,1,2>
+// G_STORE <3 x i8> z
+def truncated_store : GICombineRule<
+  (defs root:$root),
+  (match (wip_match_opcode G_STORE):$root,
+    [{
+      return matchTruncatedStore(*${root});
+    }]),
+  (apply
+    [{
+      applyTruncatedStore(*${root});
+    }])
+>;
+
+// i24 = G_LOAD x
+// i32 = G_ZEXT i24
+// =>
+// i32 loadRes = G_LOAD x
+// i32 = AND loadRes, 0x00FFFFFF
+def extended_load : GICombineRule<
+  (defs root:$root),
+  (match (wip_match_opcode G_ZEXT):$root,
+    [{
+      return matchExtendedLoad(*${root});
+    }]),
+  (apply
+    [{
+      applyExtendedLoad(*${root});
+    }])
+>;
+
+// i24 = G_LOAD x
+// => 
+// %3:_(s24) = G_ZEXTLOAD %0:reg32b(p0)
+// %7:_(s32) = G_CONSTANT i32 2
+// %6:reg32b(p0) = G_PTR_ADD %0:reg32b, %7:_(s32)
+// %9:_(s24) = G_ZEXTLOAD %6:reg32b(p0)
+// %11:_(s24) = G_CONSTANT i24 16
+// %10:_(s24) = G_SHL %9:_, %11:_(s24)
+// %12:_(s24) = G_OR %3:_, %10:_
+// Similar transformation is done for G_STORE.
+def expand_nonpowerof2_load_store : GICombineRule<
+  (defs root:$root),
+  (match (wip_match_opcode G_LOAD, G_STORE):$root,
+    [{
+      return matchExpandNonPowerOf2LoadStore(*${root});
+    }]),
+  (apply
+    [{
+      applyExpandNonPowerOf2LoadStore(*${root});
+    }])
+>;
+
+// If the value we store resulted from a G_LOAD that the rule above expanded,
+// then we can use the individual load values directly instead of merging into
+// one integer, and then splitting it again. Size modifications between the
+// loads and store (i.e. SEXT/ZEXT/TRUNC) are also supported by
+// truncating/extending the relevant load results (or, in the case of
+// truncation, ignoring some loads entirely)
+//
+// Below is a simple example where we simply load and store an i56:
+//
+//  bb.1.entry:
+//    %0:reg32b(p0) = functionParameter_32b 0
+// -> %3:_(s56) = G_ZEXTLOAD %0:reg32b(p0) ::
+//      (load (s32) from %ir.dst)
+//    %4:_(s56) = G_CONSTANT i56 0
+//    %7:_(s32) = G_CONSTANT i32 4
+//    %6:reg32b(p0) = G_PTR_ADD %0:reg32b, %7:_(s32)
+// -> %9:_(s56) = G_ZEXTLOAD %6:reg32b(p0) ::
+//      (load (s16) from %ir.dst + 4, align 4)
+//    %11:_(s56) = G_CONSTANT i56 32
+//    %10:_(s56) = G_SHL %9:_, %11:_(s56)
+//    %12:_(s56) = G_OR %3:_, %10:_
+//    %14:_(s32) = G_CONSTANT i32 6
+//    %13:reg32b(p0) = G_PTR_ADD %0:reg32b, %14:_(s32)
+// -> %16:_(s56) = G_ZEXTLOAD %13:reg32b(p0) ::
+//      (load (s8) from %ir.dst + 6, align 2, basealign 4)
+//    %18:_(s56) = G_CONSTANT i56 48
+//    %17:_(s56) = G_SHL %16:_, %18:_(s56)
+//    %19:_(s56) = G_OR %12:_, %17:_
+//    G_STORE %19:_(s56), %0:reg32b(p0) ::
+//      (store (s56) into %ir.dst, align 4)
+//    ret
+def loadVector_matchinfo : GIDefMatchData<"SmallVector<std::pair<MachineInstr 
*, unsigned>, 8>">;
+def MI_matchinfo : GIDefMatchData<"MachineInstr *">;
+def simplify_nonpowerof2_load_store_chain : GICombineRule<
+  (defs root:$root, loadVector_matchinfo:$matchinfo, 
MI_matchinfo:$MI_matchinfo),
+  (match (wip_match_opcode G_STORE):$root,
+    [{
+      return matchSimplifyNonPowerOf2LoadStoreChain(*${root}, ${matchinfo}, 
${MI_matchinfo});
+    }]),
+  (apply
+    [{
+      applySimplifyNonPowerOf2LoadStoreChain(*${root}, ${matchinfo}, 
${MI_matchinfo});
+    }])
+>;
+
+// i1 C = G_CMP ne i? A, 0
+// i? S = G_SELECT i1 C, i? LHS, i? RHS
+// => S = sel.? LHS, RHS, A
+// ... or ... 
+// i1 C = G_CMP eq i? A, 0
+// i? S = G_SELECT i1 C, i? LHS, i? RHS
+// => S = sel.? RHS, LHS, A
+def compare_select_reg : GICombineRule<
+  (defs root:$SelectMI),
+  (match (wip_match_opcode G_SELECT):$SelectMI,
+    [{
+      return matchCompareSelect(${SelectMI});
+    }]),
+  (apply
+    [{
+      applyCompareSelect(${SelectMI});
+    }])
+>;
+
+// arcp G_FDIV %0, %1
+// => 
+// %rcp = arcp G_INTRINSIC intrinsic(@llvm.pisa.frcp), %1
+// %result = arcp G_FMUL %0, %rcp
+def fdiv_to_rcp_fmul : GICombineRule<
+  (defs root:$root, build_fn_matchinfo:$matchinfo),
+  (match (wip_match_opcode G_FDIV):$root,
+    [{ return matchFDivToRcpFMul(*${root}, ${matchinfo}); }]),
+  (apply [{ Helper.applyBuildFn(*${root}, ${matchinfo}); }])
+>;
+
+//%2:registers(s32) = G_SHL %0:reg32b, 2
+//%4:registers(s32) = G_ADD %2:registers, %3:registers
+// => %4:registers(s32) = G_PISA_SMAD %0:reg32b, 4, %3:registers
+def shl_add_to_mad : GICombineRule<
+  (defs root:$root, build_fn_matchinfo:$matchinfo),
+  (match (wip_match_opcode G_ADD):$root,
+    [{ return matchShlAddToMad(*${root}, ${matchinfo}); }]),
+  (apply [{ Helper.applyBuildFn(*${root}, ${matchinfo}); }])>;
+
+
+// i32 %lo = G_TRUNC i32 a 16
+// i32 %shift = G_LSHR i32 a 16
+// %hi = G_TRUNC i32 %shift to i16
+// => %1 = G_BITCAST i32 a to <2 x 16>
+// => %hi = G_EXTRACT_VECTOR_ELT <2 x 16> %1, 1
+// => %lo = G_EXTRACT_VECTOR_ELT <2 x 16> %1, 0 
+def trunc_shift_to_vector_extract : GICombineRule<
+  (defs root:$TruncMI),
+  (match (wip_match_opcode G_TRUNC):$TruncMI,
+    [{ return matchTruncatedShift(*${TruncMI}); }]),
+  (apply
+    [{ applyTruncatedShift(*${TruncMI}); }])
+>;
+
+// %5 = G_CONSTANT i16 x
+// %6 = G_CONSTANT i16 y
+// %7 = G_AND %5:_, %6:_
+// %2 = G_TRUNC %7 to i8
+// => %2 = COPY (i8)(x & y)
+def const_and_trunc_to_copy : GICombineRule<
+  (defs root:$root),
+  (match (wip_match_opcode G_TRUNC):$root,
+    [{
+      MachineInstr *AndMI =
+          getDefIgnoringCopies(${root}->getOperand(1).getReg(), MRI);
+      if (AndMI->getOpcode() == TargetOpcode::G_AND) {
+        std::optional<ValueAndVReg> C1 =
+            getIConstantVRegValWithLookThrough(
+                AndMI->getOperand(1).getReg(), MRI);
+        std::optional<ValueAndVReg> C2 =
+            getIConstantVRegValWithLookThrough(
+                AndMI->getOperand(2).getReg(), MRI);
+        if (C1.has_value() && C2.has_value()) {
+          APInt Value = C1->Value & C2->Value;
+          return (Value.getZExtValue() >> 
MRI.getType(${root}->getOperand(0).getReg()).getSizeInBits()) == 0;
+        }
+      }
+      return false;
+    }]),
+  (apply
+    [{ 
+      MachineInstr *AndMI =
+          getDefIgnoringCopies(${root}->getOperand(1).getReg(), MRI);
+      std::optional<ValueAndVReg> C1 =
+          getIConstantVRegValWithLookThrough(
+              AndMI->getOperand(1).getReg(), MRI);
+      std::optional<ValueAndVReg> C2 =
+          getIConstantVRegValWithLookThrough(
+              AndMI->getOperand(2).getReg(), MRI);
+      APInt Value = (C1->Value & C2->Value)
+                        .trunc(MRI.getType(${root}->getOperand(0).getReg())
+                                   .getSizeInBits());
+      Helper.replaceInstWithConstant(*${root}, Value);
+    }])
+>;
+
+// G_AND (G_ZEXT x), C -> G_ZEXT (G_AND x, trunc(C)).
+// CodeGenPrepare can form the widened mask, but keeping the mask narrow lets
+// address folding see the original arithmetic shape.
+def zext_and_to_and_zext : GICombineRule<
+  (defs root:$root, build_fn_matchinfo:$matchinfo),
+  (match (wip_match_opcode G_AND):$root,
+    [{ return matchZExtAndToAndZExt(*${root}, ${matchinfo}); }]),
+  (apply [{ Helper.applyBuildFn(*${root}, ${matchinfo}); }])>;
+
+// %114:_(<5 x s32>) = G_EXTRACT_SUBVECTOR %113:_(<8 x s32>), 0
+// %65:_(s32) = G_EXTRACT_VECTOR_ELT %114:_(<5 x s32>), %66:_(s32)
+// => %65:_(s32) = G_EXTRACT_VECTOR_ELT %113:_(<8 x s32>), %66:_(s32)
+
+def extract_subvector_to_extract_elt : GICombineRule<
+  (defs root:$root),
+  (match (wip_match_opcode G_EXTRACT_VECTOR_ELT):$root,
+    [{
+      MachineInstr *SubvectorMI =
+          getDefIgnoringCopies(${root}->getOperand(1).getReg(), MRI);
+      if (!SubvectorMI) {
+        return false;
+      }
+      if (SubvectorMI->getOpcode() != TargetOpcode::G_EXTRACT_SUBVECTOR) {
+        return false;
+      }
+      if (SubvectorMI->getOperand(2).isReg()){
+       // Skip to avoid needing to generate add instruction for index 
adjustment.
+       return false;
+      }
+      std::optional<ValueAndVReg> C =
+          getIConstantVRegValWithLookThrough(
+              ${root}->getOperand(2).getReg(), MRI);
+      if (!C.has_value()){
+        if (SubvectorMI->getOperand(2).getImm() != 0){
+        // Skip to avoid needing to generate add instruction for index 
adjustment.
+          return false;
+         }
+      }
+      LLVM_DEBUG(dbgs() << "  Success: extract_subvector_to_extract_elt rule 
matches!\n");
+      return true;
+    }]),
+  (apply
+    [{
+      MachineInstr *SubvectorMI =
+          getDefIgnoringCopies(${root}->getOperand(1).getReg(), MRI);
+      Register SrcReg = SubvectorMI->getOperand(1).getReg();
+      Register IdxReg = ${root}->getOperand(2).getReg();
+      Register DstReg = ${root}->getOperand(0).getReg();
+      std::optional<ValueAndVReg> C =
+          getIConstantVRegValWithLookThrough(
+              ${root}->getOperand(2).getReg(), MRI);
+      if (C.has_value() && SubvectorMI->getOperand(2).isImm()){
+        uint64_t NewIdx = C->Value.getZExtValue() + 
SubvectorMI->getOperand(2).getImm();
+        B.buildExtractVectorElementConstant(DstReg, SrcReg, NewIdx);
+      }
+      else {
----------------
topperc wrote:

else should be on the same line as the previous closing brace

https://github.com/llvm/llvm-project/pull/214107
_______________________________________________
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits

Reply via email to