[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