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 // Check UnscheduledSuccs. 254 EXPECT_EQ(N0->getNumUnscheduledSuccs(), 1u); // N1 255 EXPECT_EQ(N1->getNumUnscheduledSuccs(), 0u); 256 EXPECT_EQ(N2->getNumUnscheduledSuccs(), 0u); 257 } 258 259 TEST_F(DependencyGraphTest, Preds) { 260 parseIR(C, R"IR( 261 declare ptr @bar(i8) 262 define i8 @foo(i8 %v0, i8 %v1) { 263 %add0 = add i8 %v0, %v0 264 %add1 = add i8 %v1, %v1 265 %add2 = add i8 %add0, %add1 266 %ptr = call ptr @bar(i8 %add1) 267 store i8 %add2, ptr %ptr 268 ret i8 %add2 269 } 270 )IR"); 271 llvm::Function *LLVMF = &*M->getFunction("foo"); 272 sandboxir::Context Ctx(C); 273 auto *F = Ctx.createFunction(LLVMF); 274 auto *BB = &*F->begin(); 275 auto It = BB->begin(); 276 sandboxir::DependencyGraph DAG(getAA(*LLVMF)); 277 DAG.extend({&*BB->begin(), BB->getTerminator()}); 278 279 auto *AddN0 = DAG.getNode(cast<sandboxir::BinaryOperator>(&*It++)); 280 auto *AddN1 = DAG.getNode(cast<sandboxir::BinaryOperator>(&*It++)); 281 auto *AddN2 = DAG.getNode(cast<sandboxir::BinaryOperator>(&*It++)); 282 auto *CallN = DAG.getNode(cast<sandboxir::CallInst>(&*It++)); 283 auto *StN = DAG.getNode(cast<sandboxir::StoreInst>(&*It++)); 284 auto *RetN = DAG.getNode(cast<sandboxir::ReturnInst>(&*It++)); 285 286 // Check preds(). 287 EXPECT_THAT(AddN0->preds(DAG), testing::ElementsAre()); 288 EXPECT_THAT(AddN1->preds(DAG), testing::ElementsAre()); 289 EXPECT_THAT(AddN2->preds(DAG), testing::ElementsAre(AddN0, AddN1)); 290 EXPECT_THAT(CallN->preds(DAG), testing::ElementsAre(AddN1)); 291 EXPECT_THAT(StN->preds(DAG), 292 testing::UnorderedElementsAre(CallN, CallN, AddN2)); 293 EXPECT_THAT(RetN->preds(DAG), testing::ElementsAre(AddN2)); 294 295 // Check UnscheduledSuccs. 296 EXPECT_EQ(AddN0->getNumUnscheduledSuccs(), 1u); // AddN2 297 EXPECT_EQ(AddN1->getNumUnscheduledSuccs(), 2u); // AddN2, CallN 298 EXPECT_EQ(AddN2->getNumUnscheduledSuccs(), 2u); // StN, RetN 299 EXPECT_EQ(CallN->getNumUnscheduledSuccs(), 2u); // StN, StN 300 EXPECT_EQ(StN->getNumUnscheduledSuccs(), 0u); 301 EXPECT_EQ(RetN->getNumUnscheduledSuccs(), 0u); 302 } 303 304 TEST_F(DependencyGraphTest, MemDGNode_getPrevNode_getNextNode) { 305 parseIR(C, R"IR( 306 define void @foo(ptr %ptr, i8 %v0, i8 %v1) { 307 store i8 %v0, ptr %ptr 308 add i8 %v0, %v0 309 store i8 %v1, ptr %ptr 310 ret void 311 } 312 )IR"); 313 llvm::Function *LLVMF = &*M->getFunction("foo"); 314 sandboxir::Context Ctx(C); 315 auto *F = Ctx.createFunction(LLVMF); 316 auto *BB = &*F->begin(); 317 auto It = BB->begin(); 318 auto *S0 = cast<sandboxir::StoreInst>(&*It++); 319 [[maybe_unused]] auto *Add = cast<sandboxir::BinaryOperator>(&*It++); 320 auto *S1 = cast<sandboxir::StoreInst>(&*It++); 321 [[maybe_unused]] auto *Ret = cast<sandboxir::ReturnInst>(&*It++); 322 323 sandboxir::DependencyGraph DAG(getAA(*LLVMF)); 324 DAG.extend({&*BB->begin(), BB->getTerminator()}); 325 326 auto *S0N = cast<sandboxir::MemDGNode>(DAG.getNode(S0)); 327 auto *S1N = cast<sandboxir::MemDGNode>(DAG.getNode(S1)); 328 329 EXPECT_EQ(S0N->getPrevNode(), nullptr); 330 EXPECT_EQ(S0N->getNextNode(), S1N); 331 332 EXPECT_EQ(S1N->getPrevNode(), S0N); 333 EXPECT_EQ(S1N->getNextNode(), nullptr); 334 } 335 336 TEST_F(DependencyGraphTest, DGNodeRange) { 337 parseIR(C, R"IR( 338 define void @foo(ptr %ptr, i8 %v0, i8 %v1) { 339 add i8 %v0, %v0 340 store i8 %v0, ptr %ptr 341 add i8 %v0, %v0 342 store i8 %v1, ptr %ptr 343 ret void 344 } 345 )IR"); 346 llvm::Function *LLVMF = &*M->getFunction("foo"); 347 sandboxir::Context Ctx(C); 348 auto *F = Ctx.createFunction(LLVMF); 349 auto *BB = &*F->begin(); 350 auto It = BB->begin(); 351 auto *Add0 = cast<sandboxir::BinaryOperator>(&*It++); 352 auto *S0 = cast<sandboxir::StoreInst>(&*It++); 353 auto *Add1 = cast<sandboxir::BinaryOperator>(&*It++); 354 auto *S1 = cast<sandboxir::StoreInst>(&*It++); 355 auto *Ret = cast<sandboxir::ReturnInst>(&*It++); 356 357 sandboxir::DependencyGraph DAG(getAA(*LLVMF)); 358 DAG.extend({&*BB->begin(), BB->getTerminator()}); 359 360 auto *S0N = cast<sandboxir::MemDGNode>(DAG.getNode(S0)); 361 auto *S1N = cast<sandboxir::MemDGNode>(DAG.getNode(S1)); 362 363 // Check getTopMemDGNode(). 364 using B = sandboxir::MemDGNodeIntervalBuilder; 365 using InstrInterval = sandboxir::Interval<sandboxir::Instruction>; 366 EXPECT_EQ(B::getTopMemDGNode(InstrInterval(S0, S0), DAG), S0N); 367 EXPECT_EQ(B::getTopMemDGNode(InstrInterval(S0, Ret), DAG), S0N); 368 EXPECT_EQ(B::getTopMemDGNode(InstrInterval(Add0, Add1), DAG), S0N); 369 EXPECT_EQ(B::getTopMemDGNode(InstrInterval(Add0, Add0), DAG), nullptr); 370 371 // Check getBotMemDGNode(). 372 EXPECT_EQ(B::getBotMemDGNode(InstrInterval(S1, S1), DAG), S1N); 373 EXPECT_EQ(B::getBotMemDGNode(InstrInterval(Add0, S1), DAG), S1N); 374 EXPECT_EQ(B::getBotMemDGNode(InstrInterval(Add0, Ret), DAG), S1N); 375 EXPECT_EQ(B::getBotMemDGNode(InstrInterval(Ret, Ret), DAG), nullptr); 376 377 // Check empty range. 378 EXPECT_THAT(sandboxir::MemDGNodeIntervalBuilder::makeEmpty(), 379 testing::ElementsAre()); 380 381 // Returns the pointers in Range. 382 auto getPtrVec = [](const auto &Range) { 383 SmallVector<const sandboxir::DGNode *> Vec; 384 for (const sandboxir::DGNode &N : Range) 385 Vec.push_back(&N); 386 return Vec; 387 }; 388 // Both TopN and BotN are memory. 389 EXPECT_THAT( 390 getPtrVec(sandboxir::MemDGNodeIntervalBuilder::make({S0, S1}, DAG)), 391 testing::ElementsAre(S0N, S1N)); 392 // Only TopN is memory. 393 EXPECT_THAT( 394 getPtrVec(sandboxir::MemDGNodeIntervalBuilder::make({S0, Ret}, DAG)), 395 testing::ElementsAre(S0N, S1N)); 396 EXPECT_THAT( 397 getPtrVec(sandboxir::MemDGNodeIntervalBuilder::make({S0, Add1}, DAG)), 398 testing::ElementsAre(S0N)); 399 // Only BotN is memory. 400 EXPECT_THAT( 401 getPtrVec(sandboxir::MemDGNodeIntervalBuilder::make({Add0, S1}, DAG)), 402 testing::ElementsAre(S0N, S1N)); 403 EXPECT_THAT( 404 getPtrVec(sandboxir::MemDGNodeIntervalBuilder::make({Add0, S0}, DAG)), 405 testing::ElementsAre(S0N)); 406 // Neither TopN or BotN is memory. 407 EXPECT_THAT( 408 getPtrVec(sandboxir::MemDGNodeIntervalBuilder::make({Add0, Ret}, DAG)), 409 testing::ElementsAre(S0N, S1N)); 410 EXPECT_THAT( 411 getPtrVec(sandboxir::MemDGNodeIntervalBuilder::make({Add0, Add0}, DAG)), 412 testing::ElementsAre()); 413 } 414 415 TEST_F(DependencyGraphTest, AliasingStores) { 416 parseIR(C, R"IR( 417 define void @foo(ptr %ptr, i8 %v0, i8 %v1) { 418 store i8 %v0, ptr %ptr 419 store i8 %v1, ptr %ptr 420 ret void 421 } 422 )IR"); 423 llvm::Function *LLVMF = &*M->getFunction("foo"); 424 sandboxir::Context Ctx(C); 425 auto *F = Ctx.createFunction(LLVMF); 426 auto *BB = &*F->begin(); 427 sandboxir::DependencyGraph DAG(getAA(*LLVMF)); 428 DAG.extend({&*BB->begin(), BB->getTerminator()}); 429 auto It = BB->begin(); 430 auto *Store0N = cast<sandboxir::MemDGNode>( 431 DAG.getNode(cast<sandboxir::StoreInst>(&*It++))); 432 auto *Store1N = cast<sandboxir::MemDGNode>( 433 DAG.getNode(cast<sandboxir::StoreInst>(&*It++))); 434 auto *RetN = DAG.getNode(cast<sandboxir::ReturnInst>(&*It++)); 435 EXPECT_TRUE(Store0N->memPreds().empty()); 436 EXPECT_THAT(Store1N->memPreds(), testing::ElementsAre(Store0N)); 437 EXPECT_TRUE(RetN->preds(DAG).empty()); 438 } 439 440 TEST_F(DependencyGraphTest, NonAliasingStores) { 441 parseIR(C, R"IR( 442 define void @foo(ptr noalias %ptr0, ptr noalias %ptr1, i8 %v0, i8 %v1) { 443 store i8 %v0, ptr %ptr0 444 store i8 %v1, ptr %ptr1 445 ret void 446 } 447 )IR"); 448 llvm::Function *LLVMF = &*M->getFunction("foo"); 449 sandboxir::Context Ctx(C); 450 auto *F = Ctx.createFunction(LLVMF); 451 auto *BB = &*F->begin(); 452 sandboxir::DependencyGraph DAG(getAA(*LLVMF)); 453 DAG.extend({&*BB->begin(), BB->getTerminator()}); 454 auto It = BB->begin(); 455 auto *Store0N = cast<sandboxir::MemDGNode>( 456 DAG.getNode(cast<sandboxir::StoreInst>(&*It++))); 457 auto *Store1N = cast<sandboxir::MemDGNode>( 458 DAG.getNode(cast<sandboxir::StoreInst>(&*It++))); 459 auto *RetN = DAG.getNode(cast<sandboxir::ReturnInst>(&*It++)); 460 // We expect no dependencies because the stores don't alias. 461 EXPECT_TRUE(Store0N->memPreds().empty()); 462 EXPECT_TRUE(Store1N->memPreds().empty()); 463 EXPECT_TRUE(RetN->preds(DAG).empty()); 464 } 465 466 TEST_F(DependencyGraphTest, VolatileLoads) { 467 parseIR(C, R"IR( 468 define void @foo(ptr noalias %ptr0, ptr noalias %ptr1) { 469 %ld0 = load volatile i8, ptr %ptr0 470 %ld1 = load volatile i8, ptr %ptr1 471 ret void 472 } 473 )IR"); 474 llvm::Function *LLVMF = &*M->getFunction("foo"); 475 sandboxir::Context Ctx(C); 476 auto *F = Ctx.createFunction(LLVMF); 477 auto *BB = &*F->begin(); 478 sandboxir::DependencyGraph DAG(getAA(*LLVMF)); 479 DAG.extend({&*BB->begin(), BB->getTerminator()}); 480 auto It = BB->begin(); 481 auto *Ld0N = cast<sandboxir::MemDGNode>( 482 DAG.getNode(cast<sandboxir::LoadInst>(&*It++))); 483 auto *Ld1N = cast<sandboxir::MemDGNode>( 484 DAG.getNode(cast<sandboxir::LoadInst>(&*It++))); 485 auto *RetN = DAG.getNode(cast<sandboxir::ReturnInst>(&*It++)); 486 EXPECT_TRUE(Ld0N->memPreds().empty()); 487 EXPECT_THAT(Ld1N->memPreds(), testing::ElementsAre(Ld0N)); 488 EXPECT_TRUE(RetN->preds(DAG).empty()); 489 } 490 491 TEST_F(DependencyGraphTest, VolatileSotres) { 492 parseIR(C, R"IR( 493 define void @foo(ptr noalias %ptr0, ptr noalias %ptr1, i8 %v) { 494 store volatile i8 %v, ptr %ptr0 495 store volatile i8 %v, ptr %ptr1 496 ret void 497 } 498 )IR"); 499 llvm::Function *LLVMF = &*M->getFunction("foo"); 500 sandboxir::Context Ctx(C); 501 auto *F = Ctx.createFunction(LLVMF); 502 auto *BB = &*F->begin(); 503 sandboxir::DependencyGraph DAG(getAA(*LLVMF)); 504 DAG.extend({&*BB->begin(), BB->getTerminator()}); 505 auto It = BB->begin(); 506 auto *Store0N = cast<sandboxir::MemDGNode>( 507 DAG.getNode(cast<sandboxir::StoreInst>(&*It++))); 508 auto *Store1N = cast<sandboxir::MemDGNode>( 509 DAG.getNode(cast<sandboxir::StoreInst>(&*It++))); 510 auto *RetN = DAG.getNode(cast<sandboxir::ReturnInst>(&*It++)); 511 EXPECT_TRUE(Store0N->memPreds().empty()); 512 EXPECT_THAT(Store1N->memPreds(), testing::ElementsAre(Store0N)); 513 EXPECT_TRUE(RetN->preds(DAG).empty()); 514 } 515 516 TEST_F(DependencyGraphTest, Call) { 517 parseIR(C, R"IR( 518 declare void @bar1() 519 declare void @bar2() 520 define void @foo(float %v1, float %v2) { 521 call void @bar1() 522 %add = fadd float %v1, %v2 523 call void @bar2() 524 ret void 525 } 526 )IR"); 527 Function *LLVMF = M->getFunction("foo"); 528 529 sandboxir::Context Ctx(C); 530 auto *F = Ctx.createFunction(LLVMF); 531 auto *BB = &*F->begin(); 532 533 sandboxir::DependencyGraph DAG(getAA(*LLVMF)); 534 DAG.extend({&*BB->begin(), BB->getTerminator()->getPrevNode()}); 535 536 auto It = BB->begin(); 537 auto *Call1N = cast<sandboxir::MemDGNode>(DAG.getNode(&*It++)); 538 auto *AddN = DAG.getNode(&*It++); 539 auto *Call2N = cast<sandboxir::MemDGNode>(DAG.getNode(&*It++)); 540 541 EXPECT_THAT(Call1N->memPreds(), testing::ElementsAre()); 542 EXPECT_THAT(AddN->preds(DAG), testing::ElementsAre()); 543 EXPECT_THAT(Call2N->memPreds(), testing::ElementsAre(Call1N)); 544 } 545 546 // Check that there is a dependency: stacksave -> alloca -> stackrestore. 547 TEST_F(DependencyGraphTest, StackSaveRestoreInAlloca) { 548 parseIR(C, R"IR( 549 declare ptr @llvm.stacksave() 550 declare void @llvm.stackrestore(ptr %ptr) 551 552 define void @foo() { 553 %stack0 = call ptr @llvm.stacksave() ; Should depend on store 554 %alloca0 = alloca inalloca i8 ; Should depend on stacksave 555 call void @llvm.stackrestore(ptr %stack0) ; Should depend transiently on %alloca0 556 ret void 557 } 558 )IR"); 559 Function *LLVMF = M->getFunction("foo"); 560 561 sandboxir::Context Ctx(C); 562 auto *F = Ctx.createFunction(LLVMF); 563 auto *BB = &*F->begin(); 564 565 sandboxir::DependencyGraph DAG(getAA(*LLVMF)); 566 DAG.extend({&*BB->begin(), BB->getTerminator()->getPrevNode()}); 567 568 auto It = BB->begin(); 569 auto *StackSaveN = DAG.getNode(&*It++); 570 auto *AllocaN = DAG.getNode(&*It++); 571 auto *StackRestoreN = DAG.getNode(&*It++); 572 573 EXPECT_TRUE(memDependency(AllocaN, StackRestoreN)); 574 EXPECT_TRUE(memDependency(StackSaveN, AllocaN)); 575 } 576 577 // Checks that stacksave and stackrestore depend on other mem instrs. 578 TEST_F(DependencyGraphTest, StackSaveRestoreDependOnOtherMem) { 579 parseIR(C, R"IR( 580 declare ptr @llvm.stacksave() 581 declare void @llvm.stackrestore(ptr %ptr) 582 583 define void @foo(i8 %v0, i8 %v1, ptr %ptr) { 584 store volatile i8 %v0, ptr %ptr, align 4 585 %stack0 = call ptr @llvm.stacksave() ; Should depend on store 586 call void @llvm.stackrestore(ptr %stack0) ; Should depend on stacksave 587 store volatile i8 %v1, ptr %ptr, align 4 ; Should depend on stackrestore 588 ret void 589 } 590 )IR"); 591 Function *LLVMF = M->getFunction("foo"); 592 593 sandboxir::Context Ctx(C); 594 auto *F = Ctx.createFunction(LLVMF); 595 auto *BB = &*F->begin(); 596 597 sandboxir::DependencyGraph DAG(getAA(*LLVMF)); 598 DAG.extend({&*BB->begin(), BB->getTerminator()->getPrevNode()}); 599 600 auto It = BB->begin(); 601 auto *Store0N = DAG.getNode(&*It++); 602 auto *StackSaveN = DAG.getNode(&*It++); 603 auto *StackRestoreN = DAG.getNode(&*It++); 604 auto *Store1N = DAG.getNode(&*It++); 605 606 EXPECT_TRUE(memDependency(Store0N, StackSaveN)); 607 EXPECT_TRUE(memDependency(StackSaveN, StackRestoreN)); 608 EXPECT_TRUE(memDependency(StackRestoreN, Store1N)); 609 } 610 611 // Make sure there is a dependency between a stackrestore and an alloca. 612 TEST_F(DependencyGraphTest, StackRestoreAndInAlloca) { 613 parseIR(C, R"IR( 614 declare void @llvm.stackrestore(ptr %ptr) 615 616 define void @foo(ptr %ptr) { 617 call void @llvm.stackrestore(ptr %ptr) 618 %alloca0 = alloca inalloca i8 ; Should depend on stackrestore 619 ret void 620 } 621 )IR"); 622 Function *LLVMF = M->getFunction("foo"); 623 624 sandboxir::Context Ctx(C); 625 auto *F = Ctx.createFunction(LLVMF); 626 auto *BB = &*F->begin(); 627 628 sandboxir::DependencyGraph DAG(getAA(*LLVMF)); 629 DAG.extend({&*BB->begin(), BB->getTerminator()->getPrevNode()}); 630 631 auto It = BB->begin(); 632 auto *StackRestoreN = DAG.getNode(&*It++); 633 auto *AllocaN = DAG.getNode(&*It++); 634 635 EXPECT_TRUE(memDependency(StackRestoreN, AllocaN)); 636 } 637 638 // Make sure there is a dependency between the alloca and stacksave 639 TEST_F(DependencyGraphTest, StackSaveAndInAlloca) { 640 parseIR(C, R"IR( 641 declare ptr @llvm.stacksave() 642 643 define void @foo(ptr %ptr) { 644 %alloca0 = alloca inalloca i8 ; Should depend on stackrestore 645 %stack0 = call ptr @llvm.stacksave() ; Should depend on alloca0 646 ret void 647 } 648 )IR"); 649 Function *LLVMF = M->getFunction("foo"); 650 651 sandboxir::Context Ctx(C); 652 auto *F = Ctx.createFunction(LLVMF); 653 auto *BB = &*F->begin(); 654 655 sandboxir::DependencyGraph DAG(getAA(*LLVMF)); 656 DAG.extend({&*BB->begin(), BB->getTerminator()->getPrevNode()}); 657 658 auto It = BB->begin(); 659 auto *AllocaN = DAG.getNode(&*It++); 660 auto *StackSaveN = DAG.getNode(&*It++); 661 662 EXPECT_TRUE(memDependency(AllocaN, StackSaveN)); 663 } 664 665 // A non-InAlloca in a stacksave-stackrestore region does not need extra 666 // dependencies. 667 TEST_F(DependencyGraphTest, StackSaveRestoreNoInAlloca) { 668 parseIR(C, R"IR( 669 declare ptr @llvm.stacksave() 670 declare void @llvm.stackrestore(ptr %ptr) 671 declare void @use(ptr %ptr) 672 673 define void @foo() { 674 %stack = call ptr @llvm.stacksave() 675 %alloca1 = alloca i8 ; No dependency 676 call void @llvm.stackrestore(ptr %stack) 677 ret void 678 } 679 )IR"); 680 Function *LLVMF = M->getFunction("foo"); 681 682 sandboxir::Context Ctx(C); 683 auto *F = Ctx.createFunction(LLVMF); 684 auto *BB = &*F->begin(); 685 686 sandboxir::DependencyGraph DAG(getAA(*LLVMF)); 687 DAG.extend({&*BB->begin(), BB->getTerminator()->getPrevNode()}); 688 689 auto It = BB->begin(); 690 auto *StackSaveN = DAG.getNode(&*It++); 691 auto *AllocaN = DAG.getNode(&*It++); 692 auto *StackRestoreN = DAG.getNode(&*It++); 693 694 EXPECT_FALSE(memDependency(StackSaveN, AllocaN)); 695 EXPECT_FALSE(memDependency(AllocaN, StackRestoreN)); 696 } 697 698 TEST_F(DependencyGraphTest, Extend) { 699 parseIR(C, R"IR( 700 define void @foo(ptr %ptr, i8 %v1, i8 %v2, i8 %v3, i8 %v4, i8 %v5) { 701 store i8 %v1, ptr %ptr 702 store i8 %v2, ptr %ptr 703 store i8 %v3, ptr %ptr 704 store i8 %v4, ptr %ptr 705 store i8 %v5, ptr %ptr 706 ret void 707 } 708 )IR"); 709 llvm::Function *LLVMF = &*M->getFunction("foo"); 710 sandboxir::Context Ctx(C); 711 auto *F = Ctx.createFunction(LLVMF); 712 auto *BB = &*F->begin(); 713 auto It = BB->begin(); 714 auto *S1 = cast<sandboxir::StoreInst>(&*It++); 715 auto *S2 = cast<sandboxir::StoreInst>(&*It++); 716 auto *S3 = cast<sandboxir::StoreInst>(&*It++); 717 auto *S4 = cast<sandboxir::StoreInst>(&*It++); 718 auto *S5 = cast<sandboxir::StoreInst>(&*It++); 719 sandboxir::DependencyGraph DAG(getAA(*LLVMF)); 720 { 721 // Scenario 1: Build new DAG 722 auto NewIntvl = DAG.extend({S3, S3}); 723 EXPECT_EQ(NewIntvl, sandboxir::Interval<sandboxir::Instruction>(S3, S3)); 724 EXPECT_EQ(DAG.getInterval().top(), S3); 725 EXPECT_EQ(DAG.getInterval().bottom(), S3); 726 [[maybe_unused]] auto *S3N = cast<sandboxir::MemDGNode>(DAG.getNode(S3)); 727 // Check UnscheduledSuccs. 728 EXPECT_EQ(S3N->getNumUnscheduledSuccs(), 0u); 729 } 730 { 731 // Scenario 2: Extend below 732 auto NewIntvl = DAG.extend({S5, S5}); 733 EXPECT_EQ(NewIntvl, sandboxir::Interval<sandboxir::Instruction>(S4, S5)); 734 auto *S3N = cast<sandboxir::MemDGNode>(DAG.getNode(S3)); 735 auto *S4N = cast<sandboxir::MemDGNode>(DAG.getNode(S4)); 736 auto *S5N = cast<sandboxir::MemDGNode>(DAG.getNode(S5)); 737 EXPECT_TRUE(S4N->hasMemPred(S3N)); 738 EXPECT_TRUE(S5N->hasMemPred(S4N)); 739 EXPECT_TRUE(S5N->hasMemPred(S3N)); 740 // Check UnscheduledSuccs. 741 EXPECT_EQ(S3N->getNumUnscheduledSuccs(), 2u); // S4N, S5N 742 EXPECT_EQ(S4N->getNumUnscheduledSuccs(), 1u); // S5N 743 EXPECT_EQ(S5N->getNumUnscheduledSuccs(), 0u); 744 } 745 { 746 // Scenario 3: Extend above 747 auto NewIntvl = DAG.extend({S1, S2}); 748 EXPECT_EQ(NewIntvl, sandboxir::Interval<sandboxir::Instruction>(S1, S2)); 749 auto *S1N = cast<sandboxir::MemDGNode>(DAG.getNode(S1)); 750 auto *S2N = cast<sandboxir::MemDGNode>(DAG.getNode(S2)); 751 auto *S3N = cast<sandboxir::MemDGNode>(DAG.getNode(S3)); 752 auto *S4N = cast<sandboxir::MemDGNode>(DAG.getNode(S4)); 753 auto *S5N = cast<sandboxir::MemDGNode>(DAG.getNode(S5)); 754 755 EXPECT_TRUE(S2N->hasMemPred(S1N)); 756 757 EXPECT_TRUE(S3N->hasMemPred(S2N)); 758 EXPECT_TRUE(S3N->hasMemPred(S1N)); 759 760 EXPECT_TRUE(S4N->hasMemPred(S3N)); 761 EXPECT_TRUE(S4N->hasMemPred(S2N)); 762 EXPECT_TRUE(S4N->hasMemPred(S1N)); 763 764 EXPECT_TRUE(S5N->hasMemPred(S4N)); 765 EXPECT_TRUE(S5N->hasMemPred(S3N)); 766 EXPECT_TRUE(S5N->hasMemPred(S2N)); 767 EXPECT_TRUE(S5N->hasMemPred(S1N)); 768 769 // Check UnscheduledSuccs. 770 EXPECT_EQ(S1N->getNumUnscheduledSuccs(), 4u); // S2N, S3N, S4N, S5N 771 EXPECT_EQ(S2N->getNumUnscheduledSuccs(), 3u); // S3N, S4N, S5N 772 EXPECT_EQ(S3N->getNumUnscheduledSuccs(), 2u); // S4N, S5N 773 EXPECT_EQ(S4N->getNumUnscheduledSuccs(), 1u); // S5N 774 EXPECT_EQ(S5N->getNumUnscheduledSuccs(), 0u); 775 } 776 } 777