xref: /llvm-project/llvm/unittests/Analysis/AssumeBundleQueriesTest.cpp (revision c00cb76274fdcc529335f55b0d19e6bc42ea9d8d)
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/AssumeBundleQueries.h"
10 #include "llvm/AsmParser/Parser.h"
11 #include "llvm/IR/CallSite.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, bool Both,
62                             AssumeQuery AQ = AssumeQuery::Highest) {
63   if (!Both) {
64     uint64_t ArgVal = 0;
65     if (!hasAttributeInAssume(*Assume, WasOn, Kind, &ArgVal, AQ))
66       return false;
67     if (ArgVal != Value)
68       return false;
69     return true;
70   }
71   uint64_t ArgValLow = 0;
72   uint64_t ArgValHigh = 0;
73   bool ResultLow = hasAttributeInAssume(*Assume, WasOn, Kind, &ArgValLow,
74                                         AssumeQuery::Lowest);
75   bool ResultHigh = hasAttributeInAssume(*Assume, WasOn, Kind, &ArgValHigh,
76                                          AssumeQuery::Highest);
77   if (ResultLow != ResultHigh || ResultHigh == false)
78     return false;
79   if (ArgValLow != Value || ArgValLow != ArgValHigh)
80     return false;
81   return true;
82 }
83 
84 TEST(AssumeQueryAPI, hasAttributeInAssume) {
85   EnableKnowledgeRetention.setValue(true);
86   StringRef Head =
87       "declare void @llvm.assume(i1)\n"
88       "declare void @func(i32*, i32*)\n"
89       "declare void @func1(i32*, i32*, i32*, i32*)\n"
90       "declare void @func_many(i32*) \"no-jump-tables\" nounwind "
91       "\"less-precise-fpmad\" willreturn norecurse\n"
92       "define void @test(i32* %P, i32* %P1, i32* %P2, i32* %P3) {\n";
93   StringRef Tail = "ret void\n"
94                    "}";
95   std::vector<std::pair<StringRef, llvm::function_ref<void(Instruction *)>>>
96       Tests;
97   Tests.push_back(std::make_pair(
98       "call void @func(i32* nonnull align 4 dereferenceable(16) %P, i32* align "
99       "8 noalias %P1)\n",
100       [](Instruction *I) {
101         IntrinsicInst *Assume = buildAssumeFromInst(I);
102         Assume->insertBefore(I);
103         ASSERT_TRUE(hasMatchesExactlyAttributes(Assume, I->getOperand(0),
104                                        "(nonnull|align|dereferenceable)"));
105         ASSERT_TRUE(hasMatchesExactlyAttributes(Assume, I->getOperand(1),
106                                        "(align)"));
107         ASSERT_TRUE(hasTheRightValue(Assume, I->getOperand(0),
108                                Attribute::AttrKind::Dereferenceable, 16, true));
109         ASSERT_TRUE(hasTheRightValue(Assume, I->getOperand(0),
110                                Attribute::AttrKind::Alignment, 4, true));
111         ASSERT_TRUE(hasTheRightValue(Assume, I->getOperand(0),
112                                Attribute::AttrKind::Alignment, 4, true));
113       }));
114   Tests.push_back(std::make_pair(
115       "call void @func1(i32* nonnull align 32 dereferenceable(48) %P, i32* "
116       "nonnull "
117       "align 8 dereferenceable(28) %P, i32* nonnull align 64 "
118       "dereferenceable(4) "
119       "%P, i32* nonnull align 16 dereferenceable(12) %P)\n",
120       [](Instruction *I) {
121         IntrinsicInst *Assume = buildAssumeFromInst(I);
122         Assume->insertBefore(I);
123         ASSERT_TRUE(hasMatchesExactlyAttributes(Assume, I->getOperand(0),
124                                        "(nonnull|align|dereferenceable)"));
125         ASSERT_TRUE(hasMatchesExactlyAttributes(Assume, I->getOperand(1),
126                                        "(nonnull|align|dereferenceable)"));
127         ASSERT_TRUE(hasMatchesExactlyAttributes(Assume, I->getOperand(2),
128                                        "(nonnull|align|dereferenceable)"));
129         ASSERT_TRUE(hasMatchesExactlyAttributes(Assume, I->getOperand(3),
130                                        "(nonnull|align|dereferenceable)"));
131         ASSERT_TRUE(hasTheRightValue(Assume, I->getOperand(0),
132                                Attribute::AttrKind::Dereferenceable, 48, false,
133                                AssumeQuery::Highest));
134         ASSERT_TRUE(hasTheRightValue(Assume, I->getOperand(0),
135                                Attribute::AttrKind::Alignment, 64, false,
136                                AssumeQuery::Highest));
137         ASSERT_TRUE(hasTheRightValue(Assume, I->getOperand(1),
138                                Attribute::AttrKind::Alignment, 64, false,
139                                AssumeQuery::Highest));
140         ASSERT_TRUE(hasTheRightValue(Assume, I->getOperand(0),
141                                Attribute::AttrKind::Dereferenceable, 4, false,
142                                AssumeQuery::Lowest));
143         ASSERT_TRUE(hasTheRightValue(Assume, I->getOperand(0),
144                                Attribute::AttrKind::Alignment, 8, false,
145                                AssumeQuery::Lowest));
146         ASSERT_TRUE(hasTheRightValue(Assume, I->getOperand(1),
147                                Attribute::AttrKind::Alignment, 8, false,
148                                AssumeQuery::Lowest));
149       }));
150   Tests.push_back(std::make_pair(
151       "call void @func_many(i32* align 8 %P1) cold\n", [](Instruction *I) {
152         ShouldPreserveAllAttributes.setValue(true);
153         IntrinsicInst *Assume = buildAssumeFromInst(I);
154         Assume->insertBefore(I);
155         ASSERT_TRUE(hasMatchesExactlyAttributes(
156             Assume, nullptr,
157             "(align|no-jump-tables|less-precise-fpmad|"
158             "nounwind|norecurse|willreturn|cold)"));
159         ShouldPreserveAllAttributes.setValue(false);
160       }));
161   Tests.push_back(
162       std::make_pair("call void @llvm.assume(i1 true)\n", [](Instruction *I) {
163         IntrinsicInst *Assume = cast<IntrinsicInst>(I);
164         ASSERT_TRUE(hasMatchesExactlyAttributes(Assume, nullptr, ""));
165       }));
166   Tests.push_back(std::make_pair(
167       "call void @func1(i32* readnone align 32 "
168       "dereferenceable(48) noalias %P, i32* "
169       "align 8 dereferenceable(28) %P1, i32* align 64 "
170       "dereferenceable(4) "
171       "%P2, i32* nonnull align 16 dereferenceable(12) %P3)\n",
172       [](Instruction *I) {
173         IntrinsicInst *Assume = buildAssumeFromInst(I);
174         Assume->insertBefore(I);
175         ASSERT_TRUE(hasMatchesExactlyAttributes(
176             Assume, I->getOperand(0),
177             "(align|dereferenceable)"));
178         ASSERT_TRUE(hasMatchesExactlyAttributes(Assume, I->getOperand(1),
179                                        "(align|dereferenceable)"));
180         ASSERT_TRUE(hasMatchesExactlyAttributes(Assume, I->getOperand(2),
181                                        "(align|dereferenceable)"));
182         ASSERT_TRUE(hasMatchesExactlyAttributes(Assume, I->getOperand(3),
183                                        "(nonnull|align|dereferenceable)"));
184         ASSERT_TRUE(hasTheRightValue(Assume, I->getOperand(0),
185                                Attribute::AttrKind::Alignment, 32, true));
186         ASSERT_TRUE(hasTheRightValue(Assume, I->getOperand(0),
187                                Attribute::AttrKind::Dereferenceable, 48, true));
188         ASSERT_TRUE(hasTheRightValue(Assume, I->getOperand(1),
189                                Attribute::AttrKind::Dereferenceable, 28, true));
190         ASSERT_TRUE(hasTheRightValue(Assume, I->getOperand(1),
191                                Attribute::AttrKind::Alignment, 8, true));
192         ASSERT_TRUE(hasTheRightValue(Assume, I->getOperand(2),
193                                Attribute::AttrKind::Alignment, 64, true));
194         ASSERT_TRUE(hasTheRightValue(Assume, I->getOperand(2),
195                                Attribute::AttrKind::Dereferenceable, 4, true));
196         ASSERT_TRUE(hasTheRightValue(Assume, I->getOperand(3),
197                                Attribute::AttrKind::Alignment, 16, true));
198         ASSERT_TRUE(hasTheRightValue(Assume, I->getOperand(3),
199                                Attribute::AttrKind::Dereferenceable, 12, true));
200       }));
201 
202   Tests.push_back(std::make_pair(
203       "call void @func1(i32* readnone align 32 "
204       "dereferenceable(48) noalias %P, i32* "
205       "align 8 dereferenceable(28) %P1, i32* align 64 "
206       "dereferenceable(4) "
207       "%P2, i32* nonnull align 16 dereferenceable(12) %P3)\n",
208       [](Instruction *I) {
209         IntrinsicInst *Assume = buildAssumeFromInst(I);
210         Assume->insertBefore(I);
211         I->getOperand(1)->dropDroppableUses();
212         I->getOperand(2)->dropDroppableUses();
213         I->getOperand(3)->dropDroppableUses();
214         ASSERT_TRUE(hasMatchesExactlyAttributes(
215             Assume, I->getOperand(0),
216             "(align|dereferenceable)"));
217         ASSERT_TRUE(hasMatchesExactlyAttributes(Assume, I->getOperand(1),
218                                        ""));
219         ASSERT_TRUE(hasMatchesExactlyAttributes(Assume, I->getOperand(2),
220                                        ""));
221         ASSERT_TRUE(hasMatchesExactlyAttributes(Assume, I->getOperand(3),
222                                        ""));
223         ASSERT_TRUE(hasTheRightValue(Assume, I->getOperand(0),
224                                Attribute::AttrKind::Alignment, 32, true));
225         ASSERT_TRUE(hasTheRightValue(Assume, I->getOperand(0),
226                                Attribute::AttrKind::Dereferenceable, 48, true));
227       }));
228   Tests.push_back(std::make_pair(
229       "call void @func(i32* nonnull align 4 dereferenceable(16) %P, i32* align "
230       "8 noalias %P1)\n",
231       [](Instruction *I) {
232         IntrinsicInst *Assume = buildAssumeFromInst(I);
233         Assume->insertBefore(I);
234         Value *New = I->getFunction()->getArg(3);
235         Value *Old = I->getOperand(0);
236         ASSERT_TRUE(hasMatchesExactlyAttributes(Assume, New, ""));
237         ASSERT_TRUE(hasMatchesExactlyAttributes(Assume, Old,
238                                        "(nonnull|align|dereferenceable)"));
239         Old->replaceAllUsesWith(New);
240         ASSERT_TRUE(hasMatchesExactlyAttributes(Assume, New,
241                                        "(nonnull|align|dereferenceable)"));
242         ASSERT_TRUE(hasMatchesExactlyAttributes(Assume, Old, ""));
243       }));
244   RunTest(Head, Tail, Tests);
245 }
246 
247 static bool FindExactlyAttributes(RetainedKnowledgeMap &Map, Value *WasOn,
248                                  StringRef AttrToMatch) {
249   Regex Reg(AttrToMatch);
250   SmallVector<StringRef, 1> Matches;
251   for (StringRef Attr : {
252 #define GET_ATTR_NAMES
253 #define ATTRIBUTE_ENUM(ENUM_NAME, DISPLAY_NAME) StringRef(#DISPLAY_NAME),
254 #include "llvm/IR/Attributes.inc"
255        }) {
256     bool ShouldHaveAttr = Reg.match(Attr, &Matches) && Matches[0] == Attr;
257 
258     if (ShouldHaveAttr != (Map.find(RetainedKnowledgeKey{WasOn, Attribute::getAttrKindFromName(Attr)}) != Map.end()))
259       return false;
260   }
261   return true;
262 }
263 
264 static bool MapHasRightValue(RetainedKnowledgeMap &Map, IntrinsicInst *II,
265                              RetainedKnowledgeKey Key, MinMax MM) {
266   auto LookupIt = Map.find(Key);
267   return (LookupIt != Map.end()) && (LookupIt->second[II].Min == MM.Min) &&
268          (LookupIt->second[II].Max == MM.Max);
269 }
270 
271 TEST(AssumeQueryAPI, fillMapFromAssume) {
272   EnableKnowledgeRetention.setValue(true);
273   StringRef Head =
274       "declare void @llvm.assume(i1)\n"
275       "declare void @func(i32*, i32*)\n"
276       "declare void @func1(i32*, i32*, i32*, i32*)\n"
277       "declare void @func_many(i32*) \"no-jump-tables\" nounwind "
278       "\"less-precise-fpmad\" willreturn norecurse\n"
279       "define void @test(i32* %P, i32* %P1, i32* %P2, i32* %P3) {\n";
280   StringRef Tail = "ret void\n"
281                    "}";
282   std::vector<std::pair<StringRef, llvm::function_ref<void(Instruction *)>>>
283       Tests;
284   Tests.push_back(std::make_pair(
285       "call void @func(i32* nonnull align 4 dereferenceable(16) %P, i32* align "
286       "8 noalias %P1)\n",
287       [](Instruction *I) {
288         IntrinsicInst *Assume = buildAssumeFromInst(I);
289         Assume->insertBefore(I);
290 
291         RetainedKnowledgeMap Map;
292         fillMapFromAssume(*Assume, Map);
293         ASSERT_TRUE(FindExactlyAttributes(Map, I->getOperand(0),
294                                        "(nonnull|align|dereferenceable)"));
295         ASSERT_TRUE(FindExactlyAttributes(Map, I->getOperand(1),
296                                        "(align)"));
297         ASSERT_TRUE(MapHasRightValue(
298             Map, Assume, {I->getOperand(0), Attribute::Dereferenceable}, {16, 16}));
299         ASSERT_TRUE(MapHasRightValue(Map, Assume, {I->getOperand(0), Attribute::Alignment},
300                                {4, 4}));
301         ASSERT_TRUE(MapHasRightValue(Map, Assume, {I->getOperand(0), Attribute::Alignment},
302                                {4, 4}));
303       }));
304   Tests.push_back(std::make_pair(
305       "call void @func1(i32* nonnull align 32 dereferenceable(48) %P, i32* "
306       "nonnull "
307       "align 8 dereferenceable(28) %P, i32* nonnull align 64 "
308       "dereferenceable(4) "
309       "%P, i32* nonnull align 16 dereferenceable(12) %P)\n",
310       [](Instruction *I) {
311         IntrinsicInst *Assume = buildAssumeFromInst(I);
312         Assume->insertBefore(I);
313 
314         RetainedKnowledgeMap Map;
315         fillMapFromAssume(*Assume, Map);
316 
317         ASSERT_TRUE(FindExactlyAttributes(Map, I->getOperand(0),
318                                        "(nonnull|align|dereferenceable)"));
319         ASSERT_TRUE(FindExactlyAttributes(Map, I->getOperand(1),
320                                        "(nonnull|align|dereferenceable)"));
321         ASSERT_TRUE(FindExactlyAttributes(Map, I->getOperand(2),
322                                        "(nonnull|align|dereferenceable)"));
323         ASSERT_TRUE(FindExactlyAttributes(Map, I->getOperand(3),
324                                        "(nonnull|align|dereferenceable)"));
325         ASSERT_TRUE(MapHasRightValue(
326             Map, Assume, {I->getOperand(0), Attribute::Dereferenceable}, {4, 48}));
327         ASSERT_TRUE(MapHasRightValue(Map, Assume, {I->getOperand(0), Attribute::Alignment},
328                                {8, 64}));
329       }));
330   Tests.push_back(std::make_pair(
331       "call void @func_many(i32* align 8 %P1) cold\n", [](Instruction *I) {
332         ShouldPreserveAllAttributes.setValue(true);
333         IntrinsicInst *Assume = buildAssumeFromInst(I);
334         Assume->insertBefore(I);
335 
336         RetainedKnowledgeMap Map;
337         fillMapFromAssume(*Assume, Map);
338 
339         ASSERT_TRUE(FindExactlyAttributes(
340             Map, nullptr, "(nounwind|norecurse|willreturn|cold)"));
341         ShouldPreserveAllAttributes.setValue(false);
342       }));
343   Tests.push_back(
344       std::make_pair("call void @llvm.assume(i1 true)\n", [](Instruction *I) {
345         RetainedKnowledgeMap Map;
346         fillMapFromAssume(*cast<IntrinsicInst>(I), Map);
347 
348         ASSERT_TRUE(FindExactlyAttributes(Map, nullptr, ""));
349         ASSERT_TRUE(Map.empty());
350       }));
351   Tests.push_back(std::make_pair(
352       "call void @func1(i32* readnone align 32 "
353       "dereferenceable(48) noalias %P, i32* "
354       "align 8 dereferenceable(28) %P1, i32* align 64 "
355       "dereferenceable(4) "
356       "%P2, i32* nonnull align 16 dereferenceable(12) %P3)\n",
357       [](Instruction *I) {
358         IntrinsicInst *Assume = buildAssumeFromInst(I);
359         Assume->insertBefore(I);
360 
361         RetainedKnowledgeMap Map;
362         fillMapFromAssume(*Assume, Map);
363 
364         ASSERT_TRUE(FindExactlyAttributes(Map, I->getOperand(0),
365                                     "(align|dereferenceable)"));
366         ASSERT_TRUE(FindExactlyAttributes(Map, I->getOperand(1),
367                                     "(align|dereferenceable)"));
368         ASSERT_TRUE(FindExactlyAttributes(Map, I->getOperand(2),
369                                        "(align|dereferenceable)"));
370         ASSERT_TRUE(FindExactlyAttributes(Map, I->getOperand(3),
371                                        "(nonnull|align|dereferenceable)"));
372         ASSERT_TRUE(MapHasRightValue(Map, Assume, {I->getOperand(0), Attribute::Alignment},
373                                {32, 32}));
374         ASSERT_TRUE(MapHasRightValue(
375             Map, Assume, {I->getOperand(0), Attribute::Dereferenceable}, {48, 48}));
376         ASSERT_TRUE(MapHasRightValue(
377             Map, Assume, {I->getOperand(1), Attribute::Dereferenceable}, {28, 28}));
378         ASSERT_TRUE(MapHasRightValue(Map, Assume, {I->getOperand(1), Attribute::Alignment},
379                                {8, 8}));
380         ASSERT_TRUE(MapHasRightValue(Map, Assume, {I->getOperand(2), Attribute::Alignment},
381                                {64, 64}));
382         ASSERT_TRUE(MapHasRightValue(
383             Map, Assume, {I->getOperand(2), Attribute::Dereferenceable}, {4, 4}));
384         ASSERT_TRUE(MapHasRightValue(Map, Assume, {I->getOperand(3), Attribute::Alignment},
385                                {16, 16}));
386         ASSERT_TRUE(MapHasRightValue(
387             Map, Assume, {I->getOperand(3), Attribute::Dereferenceable}, {12, 12}));
388       }));
389 
390   /// Keep this test last as it modifies the function.
391   Tests.push_back(std::make_pair(
392       "call void @func(i32* nonnull align 4 dereferenceable(16) %P, i32* align "
393       "8 noalias %P1)\n",
394       [](Instruction *I) {
395         IntrinsicInst *Assume = buildAssumeFromInst(I);
396         Assume->insertBefore(I);
397 
398         RetainedKnowledgeMap Map;
399         fillMapFromAssume(*Assume, Map);
400 
401         Value *New = I->getFunction()->getArg(3);
402         Value *Old = I->getOperand(0);
403         ASSERT_TRUE(FindExactlyAttributes(Map, New, ""));
404         ASSERT_TRUE(FindExactlyAttributes(Map, Old,
405                                        "(nonnull|align|dereferenceable)"));
406         Old->replaceAllUsesWith(New);
407         Map.clear();
408         fillMapFromAssume(*Assume, Map);
409         ASSERT_TRUE(FindExactlyAttributes(Map, New,
410                                        "(nonnull|align|dereferenceable)"));
411         ASSERT_TRUE(FindExactlyAttributes(Map, Old, ""));
412       }));
413   RunTest(Head, Tail, Tests);
414 }
415 
416 static void RunRandTest(uint64_t Seed, int Size, int MinCount, int MaxCount,
417                         unsigned MaxValue) {
418   LLVMContext C;
419   SMDiagnostic Err;
420 
421   std::random_device dev;
422   std::mt19937 Rng(Seed);
423   std::uniform_int_distribution<int> DistCount(MinCount, MaxCount);
424   std::uniform_int_distribution<unsigned> DistValue(0, MaxValue);
425   std::uniform_int_distribution<unsigned> DistAttr(0,
426                                                    Attribute::EndAttrKinds - 1);
427 
428   std::unique_ptr<Module> Mod = std::make_unique<Module>("AssumeQueryAPI", C);
429   if (!Mod)
430     Err.print("AssumeQueryAPI", errs());
431 
432   std::vector<Type *> TypeArgs;
433   for (int i = 0; i < (Size * 2); i++)
434     TypeArgs.push_back(Type::getInt32PtrTy(C));
435   FunctionType *FuncType =
436       FunctionType::get(Type::getVoidTy(C), TypeArgs, false);
437 
438   Function *F =
439       Function::Create(FuncType, GlobalValue::ExternalLinkage, "test", &*Mod);
440   BasicBlock *BB = BasicBlock::Create(C);
441   BB->insertInto(F);
442   Instruction *Ret = ReturnInst::Create(C);
443   BB->getInstList().insert(BB->begin(), Ret);
444   Function *FnAssume = Intrinsic::getDeclaration(Mod.get(), Intrinsic::assume);
445 
446   std::vector<Argument *> ShuffledArgs;
447   std::vector<bool> HasArg;
448   for (auto &Arg : F->args()) {
449     ShuffledArgs.push_back(&Arg);
450     HasArg.push_back(false);
451   }
452 
453   std::shuffle(ShuffledArgs.begin(), ShuffledArgs.end(), Rng);
454 
455   std::vector<OperandBundleDef> OpBundle;
456   OpBundle.reserve(Size);
457   std::vector<Value *> Args;
458   Args.reserve(2);
459   for (int i = 0; i < Size; i++) {
460     int count = DistCount(Rng);
461     int value = DistValue(Rng);
462     int attr = DistAttr(Rng);
463     std::string str;
464     raw_string_ostream ss(str);
465     ss << Attribute::getNameFromAttrKind(
466         static_cast<Attribute::AttrKind>(attr));
467     Args.clear();
468 
469     if (count > 0) {
470       Args.push_back(ShuffledArgs[i]);
471       HasArg[i] = true;
472     }
473     if (count > 1)
474       Args.push_back(ConstantInt::get(Type::getInt32Ty(C), value));
475 
476     OpBundle.push_back(OperandBundleDef{ss.str().c_str(), std::move(Args)});
477   }
478 
479   auto *Assume = cast<IntrinsicInst>(IntrinsicInst::Create(
480       FnAssume, ArrayRef<Value *>({ConstantInt::getTrue(C)}), OpBundle));
481   Assume->insertBefore(&F->begin()->front());
482   RetainedKnowledgeMap Map;
483   fillMapFromAssume(*Assume, Map);
484   for (int i = 0; i < (Size * 2); i++) {
485     if (!HasArg[i])
486       continue;
487     RetainedKnowledge K =
488         getKnowledgeFromUseInAssume(&*ShuffledArgs[i]->use_begin());
489     auto LookupIt = Map.find(RetainedKnowledgeKey{K.WasOn, K.AttrKind});
490     ASSERT_TRUE(LookupIt != Map.end());
491     MinMax MM = LookupIt->second[Assume];
492     ASSERT_TRUE(MM.Min == MM.Max);
493     ASSERT_TRUE(MM.Min == K.ArgValue);
494   }
495 }
496 
497 TEST(AssumeQueryAPI, getKnowledgeFromUseInAssume) {
498   // // For Fuzzing
499   // std::random_device dev;
500   // std::mt19937 Rng(dev());
501   // while (true) {
502   //   unsigned Seed = Rng();
503   //   dbgs() << Seed << "\n";
504   //   RunRandTest(Seed, 100000, 0, 2, 100);
505   // }
506   RunRandTest(23456, 4, 0, 2, 100);
507   RunRandTest(560987, 25, -3, 2, 100);
508 
509   // Large bundles can lead to special cases. this is why this test is soo
510   // large.
511   RunRandTest(9876789, 100000, -0, 7, 100);
512 }
513