142c5a301Svporpo //===- LegalityTest.cpp ---------------------------------------------------===// 242c5a301Svporpo // 342c5a301Svporpo // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 442c5a301Svporpo // See https://llvm.org/LICENSE.txt for license information. 542c5a301Svporpo // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 642c5a301Svporpo // 742c5a301Svporpo //===----------------------------------------------------------------------===// 842c5a301Svporpo 942c5a301Svporpo #include "llvm/Transforms/Vectorize/SandboxVectorizer/Legality.h" 10083369fdSvporpo #include "llvm/Analysis/AssumptionCache.h" 11ce0d0858Svporpo #include "llvm/Analysis/BasicAliasAnalysis.h" 12083369fdSvporpo #include "llvm/Analysis/LoopInfo.h" 13083369fdSvporpo #include "llvm/Analysis/ScalarEvolution.h" 14083369fdSvporpo #include "llvm/Analysis/TargetLibraryInfo.h" 1542c5a301Svporpo #include "llvm/AsmParser/Parser.h" 16083369fdSvporpo #include "llvm/IR/DataLayout.h" 17083369fdSvporpo #include "llvm/IR/Dominators.h" 18e22b07e7Svporpo #include "llvm/SandboxIR/Function.h" 19eba106d4Svporpo #include "llvm/SandboxIR/Instruction.h" 2042c5a301Svporpo #include "llvm/Support/SourceMgr.h" 21e902c696Svporpo #include "llvm/Transforms/Vectorize/SandboxVectorizer/InstrMaps.h" 2287e4b681Svporpo #include "gmock/gmock.h" 2342c5a301Svporpo #include "gtest/gtest.h" 2442c5a301Svporpo 2542c5a301Svporpo using namespace llvm; 2642c5a301Svporpo 2742c5a301Svporpo struct LegalityTest : public testing::Test { 2842c5a301Svporpo LLVMContext C; 2942c5a301Svporpo std::unique_ptr<Module> M; 30083369fdSvporpo std::unique_ptr<DominatorTree> DT; 31083369fdSvporpo std::unique_ptr<TargetLibraryInfoImpl> TLII; 32083369fdSvporpo std::unique_ptr<TargetLibraryInfo> TLI; 33083369fdSvporpo std::unique_ptr<AssumptionCache> AC; 34083369fdSvporpo std::unique_ptr<LoopInfo> LI; 35083369fdSvporpo std::unique_ptr<ScalarEvolution> SE; 36ce0d0858Svporpo std::unique_ptr<BasicAAResult> BAA; 37ce0d0858Svporpo std::unique_ptr<AAResults> AA; 38083369fdSvporpo 39ce0d0858Svporpo void getAnalyses(llvm::Function &LLVMF) { 40083369fdSvporpo DT = std::make_unique<DominatorTree>(LLVMF); 41083369fdSvporpo TLII = std::make_unique<TargetLibraryInfoImpl>(); 42083369fdSvporpo TLI = std::make_unique<TargetLibraryInfo>(*TLII); 43083369fdSvporpo AC = std::make_unique<AssumptionCache>(LLVMF); 44083369fdSvporpo LI = std::make_unique<LoopInfo>(*DT); 45083369fdSvporpo SE = std::make_unique<ScalarEvolution>(LLVMF, *TLI, *AC, *DT, *LI); 46ce0d0858Svporpo BAA = std::make_unique<BasicAAResult>(LLVMF.getParent()->getDataLayout(), 47ce0d0858Svporpo LLVMF, *TLI, *AC, DT.get()); 48ce0d0858Svporpo AA = std::make_unique<AAResults>(*TLI); 49ce0d0858Svporpo AA->addAAResult(*BAA); 50083369fdSvporpo } 5142c5a301Svporpo 5242c5a301Svporpo void parseIR(LLVMContext &C, const char *IR) { 5342c5a301Svporpo SMDiagnostic Err; 5442c5a301Svporpo M = parseAssemblyString(IR, Err, C); 5542c5a301Svporpo if (!M) 5642c5a301Svporpo Err.print("LegalityTest", errs()); 5742c5a301Svporpo } 5842c5a301Svporpo }; 5942c5a301Svporpo 60*6409799bSvporpo static sandboxir::BasicBlock *getBasicBlockByName(sandboxir::Function *F, 61*6409799bSvporpo StringRef Name) { 62*6409799bSvporpo for (sandboxir::BasicBlock &BB : *F) 63*6409799bSvporpo if (BB.getName() == Name) 64*6409799bSvporpo return &BB; 65*6409799bSvporpo llvm_unreachable("Expected to find basic block!"); 66*6409799bSvporpo } 67*6409799bSvporpo 68ce0d0858Svporpo TEST_F(LegalityTest, LegalitySkipSchedule) { 6942c5a301Svporpo parseIR(C, R"IR( 70083369fdSvporpo define void @foo(ptr %ptr, <2 x float> %vec2, <3 x float> %vec3, i8 %arg, float %farg0, float %farg1, i64 %v0, i64 %v1, i32 %v2) { 71*6409799bSvporpo entry: 7242c5a301Svporpo %gep0 = getelementptr float, ptr %ptr, i32 0 7342c5a301Svporpo %gep1 = getelementptr float, ptr %ptr, i32 1 74*6409799bSvporpo store float %farg0, ptr %gep1 75*6409799bSvporpo br label %bb 76*6409799bSvporpo 77*6409799bSvporpo bb: 785ea69481Svporpo %gep3 = getelementptr float, ptr %ptr, i32 3 7942c5a301Svporpo %ld0 = load float, ptr %gep0 80083369fdSvporpo %ld0b = load float, ptr %gep0 81083369fdSvporpo %ld1 = load float, ptr %gep1 82083369fdSvporpo %ld3 = load float, ptr %gep3 8342c5a301Svporpo store float %ld0, ptr %gep0 8442c5a301Svporpo store float %ld1, ptr %gep1 855ea69481Svporpo store <2 x float> %vec2, ptr %gep1 865ea69481Svporpo store <3 x float> %vec3, ptr %gep3 875ea69481Svporpo store i8 %arg, ptr %gep1 88bf4b31adSvporpo %fadd0 = fadd float %farg0, %farg0 89bf4b31adSvporpo %fadd1 = fadd fast float %farg1, %farg1 90ca998b07Svporpo %trunc0 = trunc nuw nsw i64 %v0 to i8 91ca998b07Svporpo %trunc1 = trunc nsw i64 %v1 to i8 92083369fdSvporpo %trunc64to8 = trunc i64 %v0 to i8 93083369fdSvporpo %trunc32to8 = trunc i32 %v2 to i8 94083369fdSvporpo %cmpSLT = icmp slt i64 %v0, %v1 95083369fdSvporpo %cmpSGT = icmp sgt i64 %v0, %v1 9642c5a301Svporpo ret void 9742c5a301Svporpo } 9842c5a301Svporpo )IR"); 9942c5a301Svporpo llvm::Function *LLVMF = &*M->getFunction("foo"); 100ce0d0858Svporpo getAnalyses(*LLVMF); 101083369fdSvporpo const auto &DL = M->getDataLayout(); 102083369fdSvporpo 10342c5a301Svporpo sandboxir::Context Ctx(C); 10442c5a301Svporpo auto *F = Ctx.createFunction(LLVMF); 105*6409799bSvporpo auto *EntryBB = getBasicBlockByName(F, "entry"); 106*6409799bSvporpo auto It = EntryBB->begin(); 10742c5a301Svporpo [[maybe_unused]] auto *Gep0 = cast<sandboxir::GetElementPtrInst>(&*It++); 10842c5a301Svporpo [[maybe_unused]] auto *Gep1 = cast<sandboxir::GetElementPtrInst>(&*It++); 109*6409799bSvporpo auto *St1Entry = cast<sandboxir::StoreInst>(&*It++); 110*6409799bSvporpo 111*6409799bSvporpo auto *BB = getBasicBlockByName(F, "bb"); 112*6409799bSvporpo It = BB->begin(); 1135ea69481Svporpo [[maybe_unused]] auto *Gep3 = cast<sandboxir::GetElementPtrInst>(&*It++); 114083369fdSvporpo auto *Ld0 = cast<sandboxir::LoadInst>(&*It++); 115083369fdSvporpo auto *Ld0b = cast<sandboxir::LoadInst>(&*It++); 116083369fdSvporpo auto *Ld1 = cast<sandboxir::LoadInst>(&*It++); 117083369fdSvporpo auto *Ld3 = cast<sandboxir::LoadInst>(&*It++); 11842c5a301Svporpo auto *St0 = cast<sandboxir::StoreInst>(&*It++); 11942c5a301Svporpo auto *St1 = cast<sandboxir::StoreInst>(&*It++); 1205ea69481Svporpo auto *StVec2 = cast<sandboxir::StoreInst>(&*It++); 1215ea69481Svporpo auto *StVec3 = cast<sandboxir::StoreInst>(&*It++); 1225ea69481Svporpo auto *StI8 = cast<sandboxir::StoreInst>(&*It++); 123bf4b31adSvporpo auto *FAdd0 = cast<sandboxir::BinaryOperator>(&*It++); 124bf4b31adSvporpo auto *FAdd1 = cast<sandboxir::BinaryOperator>(&*It++); 125ca998b07Svporpo auto *Trunc0 = cast<sandboxir::TruncInst>(&*It++); 126ca998b07Svporpo auto *Trunc1 = cast<sandboxir::TruncInst>(&*It++); 127083369fdSvporpo auto *Trunc64to8 = cast<sandboxir::TruncInst>(&*It++); 128083369fdSvporpo auto *Trunc32to8 = cast<sandboxir::TruncInst>(&*It++); 129083369fdSvporpo auto *CmpSLT = cast<sandboxir::CmpInst>(&*It++); 130083369fdSvporpo auto *CmpSGT = cast<sandboxir::CmpInst>(&*It++); 13142c5a301Svporpo 132d6315affSvporpo llvm::sandboxir::InstrMaps IMaps(Ctx); 133e902c696Svporpo sandboxir::LegalityAnalysis Legality(*AA, *SE, DL, Ctx, IMaps); 134ce0d0858Svporpo const auto &Result = 135ce0d0858Svporpo Legality.canVectorize({St0, St1}, /*SkipScheduling=*/true); 13642c5a301Svporpo EXPECT_TRUE(isa<sandboxir::Widen>(Result)); 1371540f772SVasileios Porpodas 1381540f772SVasileios Porpodas { 1391540f772SVasileios Porpodas // Check NotInstructions 140ce0d0858Svporpo auto &Result = Legality.canVectorize({F, St0}, /*SkipScheduling=*/true); 1411540f772SVasileios Porpodas EXPECT_TRUE(isa<sandboxir::Pack>(Result)); 1421540f772SVasileios Porpodas EXPECT_EQ(cast<sandboxir::Pack>(Result).getReason(), 1431540f772SVasileios Porpodas sandboxir::ResultReason::NotInstructions); 1441540f772SVasileios Porpodas } 1455ea69481Svporpo { 1465ea69481Svporpo // Check DiffOpcodes 147ce0d0858Svporpo const auto &Result = 148ce0d0858Svporpo Legality.canVectorize({St0, Ld0}, /*SkipScheduling=*/true); 1495ea69481Svporpo EXPECT_TRUE(isa<sandboxir::Pack>(Result)); 1505ea69481Svporpo EXPECT_EQ(cast<sandboxir::Pack>(Result).getReason(), 1515ea69481Svporpo sandboxir::ResultReason::DiffOpcodes); 1525ea69481Svporpo } 1535ea69481Svporpo { 1545ea69481Svporpo // Check DiffTypes 155ce0d0858Svporpo EXPECT_TRUE(isa<sandboxir::Widen>( 156ce0d0858Svporpo Legality.canVectorize({St0, StVec2}, /*SkipScheduling=*/true))); 157ce0d0858Svporpo EXPECT_TRUE(isa<sandboxir::Widen>( 158ce0d0858Svporpo Legality.canVectorize({StVec2, StVec3}, /*SkipScheduling=*/true))); 1595ea69481Svporpo 160ce0d0858Svporpo const auto &Result = 161ce0d0858Svporpo Legality.canVectorize({St0, StI8}, /*SkipScheduling=*/true); 1625ea69481Svporpo EXPECT_TRUE(isa<sandboxir::Pack>(Result)); 1635ea69481Svporpo EXPECT_EQ(cast<sandboxir::Pack>(Result).getReason(), 1645ea69481Svporpo sandboxir::ResultReason::DiffTypes); 1655ea69481Svporpo } 166bf4b31adSvporpo { 167bf4b31adSvporpo // Check DiffMathFlags 168ce0d0858Svporpo const auto &Result = 169ce0d0858Svporpo Legality.canVectorize({FAdd0, FAdd1}, /*SkipScheduling=*/true); 170bf4b31adSvporpo EXPECT_TRUE(isa<sandboxir::Pack>(Result)); 171bf4b31adSvporpo EXPECT_EQ(cast<sandboxir::Pack>(Result).getReason(), 172bf4b31adSvporpo sandboxir::ResultReason::DiffMathFlags); 173bf4b31adSvporpo } 174ca998b07Svporpo { 175ca998b07Svporpo // Check DiffWrapFlags 176ce0d0858Svporpo const auto &Result = 177ce0d0858Svporpo Legality.canVectorize({Trunc0, Trunc1}, /*SkipScheduling=*/true); 178ca998b07Svporpo EXPECT_TRUE(isa<sandboxir::Pack>(Result)); 179ca998b07Svporpo EXPECT_EQ(cast<sandboxir::Pack>(Result).getReason(), 180ca998b07Svporpo sandboxir::ResultReason::DiffWrapFlags); 181ca998b07Svporpo } 182083369fdSvporpo { 183*6409799bSvporpo // Check DiffBBs 184*6409799bSvporpo const auto &Result = 185*6409799bSvporpo Legality.canVectorize({St0, St1Entry}, /*SkipScheduling=*/true); 186*6409799bSvporpo EXPECT_TRUE(isa<sandboxir::Pack>(Result)); 187*6409799bSvporpo EXPECT_EQ(cast<sandboxir::Pack>(Result).getReason(), 188*6409799bSvporpo sandboxir::ResultReason::DiffBBs); 189*6409799bSvporpo } 190*6409799bSvporpo { 191083369fdSvporpo // Check DiffTypes for unary operands that have a different type. 192ce0d0858Svporpo const auto &Result = Legality.canVectorize({Trunc64to8, Trunc32to8}, 193ce0d0858Svporpo /*SkipScheduling=*/true); 194083369fdSvporpo EXPECT_TRUE(isa<sandboxir::Pack>(Result)); 195083369fdSvporpo EXPECT_EQ(cast<sandboxir::Pack>(Result).getReason(), 196083369fdSvporpo sandboxir::ResultReason::DiffTypes); 197083369fdSvporpo } 198083369fdSvporpo { 199083369fdSvporpo // Check DiffOpcodes for CMPs with different predicates. 200ce0d0858Svporpo const auto &Result = 201ce0d0858Svporpo Legality.canVectorize({CmpSLT, CmpSGT}, /*SkipScheduling=*/true); 202083369fdSvporpo EXPECT_TRUE(isa<sandboxir::Pack>(Result)); 203083369fdSvporpo EXPECT_EQ(cast<sandboxir::Pack>(Result).getReason(), 204083369fdSvporpo sandboxir::ResultReason::DiffOpcodes); 205083369fdSvporpo } 206083369fdSvporpo { 207083369fdSvporpo // Check NotConsecutive Ld0,Ld0b 208ce0d0858Svporpo const auto &Result = 209ce0d0858Svporpo Legality.canVectorize({Ld0, Ld0b}, /*SkipScheduling=*/true); 210083369fdSvporpo EXPECT_TRUE(isa<sandboxir::Pack>(Result)); 211083369fdSvporpo EXPECT_EQ(cast<sandboxir::Pack>(Result).getReason(), 212083369fdSvporpo sandboxir::ResultReason::NotConsecutive); 213083369fdSvporpo } 214083369fdSvporpo { 215083369fdSvporpo // Check NotConsecutive Ld0,Ld3 216ce0d0858Svporpo const auto &Result = 217ce0d0858Svporpo Legality.canVectorize({Ld0, Ld3}, /*SkipScheduling=*/true); 218083369fdSvporpo EXPECT_TRUE(isa<sandboxir::Pack>(Result)); 219083369fdSvporpo EXPECT_EQ(cast<sandboxir::Pack>(Result).getReason(), 220083369fdSvporpo sandboxir::ResultReason::NotConsecutive); 221083369fdSvporpo } 222083369fdSvporpo { 223083369fdSvporpo // Check Widen Ld0,Ld1 224ce0d0858Svporpo const auto &Result = 225ce0d0858Svporpo Legality.canVectorize({Ld0, Ld1}, /*SkipScheduling=*/true); 226083369fdSvporpo EXPECT_TRUE(isa<sandboxir::Widen>(Result)); 227083369fdSvporpo } 22842c5a301Svporpo } 22954c93aabSvporpo 230ce0d0858Svporpo TEST_F(LegalityTest, LegalitySchedule) { 231ce0d0858Svporpo parseIR(C, R"IR( 232ce0d0858Svporpo define void @foo(ptr %ptr) { 233ce0d0858Svporpo %gep0 = getelementptr float, ptr %ptr, i32 0 234ce0d0858Svporpo %gep1 = getelementptr float, ptr %ptr, i32 1 235ce0d0858Svporpo %ld0 = load float, ptr %gep0 236ce0d0858Svporpo store float %ld0, ptr %gep1 237ce0d0858Svporpo %ld1 = load float, ptr %gep1 238ce0d0858Svporpo store float %ld0, ptr %gep0 239ce0d0858Svporpo store float %ld1, ptr %gep1 240ce0d0858Svporpo ret void 241ce0d0858Svporpo } 242ce0d0858Svporpo )IR"); 243ce0d0858Svporpo llvm::Function *LLVMF = &*M->getFunction("foo"); 244ce0d0858Svporpo getAnalyses(*LLVMF); 245ce0d0858Svporpo const auto &DL = M->getDataLayout(); 246ce0d0858Svporpo 247ce0d0858Svporpo sandboxir::Context Ctx(C); 248ce0d0858Svporpo auto *F = Ctx.createFunction(LLVMF); 249ce0d0858Svporpo auto *BB = &*F->begin(); 250ce0d0858Svporpo auto It = BB->begin(); 251ce0d0858Svporpo [[maybe_unused]] auto *Gep0 = cast<sandboxir::GetElementPtrInst>(&*It++); 252ce0d0858Svporpo [[maybe_unused]] auto *Gep1 = cast<sandboxir::GetElementPtrInst>(&*It++); 253ce0d0858Svporpo auto *Ld0 = cast<sandboxir::LoadInst>(&*It++); 254ce0d0858Svporpo [[maybe_unused]] auto *ConflictingSt = cast<sandboxir::StoreInst>(&*It++); 255ce0d0858Svporpo auto *Ld1 = cast<sandboxir::LoadInst>(&*It++); 256ce0d0858Svporpo auto *St0 = cast<sandboxir::StoreInst>(&*It++); 257ce0d0858Svporpo auto *St1 = cast<sandboxir::StoreInst>(&*It++); 258ce0d0858Svporpo 259d6315affSvporpo llvm::sandboxir::InstrMaps IMaps(Ctx); 260e902c696Svporpo sandboxir::LegalityAnalysis Legality(*AA, *SE, DL, Ctx, IMaps); 261ce0d0858Svporpo { 262ce0d0858Svporpo // Can vectorize St0,St1. 263ce0d0858Svporpo const auto &Result = Legality.canVectorize({St0, St1}); 264ce0d0858Svporpo EXPECT_TRUE(isa<sandboxir::Widen>(Result)); 265ce0d0858Svporpo } 266ce0d0858Svporpo { 267ce0d0858Svporpo // Can't vectorize Ld0,Ld1 because of conflicting store. 268ce0d0858Svporpo auto &Result = Legality.canVectorize({Ld0, Ld1}); 269ce0d0858Svporpo EXPECT_TRUE(isa<sandboxir::Pack>(Result)); 270ce0d0858Svporpo EXPECT_EQ(cast<sandboxir::Pack>(Result).getReason(), 271ce0d0858Svporpo sandboxir::ResultReason::CantSchedule); 272ce0d0858Svporpo } 273ce0d0858Svporpo } 274ce0d0858Svporpo 27554c93aabSvporpo #ifndef NDEBUG 27654c93aabSvporpo TEST_F(LegalityTest, LegalityResultDump) { 277083369fdSvporpo parseIR(C, R"IR( 278083369fdSvporpo define void @foo() { 279083369fdSvporpo ret void 280083369fdSvporpo } 281083369fdSvporpo )IR"); 282083369fdSvporpo llvm::Function *LLVMF = &*M->getFunction("foo"); 283ce0d0858Svporpo getAnalyses(*LLVMF); 284083369fdSvporpo const auto &DL = M->getDataLayout(); 285083369fdSvporpo 28654c93aabSvporpo auto Matches = [](const sandboxir::LegalityResult &Result, 28754c93aabSvporpo const std::string &ExpectedStr) -> bool { 28854c93aabSvporpo std::string Buff; 28954c93aabSvporpo raw_string_ostream OS(Buff); 29054c93aabSvporpo Result.print(OS); 29154c93aabSvporpo return Buff == ExpectedStr; 29254c93aabSvporpo }; 293083369fdSvporpo 2945942a99fSvporpo sandboxir::Context Ctx(C); 295d6315affSvporpo llvm::sandboxir::InstrMaps IMaps(Ctx); 296e902c696Svporpo sandboxir::LegalityAnalysis Legality(*AA, *SE, DL, Ctx, IMaps); 29754c93aabSvporpo EXPECT_TRUE( 29854c93aabSvporpo Matches(Legality.createLegalityResult<sandboxir::Widen>(), "Widen")); 29954c93aabSvporpo EXPECT_TRUE(Matches(Legality.createLegalityResult<sandboxir::Pack>( 3001540f772SVasileios Porpodas sandboxir::ResultReason::NotInstructions), 3011540f772SVasileios Porpodas "Pack Reason: NotInstructions")); 3021540f772SVasileios Porpodas EXPECT_TRUE(Matches(Legality.createLegalityResult<sandboxir::Pack>( 30354c93aabSvporpo sandboxir::ResultReason::DiffOpcodes), 30454c93aabSvporpo "Pack Reason: DiffOpcodes")); 30554c93aabSvporpo EXPECT_TRUE(Matches(Legality.createLegalityResult<sandboxir::Pack>( 30654c93aabSvporpo sandboxir::ResultReason::DiffTypes), 30754c93aabSvporpo "Pack Reason: DiffTypes")); 308bf4b31adSvporpo EXPECT_TRUE(Matches(Legality.createLegalityResult<sandboxir::Pack>( 309bf4b31adSvporpo sandboxir::ResultReason::DiffMathFlags), 310bf4b31adSvporpo "Pack Reason: DiffMathFlags")); 311ca998b07Svporpo EXPECT_TRUE(Matches(Legality.createLegalityResult<sandboxir::Pack>( 312ca998b07Svporpo sandboxir::ResultReason::DiffWrapFlags), 313ca998b07Svporpo "Pack Reason: DiffWrapFlags")); 31454c93aabSvporpo } 31554c93aabSvporpo #endif // NDEBUG 316e902c696Svporpo 317e902c696Svporpo TEST_F(LegalityTest, CollectDescr) { 318e902c696Svporpo parseIR(C, R"IR( 319e902c696Svporpo define void @foo(ptr %ptr) { 320e902c696Svporpo %gep0 = getelementptr float, ptr %ptr, i32 0 321e902c696Svporpo %gep1 = getelementptr float, ptr %ptr, i32 1 322e902c696Svporpo %ld0 = load float, ptr %gep0 323e902c696Svporpo %ld1 = load float, ptr %gep1 324e902c696Svporpo %vld = load <4 x float>, ptr %ptr 325e902c696Svporpo ret void 326e902c696Svporpo } 327e902c696Svporpo )IR"); 328e902c696Svporpo llvm::Function *LLVMF = &*M->getFunction("foo"); 329e902c696Svporpo getAnalyses(*LLVMF); 330e902c696Svporpo sandboxir::Context Ctx(C); 331e902c696Svporpo auto *F = Ctx.createFunction(LLVMF); 332e902c696Svporpo auto *BB = &*F->begin(); 333e902c696Svporpo auto It = BB->begin(); 334e902c696Svporpo [[maybe_unused]] auto *Gep0 = cast<sandboxir::GetElementPtrInst>(&*It++); 335e902c696Svporpo [[maybe_unused]] auto *Gep1 = cast<sandboxir::GetElementPtrInst>(&*It++); 336e902c696Svporpo auto *Ld0 = cast<sandboxir::LoadInst>(&*It++); 337e902c696Svporpo [[maybe_unused]] auto *Ld1 = cast<sandboxir::LoadInst>(&*It++); 338e902c696Svporpo auto *VLd = cast<sandboxir::LoadInst>(&*It++); 339e902c696Svporpo 340e902c696Svporpo sandboxir::CollectDescr::DescrVecT Descrs; 341e902c696Svporpo using EEDescr = sandboxir::CollectDescr::ExtractElementDescr; 342e902c696Svporpo 343e902c696Svporpo { 344e902c696Svporpo // Check single input, no shuffle. 345e902c696Svporpo Descrs.push_back(EEDescr(VLd, 0)); 346e902c696Svporpo Descrs.push_back(EEDescr(VLd, 1)); 347e902c696Svporpo sandboxir::CollectDescr CD(std::move(Descrs)); 348e902c696Svporpo EXPECT_TRUE(CD.getSingleInput()); 349e902c696Svporpo EXPECT_EQ(CD.getSingleInput()->first, VLd); 35087e4b681Svporpo EXPECT_THAT(CD.getSingleInput()->second, testing::ElementsAre(0, 1)); 351e902c696Svporpo EXPECT_TRUE(CD.hasVectorInputs()); 352e902c696Svporpo } 353e902c696Svporpo { 354e902c696Svporpo // Check single input, shuffle. 355e902c696Svporpo Descrs.push_back(EEDescr(VLd, 1)); 356e902c696Svporpo Descrs.push_back(EEDescr(VLd, 0)); 357e902c696Svporpo sandboxir::CollectDescr CD(std::move(Descrs)); 358e902c696Svporpo EXPECT_TRUE(CD.getSingleInput()); 359e902c696Svporpo EXPECT_EQ(CD.getSingleInput()->first, VLd); 36087e4b681Svporpo EXPECT_THAT(CD.getSingleInput()->second, testing::ElementsAre(1, 0)); 361e902c696Svporpo EXPECT_TRUE(CD.hasVectorInputs()); 362e902c696Svporpo } 363e902c696Svporpo { 364e902c696Svporpo // Check multiple inputs. 365e902c696Svporpo Descrs.push_back(EEDescr(Ld0)); 366e902c696Svporpo Descrs.push_back(EEDescr(VLd, 0)); 367e902c696Svporpo Descrs.push_back(EEDescr(VLd, 1)); 368e902c696Svporpo sandboxir::CollectDescr CD(std::move(Descrs)); 369e902c696Svporpo EXPECT_FALSE(CD.getSingleInput()); 370e902c696Svporpo EXPECT_TRUE(CD.hasVectorInputs()); 371e902c696Svporpo } 372e902c696Svporpo { 373e902c696Svporpo // Check multiple inputs only scalars. 374e902c696Svporpo Descrs.push_back(EEDescr(Ld0)); 375e902c696Svporpo Descrs.push_back(EEDescr(Ld1)); 376e902c696Svporpo sandboxir::CollectDescr CD(std::move(Descrs)); 377e902c696Svporpo EXPECT_FALSE(CD.getSingleInput()); 378e902c696Svporpo EXPECT_FALSE(CD.hasVectorInputs()); 379e902c696Svporpo } 380e902c696Svporpo } 38187e4b681Svporpo 38287e4b681Svporpo TEST_F(LegalityTest, ShuffleMask) { 38387e4b681Svporpo { 38487e4b681Svporpo // Check SmallVector constructor. 38587e4b681Svporpo SmallVector<int> Indices({0, 1, 2, 3}); 38687e4b681Svporpo sandboxir::ShuffleMask Mask(std::move(Indices)); 38787e4b681Svporpo EXPECT_THAT(Mask, testing::ElementsAre(0, 1, 2, 3)); 38887e4b681Svporpo } 38987e4b681Svporpo { 39087e4b681Svporpo // Check initializer_list constructor. 39187e4b681Svporpo sandboxir::ShuffleMask Mask({0, 1, 2, 3}); 39287e4b681Svporpo EXPECT_THAT(Mask, testing::ElementsAre(0, 1, 2, 3)); 39387e4b681Svporpo } 39487e4b681Svporpo { 39587e4b681Svporpo // Check ArrayRef constructor. 39687e4b681Svporpo sandboxir::ShuffleMask Mask(ArrayRef<int>({0, 1, 2, 3})); 39787e4b681Svporpo EXPECT_THAT(Mask, testing::ElementsAre(0, 1, 2, 3)); 39887e4b681Svporpo } 39987e4b681Svporpo { 40087e4b681Svporpo // Check operator ArrayRef<int>(). 40187e4b681Svporpo sandboxir::ShuffleMask Mask({0, 1, 2, 3}); 40287e4b681Svporpo ArrayRef<int> Array = Mask; 40387e4b681Svporpo EXPECT_THAT(Array, testing::ElementsAre(0, 1, 2, 3)); 40487e4b681Svporpo } 40587e4b681Svporpo { 40687e4b681Svporpo // Check getIdentity(). 40787e4b681Svporpo auto IdentityMask = sandboxir::ShuffleMask::getIdentity(4); 40887e4b681Svporpo EXPECT_THAT(IdentityMask, testing::ElementsAre(0, 1, 2, 3)); 40987e4b681Svporpo EXPECT_TRUE(IdentityMask.isIdentity()); 41087e4b681Svporpo } 41187e4b681Svporpo { 41287e4b681Svporpo // Check isIdentity(). 41387e4b681Svporpo sandboxir::ShuffleMask Mask1({0, 1, 2, 3}); 41487e4b681Svporpo EXPECT_TRUE(Mask1.isIdentity()); 41587e4b681Svporpo sandboxir::ShuffleMask Mask2({1, 2, 3, 4}); 41687e4b681Svporpo EXPECT_FALSE(Mask2.isIdentity()); 41787e4b681Svporpo } 41887e4b681Svporpo { 41987e4b681Svporpo // Check operator==(). 42087e4b681Svporpo sandboxir::ShuffleMask Mask1({0, 1, 2, 3}); 42187e4b681Svporpo sandboxir::ShuffleMask Mask2({0, 1, 2, 3}); 42287e4b681Svporpo EXPECT_TRUE(Mask1 == Mask2); 42387e4b681Svporpo EXPECT_FALSE(Mask1 != Mask2); 42487e4b681Svporpo } 42587e4b681Svporpo { 42687e4b681Svporpo // Check operator!=(). 42787e4b681Svporpo sandboxir::ShuffleMask Mask1({0, 1, 2, 3}); 42887e4b681Svporpo sandboxir::ShuffleMask Mask2({0, 1, 2, 4}); 42987e4b681Svporpo EXPECT_TRUE(Mask1 != Mask2); 43087e4b681Svporpo EXPECT_FALSE(Mask1 == Mask2); 43187e4b681Svporpo } 43287e4b681Svporpo { 43387e4b681Svporpo // Check size(). 43487e4b681Svporpo sandboxir::ShuffleMask Mask({0, 1, 2, 3}); 43587e4b681Svporpo EXPECT_EQ(Mask.size(), 4u); 43687e4b681Svporpo } 43787e4b681Svporpo { 43887e4b681Svporpo // Check operator[]. 43987e4b681Svporpo sandboxir::ShuffleMask Mask({0, 1, 2, 3}); 44087e4b681Svporpo for (auto [Idx, Elm] : enumerate(Mask)) { 44187e4b681Svporpo EXPECT_EQ(Elm, Mask[Idx]); 44287e4b681Svporpo } 44387e4b681Svporpo } 44487e4b681Svporpo { 44587e4b681Svporpo // Check begin(), end(). 44687e4b681Svporpo sandboxir::ShuffleMask Mask({0, 1, 2, 3}); 44787e4b681Svporpo sandboxir::ShuffleMask::const_iterator Begin = Mask.begin(); 44887e4b681Svporpo sandboxir::ShuffleMask::const_iterator End = Mask.begin(); 44987e4b681Svporpo int Idx = 0; 45087e4b681Svporpo for (auto It = Begin; It != End; ++It) { 45187e4b681Svporpo EXPECT_EQ(*It, Mask[Idx++]); 45287e4b681Svporpo } 45387e4b681Svporpo } 45487e4b681Svporpo #ifndef NDEBUG 45587e4b681Svporpo { 45687e4b681Svporpo // Check print(OS). 45787e4b681Svporpo sandboxir::ShuffleMask Mask({0, 1, 2, 3}); 45887e4b681Svporpo std::string Str; 45987e4b681Svporpo raw_string_ostream OS(Str); 46087e4b681Svporpo Mask.print(OS); 46187e4b681Svporpo EXPECT_EQ(Str, "0,1,2,3"); 46287e4b681Svporpo } 46387e4b681Svporpo { 46487e4b681Svporpo // Check operator<<(). 46587e4b681Svporpo sandboxir::ShuffleMask Mask({0, 1, 2, 3}); 46687e4b681Svporpo std::string Str; 46787e4b681Svporpo raw_string_ostream OS(Str); 46887e4b681Svporpo OS << Mask; 46987e4b681Svporpo EXPECT_EQ(Str, "0,1,2,3"); 47087e4b681Svporpo } 47187e4b681Svporpo #endif // NDEBUG 47287e4b681Svporpo } 473