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 dependency(sandboxir::DGNode *SrcN, sandboxir::DGNode *DstN) { 54 const auto &Preds = DstN->memPreds(); 55 auto It = find(Preds, SrcN); 56 return It != Preds.end(); 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 sandboxir::DGNode *N0 = DAG.getNode(S0); 234 sandboxir::DGNode *N1 = DAG.getNode(S1); 235 sandboxir::DGNode *N2 = DAG.getNode(Ret); 236 // Check getInstruction(). 237 EXPECT_EQ(N0->getInstruction(), S0); 238 EXPECT_EQ(N1->getInstruction(), S1); 239 // Check hasMemPred() 240 EXPECT_TRUE(N1->hasMemPred(N0)); 241 EXPECT_FALSE(N0->hasMemPred(N1)); 242 243 // Check preds(). 244 EXPECT_TRUE(N0->preds(DAG).empty()); 245 EXPECT_THAT(N1->preds(DAG), testing::ElementsAre(N0)); 246 247 // Check memPreds(). 248 EXPECT_TRUE(N0->memPreds().empty()); 249 EXPECT_THAT(N1->memPreds(), testing::ElementsAre(N0)); 250 EXPECT_TRUE(N2->memPreds().empty()); 251 } 252 253 TEST_F(DependencyGraphTest, Preds) { 254 parseIR(C, R"IR( 255 declare ptr @bar(i8) 256 define i8 @foo(i8 %v0, i8 %v1) { 257 %add0 = add i8 %v0, %v0 258 %add1 = add i8 %v1, %v1 259 %add2 = add i8 %add0, %add1 260 %ptr = call ptr @bar(i8 %add1) 261 store i8 %add2, ptr %ptr 262 ret i8 %add2 263 } 264 )IR"); 265 llvm::Function *LLVMF = &*M->getFunction("foo"); 266 sandboxir::Context Ctx(C); 267 auto *F = Ctx.createFunction(LLVMF); 268 auto *BB = &*F->begin(); 269 auto It = BB->begin(); 270 sandboxir::DependencyGraph DAG(getAA(*LLVMF)); 271 DAG.extend({&*BB->begin(), BB->getTerminator()}); 272 273 auto *AddN0 = DAG.getNode(cast<sandboxir::BinaryOperator>(&*It++)); 274 auto *AddN1 = DAG.getNode(cast<sandboxir::BinaryOperator>(&*It++)); 275 auto *AddN2 = DAG.getNode(cast<sandboxir::BinaryOperator>(&*It++)); 276 auto *CallN = DAG.getNode(cast<sandboxir::CallInst>(&*It++)); 277 auto *StN = DAG.getNode(cast<sandboxir::StoreInst>(&*It++)); 278 auto *RetN = DAG.getNode(cast<sandboxir::ReturnInst>(&*It++)); 279 280 // Check preds(). 281 EXPECT_THAT(AddN0->preds(DAG), testing::ElementsAre()); 282 EXPECT_THAT(AddN1->preds(DAG), testing::ElementsAre()); 283 EXPECT_THAT(AddN2->preds(DAG), testing::ElementsAre(AddN0, AddN1)); 284 EXPECT_THAT(CallN->preds(DAG), testing::ElementsAre(AddN1)); 285 EXPECT_THAT(StN->preds(DAG), 286 testing::UnorderedElementsAre(CallN, CallN, AddN2)); 287 EXPECT_THAT(RetN->preds(DAG), testing::ElementsAre(AddN2)); 288 } 289 290 TEST_F(DependencyGraphTest, MemDGNode_getPrevNode_getNextNode) { 291 parseIR(C, R"IR( 292 define void @foo(ptr %ptr, i8 %v0, i8 %v1) { 293 store i8 %v0, ptr %ptr 294 add i8 %v0, %v0 295 store i8 %v1, ptr %ptr 296 ret void 297 } 298 )IR"); 299 llvm::Function *LLVMF = &*M->getFunction("foo"); 300 sandboxir::Context Ctx(C); 301 auto *F = Ctx.createFunction(LLVMF); 302 auto *BB = &*F->begin(); 303 auto It = BB->begin(); 304 auto *S0 = cast<sandboxir::StoreInst>(&*It++); 305 [[maybe_unused]] auto *Add = cast<sandboxir::BinaryOperator>(&*It++); 306 auto *S1 = cast<sandboxir::StoreInst>(&*It++); 307 [[maybe_unused]] auto *Ret = cast<sandboxir::ReturnInst>(&*It++); 308 309 sandboxir::DependencyGraph DAG(getAA(*LLVMF)); 310 DAG.extend({&*BB->begin(), BB->getTerminator()}); 311 312 auto *S0N = cast<sandboxir::MemDGNode>(DAG.getNode(S0)); 313 auto *S1N = cast<sandboxir::MemDGNode>(DAG.getNode(S1)); 314 315 EXPECT_EQ(S0N->getPrevNode(), nullptr); 316 EXPECT_EQ(S0N->getNextNode(), S1N); 317 318 EXPECT_EQ(S1N->getPrevNode(), S0N); 319 EXPECT_EQ(S1N->getNextNode(), nullptr); 320 } 321 322 TEST_F(DependencyGraphTest, DGNodeRange) { 323 parseIR(C, R"IR( 324 define void @foo(ptr %ptr, i8 %v0, i8 %v1) { 325 add i8 %v0, %v0 326 store i8 %v0, ptr %ptr 327 add i8 %v0, %v0 328 store i8 %v1, ptr %ptr 329 ret void 330 } 331 )IR"); 332 llvm::Function *LLVMF = &*M->getFunction("foo"); 333 sandboxir::Context Ctx(C); 334 auto *F = Ctx.createFunction(LLVMF); 335 auto *BB = &*F->begin(); 336 auto It = BB->begin(); 337 auto *Add0 = cast<sandboxir::BinaryOperator>(&*It++); 338 auto *S0 = cast<sandboxir::StoreInst>(&*It++); 339 auto *Add1 = cast<sandboxir::BinaryOperator>(&*It++); 340 auto *S1 = cast<sandboxir::StoreInst>(&*It++); 341 auto *Ret = cast<sandboxir::ReturnInst>(&*It++); 342 343 sandboxir::DependencyGraph DAG(getAA(*LLVMF)); 344 DAG.extend({&*BB->begin(), BB->getTerminator()}); 345 346 auto *S0N = cast<sandboxir::MemDGNode>(DAG.getNode(S0)); 347 auto *S1N = cast<sandboxir::MemDGNode>(DAG.getNode(S1)); 348 349 // Check empty range. 350 EXPECT_THAT(sandboxir::MemDGNodeIntervalBuilder::makeEmpty(), 351 testing::ElementsAre()); 352 353 // Returns the pointers in Range. 354 auto getPtrVec = [](const auto &Range) { 355 SmallVector<const sandboxir::DGNode *> Vec; 356 for (const sandboxir::DGNode &N : Range) 357 Vec.push_back(&N); 358 return Vec; 359 }; 360 // Both TopN and BotN are memory. 361 EXPECT_THAT( 362 getPtrVec(sandboxir::MemDGNodeIntervalBuilder::make({S0, S1}, DAG)), 363 testing::ElementsAre(S0N, S1N)); 364 // Only TopN is memory. 365 EXPECT_THAT( 366 getPtrVec(sandboxir::MemDGNodeIntervalBuilder::make({S0, Ret}, DAG)), 367 testing::ElementsAre(S0N, S1N)); 368 EXPECT_THAT( 369 getPtrVec(sandboxir::MemDGNodeIntervalBuilder::make({S0, Add1}, DAG)), 370 testing::ElementsAre(S0N)); 371 // Only BotN is memory. 372 EXPECT_THAT( 373 getPtrVec(sandboxir::MemDGNodeIntervalBuilder::make({Add0, S1}, DAG)), 374 testing::ElementsAre(S0N, S1N)); 375 EXPECT_THAT( 376 getPtrVec(sandboxir::MemDGNodeIntervalBuilder::make({Add0, S0}, DAG)), 377 testing::ElementsAre(S0N)); 378 // Neither TopN or BotN is memory. 379 EXPECT_THAT( 380 getPtrVec(sandboxir::MemDGNodeIntervalBuilder::make({Add0, Ret}, DAG)), 381 testing::ElementsAre(S0N, S1N)); 382 EXPECT_THAT( 383 getPtrVec(sandboxir::MemDGNodeIntervalBuilder::make({Add0, Add0}, DAG)), 384 testing::ElementsAre()); 385 } 386 387 TEST_F(DependencyGraphTest, AliasingStores) { 388 parseIR(C, R"IR( 389 define void @foo(ptr %ptr, i8 %v0, i8 %v1) { 390 store i8 %v0, ptr %ptr 391 store i8 %v1, ptr %ptr 392 ret void 393 } 394 )IR"); 395 llvm::Function *LLVMF = &*M->getFunction("foo"); 396 sandboxir::Context Ctx(C); 397 auto *F = Ctx.createFunction(LLVMF); 398 auto *BB = &*F->begin(); 399 sandboxir::DependencyGraph DAG(getAA(*LLVMF)); 400 DAG.extend({&*BB->begin(), BB->getTerminator()}); 401 auto It = BB->begin(); 402 auto *Store0N = DAG.getNode(cast<sandboxir::StoreInst>(&*It++)); 403 auto *Store1N = DAG.getNode(cast<sandboxir::StoreInst>(&*It++)); 404 auto *RetN = DAG.getNode(cast<sandboxir::ReturnInst>(&*It++)); 405 EXPECT_TRUE(Store0N->memPreds().empty()); 406 EXPECT_THAT(Store1N->memPreds(), testing::ElementsAre(Store0N)); 407 EXPECT_TRUE(RetN->memPreds().empty()); 408 } 409 410 TEST_F(DependencyGraphTest, NonAliasingStores) { 411 parseIR(C, R"IR( 412 define void @foo(ptr noalias %ptr0, ptr noalias %ptr1, i8 %v0, i8 %v1) { 413 store i8 %v0, ptr %ptr0 414 store i8 %v1, ptr %ptr1 415 ret void 416 } 417 )IR"); 418 llvm::Function *LLVMF = &*M->getFunction("foo"); 419 sandboxir::Context Ctx(C); 420 auto *F = Ctx.createFunction(LLVMF); 421 auto *BB = &*F->begin(); 422 sandboxir::DependencyGraph DAG(getAA(*LLVMF)); 423 DAG.extend({&*BB->begin(), BB->getTerminator()}); 424 auto It = BB->begin(); 425 auto *Store0N = DAG.getNode(cast<sandboxir::StoreInst>(&*It++)); 426 auto *Store1N = DAG.getNode(cast<sandboxir::StoreInst>(&*It++)); 427 auto *RetN = DAG.getNode(cast<sandboxir::ReturnInst>(&*It++)); 428 // We expect no dependencies because the stores don't alias. 429 EXPECT_TRUE(Store0N->memPreds().empty()); 430 EXPECT_TRUE(Store1N->memPreds().empty()); 431 EXPECT_TRUE(RetN->memPreds().empty()); 432 } 433 434 TEST_F(DependencyGraphTest, VolatileLoads) { 435 parseIR(C, R"IR( 436 define void @foo(ptr noalias %ptr0, ptr noalias %ptr1) { 437 %ld0 = load volatile i8, ptr %ptr0 438 %ld1 = load volatile i8, ptr %ptr1 439 ret void 440 } 441 )IR"); 442 llvm::Function *LLVMF = &*M->getFunction("foo"); 443 sandboxir::Context Ctx(C); 444 auto *F = Ctx.createFunction(LLVMF); 445 auto *BB = &*F->begin(); 446 sandboxir::DependencyGraph DAG(getAA(*LLVMF)); 447 DAG.extend({&*BB->begin(), BB->getTerminator()}); 448 auto It = BB->begin(); 449 auto *Ld0N = DAG.getNode(cast<sandboxir::LoadInst>(&*It++)); 450 auto *Ld1N = DAG.getNode(cast<sandboxir::LoadInst>(&*It++)); 451 auto *RetN = DAG.getNode(cast<sandboxir::ReturnInst>(&*It++)); 452 EXPECT_TRUE(Ld0N->memPreds().empty()); 453 EXPECT_THAT(Ld1N->memPreds(), testing::ElementsAre(Ld0N)); 454 EXPECT_TRUE(RetN->memPreds().empty()); 455 } 456 457 TEST_F(DependencyGraphTest, VolatileSotres) { 458 parseIR(C, R"IR( 459 define void @foo(ptr noalias %ptr0, ptr noalias %ptr1, i8 %v) { 460 store volatile i8 %v, ptr %ptr0 461 store volatile i8 %v, ptr %ptr1 462 ret void 463 } 464 )IR"); 465 llvm::Function *LLVMF = &*M->getFunction("foo"); 466 sandboxir::Context Ctx(C); 467 auto *F = Ctx.createFunction(LLVMF); 468 auto *BB = &*F->begin(); 469 sandboxir::DependencyGraph DAG(getAA(*LLVMF)); 470 DAG.extend({&*BB->begin(), BB->getTerminator()}); 471 auto It = BB->begin(); 472 auto *Store0N = DAG.getNode(cast<sandboxir::StoreInst>(&*It++)); 473 auto *Store1N = DAG.getNode(cast<sandboxir::StoreInst>(&*It++)); 474 auto *RetN = DAG.getNode(cast<sandboxir::ReturnInst>(&*It++)); 475 EXPECT_TRUE(Store0N->memPreds().empty()); 476 EXPECT_THAT(Store1N->memPreds(), testing::ElementsAre(Store0N)); 477 EXPECT_TRUE(RetN->memPreds().empty()); 478 } 479 480 TEST_F(DependencyGraphTest, Call) { 481 parseIR(C, R"IR( 482 declare void @bar1() 483 declare void @bar2() 484 define void @foo(float %v1, float %v2) { 485 call void @bar1() 486 %add = fadd float %v1, %v2 487 call void @bar2() 488 ret void 489 } 490 )IR"); 491 Function *LLVMF = M->getFunction("foo"); 492 493 sandboxir::Context Ctx(C); 494 auto *F = Ctx.createFunction(LLVMF); 495 auto *BB = &*F->begin(); 496 497 sandboxir::DependencyGraph DAG(getAA(*LLVMF)); 498 DAG.extend({&*BB->begin(), BB->getTerminator()->getPrevNode()}); 499 500 auto It = BB->begin(); 501 auto *Call1N = DAG.getNode(&*It++); 502 auto *AddN = DAG.getNode(&*It++); 503 auto *Call2N = DAG.getNode(&*It++); 504 505 EXPECT_THAT(Call1N->memPreds(), testing::ElementsAre()); 506 EXPECT_THAT(AddN->memPreds(), testing::ElementsAre()); 507 EXPECT_THAT(Call2N->memPreds(), testing::ElementsAre(Call1N)); 508 } 509 510 // Check that there is a dependency: stacksave -> alloca -> stackrestore. 511 TEST_F(DependencyGraphTest, StackSaveRestoreInAlloca) { 512 parseIR(C, R"IR( 513 declare ptr @llvm.stacksave() 514 declare void @llvm.stackrestore(ptr %ptr) 515 516 define void @foo() { 517 %stack0 = call ptr @llvm.stacksave() ; Should depend on store 518 %alloca0 = alloca inalloca i8 ; Should depend on stacksave 519 call void @llvm.stackrestore(ptr %stack0) ; Should depend transiently on %alloca0 520 ret void 521 } 522 )IR"); 523 Function *LLVMF = M->getFunction("foo"); 524 525 sandboxir::Context Ctx(C); 526 auto *F = Ctx.createFunction(LLVMF); 527 auto *BB = &*F->begin(); 528 529 sandboxir::DependencyGraph DAG(getAA(*LLVMF)); 530 DAG.extend({&*BB->begin(), BB->getTerminator()->getPrevNode()}); 531 532 auto It = BB->begin(); 533 auto *StackSaveN = DAG.getNode(&*It++); 534 auto *AllocaN = DAG.getNode(&*It++); 535 auto *StackRestoreN = DAG.getNode(&*It++); 536 537 EXPECT_TRUE(dependency(AllocaN, StackRestoreN)); 538 EXPECT_TRUE(dependency(StackSaveN, AllocaN)); 539 } 540 541 // Checks that stacksave and stackrestore depend on other mem instrs. 542 TEST_F(DependencyGraphTest, StackSaveRestoreDependOnOtherMem) { 543 parseIR(C, R"IR( 544 declare ptr @llvm.stacksave() 545 declare void @llvm.stackrestore(ptr %ptr) 546 547 define void @foo(i8 %v0, i8 %v1, ptr %ptr) { 548 store volatile i8 %v0, ptr %ptr, align 4 549 %stack0 = call ptr @llvm.stacksave() ; Should depend on store 550 call void @llvm.stackrestore(ptr %stack0) ; Should depend on stacksave 551 store volatile i8 %v1, ptr %ptr, align 4 ; Should depend on stackrestore 552 ret void 553 } 554 )IR"); 555 Function *LLVMF = M->getFunction("foo"); 556 557 sandboxir::Context Ctx(C); 558 auto *F = Ctx.createFunction(LLVMF); 559 auto *BB = &*F->begin(); 560 561 sandboxir::DependencyGraph DAG(getAA(*LLVMF)); 562 DAG.extend({&*BB->begin(), BB->getTerminator()->getPrevNode()}); 563 564 auto It = BB->begin(); 565 auto *Store0N = DAG.getNode(&*It++); 566 auto *StackSaveN = DAG.getNode(&*It++); 567 auto *StackRestoreN = DAG.getNode(&*It++); 568 auto *Store1N = DAG.getNode(&*It++); 569 570 EXPECT_TRUE(dependency(Store0N, StackSaveN)); 571 EXPECT_TRUE(dependency(StackSaveN, StackRestoreN)); 572 EXPECT_TRUE(dependency(StackRestoreN, Store1N)); 573 } 574 575 // Make sure there is a dependency between a stackrestore and an alloca. 576 TEST_F(DependencyGraphTest, StackRestoreAndInAlloca) { 577 parseIR(C, R"IR( 578 declare void @llvm.stackrestore(ptr %ptr) 579 580 define void @foo(ptr %ptr) { 581 call void @llvm.stackrestore(ptr %ptr) 582 %alloca0 = alloca inalloca i8 ; Should depend on stackrestore 583 ret void 584 } 585 )IR"); 586 Function *LLVMF = M->getFunction("foo"); 587 588 sandboxir::Context Ctx(C); 589 auto *F = Ctx.createFunction(LLVMF); 590 auto *BB = &*F->begin(); 591 592 sandboxir::DependencyGraph DAG(getAA(*LLVMF)); 593 DAG.extend({&*BB->begin(), BB->getTerminator()->getPrevNode()}); 594 595 auto It = BB->begin(); 596 auto *StackRestoreN = DAG.getNode(&*It++); 597 auto *AllocaN = DAG.getNode(&*It++); 598 599 EXPECT_TRUE(dependency(StackRestoreN, AllocaN)); 600 } 601 602 // Make sure there is a dependency between the alloca and stacksave 603 TEST_F(DependencyGraphTest, StackSaveAndInAlloca) { 604 parseIR(C, R"IR( 605 declare ptr @llvm.stacksave() 606 607 define void @foo(ptr %ptr) { 608 %alloca0 = alloca inalloca i8 ; Should depend on stackrestore 609 %stack0 = call ptr @llvm.stacksave() ; Should depend on alloca0 610 ret void 611 } 612 )IR"); 613 Function *LLVMF = M->getFunction("foo"); 614 615 sandboxir::Context Ctx(C); 616 auto *F = Ctx.createFunction(LLVMF); 617 auto *BB = &*F->begin(); 618 619 sandboxir::DependencyGraph DAG(getAA(*LLVMF)); 620 DAG.extend({&*BB->begin(), BB->getTerminator()->getPrevNode()}); 621 622 auto It = BB->begin(); 623 auto *AllocaN = DAG.getNode(&*It++); 624 auto *StackSaveN = DAG.getNode(&*It++); 625 626 EXPECT_TRUE(dependency(AllocaN, StackSaveN)); 627 } 628 629 // A non-InAlloca in a stacksave-stackrestore region does not need extra 630 // dependencies. 631 TEST_F(DependencyGraphTest, StackSaveRestoreNoInAlloca) { 632 parseIR(C, R"IR( 633 declare ptr @llvm.stacksave() 634 declare void @llvm.stackrestore(ptr %ptr) 635 declare void @use(ptr %ptr) 636 637 define void @foo() { 638 %stack = call ptr @llvm.stacksave() 639 %alloca1 = alloca i8 ; No dependency 640 call void @llvm.stackrestore(ptr %stack) 641 ret void 642 } 643 )IR"); 644 Function *LLVMF = M->getFunction("foo"); 645 646 sandboxir::Context Ctx(C); 647 auto *F = Ctx.createFunction(LLVMF); 648 auto *BB = &*F->begin(); 649 650 sandboxir::DependencyGraph DAG(getAA(*LLVMF)); 651 DAG.extend({&*BB->begin(), BB->getTerminator()->getPrevNode()}); 652 653 auto It = BB->begin(); 654 auto *StackSaveN = DAG.getNode(&*It++); 655 auto *AllocaN = DAG.getNode(&*It++); 656 auto *StackRestoreN = DAG.getNode(&*It++); 657 658 EXPECT_FALSE(dependency(StackSaveN, AllocaN)); 659 EXPECT_FALSE(dependency(AllocaN, StackRestoreN)); 660 } 661