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