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) {
#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"
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"