• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
RunTest(StringRef Head,StringRef Tail,std::vector<std::pair<StringRef,llvm::function_ref<void (Instruction *)>>> & Tests)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 
hasMatchesExactlyAttributes(IntrinsicInst * Assume,Value * WasOn,StringRef AttrToMatch)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 
hasTheRightValue(IntrinsicInst * Assume,Value * WasOn,Attribute::AttrKind Kind,unsigned Value)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 
TEST(AssumeQueryAPI,hasAttributeInAssume)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 
FindExactlyAttributes(RetainedKnowledgeMap & Map,Value * WasOn,StringRef AttrToMatch)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 
MapHasRightValue(RetainedKnowledgeMap & Map,IntrinsicInst * II,RetainedKnowledgeKey Key,MinMax MM)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 
TEST(AssumeQueryAPI,fillMapFromAssume)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   RunTest(Head, Tail, Tests);
387 }
388 
RunRandTest(uint64_t Seed,int Size,int MinCount,int MaxCount,unsigned MaxValue)389 static void RunRandTest(uint64_t Seed, int Size, int MinCount, int MaxCount,
390                         unsigned MaxValue) {
391   LLVMContext C;
392   SMDiagnostic Err;
393 
394   std::random_device dev;
395   std::mt19937 Rng(Seed);
396   std::uniform_int_distribution<int> DistCount(MinCount, MaxCount);
397   std::uniform_int_distribution<unsigned> DistValue(0, MaxValue);
398   std::uniform_int_distribution<unsigned> DistAttr(0,
399                                                    Attribute::EndAttrKinds - 1);
400 
401   std::unique_ptr<Module> Mod = std::make_unique<Module>("AssumeQueryAPI", C);
402   if (!Mod)
403     Err.print("AssumeQueryAPI", errs());
404 
405   std::vector<Type *> TypeArgs;
406   for (int i = 0; i < (Size * 2); i++)
407     TypeArgs.push_back(Type::getInt32PtrTy(C));
408   FunctionType *FuncType =
409       FunctionType::get(Type::getVoidTy(C), TypeArgs, false);
410 
411   Function *F =
412       Function::Create(FuncType, GlobalValue::ExternalLinkage, "test", &*Mod);
413   BasicBlock *BB = BasicBlock::Create(C);
414   BB->insertInto(F);
415   Instruction *Ret = ReturnInst::Create(C);
416   BB->getInstList().insert(BB->begin(), Ret);
417   Function *FnAssume = Intrinsic::getDeclaration(Mod.get(), Intrinsic::assume);
418 
419   std::vector<Argument *> ShuffledArgs;
420   std::vector<bool> HasArg;
421   for (auto &Arg : F->args()) {
422     ShuffledArgs.push_back(&Arg);
423     HasArg.push_back(false);
424   }
425 
426   std::shuffle(ShuffledArgs.begin(), ShuffledArgs.end(), Rng);
427 
428   std::vector<OperandBundleDef> OpBundle;
429   OpBundle.reserve(Size);
430   std::vector<Value *> Args;
431   Args.reserve(2);
432   for (int i = 0; i < Size; i++) {
433     int count = DistCount(Rng);
434     int value = DistValue(Rng);
435     int attr = DistAttr(Rng);
436     std::string str;
437     raw_string_ostream ss(str);
438     ss << Attribute::getNameFromAttrKind(
439         static_cast<Attribute::AttrKind>(attr));
440     Args.clear();
441 
442     if (count > 0) {
443       Args.push_back(ShuffledArgs[i]);
444       HasArg[i] = true;
445     }
446     if (count > 1)
447       Args.push_back(ConstantInt::get(Type::getInt32Ty(C), value));
448 
449     OpBundle.push_back(OperandBundleDef{ss.str().c_str(), std::move(Args)});
450   }
451 
452   auto *Assume = cast<IntrinsicInst>(IntrinsicInst::Create(
453       FnAssume, ArrayRef<Value *>({ConstantInt::getTrue(C)}), OpBundle));
454   Assume->insertBefore(&F->begin()->front());
455   RetainedKnowledgeMap Map;
456   fillMapFromAssume(*Assume, Map);
457   for (int i = 0; i < (Size * 2); i++) {
458     if (!HasArg[i])
459       continue;
460     RetainedKnowledge K =
461         getKnowledgeFromUseInAssume(&*ShuffledArgs[i]->use_begin());
462     auto LookupIt = Map.find(RetainedKnowledgeKey{K.WasOn, K.AttrKind});
463     ASSERT_TRUE(LookupIt != Map.end());
464     MinMax MM = LookupIt->second[Assume];
465     ASSERT_TRUE(MM.Min == MM.Max);
466     ASSERT_TRUE(MM.Min == K.ArgValue);
467   }
468 }
469 
TEST(AssumeQueryAPI,getKnowledgeFromUseInAssume)470 TEST(AssumeQueryAPI, getKnowledgeFromUseInAssume) {
471   // // For Fuzzing
472   // std::random_device dev;
473   // std::mt19937 Rng(dev());
474   // while (true) {
475   //   unsigned Seed = Rng();
476   //   dbgs() << Seed << "\n";
477   //   RunRandTest(Seed, 100000, 0, 2, 100);
478   // }
479   RunRandTest(23456, 4, 0, 2, 100);
480   RunRandTest(560987, 25, -3, 2, 100);
481 
482   // Large bundles can lead to special cases. this is why this test is soo
483   // large.
484   RunRandTest(9876789, 100000, -0, 7, 100);
485 }
486 
TEST(AssumeQueryAPI,AssumptionCache)487 TEST(AssumeQueryAPI, AssumptionCache) {
488   LLVMContext C;
489   SMDiagnostic Err;
490   std::unique_ptr<Module> Mod = parseAssemblyString(
491       "declare void @llvm.assume(i1)\n"
492       "define void @test(i32* %P, i32* %P1, i32* %P2, i32* %P3, i1 %B) {\n"
493       "call void @llvm.assume(i1 true) [\"nonnull\"(i32* %P), \"align\"(i32* "
494       "%P2, i32 4), \"align\"(i32* %P, i32 8)]\n"
495       "call void @llvm.assume(i1 %B) [\"test\"(i32* %P1), "
496       "\"dereferenceable\"(i32* %P, i32 4)]\n"
497       "ret void\n}\n",
498       Err, C);
499   if (!Mod)
500     Err.print("AssumeQueryAPI", errs());
501   Function *F = Mod->getFunction("test");
502   BasicBlock::iterator First = F->begin()->begin();
503   BasicBlock::iterator Second = F->begin()->begin();
504   Second++;
505   AssumptionCacheTracker ACT;
506   AssumptionCache &AC = ACT.getAssumptionCache(*F);
507   auto AR = AC.assumptionsFor(F->getArg(3));
508   ASSERT_EQ(AR.size(), 0u);
509   AR = AC.assumptionsFor(F->getArg(1));
510   ASSERT_EQ(AR.size(), 1u);
511   ASSERT_EQ(AR[0].Index, 0u);
512   ASSERT_EQ(AR[0].Assume, &*Second);
513   AR = AC.assumptionsFor(F->getArg(2));
514   ASSERT_EQ(AR.size(), 1u);
515   ASSERT_EQ(AR[0].Index, 1u);
516   ASSERT_EQ(AR[0].Assume, &*First);
517   AR = AC.assumptionsFor(F->getArg(0));
518   ASSERT_EQ(AR.size(), 3u);
519   llvm::sort(AR,
520              [](const auto &L, const auto &R) { return L.Index < R.Index; });
521   ASSERT_EQ(AR[0].Assume, &*First);
522   ASSERT_EQ(AR[0].Index, 0u);
523   ASSERT_EQ(AR[1].Assume, &*Second);
524   ASSERT_EQ(AR[1].Index, 1u);
525   ASSERT_EQ(AR[2].Assume, &*First);
526   ASSERT_EQ(AR[2].Index, 2u);
527   AR = AC.assumptionsFor(F->getArg(4));
528   ASSERT_EQ(AR.size(), 1u);
529   ASSERT_EQ(AR[0].Assume, &*Second);
530   ASSERT_EQ(AR[0].Index, AssumptionCache::ExprResultIdx);
531   AC.unregisterAssumption(cast<CallInst>(&*Second));
532   AR = AC.assumptionsFor(F->getArg(1));
533   ASSERT_EQ(AR.size(), 0u);
534   AR = AC.assumptionsFor(F->getArg(0));
535   ASSERT_EQ(AR.size(), 3u);
536   llvm::sort(AR,
537              [](const auto &L, const auto &R) { return L.Index < R.Index; });
538   ASSERT_EQ(AR[0].Assume, &*First);
539   ASSERT_EQ(AR[0].Index, 0u);
540   ASSERT_EQ(AR[1].Assume, nullptr);
541   ASSERT_EQ(AR[1].Index, 1u);
542   ASSERT_EQ(AR[2].Assume, &*First);
543   ASSERT_EQ(AR[2].Index, 2u);
544   AR = AC.assumptionsFor(F->getArg(2));
545   ASSERT_EQ(AR.size(), 1u);
546   ASSERT_EQ(AR[0].Index, 1u);
547   ASSERT_EQ(AR[0].Assume, &*First);
548 }
549 
TEST(AssumeQueryAPI,Alignment)550 TEST(AssumeQueryAPI, Alignment) {
551   LLVMContext C;
552   SMDiagnostic Err;
553   std::unique_ptr<Module> Mod = parseAssemblyString(
554       "declare void @llvm.assume(i1)\n"
555       "define void @test(i32* %P, i32* %P1, i32* %P2, i32 %I3, i1 %B) {\n"
556       "call void @llvm.assume(i1 true) [\"align\"(i32* %P, i32 8, i32 %I3)]\n"
557       "call void @llvm.assume(i1 true) [\"align\"(i32* %P1, i32 %I3, i32 "
558       "%I3)]\n"
559       "call void @llvm.assume(i1 true) [\"align\"(i32* %P2, i32 16, i32 8)]\n"
560       "ret void\n}\n",
561       Err, C);
562   if (!Mod)
563     Err.print("AssumeQueryAPI", errs());
564 
565   Function *F = Mod->getFunction("test");
566   BasicBlock::iterator Start = F->begin()->begin();
567   IntrinsicInst *II;
568   RetainedKnowledge RK;
569   II = cast<IntrinsicInst>(&*Start);
570   RK = getKnowledgeFromBundle(*II, II->bundle_op_info_begin()[0]);
571   ASSERT_EQ(RK.AttrKind, Attribute::Alignment);
572   ASSERT_EQ(RK.WasOn, F->getArg(0));
573   ASSERT_EQ(RK.ArgValue, 1u);
574   Start++;
575   II = cast<IntrinsicInst>(&*Start);
576   RK = getKnowledgeFromBundle(*II, II->bundle_op_info_begin()[0]);
577   ASSERT_EQ(RK.AttrKind, Attribute::Alignment);
578   ASSERT_EQ(RK.WasOn, F->getArg(1));
579   ASSERT_EQ(RK.ArgValue, 1u);
580   Start++;
581   II = cast<IntrinsicInst>(&*Start);
582   RK = getKnowledgeFromBundle(*II, II->bundle_op_info_begin()[0]);
583   ASSERT_EQ(RK.AttrKind, Attribute::Alignment);
584   ASSERT_EQ(RK.WasOn, F->getArg(2));
585   ASSERT_EQ(RK.ArgValue, 8u);
586 }
587