794 lines
31 KiB
C++
794 lines
31 KiB
C++
//===- VecUtilsTest.cpp --------------------------------------------------===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "llvm/Transforms/Vectorize/SandboxVectorizer/VecUtils.h"
|
|
#include "llvm/Analysis/AliasAnalysis.h"
|
|
#include "llvm/Analysis/AssumptionCache.h"
|
|
#include "llvm/Analysis/BasicAliasAnalysis.h"
|
|
#include "llvm/Analysis/LoopInfo.h"
|
|
#include "llvm/Analysis/ScalarEvolution.h"
|
|
#include "llvm/Analysis/TargetLibraryInfo.h"
|
|
#include "llvm/AsmParser/Parser.h"
|
|
#include "llvm/IR/DataLayout.h"
|
|
#include "llvm/IR/Dominators.h"
|
|
#include "llvm/SandboxIR/Context.h"
|
|
#include "llvm/SandboxIR/Function.h"
|
|
#include "llvm/SandboxIR/Module.h"
|
|
#include "llvm/SandboxIR/Type.h"
|
|
#include "llvm/Support/SourceMgr.h"
|
|
#include "gmock/gmock.h"
|
|
#include "gtest/gtest.h"
|
|
|
|
using namespace llvm;
|
|
|
|
struct VecUtilsTest : public testing::Test {
|
|
LLVMContext C;
|
|
std::unique_ptr<Module> M;
|
|
std::unique_ptr<AssumptionCache> AC;
|
|
std::unique_ptr<TargetLibraryInfoImpl> TLII;
|
|
std::unique_ptr<TargetLibraryInfo> TLI;
|
|
std::unique_ptr<DominatorTree> DT;
|
|
std::unique_ptr<LoopInfo> LI;
|
|
std::unique_ptr<ScalarEvolution> SE;
|
|
void parseIR(const char *IR) {
|
|
SMDiagnostic Err;
|
|
M = parseAssemblyString(IR, Err, C);
|
|
if (!M) {
|
|
Err.print("VecUtilsTest", errs());
|
|
return;
|
|
}
|
|
|
|
TLII = std::make_unique<TargetLibraryInfoImpl>(M->getTargetTriple());
|
|
TLI = std::make_unique<TargetLibraryInfo>(*TLII);
|
|
}
|
|
|
|
ScalarEvolution &getSE(llvm::Function &LLVMF) {
|
|
AC = std::make_unique<AssumptionCache>(LLVMF);
|
|
DT = std::make_unique<DominatorTree>(LLVMF);
|
|
LI = std::make_unique<LoopInfo>(*DT);
|
|
SE = std::make_unique<ScalarEvolution>(LLVMF, *TLI, *AC, *DT, *LI);
|
|
return *SE;
|
|
}
|
|
};
|
|
|
|
sandboxir::BasicBlock &getBasicBlockByName(sandboxir::Function &F,
|
|
StringRef Name) {
|
|
for (sandboxir::BasicBlock &BB : F)
|
|
if (BB.getName() == Name)
|
|
return BB;
|
|
llvm_unreachable("Expected to find basic block!");
|
|
}
|
|
|
|
TEST_F(VecUtilsTest, GetNumElements) {
|
|
sandboxir::Context Ctx(C);
|
|
auto *ElemTy = sandboxir::Type::getInt32Ty(Ctx);
|
|
EXPECT_EQ(sandboxir::VecUtils::getNumElements(ElemTy), 1);
|
|
auto *VTy = sandboxir::FixedVectorType::get(ElemTy, 2);
|
|
EXPECT_EQ(sandboxir::VecUtils::getNumElements(VTy), 2);
|
|
auto *VTy1 = sandboxir::FixedVectorType::get(ElemTy, 1);
|
|
EXPECT_EQ(sandboxir::VecUtils::getNumElements(VTy1), 1);
|
|
}
|
|
|
|
TEST_F(VecUtilsTest, GetElementType) {
|
|
sandboxir::Context Ctx(C);
|
|
auto *ElemTy = sandboxir::Type::getInt32Ty(Ctx);
|
|
EXPECT_EQ(sandboxir::VecUtils::getElementType(ElemTy), ElemTy);
|
|
auto *VTy = sandboxir::FixedVectorType::get(ElemTy, 2);
|
|
EXPECT_EQ(sandboxir::VecUtils::getElementType(VTy), ElemTy);
|
|
}
|
|
|
|
TEST_F(VecUtilsTest, AreConsecutive_gep_float) {
|
|
parseIR(R"IR(
|
|
define void @foo(ptr %ptr) {
|
|
%gep0 = getelementptr inbounds float, ptr %ptr, i64 0
|
|
%gep1 = getelementptr inbounds float, ptr %ptr, i64 1
|
|
%gep2 = getelementptr inbounds float, ptr %ptr, i64 2
|
|
%gep3 = getelementptr inbounds float, ptr %ptr, i64 3
|
|
|
|
%ld0 = load float, ptr %gep0
|
|
%ld1 = load float, ptr %gep1
|
|
%ld2 = load float, ptr %gep2
|
|
%ld3 = load float, ptr %gep3
|
|
|
|
%v2ld0 = load <2 x float>, ptr %gep0
|
|
%v2ld1 = load <2 x float>, ptr %gep1
|
|
%v2ld2 = load <2 x float>, ptr %gep2
|
|
%v2ld3 = load <2 x float>, ptr %gep3
|
|
|
|
%v3ld0 = load <3 x float>, ptr %gep0
|
|
%v3ld1 = load <3 x float>, ptr %gep1
|
|
%v3ld2 = load <3 x float>, ptr %gep2
|
|
%v3ld3 = load <3 x float>, ptr %gep3
|
|
ret void
|
|
}
|
|
)IR");
|
|
Function &LLVMF = *M->getFunction("foo");
|
|
const DataLayout &DL = M->getDataLayout();
|
|
auto &SE = getSE(LLVMF);
|
|
|
|
sandboxir::Context Ctx(C);
|
|
auto &F = *Ctx.createFunction(&LLVMF);
|
|
|
|
auto &BB = *F.begin();
|
|
auto It = std::next(BB.begin(), 4);
|
|
auto *L0 = cast<sandboxir::LoadInst>(&*It++);
|
|
auto *L1 = cast<sandboxir::LoadInst>(&*It++);
|
|
auto *L2 = cast<sandboxir::LoadInst>(&*It++);
|
|
auto *L3 = cast<sandboxir::LoadInst>(&*It++);
|
|
|
|
auto *V2L0 = cast<sandboxir::LoadInst>(&*It++);
|
|
auto *V2L1 = cast<sandboxir::LoadInst>(&*It++);
|
|
auto *V2L2 = cast<sandboxir::LoadInst>(&*It++);
|
|
auto *V2L3 = cast<sandboxir::LoadInst>(&*It++);
|
|
|
|
auto *V3L0 = cast<sandboxir::LoadInst>(&*It++);
|
|
auto *V3L1 = cast<sandboxir::LoadInst>(&*It++);
|
|
auto *V3L2 = cast<sandboxir::LoadInst>(&*It++);
|
|
auto *V3L3 = cast<sandboxir::LoadInst>(&*It++);
|
|
|
|
// Scalar
|
|
EXPECT_TRUE(sandboxir::VecUtils::areConsecutive(L0, L1, SE, DL));
|
|
EXPECT_TRUE(sandboxir::VecUtils::areConsecutive(L1, L2, SE, DL));
|
|
EXPECT_TRUE(sandboxir::VecUtils::areConsecutive(L2, L3, SE, DL));
|
|
EXPECT_FALSE(sandboxir::VecUtils::areConsecutive(L1, L0, SE, DL));
|
|
EXPECT_FALSE(sandboxir::VecUtils::areConsecutive(L2, L1, SE, DL));
|
|
EXPECT_FALSE(sandboxir::VecUtils::areConsecutive(L3, L2, SE, DL));
|
|
EXPECT_FALSE(sandboxir::VecUtils::areConsecutive(L0, L2, SE, DL));
|
|
EXPECT_FALSE(sandboxir::VecUtils::areConsecutive(L0, L3, SE, DL));
|
|
EXPECT_FALSE(sandboxir::VecUtils::areConsecutive(L1, L3, SE, DL));
|
|
EXPECT_FALSE(sandboxir::VecUtils::areConsecutive(L2, L0, SE, DL));
|
|
EXPECT_FALSE(sandboxir::VecUtils::areConsecutive(L3, L1, SE, DL));
|
|
|
|
// Check 2-wide loads
|
|
EXPECT_TRUE(sandboxir::VecUtils::areConsecutive(V2L0, V2L2, SE, DL));
|
|
EXPECT_TRUE(sandboxir::VecUtils::areConsecutive(V2L1, V2L3, SE, DL));
|
|
EXPECT_FALSE(sandboxir::VecUtils::areConsecutive(V2L0, V2L1, SE, DL));
|
|
EXPECT_FALSE(sandboxir::VecUtils::areConsecutive(V2L1, V2L2, SE, DL));
|
|
EXPECT_FALSE(sandboxir::VecUtils::areConsecutive(V2L2, V2L3, SE, DL));
|
|
|
|
EXPECT_FALSE(sandboxir::VecUtils::areConsecutive(V2L3, V2L1, SE, DL));
|
|
EXPECT_FALSE(sandboxir::VecUtils::areConsecutive(V2L3, V2L1, SE, DL));
|
|
EXPECT_FALSE(sandboxir::VecUtils::areConsecutive(V2L3, V2L1, SE, DL));
|
|
EXPECT_FALSE(sandboxir::VecUtils::areConsecutive(V2L3, V2L1, SE, DL));
|
|
|
|
// Check 3-wide loads
|
|
EXPECT_TRUE(sandboxir::VecUtils::areConsecutive(V3L0, V3L3, SE, DL));
|
|
EXPECT_FALSE(sandboxir::VecUtils::areConsecutive(V3L0, V3L1, SE, DL));
|
|
EXPECT_FALSE(sandboxir::VecUtils::areConsecutive(V3L1, V3L2, SE, DL));
|
|
EXPECT_FALSE(sandboxir::VecUtils::areConsecutive(V3L2, V3L3, SE, DL));
|
|
EXPECT_FALSE(sandboxir::VecUtils::areConsecutive(V3L1, V3L0, SE, DL));
|
|
EXPECT_FALSE(sandboxir::VecUtils::areConsecutive(V3L2, V3L1, SE, DL));
|
|
EXPECT_FALSE(sandboxir::VecUtils::areConsecutive(V3L3, V3L2, SE, DL));
|
|
|
|
// Check mixes of vectors and scalar
|
|
EXPECT_TRUE(sandboxir::VecUtils::areConsecutive(L0, V2L1, SE, DL));
|
|
EXPECT_TRUE(sandboxir::VecUtils::areConsecutive(L1, V2L2, SE, DL));
|
|
EXPECT_TRUE(sandboxir::VecUtils::areConsecutive(V2L0, L2, SE, DL));
|
|
EXPECT_TRUE(sandboxir::VecUtils::areConsecutive(V3L0, L3, SE, DL));
|
|
EXPECT_TRUE(sandboxir::VecUtils::areConsecutive(V2L0, V3L2, SE, DL));
|
|
|
|
EXPECT_FALSE(sandboxir::VecUtils::areConsecutive(L0, V2L2, SE, DL));
|
|
EXPECT_FALSE(sandboxir::VecUtils::areConsecutive(L0, V3L2, SE, DL));
|
|
EXPECT_FALSE(sandboxir::VecUtils::areConsecutive(L0, V2L3, SE, DL));
|
|
EXPECT_FALSE(sandboxir::VecUtils::areConsecutive(V2L0, V3L1, SE, DL));
|
|
EXPECT_FALSE(sandboxir::VecUtils::areConsecutive(V3L0, L1, SE, DL));
|
|
EXPECT_FALSE(sandboxir::VecUtils::areConsecutive(V3L0, L2, SE, DL));
|
|
EXPECT_FALSE(sandboxir::VecUtils::areConsecutive(V3L0, V2L1, SE, DL));
|
|
EXPECT_FALSE(sandboxir::VecUtils::areConsecutive(V3L0, V2L2, SE, DL));
|
|
EXPECT_FALSE(sandboxir::VecUtils::areConsecutive(V2L1, L0, SE, DL));
|
|
}
|
|
|
|
TEST_F(VecUtilsTest, AreConsecutive_gep_i8) {
|
|
parseIR(R"IR(
|
|
define void @foo(ptr %ptr) {
|
|
%gep0 = getelementptr inbounds i8, ptr %ptr, i64 0
|
|
%gep1 = getelementptr inbounds i8, ptr %ptr, i64 4
|
|
%gep2 = getelementptr inbounds i8, ptr %ptr, i64 8
|
|
%gep3 = getelementptr inbounds i8, ptr %ptr, i64 12
|
|
|
|
%ld0 = load float, ptr %gep0
|
|
%ld1 = load float, ptr %gep1
|
|
%ld2 = load float, ptr %gep2
|
|
%ld3 = load float, ptr %gep3
|
|
|
|
%v2ld0 = load <2 x float>, ptr %gep0
|
|
%v2ld1 = load <2 x float>, ptr %gep1
|
|
%v2ld2 = load <2 x float>, ptr %gep2
|
|
%v2ld3 = load <2 x float>, ptr %gep3
|
|
|
|
%v3ld0 = load <3 x float>, ptr %gep0
|
|
%v3ld1 = load <3 x float>, ptr %gep1
|
|
%v3ld2 = load <3 x float>, ptr %gep2
|
|
%v3ld3 = load <3 x float>, ptr %gep3
|
|
ret void
|
|
}
|
|
)IR");
|
|
Function &LLVMF = *M->getFunction("foo");
|
|
const DataLayout &DL = M->getDataLayout();
|
|
auto &SE = getSE(LLVMF);
|
|
|
|
sandboxir::Context Ctx(C);
|
|
auto &F = *Ctx.createFunction(&LLVMF);
|
|
auto &BB = *F.begin();
|
|
auto It = std::next(BB.begin(), 4);
|
|
auto *L0 = cast<sandboxir::LoadInst>(&*It++);
|
|
auto *L1 = cast<sandboxir::LoadInst>(&*It++);
|
|
auto *L2 = cast<sandboxir::LoadInst>(&*It++);
|
|
auto *L3 = cast<sandboxir::LoadInst>(&*It++);
|
|
|
|
auto *V2L0 = cast<sandboxir::LoadInst>(&*It++);
|
|
auto *V2L1 = cast<sandboxir::LoadInst>(&*It++);
|
|
auto *V2L2 = cast<sandboxir::LoadInst>(&*It++);
|
|
auto *V2L3 = cast<sandboxir::LoadInst>(&*It++);
|
|
|
|
auto *V3L0 = cast<sandboxir::LoadInst>(&*It++);
|
|
auto *V3L1 = cast<sandboxir::LoadInst>(&*It++);
|
|
auto *V3L2 = cast<sandboxir::LoadInst>(&*It++);
|
|
auto *V3L3 = cast<sandboxir::LoadInst>(&*It++);
|
|
|
|
// Scalar
|
|
EXPECT_TRUE(sandboxir::VecUtils::areConsecutive(L0, L1, SE, DL));
|
|
EXPECT_TRUE(sandboxir::VecUtils::areConsecutive(L1, L2, SE, DL));
|
|
EXPECT_TRUE(sandboxir::VecUtils::areConsecutive(L2, L3, SE, DL));
|
|
EXPECT_FALSE(sandboxir::VecUtils::areConsecutive(L1, L0, SE, DL));
|
|
EXPECT_FALSE(sandboxir::VecUtils::areConsecutive(L2, L1, SE, DL));
|
|
EXPECT_FALSE(sandboxir::VecUtils::areConsecutive(L3, L2, SE, DL));
|
|
EXPECT_FALSE(sandboxir::VecUtils::areConsecutive(L0, L2, SE, DL));
|
|
EXPECT_FALSE(sandboxir::VecUtils::areConsecutive(L0, L3, SE, DL));
|
|
EXPECT_FALSE(sandboxir::VecUtils::areConsecutive(L1, L3, SE, DL));
|
|
EXPECT_FALSE(sandboxir::VecUtils::areConsecutive(L2, L0, SE, DL));
|
|
EXPECT_FALSE(sandboxir::VecUtils::areConsecutive(L3, L1, SE, DL));
|
|
|
|
// Check 2-wide loads
|
|
EXPECT_TRUE(sandboxir::VecUtils::areConsecutive(V2L0, V2L2, SE, DL));
|
|
EXPECT_TRUE(sandboxir::VecUtils::areConsecutive(V2L1, V2L3, SE, DL));
|
|
EXPECT_FALSE(sandboxir::VecUtils::areConsecutive(V2L0, V2L1, SE, DL));
|
|
EXPECT_FALSE(sandboxir::VecUtils::areConsecutive(V2L1, V2L2, SE, DL));
|
|
EXPECT_FALSE(sandboxir::VecUtils::areConsecutive(V2L2, V2L3, SE, DL));
|
|
|
|
EXPECT_FALSE(sandboxir::VecUtils::areConsecutive(V2L3, V2L1, SE, DL));
|
|
EXPECT_FALSE(sandboxir::VecUtils::areConsecutive(V2L3, V2L1, SE, DL));
|
|
EXPECT_FALSE(sandboxir::VecUtils::areConsecutive(V2L3, V2L1, SE, DL));
|
|
EXPECT_FALSE(sandboxir::VecUtils::areConsecutive(V2L3, V2L1, SE, DL));
|
|
|
|
// Check 3-wide loads
|
|
EXPECT_TRUE(sandboxir::VecUtils::areConsecutive(V3L0, V3L3, SE, DL));
|
|
EXPECT_FALSE(sandboxir::VecUtils::areConsecutive(V3L0, V3L1, SE, DL));
|
|
EXPECT_FALSE(sandboxir::VecUtils::areConsecutive(V3L1, V3L2, SE, DL));
|
|
EXPECT_FALSE(sandboxir::VecUtils::areConsecutive(V3L2, V3L3, SE, DL));
|
|
EXPECT_FALSE(sandboxir::VecUtils::areConsecutive(V3L1, V3L0, SE, DL));
|
|
EXPECT_FALSE(sandboxir::VecUtils::areConsecutive(V3L2, V3L1, SE, DL));
|
|
EXPECT_FALSE(sandboxir::VecUtils::areConsecutive(V3L3, V3L2, SE, DL));
|
|
|
|
// Check mixes of vectors and scalar
|
|
EXPECT_TRUE(sandboxir::VecUtils::areConsecutive(L0, V2L1, SE, DL));
|
|
EXPECT_TRUE(sandboxir::VecUtils::areConsecutive(L1, V2L2, SE, DL));
|
|
EXPECT_TRUE(sandboxir::VecUtils::areConsecutive(V2L0, L2, SE, DL));
|
|
EXPECT_TRUE(sandboxir::VecUtils::areConsecutive(V3L0, L3, SE, DL));
|
|
EXPECT_TRUE(sandboxir::VecUtils::areConsecutive(V2L0, V3L2, SE, DL));
|
|
|
|
EXPECT_FALSE(sandboxir::VecUtils::areConsecutive(L0, V2L2, SE, DL));
|
|
EXPECT_FALSE(sandboxir::VecUtils::areConsecutive(L0, V3L2, SE, DL));
|
|
EXPECT_FALSE(sandboxir::VecUtils::areConsecutive(L0, V2L3, SE, DL));
|
|
EXPECT_FALSE(sandboxir::VecUtils::areConsecutive(V2L0, V3L1, SE, DL));
|
|
EXPECT_FALSE(sandboxir::VecUtils::areConsecutive(V3L0, L1, SE, DL));
|
|
EXPECT_FALSE(sandboxir::VecUtils::areConsecutive(V3L0, L2, SE, DL));
|
|
EXPECT_FALSE(sandboxir::VecUtils::areConsecutive(V3L0, V2L1, SE, DL));
|
|
EXPECT_FALSE(sandboxir::VecUtils::areConsecutive(V3L0, V2L2, SE, DL));
|
|
EXPECT_FALSE(sandboxir::VecUtils::areConsecutive(V2L1, L0, SE, DL));
|
|
}
|
|
|
|
TEST_F(VecUtilsTest, AreConsecutive_gep_i1) {
|
|
parseIR(R"IR(
|
|
define void @foo(ptr %ptr) {
|
|
%gep0 = getelementptr inbounds i1, ptr %ptr, i64 0
|
|
%gep1 = getelementptr inbounds i2, ptr %ptr, i64 4
|
|
%gep2 = getelementptr inbounds i3, ptr %ptr, i64 8
|
|
%gep3 = getelementptr inbounds i7, ptr %ptr, i64 12
|
|
|
|
%ld0 = load float, ptr %gep0
|
|
%ld1 = load float, ptr %gep1
|
|
%ld2 = load float, ptr %gep2
|
|
%ld3 = load float, ptr %gep3
|
|
|
|
%v2ld0 = load <2 x float>, ptr %gep0
|
|
%v2ld1 = load <2 x float>, ptr %gep1
|
|
%v2ld2 = load <2 x float>, ptr %gep2
|
|
%v2ld3 = load <2 x float>, ptr %gep3
|
|
|
|
%v3ld0 = load <3 x float>, ptr %gep0
|
|
%v3ld1 = load <3 x float>, ptr %gep1
|
|
%v3ld2 = load <3 x float>, ptr %gep2
|
|
%v3ld3 = load <3 x float>, ptr %gep3
|
|
ret void
|
|
}
|
|
)IR");
|
|
Function &LLVMF = *M->getFunction("foo");
|
|
const DataLayout &DL = M->getDataLayout();
|
|
auto &SE = getSE(LLVMF);
|
|
|
|
sandboxir::Context Ctx(C);
|
|
auto &F = *Ctx.createFunction(&LLVMF);
|
|
auto &BB = *F.begin();
|
|
auto It = std::next(BB.begin(), 4);
|
|
auto *L0 = cast<sandboxir::LoadInst>(&*It++);
|
|
auto *L1 = cast<sandboxir::LoadInst>(&*It++);
|
|
auto *L2 = cast<sandboxir::LoadInst>(&*It++);
|
|
auto *L3 = cast<sandboxir::LoadInst>(&*It++);
|
|
|
|
auto *V2L0 = cast<sandboxir::LoadInst>(&*It++);
|
|
auto *V2L1 = cast<sandboxir::LoadInst>(&*It++);
|
|
auto *V2L2 = cast<sandboxir::LoadInst>(&*It++);
|
|
auto *V2L3 = cast<sandboxir::LoadInst>(&*It++);
|
|
|
|
auto *V3L0 = cast<sandboxir::LoadInst>(&*It++);
|
|
auto *V3L1 = cast<sandboxir::LoadInst>(&*It++);
|
|
auto *V3L2 = cast<sandboxir::LoadInst>(&*It++);
|
|
auto *V3L3 = cast<sandboxir::LoadInst>(&*It++);
|
|
|
|
// Scalar
|
|
EXPECT_TRUE(sandboxir::VecUtils::areConsecutive(L0, L1, SE, DL));
|
|
EXPECT_TRUE(sandboxir::VecUtils::areConsecutive(L1, L2, SE, DL));
|
|
EXPECT_TRUE(sandboxir::VecUtils::areConsecutive(L2, L3, SE, DL));
|
|
EXPECT_FALSE(sandboxir::VecUtils::areConsecutive(L1, L0, SE, DL));
|
|
EXPECT_FALSE(sandboxir::VecUtils::areConsecutive(L2, L1, SE, DL));
|
|
EXPECT_FALSE(sandboxir::VecUtils::areConsecutive(L3, L2, SE, DL));
|
|
EXPECT_FALSE(sandboxir::VecUtils::areConsecutive(L0, L2, SE, DL));
|
|
EXPECT_FALSE(sandboxir::VecUtils::areConsecutive(L0, L3, SE, DL));
|
|
EXPECT_FALSE(sandboxir::VecUtils::areConsecutive(L1, L3, SE, DL));
|
|
EXPECT_FALSE(sandboxir::VecUtils::areConsecutive(L2, L0, SE, DL));
|
|
EXPECT_FALSE(sandboxir::VecUtils::areConsecutive(L3, L1, SE, DL));
|
|
|
|
// Check 2-wide loads
|
|
EXPECT_TRUE(sandboxir::VecUtils::areConsecutive(V2L0, V2L2, SE, DL));
|
|
EXPECT_TRUE(sandboxir::VecUtils::areConsecutive(V2L1, V2L3, SE, DL));
|
|
EXPECT_FALSE(sandboxir::VecUtils::areConsecutive(V2L0, V2L1, SE, DL));
|
|
EXPECT_FALSE(sandboxir::VecUtils::areConsecutive(V2L1, V2L2, SE, DL));
|
|
EXPECT_FALSE(sandboxir::VecUtils::areConsecutive(V2L2, V2L3, SE, DL));
|
|
|
|
EXPECT_FALSE(sandboxir::VecUtils::areConsecutive(V2L3, V2L1, SE, DL));
|
|
EXPECT_FALSE(sandboxir::VecUtils::areConsecutive(V2L3, V2L1, SE, DL));
|
|
EXPECT_FALSE(sandboxir::VecUtils::areConsecutive(V2L3, V2L1, SE, DL));
|
|
EXPECT_FALSE(sandboxir::VecUtils::areConsecutive(V2L3, V2L1, SE, DL));
|
|
|
|
// Check 3-wide loads
|
|
EXPECT_TRUE(sandboxir::VecUtils::areConsecutive(V3L0, V3L3, SE, DL));
|
|
EXPECT_FALSE(sandboxir::VecUtils::areConsecutive(V3L0, V3L1, SE, DL));
|
|
EXPECT_FALSE(sandboxir::VecUtils::areConsecutive(V3L1, V3L2, SE, DL));
|
|
EXPECT_FALSE(sandboxir::VecUtils::areConsecutive(V3L2, V3L3, SE, DL));
|
|
EXPECT_FALSE(sandboxir::VecUtils::areConsecutive(V3L1, V3L0, SE, DL));
|
|
EXPECT_FALSE(sandboxir::VecUtils::areConsecutive(V3L2, V3L1, SE, DL));
|
|
EXPECT_FALSE(sandboxir::VecUtils::areConsecutive(V3L3, V3L2, SE, DL));
|
|
|
|
// Check mixes of vectors and scalar
|
|
EXPECT_TRUE(sandboxir::VecUtils::areConsecutive(L0, V2L1, SE, DL));
|
|
EXPECT_TRUE(sandboxir::VecUtils::areConsecutive(L1, V2L2, SE, DL));
|
|
EXPECT_TRUE(sandboxir::VecUtils::areConsecutive(V2L0, L2, SE, DL));
|
|
EXPECT_TRUE(sandboxir::VecUtils::areConsecutive(V3L0, L3, SE, DL));
|
|
EXPECT_TRUE(sandboxir::VecUtils::areConsecutive(V2L0, V3L2, SE, DL));
|
|
|
|
EXPECT_FALSE(sandboxir::VecUtils::areConsecutive(L0, V2L2, SE, DL));
|
|
EXPECT_FALSE(sandboxir::VecUtils::areConsecutive(L0, V3L2, SE, DL));
|
|
EXPECT_FALSE(sandboxir::VecUtils::areConsecutive(L0, V2L3, SE, DL));
|
|
EXPECT_FALSE(sandboxir::VecUtils::areConsecutive(V2L0, V3L1, SE, DL));
|
|
EXPECT_FALSE(sandboxir::VecUtils::areConsecutive(V3L0, L1, SE, DL));
|
|
EXPECT_FALSE(sandboxir::VecUtils::areConsecutive(V3L0, L2, SE, DL));
|
|
EXPECT_FALSE(sandboxir::VecUtils::areConsecutive(V3L0, V2L1, SE, DL));
|
|
EXPECT_FALSE(sandboxir::VecUtils::areConsecutive(V3L0, V2L2, SE, DL));
|
|
EXPECT_FALSE(sandboxir::VecUtils::areConsecutive(V2L1, L0, SE, DL));
|
|
}
|
|
|
|
TEST_F(VecUtilsTest, GetNumLanes) {
|
|
parseIR(R"IR(
|
|
define <4 x float> @foo(float %v, <2 x float> %v2, <4 x float> %ret, ptr %ptr) {
|
|
store float %v, ptr %ptr
|
|
store <2 x float> %v2, ptr %ptr
|
|
ret <4 x float> %ret
|
|
}
|
|
)IR");
|
|
Function &LLVMF = *M->getFunction("foo");
|
|
|
|
sandboxir::Context Ctx(C);
|
|
auto &F = *Ctx.createFunction(&LLVMF);
|
|
auto &BB = *F.begin();
|
|
|
|
auto It = BB.begin();
|
|
auto *S0 = cast<sandboxir::StoreInst>(&*It++);
|
|
auto *S1 = cast<sandboxir::StoreInst>(&*It++);
|
|
auto *Ret = cast<sandboxir::ReturnInst>(&*It++);
|
|
EXPECT_EQ(sandboxir::VecUtils::getNumLanes(S0->getValueOperand()->getType()),
|
|
1u);
|
|
EXPECT_EQ(sandboxir::VecUtils::getNumLanes(S0), 1u);
|
|
EXPECT_EQ(sandboxir::VecUtils::getNumLanes(S1->getValueOperand()->getType()),
|
|
2u);
|
|
EXPECT_EQ(sandboxir::VecUtils::getNumLanes(S1), 2u);
|
|
EXPECT_EQ(sandboxir::VecUtils::getNumLanes(Ret->getReturnValue()->getType()),
|
|
4u);
|
|
EXPECT_EQ(sandboxir::VecUtils::getNumLanes(Ret), 4u);
|
|
|
|
SmallVector<sandboxir::Value *> Bndl({S0, S1, Ret});
|
|
EXPECT_EQ(sandboxir::VecUtils::getNumLanes(Bndl), 7u);
|
|
}
|
|
|
|
TEST_F(VecUtilsTest, GetWideType) {
|
|
sandboxir::Context Ctx(C);
|
|
|
|
auto *Int32Ty = sandboxir::Type::getInt32Ty(Ctx);
|
|
auto *Int32X4Ty = sandboxir::FixedVectorType::get(Int32Ty, 4);
|
|
EXPECT_EQ(sandboxir::VecUtils::getWideType(Int32Ty, 4), Int32X4Ty);
|
|
auto *Int32X8Ty = sandboxir::FixedVectorType::get(Int32Ty, 8);
|
|
EXPECT_EQ(sandboxir::VecUtils::getWideType(Int32X4Ty, 2), Int32X8Ty);
|
|
}
|
|
|
|
TEST_F(VecUtilsTest, GetCombinedVectorTypeFor) {
|
|
parseIR(R"IR(
|
|
define void @foo(ptr %ptr, i8 %i8, i16 %i16, i32 %i32, float %f32, double %f64, <2 x i8> %v2xi8, <2 x i16> %v2xi16) {
|
|
store i8 %i8, ptr %ptr
|
|
store i16 %i16, ptr %ptr
|
|
store i32 %i32, ptr %ptr
|
|
store float %f32, ptr %ptr
|
|
store double %f64, ptr %ptr
|
|
store <2 x i8> %v2xi8, ptr %ptr
|
|
store <2 x i16> %v2xi16, ptr %ptr
|
|
ret void
|
|
}
|
|
)IR");
|
|
Function &LLVMF = *M->getFunction("foo");
|
|
|
|
sandboxir::Context Ctx(C);
|
|
auto &F = *Ctx.createFunction(&LLVMF);
|
|
auto &BB = *F.begin();
|
|
const auto &DL = F.getParent()->getDataLayout();
|
|
auto It = BB.begin();
|
|
auto *Store_i8 = &*It++;
|
|
auto *Store_i16 = &*It++;
|
|
auto *Store_i32 = &*It++;
|
|
auto *Store_f32 = &*It++;
|
|
auto *Store_f64 = &*It++;
|
|
auto *Store_2xi8 = &*It++;
|
|
auto *Store_2xi16 = &*It++;
|
|
|
|
auto *I8Ty = sandboxir::IntegerType::get(Ctx, 8);
|
|
auto *I16Ty = sandboxir::IntegerType::get(Ctx, 16);
|
|
auto *F32Ty = sandboxir::Type::getFloatTy(Ctx);
|
|
|
|
// Check same type.
|
|
EXPECT_EQ(
|
|
sandboxir::VecUtils::getCombinedVectorTypeFor({Store_i8, Store_i8}, DL),
|
|
sandboxir::FixedVectorType::get(I8Ty, 2));
|
|
EXPECT_EQ(sandboxir::VecUtils::getCombinedVectorTypeFor(
|
|
{Store_2xi8, Store_2xi8}, DL),
|
|
sandboxir::FixedVectorType::get(I8Ty, 4));
|
|
|
|
// Check different types, power-of-two.
|
|
EXPECT_EQ(sandboxir::VecUtils::getCombinedVectorTypeFor(
|
|
{Store_i8, Store_i8, Store_i16}, DL),
|
|
sandboxir::FixedVectorType::get(I8Ty, 4));
|
|
EXPECT_EQ(sandboxir::VecUtils::getCombinedVectorTypeFor(
|
|
{Store_i8, Store_i8, Store_i16, Store_i32}, DL),
|
|
sandboxir::FixedVectorType::get(I8Ty, 8));
|
|
EXPECT_EQ(sandboxir::VecUtils::getCombinedVectorTypeFor(
|
|
{Store_2xi8, Store_2xi8, Store_2xi16}, DL),
|
|
sandboxir::FixedVectorType::get(I8Ty, 8));
|
|
|
|
// Check different types non-power-of-two.
|
|
EXPECT_EQ(
|
|
sandboxir::VecUtils::getCombinedVectorTypeFor({Store_f32, Store_f64}, DL),
|
|
sandboxir::FixedVectorType::get(F32Ty, 3));
|
|
EXPECT_EQ(
|
|
sandboxir::VecUtils::getCombinedVectorTypeFor({Store_i32, Store_i16}, DL),
|
|
sandboxir::FixedVectorType::get(I16Ty, 3));
|
|
EXPECT_EQ(sandboxir::VecUtils::getCombinedVectorTypeFor(
|
|
{Store_i8, Store_i16, Store_i32}, DL),
|
|
sandboxir::FixedVectorType::get(I8Ty, 7));
|
|
EXPECT_EQ(sandboxir::VecUtils::getCombinedVectorTypeFor(
|
|
{Store_i8, Store_i16, Store_2xi8}, DL),
|
|
sandboxir::FixedVectorType::get(I8Ty, 5));
|
|
|
|
// Mix float and integer.
|
|
{
|
|
auto *CVTy = sandboxir::VecUtils::getCombinedVectorTypeFor(
|
|
{Store_i32, Store_f32}, DL);
|
|
EXPECT_EQ(cast<sandboxir::FixedVectorType>(CVTy)->getNumElements(), 2u);
|
|
EXPECT_EQ(CVTy->getScalarSizeInBits(), 32u);
|
|
}
|
|
{
|
|
auto *CVTy = sandboxir::VecUtils::getCombinedVectorTypeFor(
|
|
{Store_f32, Store_2xi8}, DL);
|
|
EXPECT_EQ(cast<sandboxir::FixedVectorType>(CVTy)->getNumElements(), 6u);
|
|
EXPECT_EQ(CVTy->getScalarSizeInBits(), 8u);
|
|
}
|
|
}
|
|
|
|
TEST_F(VecUtilsTest, GetLowest) {
|
|
parseIR(R"IR(
|
|
define void @foo(i8 %v) {
|
|
bb0:
|
|
br label %bb1
|
|
bb1:
|
|
%A = add i8 %v, 1
|
|
%B = add i8 %v, 2
|
|
%C = add i8 %v, 3
|
|
ret void
|
|
}
|
|
)IR");
|
|
Function &LLVMF = *M->getFunction("foo");
|
|
|
|
sandboxir::Context Ctx(C);
|
|
auto &F = *Ctx.createFunction(&LLVMF);
|
|
auto &BB0 = getBasicBlockByName(F, "bb0");
|
|
auto It = BB0.begin();
|
|
auto *BB0I = cast<sandboxir::UncondBrInst>(&*It++);
|
|
|
|
auto &BB = getBasicBlockByName(F, "bb1");
|
|
It = BB.begin();
|
|
auto *IA = cast<sandboxir::Instruction>(&*It++);
|
|
auto *C1 = cast<sandboxir::Constant>(IA->getOperand(1));
|
|
auto *IB = cast<sandboxir::Instruction>(&*It++);
|
|
auto *C2 = cast<sandboxir::Constant>(IB->getOperand(1));
|
|
auto *IC = cast<sandboxir::Instruction>(&*It++);
|
|
auto *C3 = cast<sandboxir::Constant>(IC->getOperand(1));
|
|
// Check getLowest(ArrayRef<Instruction *>)
|
|
SmallVector<sandboxir::Instruction *> A({IA});
|
|
EXPECT_EQ(sandboxir::VecUtils::getLowest(A), IA);
|
|
SmallVector<sandboxir::Instruction *> ABC({IA, IB, IC});
|
|
EXPECT_EQ(sandboxir::VecUtils::getLowest(ABC), IC);
|
|
SmallVector<sandboxir::Instruction *> ACB({IA, IC, IB});
|
|
EXPECT_EQ(sandboxir::VecUtils::getLowest(ACB), IC);
|
|
SmallVector<sandboxir::Instruction *> CAB({IC, IA, IB});
|
|
EXPECT_EQ(sandboxir::VecUtils::getLowest(CAB), IC);
|
|
SmallVector<sandboxir::Instruction *> CBA({IC, IB, IA});
|
|
EXPECT_EQ(sandboxir::VecUtils::getLowest(CBA), IC);
|
|
|
|
// Check getLowest(ArrayRef<Value *>)
|
|
SmallVector<sandboxir::Value *> C1Only({C1});
|
|
EXPECT_EQ(sandboxir::VecUtils::getLowest(C1Only, &BB), nullptr);
|
|
EXPECT_EQ(sandboxir::VecUtils::getLowest(C1Only, &BB0), nullptr);
|
|
SmallVector<sandboxir::Value *> AOnly({IA});
|
|
EXPECT_EQ(sandboxir::VecUtils::getLowest(AOnly, &BB), IA);
|
|
EXPECT_EQ(sandboxir::VecUtils::getLowest(AOnly, &BB0), nullptr);
|
|
SmallVector<sandboxir::Value *> AC1({IA, C1});
|
|
EXPECT_EQ(sandboxir::VecUtils::getLowest(AC1, &BB), IA);
|
|
EXPECT_EQ(sandboxir::VecUtils::getLowest(AC1, &BB0), nullptr);
|
|
SmallVector<sandboxir::Value *> C1A({C1, IA});
|
|
EXPECT_EQ(sandboxir::VecUtils::getLowest(C1A, &BB), IA);
|
|
EXPECT_EQ(sandboxir::VecUtils::getLowest(C1A, &BB0), nullptr);
|
|
SmallVector<sandboxir::Value *> AC1B({IA, C1, IB});
|
|
EXPECT_EQ(sandboxir::VecUtils::getLowest(AC1B, &BB), IB);
|
|
EXPECT_EQ(sandboxir::VecUtils::getLowest(AC1B, &BB0), nullptr);
|
|
SmallVector<sandboxir::Value *> ABC1({IA, IB, C1});
|
|
EXPECT_EQ(sandboxir::VecUtils::getLowest(ABC1, &BB), IB);
|
|
EXPECT_EQ(sandboxir::VecUtils::getLowest(ABC1, &BB0), nullptr);
|
|
SmallVector<sandboxir::Value *> AC1C2({IA, C1, C2});
|
|
EXPECT_EQ(sandboxir::VecUtils::getLowest(AC1C2, &BB), IA);
|
|
EXPECT_EQ(sandboxir::VecUtils::getLowest(AC1C2, &BB0), nullptr);
|
|
SmallVector<sandboxir::Value *> C1C2C3({C1, C2, C3});
|
|
EXPECT_EQ(sandboxir::VecUtils::getLowest(C1C2C3, &BB), nullptr);
|
|
EXPECT_EQ(sandboxir::VecUtils::getLowest(C1C2C3, &BB0), nullptr);
|
|
|
|
SmallVector<sandboxir::Value *> DiffBBs({BB0I, IA});
|
|
EXPECT_EQ(sandboxir::VecUtils::getLowest(DiffBBs, &BB0), BB0I);
|
|
EXPECT_EQ(sandboxir::VecUtils::getLowest(DiffBBs, &BB), IA);
|
|
}
|
|
|
|
TEST_F(VecUtilsTest, GetLastPHIOrSelf) {
|
|
parseIR(R"IR(
|
|
define void @foo(i8 %v) {
|
|
entry:
|
|
br label %bb1
|
|
|
|
bb1:
|
|
%phi1 = phi i8 [0, %entry], [1, %bb1]
|
|
%phi2 = phi i8 [0, %entry], [1, %bb1]
|
|
br label %bb1
|
|
|
|
bb2:
|
|
ret void
|
|
}
|
|
)IR");
|
|
Function &LLVMF = *M->getFunction("foo");
|
|
|
|
sandboxir::Context Ctx(C);
|
|
auto &F = *Ctx.createFunction(&LLVMF);
|
|
auto &BB = getBasicBlockByName(F, "bb1");
|
|
auto It = BB.begin();
|
|
auto *PHI1 = cast<sandboxir::PHINode>(&*It++);
|
|
auto *PHI2 = cast<sandboxir::PHINode>(&*It++);
|
|
auto *Br = cast<sandboxir::UncondBrInst>(&*It++);
|
|
EXPECT_EQ(sandboxir::VecUtils::getLastPHIOrSelf(PHI1), PHI2);
|
|
EXPECT_EQ(sandboxir::VecUtils::getLastPHIOrSelf(PHI2), PHI2);
|
|
EXPECT_EQ(sandboxir::VecUtils::getLastPHIOrSelf(Br), Br);
|
|
EXPECT_EQ(sandboxir::VecUtils::getLastPHIOrSelf(nullptr), nullptr);
|
|
}
|
|
|
|
TEST_F(VecUtilsTest, GetCommonScalarType) {
|
|
parseIR(R"IR(
|
|
define void @foo(i8 %v, ptr %ptr) {
|
|
bb0:
|
|
%add0 = add i8 %v, %v
|
|
store i8 %v, ptr %ptr
|
|
ret void
|
|
}
|
|
)IR");
|
|
Function &LLVMF = *M->getFunction("foo");
|
|
|
|
sandboxir::Context Ctx(C);
|
|
auto &F = *Ctx.createFunction(&LLVMF);
|
|
auto &BB = *F.begin();
|
|
auto It = BB.begin();
|
|
auto *Add0 = cast<sandboxir::BinaryOperator>(&*It++);
|
|
auto *Store = cast<sandboxir::StoreInst>(&*It++);
|
|
auto *Ret = cast<sandboxir::ReturnInst>(&*It++);
|
|
{
|
|
SmallVector<sandboxir::Value *> Vec = {Add0, Store};
|
|
EXPECT_EQ(sandboxir::VecUtils::tryGetCommonScalarType(Vec),
|
|
Add0->getType());
|
|
EXPECT_EQ(sandboxir::VecUtils::getCommonScalarType(Vec), Add0->getType());
|
|
}
|
|
{
|
|
SmallVector<sandboxir::Value *> Vec = {Add0, Ret};
|
|
EXPECT_EQ(sandboxir::VecUtils::tryGetCommonScalarType(Vec), nullptr);
|
|
#ifndef NDEBUG
|
|
EXPECT_DEATH(sandboxir::VecUtils::getCommonScalarType(Vec), ".*common.*");
|
|
#endif // NDEBUG
|
|
}
|
|
}
|
|
|
|
TEST_F(VecUtilsTest, FloorPowerOf2) {
|
|
EXPECT_EQ(sandboxir::VecUtils::getFloorPowerOf2(0), 0u);
|
|
EXPECT_EQ(sandboxir::VecUtils::getFloorPowerOf2(1 << 0), 1u << 0);
|
|
EXPECT_EQ(sandboxir::VecUtils::getFloorPowerOf2(3), 2u);
|
|
EXPECT_EQ(sandboxir::VecUtils::getFloorPowerOf2(4), 4u);
|
|
EXPECT_EQ(sandboxir::VecUtils::getFloorPowerOf2(5), 4u);
|
|
EXPECT_EQ(sandboxir::VecUtils::getFloorPowerOf2(7), 4u);
|
|
EXPECT_EQ(sandboxir::VecUtils::getFloorPowerOf2(8), 8u);
|
|
EXPECT_EQ(sandboxir::VecUtils::getFloorPowerOf2(9), 8u);
|
|
}
|
|
|
|
TEST_F(VecUtilsTest, MatchPackScalar) {
|
|
parseIR(R"IR(
|
|
define void @foo(i8 %v0, i8 %v1) {
|
|
bb0:
|
|
%NotPack = insertelement <2 x i8> poison, i8 %v0, i64 0
|
|
br label %bb1
|
|
|
|
bb1:
|
|
%Pack0 = insertelement <2 x i8> poison, i8 %v0, i64 0
|
|
%Pack1 = insertelement <2 x i8> %Pack0, i8 %v1, i64 1
|
|
|
|
%NotPack0 = insertelement <2 x i8> poison, i8 %v0, i64 0
|
|
%NotPack1 = insertelement <2 x i8> %NotPack0, i8 %v1, i64 0
|
|
%NotPack2 = insertelement <2 x i8> %NotPack1, i8 %v1, i64 1
|
|
|
|
%NotPackBB = insertelement <2 x i8> %NotPack, i8 %v1, i64 1
|
|
|
|
ret void
|
|
}
|
|
)IR");
|
|
Function &LLVMF = *M->getFunction("foo");
|
|
|
|
sandboxir::Context Ctx(C);
|
|
auto &F = *Ctx.createFunction(&LLVMF);
|
|
auto &BB = getBasicBlockByName(F, "bb1");
|
|
auto It = BB.begin();
|
|
auto *Pack0 = cast<sandboxir::InsertElementInst>(&*It++);
|
|
auto *Pack1 = cast<sandboxir::InsertElementInst>(&*It++);
|
|
auto *NotPack0 = cast<sandboxir::InsertElementInst>(&*It++);
|
|
auto *NotPack1 = cast<sandboxir::InsertElementInst>(&*It++);
|
|
auto *NotPack2 = cast<sandboxir::InsertElementInst>(&*It++);
|
|
auto *NotPackBB = cast<sandboxir::InsertElementInst>(&*It++);
|
|
auto *Ret = cast<sandboxir::ReturnInst>(&*It++);
|
|
auto *Arg0 = F.getArg(0);
|
|
auto *Arg1 = F.getArg(1);
|
|
EXPECT_FALSE(sandboxir::VecUtils::matchPack(Pack0));
|
|
EXPECT_FALSE(sandboxir::VecUtils::matchPack(Ret));
|
|
{
|
|
auto PackOpt = sandboxir::VecUtils::matchPack(Pack1);
|
|
EXPECT_TRUE(PackOpt);
|
|
EXPECT_THAT(PackOpt->Instrs, testing::ElementsAre(Pack1, Pack0));
|
|
EXPECT_THAT(PackOpt->Operands, testing::ElementsAre(Arg0, Arg1));
|
|
}
|
|
{
|
|
for (auto *NotPack : {NotPack0, NotPack1, NotPack2, NotPackBB})
|
|
EXPECT_FALSE(sandboxir::VecUtils::matchPack(NotPack));
|
|
}
|
|
}
|
|
|
|
TEST_F(VecUtilsTest, Unpack) {
|
|
parseIR(R"IR(
|
|
define void @foo(<4 x i32> %vec, i32 %scalar) {
|
|
bb0:
|
|
ret void
|
|
}
|
|
)IR");
|
|
Function &LLVMF = *M->getFunction("foo");
|
|
|
|
sandboxir::Context Ctx(C);
|
|
auto &F = *Ctx.createFunction(&LLVMF);
|
|
auto &BB = getBasicBlockByName(F, "bb0");
|
|
auto It = BB.begin();
|
|
sandboxir::Value *Vec = F.getArg(0);
|
|
[[maybe_unused]] sandboxir::Value *Scalar = F.getArg(1);
|
|
|
|
auto *Int32Ty = sandboxir::Type::getInt32Ty(Ctx);
|
|
|
|
// Check unpacking scalars.
|
|
auto WhereIt = It;
|
|
for (unsigned Lane = 0; Lane != 4; ++Lane) {
|
|
auto *ExtrI = cast<sandboxir::ExtractElementInst>(
|
|
sandboxir::VecUtils::unpack(Vec, Int32Ty, Lane, WhereIt));
|
|
EXPECT_EQ(ExtrI->getOperand(0), Vec);
|
|
EXPECT_EQ(ExtrI->getOperand(1), sandboxir::ConstantInt::get(Int32Ty, Lane));
|
|
ExtrI->eraseFromParent();
|
|
}
|
|
auto *Int8Ty = sandboxir::Type::getInt8Ty(Ctx);
|
|
// Check assertions.
|
|
#ifndef NDEBUG
|
|
EXPECT_DEATH(sandboxir::VecUtils::unpack(Scalar, Int32Ty, 0, WhereIt),
|
|
".*vector.*");
|
|
EXPECT_DEATH(sandboxir::VecUtils::unpack(Vec, Int32Ty, 4, WhereIt),
|
|
"Out of bounds.*");
|
|
EXPECT_DEATH(sandboxir::VecUtils::unpack(Vec, Int8Ty, 0, WhereIt),
|
|
".*element type.*");
|
|
#endif // NDEBUG
|
|
|
|
// Check unpacking vectors.
|
|
auto *ExtrTy = sandboxir::FixedVectorType::get(Int32Ty, 2);
|
|
auto *VecTy = cast<sandboxir::FixedVectorType>(Vec->getType());
|
|
for (unsigned Lane = 0; Lane != 2; ++Lane) {
|
|
auto *Shuff = cast<sandboxir::ShuffleVectorInst>(
|
|
sandboxir::VecUtils::unpack(Vec, ExtrTy, Lane, WhereIt));
|
|
EXPECT_EQ(Shuff->getOperand(0), Vec);
|
|
EXPECT_EQ(Shuff->getOperand(1), sandboxir::PoisonValue::get(VecTy));
|
|
auto Mask = Shuff->getShuffleMask();
|
|
EXPECT_THAT(Mask, testing::ElementsAre(Lane, Lane + 1));
|
|
|
|
Shuff->eraseFromParent();
|
|
}
|
|
// Check out of bounds!.
|
|
auto *Ty2xi32 = sandboxir::FixedVectorType::get(Int32Ty, 2);
|
|
EXPECT_DEBUG_DEATH(sandboxir::VecUtils::unpack(Vec, Ty2xi32, 3, WhereIt),
|
|
"Out of bounds.*");
|
|
EXPECT_DEBUG_DEATH(sandboxir::VecUtils::unpack(Vec, Ty2xi32, 4, WhereIt),
|
|
"Out of bounds.*");
|
|
auto *Ty2xi8 = sandboxir::FixedVectorType::get(Int8Ty, 2);
|
|
EXPECT_DEBUG_DEATH(sandboxir::VecUtils::unpack(Vec, Ty2xi8, 4, WhereIt),
|
|
".*type.*");
|
|
}
|
|
|
|
TEST_F(VecUtilsTest, LaneValueEnumerator) {
|
|
parseIR(R"IR(
|
|
define void @foo(i32 %s0, <4 x i32> %v0, i32 %s1, <2 x i32> %v1, <3 x i32> %v2, i32 %s2) {
|
|
bb0:
|
|
ret void
|
|
}
|
|
)IR");
|
|
Function &LLVMF = *M->getFunction("foo");
|
|
|
|
sandboxir::Context Ctx(C);
|
|
auto &F = *Ctx.createFunction(&LLVMF);
|
|
unsigned Idx = 0;
|
|
sandboxir::Value *S0 = F.getArg(Idx++);
|
|
sandboxir::Value *V0 = F.getArg(Idx++);
|
|
sandboxir::Value *S1 = F.getArg(Idx++);
|
|
sandboxir::Value *V1 = F.getArg(Idx++);
|
|
sandboxir::Value *V2 = F.getArg(Idx++);
|
|
sandboxir::Value *S2 = F.getArg(Idx++);
|
|
|
|
SmallVector<sandboxir::Value *, 6> Bndl({S0, V0, S1, V1, V2, S2});
|
|
SmallVector<unsigned, 6> Lanes;
|
|
SmallVector<sandboxir::Value *, 6> Elms;
|
|
for (auto [Lane, Elm] : sandboxir::VecUtils::enumerateLanes(Bndl)) {
|
|
Lanes.push_back(Lane);
|
|
Elms.push_back(Elm);
|
|
}
|
|
|
|
EXPECT_EQ(Elms, Bndl);
|
|
EXPECT_THAT(Lanes, testing::ElementsAre(0, 1, 5, 6, 8, 11));
|
|
}
|