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