summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSanjay Patel <spatel@rotateright.com>2019-06-11 22:25:18 +0000
committerSanjay Patel <spatel@rotateright.com>2019-06-11 22:25:18 +0000
commit40e3bdf8764d4d6053305bd602832912da245cdf (patch)
treedf43473d4bde24babc7020232ac680b753a323b9
parent898d48117430eac158fb3b01741ac4a3c63b4a4e (diff)
downloadbcm5719-llvm-40e3bdf8764d4d6053305bd602832912da245cdf.tar.gz
bcm5719-llvm-40e3bdf8764d4d6053305bd602832912da245cdf.zip
[Analysis] add isSplatValue() for vectors in IR
We have the related getSplatValue() already in IR (see code just above the proposed addition). But sometimes we only need to know that the value is a splat rather than capture the splatted scalar value. Also, we have an isSplatValue() function already in SDAG. Motivation - recent bugs that would potentially benefit from improved splat analysis in IR: https://bugs.llvm.org/show_bug.cgi?id=37428 https://bugs.llvm.org/show_bug.cgi?id=42174 Differential Revision: https://reviews.llvm.org/D63138 llvm-svn: 363106
-rw-r--r--llvm/include/llvm/Analysis/VectorUtils.h6
-rw-r--r--llvm/lib/Analysis/VectorUtils.cpp39
-rw-r--r--llvm/unittests/Analysis/VectorUtilsTest.cpp190
3 files changed, 235 insertions, 0 deletions
diff --git a/llvm/include/llvm/Analysis/VectorUtils.h b/llvm/include/llvm/Analysis/VectorUtils.h
index f79bdc17502..ac358859437 100644
--- a/llvm/include/llvm/Analysis/VectorUtils.h
+++ b/llvm/include/llvm/Analysis/VectorUtils.h
@@ -78,6 +78,12 @@ Value *findScalarElement(Value *V, unsigned EltNo);
/// a sequence of instructions that broadcast a single value into a vector.
const Value *getSplatValue(const Value *V);
+/// Return true if the input value is known to be a vector with all identical
+/// elements (potentially including undefined elements).
+/// This may be more powerful than the related getSplatValue() because it is
+/// not limited by finding a scalar source value to a splatted vector.
+bool isSplatValue(const Value *V, unsigned Depth = 0);
+
/// Compute a map of integer instructions to their minimum legal type
/// size.
///
diff --git a/llvm/lib/Analysis/VectorUtils.cpp b/llvm/lib/Analysis/VectorUtils.cpp
index ea00f0a7dd3..8040af12d7c 100644
--- a/llvm/lib/Analysis/VectorUtils.cpp
+++ b/llvm/lib/Analysis/VectorUtils.cpp
@@ -321,6 +321,45 @@ const llvm::Value *llvm::getSplatValue(const Value *V) {
return nullptr;
}
+// This setting is based on its counterpart in value tracking, but it could be
+// adjusted if needed.
+const unsigned MaxDepth = 6;
+
+bool llvm::isSplatValue(const Value *V, unsigned Depth) {
+ assert(Depth <= MaxDepth && "Limit Search Depth");
+
+ if (isa<VectorType>(V->getType())) {
+ if (isa<UndefValue>(V))
+ return true;
+ // FIXME: Constant splat analysis does not allow undef elements.
+ if (auto *C = dyn_cast<Constant>(V))
+ return C->getSplatValue() != nullptr;
+ }
+
+ // FIXME: Constant splat analysis does not allow undef elements.
+ Constant *Mask;
+ if (match(V, m_ShuffleVector(m_Value(), m_Value(), m_Constant(Mask))))
+ return Mask->getSplatValue() != nullptr;
+
+ // The remaining tests are all recursive, so bail out if we hit the limit.
+ if (Depth++ == MaxDepth)
+ return false;
+
+ // If both operands of a binop are splats, the result is a splat.
+ Value *X, *Y, *Z;
+ if (match(V, m_BinOp(m_Value(X), m_Value(Y))))
+ return isSplatValue(X, Depth) && isSplatValue(Y, Depth);
+
+ // If all operands of a select are splats, the result is a splat.
+ if (match(V, m_Select(m_Value(X), m_Value(Y), m_Value(Z))))
+ return isSplatValue(X, Depth) && isSplatValue(Y, Depth) &&
+ isSplatValue(Z, Depth);
+
+ // TODO: Add support for unary ops (fneg), casts, intrinsics (overflow ops).
+
+ return false;
+}
+
MapVector<Instruction *, uint64_t>
llvm::computeMinimumValueSizes(ArrayRef<BasicBlock *> Blocks, DemandedBits &DB,
const TargetTransformInfo *TTI) {
diff --git a/llvm/unittests/Analysis/VectorUtilsTest.cpp b/llvm/unittests/Analysis/VectorUtilsTest.cpp
index 8ff6744bf78..a33fdb503bb 100644
--- a/llvm/unittests/Analysis/VectorUtilsTest.cpp
+++ b/llvm/unittests/Analysis/VectorUtilsTest.cpp
@@ -11,8 +11,10 @@
#include "llvm/AsmParser/Parser.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/InstIterator.h"
+#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
+#include "llvm/IR/NoFolder.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/SourceMgr.h"
#include "llvm/Support/KnownBits.h"
@@ -56,8 +58,196 @@ protected:
Instruction *A;
};
+struct BasicTest : public testing::Test {
+ LLVMContext Ctx;
+ std::unique_ptr<Module> M;
+ Function *F;
+ BasicBlock *BB;
+ IRBuilder<NoFolder> IRB;
+
+ BasicTest()
+ : M(new Module("VectorUtils", Ctx)),
+ F(Function::Create(
+ FunctionType::get(Type::getVoidTy(Ctx), /* IsVarArg */ false),
+ Function::ExternalLinkage, "f", M.get())),
+ BB(BasicBlock::Create(Ctx, "entry", F)), IRB(BB) {}
+};
+
+
} // namespace
+TEST_F(BasicTest, isSplat) {
+ Value *UndefVec = UndefValue::get(VectorType::get(IRB.getInt8Ty(), 4));
+ EXPECT_TRUE(isSplatValue(UndefVec));
+
+ Constant *UndefScalar = UndefValue::get(IRB.getInt8Ty());
+ EXPECT_FALSE(isSplatValue(UndefScalar));
+
+ Constant *ScalarC = IRB.getInt8(42);
+ EXPECT_FALSE(isSplatValue(ScalarC));
+
+ Constant *OtherScalarC = IRB.getInt8(-42);
+ Constant *NonSplatC = ConstantVector::get({ScalarC, OtherScalarC});
+ EXPECT_FALSE(isSplatValue(NonSplatC));
+
+ Value *SplatC = IRB.CreateVectorSplat(5, ScalarC);
+ EXPECT_TRUE(isSplatValue(SplatC));
+
+ // FIXME: Constant splat analysis does not allow undef elements.
+ Constant *SplatWithUndefC = ConstantVector::get({ScalarC, UndefScalar});
+ EXPECT_FALSE(isSplatValue(SplatWithUndefC));
+}
+
+TEST_F(VectorUtilsTest, isSplatValue_00) {
+ parseAssembly(
+ "define <2 x i8> @test(<2 x i8> %x) {\n"
+ " %A = shufflevector <2 x i8> %x, <2 x i8> undef, <2 x i32> zeroinitializer\n"
+ " ret <2 x i8> %A\n"
+ "}\n");
+ EXPECT_TRUE(isSplatValue(A));
+}
+
+TEST_F(VectorUtilsTest, isSplatValue_11) {
+ parseAssembly(
+ "define <2 x i8> @test(<2 x i8> %x) {\n"
+ " %A = shufflevector <2 x i8> %x, <2 x i8> undef, <2 x i32> <i32 1, i32 1>\n"
+ " ret <2 x i8> %A\n"
+ "}\n");
+ EXPECT_TRUE(isSplatValue(A));
+}
+
+TEST_F(VectorUtilsTest, isSplatValue_01) {
+ parseAssembly(
+ "define <2 x i8> @test(<2 x i8> %x) {\n"
+ " %A = shufflevector <2 x i8> %x, <2 x i8> undef, <2 x i32> <i32 0, i32 1>\n"
+ " ret <2 x i8> %A\n"
+ "}\n");
+ EXPECT_FALSE(isSplatValue(A));
+}
+
+// FIXME: Constant (mask) splat analysis does not allow undef elements.
+
+TEST_F(VectorUtilsTest, isSplatValue_0u) {
+ parseAssembly(
+ "define <2 x i8> @test(<2 x i8> %x) {\n"
+ " %A = shufflevector <2 x i8> %x, <2 x i8> undef, <2 x i32> <i32 0, i32 undef>\n"
+ " ret <2 x i8> %A\n"
+ "}\n");
+ EXPECT_FALSE(isSplatValue(A));
+}
+
+TEST_F(VectorUtilsTest, isSplatValue_Binop) {
+ parseAssembly(
+ "define <2 x i8> @test(<2 x i8> %x) {\n"
+ " %v0 = shufflevector <2 x i8> %x, <2 x i8> undef, <2 x i32> <i32 0, i32 0>\n"
+ " %v1 = shufflevector <2 x i8> %x, <2 x i8> undef, <2 x i32> <i32 1, i32 1>\n"
+ " %A = udiv <2 x i8> %v0, %v1\n"
+ " ret <2 x i8> %A\n"
+ "}\n");
+ EXPECT_TRUE(isSplatValue(A));
+}
+
+TEST_F(VectorUtilsTest, isSplatValue_Binop_ConstantOp0) {
+ parseAssembly(
+ "define <2 x i8> @test(<2 x i8> %x) {\n"
+ " %v1 = shufflevector <2 x i8> %x, <2 x i8> undef, <2 x i32> <i32 1, i32 1>\n"
+ " %A = ashr <2 x i8> <i8 42, i8 42>, %v1\n"
+ " ret <2 x i8> %A\n"
+ "}\n");
+ EXPECT_TRUE(isSplatValue(A));
+}
+
+TEST_F(VectorUtilsTest, isSplatValue_Binop_Not_Op0) {
+ parseAssembly(
+ "define <2 x i8> @test(<2 x i8> %x) {\n"
+ " %v0 = shufflevector <2 x i8> %x, <2 x i8> undef, <2 x i32> <i32 1, i32 0>\n"
+ " %v1 = shufflevector <2 x i8> %x, <2 x i8> undef, <2 x i32> <i32 1, i32 1>\n"
+ " %A = add <2 x i8> %v0, %v1\n"
+ " ret <2 x i8> %A\n"
+ "}\n");
+ EXPECT_FALSE(isSplatValue(A));
+}
+
+TEST_F(VectorUtilsTest, isSplatValue_Binop_Not_Op1) {
+ parseAssembly(
+ "define <2 x i8> @test(<2 x i8> %x) {\n"
+ " %v0 = shufflevector <2 x i8> %x, <2 x i8> undef, <2 x i32> <i32 1, i32 1>\n"
+ " %v1 = shufflevector <2 x i8> %x, <2 x i8> undef, <2 x i32> <i32 0, i32 1>\n"
+ " %A = shl <2 x i8> %v0, %v1\n"
+ " ret <2 x i8> %A\n"
+ "}\n");
+ EXPECT_FALSE(isSplatValue(A));
+}
+
+TEST_F(VectorUtilsTest, isSplatValue_Select) {
+ parseAssembly(
+ "define <2 x i8> @test(<2 x i1> %x, <2 x i8> %y, <2 x i8> %z) {\n"
+ " %v0 = shufflevector <2 x i1> %x, <2 x i1> undef, <2 x i32> <i32 1, i32 1>\n"
+ " %v1 = shufflevector <2 x i8> %y, <2 x i8> undef, <2 x i32> <i32 0, i32 0>\n"
+ " %v2 = shufflevector <2 x i8> %z, <2 x i8> undef, <2 x i32> <i32 1, i32 1>\n"
+ " %A = select <2 x i1> %v0, <2 x i8> %v1, <2 x i8> %v2\n"
+ " ret <2 x i8> %A\n"
+ "}\n");
+ EXPECT_TRUE(isSplatValue(A));
+}
+
+TEST_F(VectorUtilsTest, isSplatValue_Select_ConstantOp) {
+ parseAssembly(
+ "define <2 x i8> @test(<2 x i1> %x, <2 x i8> %y, <2 x i8> %z) {\n"
+ " %v0 = shufflevector <2 x i1> %x, <2 x i1> undef, <2 x i32> <i32 1, i32 1>\n"
+ " %v2 = shufflevector <2 x i8> %z, <2 x i8> undef, <2 x i32> <i32 1, i32 1>\n"
+ " %A = select <2 x i1> %v0, <2 x i8> <i8 42, i8 42>, <2 x i8> %v2\n"
+ " ret <2 x i8> %A\n"
+ "}\n");
+ EXPECT_TRUE(isSplatValue(A));
+}
+
+TEST_F(VectorUtilsTest, isSplatValue_Select_NotCond) {
+ parseAssembly(
+ "define <2 x i8> @test(<2 x i1> %x, <2 x i8> %y, <2 x i8> %z) {\n"
+ " %v1 = shufflevector <2 x i8> %y, <2 x i8> undef, <2 x i32> <i32 0, i32 0>\n"
+ " %v2 = shufflevector <2 x i8> %z, <2 x i8> undef, <2 x i32> <i32 1, i32 1>\n"
+ " %A = select <2 x i1> %x, <2 x i8> %v1, <2 x i8> %v2\n"
+ " ret <2 x i8> %A\n"
+ "}\n");
+ EXPECT_FALSE(isSplatValue(A));
+}
+
+TEST_F(VectorUtilsTest, isSplatValue_Select_NotOp1) {
+ parseAssembly(
+ "define <2 x i8> @test(<2 x i1> %x, <2 x i8> %y, <2 x i8> %z) {\n"
+ " %v0 = shufflevector <2 x i1> %x, <2 x i1> undef, <2 x i32> <i32 1, i32 1>\n"
+ " %v2 = shufflevector <2 x i8> %z, <2 x i8> undef, <2 x i32> <i32 1, i32 1>\n"
+ " %A = select <2 x i1> %v0, <2 x i8> %y, <2 x i8> %v2\n"
+ " ret <2 x i8> %A\n"
+ "}\n");
+ EXPECT_FALSE(isSplatValue(A));
+}
+
+TEST_F(VectorUtilsTest, isSplatValue_Select_NotOp2) {
+ parseAssembly(
+ "define <2 x i8> @test(<2 x i1> %x, <2 x i8> %y, <2 x i8> %z) {\n"
+ " %v0 = shufflevector <2 x i1> %x, <2 x i1> undef, <2 x i32> <i32 1, i32 1>\n"
+ " %v1 = shufflevector <2 x i8> %y, <2 x i8> undef, <2 x i32> <i32 0, i32 0>\n"
+ " %A = select <2 x i1> %v0, <2 x i8> %v1, <2 x i8> %z\n"
+ " ret <2 x i8> %A\n"
+ "}\n");
+ EXPECT_FALSE(isSplatValue(A));
+}
+
+TEST_F(VectorUtilsTest, isSplatValue_SelectBinop) {
+ parseAssembly(
+ "define <2 x i8> @test(<2 x i1> %x, <2 x i8> %y, <2 x i8> %z) {\n"
+ " %v0 = shufflevector <2 x i1> %x, <2 x i1> undef, <2 x i32> <i32 1, i32 1>\n"
+ " %v1 = shufflevector <2 x i8> %y, <2 x i8> undef, <2 x i32> <i32 0, i32 0>\n"
+ " %v2 = shufflevector <2 x i8> %z, <2 x i8> undef, <2 x i32> <i32 1, i32 1>\n"
+ " %bo = xor <2 x i8> %v1, %v2\n"
+ " %A = select <2 x i1> %v0, <2 x i8> %bo, <2 x i8> %v2\n"
+ " ret <2 x i8> %A\n"
+ "}\n");
+ EXPECT_TRUE(isSplatValue(A));
+}
+
TEST_F(VectorUtilsTest, getSplatValueElt0) {
parseAssembly(
"define <2 x i8> @test(i8 %x) {\n"
OpenPOWER on IntegriCloud