xref: /llvm-project/llvm/unittests/Transforms/Vectorize/SandboxVectorizer/LegalityTest.cpp (revision 6409799bdcd86be3ed72e8d172181294d3e5ad09)
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