xref: /llvm-project/llvm/unittests/Analysis/AssumeBundleQueriesTest.cpp (revision 8e702735090388a3231a863e343f880d0f96fecb)
1c00cb762STyker //===- AssumeBundleQueriesTest.cpp ------------------------------*- C++ -*-===//
2c00cb762STyker //
3c00cb762STyker // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4c00cb762STyker // See https://llvm.org/LICENSE.txt for license information.
5c00cb762STyker // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6c00cb762STyker //
7c00cb762STyker //===----------------------------------------------------------------------===//
8c00cb762STyker 
90128b950SSimon Pilgrim #include "llvm/Analysis/AssumeBundleQueries.h"
104169338eSNikita Popov #include "llvm/Analysis/AssumptionCache.h"
11c00cb762STyker #include "llvm/AsmParser/Parser.h"
120128b950SSimon Pilgrim #include "llvm/IR/IntrinsicInst.h"
134169338eSNikita Popov #include "llvm/IR/LLVMContext.h"
144169338eSNikita Popov #include "llvm/IR/Module.h"
154169338eSNikita Popov #include "llvm/Support/CommandLine.h"
16c00cb762STyker #include "llvm/Support/Regex.h"
17c00cb762STyker #include "llvm/Support/SourceMgr.h"
18c00cb762STyker #include "llvm/Transforms/Utils/AssumeBundleBuilder.h"
19c00cb762STyker #include "gtest/gtest.h"
20c00cb762STyker #include <random>
21c00cb762STyker 
22c00cb762STyker using namespace llvm;
23c00cb762STyker 
24d8aba75aSFangrui Song namespace llvm {
25c00cb762STyker extern cl::opt<bool> ShouldPreserveAllAttributes;
26d8aba75aSFangrui Song } // namespace llvm
27c00cb762STyker 
28c00cb762STyker static void RunTest(
29c00cb762STyker     StringRef Head, StringRef Tail,
30c00cb762STyker     std::vector<std::pair<StringRef, llvm::function_ref<void(Instruction *)>>>
31c00cb762STyker         &Tests) {
32c00cb762STyker   for (auto &Elem : Tests) {
33c00cb762STyker     std::string IR;
34c00cb762STyker     IR.append(Head.begin(), Head.end());
35c00cb762STyker     IR.append(Elem.first.begin(), Elem.first.end());
36c00cb762STyker     IR.append(Tail.begin(), Tail.end());
37c00cb762STyker     LLVMContext C;
38c00cb762STyker     SMDiagnostic Err;
39c00cb762STyker     std::unique_ptr<Module> Mod = parseAssemblyString(IR, Err, C);
40c00cb762STyker     if (!Mod)
41c00cb762STyker       Err.print("AssumeQueryAPI", errs());
42c00cb762STyker     Elem.second(&*(Mod->getFunction("test")->begin()->begin()));
43c00cb762STyker   }
44c00cb762STyker }
45c00cb762STyker 
469ef6aa02SPhilip Reames bool hasMatchesExactlyAttributes(AssumeInst *Assume, Value *WasOn,
47c00cb762STyker                                  StringRef AttrToMatch) {
48c00cb762STyker   Regex Reg(AttrToMatch);
49c00cb762STyker   SmallVector<StringRef, 1> Matches;
50c00cb762STyker   for (StringRef Attr : {
51c00cb762STyker #define GET_ATTR_NAMES
52c00cb762STyker #define ATTRIBUTE_ALL(ENUM_NAME, DISPLAY_NAME) StringRef(#DISPLAY_NAME),
53c00cb762STyker #include "llvm/IR/Attributes.inc"
54c00cb762STyker        }) {
55c00cb762STyker     bool ShouldHaveAttr = Reg.match(Attr, &Matches) && Matches[0] == Attr;
56c00cb762STyker     if (ShouldHaveAttr != hasAttributeInAssume(*Assume, WasOn, Attr))
57c00cb762STyker       return false;
58c00cb762STyker   }
59c00cb762STyker   return true;
60c00cb762STyker }
61c00cb762STyker 
629ef6aa02SPhilip Reames bool hasTheRightValue(AssumeInst *Assume, Value *WasOn,
63e5f8a77cSTyker                       Attribute::AttrKind Kind, unsigned Value) {
64c00cb762STyker   uint64_t ArgVal = 0;
65e5f8a77cSTyker   if (!hasAttributeInAssume(*Assume, WasOn, Kind, &ArgVal))
66c00cb762STyker     return false;
67c00cb762STyker   if (ArgVal != Value)
68c00cb762STyker     return false;
69c00cb762STyker   return true;
70c00cb762STyker }
71c00cb762STyker 
72c00cb762STyker TEST(AssumeQueryAPI, hasAttributeInAssume) {
73c00cb762STyker   EnableKnowledgeRetention.setValue(true);
74c00cb762STyker   StringRef Head =
75c00cb762STyker       "declare void @llvm.assume(i1)\n"
76edf634ebSJuneyoung Lee       "declare void @func(i32*, i32*, i32*)\n"
77c00cb762STyker       "declare void @func1(i32*, i32*, i32*, i32*)\n"
78c00cb762STyker       "declare void @func_many(i32*) \"no-jump-tables\" nounwind "
79c00cb762STyker       "\"less-precise-fpmad\" willreturn norecurse\n"
80c00cb762STyker       "define void @test(i32* %P, i32* %P1, i32* %P2, i32* %P3) {\n";
81c00cb762STyker   StringRef Tail = "ret void\n"
82c00cb762STyker                    "}";
83c00cb762STyker   std::vector<std::pair<StringRef, llvm::function_ref<void(Instruction *)>>>
84c00cb762STyker       Tests;
85c00cb762STyker   Tests.push_back(std::make_pair(
86c00cb762STyker       "call void @func(i32* nonnull align 4 dereferenceable(16) %P, i32* align "
87edf634ebSJuneyoung Lee       "8 noalias %P1, i32* align 8 noundef %P2)\n",
88c00cb762STyker       [](Instruction *I) {
899ef6aa02SPhilip Reames         auto *Assume = buildAssumeFromInst(I);
90*8e702735SJeremy Morse         Assume->insertBefore(I->getIterator());
91c00cb762STyker         ASSERT_TRUE(hasMatchesExactlyAttributes(Assume, I->getOperand(0),
92c00cb762STyker                                        "(nonnull|align|dereferenceable)"));
93c00cb762STyker         ASSERT_TRUE(hasMatchesExactlyAttributes(Assume, I->getOperand(1),
94edf634ebSJuneyoung Lee                                        "()"));
95edf634ebSJuneyoung Lee         ASSERT_TRUE(hasMatchesExactlyAttributes(Assume, I->getOperand(2),
96edf634ebSJuneyoung Lee                                        "(align|noundef)"));
97c00cb762STyker         ASSERT_TRUE(hasTheRightValue(Assume, I->getOperand(0),
98e5f8a77cSTyker                                      Attribute::AttrKind::Dereferenceable, 16));
99c00cb762STyker         ASSERT_TRUE(hasTheRightValue(Assume, I->getOperand(0),
100e5f8a77cSTyker                                      Attribute::AttrKind::Alignment, 4));
101c00cb762STyker         ASSERT_TRUE(hasTheRightValue(Assume, I->getOperand(0),
102e5f8a77cSTyker                                      Attribute::AttrKind::Alignment, 4));
103c00cb762STyker       }));
104c00cb762STyker   Tests.push_back(std::make_pair(
105c00cb762STyker       "call void @func1(i32* nonnull align 32 dereferenceable(48) %P, i32* "
106c00cb762STyker       "nonnull "
107c00cb762STyker       "align 8 dereferenceable(28) %P, i32* nonnull align 64 "
108c00cb762STyker       "dereferenceable(4) "
109c00cb762STyker       "%P, i32* nonnull align 16 dereferenceable(12) %P)\n",
110c00cb762STyker       [](Instruction *I) {
1119ef6aa02SPhilip Reames         auto *Assume = buildAssumeFromInst(I);
112*8e702735SJeremy Morse         Assume->insertBefore(I->getIterator());
113c00cb762STyker         ASSERT_TRUE(hasMatchesExactlyAttributes(Assume, I->getOperand(0),
114c00cb762STyker                                        "(nonnull|align|dereferenceable)"));
115c00cb762STyker         ASSERT_TRUE(hasMatchesExactlyAttributes(Assume, I->getOperand(1),
116c00cb762STyker                                        "(nonnull|align|dereferenceable)"));
117c00cb762STyker         ASSERT_TRUE(hasMatchesExactlyAttributes(Assume, I->getOperand(2),
118c00cb762STyker                                        "(nonnull|align|dereferenceable)"));
119c00cb762STyker         ASSERT_TRUE(hasMatchesExactlyAttributes(Assume, I->getOperand(3),
120c00cb762STyker                                        "(nonnull|align|dereferenceable)"));
121c00cb762STyker         ASSERT_TRUE(hasTheRightValue(Assume, I->getOperand(0),
122e5f8a77cSTyker                                      Attribute::AttrKind::Dereferenceable, 48));
123c00cb762STyker         ASSERT_TRUE(hasTheRightValue(Assume, I->getOperand(0),
124e5f8a77cSTyker                                      Attribute::AttrKind::Alignment, 64));
125c00cb762STyker         ASSERT_TRUE(hasTheRightValue(Assume, I->getOperand(1),
126e5f8a77cSTyker                                      Attribute::AttrKind::Alignment, 64));
127c00cb762STyker       }));
128c00cb762STyker   Tests.push_back(std::make_pair(
129edf634ebSJuneyoung Lee       "call void @func_many(i32* align 8 noundef %P1) cold\n", [](Instruction *I) {
130c00cb762STyker         ShouldPreserveAllAttributes.setValue(true);
1319ef6aa02SPhilip Reames         auto *Assume = buildAssumeFromInst(I);
132*8e702735SJeremy Morse         Assume->insertBefore(I->getIterator());
133c00cb762STyker         ASSERT_TRUE(hasMatchesExactlyAttributes(
134edf634ebSJuneyoung Lee             Assume, nullptr,
135edf634ebSJuneyoung Lee             "(align|nounwind|norecurse|noundef|willreturn|cold)"));
136c00cb762STyker         ShouldPreserveAllAttributes.setValue(false);
137c00cb762STyker       }));
138c00cb762STyker   Tests.push_back(
139c00cb762STyker       std::make_pair("call void @llvm.assume(i1 true)\n", [](Instruction *I) {
1409ef6aa02SPhilip Reames         auto *Assume = cast<AssumeInst>(I);
141c00cb762STyker         ASSERT_TRUE(hasMatchesExactlyAttributes(Assume, nullptr, ""));
142c00cb762STyker       }));
143c00cb762STyker   Tests.push_back(std::make_pair(
144c00cb762STyker       "call void @func1(i32* readnone align 32 "
145c00cb762STyker       "dereferenceable(48) noalias %P, i32* "
146c00cb762STyker       "align 8 dereferenceable(28) %P1, i32* align 64 "
147c00cb762STyker       "dereferenceable(4) "
148c00cb762STyker       "%P2, i32* nonnull align 16 dereferenceable(12) %P3)\n",
149c00cb762STyker       [](Instruction *I) {
1509ef6aa02SPhilip Reames         auto *Assume = buildAssumeFromInst(I);
151*8e702735SJeremy Morse         Assume->insertBefore(I->getIterator());
152c00cb762STyker         ASSERT_TRUE(hasMatchesExactlyAttributes(
153c00cb762STyker             Assume, I->getOperand(0),
154c00cb762STyker             "(align|dereferenceable)"));
155c00cb762STyker         ASSERT_TRUE(hasMatchesExactlyAttributes(Assume, I->getOperand(1),
156c00cb762STyker                                        "(align|dereferenceable)"));
157c00cb762STyker         ASSERT_TRUE(hasMatchesExactlyAttributes(Assume, I->getOperand(2),
158c00cb762STyker                                        "(align|dereferenceable)"));
159c00cb762STyker         ASSERT_TRUE(hasMatchesExactlyAttributes(Assume, I->getOperand(3),
160c00cb762STyker                                        "(nonnull|align|dereferenceable)"));
161c00cb762STyker         ASSERT_TRUE(hasTheRightValue(Assume, I->getOperand(0),
162e5f8a77cSTyker                                      Attribute::AttrKind::Alignment, 32));
163c00cb762STyker         ASSERT_TRUE(hasTheRightValue(Assume, I->getOperand(0),
164e5f8a77cSTyker                                      Attribute::AttrKind::Dereferenceable, 48));
165c00cb762STyker         ASSERT_TRUE(hasTheRightValue(Assume, I->getOperand(1),
166e5f8a77cSTyker                                      Attribute::AttrKind::Dereferenceable, 28));
167c00cb762STyker         ASSERT_TRUE(hasTheRightValue(Assume, I->getOperand(1),
168e5f8a77cSTyker                                      Attribute::AttrKind::Alignment, 8));
169c00cb762STyker         ASSERT_TRUE(hasTheRightValue(Assume, I->getOperand(2),
170e5f8a77cSTyker                                      Attribute::AttrKind::Alignment, 64));
171c00cb762STyker         ASSERT_TRUE(hasTheRightValue(Assume, I->getOperand(2),
172e5f8a77cSTyker                                      Attribute::AttrKind::Dereferenceable, 4));
173c00cb762STyker         ASSERT_TRUE(hasTheRightValue(Assume, I->getOperand(3),
174e5f8a77cSTyker                                      Attribute::AttrKind::Alignment, 16));
175c00cb762STyker         ASSERT_TRUE(hasTheRightValue(Assume, I->getOperand(3),
176e5f8a77cSTyker                                      Attribute::AttrKind::Dereferenceable, 12));
177c00cb762STyker       }));
178c00cb762STyker 
179c00cb762STyker   Tests.push_back(std::make_pair(
180c00cb762STyker       "call void @func1(i32* readnone align 32 "
181c00cb762STyker       "dereferenceable(48) noalias %P, i32* "
182c00cb762STyker       "align 8 dereferenceable(28) %P1, i32* align 64 "
183c00cb762STyker       "dereferenceable(4) "
184c00cb762STyker       "%P2, i32* nonnull align 16 dereferenceable(12) %P3)\n",
185c00cb762STyker       [](Instruction *I) {
1869ef6aa02SPhilip Reames         auto *Assume = buildAssumeFromInst(I);
187*8e702735SJeremy Morse         Assume->insertBefore(I->getIterator());
188c00cb762STyker         I->getOperand(1)->dropDroppableUses();
189c00cb762STyker         I->getOperand(2)->dropDroppableUses();
190c00cb762STyker         I->getOperand(3)->dropDroppableUses();
191c00cb762STyker         ASSERT_TRUE(hasMatchesExactlyAttributes(
192c00cb762STyker             Assume, I->getOperand(0),
193c00cb762STyker             "(align|dereferenceable)"));
194c00cb762STyker         ASSERT_TRUE(hasMatchesExactlyAttributes(Assume, I->getOperand(1),
195c00cb762STyker                                        ""));
196c00cb762STyker         ASSERT_TRUE(hasMatchesExactlyAttributes(Assume, I->getOperand(2),
197c00cb762STyker                                        ""));
198c00cb762STyker         ASSERT_TRUE(hasMatchesExactlyAttributes(Assume, I->getOperand(3),
199c00cb762STyker                                        ""));
200c00cb762STyker         ASSERT_TRUE(hasTheRightValue(Assume, I->getOperand(0),
201e5f8a77cSTyker                                      Attribute::AttrKind::Alignment, 32));
202c00cb762STyker         ASSERT_TRUE(hasTheRightValue(Assume, I->getOperand(0),
203e5f8a77cSTyker                                      Attribute::AttrKind::Dereferenceable, 48));
204c00cb762STyker       }));
205c00cb762STyker   Tests.push_back(std::make_pair(
206c00cb762STyker       "call void @func(i32* nonnull align 4 dereferenceable(16) %P, i32* align "
207edf634ebSJuneyoung Lee       "8 noalias %P1, i32* %P1)\n",
208c00cb762STyker       [](Instruction *I) {
2099ef6aa02SPhilip Reames         auto *Assume = buildAssumeFromInst(I);
210*8e702735SJeremy Morse         Assume->insertBefore(I->getIterator());
211c00cb762STyker         Value *New = I->getFunction()->getArg(3);
212c00cb762STyker         Value *Old = I->getOperand(0);
213c00cb762STyker         ASSERT_TRUE(hasMatchesExactlyAttributes(Assume, New, ""));
214c00cb762STyker         ASSERT_TRUE(hasMatchesExactlyAttributes(Assume, Old,
215c00cb762STyker                                        "(nonnull|align|dereferenceable)"));
216c00cb762STyker         Old->replaceAllUsesWith(New);
217c00cb762STyker         ASSERT_TRUE(hasMatchesExactlyAttributes(Assume, New,
218c00cb762STyker                                        "(nonnull|align|dereferenceable)"));
219c00cb762STyker         ASSERT_TRUE(hasMatchesExactlyAttributes(Assume, Old, ""));
220c00cb762STyker       }));
221c00cb762STyker   RunTest(Head, Tail, Tests);
222c00cb762STyker }
223c00cb762STyker 
224c00cb762STyker static bool FindExactlyAttributes(RetainedKnowledgeMap &Map, Value *WasOn,
225c00cb762STyker                                  StringRef AttrToMatch) {
226c00cb762STyker   Regex Reg(AttrToMatch);
227c00cb762STyker   SmallVector<StringRef, 1> Matches;
228c00cb762STyker   for (StringRef Attr : {
229c00cb762STyker #define GET_ATTR_NAMES
230c00cb762STyker #define ATTRIBUTE_ENUM(ENUM_NAME, DISPLAY_NAME) StringRef(#DISPLAY_NAME),
231c00cb762STyker #include "llvm/IR/Attributes.inc"
232c00cb762STyker        }) {
233c00cb762STyker     bool ShouldHaveAttr = Reg.match(Attr, &Matches) && Matches[0] == Attr;
234c00cb762STyker 
235b595eb83SKazu Hirata     if (ShouldHaveAttr != (Map.contains(RetainedKnowledgeKey{
236b595eb83SKazu Hirata                               WasOn, Attribute::getAttrKindFromName(Attr)})))
237c00cb762STyker       return false;
238c00cb762STyker   }
239c00cb762STyker   return true;
240c00cb762STyker }
241c00cb762STyker 
2429ef6aa02SPhilip Reames static bool MapHasRightValue(RetainedKnowledgeMap &Map, AssumeInst *II,
243c00cb762STyker                              RetainedKnowledgeKey Key, MinMax MM) {
244c00cb762STyker   auto LookupIt = Map.find(Key);
245c00cb762STyker   return (LookupIt != Map.end()) && (LookupIt->second[II].Min == MM.Min) &&
246c00cb762STyker          (LookupIt->second[II].Max == MM.Max);
247c00cb762STyker }
248c00cb762STyker 
249c00cb762STyker TEST(AssumeQueryAPI, fillMapFromAssume) {
250c00cb762STyker   EnableKnowledgeRetention.setValue(true);
251c00cb762STyker   StringRef Head =
252c00cb762STyker       "declare void @llvm.assume(i1)\n"
253edf634ebSJuneyoung Lee       "declare void @func(i32*, i32*, i32*)\n"
254c00cb762STyker       "declare void @func1(i32*, i32*, i32*, i32*)\n"
255c00cb762STyker       "declare void @func_many(i32*) \"no-jump-tables\" nounwind "
256c00cb762STyker       "\"less-precise-fpmad\" willreturn norecurse\n"
257c00cb762STyker       "define void @test(i32* %P, i32* %P1, i32* %P2, i32* %P3) {\n";
258c00cb762STyker   StringRef Tail = "ret void\n"
259c00cb762STyker                    "}";
260c00cb762STyker   std::vector<std::pair<StringRef, llvm::function_ref<void(Instruction *)>>>
261c00cb762STyker       Tests;
262c00cb762STyker   Tests.push_back(std::make_pair(
263c00cb762STyker       "call void @func(i32* nonnull align 4 dereferenceable(16) %P, i32* align "
264edf634ebSJuneyoung Lee       "8 noalias %P1, i32* align 8 dereferenceable(8) %P2)\n",
265c00cb762STyker       [](Instruction *I) {
2669ef6aa02SPhilip Reames         auto *Assume = buildAssumeFromInst(I);
267*8e702735SJeremy Morse         Assume->insertBefore(I->getIterator());
268c00cb762STyker 
269c00cb762STyker         RetainedKnowledgeMap Map;
270c00cb762STyker         fillMapFromAssume(*Assume, Map);
271c00cb762STyker         ASSERT_TRUE(FindExactlyAttributes(Map, I->getOperand(0),
272c00cb762STyker                                        "(nonnull|align|dereferenceable)"));
273edf634ebSJuneyoung Lee         ASSERT_FALSE(FindExactlyAttributes(Map, I->getOperand(1),
274c00cb762STyker                                        "(align)"));
275edf634ebSJuneyoung Lee         ASSERT_TRUE(FindExactlyAttributes(Map, I->getOperand(2),
276edf634ebSJuneyoung Lee                                        "(align|dereferenceable)"));
277c00cb762STyker         ASSERT_TRUE(MapHasRightValue(
278c00cb762STyker             Map, Assume, {I->getOperand(0), Attribute::Dereferenceable}, {16, 16}));
279c00cb762STyker         ASSERT_TRUE(MapHasRightValue(Map, Assume, {I->getOperand(0), Attribute::Alignment},
280c00cb762STyker                                {4, 4}));
281c00cb762STyker         ASSERT_TRUE(MapHasRightValue(Map, Assume, {I->getOperand(0), Attribute::Alignment},
282c00cb762STyker                                {4, 4}));
283c00cb762STyker       }));
284c00cb762STyker   Tests.push_back(std::make_pair(
285c00cb762STyker       "call void @func1(i32* nonnull align 32 dereferenceable(48) %P, i32* "
286c00cb762STyker       "nonnull "
287c00cb762STyker       "align 8 dereferenceable(28) %P, i32* nonnull align 64 "
288c00cb762STyker       "dereferenceable(4) "
289c00cb762STyker       "%P, i32* nonnull align 16 dereferenceable(12) %P)\n",
290c00cb762STyker       [](Instruction *I) {
2919ef6aa02SPhilip Reames         auto *Assume = buildAssumeFromInst(I);
292*8e702735SJeremy Morse         Assume->insertBefore(I->getIterator());
293c00cb762STyker 
294c00cb762STyker         RetainedKnowledgeMap Map;
295c00cb762STyker         fillMapFromAssume(*Assume, Map);
296c00cb762STyker 
297c00cb762STyker         ASSERT_TRUE(FindExactlyAttributes(Map, I->getOperand(0),
298c00cb762STyker                                        "(nonnull|align|dereferenceable)"));
299c00cb762STyker         ASSERT_TRUE(FindExactlyAttributes(Map, I->getOperand(1),
300c00cb762STyker                                        "(nonnull|align|dereferenceable)"));
301c00cb762STyker         ASSERT_TRUE(FindExactlyAttributes(Map, I->getOperand(2),
302c00cb762STyker                                        "(nonnull|align|dereferenceable)"));
303c00cb762STyker         ASSERT_TRUE(FindExactlyAttributes(Map, I->getOperand(3),
304c00cb762STyker                                        "(nonnull|align|dereferenceable)"));
305c00cb762STyker         ASSERT_TRUE(MapHasRightValue(
306e5f8a77cSTyker             Map, Assume, {I->getOperand(0), Attribute::Dereferenceable},
307e5f8a77cSTyker             {48, 48}));
308e5f8a77cSTyker         ASSERT_TRUE(MapHasRightValue(
309e5f8a77cSTyker             Map, Assume, {I->getOperand(0), Attribute::Alignment}, {64, 64}));
310c00cb762STyker       }));
311c00cb762STyker   Tests.push_back(std::make_pair(
312c00cb762STyker       "call void @func_many(i32* align 8 %P1) cold\n", [](Instruction *I) {
313c00cb762STyker         ShouldPreserveAllAttributes.setValue(true);
3149ef6aa02SPhilip Reames         auto *Assume = buildAssumeFromInst(I);
315*8e702735SJeremy Morse         Assume->insertBefore(I->getIterator());
316c00cb762STyker 
317c00cb762STyker         RetainedKnowledgeMap Map;
318c00cb762STyker         fillMapFromAssume(*Assume, Map);
319c00cb762STyker 
320c00cb762STyker         ASSERT_TRUE(FindExactlyAttributes(
321c00cb762STyker             Map, nullptr, "(nounwind|norecurse|willreturn|cold)"));
322c00cb762STyker         ShouldPreserveAllAttributes.setValue(false);
323c00cb762STyker       }));
324c00cb762STyker   Tests.push_back(
325c00cb762STyker       std::make_pair("call void @llvm.assume(i1 true)\n", [](Instruction *I) {
326c00cb762STyker         RetainedKnowledgeMap Map;
3279ef6aa02SPhilip Reames         fillMapFromAssume(*cast<AssumeInst>(I), Map);
328c00cb762STyker 
329c00cb762STyker         ASSERT_TRUE(FindExactlyAttributes(Map, nullptr, ""));
330c00cb762STyker         ASSERT_TRUE(Map.empty());
331c00cb762STyker       }));
332c00cb762STyker   Tests.push_back(std::make_pair(
333c00cb762STyker       "call void @func1(i32* readnone align 32 "
334c00cb762STyker       "dereferenceable(48) noalias %P, i32* "
335c00cb762STyker       "align 8 dereferenceable(28) %P1, i32* align 64 "
336c00cb762STyker       "dereferenceable(4) "
337c00cb762STyker       "%P2, i32* nonnull align 16 dereferenceable(12) %P3)\n",
338c00cb762STyker       [](Instruction *I) {
3399ef6aa02SPhilip Reames         auto *Assume = buildAssumeFromInst(I);
340*8e702735SJeremy Morse         Assume->insertBefore(I->getIterator());
341c00cb762STyker 
342c00cb762STyker         RetainedKnowledgeMap Map;
343c00cb762STyker         fillMapFromAssume(*Assume, Map);
344c00cb762STyker 
345c00cb762STyker         ASSERT_TRUE(FindExactlyAttributes(Map, I->getOperand(0),
346c00cb762STyker                                     "(align|dereferenceable)"));
347c00cb762STyker         ASSERT_TRUE(FindExactlyAttributes(Map, I->getOperand(1),
348c00cb762STyker                                     "(align|dereferenceable)"));
349c00cb762STyker         ASSERT_TRUE(FindExactlyAttributes(Map, I->getOperand(2),
350c00cb762STyker                                        "(align|dereferenceable)"));
351c00cb762STyker         ASSERT_TRUE(FindExactlyAttributes(Map, I->getOperand(3),
352c00cb762STyker                                        "(nonnull|align|dereferenceable)"));
353c00cb762STyker         ASSERT_TRUE(MapHasRightValue(Map, Assume, {I->getOperand(0), Attribute::Alignment},
354c00cb762STyker                                {32, 32}));
355c00cb762STyker         ASSERT_TRUE(MapHasRightValue(
356c00cb762STyker             Map, Assume, {I->getOperand(0), Attribute::Dereferenceable}, {48, 48}));
357c00cb762STyker         ASSERT_TRUE(MapHasRightValue(
358c00cb762STyker             Map, Assume, {I->getOperand(1), Attribute::Dereferenceable}, {28, 28}));
359c00cb762STyker         ASSERT_TRUE(MapHasRightValue(Map, Assume, {I->getOperand(1), Attribute::Alignment},
360c00cb762STyker                                {8, 8}));
361c00cb762STyker         ASSERT_TRUE(MapHasRightValue(Map, Assume, {I->getOperand(2), Attribute::Alignment},
362c00cb762STyker                                {64, 64}));
363c00cb762STyker         ASSERT_TRUE(MapHasRightValue(
364c00cb762STyker             Map, Assume, {I->getOperand(2), Attribute::Dereferenceable}, {4, 4}));
365c00cb762STyker         ASSERT_TRUE(MapHasRightValue(Map, Assume, {I->getOperand(3), Attribute::Alignment},
366c00cb762STyker                                {16, 16}));
367c00cb762STyker         ASSERT_TRUE(MapHasRightValue(
368c00cb762STyker             Map, Assume, {I->getOperand(3), Attribute::Dereferenceable}, {12, 12}));
369c00cb762STyker       }));
370c00cb762STyker 
371c00cb762STyker   /// Keep this test last as it modifies the function.
372c00cb762STyker   Tests.push_back(std::make_pair(
373c00cb762STyker       "call void @func(i32* nonnull align 4 dereferenceable(16) %P, i32* align "
374edf634ebSJuneyoung Lee       "8 noalias %P1, i32* %P2)\n",
375c00cb762STyker       [](Instruction *I) {
3769ef6aa02SPhilip Reames         auto *Assume = buildAssumeFromInst(I);
377*8e702735SJeremy Morse         Assume->insertBefore(I->getIterator());
378c00cb762STyker 
379c00cb762STyker         RetainedKnowledgeMap Map;
380c00cb762STyker         fillMapFromAssume(*Assume, Map);
381c00cb762STyker 
382c00cb762STyker         Value *New = I->getFunction()->getArg(3);
383c00cb762STyker         Value *Old = I->getOperand(0);
384c00cb762STyker         ASSERT_TRUE(FindExactlyAttributes(Map, New, ""));
385c00cb762STyker         ASSERT_TRUE(FindExactlyAttributes(Map, Old,
386c00cb762STyker                                        "(nonnull|align|dereferenceable)"));
387c00cb762STyker         Old->replaceAllUsesWith(New);
388c00cb762STyker         Map.clear();
389c00cb762STyker         fillMapFromAssume(*Assume, Map);
390c00cb762STyker         ASSERT_TRUE(FindExactlyAttributes(Map, New,
391c00cb762STyker                                        "(nonnull|align|dereferenceable)"));
392c00cb762STyker         ASSERT_TRUE(FindExactlyAttributes(Map, Old, ""));
393c00cb762STyker       }));
394d22fbccfSJohannes Doerfert   Tests.push_back(std::make_pair(
395d22fbccfSJohannes Doerfert       "call void @llvm.assume(i1 true) [\"align\"(i8* undef, i32 undef)]",
396d22fbccfSJohannes Doerfert       [](Instruction *I) {
397d22fbccfSJohannes Doerfert         // Don't crash but don't learn from undef.
398d22fbccfSJohannes Doerfert         RetainedKnowledgeMap Map;
3999ef6aa02SPhilip Reames         fillMapFromAssume(*cast<AssumeInst>(I), Map);
400d22fbccfSJohannes Doerfert 
401d22fbccfSJohannes Doerfert         ASSERT_TRUE(Map.empty());
402d22fbccfSJohannes Doerfert       }));
403c00cb762STyker   RunTest(Head, Tail, Tests);
404c00cb762STyker }
405c00cb762STyker 
406c00cb762STyker static void RunRandTest(uint64_t Seed, int Size, int MinCount, int MaxCount,
407c00cb762STyker                         unsigned MaxValue) {
408c00cb762STyker   LLVMContext C;
409c00cb762STyker   SMDiagnostic Err;
410c00cb762STyker 
411c00cb762STyker   std::mt19937 Rng(Seed);
412c00cb762STyker   std::uniform_int_distribution<int> DistCount(MinCount, MaxCount);
413c00cb762STyker   std::uniform_int_distribution<unsigned> DistValue(0, MaxValue);
414c00cb762STyker   std::uniform_int_distribution<unsigned> DistAttr(0,
415c00cb762STyker                                                    Attribute::EndAttrKinds - 1);
416c00cb762STyker 
417c00cb762STyker   std::unique_ptr<Module> Mod = std::make_unique<Module>("AssumeQueryAPI", C);
418c00cb762STyker   if (!Mod)
419c00cb762STyker     Err.print("AssumeQueryAPI", errs());
420c00cb762STyker 
421c00cb762STyker   std::vector<Type *> TypeArgs;
422c00cb762STyker   for (int i = 0; i < (Size * 2); i++)
423fd05c34bSBjorn Pettersson     TypeArgs.push_back(PointerType::getUnqual(C));
424c00cb762STyker   FunctionType *FuncType =
425c00cb762STyker       FunctionType::get(Type::getVoidTy(C), TypeArgs, false);
426c00cb762STyker 
427c00cb762STyker   Function *F =
428c00cb762STyker       Function::Create(FuncType, GlobalValue::ExternalLinkage, "test", &*Mod);
429c00cb762STyker   BasicBlock *BB = BasicBlock::Create(C);
430c00cb762STyker   BB->insertInto(F);
431c00cb762STyker   Instruction *Ret = ReturnInst::Create(C);
43232b38d24SVasileios Porpodas   Ret->insertInto(BB, BB->begin());
433fa789dffSRahul Joshi   Function *FnAssume =
434fa789dffSRahul Joshi       Intrinsic::getOrInsertDeclaration(Mod.get(), Intrinsic::assume);
435c00cb762STyker 
436c00cb762STyker   std::vector<Argument *> ShuffledArgs;
4375f4ae564SJan Svoboda   BitVector HasArg;
438c00cb762STyker   for (auto &Arg : F->args()) {
439c00cb762STyker     ShuffledArgs.push_back(&Arg);
440c00cb762STyker     HasArg.push_back(false);
441c00cb762STyker   }
442c00cb762STyker 
443c00cb762STyker   std::shuffle(ShuffledArgs.begin(), ShuffledArgs.end(), Rng);
444c00cb762STyker 
445c00cb762STyker   std::vector<OperandBundleDef> OpBundle;
446c00cb762STyker   OpBundle.reserve(Size);
447c00cb762STyker   std::vector<Value *> Args;
448c00cb762STyker   Args.reserve(2);
449c00cb762STyker   for (int i = 0; i < Size; i++) {
450c00cb762STyker     int count = DistCount(Rng);
451c00cb762STyker     int value = DistValue(Rng);
452c00cb762STyker     int attr = DistAttr(Rng);
453c00cb762STyker     std::string str;
454c00cb762STyker     raw_string_ostream ss(str);
455c00cb762STyker     ss << Attribute::getNameFromAttrKind(
456c00cb762STyker         static_cast<Attribute::AttrKind>(attr));
457c00cb762STyker     Args.clear();
458c00cb762STyker 
459c00cb762STyker     if (count > 0) {
460c00cb762STyker       Args.push_back(ShuffledArgs[i]);
461c00cb762STyker       HasArg[i] = true;
462c00cb762STyker     }
463c00cb762STyker     if (count > 1)
464c00cb762STyker       Args.push_back(ConstantInt::get(Type::getInt32Ty(C), value));
465c00cb762STyker 
46652b48a70SJOE1994     OpBundle.push_back(OperandBundleDef{str.c_str(), std::move(Args)});
467c00cb762STyker   }
468c00cb762STyker 
4699ef6aa02SPhilip Reames   auto *Assume = cast<AssumeInst>(CallInst::Create(
470c00cb762STyker       FnAssume, ArrayRef<Value *>({ConstantInt::getTrue(C)}), OpBundle));
471*8e702735SJeremy Morse   Assume->insertBefore(F->begin()->begin());
472c00cb762STyker   RetainedKnowledgeMap Map;
473c00cb762STyker   fillMapFromAssume(*Assume, Map);
474c00cb762STyker   for (int i = 0; i < (Size * 2); i++) {
475c00cb762STyker     if (!HasArg[i])
476c00cb762STyker       continue;
477c00cb762STyker     RetainedKnowledge K =
478c00cb762STyker         getKnowledgeFromUseInAssume(&*ShuffledArgs[i]->use_begin());
479c00cb762STyker     auto LookupIt = Map.find(RetainedKnowledgeKey{K.WasOn, K.AttrKind});
480c00cb762STyker     ASSERT_TRUE(LookupIt != Map.end());
481c00cb762STyker     MinMax MM = LookupIt->second[Assume];
482c00cb762STyker     ASSERT_TRUE(MM.Min == MM.Max);
483c00cb762STyker     ASSERT_TRUE(MM.Min == K.ArgValue);
484c00cb762STyker   }
485c00cb762STyker }
486c00cb762STyker 
487c00cb762STyker TEST(AssumeQueryAPI, getKnowledgeFromUseInAssume) {
488c00cb762STyker   // // For Fuzzing
489c00cb762STyker   // std::random_device dev;
490c00cb762STyker   // std::mt19937 Rng(dev());
491c00cb762STyker   // while (true) {
492c00cb762STyker   //   unsigned Seed = Rng();
493c00cb762STyker   //   dbgs() << Seed << "\n";
494c00cb762STyker   //   RunRandTest(Seed, 100000, 0, 2, 100);
495c00cb762STyker   // }
496c00cb762STyker   RunRandTest(23456, 4, 0, 2, 100);
497c00cb762STyker   RunRandTest(560987, 25, -3, 2, 100);
498c00cb762STyker 
499c00cb762STyker   // Large bundles can lead to special cases. this is why this test is soo
500c00cb762STyker   // large.
501c00cb762STyker   RunRandTest(9876789, 100000, -0, 7, 100);
502c00cb762STyker }
503813f438bSTyker 
504813f438bSTyker TEST(AssumeQueryAPI, AssumptionCache) {
505813f438bSTyker   LLVMContext C;
506813f438bSTyker   SMDiagnostic Err;
507813f438bSTyker   std::unique_ptr<Module> Mod = parseAssemblyString(
508813f438bSTyker       "declare void @llvm.assume(i1)\n"
509813f438bSTyker       "define void @test(i32* %P, i32* %P1, i32* %P2, i32* %P3, i1 %B) {\n"
510813f438bSTyker       "call void @llvm.assume(i1 true) [\"nonnull\"(i32* %P), \"align\"(i32* "
511813f438bSTyker       "%P2, i32 4), \"align\"(i32* %P, i32 8)]\n"
512813f438bSTyker       "call void @llvm.assume(i1 %B) [\"test\"(i32* %P1), "
513813f438bSTyker       "\"dereferenceable\"(i32* %P, i32 4)]\n"
514813f438bSTyker       "ret void\n}\n",
515813f438bSTyker       Err, C);
516813f438bSTyker   if (!Mod)
517813f438bSTyker     Err.print("AssumeQueryAPI", errs());
518813f438bSTyker   Function *F = Mod->getFunction("test");
519813f438bSTyker   BasicBlock::iterator First = F->begin()->begin();
520813f438bSTyker   BasicBlock::iterator Second = F->begin()->begin();
521813f438bSTyker   Second++;
522bf225939SMichael Liao   AssumptionCache AC(*F);
523813f438bSTyker   auto AR = AC.assumptionsFor(F->getArg(3));
524813f438bSTyker   ASSERT_EQ(AR.size(), 0u);
525813f438bSTyker   AR = AC.assumptionsFor(F->getArg(1));
526813f438bSTyker   ASSERT_EQ(AR.size(), 1u);
527813f438bSTyker   ASSERT_EQ(AR[0].Index, 0u);
528813f438bSTyker   ASSERT_EQ(AR[0].Assume, &*Second);
529813f438bSTyker   AR = AC.assumptionsFor(F->getArg(2));
530813f438bSTyker   ASSERT_EQ(AR.size(), 1u);
531813f438bSTyker   ASSERT_EQ(AR[0].Index, 1u);
532813f438bSTyker   ASSERT_EQ(AR[0].Assume, &*First);
533813f438bSTyker   AR = AC.assumptionsFor(F->getArg(0));
534813f438bSTyker   ASSERT_EQ(AR.size(), 3u);
535813f438bSTyker   llvm::sort(AR,
536813f438bSTyker              [](const auto &L, const auto &R) { return L.Index < R.Index; });
537813f438bSTyker   ASSERT_EQ(AR[0].Assume, &*First);
538813f438bSTyker   ASSERT_EQ(AR[0].Index, 0u);
539813f438bSTyker   ASSERT_EQ(AR[1].Assume, &*Second);
540813f438bSTyker   ASSERT_EQ(AR[1].Index, 1u);
541813f438bSTyker   ASSERT_EQ(AR[2].Assume, &*First);
542813f438bSTyker   ASSERT_EQ(AR[2].Index, 2u);
543813f438bSTyker   AR = AC.assumptionsFor(F->getArg(4));
544813f438bSTyker   ASSERT_EQ(AR.size(), 1u);
545813f438bSTyker   ASSERT_EQ(AR[0].Assume, &*Second);
546813f438bSTyker   ASSERT_EQ(AR[0].Index, AssumptionCache::ExprResultIdx);
547a6d2a8d6SPhilip Reames   AC.unregisterAssumption(cast<AssumeInst>(&*Second));
548813f438bSTyker   AR = AC.assumptionsFor(F->getArg(1));
549813f438bSTyker   ASSERT_EQ(AR.size(), 0u);
550813f438bSTyker   AR = AC.assumptionsFor(F->getArg(0));
551813f438bSTyker   ASSERT_EQ(AR.size(), 3u);
552813f438bSTyker   llvm::sort(AR,
553813f438bSTyker              [](const auto &L, const auto &R) { return L.Index < R.Index; });
554813f438bSTyker   ASSERT_EQ(AR[0].Assume, &*First);
555813f438bSTyker   ASSERT_EQ(AR[0].Index, 0u);
556813f438bSTyker   ASSERT_EQ(AR[1].Assume, nullptr);
557813f438bSTyker   ASSERT_EQ(AR[1].Index, 1u);
558813f438bSTyker   ASSERT_EQ(AR[2].Assume, &*First);
559813f438bSTyker   ASSERT_EQ(AR[2].Index, 2u);
560813f438bSTyker   AR = AC.assumptionsFor(F->getArg(2));
561813f438bSTyker   ASSERT_EQ(AR.size(), 1u);
562813f438bSTyker   ASSERT_EQ(AR[0].Index, 1u);
563813f438bSTyker   ASSERT_EQ(AR[0].Assume, &*First);
564813f438bSTyker }
56578de7297STyker 
56678de7297STyker TEST(AssumeQueryAPI, Alignment) {
56778de7297STyker   LLVMContext C;
56878de7297STyker   SMDiagnostic Err;
56978de7297STyker   std::unique_ptr<Module> Mod = parseAssemblyString(
57078de7297STyker       "declare void @llvm.assume(i1)\n"
57178de7297STyker       "define void @test(i32* %P, i32* %P1, i32* %P2, i32 %I3, i1 %B) {\n"
57278de7297STyker       "call void @llvm.assume(i1 true) [\"align\"(i32* %P, i32 8, i32 %I3)]\n"
57378de7297STyker       "call void @llvm.assume(i1 true) [\"align\"(i32* %P1, i32 %I3, i32 "
57478de7297STyker       "%I3)]\n"
57578de7297STyker       "call void @llvm.assume(i1 true) [\"align\"(i32* %P2, i32 16, i32 8)]\n"
57678de7297STyker       "ret void\n}\n",
57778de7297STyker       Err, C);
57878de7297STyker   if (!Mod)
57978de7297STyker     Err.print("AssumeQueryAPI", errs());
58078de7297STyker 
58178de7297STyker   Function *F = Mod->getFunction("test");
58278de7297STyker   BasicBlock::iterator Start = F->begin()->begin();
5839ef6aa02SPhilip Reames   AssumeInst *II;
58478de7297STyker   RetainedKnowledge RK;
5859ef6aa02SPhilip Reames   II = cast<AssumeInst>(&*Start);
58678de7297STyker   RK = getKnowledgeFromBundle(*II, II->bundle_op_info_begin()[0]);
58778de7297STyker   ASSERT_EQ(RK.AttrKind, Attribute::Alignment);
58878de7297STyker   ASSERT_EQ(RK.WasOn, F->getArg(0));
58978de7297STyker   ASSERT_EQ(RK.ArgValue, 1u);
59078de7297STyker   Start++;
5919ef6aa02SPhilip Reames   II = cast<AssumeInst>(&*Start);
59278de7297STyker   RK = getKnowledgeFromBundle(*II, II->bundle_op_info_begin()[0]);
59378de7297STyker   ASSERT_EQ(RK.AttrKind, Attribute::Alignment);
59478de7297STyker   ASSERT_EQ(RK.WasOn, F->getArg(1));
59578de7297STyker   ASSERT_EQ(RK.ArgValue, 1u);
59678de7297STyker   Start++;
5979ef6aa02SPhilip Reames   II = cast<AssumeInst>(&*Start);
59878de7297STyker   RK = getKnowledgeFromBundle(*II, II->bundle_op_info_begin()[0]);
59978de7297STyker   ASSERT_EQ(RK.AttrKind, Attribute::Alignment);
60078de7297STyker   ASSERT_EQ(RK.WasOn, F->getArg(2));
60178de7297STyker   ASSERT_EQ(RK.ArgValue, 8u);
60278de7297STyker }
603