1 //===- DependencyGraphTest.cpp --------------------------------------------===// 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/Transforms/Vectorize/SandboxVectorizer/DependencyGraph.h" 10 #include "llvm/Analysis/AliasAnalysis.h" 11 #include "llvm/Analysis/AssumptionCache.h" 12 #include "llvm/Analysis/BasicAliasAnalysis.h" 13 #include "llvm/Analysis/TargetLibraryInfo.h" 14 #include "llvm/AsmParser/Parser.h" 15 #include "llvm/IR/DataLayout.h" 16 #include "llvm/IR/Dominators.h" 17 #include "llvm/SandboxIR/Context.h" 18 #include "llvm/SandboxIR/Function.h" 19 #include "llvm/SandboxIR/Instruction.h" 20 #include "llvm/Support/SourceMgr.h" 21 #include "gmock/gmock-matchers.h" 22 #include "gtest/gtest.h" 23 24 using namespace llvm; 25 26 struct DependencyGraphTest : public testing::Test { 27 LLVMContext C; 28 std::unique_ptr<Module> M; 29 std::unique_ptr<AssumptionCache> AC; 30 std::unique_ptr<DominatorTree> DT; 31 std::unique_ptr<BasicAAResult> BAA; 32 std::unique_ptr<AAResults> AA; 33 34 void parseIR(LLVMContext &C, const char *IR) { 35 SMDiagnostic Err; 36 M = parseAssemblyString(IR, Err, C); 37 if (!M) 38 Err.print("DependencyGraphTest", errs()); 39 } 40 41 AAResults &getAA(llvm::Function &LLVMF) { 42 TargetLibraryInfoImpl TLII; 43 TargetLibraryInfo TLI(TLII); 44 AA = std::make_unique<AAResults>(TLI); 45 AC = std::make_unique<AssumptionCache>(LLVMF); 46 DT = std::make_unique<DominatorTree>(LLVMF); 47 BAA = std::make_unique<BasicAAResult>(M->getDataLayout(), LLVMF, TLI, *AC, 48 DT.get()); 49 AA->addAAResult(*BAA); 50 return *AA; 51 } 52 /// \Returns true if there is a dependency: SrcN->DstN. 53 bool memDependency(sandboxir::DGNode *SrcN, sandboxir::DGNode *DstN) { 54 if (auto *MemDstN = dyn_cast<sandboxir::MemDGNode>(DstN)) 55 return MemDstN->hasMemPred(SrcN); 56 return false; 57 } 58 }; 59 60 TEST_F(DependencyGraphTest, isStackSaveOrRestoreIntrinsic) { 61 parseIR(C, R"IR( 62 declare void @llvm.sideeffect() 63 define void @foo(i8 %v1, ptr %ptr) { 64 %add = add i8 %v1, %v1 65 %stacksave = call ptr @llvm.stacksave() 66 call void @llvm.stackrestore(ptr %stacksave) 67 call void @llvm.sideeffect() 68 ret void 69 } 70 )IR"); 71 llvm::Function *LLVMF = &*M->getFunction("foo"); 72 sandboxir::Context Ctx(C); 73 sandboxir::Function *F = Ctx.createFunction(LLVMF); 74 auto *BB = &*F->begin(); 75 auto It = BB->begin(); 76 auto *Add = cast<sandboxir::BinaryOperator>(&*It++); 77 auto *StackSave = cast<sandboxir::CallInst>(&*It++); 78 auto *StackRestore = cast<sandboxir::CallInst>(&*It++); 79 auto *Other = cast<sandboxir::CallInst>(&*It++); 80 auto *Ret = cast<sandboxir::ReturnInst>(&*It++); 81 82 using DGNode = sandboxir::DGNode; 83 EXPECT_FALSE(DGNode::isStackSaveOrRestoreIntrinsic(Add)); 84 EXPECT_TRUE(DGNode::isStackSaveOrRestoreIntrinsic(StackSave)); 85 EXPECT_TRUE(DGNode::isStackSaveOrRestoreIntrinsic(StackRestore)); 86 EXPECT_FALSE(DGNode::isStackSaveOrRestoreIntrinsic(Other)); 87 EXPECT_FALSE(DGNode::isStackSaveOrRestoreIntrinsic(Ret)); 88 } 89 90 TEST_F(DependencyGraphTest, Instruction_isMemDepCandidate) { 91 parseIR(C, R"IR( 92 declare void @llvm.fake.use(...) 93 declare void @llvm.sideeffect() 94 declare void @llvm.pseudoprobe(i64, i64, i32, i64) 95 declare void @bar() 96 define void @foo(i8 %v1, ptr %ptr) { 97 %add0 = add i8 %v1, %v1 98 %ld0 = load i8, ptr %ptr 99 store i8 %v1, ptr %ptr 100 call void @llvm.sideeffect() 101 call void @llvm.pseudoprobe(i64 42, i64 1, i32 0, i64 -1) 102 call void @llvm.fake.use(ptr %ptr) 103 call void @bar() 104 ret void 105 } 106 )IR"); 107 llvm::Function *LLVMF = &*M->getFunction("foo"); 108 sandboxir::Context Ctx(C); 109 sandboxir::Function *F = Ctx.createFunction(LLVMF); 110 auto *BB = &*F->begin(); 111 auto It = BB->begin(); 112 auto *Add0 = cast<sandboxir::BinaryOperator>(&*It++); 113 auto *Ld0 = cast<sandboxir::LoadInst>(&*It++); 114 auto *St0 = cast<sandboxir::StoreInst>(&*It++); 115 auto *SideEffect0 = cast<sandboxir::CallInst>(&*It++); 116 auto *PseudoProbe0 = cast<sandboxir::CallInst>(&*It++); 117 auto *OtherIntrinsic0 = cast<sandboxir::CallInst>(&*It++); 118 auto *CallBar = cast<sandboxir::CallInst>(&*It++); 119 auto *Ret = cast<sandboxir::ReturnInst>(&*It++); 120 121 using DGNode = sandboxir::DGNode; 122 123 EXPECT_FALSE(DGNode::isMemDepCandidate(Add0)); 124 EXPECT_TRUE(DGNode::isMemDepCandidate(Ld0)); 125 EXPECT_TRUE(DGNode::isMemDepCandidate(St0)); 126 EXPECT_FALSE(DGNode::isMemDepCandidate(SideEffect0)); 127 EXPECT_FALSE(DGNode::isMemDepCandidate(PseudoProbe0)); 128 EXPECT_TRUE(DGNode::isMemDepCandidate(OtherIntrinsic0)); 129 EXPECT_TRUE(DGNode::isMemDepCandidate(CallBar)); 130 EXPECT_FALSE(DGNode::isMemDepCandidate(Ret)); 131 } 132 133 TEST_F(DependencyGraphTest, Instruction_isMemIntrinsic) { 134 parseIR(C, R"IR( 135 declare void @llvm.sideeffect() 136 declare void @llvm.pseudoprobe(i64) 137 declare void @llvm.assume(i1) 138 139 define void @foo(ptr %ptr, i1 %cond) { 140 call void @llvm.sideeffect() 141 call void @llvm.pseudoprobe(i64 42) 142 call void @llvm.assume(i1 %cond) 143 ret void 144 } 145 )IR"); 146 llvm::Function *LLVMF = &*M->getFunction("foo"); 147 sandboxir::Context Ctx(C); 148 sandboxir::Function *F = Ctx.createFunction(LLVMF); 149 auto *BB = &*F->begin(); 150 auto It = BB->begin(); 151 auto *SideEffect = cast<sandboxir::IntrinsicInst>(&*It++); 152 auto *PseudoProbe = cast<sandboxir::IntrinsicInst>(&*It++); 153 auto *OtherIntrinsic = cast<sandboxir::IntrinsicInst>(&*It++); 154 155 using DGNode = sandboxir::DGNode; 156 EXPECT_FALSE(DGNode::isMemIntrinsic(SideEffect)); 157 EXPECT_FALSE(DGNode::isMemIntrinsic(PseudoProbe)); 158 EXPECT_TRUE(DGNode::isMemIntrinsic(OtherIntrinsic)); 159 } 160 161 TEST_F(DependencyGraphTest, MemDGNode) { 162 parseIR(C, R"IR( 163 declare void @llvm.sideeffect() 164 declare void @llvm.pseudoprobe(i64, i64, i32, i64) 165 declare void @llvm.fake.use(...) 166 declare void @bar() 167 define void @foo(i8 %v1, ptr %ptr) { 168 store i8 %v1, ptr %ptr 169 %ld0 = load i8, ptr %ptr 170 %add = add i8 %v1, %v1 171 %stacksave = call ptr @llvm.stacksave() 172 call void @llvm.stackrestore(ptr %stacksave) 173 call void @llvm.sideeffect() 174 call void @llvm.pseudoprobe(i64 42, i64 1, i32 0, i64 -1) 175 call void @llvm.fake.use(ptr %ptr) 176 call void @bar() 177 ret void 178 } 179 )IR"); 180 llvm::Function *LLVMF = &*M->getFunction("foo"); 181 sandboxir::Context Ctx(C); 182 183 auto *F = Ctx.createFunction(LLVMF); 184 auto *BB = &*F->begin(); 185 auto It = BB->begin(); 186 auto *Store = cast<sandboxir::StoreInst>(&*It++); 187 auto *Load = cast<sandboxir::LoadInst>(&*It++); 188 auto *Add = cast<sandboxir::BinaryOperator>(&*It++); 189 auto *StackSave = cast<sandboxir::CallInst>(&*It++); 190 auto *StackRestore = cast<sandboxir::CallInst>(&*It++); 191 auto *SideEffect = cast<sandboxir::CallInst>(&*It++); 192 auto *PseudoProbe = cast<sandboxir::CallInst>(&*It++); 193 auto *FakeUse = cast<sandboxir::CallInst>(&*It++); 194 auto *Call = cast<sandboxir::CallInst>(&*It++); 195 auto *Ret = cast<sandboxir::ReturnInst>(&*It++); 196 197 sandboxir::DependencyGraph DAG(getAA(*LLVMF)); 198 DAG.extend({&*BB->begin(), BB->getTerminator()}); 199 EXPECT_TRUE(isa<llvm::sandboxir::MemDGNode>(DAG.getNode(Store))); 200 EXPECT_TRUE(isa<llvm::sandboxir::MemDGNode>(DAG.getNode(Load))); 201 EXPECT_FALSE(isa<llvm::sandboxir::MemDGNode>(DAG.getNode(Add))); 202 EXPECT_TRUE(isa<llvm::sandboxir::MemDGNode>(DAG.getNode(StackSave))); 203 EXPECT_TRUE(isa<llvm::sandboxir::MemDGNode>(DAG.getNode(StackRestore))); 204 EXPECT_FALSE(isa<llvm::sandboxir::MemDGNode>(DAG.getNode(SideEffect))); 205 EXPECT_FALSE(isa<llvm::sandboxir::MemDGNode>(DAG.getNode(PseudoProbe))); 206 EXPECT_TRUE(isa<llvm::sandboxir::MemDGNode>(DAG.getNode(FakeUse))); 207 EXPECT_TRUE(isa<llvm::sandboxir::MemDGNode>(DAG.getNode(Call))); 208 EXPECT_FALSE(isa<llvm::sandboxir::MemDGNode>(DAG.getNode(Ret))); 209 } 210 211 TEST_F(DependencyGraphTest, Basic) { 212 parseIR(C, R"IR( 213 define void @foo(ptr %ptr, i8 %v0, i8 %v1) { 214 store i8 %v0, ptr %ptr 215 store i8 %v1, ptr %ptr 216 ret void 217 } 218 )IR"); 219 llvm::Function *LLVMF = &*M->getFunction("foo"); 220 sandboxir::Context Ctx(C); 221 auto *F = Ctx.createFunction(LLVMF); 222 auto *BB = &*F->begin(); 223 auto It = BB->begin(); 224 auto *S0 = cast<sandboxir::StoreInst>(&*It++); 225 auto *S1 = cast<sandboxir::StoreInst>(&*It++); 226 auto *Ret = cast<sandboxir::ReturnInst>(&*It++); 227 sandboxir::DependencyGraph DAG(getAA(*LLVMF)); 228 auto Span = DAG.extend({&*BB->begin(), BB->getTerminator()}); 229 // Check extend(). 230 EXPECT_EQ(Span.top(), &*BB->begin()); 231 EXPECT_EQ(Span.bottom(), BB->getTerminator()); 232 233 auto *N0 = cast<sandboxir::MemDGNode>(DAG.getNode(S0)); 234 auto *N1 = cast<sandboxir::MemDGNode>(DAG.getNode(S1)); 235 auto *N2 = DAG.getNode(Ret); 236 237 // Check getInstruction(). 238 EXPECT_EQ(N0->getInstruction(), S0); 239 EXPECT_EQ(N1->getInstruction(), S1); 240 // Check hasMemPred() 241 EXPECT_TRUE(N1->hasMemPred(N0)); 242 EXPECT_FALSE(N0->hasMemPred(N1)); 243 244 // Check preds(). 245 EXPECT_TRUE(N0->preds(DAG).empty()); 246 EXPECT_THAT(N1->preds(DAG), testing::ElementsAre(N0)); 247 248 // Check memPreds(). 249 EXPECT_TRUE(N0->memPreds().empty()); 250 EXPECT_THAT(N1->memPreds(), testing::ElementsAre(N0)); 251 EXPECT_TRUE(N2->preds(DAG).empty()); 252 } 253 254 TEST_F(DependencyGraphTest, Preds) { 255 parseIR(C, R"IR( 256 declare ptr @bar(i8) 257 define i8 @foo(i8 %v0, i8 %v1) { 258 %add0 = add i8 %v0, %v0 259 %add1 = add i8 %v1, %v1 260 %add2 = add i8 %add0, %add1 261 %ptr = call ptr @bar(i8 %add1) 262 store i8 %add2, ptr %ptr 263 ret i8 %add2 264 } 265 )IR"); 266 llvm::Function *LLVMF = &*M->getFunction("foo"); 267 sandboxir::Context Ctx(C); 268 auto *F = Ctx.createFunction(LLVMF); 269 auto *BB = &*F->begin(); 270 auto It = BB->begin(); 271 sandboxir::DependencyGraph DAG(getAA(*LLVMF)); 272 DAG.extend({&*BB->begin(), BB->getTerminator()}); 273 274 auto *AddN0 = DAG.getNode(cast<sandboxir::BinaryOperator>(&*It++)); 275 auto *AddN1 = DAG.getNode(cast<sandboxir::BinaryOperator>(&*It++)); 276 auto *AddN2 = DAG.getNode(cast<sandboxir::BinaryOperator>(&*It++)); 277 auto *CallN = DAG.getNode(cast<sandboxir::CallInst>(&*It++)); 278 auto *StN = DAG.getNode(cast<sandboxir::StoreInst>(&*It++)); 279 auto *RetN = DAG.getNode(cast<sandboxir::ReturnInst>(&*It++)); 280 281 // Check preds(). 282 EXPECT_THAT(AddN0->preds(DAG), testing::ElementsAre()); 283 EXPECT_THAT(AddN1->preds(DAG), testing::ElementsAre()); 284 EXPECT_THAT(AddN2->preds(DAG), testing::ElementsAre(AddN0, AddN1)); 285 EXPECT_THAT(CallN->preds(DAG), testing::ElementsAre(AddN1)); 286 EXPECT_THAT(StN->preds(DAG), 287 testing::UnorderedElementsAre(CallN, CallN, AddN2)); 288 EXPECT_THAT(RetN->preds(DAG), testing::ElementsAre(AddN2)); 289 } 290 291 TEST_F(DependencyGraphTest, MemDGNode_getPrevNode_getNextNode) { 292 parseIR(C, R"IR( 293 define void @foo(ptr %ptr, i8 %v0, i8 %v1) { 294 store i8 %v0, ptr %ptr 295 add i8 %v0, %v0 296 store i8 %v1, ptr %ptr 297 ret void 298 } 299 )IR"); 300 llvm::Function *LLVMF = &*M->getFunction("foo"); 301 sandboxir::Context Ctx(C); 302 auto *F = Ctx.createFunction(LLVMF); 303 auto *BB = &*F->begin(); 304 auto It = BB->begin(); 305 auto *S0 = cast<sandboxir::StoreInst>(&*It++); 306 [[maybe_unused]] auto *Add = cast<sandboxir::BinaryOperator>(&*It++); 307 auto *S1 = cast<sandboxir::StoreInst>(&*It++); 308 [[maybe_unused]] auto *Ret = cast<sandboxir::ReturnInst>(&*It++); 309 310 sandboxir::DependencyGraph DAG(getAA(*LLVMF)); 311 DAG.extend({&*BB->begin(), BB->getTerminator()}); 312 313 auto *S0N = cast<sandboxir::MemDGNode>(DAG.getNode(S0)); 314 auto *S1N = cast<sandboxir::MemDGNode>(DAG.getNode(S1)); 315 316 EXPECT_EQ(S0N->getPrevNode(), nullptr); 317 EXPECT_EQ(S0N->getNextNode(), S1N); 318 319 EXPECT_EQ(S1N->getPrevNode(), S0N); 320 EXPECT_EQ(S1N->getNextNode(), nullptr); 321 } 322 323 TEST_F(DependencyGraphTest, DGNodeRange) { 324 parseIR(C, R"IR( 325 define void @foo(ptr %ptr, i8 %v0, i8 %v1) { 326 add i8 %v0, %v0 327 store i8 %v0, ptr %ptr 328 add i8 %v0, %v0 329 store i8 %v1, ptr %ptr 330 ret void 331 } 332 )IR"); 333 llvm::Function *LLVMF = &*M->getFunction("foo"); 334 sandboxir::Context Ctx(C); 335 auto *F = Ctx.createFunction(LLVMF); 336 auto *BB = &*F->begin(); 337 auto It = BB->begin(); 338 auto *Add0 = cast<sandboxir::BinaryOperator>(&*It++); 339 auto *S0 = cast<sandboxir::StoreInst>(&*It++); 340 auto *Add1 = cast<sandboxir::BinaryOperator>(&*It++); 341 auto *S1 = cast<sandboxir::StoreInst>(&*It++); 342 auto *Ret = cast<sandboxir::ReturnInst>(&*It++); 343 344 sandboxir::DependencyGraph DAG(getAA(*LLVMF)); 345 DAG.extend({&*BB->begin(), BB->getTerminator()}); 346 347 auto *S0N = cast<sandboxir::MemDGNode>(DAG.getNode(S0)); 348 auto *S1N = cast<sandboxir::MemDGNode>(DAG.getNode(S1)); 349 350 // Check getTopMemDGNode(). 351 using B = sandboxir::MemDGNodeIntervalBuilder; 352 using InstrInterval = sandboxir::Interval<sandboxir::Instruction>; 353 EXPECT_EQ(B::getTopMemDGNode(InstrInterval(S0, S0), DAG), S0N); 354 EXPECT_EQ(B::getTopMemDGNode(InstrInterval(S0, Ret), DAG), S0N); 355 EXPECT_EQ(B::getTopMemDGNode(InstrInterval(Add0, Add1), DAG), S0N); 356 EXPECT_EQ(B::getTopMemDGNode(InstrInterval(Add0, Add0), DAG), nullptr); 357 358 // Check getBotMemDGNode(). 359 EXPECT_EQ(B::getBotMemDGNode(InstrInterval(S1, S1), DAG), S1N); 360 EXPECT_EQ(B::getBotMemDGNode(InstrInterval(Add0, S1), DAG), S1N); 361 EXPECT_EQ(B::getBotMemDGNode(InstrInterval(Add0, Ret), DAG), S1N); 362 EXPECT_EQ(B::getBotMemDGNode(InstrInterval(Ret, Ret), DAG), nullptr); 363 364 // Check empty range. 365 EXPECT_THAT(sandboxir::MemDGNodeIntervalBuilder::makeEmpty(), 366 testing::ElementsAre()); 367 368 // Returns the pointers in Range. 369 auto getPtrVec = [](const auto &Range) { 370 SmallVector<const sandboxir::DGNode *> Vec; 371 for (const sandboxir::DGNode &N : Range) 372 Vec.push_back(&N); 373 return Vec; 374 }; 375 // Both TopN and BotN are memory. 376 EXPECT_THAT( 377 getPtrVec(sandboxir::MemDGNodeIntervalBuilder::make({S0, S1}, DAG)), 378 testing::ElementsAre(S0N, S1N)); 379 // Only TopN is memory. 380 EXPECT_THAT( 381 getPtrVec(sandboxir::MemDGNodeIntervalBuilder::make({S0, Ret}, DAG)), 382 testing::ElementsAre(S0N, S1N)); 383 EXPECT_THAT( 384 getPtrVec(sandboxir::MemDGNodeIntervalBuilder::make({S0, Add1}, DAG)), 385 testing::ElementsAre(S0N)); 386 // Only BotN is memory. 387 EXPECT_THAT( 388 getPtrVec(sandboxir::MemDGNodeIntervalBuilder::make({Add0, S1}, DAG)), 389 testing::ElementsAre(S0N, S1N)); 390 EXPECT_THAT( 391 getPtrVec(sandboxir::MemDGNodeIntervalBuilder::make({Add0, S0}, DAG)), 392 testing::ElementsAre(S0N)); 393 // Neither TopN or BotN is memory. 394 EXPECT_THAT( 395 getPtrVec(sandboxir::MemDGNodeIntervalBuilder::make({Add0, Ret}, DAG)), 396 testing::ElementsAre(S0N, S1N)); 397 EXPECT_THAT( 398 getPtrVec(sandboxir::MemDGNodeIntervalBuilder::make({Add0, Add0}, DAG)), 399 testing::ElementsAre()); 400 } 401 402 TEST_F(DependencyGraphTest, AliasingStores) { 403 parseIR(C, R"IR( 404 define void @foo(ptr %ptr, i8 %v0, i8 %v1) { 405 store i8 %v0, ptr %ptr 406 store i8 %v1, ptr %ptr 407 ret void 408 } 409 )IR"); 410 llvm::Function *LLVMF = &*M->getFunction("foo"); 411 sandboxir::Context Ctx(C); 412 auto *F = Ctx.createFunction(LLVMF); 413 auto *BB = &*F->begin(); 414 sandboxir::DependencyGraph DAG(getAA(*LLVMF)); 415 DAG.extend({&*BB->begin(), BB->getTerminator()}); 416 auto It = BB->begin(); 417 auto *Store0N = cast<sandboxir::MemDGNode>( 418 DAG.getNode(cast<sandboxir::StoreInst>(&*It++))); 419 auto *Store1N = cast<sandboxir::MemDGNode>( 420 DAG.getNode(cast<sandboxir::StoreInst>(&*It++))); 421 auto *RetN = DAG.getNode(cast<sandboxir::ReturnInst>(&*It++)); 422 EXPECT_TRUE(Store0N->memPreds().empty()); 423 EXPECT_THAT(Store1N->memPreds(), testing::ElementsAre(Store0N)); 424 EXPECT_TRUE(RetN->preds(DAG).empty()); 425 } 426 427 TEST_F(DependencyGraphTest, NonAliasingStores) { 428 parseIR(C, R"IR( 429 define void @foo(ptr noalias %ptr0, ptr noalias %ptr1, i8 %v0, i8 %v1) { 430 store i8 %v0, ptr %ptr0 431 store i8 %v1, ptr %ptr1 432 ret void 433 } 434 )IR"); 435 llvm::Function *LLVMF = &*M->getFunction("foo"); 436 sandboxir::Context Ctx(C); 437 auto *F = Ctx.createFunction(LLVMF); 438 auto *BB = &*F->begin(); 439 sandboxir::DependencyGraph DAG(getAA(*LLVMF)); 440 DAG.extend({&*BB->begin(), BB->getTerminator()}); 441 auto It = BB->begin(); 442 auto *Store0N = cast<sandboxir::MemDGNode>( 443 DAG.getNode(cast<sandboxir::StoreInst>(&*It++))); 444 auto *Store1N = cast<sandboxir::MemDGNode>( 445 DAG.getNode(cast<sandboxir::StoreInst>(&*It++))); 446 auto *RetN = DAG.getNode(cast<sandboxir::ReturnInst>(&*It++)); 447 // We expect no dependencies because the stores don't alias. 448 EXPECT_TRUE(Store0N->memPreds().empty()); 449 EXPECT_TRUE(Store1N->memPreds().empty()); 450 EXPECT_TRUE(RetN->preds(DAG).empty()); 451 } 452 453 TEST_F(DependencyGraphTest, VolatileLoads) { 454 parseIR(C, R"IR( 455 define void @foo(ptr noalias %ptr0, ptr noalias %ptr1) { 456 %ld0 = load volatile i8, ptr %ptr0 457 %ld1 = load volatile i8, ptr %ptr1 458 ret void 459 } 460 )IR"); 461 llvm::Function *LLVMF = &*M->getFunction("foo"); 462 sandboxir::Context Ctx(C); 463 auto *F = Ctx.createFunction(LLVMF); 464 auto *BB = &*F->begin(); 465 sandboxir::DependencyGraph DAG(getAA(*LLVMF)); 466 DAG.extend({&*BB->begin(), BB->getTerminator()}); 467 auto It = BB->begin(); 468 auto *Ld0N = cast<sandboxir::MemDGNode>( 469 DAG.getNode(cast<sandboxir::LoadInst>(&*It++))); 470 auto *Ld1N = cast<sandboxir::MemDGNode>( 471 DAG.getNode(cast<sandboxir::LoadInst>(&*It++))); 472 auto *RetN = DAG.getNode(cast<sandboxir::ReturnInst>(&*It++)); 473 EXPECT_TRUE(Ld0N->memPreds().empty()); 474 EXPECT_THAT(Ld1N->memPreds(), testing::ElementsAre(Ld0N)); 475 EXPECT_TRUE(RetN->preds(DAG).empty()); 476 } 477 478 TEST_F(DependencyGraphTest, VolatileSotres) { 479 parseIR(C, R"IR( 480 define void @foo(ptr noalias %ptr0, ptr noalias %ptr1, i8 %v) { 481 store volatile i8 %v, ptr %ptr0 482 store volatile i8 %v, ptr %ptr1 483 ret void 484 } 485 )IR"); 486 llvm::Function *LLVMF = &*M->getFunction("foo"); 487 sandboxir::Context Ctx(C); 488 auto *F = Ctx.createFunction(LLVMF); 489 auto *BB = &*F->begin(); 490 sandboxir::DependencyGraph DAG(getAA(*LLVMF)); 491 DAG.extend({&*BB->begin(), BB->getTerminator()}); 492 auto It = BB->begin(); 493 auto *Store0N = cast<sandboxir::MemDGNode>( 494 DAG.getNode(cast<sandboxir::StoreInst>(&*It++))); 495 auto *Store1N = cast<sandboxir::MemDGNode>( 496 DAG.getNode(cast<sandboxir::StoreInst>(&*It++))); 497 auto *RetN = DAG.getNode(cast<sandboxir::ReturnInst>(&*It++)); 498 EXPECT_TRUE(Store0N->memPreds().empty()); 499 EXPECT_THAT(Store1N->memPreds(), testing::ElementsAre(Store0N)); 500 EXPECT_TRUE(RetN->preds(DAG).empty()); 501 } 502 503 TEST_F(DependencyGraphTest, Call) { 504 parseIR(C, R"IR( 505 declare void @bar1() 506 declare void @bar2() 507 define void @foo(float %v1, float %v2) { 508 call void @bar1() 509 %add = fadd float %v1, %v2 510 call void @bar2() 511 ret void 512 } 513 )IR"); 514 Function *LLVMF = M->getFunction("foo"); 515 516 sandboxir::Context Ctx(C); 517 auto *F = Ctx.createFunction(LLVMF); 518 auto *BB = &*F->begin(); 519 520 sandboxir::DependencyGraph DAG(getAA(*LLVMF)); 521 DAG.extend({&*BB->begin(), BB->getTerminator()->getPrevNode()}); 522 523 auto It = BB->begin(); 524 auto *Call1N = cast<sandboxir::MemDGNode>(DAG.getNode(&*It++)); 525 auto *AddN = DAG.getNode(&*It++); 526 auto *Call2N = cast<sandboxir::MemDGNode>(DAG.getNode(&*It++)); 527 528 EXPECT_THAT(Call1N->memPreds(), testing::ElementsAre()); 529 EXPECT_THAT(AddN->preds(DAG), testing::ElementsAre()); 530 EXPECT_THAT(Call2N->memPreds(), testing::ElementsAre(Call1N)); 531 } 532 533 // Check that there is a dependency: stacksave -> alloca -> stackrestore. 534 TEST_F(DependencyGraphTest, StackSaveRestoreInAlloca) { 535 parseIR(C, R"IR( 536 declare ptr @llvm.stacksave() 537 declare void @llvm.stackrestore(ptr %ptr) 538 539 define void @foo() { 540 %stack0 = call ptr @llvm.stacksave() ; Should depend on store 541 %alloca0 = alloca inalloca i8 ; Should depend on stacksave 542 call void @llvm.stackrestore(ptr %stack0) ; Should depend transiently on %alloca0 543 ret void 544 } 545 )IR"); 546 Function *LLVMF = M->getFunction("foo"); 547 548 sandboxir::Context Ctx(C); 549 auto *F = Ctx.createFunction(LLVMF); 550 auto *BB = &*F->begin(); 551 552 sandboxir::DependencyGraph DAG(getAA(*LLVMF)); 553 DAG.extend({&*BB->begin(), BB->getTerminator()->getPrevNode()}); 554 555 auto It = BB->begin(); 556 auto *StackSaveN = DAG.getNode(&*It++); 557 auto *AllocaN = DAG.getNode(&*It++); 558 auto *StackRestoreN = DAG.getNode(&*It++); 559 560 EXPECT_TRUE(memDependency(AllocaN, StackRestoreN)); 561 EXPECT_TRUE(memDependency(StackSaveN, AllocaN)); 562 } 563 564 // Checks that stacksave and stackrestore depend on other mem instrs. 565 TEST_F(DependencyGraphTest, StackSaveRestoreDependOnOtherMem) { 566 parseIR(C, R"IR( 567 declare ptr @llvm.stacksave() 568 declare void @llvm.stackrestore(ptr %ptr) 569 570 define void @foo(i8 %v0, i8 %v1, ptr %ptr) { 571 store volatile i8 %v0, ptr %ptr, align 4 572 %stack0 = call ptr @llvm.stacksave() ; Should depend on store 573 call void @llvm.stackrestore(ptr %stack0) ; Should depend on stacksave 574 store volatile i8 %v1, ptr %ptr, align 4 ; Should depend on stackrestore 575 ret void 576 } 577 )IR"); 578 Function *LLVMF = M->getFunction("foo"); 579 580 sandboxir::Context Ctx(C); 581 auto *F = Ctx.createFunction(LLVMF); 582 auto *BB = &*F->begin(); 583 584 sandboxir::DependencyGraph DAG(getAA(*LLVMF)); 585 DAG.extend({&*BB->begin(), BB->getTerminator()->getPrevNode()}); 586 587 auto It = BB->begin(); 588 auto *Store0N = DAG.getNode(&*It++); 589 auto *StackSaveN = DAG.getNode(&*It++); 590 auto *StackRestoreN = DAG.getNode(&*It++); 591 auto *Store1N = DAG.getNode(&*It++); 592 593 EXPECT_TRUE(memDependency(Store0N, StackSaveN)); 594 EXPECT_TRUE(memDependency(StackSaveN, StackRestoreN)); 595 EXPECT_TRUE(memDependency(StackRestoreN, Store1N)); 596 } 597 598 // Make sure there is a dependency between a stackrestore and an alloca. 599 TEST_F(DependencyGraphTest, StackRestoreAndInAlloca) { 600 parseIR(C, R"IR( 601 declare void @llvm.stackrestore(ptr %ptr) 602 603 define void @foo(ptr %ptr) { 604 call void @llvm.stackrestore(ptr %ptr) 605 %alloca0 = alloca inalloca i8 ; Should depend on stackrestore 606 ret void 607 } 608 )IR"); 609 Function *LLVMF = M->getFunction("foo"); 610 611 sandboxir::Context Ctx(C); 612 auto *F = Ctx.createFunction(LLVMF); 613 auto *BB = &*F->begin(); 614 615 sandboxir::DependencyGraph DAG(getAA(*LLVMF)); 616 DAG.extend({&*BB->begin(), BB->getTerminator()->getPrevNode()}); 617 618 auto It = BB->begin(); 619 auto *StackRestoreN = DAG.getNode(&*It++); 620 auto *AllocaN = DAG.getNode(&*It++); 621 622 EXPECT_TRUE(memDependency(StackRestoreN, AllocaN)); 623 } 624 625 // Make sure there is a dependency between the alloca and stacksave 626 TEST_F(DependencyGraphTest, StackSaveAndInAlloca) { 627 parseIR(C, R"IR( 628 declare ptr @llvm.stacksave() 629 630 define void @foo(ptr %ptr) { 631 %alloca0 = alloca inalloca i8 ; Should depend on stackrestore 632 %stack0 = call ptr @llvm.stacksave() ; Should depend on alloca0 633 ret void 634 } 635 )IR"); 636 Function *LLVMF = M->getFunction("foo"); 637 638 sandboxir::Context Ctx(C); 639 auto *F = Ctx.createFunction(LLVMF); 640 auto *BB = &*F->begin(); 641 642 sandboxir::DependencyGraph DAG(getAA(*LLVMF)); 643 DAG.extend({&*BB->begin(), BB->getTerminator()->getPrevNode()}); 644 645 auto It = BB->begin(); 646 auto *AllocaN = DAG.getNode(&*It++); 647 auto *StackSaveN = DAG.getNode(&*It++); 648 649 EXPECT_TRUE(memDependency(AllocaN, StackSaveN)); 650 } 651 652 // A non-InAlloca in a stacksave-stackrestore region does not need extra 653 // dependencies. 654 TEST_F(DependencyGraphTest, StackSaveRestoreNoInAlloca) { 655 parseIR(C, R"IR( 656 declare ptr @llvm.stacksave() 657 declare void @llvm.stackrestore(ptr %ptr) 658 declare void @use(ptr %ptr) 659 660 define void @foo() { 661 %stack = call ptr @llvm.stacksave() 662 %alloca1 = alloca i8 ; No dependency 663 call void @llvm.stackrestore(ptr %stack) 664 ret void 665 } 666 )IR"); 667 Function *LLVMF = M->getFunction("foo"); 668 669 sandboxir::Context Ctx(C); 670 auto *F = Ctx.createFunction(LLVMF); 671 auto *BB = &*F->begin(); 672 673 sandboxir::DependencyGraph DAG(getAA(*LLVMF)); 674 DAG.extend({&*BB->begin(), BB->getTerminator()->getPrevNode()}); 675 676 auto It = BB->begin(); 677 auto *StackSaveN = DAG.getNode(&*It++); 678 auto *AllocaN = DAG.getNode(&*It++); 679 auto *StackRestoreN = DAG.getNode(&*It++); 680 681 EXPECT_FALSE(memDependency(StackSaveN, AllocaN)); 682 EXPECT_FALSE(memDependency(AllocaN, StackRestoreN)); 683 } 684 685 TEST_F(DependencyGraphTest, Extend) { 686 parseIR(C, R"IR( 687 define void @foo(ptr %ptr, i8 %v1, i8 %v2, i8 %v3, i8 %v4, i8 %v5) { 688 store i8 %v1, ptr %ptr 689 store i8 %v2, ptr %ptr 690 store i8 %v3, ptr %ptr 691 store i8 %v4, ptr %ptr 692 store i8 %v5, ptr %ptr 693 ret void 694 } 695 )IR"); 696 llvm::Function *LLVMF = &*M->getFunction("foo"); 697 sandboxir::Context Ctx(C); 698 auto *F = Ctx.createFunction(LLVMF); 699 auto *BB = &*F->begin(); 700 auto It = BB->begin(); 701 auto *S1 = cast<sandboxir::StoreInst>(&*It++); 702 auto *S2 = cast<sandboxir::StoreInst>(&*It++); 703 auto *S3 = cast<sandboxir::StoreInst>(&*It++); 704 auto *S4 = cast<sandboxir::StoreInst>(&*It++); 705 auto *S5 = cast<sandboxir::StoreInst>(&*It++); 706 sandboxir::DependencyGraph DAG(getAA(*LLVMF)); 707 { 708 // Scenario 1: Build new DAG 709 auto NewIntvl = DAG.extend({S3, S3}); 710 EXPECT_EQ(NewIntvl, sandboxir::Interval<sandboxir::Instruction>(S3, S3)); 711 EXPECT_EQ(DAG.getInterval().top(), S3); 712 EXPECT_EQ(DAG.getInterval().bottom(), S3); 713 [[maybe_unused]] auto *S3N = cast<sandboxir::MemDGNode>(DAG.getNode(S3)); 714 } 715 { 716 // Scenario 2: Extend below 717 auto NewIntvl = DAG.extend({S5, S5}); 718 EXPECT_EQ(NewIntvl, sandboxir::Interval<sandboxir::Instruction>(S4, S5)); 719 auto *S3N = cast<sandboxir::MemDGNode>(DAG.getNode(S3)); 720 auto *S4N = cast<sandboxir::MemDGNode>(DAG.getNode(S4)); 721 auto *S5N = cast<sandboxir::MemDGNode>(DAG.getNode(S5)); 722 EXPECT_TRUE(S4N->hasMemPred(S3N)); 723 EXPECT_TRUE(S5N->hasMemPred(S4N)); 724 EXPECT_TRUE(S5N->hasMemPred(S3N)); 725 } 726 { 727 // Scenario 3: Extend above 728 auto NewIntvl = DAG.extend({S1, S2}); 729 EXPECT_EQ(NewIntvl, sandboxir::Interval<sandboxir::Instruction>(S1, S2)); 730 auto *S1N = cast<sandboxir::MemDGNode>(DAG.getNode(S1)); 731 auto *S2N = cast<sandboxir::MemDGNode>(DAG.getNode(S2)); 732 auto *S3N = cast<sandboxir::MemDGNode>(DAG.getNode(S3)); 733 auto *S4N = cast<sandboxir::MemDGNode>(DAG.getNode(S4)); 734 auto *S5N = cast<sandboxir::MemDGNode>(DAG.getNode(S5)); 735 736 EXPECT_TRUE(S2N->hasMemPred(S1N)); 737 738 EXPECT_TRUE(S3N->hasMemPred(S2N)); 739 EXPECT_TRUE(S3N->hasMemPred(S1N)); 740 741 EXPECT_TRUE(S4N->hasMemPred(S3N)); 742 EXPECT_TRUE(S4N->hasMemPred(S2N)); 743 EXPECT_TRUE(S4N->hasMemPred(S1N)); 744 745 EXPECT_TRUE(S5N->hasMemPred(S4N)); 746 EXPECT_TRUE(S5N->hasMemPred(S3N)); 747 EXPECT_TRUE(S5N->hasMemPred(S2N)); 748 EXPECT_TRUE(S5N->hasMemPred(S1N)); 749 } 750 } 751