xref: /llvm-project/llvm/unittests/Analysis/AssumeBundleQueriesTest.cpp (revision d22fbccfe251f5839d9df4c3bbbcc745163a28e9)
1 //===- AssumeBundleQueriesTest.cpp ------------------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "llvm/Analysis/AssumptionCache.h"
10 #include "llvm/Analysis/AssumeBundleQueries.h"
11 #include "llvm/AsmParser/Parser.h"
12 #include "llvm/IR/LLVMContext.h"
13 #include "llvm/IR/IntrinsicInst.h"
14 #include "llvm/Support/Regex.h"
15 #include "llvm/Support/SourceMgr.h"
16 #include "llvm/Support/CommandLine.h"
17 #include "llvm/Transforms/Utils/AssumeBundleBuilder.h"
18 #include "gtest/gtest.h"
19 #include <random>
20 
21 using namespace llvm;
22 
23 extern cl::opt<bool> ShouldPreserveAllAttributes;
24 extern cl::opt<bool> EnableKnowledgeRetention;
25 
26 static void RunTest(
27     StringRef Head, StringRef Tail,
28     std::vector<std::pair<StringRef, llvm::function_ref<void(Instruction *)>>>
29         &Tests) {
30   for (auto &Elem : Tests) {
31     std::string IR;
32     IR.append(Head.begin(), Head.end());
33     IR.append(Elem.first.begin(), Elem.first.end());
34     IR.append(Tail.begin(), Tail.end());
35     LLVMContext C;
36     SMDiagnostic Err;
37     std::unique_ptr<Module> Mod = parseAssemblyString(IR, Err, C);
38     if (!Mod)
39       Err.print("AssumeQueryAPI", errs());
40     Elem.second(&*(Mod->getFunction("test")->begin()->begin()));
41   }
42 }
43 
44 bool hasMatchesExactlyAttributes(IntrinsicInst *Assume, Value *WasOn,
45                                     StringRef AttrToMatch) {
46   Regex Reg(AttrToMatch);
47   SmallVector<StringRef, 1> Matches;
48   for (StringRef Attr : {
49 #define GET_ATTR_NAMES
50 #define ATTRIBUTE_ALL(ENUM_NAME, DISPLAY_NAME) StringRef(#DISPLAY_NAME),
51 #include "llvm/IR/Attributes.inc"
52        }) {
53     bool ShouldHaveAttr = Reg.match(Attr, &Matches) && Matches[0] == Attr;
54     if (ShouldHaveAttr != hasAttributeInAssume(*Assume, WasOn, Attr))
55       return false;
56   }
57   return true;
58 }
59 
60 bool hasTheRightValue(IntrinsicInst *Assume, Value *WasOn,
61                       Attribute::AttrKind Kind, unsigned Value) {
62   uint64_t ArgVal = 0;
63   if (!hasAttributeInAssume(*Assume, WasOn, Kind, &ArgVal))
64     return false;
65   if (ArgVal != Value)
66     return false;
67   return true;
68 }
69 
70 TEST(AssumeQueryAPI, hasAttributeInAssume) {
71   EnableKnowledgeRetention.setValue(true);
72   StringRef Head =
73       "declare void @llvm.assume(i1)\n"
74       "declare void @func(i32*, i32*)\n"
75       "declare void @func1(i32*, i32*, i32*, i32*)\n"
76       "declare void @func_many(i32*) \"no-jump-tables\" nounwind "
77       "\"less-precise-fpmad\" willreturn norecurse\n"
78       "define void @test(i32* %P, i32* %P1, i32* %P2, i32* %P3) {\n";
79   StringRef Tail = "ret void\n"
80                    "}";
81   std::vector<std::pair<StringRef, llvm::function_ref<void(Instruction *)>>>
82       Tests;
83   Tests.push_back(std::make_pair(
84       "call void @func(i32* nonnull align 4 dereferenceable(16) %P, i32* align "
85       "8 noalias %P1)\n",
86       [](Instruction *I) {
87         IntrinsicInst *Assume = buildAssumeFromInst(I);
88         Assume->insertBefore(I);
89         ASSERT_TRUE(hasMatchesExactlyAttributes(Assume, I->getOperand(0),
90                                        "(nonnull|align|dereferenceable)"));
91         ASSERT_TRUE(hasMatchesExactlyAttributes(Assume, I->getOperand(1),
92                                        "(align)"));
93         ASSERT_TRUE(hasTheRightValue(Assume, I->getOperand(0),
94                                      Attribute::AttrKind::Dereferenceable, 16));
95         ASSERT_TRUE(hasTheRightValue(Assume, I->getOperand(0),
96                                      Attribute::AttrKind::Alignment, 4));
97         ASSERT_TRUE(hasTheRightValue(Assume, I->getOperand(0),
98                                      Attribute::AttrKind::Alignment, 4));
99       }));
100   Tests.push_back(std::make_pair(
101       "call void @func1(i32* nonnull align 32 dereferenceable(48) %P, i32* "
102       "nonnull "
103       "align 8 dereferenceable(28) %P, i32* nonnull align 64 "
104       "dereferenceable(4) "
105       "%P, i32* nonnull align 16 dereferenceable(12) %P)\n",
106       [](Instruction *I) {
107         IntrinsicInst *Assume = buildAssumeFromInst(I);
108         Assume->insertBefore(I);
109         ASSERT_TRUE(hasMatchesExactlyAttributes(Assume, I->getOperand(0),
110                                        "(nonnull|align|dereferenceable)"));
111         ASSERT_TRUE(hasMatchesExactlyAttributes(Assume, I->getOperand(1),
112                                        "(nonnull|align|dereferenceable)"));
113         ASSERT_TRUE(hasMatchesExactlyAttributes(Assume, I->getOperand(2),
114                                        "(nonnull|align|dereferenceable)"));
115         ASSERT_TRUE(hasMatchesExactlyAttributes(Assume, I->getOperand(3),
116                                        "(nonnull|align|dereferenceable)"));
117         ASSERT_TRUE(hasTheRightValue(Assume, I->getOperand(0),
118                                      Attribute::AttrKind::Dereferenceable, 48));
119         ASSERT_TRUE(hasTheRightValue(Assume, I->getOperand(0),
120                                      Attribute::AttrKind::Alignment, 64));
121         ASSERT_TRUE(hasTheRightValue(Assume, I->getOperand(1),
122                                      Attribute::AttrKind::Alignment, 64));
123       }));
124   Tests.push_back(std::make_pair(
125       "call void @func_many(i32* align 8 %P1) cold\n", [](Instruction *I) {
126         ShouldPreserveAllAttributes.setValue(true);
127         IntrinsicInst *Assume = buildAssumeFromInst(I);
128         Assume->insertBefore(I);
129         ASSERT_TRUE(hasMatchesExactlyAttributes(
130             Assume, nullptr, "(align|nounwind|norecurse|willreturn|cold)"));
131         ShouldPreserveAllAttributes.setValue(false);
132       }));
133   Tests.push_back(
134       std::make_pair("call void @llvm.assume(i1 true)\n", [](Instruction *I) {
135         IntrinsicInst *Assume = cast<IntrinsicInst>(I);
136         ASSERT_TRUE(hasMatchesExactlyAttributes(Assume, nullptr, ""));
137       }));
138   Tests.push_back(std::make_pair(
139       "call void @func1(i32* readnone align 32 "
140       "dereferenceable(48) noalias %P, i32* "
141       "align 8 dereferenceable(28) %P1, i32* align 64 "
142       "dereferenceable(4) "
143       "%P2, i32* nonnull align 16 dereferenceable(12) %P3)\n",
144       [](Instruction *I) {
145         IntrinsicInst *Assume = buildAssumeFromInst(I);
146         Assume->insertBefore(I);
147         ASSERT_TRUE(hasMatchesExactlyAttributes(
148             Assume, I->getOperand(0),
149             "(align|dereferenceable)"));
150         ASSERT_TRUE(hasMatchesExactlyAttributes(Assume, I->getOperand(1),
151                                        "(align|dereferenceable)"));
152         ASSERT_TRUE(hasMatchesExactlyAttributes(Assume, I->getOperand(2),
153                                        "(align|dereferenceable)"));
154         ASSERT_TRUE(hasMatchesExactlyAttributes(Assume, I->getOperand(3),
155                                        "(nonnull|align|dereferenceable)"));
156         ASSERT_TRUE(hasTheRightValue(Assume, I->getOperand(0),
157                                      Attribute::AttrKind::Alignment, 32));
158         ASSERT_TRUE(hasTheRightValue(Assume, I->getOperand(0),
159                                      Attribute::AttrKind::Dereferenceable, 48));
160         ASSERT_TRUE(hasTheRightValue(Assume, I->getOperand(1),
161                                      Attribute::AttrKind::Dereferenceable, 28));
162         ASSERT_TRUE(hasTheRightValue(Assume, I->getOperand(1),
163                                      Attribute::AttrKind::Alignment, 8));
164         ASSERT_TRUE(hasTheRightValue(Assume, I->getOperand(2),
165                                      Attribute::AttrKind::Alignment, 64));
166         ASSERT_TRUE(hasTheRightValue(Assume, I->getOperand(2),
167                                      Attribute::AttrKind::Dereferenceable, 4));
168         ASSERT_TRUE(hasTheRightValue(Assume, I->getOperand(3),
169                                      Attribute::AttrKind::Alignment, 16));
170         ASSERT_TRUE(hasTheRightValue(Assume, I->getOperand(3),
171                                      Attribute::AttrKind::Dereferenceable, 12));
172       }));
173 
174   Tests.push_back(std::make_pair(
175       "call void @func1(i32* readnone align 32 "
176       "dereferenceable(48) noalias %P, i32* "
177       "align 8 dereferenceable(28) %P1, i32* align 64 "
178       "dereferenceable(4) "
179       "%P2, i32* nonnull align 16 dereferenceable(12) %P3)\n",
180       [](Instruction *I) {
181         IntrinsicInst *Assume = buildAssumeFromInst(I);
182         Assume->insertBefore(I);
183         I->getOperand(1)->dropDroppableUses();
184         I->getOperand(2)->dropDroppableUses();
185         I->getOperand(3)->dropDroppableUses();
186         ASSERT_TRUE(hasMatchesExactlyAttributes(
187             Assume, I->getOperand(0),
188             "(align|dereferenceable)"));
189         ASSERT_TRUE(hasMatchesExactlyAttributes(Assume, I->getOperand(1),
190                                        ""));
191         ASSERT_TRUE(hasMatchesExactlyAttributes(Assume, I->getOperand(2),
192                                        ""));
193         ASSERT_TRUE(hasMatchesExactlyAttributes(Assume, I->getOperand(3),
194                                        ""));
195         ASSERT_TRUE(hasTheRightValue(Assume, I->getOperand(0),
196                                      Attribute::AttrKind::Alignment, 32));
197         ASSERT_TRUE(hasTheRightValue(Assume, I->getOperand(0),
198                                      Attribute::AttrKind::Dereferenceable, 48));
199       }));
200   Tests.push_back(std::make_pair(
201       "call void @func(i32* nonnull align 4 dereferenceable(16) %P, i32* align "
202       "8 noalias %P1)\n",
203       [](Instruction *I) {
204         IntrinsicInst *Assume = buildAssumeFromInst(I);
205         Assume->insertBefore(I);
206         Value *New = I->getFunction()->getArg(3);
207         Value *Old = I->getOperand(0);
208         ASSERT_TRUE(hasMatchesExactlyAttributes(Assume, New, ""));
209         ASSERT_TRUE(hasMatchesExactlyAttributes(Assume, Old,
210                                        "(nonnull|align|dereferenceable)"));
211         Old->replaceAllUsesWith(New);
212         ASSERT_TRUE(hasMatchesExactlyAttributes(Assume, New,
213                                        "(nonnull|align|dereferenceable)"));
214         ASSERT_TRUE(hasMatchesExactlyAttributes(Assume, Old, ""));
215       }));
216   RunTest(Head, Tail, Tests);
217 }
218 
219 static bool FindExactlyAttributes(RetainedKnowledgeMap &Map, Value *WasOn,
220                                  StringRef AttrToMatch) {
221   Regex Reg(AttrToMatch);
222   SmallVector<StringRef, 1> Matches;
223   for (StringRef Attr : {
224 #define GET_ATTR_NAMES
225 #define ATTRIBUTE_ENUM(ENUM_NAME, DISPLAY_NAME) StringRef(#DISPLAY_NAME),
226 #include "llvm/IR/Attributes.inc"
227        }) {
228     bool ShouldHaveAttr = Reg.match(Attr, &Matches) && Matches[0] == Attr;
229 
230     if (ShouldHaveAttr != (Map.find(RetainedKnowledgeKey{WasOn, Attribute::getAttrKindFromName(Attr)}) != Map.end()))
231       return false;
232   }
233   return true;
234 }
235 
236 static bool MapHasRightValue(RetainedKnowledgeMap &Map, IntrinsicInst *II,
237                              RetainedKnowledgeKey Key, MinMax MM) {
238   auto LookupIt = Map.find(Key);
239   return (LookupIt != Map.end()) && (LookupIt->second[II].Min == MM.Min) &&
240          (LookupIt->second[II].Max == MM.Max);
241 }
242 
243 TEST(AssumeQueryAPI, fillMapFromAssume) {
244   EnableKnowledgeRetention.setValue(true);
245   StringRef Head =
246       "declare void @llvm.assume(i1)\n"
247       "declare void @func(i32*, i32*)\n"
248       "declare void @func1(i32*, i32*, i32*, i32*)\n"
249       "declare void @func_many(i32*) \"no-jump-tables\" nounwind "
250       "\"less-precise-fpmad\" willreturn norecurse\n"
251       "define void @test(i32* %P, i32* %P1, i32* %P2, i32* %P3) {\n";
252   StringRef Tail = "ret void\n"
253                    "}";
254   std::vector<std::pair<StringRef, llvm::function_ref<void(Instruction *)>>>
255       Tests;
256   Tests.push_back(std::make_pair(
257       "call void @func(i32* nonnull align 4 dereferenceable(16) %P, i32* align "
258       "8 noalias %P1)\n",
259       [](Instruction *I) {
260         IntrinsicInst *Assume = buildAssumeFromInst(I);
261         Assume->insertBefore(I);
262 
263         RetainedKnowledgeMap Map;
264         fillMapFromAssume(*Assume, Map);
265         ASSERT_TRUE(FindExactlyAttributes(Map, I->getOperand(0),
266                                        "(nonnull|align|dereferenceable)"));
267         ASSERT_TRUE(FindExactlyAttributes(Map, I->getOperand(1),
268                                        "(align)"));
269         ASSERT_TRUE(MapHasRightValue(
270             Map, Assume, {I->getOperand(0), Attribute::Dereferenceable}, {16, 16}));
271         ASSERT_TRUE(MapHasRightValue(Map, Assume, {I->getOperand(0), Attribute::Alignment},
272                                {4, 4}));
273         ASSERT_TRUE(MapHasRightValue(Map, Assume, {I->getOperand(0), Attribute::Alignment},
274                                {4, 4}));
275       }));
276   Tests.push_back(std::make_pair(
277       "call void @func1(i32* nonnull align 32 dereferenceable(48) %P, i32* "
278       "nonnull "
279       "align 8 dereferenceable(28) %P, i32* nonnull align 64 "
280       "dereferenceable(4) "
281       "%P, i32* nonnull align 16 dereferenceable(12) %P)\n",
282       [](Instruction *I) {
283         IntrinsicInst *Assume = buildAssumeFromInst(I);
284         Assume->insertBefore(I);
285 
286         RetainedKnowledgeMap Map;
287         fillMapFromAssume(*Assume, Map);
288 
289         ASSERT_TRUE(FindExactlyAttributes(Map, I->getOperand(0),
290                                        "(nonnull|align|dereferenceable)"));
291         ASSERT_TRUE(FindExactlyAttributes(Map, I->getOperand(1),
292                                        "(nonnull|align|dereferenceable)"));
293         ASSERT_TRUE(FindExactlyAttributes(Map, I->getOperand(2),
294                                        "(nonnull|align|dereferenceable)"));
295         ASSERT_TRUE(FindExactlyAttributes(Map, I->getOperand(3),
296                                        "(nonnull|align|dereferenceable)"));
297         ASSERT_TRUE(MapHasRightValue(
298             Map, Assume, {I->getOperand(0), Attribute::Dereferenceable},
299             {48, 48}));
300         ASSERT_TRUE(MapHasRightValue(
301             Map, Assume, {I->getOperand(0), Attribute::Alignment}, {64, 64}));
302       }));
303   Tests.push_back(std::make_pair(
304       "call void @func_many(i32* align 8 %P1) cold\n", [](Instruction *I) {
305         ShouldPreserveAllAttributes.setValue(true);
306         IntrinsicInst *Assume = buildAssumeFromInst(I);
307         Assume->insertBefore(I);
308 
309         RetainedKnowledgeMap Map;
310         fillMapFromAssume(*Assume, Map);
311 
312         ASSERT_TRUE(FindExactlyAttributes(
313             Map, nullptr, "(nounwind|norecurse|willreturn|cold)"));
314         ShouldPreserveAllAttributes.setValue(false);
315       }));
316   Tests.push_back(
317       std::make_pair("call void @llvm.assume(i1 true)\n", [](Instruction *I) {
318         RetainedKnowledgeMap Map;
319         fillMapFromAssume(*cast<IntrinsicInst>(I), Map);
320 
321         ASSERT_TRUE(FindExactlyAttributes(Map, nullptr, ""));
322         ASSERT_TRUE(Map.empty());
323       }));
324   Tests.push_back(std::make_pair(
325       "call void @func1(i32* readnone align 32 "
326       "dereferenceable(48) noalias %P, i32* "
327       "align 8 dereferenceable(28) %P1, i32* align 64 "
328       "dereferenceable(4) "
329       "%P2, i32* nonnull align 16 dereferenceable(12) %P3)\n",
330       [](Instruction *I) {
331         IntrinsicInst *Assume = buildAssumeFromInst(I);
332         Assume->insertBefore(I);
333 
334         RetainedKnowledgeMap Map;
335         fillMapFromAssume(*Assume, Map);
336 
337         ASSERT_TRUE(FindExactlyAttributes(Map, I->getOperand(0),
338                                     "(align|dereferenceable)"));
339         ASSERT_TRUE(FindExactlyAttributes(Map, I->getOperand(1),
340                                     "(align|dereferenceable)"));
341         ASSERT_TRUE(FindExactlyAttributes(Map, I->getOperand(2),
342                                        "(align|dereferenceable)"));
343         ASSERT_TRUE(FindExactlyAttributes(Map, I->getOperand(3),
344                                        "(nonnull|align|dereferenceable)"));
345         ASSERT_TRUE(MapHasRightValue(Map, Assume, {I->getOperand(0), Attribute::Alignment},
346                                {32, 32}));
347         ASSERT_TRUE(MapHasRightValue(
348             Map, Assume, {I->getOperand(0), Attribute::Dereferenceable}, {48, 48}));
349         ASSERT_TRUE(MapHasRightValue(
350             Map, Assume, {I->getOperand(1), Attribute::Dereferenceable}, {28, 28}));
351         ASSERT_TRUE(MapHasRightValue(Map, Assume, {I->getOperand(1), Attribute::Alignment},
352                                {8, 8}));
353         ASSERT_TRUE(MapHasRightValue(Map, Assume, {I->getOperand(2), Attribute::Alignment},
354                                {64, 64}));
355         ASSERT_TRUE(MapHasRightValue(
356             Map, Assume, {I->getOperand(2), Attribute::Dereferenceable}, {4, 4}));
357         ASSERT_TRUE(MapHasRightValue(Map, Assume, {I->getOperand(3), Attribute::Alignment},
358                                {16, 16}));
359         ASSERT_TRUE(MapHasRightValue(
360             Map, Assume, {I->getOperand(3), Attribute::Dereferenceable}, {12, 12}));
361       }));
362 
363   /// Keep this test last as it modifies the function.
364   Tests.push_back(std::make_pair(
365       "call void @func(i32* nonnull align 4 dereferenceable(16) %P, i32* align "
366       "8 noalias %P1)\n",
367       [](Instruction *I) {
368         IntrinsicInst *Assume = buildAssumeFromInst(I);
369         Assume->insertBefore(I);
370 
371         RetainedKnowledgeMap Map;
372         fillMapFromAssume(*Assume, Map);
373 
374         Value *New = I->getFunction()->getArg(3);
375         Value *Old = I->getOperand(0);
376         ASSERT_TRUE(FindExactlyAttributes(Map, New, ""));
377         ASSERT_TRUE(FindExactlyAttributes(Map, Old,
378                                        "(nonnull|align|dereferenceable)"));
379         Old->replaceAllUsesWith(New);
380         Map.clear();
381         fillMapFromAssume(*Assume, Map);
382         ASSERT_TRUE(FindExactlyAttributes(Map, New,
383                                        "(nonnull|align|dereferenceable)"));
384         ASSERT_TRUE(FindExactlyAttributes(Map, Old, ""));
385       }));
386   Tests.push_back(std::make_pair(
387       "call void @llvm.assume(i1 true) [\"align\"(i8* undef, i32 undef)]",
388       [](Instruction *I) {
389         // Don't crash but don't learn from undef.
390         RetainedKnowledgeMap Map;
391         fillMapFromAssume(*cast<IntrinsicInst>(I), Map);
392 
393         ASSERT_TRUE(Map.empty());
394       }));
395   RunTest(Head, Tail, Tests);
396 }
397 
398 static void RunRandTest(uint64_t Seed, int Size, int MinCount, int MaxCount,
399                         unsigned MaxValue) {
400   LLVMContext C;
401   SMDiagnostic Err;
402 
403   std::random_device dev;
404   std::mt19937 Rng(Seed);
405   std::uniform_int_distribution<int> DistCount(MinCount, MaxCount);
406   std::uniform_int_distribution<unsigned> DistValue(0, MaxValue);
407   std::uniform_int_distribution<unsigned> DistAttr(0,
408                                                    Attribute::EndAttrKinds - 1);
409 
410   std::unique_ptr<Module> Mod = std::make_unique<Module>("AssumeQueryAPI", C);
411   if (!Mod)
412     Err.print("AssumeQueryAPI", errs());
413 
414   std::vector<Type *> TypeArgs;
415   for (int i = 0; i < (Size * 2); i++)
416     TypeArgs.push_back(Type::getInt32PtrTy(C));
417   FunctionType *FuncType =
418       FunctionType::get(Type::getVoidTy(C), TypeArgs, false);
419 
420   Function *F =
421       Function::Create(FuncType, GlobalValue::ExternalLinkage, "test", &*Mod);
422   BasicBlock *BB = BasicBlock::Create(C);
423   BB->insertInto(F);
424   Instruction *Ret = ReturnInst::Create(C);
425   BB->getInstList().insert(BB->begin(), Ret);
426   Function *FnAssume = Intrinsic::getDeclaration(Mod.get(), Intrinsic::assume);
427 
428   std::vector<Argument *> ShuffledArgs;
429   std::vector<bool> HasArg;
430   for (auto &Arg : F->args()) {
431     ShuffledArgs.push_back(&Arg);
432     HasArg.push_back(false);
433   }
434 
435   std::shuffle(ShuffledArgs.begin(), ShuffledArgs.end(), Rng);
436 
437   std::vector<OperandBundleDef> OpBundle;
438   OpBundle.reserve(Size);
439   std::vector<Value *> Args;
440   Args.reserve(2);
441   for (int i = 0; i < Size; i++) {
442     int count = DistCount(Rng);
443     int value = DistValue(Rng);
444     int attr = DistAttr(Rng);
445     std::string str;
446     raw_string_ostream ss(str);
447     ss << Attribute::getNameFromAttrKind(
448         static_cast<Attribute::AttrKind>(attr));
449     Args.clear();
450 
451     if (count > 0) {
452       Args.push_back(ShuffledArgs[i]);
453       HasArg[i] = true;
454     }
455     if (count > 1)
456       Args.push_back(ConstantInt::get(Type::getInt32Ty(C), value));
457 
458     OpBundle.push_back(OperandBundleDef{ss.str().c_str(), std::move(Args)});
459   }
460 
461   auto *Assume = cast<IntrinsicInst>(IntrinsicInst::Create(
462       FnAssume, ArrayRef<Value *>({ConstantInt::getTrue(C)}), OpBundle));
463   Assume->insertBefore(&F->begin()->front());
464   RetainedKnowledgeMap Map;
465   fillMapFromAssume(*Assume, Map);
466   for (int i = 0; i < (Size * 2); i++) {
467     if (!HasArg[i])
468       continue;
469     RetainedKnowledge K =
470         getKnowledgeFromUseInAssume(&*ShuffledArgs[i]->use_begin());
471     auto LookupIt = Map.find(RetainedKnowledgeKey{K.WasOn, K.AttrKind});
472     ASSERT_TRUE(LookupIt != Map.end());
473     MinMax MM = LookupIt->second[Assume];
474     ASSERT_TRUE(MM.Min == MM.Max);
475     ASSERT_TRUE(MM.Min == K.ArgValue);
476   }
477 }
478 
479 TEST(AssumeQueryAPI, getKnowledgeFromUseInAssume) {
480   // // For Fuzzing
481   // std::random_device dev;
482   // std::mt19937 Rng(dev());
483   // while (true) {
484   //   unsigned Seed = Rng();
485   //   dbgs() << Seed << "\n";
486   //   RunRandTest(Seed, 100000, 0, 2, 100);
487   // }
488   RunRandTest(23456, 4, 0, 2, 100);
489   RunRandTest(560987, 25, -3, 2, 100);
490 
491   // Large bundles can lead to special cases. this is why this test is soo
492   // large.
493   RunRandTest(9876789, 100000, -0, 7, 100);
494 }
495 
496 TEST(AssumeQueryAPI, AssumptionCache) {
497   LLVMContext C;
498   SMDiagnostic Err;
499   std::unique_ptr<Module> Mod = parseAssemblyString(
500       "declare void @llvm.assume(i1)\n"
501       "define void @test(i32* %P, i32* %P1, i32* %P2, i32* %P3, i1 %B) {\n"
502       "call void @llvm.assume(i1 true) [\"nonnull\"(i32* %P), \"align\"(i32* "
503       "%P2, i32 4), \"align\"(i32* %P, i32 8)]\n"
504       "call void @llvm.assume(i1 %B) [\"test\"(i32* %P1), "
505       "\"dereferenceable\"(i32* %P, i32 4)]\n"
506       "ret void\n}\n",
507       Err, C);
508   if (!Mod)
509     Err.print("AssumeQueryAPI", errs());
510   Function *F = Mod->getFunction("test");
511   BasicBlock::iterator First = F->begin()->begin();
512   BasicBlock::iterator Second = F->begin()->begin();
513   Second++;
514   AssumptionCacheTracker ACT;
515   AssumptionCache &AC = ACT.getAssumptionCache(*F);
516   auto AR = AC.assumptionsFor(F->getArg(3));
517   ASSERT_EQ(AR.size(), 0u);
518   AR = AC.assumptionsFor(F->getArg(1));
519   ASSERT_EQ(AR.size(), 1u);
520   ASSERT_EQ(AR[0].Index, 0u);
521   ASSERT_EQ(AR[0].Assume, &*Second);
522   AR = AC.assumptionsFor(F->getArg(2));
523   ASSERT_EQ(AR.size(), 1u);
524   ASSERT_EQ(AR[0].Index, 1u);
525   ASSERT_EQ(AR[0].Assume, &*First);
526   AR = AC.assumptionsFor(F->getArg(0));
527   ASSERT_EQ(AR.size(), 3u);
528   llvm::sort(AR,
529              [](const auto &L, const auto &R) { return L.Index < R.Index; });
530   ASSERT_EQ(AR[0].Assume, &*First);
531   ASSERT_EQ(AR[0].Index, 0u);
532   ASSERT_EQ(AR[1].Assume, &*Second);
533   ASSERT_EQ(AR[1].Index, 1u);
534   ASSERT_EQ(AR[2].Assume, &*First);
535   ASSERT_EQ(AR[2].Index, 2u);
536   AR = AC.assumptionsFor(F->getArg(4));
537   ASSERT_EQ(AR.size(), 1u);
538   ASSERT_EQ(AR[0].Assume, &*Second);
539   ASSERT_EQ(AR[0].Index, AssumptionCache::ExprResultIdx);
540   AC.unregisterAssumption(cast<CallInst>(&*Second));
541   AR = AC.assumptionsFor(F->getArg(1));
542   ASSERT_EQ(AR.size(), 0u);
543   AR = AC.assumptionsFor(F->getArg(0));
544   ASSERT_EQ(AR.size(), 3u);
545   llvm::sort(AR,
546              [](const auto &L, const auto &R) { return L.Index < R.Index; });
547   ASSERT_EQ(AR[0].Assume, &*First);
548   ASSERT_EQ(AR[0].Index, 0u);
549   ASSERT_EQ(AR[1].Assume, nullptr);
550   ASSERT_EQ(AR[1].Index, 1u);
551   ASSERT_EQ(AR[2].Assume, &*First);
552   ASSERT_EQ(AR[2].Index, 2u);
553   AR = AC.assumptionsFor(F->getArg(2));
554   ASSERT_EQ(AR.size(), 1u);
555   ASSERT_EQ(AR[0].Index, 1u);
556   ASSERT_EQ(AR[0].Assume, &*First);
557 }
558 
559 TEST(AssumeQueryAPI, Alignment) {
560   LLVMContext C;
561   SMDiagnostic Err;
562   std::unique_ptr<Module> Mod = parseAssemblyString(
563       "declare void @llvm.assume(i1)\n"
564       "define void @test(i32* %P, i32* %P1, i32* %P2, i32 %I3, i1 %B) {\n"
565       "call void @llvm.assume(i1 true) [\"align\"(i32* %P, i32 8, i32 %I3)]\n"
566       "call void @llvm.assume(i1 true) [\"align\"(i32* %P1, i32 %I3, i32 "
567       "%I3)]\n"
568       "call void @llvm.assume(i1 true) [\"align\"(i32* %P2, i32 16, i32 8)]\n"
569       "ret void\n}\n",
570       Err, C);
571   if (!Mod)
572     Err.print("AssumeQueryAPI", errs());
573 
574   Function *F = Mod->getFunction("test");
575   BasicBlock::iterator Start = F->begin()->begin();
576   IntrinsicInst *II;
577   RetainedKnowledge RK;
578   II = cast<IntrinsicInst>(&*Start);
579   RK = getKnowledgeFromBundle(*II, II->bundle_op_info_begin()[0]);
580   ASSERT_EQ(RK.AttrKind, Attribute::Alignment);
581   ASSERT_EQ(RK.WasOn, F->getArg(0));
582   ASSERT_EQ(RK.ArgValue, 1u);
583   Start++;
584   II = cast<IntrinsicInst>(&*Start);
585   RK = getKnowledgeFromBundle(*II, II->bundle_op_info_begin()[0]);
586   ASSERT_EQ(RK.AttrKind, Attribute::Alignment);
587   ASSERT_EQ(RK.WasOn, F->getArg(1));
588   ASSERT_EQ(RK.ArgValue, 1u);
589   Start++;
590   II = cast<IntrinsicInst>(&*Start);
591   RK = getKnowledgeFromBundle(*II, II->bundle_op_info_begin()[0]);
592   ASSERT_EQ(RK.AttrKind, Attribute::Alignment);
593   ASSERT_EQ(RK.WasOn, F->getArg(2));
594   ASSERT_EQ(RK.ArgValue, 8u);
595 }
596