Skip to content

Commit

Permalink
Remove "mask" operand from shufflevector.
Browse files Browse the repository at this point in the history
Instead, represent the mask as out-of-line data in the instruction. This
should be more efficient in the places that currently use
getShuffleVector(), and paves the way for further changes to add new
shuffles for scalable vectors.

This doesn't change the syntax in textual IR. And I don't currently plan
to change the bitcode encoding in this patch, although we'll probably
need to do something once we extend shufflevector for scalable types.

I expect that once this is finished, we can then replace the raw "mask"
with something more appropriate for scalable vectors.  Not sure exactly
what this looks like at the moment, but there are a few different ways
we could handle it.  Maybe we could try to describe specific shuffles.
Or maybe we could define it in terms of a function to convert a fixed-length
array into an appropriate scalable vector, using a "step", or something
like that.

Differential Revision: https://reviews.llvm.org/D72467
  • Loading branch information
efriedma-quic committed Mar 31, 2020
1 parent c538c57 commit 1ee6ec2
Show file tree
Hide file tree
Showing 53 changed files with 672 additions and 383 deletions.
2 changes: 1 addition & 1 deletion clang/lib/CodeGen/CGExpr.cpp
Expand Up @@ -1675,7 +1675,7 @@ llvm::Value *CodeGenFunction::EmitLoadOfScalar(Address Addr, bool Volatile,

// Shuffle vector to get vec3.
V = Builder.CreateShuffleVector(V, llvm::UndefValue::get(vec4Ty),
{0, 1, 2}, "extractVec");
ArrayRef<int>{0, 1, 2}, "extractVec");
return EmitFromMemory(V, Ty);
}
}
Expand Down
12 changes: 11 additions & 1 deletion llvm/include/llvm/ADT/ArrayRef.h
Expand Up @@ -532,11 +532,21 @@ namespace llvm {
return LHS.equals(RHS);
}

template<typename T>
template <typename T>
inline bool operator==(SmallVectorImpl<T> &LHS, ArrayRef<T> RHS) {
return ArrayRef<T>(LHS).equals(RHS);
}

template <typename T>
inline bool operator!=(ArrayRef<T> LHS, ArrayRef<T> RHS) {
return !(LHS == RHS);
}

template <typename T>
inline bool operator!=(SmallVectorImpl<T> &LHS, ArrayRef<T> RHS) {
return !(LHS == RHS);
}

/// @}

