[llvm] [AArch64][GlobalISel] Prefer to use Vector Truncate (PR #105692)

Matt Arsenault via llvm-commits llvm-commits at lists.llvm.org
Wed Aug 28 07:00:08 PDT 2024


================
@@ -3313,6 +3313,120 @@ static bool isConstValidTrue(const TargetLowering &TLI, unsigned ScalarSizeBits,
          isConstTrueVal(TLI, Cst, IsVector, IsFP);
 }
 
+// This combine tries to reduce the number of scalarised G_TRUNC instructions by
+// using vector truncates instead
+//
+// EXAMPLE:
+// %a(i32), %b(i32) = G_UNMERGE_VALUES %src(<2 x i32>)
+// %T_a(i16) = G_TRUNC %a(i32)
+// %T_b(i16) = G_TRUNC %b(i32)
+// %Undef(i16) = G_IMPLICIT_DEF(i16)
+// %dst(v4i16) = G_BUILD_VECTORS %T_a(i16), %T_b(i16), %Undef(i16), %Undef(i16)
+//
+// ===>
+// %Undef(<2 x i32>) = G_IMPLICIT_DEF(<2 x i32>)
+// %Mid(<4 x s32>) = G_CONCAT_VECTORS %src(<2 x i32>), %Undef(<2 x i32>)
+// %dst(<4 x s16>) = G_TRUNC %Mid(<4 x s32>)
+//
+// This will ALSO match:
+// %a(i32), %b(i32) = G_UNMERGE_VALUES %src(<2 x i32>)
+// %Undef(i32) = G_IMPLICIT_DEF(i32)
+// %dst(v4i32) = G_BUILD_VECTORS %T_a(i32), %T_b(i32), %Undef(i32), %Undef(i32)
+//
+// ===>
+// %Undef(<2 x i32>) = G_IMPLICIT_DEF(<2 x i32>)
+// %Mid(<4 x s32>) = G_CONCAT_VECTORS %src(<2 x i32>), %Undef(<2 x i32>)
+//
+bool CombinerHelper::matchUseVectorTruncate(MachineInstr &MI,
+                                            Register &MatchInfo) {
+  assert(MI.getOpcode() == TargetOpcode::G_BUILD_VECTOR &&
+         "Expected G_BUILD_VECTOR instruction\n");
+
+  unsigned NumOperands = MI.getNumOperands();
+  LLT DstTy = MRI.getType(MI.getOperand(0).getReg());
+
+  // Check the G_BUILD_VECTOR sources
+  SmallVector<MachineInstr *> TruncMIs;
+  for (unsigned i = 1; i < NumOperands; ++i) {
+    auto SrcMI = MRI.getVRegDef(MI.getOperand(i).getReg());
+    auto SrcMIOpc = SrcMI->getOpcode();
+
+    if (SrcMIOpc == TargetOpcode::G_TRUNC)
+      TruncMIs.push_back(SrcMI);
+    else if (SrcMIOpc != TargetOpcode::G_IMPLICIT_DEF)
+      return false;
+  }
+
+  if (TruncMIs.size() < 2)
+    return false;
+
+  // Check if the Trunc instructions all come from the same MI
+  auto UnmergeMI = MRI.getVRegDef(TruncMIs[0]->getOperand(1).getReg());
+  if (UnmergeMI->getOpcode() != TargetOpcode::G_UNMERGE_VALUES)
+    return false;
+
+  for (auto TruncMI : TruncMIs) {
+    auto SrcMI = MRI.getVRegDef(TruncMI->getOperand(1).getReg());
+    if (!UnmergeMI->isIdenticalTo(*SrcMI))
+      return false;
+  }
+
+  // Check the size of unmerge source
+  unsigned numOps = UnmergeMI->getNumOperands();
+  MatchInfo = UnmergeMI->getOperand(numOps - 1).getReg();
+  LLT UnmergeSrcTy = MRI.getType(MatchInfo);
+  unsigned DstTyNumElts = DstTy.getNumElements();
+  unsigned UnmergeSrcTyNumElts = UnmergeSrcTy.getNumElements();
+  if (DstTyNumElts % UnmergeSrcTyNumElts != 0)
+    return false;
+
+  // If post legalizer, ensure generated instructions are legal
+  if (!IsPreLegalize) {
+    LLT MidTy = DstTy.changeElementSize(UnmergeSrcTy.getScalarSizeInBits());
+
+    if (DstTyNumElts != UnmergeSrcTyNumElts &&
+        !isLegal({TargetOpcode::G_CONCAT_VECTORS, {MidTy, UnmergeSrcTy}}))
+      return false;
+
+    if (!isLegal({TargetOpcode::G_TRUNC, {DstTy, MidTy}}))
+      return false;
+  }
+
+  return true;
+}
+
+void CombinerHelper::applyUseVectorTruncate(MachineInstr &MI,
+                                            Register &MatchInfo) {
+  assert(MI.getOpcode() == TargetOpcode::G_BUILD_VECTOR &&
----------------
arsenm wrote:

Same as above, use the same cast 

https://github.com/llvm/llvm-project/pull/105692


More information about the llvm-commits mailing list