[llvm] [Instructions] cache computed shufflevector properties (PR #115536)

Princeton Ferro via llvm-commits llvm-commits at lists.llvm.org
Wed Jan 22 01:10:59 PST 2025


https://github.com/Prince781 updated https://github.com/llvm/llvm-project/pull/115536

>From b49de7e5f366dde0e8a7360a522d2cec44e3d94d Mon Sep 17 00:00:00 2001
From: Princeton Ferro <pferro at nvidia.com>
Date: Sat, 7 Dec 2024 21:30:20 -0500
Subject: [PATCH 1/4] [Instructions] cache computed shufflevector properties

- Cache computed properties of a shufflevector mask.
- Merge several shuffle mask property analyses into a single analysis
  and introduce ShuffleMaskAttrs.
- Compute the properties on shufflevector construction.
---
 llvm/include/llvm/IR/Instructions.h | 160 ++++++++++++++------------
 llvm/lib/IR/Instructions.cpp        | 169 ++++++++++++++++++----------
 2 files changed, 197 insertions(+), 132 deletions(-)

diff --git a/llvm/include/llvm/IR/Instructions.h b/llvm/include/llvm/IR/Instructions.h
index 9a41971b63373c..f8702704b49ff2 100644
--- a/llvm/include/llvm/IR/Instructions.h
+++ b/llvm/include/llvm/IR/Instructions.h
@@ -1888,6 +1888,76 @@ DEFINE_TRANSPARENT_OPERAND_ACCESSORS(InsertElementInst, Value)
 
 constexpr int PoisonMaskElem = -1;
 
+/// Attributes of a shufflevector mask.
+struct ShuffleMaskAttrs {
+  /// If the shuffle chooses elements from exactly one source vector without
+  /// changing the length of that vector.
+  /// Example: shufflevector <4 x n> A, <4 x n> B, <3,0,undef,3>
+  /// TODO: Optionally allow length-changing shuffles.
+  bool SingleSource : 1;
+
+  /// If the shuffle chooses elements from exactly one source vector without
+  /// lane crossings and does not change the number of elements from its input
+  /// vectors.
+  /// Example: shufflevector <4 x n> A, <4 x n> B, <4,undef,6,undef>
+  bool Identity : 1;
+
+  /// If the shuffle lengthens exactly one source vector with undefs in the
+  /// high elements.
+  bool IdentityWithPadding : 1;
+
+  /// If the shuffle extracts the first N elements of exactly one source
+  /// vector.
+  bool IdentityWithExtract : 1;
+
+  /// If the shuffle concatenates the two source vectors. This is false if
+  /// either input is undefined. In that case, the shuffle is better classified
+  /// as an identity with padding operation.
+  bool Concat : 1;
+
+  /// If the shuffle swaps the order of elements from exactly one source vector.
+  /// Example: shufflevector <4 x n> A, <4 x n> B, <3,undef,1,undef>
+  /// TODO: Optionally allow length-changing shuffles.
+  bool Reverse : 1;
+
+  /// If all elements of the shuffle are the same value as the first element of
+  /// exactly one source vector without changing the length of that vector.
+  /// Example: shufflevector <4 x n> A, <4 x n> B, <undef,0,undef,0>
+  /// TODO: Optionally allow length-changing shuffles.
+  /// TODO: Optionally allow splats from other elements.
+  bool ZeroEltSplat : 1;
+
+  /// Return true if this shuffle chooses elements from its source vectors
+  /// without lane crossings and all operands have the same number of elements.
+  /// In other words, this shuffle is equivalent to a vector select with a
+  /// constant condition operand.
+  /// Example: shufflevector <4 x n> A, <4 x n> B, <undef,1,6,3>
+  /// This returns false if the mask does not choose from both input vectors.
+  /// In that case, the shuffle is better classified as an identity shuffle.
+  /// TODO: Optionally allow length-changing shuffles.
+  bool Select : 1;
+
+  /// If the shuffle transposes the elements of its inputs without changing the
+  /// length of the vectors. This operation may also be known as a merge or
+  /// interleave. See the description for isTransposeMask() for the exact
+  /// specification.
+  /// Example: shufflevector <4 x n> A, <4 x n> B, <0,4,2,6>
+  bool Transpose : 1;
+
+  /// If the shuffle splices two inputs without changing the length of the
+  /// vectors. This operation concatenates the two inputs together and then
+  /// extracts an original width vector starting from the splice index.
+  /// Example: shufflevector <4 x n> A, <4 x n> B, <1,2,3,4>
+  bool Splice : 1;
+
+  /// The starting index of the splice.
+  /// Example: 1, from the previous example
+  int SpliceIndex;
+};
+
+static_assert(sizeof(ShuffleMaskAttrs) <= sizeof(uint64_t),
+              "ShuffleMaskAttrs is too large!");
+
 /// This instruction constructs a fixed permutation of two
 /// input vectors.
 ///
@@ -1903,6 +1973,7 @@ class ShuffleVectorInst : public Instruction {
 
   SmallVector<int, 4> ShuffleMask;
   Constant *ShuffleMaskForBitcode;
+  ShuffleMaskAttrs MaskAttrs;
 
 protected:
   // Note: Instruction needs to be a friend here to call cloneImpl.
@@ -1929,6 +2000,12 @@ class ShuffleVectorInst : public Instruction {
   /// of the instruction.
   void commute();
 
+  // Analyze mask of fixed vector. NumOpElts is number of known elements in
+  // operand1/operand2. Scalable is set if any operands are scalable vectors.
+  // HasUndefOp is set if there are any undef operands.
+  static ShuffleMaskAttrs analyzeMask(ArrayRef<int> Mask, int NumOpElts,
+                                      bool Scalable, bool HasUndefOp);
+
   /// Return true if a shufflevector instruction can be
   /// formed with the specified operands.
   static bool isValidOperands(const Value *V1, const Value *V2,
@@ -2009,14 +2086,7 @@ class ShuffleVectorInst : public Instruction {
     return isSingleSourceMask(MaskAsInts, NumSrcElts);
   }
 
-  /// Return true if this shuffle chooses elements from exactly one source
-  /// vector without changing the length of that vector.
-  /// Example: shufflevector <4 x n> A, <4 x n> B, <3,0,undef,3>
-  /// TODO: Optionally allow length-changing shuffles.
-  bool isSingleSource() const {
-    return !changesLength() &&
-           isSingleSourceMask(ShuffleMask, ShuffleMask.size());
-  }
+  bool isSingleSource() const { return MaskAttrs.SingleSource; }
 
   /// Return true if this shuffle mask chooses elements from exactly one source
   /// vector without lane crossings. A shuffle using this mask is not
@@ -2037,31 +2107,13 @@ class ShuffleVectorInst : public Instruction {
     return isIdentityMask(MaskAsInts, NumSrcElts);
   }
 
-  /// Return true if this shuffle chooses elements from exactly one source
-  /// vector without lane crossings and does not change the number of elements
-  /// from its input vectors.
-  /// Example: shufflevector <4 x n> A, <4 x n> B, <4,undef,6,undef>
-  bool isIdentity() const {
-    // Not possible to express a shuffle mask for a scalable vector for this
-    // case.
-    if (isa<ScalableVectorType>(getType()))
-      return false;
-
-    return !changesLength() && isIdentityMask(ShuffleMask, ShuffleMask.size());
-  }
+  bool isIdentity() const { return MaskAttrs.Identity; }
 
-  /// Return true if this shuffle lengthens exactly one source vector with
-  /// undefs in the high elements.
-  bool isIdentityWithPadding() const;
+  bool isIdentityWithPadding() const { return MaskAttrs.IdentityWithPadding; }
 
-  /// Return true if this shuffle extracts the first N elements of exactly one
-  /// source vector.
-  bool isIdentityWithExtract() const;
+  bool isIdentityWithExtract() const { return MaskAttrs.IdentityWithExtract; }
 
-  /// Return true if this shuffle concatenates its 2 source vectors. This
-  /// returns false if either input is undefined. In that case, the shuffle is
-  /// is better classified as an identity with padding operation.
-  bool isConcat() const;
+  bool isConcat() const { return MaskAttrs.Concat; }
 
   /// Return true if this shuffle mask chooses elements from its source vectors
   /// without lane crossings. A shuffle using this mask would be
@@ -2079,17 +2131,7 @@ class ShuffleVectorInst : public Instruction {
     return isSelectMask(MaskAsInts, NumSrcElts);
   }
 
-  /// Return true if this shuffle chooses elements from its source vectors
-  /// without lane crossings and all operands have the same number of elements.
-  /// In other words, this shuffle is equivalent to a vector select with a
-  /// constant condition operand.
-  /// Example: shufflevector <4 x n> A, <4 x n> B, <undef,1,6,3>
-  /// This returns false if the mask does not choose from both input vectors.
-  /// In that case, the shuffle is better classified as an identity shuffle.
-  /// TODO: Optionally allow length-changing shuffles.
-  bool isSelect() const {
-    return !changesLength() && isSelectMask(ShuffleMask, ShuffleMask.size());
-  }
+  bool isSelect() const { return MaskAttrs.Select; }
 
   /// Return true if this shuffle mask swaps the order of elements from exactly
   /// one source vector.
@@ -2104,13 +2146,7 @@ class ShuffleVectorInst : public Instruction {
     return isReverseMask(MaskAsInts, NumSrcElts);
   }
 
-  /// Return true if this shuffle swaps the order of elements from exactly
-  /// one source vector.
-  /// Example: shufflevector <4 x n> A, <4 x n> B, <3,undef,1,undef>
-  /// TODO: Optionally allow length-changing shuffles.
-  bool isReverse() const {
-    return !changesLength() && isReverseMask(ShuffleMask, ShuffleMask.size());
-  }
+  bool isReverse() const { return MaskAttrs.Reverse; }
 
   /// Return true if this shuffle mask chooses all elements with the same value
   /// as the first element of exactly one source vector.
@@ -2125,16 +2161,7 @@ class ShuffleVectorInst : public Instruction {
     return isZeroEltSplatMask(MaskAsInts, NumSrcElts);
   }
 
-  /// Return true if all elements of this shuffle are the same value as the
-  /// first element of exactly one source vector without changing the length
-  /// of that vector.
-  /// Example: shufflevector <4 x n> A, <4 x n> B, <undef,0,undef,0>
-  /// TODO: Optionally allow length-changing shuffles.
-  /// TODO: Optionally allow splats from other elements.
-  bool isZeroEltSplat() const {
-    return !changesLength() &&
-           isZeroEltSplatMask(ShuffleMask, ShuffleMask.size());
-  }
+  bool isZeroEltSplat() const { return MaskAttrs.ZeroEltSplat; }
 
   /// Return true if this shuffle mask is a transpose mask.
   /// Transpose vector masks transpose a 2xn matrix. They read corresponding
@@ -2176,14 +2203,7 @@ class ShuffleVectorInst : public Instruction {
     return isTransposeMask(MaskAsInts, NumSrcElts);
   }
 
-  /// Return true if this shuffle transposes the elements of its inputs without
-  /// changing the length of the vectors. This operation may also be known as a
-  /// merge or interleave. See the description for isTransposeMask() for the
-  /// exact specification.
-  /// Example: shufflevector <4 x n> A, <4 x n> B, <0,4,2,6>
-  bool isTranspose() const {
-    return !changesLength() && isTransposeMask(ShuffleMask, ShuffleMask.size());
-  }
+  bool isTranspose() const { return MaskAttrs.Transpose; }
 
   /// Return true if this shuffle mask is a splice mask, concatenating the two
   /// inputs together and then extracts an original width vector starting from
@@ -2199,13 +2219,9 @@ class ShuffleVectorInst : public Instruction {
     return isSpliceMask(MaskAsInts, NumSrcElts, Index);
   }
 
-  /// Return true if this shuffle splices two inputs without changing the length
-  /// of the vectors. This operation concatenates the two inputs together and
-  /// then extracts an original width vector starting from the splice index.
-  /// Example: shufflevector <4 x n> A, <4 x n> B, <1,2,3,4>
   bool isSplice(int &Index) const {
-    return !changesLength() &&
-           isSpliceMask(ShuffleMask, ShuffleMask.size(), Index);
+    Index = MaskAttrs.SpliceIndex;
+    return MaskAttrs.Splice;
   }
 
   /// Return true if this shuffle mask is an extract subvector mask.
diff --git a/llvm/lib/IR/Instructions.cpp b/llvm/lib/IR/Instructions.cpp
index b585d8cfbf2e2b..ceace65e534ba5 100644
--- a/llvm/lib/IR/Instructions.cpp
+++ b/llvm/lib/IR/Instructions.cpp
@@ -1822,6 +1822,14 @@ void ShuffleVectorInst::getShuffleMask(const Constant *Mask,
 void ShuffleVectorInst::setShuffleMask(ArrayRef<int> Mask) {
   ShuffleMask.assign(Mask.begin(), Mask.end());
   ShuffleMaskForBitcode = convertShuffleMaskForBitcode(Mask, getType());
+
+  bool HasUndef = isa<UndefValue>(Op<0>()) || isa<UndefValue>(Op<1>());
+  if (auto *FixedVecTy = dyn_cast<FixedVectorType>(Op<0>()->getType())) {
+    int NumOpElts = FixedVecTy->getNumElements();
+    MaskAttrs = analyzeMask(Mask, NumOpElts, false, HasUndef);
+  } else {
+    MaskAttrs = analyzeMask(Mask, Mask.size(), true, HasUndef);
+  }
 }
 
 Constant *ShuffleVectorInst::convertShuffleMaskForBitcode(ArrayRef<int> Mask,
@@ -1844,6 +1852,106 @@ Constant *ShuffleVectorInst::convertShuffleMaskForBitcode(ArrayRef<int> Mask,
   return ConstantVector::get(MaskConst);
 }
 
+ShuffleMaskAttrs ShuffleVectorInst::analyzeMask(ArrayRef<int> Mask,
+                                                int NumOpElts, bool Scalable,
+                                                bool HasUndefOp) {
+  assert(!Mask.empty() && "Shuffle mask must contain elements");
+
+  using SizeTy = decltype(Mask.size());
+  bool UsesLHS = false;
+  bool UsesRHS = false;
+  bool ExtendsWithPadding = Mask.size() > static_cast<SizeTy>(NumOpElts);
+  const bool Extracts = Mask.size() < static_cast<SizeTy>(NumOpElts);
+  const bool PreservesLength = Mask.size() == static_cast<SizeTy>(NumOpElts);
+  bool CrossesLanes = false;
+  bool ReversesLanes = NumOpElts >= 2;
+  bool FirstLaneOnly = true;
+  bool HasTransposeInterleaving = true;
+  std::optional<int> SpliceIndex;
+  bool Splices = true;
+
+  for (int Idx = 0, NumMaskElts = Mask.size(); Idx < NumMaskElts; ++Idx) {
+    const auto I = Mask[Idx];
+    if (I == -1) {
+      HasTransposeInterleaving = false;
+      continue;
+    }
+    assert(I >= 0 && I < (NumOpElts * 2) &&
+           "Out-of-bounds shuffle mask element");
+    UsesLHS |= (I < NumOpElts);
+    UsesRHS |= (I >= NumOpElts);
+    CrossesLanes |= I != Idx && I != (NumOpElts + Idx);
+    ReversesLanes &=
+        I == (NumOpElts - 1 - Idx) || I == (NumOpElts + NumOpElts - 1 - Idx);
+    FirstLaneOnly &= I == 0 || I == NumOpElts;
+
+    if (Idx >= 2)
+      HasTransposeInterleaving &= Mask[Idx] - Mask[Idx - 2] == 2;
+    else if (Idx == 1)
+      HasTransposeInterleaving &= Mask[Idx] - Mask[0] == NumOpElts;
+    else // Idx == 0
+      HasTransposeInterleaving &= I == 0 || I == 1;
+
+    if (!SpliceIndex) {
+      Splices &= I >= Idx && I - Idx < NumOpElts;
+      if (Splices)
+        SpliceIndex = I - Idx;
+    } else {
+      Splices &= I == *SpliceIndex + Idx;
+    }
+
+    // Padding occurs when the mask size is >= operand size (see above) and all
+    // remaining elements must be undef.
+    ExtendsWithPadding &= Idx < NumOpElts;
+  }
+
+  ShuffleMaskAttrs MaskAttrs = {};
+
+  // Single-source if uses either LHS or RHS but not both.
+  MaskAttrs.SingleSource = (UsesLHS ^ UsesRHS) && PreservesLength;
+
+  // Identity if chooses elements without lane-crossings from either LHS or RHS.
+  MaskAttrs.Identity = !Scalable && MaskAttrs.SingleSource && !CrossesLanes;
+
+  // Identity with padding if mask size > operand size and all extra mask
+  // elements are undef/-1.
+  MaskAttrs.IdentityWithPadding =
+      !Scalable && (UsesLHS ^ UsesRHS) && !CrossesLanes && ExtendsWithPadding;
+
+  // Identity with extract if mask size < operand size.
+  MaskAttrs.IdentityWithExtract =
+      !Scalable && (UsesLHS ^ UsesRHS) && !CrossesLanes && Extracts;
+
+  // Concat if chooses elements without lane-crossings from both LHS and RHS.
+  MaskAttrs.Concat = !Scalable && !HasUndefOp && UsesLHS && UsesRHS &&
+                     Mask.size() == 2 * static_cast<SizeTy>(NumOpElts) &&
+                     !CrossesLanes;
+
+  // Reverse if chooses lanes in reverse order from either LHS or RHS.
+  MaskAttrs.Reverse = MaskAttrs.SingleSource && ReversesLanes;
+
+  // Splat of 0th elt if only picks first lane (or undef) of either LHS or RHS.
+  MaskAttrs.ZeroEltSplat = MaskAttrs.SingleSource && FirstLaneOnly;
+
+  // Select if chooses elements without lane-crossings from both LHS and RHS.
+  MaskAttrs.Select = UsesLHS && UsesRHS && PreservesLength && !CrossesLanes;
+
+  // Transpose if (1) number of elements is >= 2 and a power of 2, (2) first
+  // element is 0 or 1, (3) difference between first 2 elements == mask length,
+  // and (4) difference between consecutive even/odd elements == 2.
+  MaskAttrs.Transpose = PreservesLength && Mask.size() >= 2 &&
+                        isPowerOf2_32(Mask.size()) && HasTransposeInterleaving;
+
+  // Splice if (1) the starting index is >= 0, and (2) we have a contiguous
+  // sub-range spanning the 1st and 2nd vectors (or just the 1st).
+  if (PreservesLength && Splices && SpliceIndex) {
+    MaskAttrs.Splice = true;
+    MaskAttrs.SpliceIndex = *SpliceIndex;
+  }
+
+  return MaskAttrs;
+}
+
 static bool isSingleSourceMaskImpl(ArrayRef<int> Mask, int NumOpElts) {
   assert(!Mask.empty() && "Shuffle mask must contain elements");
   bool UsesLHS = false;
@@ -1978,6 +2086,7 @@ bool ShuffleVectorInst::isSpliceMask(ArrayRef<int> Mask, int NumSrcElts,
   if (Mask.size() != static_cast<unsigned>(NumSrcElts))
     return false;
   // Example: shufflevector <4 x n> A, <4 x n> B, <1,2,3,4>
+  // Counter: shufflevector <4 x n> A, <4 x n> B, <.,0,1,2>
   int StartIndex = -1;
   for (int I = 0, E = Mask.size(); I != E; ++I) {
     int MaskEltVal = Mask[I];
@@ -2109,66 +2218,6 @@ bool ShuffleVectorInst::isInsertSubvectorMask(ArrayRef<int> Mask,
   return false;
 }
 
-bool ShuffleVectorInst::isIdentityWithPadding() const {
-  // FIXME: Not currently possible to express a shuffle mask for a scalable
-  // vector for this case.
-  if (isa<ScalableVectorType>(getType()))
-    return false;
-
-  int NumOpElts = cast<FixedVectorType>(Op<0>()->getType())->getNumElements();
-  int NumMaskElts = cast<FixedVectorType>(getType())->getNumElements();
-  if (NumMaskElts <= NumOpElts)
-    return false;
-
-  // The first part of the mask must choose elements from exactly 1 source op.
-  ArrayRef<int> Mask = getShuffleMask();
-  if (!isIdentityMaskImpl(Mask, NumOpElts))
-    return false;
-
-  // All extending must be with undef elements.
-  for (int i = NumOpElts; i < NumMaskElts; ++i)
-    if (Mask[i] != -1)
-      return false;
-
-  return true;
-}
-
-bool ShuffleVectorInst::isIdentityWithExtract() const {
-  // FIXME: Not currently possible to express a shuffle mask for a scalable
-  // vector for this case.
-  if (isa<ScalableVectorType>(getType()))
-    return false;
-
-  int NumOpElts = cast<FixedVectorType>(Op<0>()->getType())->getNumElements();
-  int NumMaskElts = cast<FixedVectorType>(getType())->getNumElements();
-  if (NumMaskElts >= NumOpElts)
-    return false;
-
-  return isIdentityMaskImpl(getShuffleMask(), NumOpElts);
-}
-
-bool ShuffleVectorInst::isConcat() const {
-  // Vector concatenation is differentiated from identity with padding.
-  if (isa<UndefValue>(Op<0>()) || isa<UndefValue>(Op<1>()))
-    return false;
-
-  // FIXME: Not currently possible to express a shuffle mask for a scalable
-  // vector for this case.
-  if (isa<ScalableVectorType>(getType()))
-    return false;
-
-  int NumOpElts = cast<FixedVectorType>(Op<0>()->getType())->getNumElements();
-  int NumMaskElts = cast<FixedVectorType>(getType())->getNumElements();
-  if (NumMaskElts != NumOpElts * 2)
-    return false;
-
-  // Use the mask length rather than the operands' vector lengths here. We
-  // already know that the shuffle returns a vector twice as long as the inputs,
-  // and neither of the inputs are undef vectors. If the mask picks consecutive
-  // elements from both inputs, then this is a concatenation of the inputs.
-  return isIdentityMaskImpl(getShuffleMask(), NumMaskElts);
-}
-
 static bool isReplicationMaskWithParams(ArrayRef<int> Mask,
                                         int ReplicationFactor, int VF) {
   assert(Mask.size() == (unsigned)ReplicationFactor * VF &&

>From 5bb4ffe23bf596bca069caef282f393a4e0fe859 Mon Sep 17 00:00:00 2001
From: Princeton Ferro <pferro at nvidia.com>
Date: Mon, 6 Jan 2025 17:19:58 -0800
Subject: [PATCH 2/4] Revert "[Instructions] cache computed shufflevector
 properties"

This reverts commit 24a39050595b7f32e7374f67d281d91bfd3cf303.
---
 llvm/include/llvm/IR/Instructions.h | 160 ++++++++++++--------------
 llvm/lib/IR/Instructions.cpp        | 169 ++++++++++------------------
 2 files changed, 132 insertions(+), 197 deletions(-)

diff --git a/llvm/include/llvm/IR/Instructions.h b/llvm/include/llvm/IR/Instructions.h
index f8702704b49ff2..9a41971b63373c 100644
--- a/llvm/include/llvm/IR/Instructions.h
+++ b/llvm/include/llvm/IR/Instructions.h
@@ -1888,76 +1888,6 @@ DEFINE_TRANSPARENT_OPERAND_ACCESSORS(InsertElementInst, Value)
 
 constexpr int PoisonMaskElem = -1;
 
-/// Attributes of a shufflevector mask.
-struct ShuffleMaskAttrs {
-  /// If the shuffle chooses elements from exactly one source vector without
-  /// changing the length of that vector.
-  /// Example: shufflevector <4 x n> A, <4 x n> B, <3,0,undef,3>
-  /// TODO: Optionally allow length-changing shuffles.
-  bool SingleSource : 1;
-
-  /// If the shuffle chooses elements from exactly one source vector without
-  /// lane crossings and does not change the number of elements from its input
-  /// vectors.
-  /// Example: shufflevector <4 x n> A, <4 x n> B, <4,undef,6,undef>
-  bool Identity : 1;
-
-  /// If the shuffle lengthens exactly one source vector with undefs in the
-  /// high elements.
-  bool IdentityWithPadding : 1;
-
-  /// If the shuffle extracts the first N elements of exactly one source
-  /// vector.
-  bool IdentityWithExtract : 1;
-
-  /// If the shuffle concatenates the two source vectors. This is false if
-  /// either input is undefined. In that case, the shuffle is better classified
-  /// as an identity with padding operation.
-  bool Concat : 1;
-
-  /// If the shuffle swaps the order of elements from exactly one source vector.
-  /// Example: shufflevector <4 x n> A, <4 x n> B, <3,undef,1,undef>
-  /// TODO: Optionally allow length-changing shuffles.
-  bool Reverse : 1;
-
-  /// If all elements of the shuffle are the same value as the first element of
-  /// exactly one source vector without changing the length of that vector.
-  /// Example: shufflevector <4 x n> A, <4 x n> B, <undef,0,undef,0>
-  /// TODO: Optionally allow length-changing shuffles.
-  /// TODO: Optionally allow splats from other elements.
-  bool ZeroEltSplat : 1;
-
-  /// Return true if this shuffle chooses elements from its source vectors
-  /// without lane crossings and all operands have the same number of elements.
-  /// In other words, this shuffle is equivalent to a vector select with a
-  /// constant condition operand.
-  /// Example: shufflevector <4 x n> A, <4 x n> B, <undef,1,6,3>
-  /// This returns false if the mask does not choose from both input vectors.
-  /// In that case, the shuffle is better classified as an identity shuffle.
-  /// TODO: Optionally allow length-changing shuffles.
-  bool Select : 1;
-
-  /// If the shuffle transposes the elements of its inputs without changing the
-  /// length of the vectors. This operation may also be known as a merge or
-  /// interleave. See the description for isTransposeMask() for the exact
-  /// specification.
-  /// Example: shufflevector <4 x n> A, <4 x n> B, <0,4,2,6>
-  bool Transpose : 1;
-
-  /// If the shuffle splices two inputs without changing the length of the
-  /// vectors. This operation concatenates the two inputs together and then
-  /// extracts an original width vector starting from the splice index.
-  /// Example: shufflevector <4 x n> A, <4 x n> B, <1,2,3,4>
-  bool Splice : 1;
-
-  /// The starting index of the splice.
-  /// Example: 1, from the previous example
-  int SpliceIndex;
-};
-
-static_assert(sizeof(ShuffleMaskAttrs) <= sizeof(uint64_t),
-              "ShuffleMaskAttrs is too large!");
-
 /// This instruction constructs a fixed permutation of two
 /// input vectors.
 ///
@@ -1973,7 +1903,6 @@ class ShuffleVectorInst : public Instruction {
 
   SmallVector<int, 4> ShuffleMask;
   Constant *ShuffleMaskForBitcode;
-  ShuffleMaskAttrs MaskAttrs;
 
 protected:
   // Note: Instruction needs to be a friend here to call cloneImpl.
@@ -2000,12 +1929,6 @@ class ShuffleVectorInst : public Instruction {
   /// of the instruction.
   void commute();
 
-  // Analyze mask of fixed vector. NumOpElts is number of known elements in
-  // operand1/operand2. Scalable is set if any operands are scalable vectors.
-  // HasUndefOp is set if there are any undef operands.
-  static ShuffleMaskAttrs analyzeMask(ArrayRef<int> Mask, int NumOpElts,
-                                      bool Scalable, bool HasUndefOp);
-
   /// Return true if a shufflevector instruction can be
   /// formed with the specified operands.
   static bool isValidOperands(const Value *V1, const Value *V2,
@@ -2086,7 +2009,14 @@ class ShuffleVectorInst : public Instruction {
     return isSingleSourceMask(MaskAsInts, NumSrcElts);
   }
 
-  bool isSingleSource() const { return MaskAttrs.SingleSource; }
+  /// Return true if this shuffle chooses elements from exactly one source
+  /// vector without changing the length of that vector.
+  /// Example: shufflevector <4 x n> A, <4 x n> B, <3,0,undef,3>
+  /// TODO: Optionally allow length-changing shuffles.
+  bool isSingleSource() const {
+    return !changesLength() &&
+           isSingleSourceMask(ShuffleMask, ShuffleMask.size());
+  }
 
   /// Return true if this shuffle mask chooses elements from exactly one source
   /// vector without lane crossings. A shuffle using this mask is not
@@ -2107,13 +2037,31 @@ class ShuffleVectorInst : public Instruction {
     return isIdentityMask(MaskAsInts, NumSrcElts);
   }
 
-  bool isIdentity() const { return MaskAttrs.Identity; }
+  /// Return true if this shuffle chooses elements from exactly one source
+  /// vector without lane crossings and does not change the number of elements
+  /// from its input vectors.
+  /// Example: shufflevector <4 x n> A, <4 x n> B, <4,undef,6,undef>
+  bool isIdentity() const {
+    // Not possible to express a shuffle mask for a scalable vector for this
+    // case.
+    if (isa<ScalableVectorType>(getType()))
+      return false;
+
+    return !changesLength() && isIdentityMask(ShuffleMask, ShuffleMask.size());
+  }
 
-  bool isIdentityWithPadding() const { return MaskAttrs.IdentityWithPadding; }
+  /// Return true if this shuffle lengthens exactly one source vector with
+  /// undefs in the high elements.
+  bool isIdentityWithPadding() const;
 
-  bool isIdentityWithExtract() const { return MaskAttrs.IdentityWithExtract; }
+  /// Return true if this shuffle extracts the first N elements of exactly one
+  /// source vector.
+  bool isIdentityWithExtract() const;
 
-  bool isConcat() const { return MaskAttrs.Concat; }
+  /// Return true if this shuffle concatenates its 2 source vectors. This
+  /// returns false if either input is undefined. In that case, the shuffle is
+  /// is better classified as an identity with padding operation.
+  bool isConcat() const;
 
   /// Return true if this shuffle mask chooses elements from its source vectors
   /// without lane crossings. A shuffle using this mask would be
@@ -2131,7 +2079,17 @@ class ShuffleVectorInst : public Instruction {
     return isSelectMask(MaskAsInts, NumSrcElts);
   }
 
-  bool isSelect() const { return MaskAttrs.Select; }
+  /// Return true if this shuffle chooses elements from its source vectors
+  /// without lane crossings and all operands have the same number of elements.
+  /// In other words, this shuffle is equivalent to a vector select with a
+  /// constant condition operand.
+  /// Example: shufflevector <4 x n> A, <4 x n> B, <undef,1,6,3>
+  /// This returns false if the mask does not choose from both input vectors.
+  /// In that case, the shuffle is better classified as an identity shuffle.
+  /// TODO: Optionally allow length-changing shuffles.
+  bool isSelect() const {
+    return !changesLength() && isSelectMask(ShuffleMask, ShuffleMask.size());
+  }
 
   /// Return true if this shuffle mask swaps the order of elements from exactly
   /// one source vector.
@@ -2146,7 +2104,13 @@ class ShuffleVectorInst : public Instruction {
     return isReverseMask(MaskAsInts, NumSrcElts);
   }
 
-  bool isReverse() const { return MaskAttrs.Reverse; }
+  /// Return true if this shuffle swaps the order of elements from exactly
+  /// one source vector.
+  /// Example: shufflevector <4 x n> A, <4 x n> B, <3,undef,1,undef>
+  /// TODO: Optionally allow length-changing shuffles.
+  bool isReverse() const {
+    return !changesLength() && isReverseMask(ShuffleMask, ShuffleMask.size());
+  }
 
   /// Return true if this shuffle mask chooses all elements with the same value
   /// as the first element of exactly one source vector.
@@ -2161,7 +2125,16 @@ class ShuffleVectorInst : public Instruction {
     return isZeroEltSplatMask(MaskAsInts, NumSrcElts);
   }
 
-  bool isZeroEltSplat() const { return MaskAttrs.ZeroEltSplat; }
+  /// Return true if all elements of this shuffle are the same value as the
+  /// first element of exactly one source vector without changing the length
+  /// of that vector.
+  /// Example: shufflevector <4 x n> A, <4 x n> B, <undef,0,undef,0>
+  /// TODO: Optionally allow length-changing shuffles.
+  /// TODO: Optionally allow splats from other elements.
+  bool isZeroEltSplat() const {
+    return !changesLength() &&
+           isZeroEltSplatMask(ShuffleMask, ShuffleMask.size());
+  }
 
   /// Return true if this shuffle mask is a transpose mask.
   /// Transpose vector masks transpose a 2xn matrix. They read corresponding
@@ -2203,7 +2176,14 @@ class ShuffleVectorInst : public Instruction {
     return isTransposeMask(MaskAsInts, NumSrcElts);
   }
 
-  bool isTranspose() const { return MaskAttrs.Transpose; }
+  /// Return true if this shuffle transposes the elements of its inputs without
+  /// changing the length of the vectors. This operation may also be known as a
+  /// merge or interleave. See the description for isTransposeMask() for the
+  /// exact specification.
+  /// Example: shufflevector <4 x n> A, <4 x n> B, <0,4,2,6>
+  bool isTranspose() const {
+    return !changesLength() && isTransposeMask(ShuffleMask, ShuffleMask.size());
+  }
 
   /// Return true if this shuffle mask is a splice mask, concatenating the two
   /// inputs together and then extracts an original width vector starting from
@@ -2219,9 +2199,13 @@ class ShuffleVectorInst : public Instruction {
     return isSpliceMask(MaskAsInts, NumSrcElts, Index);
   }
 
+  /// Return true if this shuffle splices two inputs without changing the length
+  /// of the vectors. This operation concatenates the two inputs together and
+  /// then extracts an original width vector starting from the splice index.
+  /// Example: shufflevector <4 x n> A, <4 x n> B, <1,2,3,4>
   bool isSplice(int &Index) const {
-    Index = MaskAttrs.SpliceIndex;
-    return MaskAttrs.Splice;
+    return !changesLength() &&
+           isSpliceMask(ShuffleMask, ShuffleMask.size(), Index);
   }
 
   /// Return true if this shuffle mask is an extract subvector mask.
diff --git a/llvm/lib/IR/Instructions.cpp b/llvm/lib/IR/Instructions.cpp
index ceace65e534ba5..b585d8cfbf2e2b 100644
--- a/llvm/lib/IR/Instructions.cpp
+++ b/llvm/lib/IR/Instructions.cpp
@@ -1822,14 +1822,6 @@ void ShuffleVectorInst::getShuffleMask(const Constant *Mask,
 void ShuffleVectorInst::setShuffleMask(ArrayRef<int> Mask) {
   ShuffleMask.assign(Mask.begin(), Mask.end());
   ShuffleMaskForBitcode = convertShuffleMaskForBitcode(Mask, getType());
-
-  bool HasUndef = isa<UndefValue>(Op<0>()) || isa<UndefValue>(Op<1>());
-  if (auto *FixedVecTy = dyn_cast<FixedVectorType>(Op<0>()->getType())) {
-    int NumOpElts = FixedVecTy->getNumElements();
-    MaskAttrs = analyzeMask(Mask, NumOpElts, false, HasUndef);
-  } else {
-    MaskAttrs = analyzeMask(Mask, Mask.size(), true, HasUndef);
-  }
 }
 
 Constant *ShuffleVectorInst::convertShuffleMaskForBitcode(ArrayRef<int> Mask,
@@ -1852,106 +1844,6 @@ Constant *ShuffleVectorInst::convertShuffleMaskForBitcode(ArrayRef<int> Mask,
   return ConstantVector::get(MaskConst);
 }
 
-ShuffleMaskAttrs ShuffleVectorInst::analyzeMask(ArrayRef<int> Mask,
-                                                int NumOpElts, bool Scalable,
-                                                bool HasUndefOp) {
-  assert(!Mask.empty() && "Shuffle mask must contain elements");
-
-  using SizeTy = decltype(Mask.size());
-  bool UsesLHS = false;
-  bool UsesRHS = false;
-  bool ExtendsWithPadding = Mask.size() > static_cast<SizeTy>(NumOpElts);
-  const bool Extracts = Mask.size() < static_cast<SizeTy>(NumOpElts);
-  const bool PreservesLength = Mask.size() == static_cast<SizeTy>(NumOpElts);
-  bool CrossesLanes = false;
-  bool ReversesLanes = NumOpElts >= 2;
-  bool FirstLaneOnly = true;
-  bool HasTransposeInterleaving = true;
-  std::optional<int> SpliceIndex;
-  bool Splices = true;
-
-  for (int Idx = 0, NumMaskElts = Mask.size(); Idx < NumMaskElts; ++Idx) {
-    const auto I = Mask[Idx];
-    if (I == -1) {
-      HasTransposeInterleaving = false;
-      continue;
-    }
-    assert(I >= 0 && I < (NumOpElts * 2) &&
-           "Out-of-bounds shuffle mask element");
-    UsesLHS |= (I < NumOpElts);
-    UsesRHS |= (I >= NumOpElts);
-    CrossesLanes |= I != Idx && I != (NumOpElts + Idx);
-    ReversesLanes &=
-        I == (NumOpElts - 1 - Idx) || I == (NumOpElts + NumOpElts - 1 - Idx);
-    FirstLaneOnly &= I == 0 || I == NumOpElts;
-
-    if (Idx >= 2)
-      HasTransposeInterleaving &= Mask[Idx] - Mask[Idx - 2] == 2;
-    else if (Idx == 1)
-      HasTransposeInterleaving &= Mask[Idx] - Mask[0] == NumOpElts;
-    else // Idx == 0
-      HasTransposeInterleaving &= I == 0 || I == 1;
-
-    if (!SpliceIndex) {
-      Splices &= I >= Idx && I - Idx < NumOpElts;
-      if (Splices)
-        SpliceIndex = I - Idx;
-    } else {
-      Splices &= I == *SpliceIndex + Idx;
-    }
-
-    // Padding occurs when the mask size is >= operand size (see above) and all
-    // remaining elements must be undef.
-    ExtendsWithPadding &= Idx < NumOpElts;
-  }
-
-  ShuffleMaskAttrs MaskAttrs = {};
-
-  // Single-source if uses either LHS or RHS but not both.
-  MaskAttrs.SingleSource = (UsesLHS ^ UsesRHS) && PreservesLength;
-
-  // Identity if chooses elements without lane-crossings from either LHS or RHS.
-  MaskAttrs.Identity = !Scalable && MaskAttrs.SingleSource && !CrossesLanes;
-
-  // Identity with padding if mask size > operand size and all extra mask
-  // elements are undef/-1.
-  MaskAttrs.IdentityWithPadding =
-      !Scalable && (UsesLHS ^ UsesRHS) && !CrossesLanes && ExtendsWithPadding;
-
-  // Identity with extract if mask size < operand size.
-  MaskAttrs.IdentityWithExtract =
-      !Scalable && (UsesLHS ^ UsesRHS) && !CrossesLanes && Extracts;
-
-  // Concat if chooses elements without lane-crossings from both LHS and RHS.
-  MaskAttrs.Concat = !Scalable && !HasUndefOp && UsesLHS && UsesRHS &&
-                     Mask.size() == 2 * static_cast<SizeTy>(NumOpElts) &&
-                     !CrossesLanes;
-
-  // Reverse if chooses lanes in reverse order from either LHS or RHS.
-  MaskAttrs.Reverse = MaskAttrs.SingleSource && ReversesLanes;
-
-  // Splat of 0th elt if only picks first lane (or undef) of either LHS or RHS.
-  MaskAttrs.ZeroEltSplat = MaskAttrs.SingleSource && FirstLaneOnly;
-
-  // Select if chooses elements without lane-crossings from both LHS and RHS.
-  MaskAttrs.Select = UsesLHS && UsesRHS && PreservesLength && !CrossesLanes;
-
-  // Transpose if (1) number of elements is >= 2 and a power of 2, (2) first
-  // element is 0 or 1, (3) difference between first 2 elements == mask length,
-  // and (4) difference between consecutive even/odd elements == 2.
-  MaskAttrs.Transpose = PreservesLength && Mask.size() >= 2 &&
-                        isPowerOf2_32(Mask.size()) && HasTransposeInterleaving;
-
-  // Splice if (1) the starting index is >= 0, and (2) we have a contiguous
-  // sub-range spanning the 1st and 2nd vectors (or just the 1st).
-  if (PreservesLength && Splices && SpliceIndex) {
-    MaskAttrs.Splice = true;
-    MaskAttrs.SpliceIndex = *SpliceIndex;
-  }
-
-  return MaskAttrs;
-}
-
 static bool isSingleSourceMaskImpl(ArrayRef<int> Mask, int NumOpElts) {
   assert(!Mask.empty() && "Shuffle mask must contain elements");
   bool UsesLHS = false;
@@ -2086,7 +1978,6 @@ bool ShuffleVectorInst::isSpliceMask(ArrayRef<int> Mask, int NumSrcElts,
   if (Mask.size() != static_cast<unsigned>(NumSrcElts))
     return false;
   // Example: shufflevector <4 x n> A, <4 x n> B, <1,2,3,4>
-  // Counter: shufflevector <4 x n> A, <4 x n> B, <.,0,1,2>
   int StartIndex = -1;
   for (int I = 0, E = Mask.size(); I != E; ++I) {
     int MaskEltVal = Mask[I];
@@ -2218,6 +2109,66 @@ bool ShuffleVectorInst::isInsertSubvectorMask(ArrayRef<int> Mask,
   return false;
 }
 
+bool ShuffleVectorInst::isIdentityWithPadding() const {
+  // FIXME: Not currently possible to express a shuffle mask for a scalable
+  // vector for this case.
+  if (isa<ScalableVectorType>(getType()))
+    return false;
+
+  int NumOpElts = cast<FixedVectorType>(Op<0>()->getType())->getNumElements();
+  int NumMaskElts = cast<FixedVectorType>(getType())->getNumElements();
+  if (NumMaskElts <= NumOpElts)
+    return false;
+
+  // The first part of the mask must choose elements from exactly 1 source op.
+  ArrayRef<int> Mask = getShuffleMask();
+  if (!isIdentityMaskImpl(Mask, NumOpElts))
+    return false;
+
+  // All extending must be with undef elements.
+  for (int i = NumOpElts; i < NumMaskElts; ++i)
+    if (Mask[i] != -1)
+      return false;
+
+  return true;
+}
+
+bool ShuffleVectorInst::isIdentityWithExtract() const {
+  // FIXME: Not currently possible to express a shuffle mask for a scalable
+  // vector for this case.
+  if (isa<ScalableVectorType>(getType()))
+    return false;
+
+  int NumOpElts = cast<FixedVectorType>(Op<0>()->getType())->getNumElements();
+  int NumMaskElts = cast<FixedVectorType>(getType())->getNumElements();
+  if (NumMaskElts >= NumOpElts)
+    return false;
+
+  return isIdentityMaskImpl(getShuffleMask(), NumOpElts);
+}
+
+bool ShuffleVectorInst::isConcat() const {
+  // Vector concatenation is differentiated from identity with padding.
+  if (isa<UndefValue>(Op<0>()) || isa<UndefValue>(Op<1>()))
+    return false;
+
+  // FIXME: Not currently possible to express a shuffle mask for a scalable
+  // vector for this case.
+  if (isa<ScalableVectorType>(getType()))
+    return false;
+
+  int NumOpElts = cast<FixedVectorType>(Op<0>()->getType())->getNumElements();
+  int NumMaskElts = cast<FixedVectorType>(getType())->getNumElements();
+  if (NumMaskElts != NumOpElts * 2)
+    return false;
+
+  // Use the mask length rather than the operands' vector lengths here. We
+  // already know that the shuffle returns a vector twice as long as the inputs,
+  // and neither of the inputs are undef vectors. If the mask picks consecutive
+  // elements from both inputs, then this is a concatenation of the inputs.
+  return isIdentityMaskImpl(getShuffleMask(), NumMaskElts);
+}
+
 static bool isReplicationMaskWithParams(ArrayRef<int> Mask,
                                         int ReplicationFactor, int VF) {
   assert(Mask.size() == (unsigned)ReplicationFactor * VF &&

>From 4f45fe455f404339a9f2f9ff5383e746ab4cc2f7 Mon Sep 17 00:00:00 2001
From: Princeton Ferro <pferro at nvidia.com>
Date: Tue, 21 Jan 2025 20:25:19 -0800
Subject: [PATCH 3/4] [Instructions] reimplement shufflevector property caching

Simplify implementation
---
 llvm/include/llvm/IR/Instructions.h | 67 ++++++++++++++++++++---------
 llvm/lib/IR/Instructions.cpp        |  1 +
 2 files changed, 48 insertions(+), 20 deletions(-)

diff --git a/llvm/include/llvm/IR/Instructions.h b/llvm/include/llvm/IR/Instructions.h
index 9a41971b63373c..5ba1223d1419cd 100644
--- a/llvm/include/llvm/IR/Instructions.h
+++ b/llvm/include/llvm/IR/Instructions.h
@@ -1886,6 +1886,23 @@ DEFINE_TRANSPARENT_OPERAND_ACCESSORS(InsertElementInst, Value)
 //                           ShuffleVectorInst Class
 //===----------------------------------------------------------------------===//
 
+struct ShuffleMaskAttrs {
+  bool SingleSource : 1;
+  bool Identity : 1;
+  // bool IdentityWithPadding : 1;
+  // bool IdentityWithExtract : 1;
+  // bool Concat : 1;
+  bool Reverse : 1;
+  bool ZeroEltSplat : 1;
+  bool Select : 1;
+  bool Transpose : 1;
+  bool Splice : 1;
+  int SpliceIndex;
+};
+
+static_assert(sizeof(ShuffleMaskAttrs) <= sizeof(uint64_t),
+              "ShuffleMaskAttrs is too large!");
+
 constexpr int PoisonMaskElem = -1;
 
 /// This instruction constructs a fixed permutation of two
@@ -1903,6 +1920,27 @@ class ShuffleVectorInst : public Instruction {
 
   SmallVector<int, 4> ShuffleMask;
   Constant *ShuffleMaskForBitcode;
+  mutable ShuffleMaskAttrs ShuffleAttrs;
+
+  // This function is const so that it's callable from other const functions.
+  void computeShuffleAttrs() const {
+    ShuffleAttrs = {};  // reset
+    ShuffleAttrs.SingleSource =
+        !changesLength() && isSingleSourceMask(ShuffleMask, ShuffleMask.size());
+    ShuffleAttrs.Identity =
+        !changesLength() && isIdentityMask(ShuffleMask, ShuffleMask.size());
+    ShuffleAttrs.Select =
+        !changesLength() && isSelectMask(ShuffleMask, ShuffleMask.size());
+    ShuffleAttrs.Reverse =
+        !changesLength() && isReverseMask(ShuffleMask, ShuffleMask.size());
+    ShuffleAttrs.ZeroEltSplat =
+        !changesLength() && isZeroEltSplatMask(ShuffleMask, ShuffleMask.size());
+    ShuffleAttrs.Transpose =
+        !changesLength() && isTransposeMask(ShuffleMask, ShuffleMask.size());
+    ShuffleAttrs.Splice =
+        !changesLength() &&
+        isSpliceMask(ShuffleMask, ShuffleMask.size(), ShuffleAttrs.SpliceIndex);
+  }
 
 protected:
   // Note: Instruction needs to be a friend here to call cloneImpl.
@@ -2013,10 +2051,7 @@ class ShuffleVectorInst : public Instruction {
   /// vector without changing the length of that vector.
   /// Example: shufflevector <4 x n> A, <4 x n> B, <3,0,undef,3>
   /// TODO: Optionally allow length-changing shuffles.
-  bool isSingleSource() const {
-    return !changesLength() &&
-           isSingleSourceMask(ShuffleMask, ShuffleMask.size());
-  }
+  bool isSingleSource() const { return ShuffleAttrs.SingleSource; }
 
   /// Return true if this shuffle mask chooses elements from exactly one source
   /// vector without lane crossings. A shuffle using this mask is not
@@ -2047,7 +2082,7 @@ class ShuffleVectorInst : public Instruction {
     if (isa<ScalableVectorType>(getType()))
       return false;
 
-    return !changesLength() && isIdentityMask(ShuffleMask, ShuffleMask.size());
+    return ShuffleAttrs.Identity;
   }
 
   /// Return true if this shuffle lengthens exactly one source vector with
@@ -2087,9 +2122,7 @@ class ShuffleVectorInst : public Instruction {
   /// This returns false if the mask does not choose from both input vectors.
   /// In that case, the shuffle is better classified as an identity shuffle.
   /// TODO: Optionally allow length-changing shuffles.
-  bool isSelect() const {
-    return !changesLength() && isSelectMask(ShuffleMask, ShuffleMask.size());
-  }
+  bool isSelect() const { return ShuffleAttrs.Select; }
 
   /// Return true if this shuffle mask swaps the order of elements from exactly
   /// one source vector.
@@ -2108,9 +2141,7 @@ class ShuffleVectorInst : public Instruction {
   /// one source vector.
   /// Example: shufflevector <4 x n> A, <4 x n> B, <3,undef,1,undef>
   /// TODO: Optionally allow length-changing shuffles.
-  bool isReverse() const {
-    return !changesLength() && isReverseMask(ShuffleMask, ShuffleMask.size());
-  }
+  bool isReverse() const { return ShuffleAttrs.Reverse; }
 
   /// Return true if this shuffle mask chooses all elements with the same value
   /// as the first element of exactly one source vector.
@@ -2131,10 +2162,7 @@ class ShuffleVectorInst : public Instruction {
   /// Example: shufflevector <4 x n> A, <4 x n> B, <undef,0,undef,0>
   /// TODO: Optionally allow length-changing shuffles.
   /// TODO: Optionally allow splats from other elements.
-  bool isZeroEltSplat() const {
-    return !changesLength() &&
-           isZeroEltSplatMask(ShuffleMask, ShuffleMask.size());
-  }
+  bool isZeroEltSplat() const { return ShuffleAttrs.ZeroEltSplat; }
 
   /// Return true if this shuffle mask is a transpose mask.
   /// Transpose vector masks transpose a 2xn matrix. They read corresponding
@@ -2181,9 +2209,7 @@ class ShuffleVectorInst : public Instruction {
   /// merge or interleave. See the description for isTransposeMask() for the
   /// exact specification.
   /// Example: shufflevector <4 x n> A, <4 x n> B, <0,4,2,6>
-  bool isTranspose() const {
-    return !changesLength() && isTransposeMask(ShuffleMask, ShuffleMask.size());
-  }
+  bool isTranspose() const { return ShuffleAttrs.Transpose; }
 
   /// Return true if this shuffle mask is a splice mask, concatenating the two
   /// inputs together and then extracts an original width vector starting from
@@ -2204,8 +2230,9 @@ class ShuffleVectorInst : public Instruction {
   /// then extracts an original width vector starting from the splice index.
   /// Example: shufflevector <4 x n> A, <4 x n> B, <1,2,3,4>
   bool isSplice(int &Index) const {
-    return !changesLength() &&
-           isSpliceMask(ShuffleMask, ShuffleMask.size(), Index);
+    if (ShuffleAttrs.Splice)
+      Index = ShuffleAttrs.SpliceIndex;
+    return ShuffleAttrs.Splice;
   }
 
   /// Return true if this shuffle mask is an extract subvector mask.
diff --git a/llvm/lib/IR/Instructions.cpp b/llvm/lib/IR/Instructions.cpp
index b585d8cfbf2e2b..794307b81ea7d4 100644
--- a/llvm/lib/IR/Instructions.cpp
+++ b/llvm/lib/IR/Instructions.cpp
@@ -1822,6 +1822,7 @@ void ShuffleVectorInst::getShuffleMask(const Constant *Mask,
 void ShuffleVectorInst::setShuffleMask(ArrayRef<int> Mask) {
   ShuffleMask.assign(Mask.begin(), Mask.end());
   ShuffleMaskForBitcode = convertShuffleMaskForBitcode(Mask, getType());
+  computeShuffleAttrs();
 }
 
 Constant *ShuffleVectorInst::convertShuffleMaskForBitcode(ArrayRef<int> Mask,

>From 04b15aa81135f25d3608a23f48c2477ce58eec12 Mon Sep 17 00:00:00 2001
From: Princeton Ferro <pferro at nvidia.com>
Date: Tue, 21 Jan 2025 20:25:52 -0800
Subject: [PATCH 4/4] remove unused fields in ShuffleMaskAttrs

---
 llvm/include/llvm/IR/Instructions.h | 5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)

diff --git a/llvm/include/llvm/IR/Instructions.h b/llvm/include/llvm/IR/Instructions.h
index 5ba1223d1419cd..82fa87ed3655d4 100644
--- a/llvm/include/llvm/IR/Instructions.h
+++ b/llvm/include/llvm/IR/Instructions.h
@@ -1889,9 +1889,6 @@ DEFINE_TRANSPARENT_OPERAND_ACCESSORS(InsertElementInst, Value)
 struct ShuffleMaskAttrs {
   bool SingleSource : 1;
   bool Identity : 1;
-  // bool IdentityWithPadding : 1;
-  // bool IdentityWithExtract : 1;
-  // bool Concat : 1;
   bool Reverse : 1;
   bool ZeroEltSplat : 1;
   bool Select : 1;
@@ -1924,7 +1921,7 @@ class ShuffleVectorInst : public Instruction {
 
   // This function is const so that it's callable from other const functions.
   void computeShuffleAttrs() const {
-    ShuffleAttrs = {};  // reset
+    ShuffleAttrs = {}; // reset
     ShuffleAttrs.SingleSource =
         !changesLength() && isSingleSourceMask(ShuffleMask, ShuffleMask.size());
     ShuffleAttrs.Identity =



More information about the llvm-commits mailing list