template <typename T> hash_code hash_value(ArrayRef<T> S) {
Expand Down
7 changes: 4 additions & 3 deletions llvm/include/llvm/Analysis/ConstantFolding.h
Expand Up @@ -119,10 +119,11 @@ Constant *ConstantFoldInsertElementInstruction(Constant *Val,
Constant *ConstantFoldExtractElementInstruction(Constant *Val, Constant *Idx);

/// Attempt to constant fold a shufflevector instruction with the
/// specified operands and indices. The constant result is returned if
/// successful; if not, null is returned.
/// specified operands and mask. See class ShuffleVectorInst for a description
/// of the mask representation. The constant result is returned if successful;
/// if not, null is returned.
Constant *ConstantFoldShuffleVectorInstruction(Constant *V1, Constant *V2,
Constant *Mask);
ArrayRef<int> Mask);

/// ConstantFoldLoadFromConstPtr - Return the value that a load from C would
/// produce if it is constant and determinable. If this is not determinable,
Expand Down
3 changes: 2 additions & 1 deletion llvm/include/llvm/Analysis/InstructionSimplify.h
Expand Up @@ -230,7 +230,8 @@ Value *SimplifyCastInst(unsigned CastOpc, Value *Op, Type *Ty,
const SimplifyQuery &Q);

/// Given operands for a ShuffleVectorInst, fold the result or return null.
Value *SimplifyShuffleVectorInst(Value *Op0, Value *Op1, Constant *Mask,
/// See class ShuffleVectorInst for a description of the mask representation.
Value *SimplifyShuffleVectorInst(Value *Op0, Value *Op1, ArrayRef<int> Mask,
Type *RetTy, const SimplifyQuery &Q);

//=== Helper functions for higher up the class hierarchy.
Expand Down
2 changes: 1 addition & 1 deletion llvm/include/llvm/Analysis/TargetFolder.h
Expand Up @@ -259,7 +259,7 @@ class TargetFolder final : public IRBuilderFolder {
}

Constant *CreateShuffleVector(Constant *V1, Constant *V2,
Constant *Mask) const override {
ArrayRef<int> Mask) const override {
return Fold(ConstantExpr::getShuffleVector(V1, V2, Mask));
}

Expand Down
2 changes: 1 addition & 1 deletion llvm/include/llvm/IR/ConstantFolder.h
Expand Up @@ -265,7 +265,7 @@ class ConstantFolder final : public IRBuilderFolder {
}

Constant *CreateShuffleVector(Constant *V1, Constant *V2,
Constant *Mask) const override {
ArrayRef<int> Mask) const override {
return ConstantExpr::getShuffleVector(V1, V2, Mask);
}

Expand Down
13 changes: 12 additions & 1 deletion llvm/include/llvm/IR/Constants.h
Expand Up @@ -1206,7 +1206,8 @@ class ConstantExpr : public Constant {
Type *OnlyIfReducedTy = nullptr);
static Constant *getInsertElement(Constant *Vec, Constant *Elt, Constant *Idx,
Type *OnlyIfReducedTy = nullptr);
static Constant *getShuffleVector(Constant *V1, Constant *V2, Constant *Mask,
static Constant *getShuffleVector(Constant *V1, Constant *V2,
ArrayRef<int> Mask,
Type *OnlyIfReducedTy = nullptr);
static Constant *getExtractValue(Constant *Agg, ArrayRef<unsigned> Idxs,
Type *OnlyIfReducedTy = nullptr);
Expand All @@ -1225,6 +1226,16 @@ class ConstantExpr : public Constant {
/// expression and return the list of indices.
ArrayRef<unsigned> getIndices() const;

/// Assert that this is a shufflevector and return the mask. See class
/// ShuffleVectorInst for a description of the mask representation.
ArrayRef<int> getShuffleMask() const;

/// Assert that this is a shufflevector and return the mask.
///
/// TODO: This is a temporary hack until we update the bitcode format for
/// shufflevector.
Constant *getShuffleMaskForBitcode() const;

/// Return a string representation for an opcode.
const char *getOpcodeName() const;

Expand Down
24 changes: 16 additions & 8 deletions llvm/include/llvm/IR/IRBuilder.h
Expand Up @@ -2617,17 +2617,25 @@ class IRBuilderBase {

Value *CreateShuffleVector(Value *V1, Value *V2, Value *Mask,
const Twine &Name = "") {
if (auto *V1C = dyn_cast<Constant>(V1))
if (auto *V2C = dyn_cast<Constant>(V2))
if (auto *MC = dyn_cast<Constant>(Mask))
return Insert(Folder.CreateShuffleVector(V1C, V2C, MC), Name);
return Insert(new ShuffleVectorInst(V1, V2, Mask), Name);
SmallVector<int, 16> IntMask;
ShuffleVectorInst::getShuffleMask(cast<Constant>(Mask), IntMask);
return CreateShuffleVector(V1, V2, IntMask, Name);
}

Value *CreateShuffleVector(Value *V1, Value *V2, ArrayRef<uint32_t> IntMask,
Value *CreateShuffleVector(Value *V1, Value *V2, ArrayRef<uint32_t> Mask,
const Twine &Name = "") {
Value *Mask = ConstantDataVector::get(Context, IntMask);
return CreateShuffleVector(V1, V2, Mask, Name);
SmallVector<int, 16> IntMask;
IntMask.assign(Mask.begin(), Mask.end());
return CreateShuffleVector(V1, V2, IntMask, Name);
}

/// See class ShuffleVectorInst for a description of the mask representation.
Value *CreateShuffleVector(Value *V1, Value *V2, ArrayRef<int> Mask,
const Twine &Name = "") {
if (auto *V1C = dyn_cast<Constant>(V1))
if (auto *V2C = dyn_cast<Constant>(V2))
return Insert(Folder.CreateShuffleVector(V1C, V2C, Mask), Name);
return Insert(new ShuffleVectorInst(V1, V2, Mask), Name);
}

Value *CreateExtractValue(Value *Agg,
Expand Down
2 changes: 1 addition & 1 deletion llvm/include/llvm/IR/IRBuilderFolder.h
Expand Up @@ -129,7 +129,7 @@ class IRBuilderFolder {
virtual Value *CreateInsertElement(Constant *Vec, Constant *NewElt,
Constant *Idx) const = 0;
virtual Value *CreateShuffleVector(Constant *V1, Constant *V2,
Constant *Mask) const = 0;
ArrayRef<int> Mask) const = 0;
virtual Value *CreateExtractValue(Constant *Agg,
ArrayRef<unsigned> IdxList) const = 0;
virtual Value *CreateInsertValue(Constant *Agg, Constant *Val,
Expand Down
86 changes: 49 additions & 37 deletions llvm/include/llvm/IR/Instructions.h
Expand Up @@ -1988,10 +1988,22 @@ DEFINE_TRANSPARENT_OPERAND_ACCESSORS(InsertElementInst, Value)
// ShuffleVectorInst Class
//===----------------------------------------------------------------------===//

constexpr int UndefMaskElem = -1;

/// This instruction constructs a fixed permutation of two
/// input vectors.
///
/// For each element of the result vector, the shuffle mask selects an element
/// from one of the input vectors to copy to the result. Non-negative elements
/// in the mask represent an index into the concatenated pair of input vectors.
/// UndefMaskElem (-1) specifies that the result element is undefined.
///
/// For scalable vectors, all the elements of the mask must be 0 or -1. This
/// requirement may be relaxed in the future.
class ShuffleVectorInst : public Instruction {
SmallVector<int, 4> ShuffleMask;
Constant *ShuffleMaskForBitcode;

protected:
// Note: Instruction needs to be a friend here to call cloneImpl.
friend class Instruction;
Expand All @@ -2004,20 +2016,24 @@ class ShuffleVectorInst : public Instruction {
Instruction *InsertBefor = nullptr);
ShuffleVectorInst(Value *V1, Value *V2, Value *Mask,
const Twine &NameStr, BasicBlock *InsertAtEnd);
ShuffleVectorInst(Value *V1, Value *V2, ArrayRef<int> Mask,
const Twine &NameStr = "",
Instruction *InsertBefor = nullptr);
ShuffleVectorInst(Value *V1, Value *V2, ArrayRef<int> Mask,
const Twine &NameStr, BasicBlock *InsertAtEnd);

// allocate space for exactly three operands
void *operator new(size_t s) {
return User::operator new(s, 3);
}
void *operator new(size_t s) { return User::operator new(s, 2); }

/// Swap the first 2 operands and adjust the mask to preserve the semantics
/// Swap the operands and adjust the mask to preserve the semantics
/// of the instruction.
void 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);
static bool isValidOperands(const Value *V1, const Value *V2,
ArrayRef<int> Mask);

/// Overload to return most specific vector type.
///
Expand All @@ -2028,44 +2044,41 @@ class ShuffleVectorInst : public Instruction {
/// Transparently provide more efficient getOperand methods.
DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value);

Constant *getMask() const {
return cast<Constant>(getOperand(2));
}

/// Return the shuffle mask value for the specified element of the mask.
/// Return -1 if the element is undef.
static int getMaskValue(const Constant *Mask, unsigned Elt);

/// Return the shuffle mask value of this instruction for the given element
/// index. Return -1 if the element is undef.
int getMaskValue(unsigned Elt) const {
return getMaskValue(getMask(), Elt);
}
/// index. Return UndefMaskElem if the element is undef.
int getMaskValue(unsigned Elt) const { return ShuffleMask[Elt]; }

/// Convert the input shuffle mask operand to a vector of integers. Undefined
/// elements of the mask are returned as -1.
/// elements of the mask are returned as UndefMaskElem.
static void getShuffleMask(const Constant *Mask,
SmallVectorImpl<int> &Result);

/// Return the mask for this instruction as a vector of integers. Undefined
/// elements of the mask are returned as -1.
/// elements of the mask are returned as UndefMaskElem.
void getShuffleMask(SmallVectorImpl<int> &Result) const {
return getShuffleMask(getMask(), Result);
Result.assign(ShuffleMask.begin(), ShuffleMask.end());
}

SmallVector<int, 16> getShuffleMask() const {
SmallVector<int, 16> Mask;
getShuffleMask(Mask);
return Mask;
}
/// Return the mask for this instruction, for use in bitcode.
///
/// TODO: This is temporary until we decide a new bitcode encoding for
/// shufflevector.
Constant *getShuffleMaskForBitcode() const { return ShuffleMaskForBitcode; }

static Constant *convertShuffleMaskForBitcode(ArrayRef<int> Mask,
Type *ResultTy);

void setShuffleMask(ArrayRef<int> Mask);

ArrayRef<int> getShuffleMask() const { return ShuffleMask; }

/// 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 {
unsigned NumSourceElts = Op<0>()->getType()->getVectorNumElements();
unsigned NumMaskElts = getMask()->getType()->getVectorNumElements();
unsigned NumMaskElts = ShuffleMask.size();
return NumSourceElts != NumMaskElts;
}

Expand All @@ -2074,7 +2087,7 @@ class ShuffleVectorInst : public Instruction {
/// Example: shufflevector <2 x n> A, <2 x n> B, <1,2,3>
bool increasesLength() const {
unsigned NumSourceElts = Op<0>()->getType()->getVectorNumElements();
unsigned NumMaskElts = getMask()->getType()->getVectorNumElements();
unsigned NumMaskElts = ShuffleMask.size();
return NumSourceElts < NumMaskElts;
}

Expand All @@ -2095,7 +2108,7 @@ class ShuffleVectorInst : public Instruction {
/// Example: shufflevector <4 x n> A, <4 x n> B, <3,0,undef,3>
/// TODO: Optionally allow length-changing shuffles.
bool isSingleSource() const {
return !changesLength() && isSingleSourceMask(getMask());
return !changesLength() && isSingleSourceMask(ShuffleMask);
}

/// Return true if this shuffle mask chooses elements from exactly one source
Expand All @@ -2116,7 +2129,7 @@ class ShuffleVectorInst : public Instruction {
/// from its input vectors.
/// Example: shufflevector <4 x n> A, <4 x n> B, <4,undef,6,undef>
bool isIdentity() const {
return !changesLength() && isIdentityMask(getShuffleMask());
return !changesLength() && isIdentityMask(ShuffleMask);
}

/// Return true if this shuffle lengthens exactly one source vector with
Expand Down Expand Up @@ -2157,7 +2170,7 @@ class ShuffleVectorInst : public Instruction {
/// In that case, the shuffle is better classified as an identity shuffle.
/// TODO: Optionally allow length-changing shuffles.
bool isSelect() const {
return !changesLength() && isSelectMask(getMask());
return !changesLength() && isSelectMask(ShuffleMask);
}

/// Return true if this shuffle mask swaps the order of elements from exactly
Expand All @@ -2177,7 +2190,7 @@ class ShuffleVectorInst : public Instruction {
/// Example: shufflevector <4 x n> A, <4 x n> B, <3,undef,1,undef>
/// TODO: Optionally allow length-changing shuffles.
bool isReverse() const {
return !changesLength() && isReverseMask(getMask());
return !changesLength() && isReverseMask(ShuffleMask);
}

/// Return true if this shuffle mask chooses all elements with the same value
Expand All @@ -2199,7 +2212,7 @@ class ShuffleVectorInst : public Instruction {
/// TODO: Optionally allow length-changing shuffles.
/// TODO: Optionally allow splats from other elements.
bool isZeroEltSplat() const {
return !changesLength() && isZeroEltSplatMask(getMask());
return !changesLength() && isZeroEltSplatMask(ShuffleMask);
}

/// Return true if this shuffle mask is a transpose mask.
Expand Down Expand Up @@ -2248,7 +2261,7 @@ class ShuffleVectorInst : public Instruction {
/// exact specification.
/// Example: shufflevector <4 x n> A, <4 x n> B, <0,4,2,6>
bool isTranspose() const {
return !changesLength() && isTransposeMask(getMask());
return !changesLength() && isTransposeMask(ShuffleMask);
}

/// Return true if this shuffle mask is an extract subvector mask.
Expand All @@ -2267,7 +2280,7 @@ class ShuffleVectorInst : public Instruction {
/// Return true if this shuffle mask is an extract subvector mask.
bool isExtractSubvectorMask(int &Index) const {
int NumSrcElts = Op<0>()->getType()->getVectorNumElements();
return isExtractSubvectorMask(getMask(), NumSrcElts, Index);
return isExtractSubvectorMask(ShuffleMask, NumSrcElts, Index);
}

/// Change values in a shuffle permute mask assuming the two vector operands
Expand All @@ -2293,9 +2306,8 @@ class ShuffleVectorInst : public Instruction {
};

template <>
struct OperandTraits<ShuffleVectorInst> :
public FixedNumOperandTraits<ShuffleVectorInst, 3> {
};
struct OperandTraits<ShuffleVectorInst>
: public FixedNumOperandTraits<ShuffleVectorInst, 2> {};

DEFINE_TRANSPARENT_OPERAND_ACCESSORS(ShuffleVectorInst, Value)

Expand Down
2 changes: 1 addition & 1 deletion llvm/include/llvm/IR/NoFolder.h
Expand Up @@ -300,7 +300,7 @@ class NoFolder final : public IRBuilderFolder {
}

Instruction *CreateShuffleVector(Constant *V1, Constant *V2,
Constant *Mask) const override {
ArrayRef<int> Mask) const override {
return new ShuffleVectorInst(V1, V2, Mask);
}

Expand Down

0 comments on commit 1ee6ec2

Please sign in to comment.