[llvm] [SandboxIR] Add ShuffleVectorInst (PR #104891)

Jorge Gorbe Moya via llvm-commits llvm-commits at lists.llvm.org
Tue Aug 20 16:37:30 PDT 2024


https://github.com/slackito updated https://github.com/llvm/llvm-project/pull/104891

>From c7738a323cdf0648e11a61a2fa6f8d83800d8470 Mon Sep 17 00:00:00 2001
From: Jorge Gorbe Moya <jgorbe at google.com>
Date: Mon, 12 Aug 2024 15:35:17 -0700
Subject: [PATCH 1/3] Add ShuffleVectorInst.

---
 llvm/include/llvm/SandboxIR/SandboxIR.h       | 284 ++++++++++++++
 .../llvm/SandboxIR/SandboxIRValues.def        |  77 ++--
 llvm/lib/SandboxIR/SandboxIR.cpp              |  74 ++++
 llvm/unittests/SandboxIR/SandboxIRTest.cpp    | 355 ++++++++++++++++++
 4 files changed, 752 insertions(+), 38 deletions(-)

diff --git a/llvm/include/llvm/SandboxIR/SandboxIR.h b/llvm/include/llvm/SandboxIR/SandboxIR.h
index ca71566091bf82..2ec5e43b25c109 100644
--- a/llvm/include/llvm/SandboxIR/SandboxIR.h
+++ b/llvm/include/llvm/SandboxIR/SandboxIR.h
@@ -114,6 +114,7 @@ class Instruction;
 class SelectInst;
 class ExtractElementInst;
 class InsertElementInst;
+class ShuffleVectorInst;
 class BranchInst;
 class UnaryInstruction;
 class LoadInst;
@@ -246,6 +247,7 @@ class Value {
   friend class SelectInst;         // For getting `Val`.
   friend class ExtractElementInst; // For getting `Val`.
   friend class InsertElementInst;  // For getting `Val`.
+  friend class ShuffleVectorInst;  // For getting `Val`.
   friend class BranchInst;         // For getting `Val`.
   friend class LoadInst;           // For getting `Val`.
   friend class StoreInst;          // For getting `Val`.
@@ -669,6 +671,7 @@ class Instruction : public sandboxir::User {
   friend class SelectInst;         // For getTopmostLLVMInstruction().
   friend class ExtractElementInst; // For getTopmostLLVMInstruction().
   friend class InsertElementInst;  // For getTopmostLLVMInstruction().
+  friend class ShuffleVectorInst;  // For getTopmostLLVMInstruction().
   friend class BranchInst;         // For getTopmostLLVMInstruction().
   friend class LoadInst;           // For getTopmostLLVMInstruction().
   friend class StoreInst;          // For getTopmostLLVMInstruction().
@@ -949,6 +952,285 @@ class ExtractElementInst final
   }
 };
 
+class ShuffleVectorInst final
+  : public SingleLLVMInstructionImpl<llvm::ShuffleVectorInst> {
+  /// Use Context::createShuffleVectorInst() instead.
+  ShuffleVectorInst(llvm::Instruction *I, Context &Ctx)
+      : SingleLLVMInstructionImpl(ClassID::ShuffleVector, Opcode::ShuffleVector,
+                                  I, Ctx) {}
+  friend class Context; // For accessing the constructor in create*()
+
+public:
+  static Value *create(Value *V1, Value *V2, Value *Mask,
+                       Instruction *InsertBefore, Context &Ctx,
+                       const Twine &Name = "");
+  static Value *create(Value *V1, Value *V2, Value *Mask,
+                       BasicBlock *InsertAtEnd, Context &Ctx,
+                       const Twine &Name = "");
+  static Value *create(Value *V1, Value *V2, ArrayRef<int> Mask,
+                       Instruction *InsertBefore, Context &Ctx,
+                       const Twine &Name = "");
+  static Value *create(Value *V1, Value *V2, ArrayRef<int> Mask,
+                       BasicBlock *InsertAtEnd, Context &Ctx,
+                       const Twine &Name = "");
+  static bool classof(const Value *From) {
+    return From->getSubclassID() == ClassID::ShuffleVector;
+  }
+
+  static bool isValidOperands(const Value *V1, const Value *V2,
+                              const Value *Mask) {
+    return llvm::ShuffleVectorInst::isValidOperands(V1->Val, V2->Val,
+                                                    Mask->Val);
+  }
+
+  static bool isValidOperands(const Value *V1, const Value *V2,
+                              ArrayRef<int> Mask) {
+    return llvm::ShuffleVectorInst::isValidOperands(V1->Val, V2->Val,
+                                                    Mask);
+  }
+
+  void commute() {
+    cast<llvm::ShuffleVectorInst>(Val)->commute();
+  }
+
+  VectorType *getType() const {
+    return cast<llvm::ShuffleVectorInst>(Val)->getType();
+  }
+
+  int getMaskValue(unsigned Elt) const {
+    return cast<llvm::ShuffleVectorInst>(Val)->getMaskValue(Elt);
+  }
+
+  static void getShuffleMask(const Constant *Mask,
+                             SmallVectorImpl<int> &Result) {
+    llvm::ShuffleVectorInst::getShuffleMask(cast<llvm::Constant>(Mask->Val),
+                                            Result);
+  }
+
+  void getShuffleMask(SmallVectorImpl<int> &Result) const {
+    cast<llvm::ShuffleVectorInst>(Val)->getShuffleMask(Result);
+  }
+
+  Constant *getShuffleMaskForBitcode() const;
+
+  static Constant *convertShuffleMaskForBitcode(ArrayRef<int> Mask,
+                                                Type *ResultTy, Context &Ctx);
+
+  void setShuffleMask(ArrayRef<int> Mask) {
+    cast<llvm::ShuffleVectorInst>(Val)->setShuffleMask(Mask);
+  }
+
+  ArrayRef<int> getShuffleMask() const {
+    return cast<llvm::ShuffleVectorInst>(Val)->getShuffleMask();
+  }
+
+  bool changesLength() const {
+    return cast<llvm::ShuffleVectorInst>(Val)->changesLength();
+  }
+
+  bool increasesLength() const {
+    return cast<llvm::ShuffleVectorInst>(Val)->increasesLength();
+  }
+
+  static bool isSingleSourceMask(ArrayRef<int> Mask, int NumSrcElts) {
+    return llvm::ShuffleVectorInst::isSingleSourceMask(Mask, NumSrcElts);
+  }
+
+  static bool isSingleSourceMask(const Constant *Mask, int NumSrcElts) {
+    return llvm::ShuffleVectorInst::isSingleSourceMask(
+        cast<llvm::Constant>(Mask->Val), NumSrcElts);
+  }
+
+  bool isSingleSource() const {
+    return cast<llvm::ShuffleVectorInst>(Val)->isSingleSource();
+  }
+
+  static bool isIdentityMask(ArrayRef<int> Mask, int NumSrcElts) {
+    return llvm::ShuffleVectorInst::isIdentityMask(Mask, NumSrcElts);
+  }
+
+  static bool isIdentityMask(const Constant *Mask, int NumSrcElts) {
+    return llvm::ShuffleVectorInst::isIdentityMask(
+        cast<llvm::Constant>(Mask->Val), NumSrcElts);
+  }
+
+  bool isIdentity() const {
+    return cast<llvm::ShuffleVectorInst>(Val)->isIdentity();
+  }
+
+  bool isIdentityWithPadding() const {
+    return cast<llvm::ShuffleVectorInst>(Val)->isIdentityWithPadding();
+  }
+
+  bool isIdentityWithExtract() const {
+    return cast<llvm::ShuffleVectorInst>(Val)->isIdentityWithExtract();
+  }
+
+  bool isConcat() const {
+    return cast<llvm::ShuffleVectorInst>(Val)->isConcat();
+  }
+
+  static bool isSelectMask(ArrayRef<int> Mask, int NumSrcElts) {
+    return llvm::ShuffleVectorInst::isSelectMask(Mask, NumSrcElts);
+  }
+
+  static bool isSelectMask(const Constant *Mask, int NumSrcElts) {
+    return llvm::ShuffleVectorInst::isSelectMask(
+        cast<llvm::Constant>(Mask->Val), NumSrcElts);
+  }
+
+  bool isSelect() const {
+    return cast<llvm::ShuffleVectorInst>(Val)->isSelect();
+  }
+
+  static bool isReverseMask(ArrayRef<int> Mask, int NumSrcElts) {
+    return llvm::ShuffleVectorInst::isReverseMask(Mask, NumSrcElts);
+  }
+
+  static bool isReverseMask(const Constant *Mask, int NumSrcElts) {
+    return llvm::ShuffleVectorInst::isReverseMask(
+        cast<llvm::Constant>(Mask->Val), NumSrcElts);
+  }
+
+  bool isReverse() const {
+    return cast<llvm::ShuffleVectorInst>(Val)->isReverse();
+  }
+
+  static bool isZeroEltSplatMask(ArrayRef<int> Mask, int NumSrcElts) {
+    return llvm::ShuffleVectorInst::isZeroEltSplatMask(Mask, NumSrcElts);
+  }
+
+  static bool isZeroEltSplatMask(const Constant *Mask, int NumSrcElts) {
+    return llvm::ShuffleVectorInst::isZeroEltSplatMask(
+        cast<llvm::Constant>(Mask->Val), NumSrcElts);
+  }
+
+  bool isZeroEltSplat() const {
+    return cast<llvm::ShuffleVectorInst>(Val)->isZeroEltSplat();
+  }
+
+  static bool isTransposeMask(ArrayRef<int> Mask, int NumSrcElts) {
+    return llvm::ShuffleVectorInst::isTransposeMask(Mask, NumSrcElts);
+  }
+
+  static bool isTransposeMask(const Constant *Mask, int NumSrcElts) {
+    return llvm::ShuffleVectorInst::isTransposeMask(
+        cast<llvm::Constant>(Mask->Val), NumSrcElts);
+  }
+
+  bool isTranspose() const {
+    return cast<llvm::ShuffleVectorInst>(Val)->isTranspose();
+  }
+
+  static bool isSpliceMask(ArrayRef<int> Mask, int NumSrcElts, int &Index) {
+    return llvm::ShuffleVectorInst::isSpliceMask(Mask, NumSrcElts, Index);
+  }
+
+  static bool isSpliceMask(const Constant *Mask, int NumSrcElts, int &Index) {
+    return llvm::ShuffleVectorInst::isSpliceMask(
+        cast<llvm::Constant>(Mask->Val), NumSrcElts, Index);
+  }
+
+  bool isSplice(int &Index) const {
+    return cast<llvm::ShuffleVectorInst>(Val)->isSplice(Index);
+  }
+
+  static bool isExtractSubvectorMask(ArrayRef<int> Mask, int NumSrcElts,
+                                     int &Index) {
+    return llvm::ShuffleVectorInst::isExtractSubvectorMask(Mask, NumSrcElts,
+                                                           Index);
+  }
+
+  static bool isExtractSubvectorMask(const Constant *Mask, int NumSrcElts,
+                                     int &Index) {
+    return llvm::ShuffleVectorInst::isExtractSubvectorMask(
+        cast<llvm::Constant>(Mask->Val), NumSrcElts, Index);
+  }
+
+  bool isExtractSubvectorMask(int &Index) const {
+    return cast<llvm::ShuffleVectorInst>(Val)->isExtractSubvectorMask(Index);
+  }
+
+  static bool isInsertSubvectorMask(ArrayRef<int> Mask, int NumSrcElts,
+                                    int &NumSubElts, int &Index) {
+    return llvm::ShuffleVectorInst::isInsertSubvectorMask(Mask, NumSrcElts,
+                                                          NumSubElts, Index);
+  }
+
+  static bool isInsertSubvectorMask(const Constant *Mask, int NumSrcElts,
+                                    int &NumSubElts, int &Index) {
+    return llvm::ShuffleVectorInst::isInsertSubvectorMask(
+        cast<llvm::Constant>(Mask->Val), NumSrcElts, NumSubElts, Index);
+  }
+
+  bool isInsertSubvectorMask(int &NumSubElts, int &Index) const {
+    return cast<llvm::ShuffleVectorInst>(Val)->isInsertSubvectorMask(NumSubElts,
+                                                                     Index);
+  }
+
+  static bool isReplicationMask(ArrayRef<int> Mask, int &ReplicationFactor,
+                                int &VF) {
+    return llvm::ShuffleVectorInst::isReplicationMask(Mask, ReplicationFactor,
+                                                      VF);
+  }
+  static bool isReplicationMask(const Constant *Mask, int &ReplicationFactor,
+                                int &VF) {
+    return llvm::ShuffleVectorInst::isReplicationMask(cast<llvm::Constant>(Mask->Val), ReplicationFactor, VF);
+  }
+
+  /// Return true if this shuffle mask is a replication mask.
+  bool isReplicationMask(int &ReplicationFactor, int &VF) const {
+    return cast<llvm::ShuffleVectorInst>(Val)->isReplicationMask(
+        ReplicationFactor, VF);
+  }
+
+  static bool isOneUseSingleSourceMask(ArrayRef<int> Mask, int VF) {
+    return llvm::ShuffleVectorInst::isOneUseSingleSourceMask(Mask, VF);
+  }
+
+  bool isOneUseSingleSourceMask(int VF) const {
+    return cast<llvm::ShuffleVectorInst>(Val)->isOneUseSingleSourceMask(VF);
+  }
+
+  static void commuteShuffleMask(MutableArrayRef<int> Mask,
+                                 unsigned InVecNumElts) {
+    llvm::ShuffleVectorInst::commuteShuffleMask(Mask, InVecNumElts);
+  }
+
+  static bool isInterleaveMask(ArrayRef<int> Mask, unsigned Factor,
+                               unsigned NumInputElts,
+                               SmallVectorImpl<unsigned> &StartIndexes) {
+    return llvm::ShuffleVectorInst::isInterleaveMask(Mask, Factor, NumInputElts,
+                                                     StartIndexes);
+  }
+
+  static bool isInterleaveMask(ArrayRef<int> Mask, unsigned Factor,
+                               unsigned NumInputElts) {
+    return llvm::ShuffleVectorInst::isInterleaveMask(Mask, Factor,
+                                                     NumInputElts);
+  }
+
+  bool isInterleave(unsigned Factor) const {
+    return cast<llvm::ShuffleVectorInst>(Val)->isInterleave(Factor);
+  }
+
+  static bool isDeInterleaveMaskOfFactor(ArrayRef<int> Mask, unsigned Factor,
+                                         unsigned &Index) {
+    return llvm::ShuffleVectorInst::isDeInterleaveMaskOfFactor(Mask, Factor,
+                                                               Index);
+  }
+  static bool isDeInterleaveMaskOfFactor(ArrayRef<int> Mask, unsigned Factor) {
+    return llvm::ShuffleVectorInst::isDeInterleaveMaskOfFactor(Mask, Factor);
+  }
+
+  static bool isBitRotateMask(ArrayRef<int> Mask, unsigned EltSizeInBits,
+                              unsigned MinSubElts, unsigned MaxSubElts,
+                              unsigned &NumSubElts, unsigned &RotateAmt) {
+    return llvm::ShuffleVectorInst::isBitRotateMask(
+        Mask, EltSizeInBits, MinSubElts, MaxSubElts, NumSubElts, RotateAmt);
+  }
+};
+
 class BranchInst : public SingleLLVMInstructionImpl<llvm::BranchInst> {
   /// Use Context::createBranchInst(). Don't call the constructor directly.
   BranchInst(llvm::BranchInst *BI, Context &Ctx)
@@ -2280,6 +2562,8 @@ class Context {
   friend InsertElementInst; // For createInsertElementInst()
   ExtractElementInst *createExtractElementInst(llvm::ExtractElementInst *EEI);
   friend ExtractElementInst; // For createExtractElementInst()
+  ShuffleVectorInst *createShuffleVectorInst(llvm::ShuffleVectorInst *SVI);
+  friend ShuffleVectorInst; // For createShuffleVectorInst()
   BranchInst *createBranchInst(llvm::BranchInst *I);
   friend BranchInst; // For createBranchInst()
   LoadInst *createLoadInst(llvm::LoadInst *LI);
diff --git a/llvm/include/llvm/SandboxIR/SandboxIRValues.def b/llvm/include/llvm/SandboxIR/SandboxIRValues.def
index 402b6f3324a222..56720f564a7cae 100644
--- a/llvm/include/llvm/SandboxIR/SandboxIRValues.def
+++ b/llvm/include/llvm/SandboxIR/SandboxIRValues.def
@@ -33,46 +33,47 @@ DEF_USER(ConstantInt, ConstantInt)
 #define OPCODES(...)
 #endif
 // clang-format off
-//       ClassID,        Opcode(s),         Class
-DEF_INSTR(Opaque,        OP(Opaque),        OpaqueInst)
+//        ClassID,        Opcode(s),          Class
+DEF_INSTR(Opaque,         OP(Opaque),         OpaqueInst)
 DEF_INSTR(ExtractElement, OP(ExtractElement), ExtractElementInst)
-DEF_INSTR(InsertElement, OP(InsertElement), InsertElementInst)
-DEF_INSTR(Select,        OP(Select),        SelectInst)
-DEF_INSTR(Br,            OP(Br),            BranchInst)
-DEF_INSTR(Load,          OP(Load),          LoadInst)
-DEF_INSTR(Store,         OP(Store),         StoreInst)
-DEF_INSTR(Ret,           OP(Ret),           ReturnInst)
-DEF_INSTR(Call,          OP(Call),          CallInst)
-DEF_INSTR(Invoke,        OP(Invoke),        InvokeInst)
-DEF_INSTR(CallBr,        OP(CallBr),        CallBrInst)
-DEF_INSTR(GetElementPtr, OP(GetElementPtr), GetElementPtrInst)
-DEF_INSTR(CatchSwitch,   OP(CatchSwitch),   CatchSwitchInst)
-DEF_INSTR(Switch,        OP(Switch),        SwitchInst)
-DEF_INSTR(UnOp,          OPCODES( \
-                         OP(FNeg) \
-                         ),                 UnaryOperator)
+DEF_INSTR(InsertElement,  OP(InsertElement),  InsertElementInst)
+DEF_INSTR(ShuffleVector,  OP(ShuffleVector),  ShuffleVectorInst)
+DEF_INSTR(Select,         OP(Select),         SelectInst)
+DEF_INSTR(Br,             OP(Br),             BranchInst)
+DEF_INSTR(Load,           OP(Load),           LoadInst)
+DEF_INSTR(Store,          OP(Store),          StoreInst)
+DEF_INSTR(Ret,            OP(Ret),            ReturnInst)
+DEF_INSTR(Call,           OP(Call),           CallInst)
+DEF_INSTR(Invoke,         OP(Invoke),         InvokeInst)
+DEF_INSTR(CallBr,         OP(CallBr),         CallBrInst)
+DEF_INSTR(GetElementPtr,  OP(GetElementPtr),  GetElementPtrInst)
+DEF_INSTR(CatchSwitch,    OP(CatchSwitch),    CatchSwitchInst)
+DEF_INSTR(Switch,         OP(Switch),         SwitchInst)
+DEF_INSTR(UnOp,           OPCODES( \
+                          OP(FNeg) \
+                          ),                  UnaryOperator)
 DEF_INSTR(BinaryOperator, OPCODES(\
-                         OP(Add)  \
-                         OP(FAdd) \
-                         OP(Sub)  \
-                         OP(FSub) \
-                         OP(Mul)  \
-                         OP(FMul) \
-                         OP(UDiv) \
-                         OP(SDiv) \
-                         OP(FDiv) \
-                         OP(URem) \
-                         OP(SRem) \
-                         OP(FRem) \
-                         OP(Shl)  \
-                         OP(LShr) \
-                         OP(AShr) \
-                         OP(And)  \
-                         OP(Or)   \
-                         OP(Xor)  \
-                         ),                 BinaryOperator)
-DEF_INSTR(AtomicRMW,     OP(AtomicRMW),     AtomicRMWInst)
-DEF_INSTR(AtomicCmpXchg, OP(AtomicCmpXchg), AtomicCmpXchgInst)
+                          OP(Add)  \
+                          OP(FAdd) \
+                          OP(Sub)  \
+                          OP(FSub) \
+                          OP(Mul)  \
+                          OP(FMul) \
+                          OP(UDiv) \
+                          OP(SDiv) \
+                          OP(FDiv) \
+                          OP(URem) \
+                          OP(SRem) \
+                          OP(FRem) \
+                          OP(Shl)  \
+                          OP(LShr) \
+                          OP(AShr) \
+                          OP(And)  \
+                          OP(Or)   \
+                          OP(Xor)  \
+                          ),                  BinaryOperator)
+DEF_INSTR(AtomicRMW,      OP(AtomicRMW),      AtomicRMWInst)
+DEF_INSTR(AtomicCmpXchg,  OP(AtomicCmpXchg),  AtomicCmpXchgInst)
 DEF_INSTR(Alloca,         OP(Alloca),         AllocaInst)
 DEF_INSTR(Cast,   OPCODES(\
                           OP(ZExt)          \
diff --git a/llvm/lib/SandboxIR/SandboxIR.cpp b/llvm/lib/SandboxIR/SandboxIR.cpp
index 5b170cee20c940..a62c879b91e8b9 100644
--- a/llvm/lib/SandboxIR/SandboxIR.cpp
+++ b/llvm/lib/SandboxIR/SandboxIR.cpp
@@ -1818,6 +1818,67 @@ Value *ExtractElementInst::create(Value *Vec, Value *Idx,
   return Ctx.getOrCreateConstant(cast<llvm::Constant>(NewV));
 }
 
+Value *ShuffleVectorInst::create(Value *V1, Value *V2, Value *Mask,
+                                 Instruction *InsertBefore, Context &Ctx,
+                                 const Twine &Name) {
+  auto &Builder = Ctx.getLLVMIRBuilder();
+  Builder.SetInsertPoint(InsertBefore->getTopmostLLVMInstruction());
+  llvm::Value *NewV =
+      Builder.CreateShuffleVector(V1->Val, V2->Val, Mask->Val, Name);
+  if (auto *NewShuffle = dyn_cast<llvm::ShuffleVectorInst>(NewV))
+    return Ctx.createShuffleVectorInst(NewShuffle);
+  assert(isa<llvm::Constant>(NewV) && "Expected constant");
+  return Ctx.getOrCreateConstant(cast<llvm::Constant>(NewV));
+}
+
+Value *ShuffleVectorInst::create(Value *V1, Value *V2, Value *Mask,
+                                 BasicBlock *InsertAtEnd, Context &Ctx,
+                                 const Twine &Name) {
+  auto &Builder = Ctx.getLLVMIRBuilder();
+  Builder.SetInsertPoint(cast<llvm::BasicBlock>(InsertAtEnd->Val));
+  llvm::Value *NewV =
+      Builder.CreateShuffleVector(V1->Val, V2->Val, Mask->Val, Name);
+  if (auto *NewShuffle = dyn_cast<llvm::ShuffleVectorInst>(NewV))
+    return Ctx.createShuffleVectorInst(NewShuffle);
+  assert(isa<llvm::Constant>(NewV) && "Expected constant");
+  return Ctx.getOrCreateConstant(cast<llvm::Constant>(NewV));
+}
+
+Value *ShuffleVectorInst::create(Value *V1, Value *V2, ArrayRef<int> Mask,
+                                 Instruction *InsertBefore, Context &Ctx,
+                                 const Twine &Name) {
+  auto &Builder = Ctx.getLLVMIRBuilder();
+  Builder.SetInsertPoint(InsertBefore->getTopmostLLVMInstruction());
+  llvm::Value *NewV = Builder.CreateShuffleVector(V1->Val, V2->Val, Mask, Name);
+  if (auto *NewShuffle = dyn_cast<llvm::ShuffleVectorInst>(NewV))
+    return Ctx.createShuffleVectorInst(NewShuffle);
+  assert(isa<llvm::Constant>(NewV) && "Expected constant");
+  return Ctx.getOrCreateConstant(cast<llvm::Constant>(NewV));
+}
+
+Value *ShuffleVectorInst::create(Value *V1, Value *V2, ArrayRef<int> Mask,
+                                 BasicBlock *InsertAtEnd, Context &Ctx,
+                                 const Twine &Name) {
+  auto &Builder = Ctx.getLLVMIRBuilder();
+  Builder.SetInsertPoint(cast<llvm::BasicBlock>(InsertAtEnd->Val));
+  llvm::Value *NewV = Builder.CreateShuffleVector(V1->Val, V2->Val, Mask, Name);
+  if (auto *NewShuffle = dyn_cast<llvm::ShuffleVectorInst>(NewV))
+    return Ctx.createShuffleVectorInst(NewShuffle);
+  assert(isa<llvm::Constant>(NewV) && "Expected constant");
+  return Ctx.getOrCreateConstant(cast<llvm::Constant>(NewV));
+}
+
+Constant *ShuffleVectorInst::getShuffleMaskForBitcode() const {
+  return Ctx.getOrCreateConstant(
+      cast<llvm::ShuffleVectorInst>(Val)->getShuffleMaskForBitcode());
+}
+
+Constant *ShuffleVectorInst::convertShuffleMaskForBitcode(
+    llvm::ArrayRef<int> Mask, llvm::Type *ResultTy, Context &Ctx) {
+  return Ctx.getOrCreateConstant(
+      llvm::ShuffleVectorInst::convertShuffleMaskForBitcode(Mask, ResultTy));
+}
+
 #ifndef NDEBUG
 void Constant::dumpOS(raw_ostream &OS) const {
   dumpCommonPrefix(OS);
@@ -1957,6 +2018,12 @@ Value *Context::getOrCreateValueInternal(llvm::Value *LLVMV, llvm::User *U) {
         new InsertElementInst(LLVMIns, *this));
     return It->second.get();
   }
+  case llvm::Instruction::ShuffleVector: {
+    auto *LLVMIns = cast<llvm::ShuffleVectorInst>(LLVMV);
+    It->second = std::unique_ptr<ShuffleVectorInst>(
+        new ShuffleVectorInst(LLVMIns, *this));
+    return It->second.get();
+  }
   case llvm::Instruction::Br: {
     auto *LLVMBr = cast<llvm::BranchInst>(LLVMV);
     It->second = std::unique_ptr<BranchInst>(new BranchInst(LLVMBr, *this));
@@ -2121,6 +2188,13 @@ Context::createInsertElementInst(llvm::InsertElementInst *IEI) {
   return cast<InsertElementInst>(registerValue(std::move(NewPtr)));
 }
 
+ShuffleVectorInst *
+Context::createShuffleVectorInst(llvm::ShuffleVectorInst *SVI) {
+  auto NewPtr =
+      std::unique_ptr<ShuffleVectorInst>(new ShuffleVectorInst(SVI, *this));
+  return cast<ShuffleVectorInst>(registerValue(std::move(NewPtr)));
+}
+
 BranchInst *Context::createBranchInst(llvm::BranchInst *BI) {
   auto NewPtr = std::unique_ptr<BranchInst>(new BranchInst(BI, *this));
   return cast<BranchInst>(registerValue(std::move(NewPtr)));
diff --git a/llvm/unittests/SandboxIR/SandboxIRTest.cpp b/llvm/unittests/SandboxIR/SandboxIRTest.cpp
index 712865fd07cd7b..0e7e0c97d7a84c 100644
--- a/llvm/unittests/SandboxIR/SandboxIRTest.cpp
+++ b/llvm/unittests/SandboxIR/SandboxIRTest.cpp
@@ -15,6 +15,7 @@
 #include "llvm/IR/Instruction.h"
 #include "llvm/IR/Module.h"
 #include "llvm/Support/SourceMgr.h"
+#include "gmock/gmock-matchers.h"
 #include "gtest/gtest.h"
 
 using namespace llvm;
@@ -739,6 +740,360 @@ define void @foo(i8 %v0, i8 %v1, <2 x i8> %vec) {
       llvm::InsertElementInst::isValidOperands(LLVMArg0, LLVMArgVec, LLVMZero));
 }
 
+TEST_F(SandboxIRTest, ShuffleVectorInst) {
+  parseIR(C, R"IR(
+define void @foo(<2 x i8> %v1, <2 x i8> %v2) {
+  %ins0 = shufflevector <2 x i8> %v1, <2 x i8> %v2, <2 x i32> <i32 0, i32 2>
+  ret void
+}
+)IR");
+  Function &LLVMF = *M->getFunction("foo");
+  sandboxir::Context Ctx(C);
+  auto &F = *Ctx.createFunction(&LLVMF);
+  auto *ArgV1 = F.getArg(0);
+  auto *ArgV2 = F.getArg(1);
+  auto *BB = &*F.begin();
+  auto It = BB->begin();
+  auto *SI = cast<sandboxir::ShuffleVectorInst>(&*It++);
+  auto *Ret = &*It++;
+
+  EXPECT_EQ(SI->getOpcode(), sandboxir::Instruction::Opcode::ShuffleVector);
+  EXPECT_EQ(SI->getType(), ArgV1->getType());
+  EXPECT_EQ(SI->getOperand(0), ArgV1);
+  EXPECT_EQ(SI->getOperand(1), ArgV2);
+  EXPECT_EQ(SI->getMaskValue(0), 0);
+  EXPECT_EQ(SI->getMaskValue(1), 2);
+  SI->commute();
+  EXPECT_EQ(SI->getOperand(0), ArgV2);
+  EXPECT_EQ(SI->getOperand(1), ArgV1);
+  EXPECT_THAT(SI->getShuffleMask(),
+              testing::ContainerEq(ArrayRef<int>({2, 0})));
+
+  auto *NewI1 =
+      cast<sandboxir::ShuffleVectorInst>(sandboxir::ShuffleVectorInst::create(
+          ArgV1, ArgV2, ArrayRef<int>({0, 2, 1, 3}), Ret, Ctx,
+          "NewShuffleBeforeRet"));
+  EXPECT_EQ(NewI1->getOperand(0), ArgV1);
+  EXPECT_EQ(NewI1->getOperand(1), ArgV2);
+  EXPECT_EQ(NewI1->getNextNode(), Ret);
+  EXPECT_TRUE(NewI1->changesLength());
+  EXPECT_TRUE(NewI1->increasesLength());
+
+  auto *NewI2 =
+      cast<sandboxir::ShuffleVectorInst>(sandboxir::ShuffleVectorInst::create(
+          ArgV1, ArgV2, ArrayRef<int>({0, 1}), BB, Ctx, "NewShuffleAtEndOfBB"));
+  EXPECT_EQ(NewI2->getPrevNode(), Ret);
+
+  auto *LLVMArgV1 = LLVMF.getArg(0);
+  auto *LLVMArgV2 = LLVMF.getArg(1);
+  ArrayRef<int> Mask({1, 2});
+  EXPECT_EQ(
+      sandboxir::ShuffleVectorInst::isValidOperands(ArgV1, ArgV2, Mask),
+      llvm::ShuffleVectorInst::isValidOperands(LLVMArgV1, LLVMArgV2, Mask));
+  EXPECT_EQ(sandboxir::ShuffleVectorInst::isValidOperands(ArgV1, ArgV1, ArgV1),
+            llvm::ShuffleVectorInst::isValidOperands(LLVMArgV1, LLVMArgV1,
+                                                     LLVMArgV1));
+
+  // The following functions check different mask properties. Note that most
+  // of these come in three different flavors: a method that checks the mask
+  // in the current instructions and two static member functions that check
+  // a mask given as an ArrayRef<int> or Constant*, so there's quite a bit of
+  // repetition in order to check all of them.
+  //
+  // Because we need masks of different lengths we can't simply reuse one of the
+  // instructions we have created above, so we'll create a new instruction for
+  // each test using this helper.
+  auto shuffleWithMask = [&](auto &&...Indices) {
+    SmallVector<int, 4> Mask = {Indices...};
+    return cast<sandboxir::ShuffleVectorInst>(
+        sandboxir::ShuffleVectorInst::create(ArgV1, ArgV2, Mask, Ret, Ctx));
+  };
+
+  // changesLength / increasesLength
+  {
+    auto *I = shuffleWithMask(1);
+    EXPECT_TRUE(I->changesLength());
+    EXPECT_FALSE(I->increasesLength());
+  }
+  {
+    auto *I = shuffleWithMask(1, 1);
+    EXPECT_FALSE(I->changesLength());
+    EXPECT_FALSE(I->increasesLength());
+  }
+  {
+    auto *I = shuffleWithMask(1, 1, 1);
+    EXPECT_TRUE(I->changesLength());
+    EXPECT_TRUE(I->increasesLength());
+  }
+
+  // isSingleSourceMask
+  {
+    auto *I = shuffleWithMask(0, 1);
+    EXPECT_TRUE(I->isSingleSource());
+    EXPECT_TRUE(sandboxir::ShuffleVectorInst::isSingleSourceMask(
+        I->getShuffleMaskForBitcode(), 2));
+    EXPECT_TRUE(sandboxir::ShuffleVectorInst::isSingleSourceMask(
+        I->getShuffleMask(), 2));
+  }
+  {
+    auto *I = shuffleWithMask(0, 2);
+    EXPECT_FALSE(I->isSingleSource());
+    EXPECT_FALSE(sandboxir::ShuffleVectorInst::isSingleSourceMask(
+        I->getShuffleMaskForBitcode(), 2));
+    EXPECT_FALSE(sandboxir::ShuffleVectorInst::isSingleSourceMask(
+        I->getShuffleMask(), 2));
+  }
+
+  // isIdentityMask
+  {
+    auto *I = shuffleWithMask(0, 1);
+    EXPECT_TRUE(I->isIdentity());
+    EXPECT_TRUE(sandboxir::ShuffleVectorInst::isIdentityMask(
+        I->getShuffleMaskForBitcode(), 2));
+    EXPECT_TRUE(
+        sandboxir::ShuffleVectorInst::isIdentityMask(I->getShuffleMask(), 2));
+  }
+  {
+    auto *I = shuffleWithMask(1, 0);
+    EXPECT_FALSE(I->isIdentity());
+    EXPECT_FALSE(sandboxir::ShuffleVectorInst::isIdentityMask(
+        I->getShuffleMaskForBitcode(), 2));
+    EXPECT_FALSE(
+        sandboxir::ShuffleVectorInst::isIdentityMask(I->getShuffleMask(), 2));
+  }
+
+  // isIdentityWithPadding
+  EXPECT_TRUE(shuffleWithMask(0, 1, -1, -1)->isIdentityWithPadding());
+  EXPECT_FALSE(shuffleWithMask(0, 1)->isIdentityWithPadding());
+
+  // isIdentityWithExtract
+  EXPECT_TRUE(shuffleWithMask(0)->isIdentityWithExtract());
+  EXPECT_FALSE(shuffleWithMask(0, 1)->isIdentityWithExtract());
+  EXPECT_FALSE(shuffleWithMask(0, 1, 2)->isIdentityWithExtract());
+  EXPECT_FALSE(shuffleWithMask(1)->isIdentityWithExtract());
+
+  // isConcat
+  EXPECT_TRUE(shuffleWithMask(0, 1, 2, 3)->isConcat());
+  EXPECT_FALSE(shuffleWithMask(0, 3)->isConcat());
+
+  // isSelectMask
+  {
+    auto *I = shuffleWithMask(0, 3);
+    EXPECT_TRUE(I->isSelect());
+    EXPECT_TRUE(sandboxir::ShuffleVectorInst::isSelectMask(
+        I->getShuffleMaskForBitcode(), 2));
+    EXPECT_TRUE(
+        sandboxir::ShuffleVectorInst::isSelectMask(I->getShuffleMask(), 2));
+  }
+  {
+    auto *I = shuffleWithMask(0, 2);
+    EXPECT_FALSE(I->isSelect());
+    EXPECT_FALSE(sandboxir::ShuffleVectorInst::isSelectMask(
+        I->getShuffleMaskForBitcode(), 2));
+    EXPECT_FALSE(
+        sandboxir::ShuffleVectorInst::isSelectMask(I->getShuffleMask(), 2));
+  }
+
+  // isReverseMask
+  {
+    auto *I = shuffleWithMask(1, 0);
+    EXPECT_TRUE(I->isReverse());
+    EXPECT_TRUE(sandboxir::ShuffleVectorInst::isReverseMask(
+        I->getShuffleMaskForBitcode(), 2));
+    EXPECT_TRUE(
+        sandboxir::ShuffleVectorInst::isReverseMask(I->getShuffleMask(), 2));
+  }
+  {
+    auto *I = shuffleWithMask(1, 2);
+    EXPECT_FALSE(I->isReverse());
+    EXPECT_FALSE(sandboxir::ShuffleVectorInst::isReverseMask(
+        I->getShuffleMaskForBitcode(), 2));
+    EXPECT_FALSE(
+        sandboxir::ShuffleVectorInst::isReverseMask(I->getShuffleMask(), 2));
+  }
+
+  // isZeroEltSplatMask
+  {
+    auto *I = shuffleWithMask(0, 0);
+    EXPECT_TRUE(I->isZeroEltSplat());
+    EXPECT_TRUE(sandboxir::ShuffleVectorInst::isZeroEltSplatMask(
+        I->getShuffleMaskForBitcode(), 2));
+    EXPECT_TRUE(sandboxir::ShuffleVectorInst::isZeroEltSplatMask(
+        I->getShuffleMask(), 2));
+  }
+  {
+    auto *I = shuffleWithMask(1, 1);
+    EXPECT_FALSE(I->isZeroEltSplat());
+    EXPECT_FALSE(sandboxir::ShuffleVectorInst::isZeroEltSplatMask(
+        I->getShuffleMaskForBitcode(), 2));
+    EXPECT_FALSE(sandboxir::ShuffleVectorInst::isZeroEltSplatMask(
+        I->getShuffleMask(), 2));
+  }
+
+  // isTransposeMask
+  {
+    auto *I = shuffleWithMask(0, 2);
+    EXPECT_TRUE(I->isTranspose());
+    EXPECT_TRUE(sandboxir::ShuffleVectorInst::isTransposeMask(
+        I->getShuffleMaskForBitcode(), 2));
+    EXPECT_TRUE(
+        sandboxir::ShuffleVectorInst::isTransposeMask(I->getShuffleMask(), 2));
+  }
+  {
+    auto *I = shuffleWithMask(1, 1);
+    EXPECT_FALSE(I->isTranspose());
+    EXPECT_FALSE(sandboxir::ShuffleVectorInst::isTransposeMask(
+        I->getShuffleMaskForBitcode(), 2));
+    EXPECT_FALSE(
+        sandboxir::ShuffleVectorInst::isTransposeMask(I->getShuffleMask(), 2));
+  }
+
+  // isSpliceMask
+  {
+    auto *I = shuffleWithMask(1, 2);
+    int Index;
+    EXPECT_TRUE(I->isSplice(Index));
+    EXPECT_EQ(Index, 1);
+    EXPECT_TRUE(sandboxir::ShuffleVectorInst::isSpliceMask(
+        I->getShuffleMaskForBitcode(), 2, Index));
+    EXPECT_TRUE(sandboxir::ShuffleVectorInst::isSpliceMask(I->getShuffleMask(),
+                                                           2, Index));
+  }
+  {
+    auto *I = shuffleWithMask(2, 1);
+    int Index;
+    EXPECT_FALSE(I->isSplice(Index));
+    EXPECT_FALSE(sandboxir::ShuffleVectorInst::isSpliceMask(
+        I->getShuffleMaskForBitcode(), 2, Index));
+    EXPECT_FALSE(sandboxir::ShuffleVectorInst::isSpliceMask(I->getShuffleMask(),
+                                                            2, Index));
+  }
+
+  // isExtractSubvectorMask
+  {
+    auto *I = shuffleWithMask(1);
+    int Index;
+    EXPECT_TRUE(I->isExtractSubvectorMask(Index));
+    EXPECT_EQ(Index, 1);
+    EXPECT_TRUE(sandboxir::ShuffleVectorInst::isExtractSubvectorMask(
+        I->getShuffleMaskForBitcode(), 2, Index));
+    EXPECT_TRUE(sandboxir::ShuffleVectorInst::isExtractSubvectorMask(
+        I->getShuffleMask(), 2, Index));
+  }
+  {
+    auto *I = shuffleWithMask(1, 2);
+    int Index;
+    EXPECT_FALSE(I->isExtractSubvectorMask(Index));
+    EXPECT_FALSE(sandboxir::ShuffleVectorInst::isExtractSubvectorMask(
+        I->getShuffleMaskForBitcode(), 2, Index));
+    EXPECT_FALSE(sandboxir::ShuffleVectorInst::isExtractSubvectorMask(
+        I->getShuffleMask(), 2, Index));
+  }
+
+  // isInsertSubvectorMask
+  {
+    auto *I = shuffleWithMask(0, 2);
+    int NumSubElts, Index;
+    EXPECT_TRUE(I->isInsertSubvectorMask(NumSubElts, Index));
+    EXPECT_EQ(Index, 1);
+    EXPECT_EQ(NumSubElts, 1);
+    EXPECT_TRUE(sandboxir::ShuffleVectorInst::isInsertSubvectorMask(
+        I->getShuffleMaskForBitcode(), 2, NumSubElts, Index));
+    EXPECT_TRUE(sandboxir::ShuffleVectorInst::isInsertSubvectorMask(
+        I->getShuffleMask(), 2, NumSubElts, Index));
+  }
+  {
+    auto *I = shuffleWithMask(0, 1);
+    int NumSubElts, Index;
+    EXPECT_FALSE(I->isInsertSubvectorMask(NumSubElts, Index));
+    EXPECT_FALSE(sandboxir::ShuffleVectorInst::isInsertSubvectorMask(
+        I->getShuffleMaskForBitcode(), 2, NumSubElts, Index));
+    EXPECT_FALSE(sandboxir::ShuffleVectorInst::isInsertSubvectorMask(
+        I->getShuffleMask(), 2, NumSubElts, Index));
+  }
+
+  // isReplicationMask
+  {
+    auto *I = shuffleWithMask(0, 0, 0, 1, 1, 1);
+    int ReplicationFactor, VF;
+    EXPECT_TRUE(I->isReplicationMask(ReplicationFactor, VF));
+    EXPECT_EQ(ReplicationFactor, 3);
+    EXPECT_EQ(VF, 2);
+    EXPECT_TRUE(sandboxir::ShuffleVectorInst::isReplicationMask(
+        I->getShuffleMaskForBitcode(), ReplicationFactor, VF));
+    EXPECT_TRUE(sandboxir::ShuffleVectorInst::isReplicationMask(
+        I->getShuffleMask(), ReplicationFactor, VF));
+  }
+  {
+    auto *I = shuffleWithMask(1, 2);
+    int ReplicationFactor, VF;
+    EXPECT_FALSE(I->isReplicationMask(ReplicationFactor, VF));
+    EXPECT_FALSE(sandboxir::ShuffleVectorInst::isReplicationMask(
+        I->getShuffleMaskForBitcode(), ReplicationFactor, VF));
+    EXPECT_FALSE(sandboxir::ShuffleVectorInst::isReplicationMask(
+        I->getShuffleMask(), ReplicationFactor, VF));
+  }
+
+  // isOneUseSingleSourceMask
+  {
+    auto *I = shuffleWithMask(0, 1, 1, 0);
+    EXPECT_TRUE(I->isOneUseSingleSourceMask(2));
+    EXPECT_TRUE(sandboxir::ShuffleVectorInst::isOneUseSingleSourceMask(
+        I->getShuffleMask(), 2));
+  }
+  {
+    auto *I = shuffleWithMask(0, 1, 0, 0);
+    EXPECT_FALSE(I->isOneUseSingleSourceMask(2));
+    EXPECT_FALSE(sandboxir::ShuffleVectorInst::isOneUseSingleSourceMask(
+        I->getShuffleMask(), 2));
+  }
+
+  // commuteShuffleMask
+  {
+    SmallVector<int, 4> M = {0, 2, 1, 3};
+    ShuffleVectorInst::commuteShuffleMask(M, 2);
+    EXPECT_THAT(M, testing::ContainerEq(ArrayRef<int>({2, 0, 3, 1})));
+  }
+
+  // isInterleaveMask
+  {
+    auto *I = shuffleWithMask(0, 2, 1, 3);
+    EXPECT_TRUE(I->isInterleave(2));
+    EXPECT_TRUE(sandboxir::ShuffleVectorInst::isInterleaveMask(
+        I->getShuffleMask(), 2, 4));
+    SmallVector<unsigned, 4> StartIndexes;
+    EXPECT_TRUE(sandboxir::ShuffleVectorInst::isInterleaveMask(
+        I->getShuffleMask(), 2, 4, StartIndexes));
+    EXPECT_THAT(StartIndexes, testing::ContainerEq(ArrayRef<unsigned>({0, 2})));
+  }
+  {
+    auto *I = shuffleWithMask(0, 3, 1, 2);
+    EXPECT_FALSE(I->isInterleave(2));
+    EXPECT_FALSE(sandboxir::ShuffleVectorInst::isInterleaveMask(
+        I->getShuffleMask(), 2, 4));
+  }
+
+  // isDeInterleaveMaskOfFactor
+  EXPECT_TRUE(sandboxir::ShuffleVectorInst::isDeInterleaveMaskOfFactor(
+      ArrayRef<int>({0, 2}), 2));
+  EXPECT_FALSE(sandboxir::ShuffleVectorInst::isDeInterleaveMaskOfFactor(
+      ArrayRef<int>({0, 1}), 2));
+
+  // isBitRotateMask
+  {
+    unsigned NumSubElts, RotateAmt;
+    EXPECT_TRUE(sandboxir::ShuffleVectorInst::isBitRotateMask(
+        ArrayRef<int>({1, 0, 3, 2, 5, 4, 7, 6}), 8, 2, 2, NumSubElts,
+        RotateAmt));
+    EXPECT_EQ(NumSubElts, 2u);
+    EXPECT_EQ(RotateAmt, 8u);
+
+    EXPECT_FALSE(sandboxir::ShuffleVectorInst::isBitRotateMask(
+        ArrayRef<int>({0, 7, 1, 6, 2, 5, 3, 4}), 8, 2, 2, NumSubElts,
+        RotateAmt));
+  }
+}
+
 TEST_F(SandboxIRTest, BranchInst) {
   parseIR(C, R"IR(
 define void @foo(i1 %cond0, i1 %cond2) {

>From 06f5884e42bded3a691f652a908bb351ae4fb6a5 Mon Sep 17 00:00:00 2001
From: Jorge Gorbe Moya <jgorbe at google.com>
Date: Mon, 19 Aug 2024 19:08:16 -0700
Subject: [PATCH 2/3] fix clang-format diff

---
 llvm/include/llvm/SandboxIR/SandboxIR.h | 12 +++++-------
 1 file changed, 5 insertions(+), 7 deletions(-)

diff --git a/llvm/include/llvm/SandboxIR/SandboxIR.h b/llvm/include/llvm/SandboxIR/SandboxIR.h
index 2ec5e43b25c109..8485431504524d 100644
--- a/llvm/include/llvm/SandboxIR/SandboxIR.h
+++ b/llvm/include/llvm/SandboxIR/SandboxIR.h
@@ -953,7 +953,7 @@ class ExtractElementInst final
 };
 
 class ShuffleVectorInst final
-  : public SingleLLVMInstructionImpl<llvm::ShuffleVectorInst> {
+    : public SingleLLVMInstructionImpl<llvm::ShuffleVectorInst> {
   /// Use Context::createShuffleVectorInst() instead.
   ShuffleVectorInst(llvm::Instruction *I, Context &Ctx)
       : SingleLLVMInstructionImpl(ClassID::ShuffleVector, Opcode::ShuffleVector,
@@ -985,13 +985,10 @@ class ShuffleVectorInst final
 
   static bool isValidOperands(const Value *V1, const Value *V2,
                               ArrayRef<int> Mask) {
-    return llvm::ShuffleVectorInst::isValidOperands(V1->Val, V2->Val,
-                                                    Mask);
+    return llvm::ShuffleVectorInst::isValidOperands(V1->Val, V2->Val, Mask);
   }
 
-  void commute() {
-    cast<llvm::ShuffleVectorInst>(Val)->commute();
-  }
+  void commute() { cast<llvm::ShuffleVectorInst>(Val)->commute(); }
 
   VectorType *getType() const {
     return cast<llvm::ShuffleVectorInst>(Val)->getType();
@@ -1175,7 +1172,8 @@ class ShuffleVectorInst final
   }
   static bool isReplicationMask(const Constant *Mask, int &ReplicationFactor,
                                 int &VF) {
-    return llvm::ShuffleVectorInst::isReplicationMask(cast<llvm::Constant>(Mask->Val), ReplicationFactor, VF);
+    return llvm::ShuffleVectorInst::isReplicationMask(
+        cast<llvm::Constant>(Mask->Val), ReplicationFactor, VF);
   }
 
   /// Return true if this shuffle mask is a replication mask.

>From 784cad7e9af63f1c29abcb6300cdaa65b5a96125 Mon Sep 17 00:00:00 2001
From: Jorge Gorbe Moya <jgorbe at google.com>
Date: Tue, 20 Aug 2024 16:37:01 -0700
Subject: [PATCH 3/3] address review comments

---
 llvm/include/llvm/SandboxIR/SandboxIR.h    | 257 +++++++++++++++++----
 llvm/unittests/SandboxIR/SandboxIRTest.cpp | 149 +++++++-----
 2 files changed, 309 insertions(+), 97 deletions(-)

diff --git a/llvm/include/llvm/SandboxIR/SandboxIR.h b/llvm/include/llvm/SandboxIR/SandboxIR.h
index 8485431504524d..01ef8013ea42a0 100644
--- a/llvm/include/llvm/SandboxIR/SandboxIR.h
+++ b/llvm/include/llvm/SandboxIR/SandboxIR.h
@@ -241,32 +241,32 @@ class Value {
   /// order.
   llvm::Value *Val = nullptr;
 
-  friend class Context;            // For getting `Val`.
-  friend class User;               // For getting `Val`.
-  friend class Use;                // For getting `Val`.
-  friend class SelectInst;         // For getting `Val`.
-  friend class ExtractElementInst; // For getting `Val`.
-  friend class InsertElementInst;  // For getting `Val`.
-  friend class ShuffleVectorInst;  // For getting `Val`.
-  friend class BranchInst;         // For getting `Val`.
-  friend class LoadInst;           // For getting `Val`.
-  friend class StoreInst;          // For getting `Val`.
-  friend class ReturnInst;         // For getting `Val`.
-  friend class CallBase;           // For getting `Val`.
-  friend class CallInst;           // For getting `Val`.
-  friend class InvokeInst;         // For getting `Val`.
-  friend class CallBrInst;         // For getting `Val`.
-  friend class GetElementPtrInst;  // For getting `Val`.
-  friend class CatchSwitchInst;    // For getting `Val`.
-  friend class SwitchInst;         // For getting `Val`.
-  friend class UnaryOperator;      // For getting `Val`.
-  friend class BinaryOperator;     // For getting `Val`.
-  friend class AtomicRMWInst;      // For getting `Val`.
-  friend class AtomicCmpXchgInst;  // For getting `Val`.
-  friend class AllocaInst;         // For getting `Val`.
-  friend class CastInst;           // For getting `Val`.
-  friend class PHINode;            // For getting `Val`.
-  friend class UnreachableInst;    // For getting `Val`.
+  friend class Context;               // For getting `Val`.
+  friend class User;                  // For getting `Val`.
+  friend class Use;                   // For getting `Val`.
+  friend class SelectInst;            // For getting `Val`.
+  friend class ExtractElementInst;    // For getting `Val`.
+  friend class InsertElementInst;     // For getting `Val`.
+  friend class ShuffleVectorInst;     // For getting `Val`.
+  friend class BranchInst;            // For getting `Val`.
+  friend class LoadInst;              // For getting `Val`.
+  friend class StoreInst;             // For getting `Val`.
+  friend class ReturnInst;            // For getting `Val`.
+  friend class CallBase;              // For getting `Val`.
+  friend class CallInst;              // For getting `Val`.
+  friend class InvokeInst;            // For getting `Val`.
+  friend class CallBrInst;            // For getting `Val`.
+  friend class GetElementPtrInst;     // For getting `Val`.
+  friend class CatchSwitchInst;       // For getting `Val`.
+  friend class SwitchInst;            // For getting `Val`.
+  friend class UnaryOperator;         // For getting `Val`.
+  friend class BinaryOperator;        // For getting `Val`.
+  friend class AtomicRMWInst;         // For getting `Val`.
+  friend class AtomicCmpXchgInst;     // For getting `Val`.
+  friend class AllocaInst;            // For getting `Val`.
+  friend class CastInst;              // For getting `Val`.
+  friend class PHINode;               // For getting `Val`.
+  friend class UnreachableInst;       // For getting `Val`.
   friend class CatchSwitchAddHandler; // For `Val`.
 
   /// All values point to the context.
@@ -977,37 +977,48 @@ class ShuffleVectorInst final
     return From->getSubclassID() == ClassID::ShuffleVector;
   }
 
+  /// Swap the operands and adjust the mask to preserve the semantics of the
+  /// instruction.
+  void commute() { cast<llvm::ShuffleVectorInst>(Val)->commute(); }
+
+  /// Return true if a shufflevector instruction can be formed with the
+  /// specified operands.
   static bool isValidOperands(const Value *V1, const Value *V2,
                               const Value *Mask) {
     return llvm::ShuffleVectorInst::isValidOperands(V1->Val, V2->Val,
                                                     Mask->Val);
   }
-
   static bool isValidOperands(const Value *V1, const Value *V2,
                               ArrayRef<int> Mask) {
     return llvm::ShuffleVectorInst::isValidOperands(V1->Val, V2->Val, Mask);
   }
 
-  void commute() { cast<llvm::ShuffleVectorInst>(Val)->commute(); }
-
+  /// Overload to return most specific vector type.
   VectorType *getType() const {
     return cast<llvm::ShuffleVectorInst>(Val)->getType();
   }
 
+  /// Return the shuffle mask value of this instruction for the given element
+  /// index. Return PoisonMaskElem if the element is undef.
   int getMaskValue(unsigned Elt) const {
     return cast<llvm::ShuffleVectorInst>(Val)->getMaskValue(Elt);
   }
 
+  /// Convert the input shuffle mask operand to a vector of integers. Undefined
+  /// elements of the mask are returned as PoisonMaskElem.
   static void getShuffleMask(const Constant *Mask,
                              SmallVectorImpl<int> &Result) {
     llvm::ShuffleVectorInst::getShuffleMask(cast<llvm::Constant>(Mask->Val),
                                             Result);
   }
 
+  /// Return the mask for this instruction as a vector of integers. Undefined
+  /// elements of the mask are returned as PoisonMaskElem.
   void getShuffleMask(SmallVectorImpl<int> &Result) const {
     cast<llvm::ShuffleVectorInst>(Val)->getShuffleMask(Result);
   }
 
+  /// Return the mask for this instruction, for use in bitcode.
   Constant *getShuffleMaskForBitcode() const;
 
   static Constant *convertShuffleMaskForBitcode(ArrayRef<int> Mask,
@@ -1021,150 +1032,264 @@ class ShuffleVectorInst final
     return cast<llvm::ShuffleVectorInst>(Val)->getShuffleMask();
   }
 
+  /// Return true if this shuffle returns a vector with a different number of
+  /// elements than its source vectors.
+  /// Examples: shufflevector <4 x n> A, <4 x n> B, <1,2,3>
+  ///           shufflevector <4 x n> A, <4 x n> B, <1,2,3,4,5>
   bool changesLength() const {
     return cast<llvm::ShuffleVectorInst>(Val)->changesLength();
   }
 
+  /// Return true if this shuffle returns a vector with a greater number of
+  /// elements than its source vectors.
+  /// Example: shufflevector <2 x n> A, <2 x n> B, <1,2,3>
   bool increasesLength() const {
     return cast<llvm::ShuffleVectorInst>(Val)->increasesLength();
   }
 
+  /// Return true if this shuffle mask chooses elements from exactly one source
+  /// vector.
+  /// Example: <7,5,undef,7>
+  /// This assumes that vector operands (of length \p NumSrcElts) are the same
+  /// length as the mask.
   static bool isSingleSourceMask(ArrayRef<int> Mask, int NumSrcElts) {
     return llvm::ShuffleVectorInst::isSingleSourceMask(Mask, NumSrcElts);
   }
-
   static bool isSingleSourceMask(const Constant *Mask, int NumSrcElts) {
     return llvm::ShuffleVectorInst::isSingleSourceMask(
         cast<llvm::Constant>(Mask->Val), 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>
   bool isSingleSource() const {
     return cast<llvm::ShuffleVectorInst>(Val)->isSingleSource();
   }
 
+  /// Return true if this shuffle mask chooses elements from exactly one source
+  /// vector without lane crossings. A shuffle using this mask is not
+  /// necessarily a no-op because it may change the number of elements from its
+  /// input vectors or it may provide demanded bits knowledge via undef lanes.
+  /// Example: <undef,undef,2,3>
   static bool isIdentityMask(ArrayRef<int> Mask, int NumSrcElts) {
     return llvm::ShuffleVectorInst::isIdentityMask(Mask, NumSrcElts);
   }
-
   static bool isIdentityMask(const Constant *Mask, int NumSrcElts) {
     return llvm::ShuffleVectorInst::isIdentityMask(
         cast<llvm::Constant>(Mask->Val), 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 {
     return cast<llvm::ShuffleVectorInst>(Val)->isIdentity();
   }
 
+  /// Return true if this shuffle lengthens exactly one source vector with
+  /// undefs in the high elements.
   bool isIdentityWithPadding() const {
     return cast<llvm::ShuffleVectorInst>(Val)->isIdentityWithPadding();
   }
 
+  /// Return true if this shuffle extracts the first N elements of exactly one
+  /// source vector.
   bool isIdentityWithExtract() const {
     return cast<llvm::ShuffleVectorInst>(Val)->isIdentityWithExtract();
   }
 
+  /// 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 cast<llvm::ShuffleVectorInst>(Val)->isConcat();
   }
 
+  /// Return true if this shuffle mask chooses elements from its source vectors
+  /// without lane crossings. A shuffle using this mask would be
+  /// equivalent to a vector select with a constant condition operand.
+  /// Example: <4,1,6,undef>
+  /// 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.
+  /// This assumes that vector operands are the same length as the mask
+  /// (a length-changing shuffle can never be equivalent to a vector select).
   static bool isSelectMask(ArrayRef<int> Mask, int NumSrcElts) {
     return llvm::ShuffleVectorInst::isSelectMask(Mask, NumSrcElts);
   }
-
   static bool isSelectMask(const Constant *Mask, int NumSrcElts) {
     return llvm::ShuffleVectorInst::isSelectMask(
         cast<llvm::Constant>(Mask->Val), 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.
   bool isSelect() const {
     return cast<llvm::ShuffleVectorInst>(Val)->isSelect();
   }
 
+  /// Return true if this shuffle mask swaps the order of elements from exactly
+  /// one source vector.
+  /// Example: <7,6,undef,4>
+  /// This assumes that vector operands (of length \p NumSrcElts) are the same
+  /// length as the mask.
   static bool isReverseMask(ArrayRef<int> Mask, int NumSrcElts) {
     return llvm::ShuffleVectorInst::isReverseMask(Mask, NumSrcElts);
   }
-
   static bool isReverseMask(const Constant *Mask, int NumSrcElts) {
     return llvm::ShuffleVectorInst::isReverseMask(
         cast<llvm::Constant>(Mask->Val), 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>
   bool isReverse() const {
     return cast<llvm::ShuffleVectorInst>(Val)->isReverse();
   }
 
+  /// Return true if this shuffle mask chooses all elements with the same value
+  /// as the first element of exactly one source vector.
+  /// Example: <4,undef,undef,4>
+  /// This assumes that vector operands (of length \p NumSrcElts) are the same
+  /// length as the mask.
   static bool isZeroEltSplatMask(ArrayRef<int> Mask, int NumSrcElts) {
     return llvm::ShuffleVectorInst::isZeroEltSplatMask(Mask, NumSrcElts);
   }
-
   static bool isZeroEltSplatMask(const Constant *Mask, int NumSrcElts) {
     return llvm::ShuffleVectorInst::isZeroEltSplatMask(
         cast<llvm::Constant>(Mask->Val), 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>
   bool isZeroEltSplat() const {
     return cast<llvm::ShuffleVectorInst>(Val)->isZeroEltSplat();
   }
 
+  /// Return true if this shuffle mask is a transpose mask.
+  /// Transpose vector masks transpose a 2xn matrix. They read corresponding
+  /// even- or odd-numbered vector elements from two n-dimensional source
+  /// vectors and write each result into consecutive elements of an
+  /// n-dimensional destination vector. Two shuffles are necessary to complete
+  /// the transpose, one for the even elements and another for the odd elements.
+  /// This description closely follows how the TRN1 and TRN2 AArch64
+  /// instructions operate.
+  ///
+  /// For example, a simple 2x2 matrix can be transposed with:
+  ///
+  ///   ; Original matrix
+  ///   m0 = < a, b >
+  ///   m1 = < c, d >
+  ///
+  ///   ; Transposed matrix
+  ///   t0 = < a, c > = shufflevector m0, m1, < 0, 2 >
+  ///   t1 = < b, d > = shufflevector m0, m1, < 1, 3 >
+  ///
+  /// For matrices having greater than n columns, the resulting nx2 transposed
+  /// matrix is stored in two result vectors such that one vector contains
+  /// interleaved elements from all the even-numbered rows and the other vector
+  /// contains interleaved elements from all the odd-numbered rows. For example,
+  /// a 2x4 matrix can be transposed with:
+  ///
+  ///   ; Original matrix
+  ///   m0 = < a, b, c, d >
+  ///   m1 = < e, f, g, h >
+  ///
+  ///   ; Transposed matrix
+  ///   t0 = < a, e, c, g > = shufflevector m0, m1 < 0, 4, 2, 6 >
+  ///   t1 = < b, f, d, h > = shufflevector m0, m1 < 1, 5, 3, 7 >
   static bool isTransposeMask(ArrayRef<int> Mask, int NumSrcElts) {
     return llvm::ShuffleVectorInst::isTransposeMask(Mask, NumSrcElts);
   }
-
   static bool isTransposeMask(const Constant *Mask, int NumSrcElts) {
     return llvm::ShuffleVectorInst::isTransposeMask(
         cast<llvm::Constant>(Mask->Val), 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 cast<llvm::ShuffleVectorInst>(Val)->isTranspose();
   }
 
+  /// Return true if this shuffle mask is a splice mask, concatenating 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>
+  /// This assumes that vector operands (of length \p NumSrcElts) are the same
+  /// length as the mask.
   static bool isSpliceMask(ArrayRef<int> Mask, int NumSrcElts, int &Index) {
     return llvm::ShuffleVectorInst::isSpliceMask(Mask, NumSrcElts, Index);
   }
-
   static bool isSpliceMask(const Constant *Mask, int NumSrcElts, int &Index) {
     return llvm::ShuffleVectorInst::isSpliceMask(
         cast<llvm::Constant>(Mask->Val), 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 cast<llvm::ShuffleVectorInst>(Val)->isSplice(Index);
   }
 
+  /// Return true if this shuffle mask is an extract subvector mask.
+  /// A valid extract subvector mask returns a smaller vector from a single
+  /// source operand. The base extraction index is returned as well.
   static bool isExtractSubvectorMask(ArrayRef<int> Mask, int NumSrcElts,
                                      int &Index) {
     return llvm::ShuffleVectorInst::isExtractSubvectorMask(Mask, NumSrcElts,
                                                            Index);
   }
-
   static bool isExtractSubvectorMask(const Constant *Mask, int NumSrcElts,
                                      int &Index) {
     return llvm::ShuffleVectorInst::isExtractSubvectorMask(
         cast<llvm::Constant>(Mask->Val), NumSrcElts, Index);
   }
 
+  /// Return true if this shuffle mask is an extract subvector mask.
   bool isExtractSubvectorMask(int &Index) const {
     return cast<llvm::ShuffleVectorInst>(Val)->isExtractSubvectorMask(Index);
   }
 
+  /// Return true if this shuffle mask is an insert subvector mask.
+  /// A valid insert subvector mask inserts the lowest elements of a second
+  /// source operand into an in-place first source operand.
+  /// Both the sub vector width and the insertion index is returned.
   static bool isInsertSubvectorMask(ArrayRef<int> Mask, int NumSrcElts,
                                     int &NumSubElts, int &Index) {
     return llvm::ShuffleVectorInst::isInsertSubvectorMask(Mask, NumSrcElts,
                                                           NumSubElts, Index);
   }
-
   static bool isInsertSubvectorMask(const Constant *Mask, int NumSrcElts,
                                     int &NumSubElts, int &Index) {
     return llvm::ShuffleVectorInst::isInsertSubvectorMask(
         cast<llvm::Constant>(Mask->Val), NumSrcElts, NumSubElts, Index);
   }
 
+  /// Return true if this shuffle mask is an insert subvector mask.
   bool isInsertSubvectorMask(int &NumSubElts, int &Index) const {
     return cast<llvm::ShuffleVectorInst>(Val)->isInsertSubvectorMask(NumSubElts,
                                                                      Index);
   }
 
+  /// Return true if this shuffle mask replicates each of the \p VF elements
+  /// in a vector \p ReplicationFactor times.
+  /// For example, the mask for \p ReplicationFactor=3 and \p VF=4 is:
+  ///   <0,0,0,1,1,1,2,2,2,3,3,3>
   static bool isReplicationMask(ArrayRef<int> Mask, int &ReplicationFactor,
                                 int &VF) {
     return llvm::ShuffleVectorInst::isReplicationMask(Mask, ReplicationFactor,
@@ -1182,36 +1307,71 @@ class ShuffleVectorInst final
         ReplicationFactor, VF);
   }
 
+  /// Return true if this shuffle mask represents "clustered" mask of size VF,
+  /// i.e. each index between [0..VF) is used exactly once in each submask of
+  /// size VF.
+  /// For example, the mask for \p VF=4 is:
+  /// 0, 1, 2, 3, 3, 2, 0, 1 - "clustered", because each submask of size 4
+  /// (0,1,2,3 and 3,2,0,1) uses indices [0..VF) exactly one time.
+  /// 0, 1, 2, 3, 3, 3, 1, 0 - not "clustered", because
+  ///                          element 3 is used twice in the second submask
+  ///                          (3,3,1,0) and index 2 is not used at all.
   static bool isOneUseSingleSourceMask(ArrayRef<int> Mask, int VF) {
     return llvm::ShuffleVectorInst::isOneUseSingleSourceMask(Mask, VF);
   }
 
+  /// Return true if this shuffle mask is a one-use-single-source("clustered")
+  /// mask.
   bool isOneUseSingleSourceMask(int VF) const {
     return cast<llvm::ShuffleVectorInst>(Val)->isOneUseSingleSourceMask(VF);
   }
 
+  /// Change values in a shuffle permute mask assuming the two vector operands
+  /// of length InVecNumElts have swapped position.
   static void commuteShuffleMask(MutableArrayRef<int> Mask,
                                  unsigned InVecNumElts) {
     llvm::ShuffleVectorInst::commuteShuffleMask(Mask, InVecNumElts);
   }
 
+  /// Return if this shuffle interleaves its two input vectors together.
+  bool isInterleave(unsigned Factor) const {
+    return cast<llvm::ShuffleVectorInst>(Val)->isInterleave(Factor);
+  }
+
+  /// Return true if the mask interleaves one or more input vectors together.
+  ///
+  /// I.e. <0, LaneLen, ... , LaneLen*(Factor - 1), 1, LaneLen + 1, ...>
+  /// E.g. For a Factor of 2 (LaneLen=4):
+  ///   <0, 4, 1, 5, 2, 6, 3, 7>
+  /// E.g. For a Factor of 3 (LaneLen=4):
+  ///   <4, 0, 9, 5, 1, 10, 6, 2, 11, 7, 3, 12>
+  /// E.g. For a Factor of 4 (LaneLen=2):
+  ///   <0, 2, 6, 4, 1, 3, 7, 5>
+  ///
+  /// NumInputElts is the total number of elements in the input vectors.
+  ///
+  /// StartIndexes are the first indexes of each vector being interleaved,
+  /// substituting any indexes that were undef
+  /// E.g. <4, -1, 2, 5, 1, 3> (Factor=3): StartIndexes=<4, 0, 2>
+  ///
+  /// Note that this does not check if the input vectors are consecutive:
+  /// It will return true for masks such as
+  /// <0, 4, 6, 1, 5, 7> (Factor=3, LaneLen=2)
   static bool isInterleaveMask(ArrayRef<int> Mask, unsigned Factor,
                                unsigned NumInputElts,
                                SmallVectorImpl<unsigned> &StartIndexes) {
     return llvm::ShuffleVectorInst::isInterleaveMask(Mask, Factor, NumInputElts,
                                                      StartIndexes);
   }
-
   static bool isInterleaveMask(ArrayRef<int> Mask, unsigned Factor,
                                unsigned NumInputElts) {
     return llvm::ShuffleVectorInst::isInterleaveMask(Mask, Factor,
                                                      NumInputElts);
   }
 
-  bool isInterleave(unsigned Factor) const {
-    return cast<llvm::ShuffleVectorInst>(Val)->isInterleave(Factor);
-  }
-
+  /// Check if the mask is a DE-interleave mask of the given factor
+  /// \p Factor like:
+  ///     <Index, Index+Factor, ..., Index+(NumElts-1)*Factor>
   static bool isDeInterleaveMaskOfFactor(ArrayRef<int> Mask, unsigned Factor,
                                          unsigned &Index) {
     return llvm::ShuffleVectorInst::isDeInterleaveMaskOfFactor(Mask, Factor,
@@ -1221,6 +1381,17 @@ class ShuffleVectorInst final
     return llvm::ShuffleVectorInst::isDeInterleaveMaskOfFactor(Mask, Factor);
   }
 
+  /// Checks if the shuffle is a bit rotation of the first operand across
+  /// multiple subelements, e.g:
+  ///
+  /// shuffle <8 x i8> %a, <8 x i8> poison, <8 x i32> <1, 0, 3, 2, 5, 4, 7, 6>
+  ///
+  /// could be expressed as
+  ///
+  /// rotl <4 x i16> %a, 8
+  ///
+  /// If it can be expressed as a rotation, returns the number of subelements to
+  /// group by in NumSubElts and the number of bits to rotate left in RotateAmt.
   static bool isBitRotateMask(ArrayRef<int> Mask, unsigned EltSizeInBits,
                               unsigned MinSubElts, unsigned MaxSubElts,
                               unsigned &NumSubElts, unsigned &RotateAmt) {
diff --git a/llvm/unittests/SandboxIR/SandboxIRTest.cpp b/llvm/unittests/SandboxIR/SandboxIRTest.cpp
index 0e7e0c97d7a84c..8570d8f5ba0d8d 100644
--- a/llvm/unittests/SandboxIR/SandboxIRTest.cpp
+++ b/llvm/unittests/SandboxIR/SandboxIRTest.cpp
@@ -758,17 +758,19 @@ define void @foo(<2 x i8> %v1, <2 x i8> %v2) {
   auto *Ret = &*It++;
 
   EXPECT_EQ(SI->getOpcode(), sandboxir::Instruction::Opcode::ShuffleVector);
-  EXPECT_EQ(SI->getType(), ArgV1->getType());
   EXPECT_EQ(SI->getOperand(0), ArgV1);
   EXPECT_EQ(SI->getOperand(1), ArgV2);
-  EXPECT_EQ(SI->getMaskValue(0), 0);
-  EXPECT_EQ(SI->getMaskValue(1), 2);
-  SI->commute();
-  EXPECT_EQ(SI->getOperand(0), ArgV2);
-  EXPECT_EQ(SI->getOperand(1), ArgV1);
-  EXPECT_THAT(SI->getShuffleMask(),
-              testing::ContainerEq(ArrayRef<int>({2, 0})));
 
+  // In order to test all the methods we need masks of different lengths, so we
+  // can't simply reuse one of the instructions created above. This helper
+  // creates a new `shufflevector %v1, %2, <mask>` with the given mask indices.
+  auto CreateShuffleWithMask = [&](auto &&...Indices) {
+    SmallVector<int, 4> Mask = {Indices...};
+    return cast<sandboxir::ShuffleVectorInst>(
+        sandboxir::ShuffleVectorInst::create(ArgV1, ArgV2, Mask, Ret, Ctx));
+  };
+
+  // create (InsertBefore)
   auto *NewI1 =
       cast<sandboxir::ShuffleVectorInst>(sandboxir::ShuffleVectorInst::create(
           ArgV1, ArgV2, ArrayRef<int>({0, 2, 1, 3}), Ret, Ctx,
@@ -776,14 +778,17 @@ define void @foo(<2 x i8> %v1, <2 x i8> %v2) {
   EXPECT_EQ(NewI1->getOperand(0), ArgV1);
   EXPECT_EQ(NewI1->getOperand(1), ArgV2);
   EXPECT_EQ(NewI1->getNextNode(), Ret);
-  EXPECT_TRUE(NewI1->changesLength());
-  EXPECT_TRUE(NewI1->increasesLength());
+#ifndef NDEBUG
+  EXPECT_EQ(NewI1->getName(), "NewShuffleBeforeRet");
+#endif
 
+  // create (InsertAtEnd)
   auto *NewI2 =
       cast<sandboxir::ShuffleVectorInst>(sandboxir::ShuffleVectorInst::create(
           ArgV1, ArgV2, ArrayRef<int>({0, 1}), BB, Ctx, "NewShuffleAtEndOfBB"));
   EXPECT_EQ(NewI2->getPrevNode(), Ret);
 
+  // isValidOperands
   auto *LLVMArgV1 = LLVMF.getArg(0);
   auto *LLVMArgV2 = LLVMF.getArg(1);
   ArrayRef<int> Mask({1, 2});
@@ -794,41 +799,77 @@ define void @foo(<2 x i8> %v1, <2 x i8> %v2) {
             llvm::ShuffleVectorInst::isValidOperands(LLVMArgV1, LLVMArgV1,
                                                      LLVMArgV1));
 
+  // commute
+  {
+    auto *I = CreateShuffleWithMask(0, 2);
+    I->commute();
+    EXPECT_EQ(I->getOperand(0), ArgV2);
+    EXPECT_EQ(I->getOperand(1), ArgV1);
+    EXPECT_THAT(I->getShuffleMask(),
+                testing::ContainerEq(ArrayRef<int>({2, 0})));
+  }
+
+  // getType
+  EXPECT_EQ(SI->getType(), ArgV1->getType());
+
+  // getMaskValue
+  EXPECT_EQ(SI->getMaskValue(0), 0);
+  EXPECT_EQ(SI->getMaskValue(1), 2);
+
+  // getShuffleMask/getShuffleMaskForBitcode
+  {
+    EXPECT_THAT(SI->getShuffleMask(),
+                testing::ContainerEq(ArrayRef<int>({0, 2})));
+
+    SmallVector<int, 2> Result;
+    sandboxir::ShuffleVectorInst::getShuffleMask(SI->getShuffleMaskForBitcode(),
+                                                 Result);
+    EXPECT_THAT(Result, testing::ContainerEq(ArrayRef<int>({0, 2})));
+  }
+
+  // convertShuffleMaskForBitcode
+  {
+    auto *C = sandboxir::ShuffleVectorInst::convertShuffleMaskForBitcode(
+        ArrayRef<int>({2, 3}), ArgV1->getType(), Ctx);
+    SmallVector<int, 2> Result;
+    sandboxir::ShuffleVectorInst::getShuffleMask(C, Result);
+    EXPECT_THAT(Result, testing::ContainerEq(ArrayRef<int>({2, 3})));
+  }
+
+  // setShuffleMask
+  {
+    auto *I = CreateShuffleWithMask(0, 1);
+    I->setShuffleMask(ArrayRef<int>({2, 3}));
+    EXPECT_THAT(I->getShuffleMask(),
+                testing::ContainerEq(ArrayRef<int>({2, 3})));
+  }
+
   // The following functions check different mask properties. Note that most
   // of these come in three different flavors: a method that checks the mask
   // in the current instructions and two static member functions that check
   // a mask given as an ArrayRef<int> or Constant*, so there's quite a bit of
   // repetition in order to check all of them.
-  //
-  // Because we need masks of different lengths we can't simply reuse one of the
-  // instructions we have created above, so we'll create a new instruction for
-  // each test using this helper.
-  auto shuffleWithMask = [&](auto &&...Indices) {
-    SmallVector<int, 4> Mask = {Indices...};
-    return cast<sandboxir::ShuffleVectorInst>(
-        sandboxir::ShuffleVectorInst::create(ArgV1, ArgV2, Mask, Ret, Ctx));
-  };
 
   // changesLength / increasesLength
   {
-    auto *I = shuffleWithMask(1);
+    auto *I = CreateShuffleWithMask(1);
     EXPECT_TRUE(I->changesLength());
     EXPECT_FALSE(I->increasesLength());
   }
   {
-    auto *I = shuffleWithMask(1, 1);
+    auto *I = CreateShuffleWithMask(1, 1);
     EXPECT_FALSE(I->changesLength());
     EXPECT_FALSE(I->increasesLength());
   }
   {
-    auto *I = shuffleWithMask(1, 1, 1);
+    auto *I = CreateShuffleWithMask(1, 1, 1);
     EXPECT_TRUE(I->changesLength());
     EXPECT_TRUE(I->increasesLength());
   }
 
   // isSingleSourceMask
   {
-    auto *I = shuffleWithMask(0, 1);
+    auto *I = CreateShuffleWithMask(0, 1);
     EXPECT_TRUE(I->isSingleSource());
     EXPECT_TRUE(sandboxir::ShuffleVectorInst::isSingleSourceMask(
         I->getShuffleMaskForBitcode(), 2));
@@ -836,7 +877,7 @@ define void @foo(<2 x i8> %v1, <2 x i8> %v2) {
         I->getShuffleMask(), 2));
   }
   {
-    auto *I = shuffleWithMask(0, 2);
+    auto *I = CreateShuffleWithMask(0, 2);
     EXPECT_FALSE(I->isSingleSource());
     EXPECT_FALSE(sandboxir::ShuffleVectorInst::isSingleSourceMask(
         I->getShuffleMaskForBitcode(), 2));
@@ -846,7 +887,7 @@ define void @foo(<2 x i8> %v1, <2 x i8> %v2) {
 
   // isIdentityMask
   {
-    auto *I = shuffleWithMask(0, 1);
+    auto *I = CreateShuffleWithMask(0, 1);
     EXPECT_TRUE(I->isIdentity());
     EXPECT_TRUE(sandboxir::ShuffleVectorInst::isIdentityMask(
         I->getShuffleMaskForBitcode(), 2));
@@ -854,7 +895,7 @@ define void @foo(<2 x i8> %v1, <2 x i8> %v2) {
         sandboxir::ShuffleVectorInst::isIdentityMask(I->getShuffleMask(), 2));
   }
   {
-    auto *I = shuffleWithMask(1, 0);
+    auto *I = CreateShuffleWithMask(1, 0);
     EXPECT_FALSE(I->isIdentity());
     EXPECT_FALSE(sandboxir::ShuffleVectorInst::isIdentityMask(
         I->getShuffleMaskForBitcode(), 2));
@@ -863,22 +904,22 @@ define void @foo(<2 x i8> %v1, <2 x i8> %v2) {
   }
 
   // isIdentityWithPadding
-  EXPECT_TRUE(shuffleWithMask(0, 1, -1, -1)->isIdentityWithPadding());
-  EXPECT_FALSE(shuffleWithMask(0, 1)->isIdentityWithPadding());
+  EXPECT_TRUE(CreateShuffleWithMask(0, 1, -1, -1)->isIdentityWithPadding());
+  EXPECT_FALSE(CreateShuffleWithMask(0, 1)->isIdentityWithPadding());
 
   // isIdentityWithExtract
-  EXPECT_TRUE(shuffleWithMask(0)->isIdentityWithExtract());
-  EXPECT_FALSE(shuffleWithMask(0, 1)->isIdentityWithExtract());
-  EXPECT_FALSE(shuffleWithMask(0, 1, 2)->isIdentityWithExtract());
-  EXPECT_FALSE(shuffleWithMask(1)->isIdentityWithExtract());
+  EXPECT_TRUE(CreateShuffleWithMask(0)->isIdentityWithExtract());
+  EXPECT_FALSE(CreateShuffleWithMask(0, 1)->isIdentityWithExtract());
+  EXPECT_FALSE(CreateShuffleWithMask(0, 1, 2)->isIdentityWithExtract());
+  EXPECT_FALSE(CreateShuffleWithMask(1)->isIdentityWithExtract());
 
   // isConcat
-  EXPECT_TRUE(shuffleWithMask(0, 1, 2, 3)->isConcat());
-  EXPECT_FALSE(shuffleWithMask(0, 3)->isConcat());
+  EXPECT_TRUE(CreateShuffleWithMask(0, 1, 2, 3)->isConcat());
+  EXPECT_FALSE(CreateShuffleWithMask(0, 3)->isConcat());
 
   // isSelectMask
   {
-    auto *I = shuffleWithMask(0, 3);
+    auto *I = CreateShuffleWithMask(0, 3);
     EXPECT_TRUE(I->isSelect());
     EXPECT_TRUE(sandboxir::ShuffleVectorInst::isSelectMask(
         I->getShuffleMaskForBitcode(), 2));
@@ -886,7 +927,7 @@ define void @foo(<2 x i8> %v1, <2 x i8> %v2) {
         sandboxir::ShuffleVectorInst::isSelectMask(I->getShuffleMask(), 2));
   }
   {
-    auto *I = shuffleWithMask(0, 2);
+    auto *I = CreateShuffleWithMask(0, 2);
     EXPECT_FALSE(I->isSelect());
     EXPECT_FALSE(sandboxir::ShuffleVectorInst::isSelectMask(
         I->getShuffleMaskForBitcode(), 2));
@@ -896,7 +937,7 @@ define void @foo(<2 x i8> %v1, <2 x i8> %v2) {
 
   // isReverseMask
   {
-    auto *I = shuffleWithMask(1, 0);
+    auto *I = CreateShuffleWithMask(1, 0);
     EXPECT_TRUE(I->isReverse());
     EXPECT_TRUE(sandboxir::ShuffleVectorInst::isReverseMask(
         I->getShuffleMaskForBitcode(), 2));
@@ -904,7 +945,7 @@ define void @foo(<2 x i8> %v1, <2 x i8> %v2) {
         sandboxir::ShuffleVectorInst::isReverseMask(I->getShuffleMask(), 2));
   }
   {
-    auto *I = shuffleWithMask(1, 2);
+    auto *I = CreateShuffleWithMask(1, 2);
     EXPECT_FALSE(I->isReverse());
     EXPECT_FALSE(sandboxir::ShuffleVectorInst::isReverseMask(
         I->getShuffleMaskForBitcode(), 2));
@@ -914,7 +955,7 @@ define void @foo(<2 x i8> %v1, <2 x i8> %v2) {
 
   // isZeroEltSplatMask
   {
-    auto *I = shuffleWithMask(0, 0);
+    auto *I = CreateShuffleWithMask(0, 0);
     EXPECT_TRUE(I->isZeroEltSplat());
     EXPECT_TRUE(sandboxir::ShuffleVectorInst::isZeroEltSplatMask(
         I->getShuffleMaskForBitcode(), 2));
@@ -922,7 +963,7 @@ define void @foo(<2 x i8> %v1, <2 x i8> %v2) {
         I->getShuffleMask(), 2));
   }
   {
-    auto *I = shuffleWithMask(1, 1);
+    auto *I = CreateShuffleWithMask(1, 1);
     EXPECT_FALSE(I->isZeroEltSplat());
     EXPECT_FALSE(sandboxir::ShuffleVectorInst::isZeroEltSplatMask(
         I->getShuffleMaskForBitcode(), 2));
@@ -932,7 +973,7 @@ define void @foo(<2 x i8> %v1, <2 x i8> %v2) {
 
   // isTransposeMask
   {
-    auto *I = shuffleWithMask(0, 2);
+    auto *I = CreateShuffleWithMask(0, 2);
     EXPECT_TRUE(I->isTranspose());
     EXPECT_TRUE(sandboxir::ShuffleVectorInst::isTransposeMask(
         I->getShuffleMaskForBitcode(), 2));
@@ -940,7 +981,7 @@ define void @foo(<2 x i8> %v1, <2 x i8> %v2) {
         sandboxir::ShuffleVectorInst::isTransposeMask(I->getShuffleMask(), 2));
   }
   {
-    auto *I = shuffleWithMask(1, 1);
+    auto *I = CreateShuffleWithMask(1, 1);
     EXPECT_FALSE(I->isTranspose());
     EXPECT_FALSE(sandboxir::ShuffleVectorInst::isTransposeMask(
         I->getShuffleMaskForBitcode(), 2));
@@ -950,7 +991,7 @@ define void @foo(<2 x i8> %v1, <2 x i8> %v2) {
 
   // isSpliceMask
   {
-    auto *I = shuffleWithMask(1, 2);
+    auto *I = CreateShuffleWithMask(1, 2);
     int Index;
     EXPECT_TRUE(I->isSplice(Index));
     EXPECT_EQ(Index, 1);
@@ -960,7 +1001,7 @@ define void @foo(<2 x i8> %v1, <2 x i8> %v2) {
                                                            2, Index));
   }
   {
-    auto *I = shuffleWithMask(2, 1);
+    auto *I = CreateShuffleWithMask(2, 1);
     int Index;
     EXPECT_FALSE(I->isSplice(Index));
     EXPECT_FALSE(sandboxir::ShuffleVectorInst::isSpliceMask(
@@ -971,7 +1012,7 @@ define void @foo(<2 x i8> %v1, <2 x i8> %v2) {
 
   // isExtractSubvectorMask
   {
-    auto *I = shuffleWithMask(1);
+    auto *I = CreateShuffleWithMask(1);
     int Index;
     EXPECT_TRUE(I->isExtractSubvectorMask(Index));
     EXPECT_EQ(Index, 1);
@@ -981,7 +1022,7 @@ define void @foo(<2 x i8> %v1, <2 x i8> %v2) {
         I->getShuffleMask(), 2, Index));
   }
   {
-    auto *I = shuffleWithMask(1, 2);
+    auto *I = CreateShuffleWithMask(1, 2);
     int Index;
     EXPECT_FALSE(I->isExtractSubvectorMask(Index));
     EXPECT_FALSE(sandboxir::ShuffleVectorInst::isExtractSubvectorMask(
@@ -992,7 +1033,7 @@ define void @foo(<2 x i8> %v1, <2 x i8> %v2) {
 
   // isInsertSubvectorMask
   {
-    auto *I = shuffleWithMask(0, 2);
+    auto *I = CreateShuffleWithMask(0, 2);
     int NumSubElts, Index;
     EXPECT_TRUE(I->isInsertSubvectorMask(NumSubElts, Index));
     EXPECT_EQ(Index, 1);
@@ -1003,7 +1044,7 @@ define void @foo(<2 x i8> %v1, <2 x i8> %v2) {
         I->getShuffleMask(), 2, NumSubElts, Index));
   }
   {
-    auto *I = shuffleWithMask(0, 1);
+    auto *I = CreateShuffleWithMask(0, 1);
     int NumSubElts, Index;
     EXPECT_FALSE(I->isInsertSubvectorMask(NumSubElts, Index));
     EXPECT_FALSE(sandboxir::ShuffleVectorInst::isInsertSubvectorMask(
@@ -1014,7 +1055,7 @@ define void @foo(<2 x i8> %v1, <2 x i8> %v2) {
 
   // isReplicationMask
   {
-    auto *I = shuffleWithMask(0, 0, 0, 1, 1, 1);
+    auto *I = CreateShuffleWithMask(0, 0, 0, 1, 1, 1);
     int ReplicationFactor, VF;
     EXPECT_TRUE(I->isReplicationMask(ReplicationFactor, VF));
     EXPECT_EQ(ReplicationFactor, 3);
@@ -1025,7 +1066,7 @@ define void @foo(<2 x i8> %v1, <2 x i8> %v2) {
         I->getShuffleMask(), ReplicationFactor, VF));
   }
   {
-    auto *I = shuffleWithMask(1, 2);
+    auto *I = CreateShuffleWithMask(1, 2);
     int ReplicationFactor, VF;
     EXPECT_FALSE(I->isReplicationMask(ReplicationFactor, VF));
     EXPECT_FALSE(sandboxir::ShuffleVectorInst::isReplicationMask(
@@ -1036,13 +1077,13 @@ define void @foo(<2 x i8> %v1, <2 x i8> %v2) {
 
   // isOneUseSingleSourceMask
   {
-    auto *I = shuffleWithMask(0, 1, 1, 0);
+    auto *I = CreateShuffleWithMask(0, 1, 1, 0);
     EXPECT_TRUE(I->isOneUseSingleSourceMask(2));
     EXPECT_TRUE(sandboxir::ShuffleVectorInst::isOneUseSingleSourceMask(
         I->getShuffleMask(), 2));
   }
   {
-    auto *I = shuffleWithMask(0, 1, 0, 0);
+    auto *I = CreateShuffleWithMask(0, 1, 0, 0);
     EXPECT_FALSE(I->isOneUseSingleSourceMask(2));
     EXPECT_FALSE(sandboxir::ShuffleVectorInst::isOneUseSingleSourceMask(
         I->getShuffleMask(), 2));
@@ -1057,7 +1098,7 @@ define void @foo(<2 x i8> %v1, <2 x i8> %v2) {
 
   // isInterleaveMask
   {
-    auto *I = shuffleWithMask(0, 2, 1, 3);
+    auto *I = CreateShuffleWithMask(0, 2, 1, 3);
     EXPECT_TRUE(I->isInterleave(2));
     EXPECT_TRUE(sandboxir::ShuffleVectorInst::isInterleaveMask(
         I->getShuffleMask(), 2, 4));
@@ -1067,7 +1108,7 @@ define void @foo(<2 x i8> %v1, <2 x i8> %v2) {
     EXPECT_THAT(StartIndexes, testing::ContainerEq(ArrayRef<unsigned>({0, 2})));
   }
   {
-    auto *I = shuffleWithMask(0, 3, 1, 2);
+    auto *I = CreateShuffleWithMask(0, 3, 1, 2);
     EXPECT_FALSE(I->isInterleave(2));
     EXPECT_FALSE(sandboxir::ShuffleVectorInst::isInterleaveMask(
         I->getShuffleMask(), 2, 4));



More information about the llvm-commits mailing list