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