Mercurial > hg > CbC > CbC_llvm
comparison lib/IR/SafepointIRVerifier.cpp @ 148:63bd29f05246
merged
author | Shinji KONO <kono@ie.u-ryukyu.ac.jp> |
---|---|
date | Wed, 14 Aug 2019 19:46:37 +0900 |
parents | c2174574ed3a |
children |
comparison
equal
deleted
inserted
replaced
146:3fc4d5c3e21e | 148:63bd29f05246 |
---|---|
1 //===-- SafepointIRVerifier.cpp - Verify gc.statepoint invariants ---------===// | 1 //===-- SafepointIRVerifier.cpp - Verify gc.statepoint invariants ---------===// |
2 // | 2 // |
3 // The LLVM Compiler Infrastructure | 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 // | 4 // See https://llvm.org/LICENSE.txt for license information. |
5 // This file is distributed under the University of Illinois Open Source | 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 // License. See LICENSE.TXT for details. | |
7 // | 6 // |
8 //===----------------------------------------------------------------------===// | 7 //===----------------------------------------------------------------------===// |
9 // | 8 // |
10 // Run a sanity check on the IR to ensure that Safepoints - if they've been | 9 // Run a sanity check on the IR to ensure that Safepoints - if they've been |
11 // inserted - were inserted correctly. In particular, look for use of | 10 // inserted - were inserted correctly. In particular, look for use of |
57 /// when verification fails, report a message to the console (for FileCheck | 56 /// when verification fails, report a message to the console (for FileCheck |
58 /// usage) and continue execution as if nothing happened. | 57 /// usage) and continue execution as if nothing happened. |
59 static cl::opt<bool> PrintOnly("safepoint-ir-verifier-print-only", | 58 static cl::opt<bool> PrintOnly("safepoint-ir-verifier-print-only", |
60 cl::init(false)); | 59 cl::init(false)); |
61 | 60 |
62 static void Verify(const Function &F, const DominatorTree &DT); | |
63 | |
64 namespace { | 61 namespace { |
62 | |
63 /// This CFG Deadness finds dead blocks and edges. Algorithm starts with a set | |
64 /// of blocks unreachable from entry then propagates deadness using foldable | |
65 /// conditional branches without modifying CFG. So GVN does but it changes CFG | |
66 /// by splitting critical edges. In most cases passes rely on SimplifyCFG to | |
67 /// clean up dead blocks, but in some cases, like verification or loop passes | |
68 /// it's not possible. | |
69 class CFGDeadness { | |
70 const DominatorTree *DT = nullptr; | |
71 SetVector<const BasicBlock *> DeadBlocks; | |
72 SetVector<const Use *> DeadEdges; // Contains all dead edges from live blocks. | |
73 | |
74 public: | |
75 /// Return the edge that coresponds to the predecessor. | |
76 static const Use& getEdge(const_pred_iterator &PredIt) { | |
77 auto &PU = PredIt.getUse(); | |
78 return PU.getUser()->getOperandUse(PU.getOperandNo()); | |
79 } | |
80 | |
81 /// Return true if there is at least one live edge that corresponds to the | |
82 /// basic block InBB listed in the phi node. | |
83 bool hasLiveIncomingEdge(const PHINode *PN, const BasicBlock *InBB) const { | |
84 assert(!isDeadBlock(InBB) && "block must be live"); | |
85 const BasicBlock* BB = PN->getParent(); | |
86 bool Listed = false; | |
87 for (const_pred_iterator PredIt(BB), End(BB, true); PredIt != End; ++PredIt) { | |
88 if (InBB == *PredIt) { | |
89 if (!isDeadEdge(&getEdge(PredIt))) | |
90 return true; | |
91 Listed = true; | |
92 } | |
93 } | |
94 (void)Listed; | |
95 assert(Listed && "basic block is not found among incoming blocks"); | |
96 return false; | |
97 } | |
98 | |
99 | |
100 bool isDeadBlock(const BasicBlock *BB) const { | |
101 return DeadBlocks.count(BB); | |
102 } | |
103 | |
104 bool isDeadEdge(const Use *U) const { | |
105 assert(dyn_cast<Instruction>(U->getUser())->isTerminator() && | |
106 "edge must be operand of terminator"); | |
107 assert(cast_or_null<BasicBlock>(U->get()) && | |
108 "edge must refer to basic block"); | |
109 assert(!isDeadBlock(dyn_cast<Instruction>(U->getUser())->getParent()) && | |
110 "isDeadEdge() must be applied to edge from live block"); | |
111 return DeadEdges.count(U); | |
112 } | |
113 | |
114 bool hasLiveIncomingEdges(const BasicBlock *BB) const { | |
115 // Check if all incoming edges are dead. | |
116 for (const_pred_iterator PredIt(BB), End(BB, true); PredIt != End; ++PredIt) { | |
117 auto &PU = PredIt.getUse(); | |
118 const Use &U = PU.getUser()->getOperandUse(PU.getOperandNo()); | |
119 if (!isDeadBlock(*PredIt) && !isDeadEdge(&U)) | |
120 return true; // Found a live edge. | |
121 } | |
122 return false; | |
123 } | |
124 | |
125 void processFunction(const Function &F, const DominatorTree &DT) { | |
126 this->DT = &DT; | |
127 | |
128 // Start with all blocks unreachable from entry. | |
129 for (const BasicBlock &BB : F) | |
130 if (!DT.isReachableFromEntry(&BB)) | |
131 DeadBlocks.insert(&BB); | |
132 | |
133 // Top-down walk of the dominator tree | |
134 ReversePostOrderTraversal<const Function *> RPOT(&F); | |
135 for (const BasicBlock *BB : RPOT) { | |
136 const Instruction *TI = BB->getTerminator(); | |
137 assert(TI && "blocks must be well formed"); | |
138 | |
139 // For conditional branches, we can perform simple conditional propagation on | |
140 // the condition value itself. | |
141 const BranchInst *BI = dyn_cast<BranchInst>(TI); | |
142 if (!BI || !BI->isConditional() || !isa<Constant>(BI->getCondition())) | |
143 continue; | |
144 | |
145 // If a branch has two identical successors, we cannot declare either dead. | |
146 if (BI->getSuccessor(0) == BI->getSuccessor(1)) | |
147 continue; | |
148 | |
149 ConstantInt *Cond = dyn_cast<ConstantInt>(BI->getCondition()); | |
150 if (!Cond) | |
151 continue; | |
152 | |
153 addDeadEdge(BI->getOperandUse(Cond->getZExtValue() ? 1 : 2)); | |
154 } | |
155 } | |
156 | |
157 protected: | |
158 void addDeadBlock(const BasicBlock *BB) { | |
159 SmallVector<const BasicBlock *, 4> NewDead; | |
160 SmallSetVector<const BasicBlock *, 4> DF; | |
161 | |
162 NewDead.push_back(BB); | |
163 while (!NewDead.empty()) { | |
164 const BasicBlock *D = NewDead.pop_back_val(); | |
165 if (isDeadBlock(D)) | |
166 continue; | |
167 | |
168 // All blocks dominated by D are dead. | |
169 SmallVector<BasicBlock *, 8> Dom; | |
170 DT->getDescendants(const_cast<BasicBlock*>(D), Dom); | |
171 // Do not need to mark all in and out edges dead | |
172 // because BB is marked dead and this is enough | |
173 // to run further. | |
174 DeadBlocks.insert(Dom.begin(), Dom.end()); | |
175 | |
176 // Figure out the dominance-frontier(D). | |
177 for (BasicBlock *B : Dom) | |
178 for (BasicBlock *S : successors(B)) | |
179 if (!isDeadBlock(S) && !hasLiveIncomingEdges(S)) | |
180 NewDead.push_back(S); | |
181 } | |
182 } | |
183 | |
184 void addDeadEdge(const Use &DeadEdge) { | |
185 if (!DeadEdges.insert(&DeadEdge)) | |
186 return; | |
187 | |
188 BasicBlock *BB = cast_or_null<BasicBlock>(DeadEdge.get()); | |
189 if (hasLiveIncomingEdges(BB)) | |
190 return; | |
191 | |
192 addDeadBlock(BB); | |
193 } | |
194 }; | |
195 } // namespace | |
196 | |
197 static void Verify(const Function &F, const DominatorTree &DT, | |
198 const CFGDeadness &CD); | |
199 | |
200 namespace llvm { | |
201 PreservedAnalyses SafepointIRVerifierPass::run(Function &F, | |
202 FunctionAnalysisManager &AM) { | |
203 const auto &DT = AM.getResult<DominatorTreeAnalysis>(F); | |
204 CFGDeadness CD; | |
205 CD.processFunction(F, DT); | |
206 Verify(F, DT, CD); | |
207 return PreservedAnalyses::all(); | |
208 } | |
209 } | |
210 | |
211 namespace { | |
212 | |
65 struct SafepointIRVerifier : public FunctionPass { | 213 struct SafepointIRVerifier : public FunctionPass { |
66 static char ID; // Pass identification, replacement for typeid | 214 static char ID; // Pass identification, replacement for typeid |
67 DominatorTree DT; | |
68 SafepointIRVerifier() : FunctionPass(ID) { | 215 SafepointIRVerifier() : FunctionPass(ID) { |
69 initializeSafepointIRVerifierPass(*PassRegistry::getPassRegistry()); | 216 initializeSafepointIRVerifierPass(*PassRegistry::getPassRegistry()); |
70 } | 217 } |
71 | 218 |
72 bool runOnFunction(Function &F) override { | 219 bool runOnFunction(Function &F) override { |
73 DT.recalculate(F); | 220 auto &DT = getAnalysis<DominatorTreeWrapperPass>().getDomTree(); |
74 Verify(F, DT); | 221 CFGDeadness CD; |
222 CD.processFunction(F, DT); | |
223 Verify(F, DT, CD); | |
75 return false; // no modifications | 224 return false; // no modifications |
76 } | 225 } |
77 | 226 |
78 void getAnalysisUsage(AnalysisUsage &AU) const override { | 227 void getAnalysisUsage(AnalysisUsage &AU) const override { |
228 AU.addRequiredID(DominatorTreeWrapperPass::ID); | |
79 AU.setPreservesAll(); | 229 AU.setPreservesAll(); |
80 } | 230 } |
81 | 231 |
82 StringRef getPassName() const override { return "safepoint verifier"; } | 232 StringRef getPassName() const override { return "safepoint verifier"; } |
83 }; | 233 }; |
93 FunctionPass *llvm::createSafepointIRVerifierPass() { | 243 FunctionPass *llvm::createSafepointIRVerifierPass() { |
94 return new SafepointIRVerifier(); | 244 return new SafepointIRVerifier(); |
95 } | 245 } |
96 | 246 |
97 INITIALIZE_PASS_BEGIN(SafepointIRVerifier, "verify-safepoint-ir", | 247 INITIALIZE_PASS_BEGIN(SafepointIRVerifier, "verify-safepoint-ir", |
98 "Safepoint IR Verifier", false, true) | 248 "Safepoint IR Verifier", false, false) |
249 INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass) | |
99 INITIALIZE_PASS_END(SafepointIRVerifier, "verify-safepoint-ir", | 250 INITIALIZE_PASS_END(SafepointIRVerifier, "verify-safepoint-ir", |
100 "Safepoint IR Verifier", false, true) | 251 "Safepoint IR Verifier", false, false) |
101 | 252 |
102 static bool isGCPointerType(Type *T) { | 253 static bool isGCPointerType(Type *T) { |
103 if (auto *PT = dyn_cast<PointerType>(T)) | 254 if (auto *PT = dyn_cast<PointerType>(T)) |
104 // For the sake of this example GC, we arbitrarily pick addrspace(1) as our | 255 // For the sake of this example GC, we arbitrarily pick addrspace(1) as our |
105 // GC managed heap. We know that a pointer into this heap needs to be | 256 // GC managed heap. We know that a pointer into this heap needs to be |
114 if (VectorType *VT = dyn_cast<VectorType>(Ty)) | 265 if (VectorType *VT = dyn_cast<VectorType>(Ty)) |
115 return isGCPointerType(VT->getScalarType()); | 266 return isGCPointerType(VT->getScalarType()); |
116 if (ArrayType *AT = dyn_cast<ArrayType>(Ty)) | 267 if (ArrayType *AT = dyn_cast<ArrayType>(Ty)) |
117 return containsGCPtrType(AT->getElementType()); | 268 return containsGCPtrType(AT->getElementType()); |
118 if (StructType *ST = dyn_cast<StructType>(Ty)) | 269 if (StructType *ST = dyn_cast<StructType>(Ty)) |
119 return std::any_of(ST->subtypes().begin(), ST->subtypes().end(), | 270 return llvm::any_of(ST->elements(), containsGCPtrType); |
120 containsGCPtrType); | |
121 return false; | 271 return false; |
122 } | 272 } |
123 | 273 |
124 // Debugging aid -- prints a [Begin, End) range of values. | 274 // Debugging aid -- prints a [Begin, End) range of values. |
125 template<typename IteratorTy> | 275 template<typename IteratorTy> |
290 /// To fix this we need to introduce conception of generations and be able to | 440 /// To fix this we need to introduce conception of generations and be able to |
291 /// check if two values belong to one generation or not. This way p2 will be | 441 /// check if two values belong to one generation or not. This way p2 will be |
292 /// considered to be unrelocated and no false alarm will happen. | 442 /// considered to be unrelocated and no false alarm will happen. |
293 class GCPtrTracker { | 443 class GCPtrTracker { |
294 const Function &F; | 444 const Function &F; |
445 const CFGDeadness &CD; | |
295 SpecificBumpPtrAllocator<BasicBlockState> BSAllocator; | 446 SpecificBumpPtrAllocator<BasicBlockState> BSAllocator; |
296 DenseMap<const BasicBlock *, BasicBlockState *> BlockMap; | 447 DenseMap<const BasicBlock *, BasicBlockState *> BlockMap; |
297 // This set contains defs of unrelocated pointers that are proved to be legal | 448 // This set contains defs of unrelocated pointers that are proved to be legal |
298 // and don't need verification. | 449 // and don't need verification. |
299 DenseSet<const Instruction *> ValidUnrelocatedDefs; | 450 DenseSet<const Instruction *> ValidUnrelocatedDefs; |
300 // This set contains poisoned defs. They can be safely ignored during | 451 // This set contains poisoned defs. They can be safely ignored during |
301 // verification too. | 452 // verification too. |
302 DenseSet<const Value *> PoisonedDefs; | 453 DenseSet<const Value *> PoisonedDefs; |
303 | 454 |
304 public: | 455 public: |
305 GCPtrTracker(const Function &F, const DominatorTree &DT); | 456 GCPtrTracker(const Function &F, const DominatorTree &DT, |
457 const CFGDeadness &CD); | |
458 | |
459 bool hasLiveIncomingEdge(const PHINode *PN, const BasicBlock *InBB) const { | |
460 return CD.hasLiveIncomingEdge(PN, InBB); | |
461 } | |
306 | 462 |
307 BasicBlockState *getBasicBlockState(const BasicBlock *BB); | 463 BasicBlockState *getBasicBlockState(const BasicBlock *BB); |
308 const BasicBlockState *getBasicBlockState(const BasicBlock *BB) const; | 464 const BasicBlockState *getBasicBlockState(const BasicBlock *BB) const; |
309 | 465 |
310 bool isValuePoisoned(const Value *V) const { return PoisonedDefs.count(V); } | 466 bool isValuePoisoned(const Value *V) const { return PoisonedDefs.count(V); } |
315 /// It destructively modifies GCPtrTracker so it's passed via rvalue reference | 471 /// It destructively modifies GCPtrTracker so it's passed via rvalue reference |
316 /// in order to prohibit further usages of GCPtrTracker as it'll be in | 472 /// in order to prohibit further usages of GCPtrTracker as it'll be in |
317 /// inconsistent state. | 473 /// inconsistent state. |
318 static void verifyFunction(GCPtrTracker &&Tracker, | 474 static void verifyFunction(GCPtrTracker &&Tracker, |
319 InstructionVerifier &Verifier); | 475 InstructionVerifier &Verifier); |
476 | |
477 /// Returns true for reachable and live blocks. | |
478 bool isMapped(const BasicBlock *BB) const { | |
479 return BlockMap.find(BB) != BlockMap.end(); | |
480 } | |
320 | 481 |
321 private: | 482 private: |
322 /// Returns true if the instruction may be safely skipped during verification. | 483 /// Returns true if the instruction may be safely skipped during verification. |
323 bool instructionMayBeSkipped(const Instruction *I) const; | 484 bool instructionMayBeSkipped(const Instruction *I) const; |
324 | 485 |
370 private: | 531 private: |
371 void reportInvalidUse(const Value &V, const Instruction &I); | 532 void reportInvalidUse(const Value &V, const Instruction &I); |
372 }; | 533 }; |
373 } // end anonymous namespace | 534 } // end anonymous namespace |
374 | 535 |
375 GCPtrTracker::GCPtrTracker(const Function &F, const DominatorTree &DT) : F(F) { | 536 GCPtrTracker::GCPtrTracker(const Function &F, const DominatorTree &DT, |
376 // First, calculate Contribution of each BB. | 537 const CFGDeadness &CD) : F(F), CD(CD) { |
377 for (const BasicBlock &BB : F) { | 538 // Calculate Contribution of each live BB. |
378 BasicBlockState *BBS = new (BSAllocator.Allocate()) BasicBlockState; | 539 // Allocate BB states for live blocks. |
379 for (const auto &I : BB) | 540 for (const BasicBlock &BB : F) |
380 transferInstruction(I, BBS->Cleared, BBS->Contribution); | 541 if (!CD.isDeadBlock(&BB)) { |
381 BlockMap[&BB] = BBS; | 542 BasicBlockState *BBS = new (BSAllocator.Allocate()) BasicBlockState; |
382 } | 543 for (const auto &I : BB) |
544 transferInstruction(I, BBS->Cleared, BBS->Contribution); | |
545 BlockMap[&BB] = BBS; | |
546 } | |
383 | 547 |
384 // Initialize AvailableIn/Out sets of each BB using only information about | 548 // Initialize AvailableIn/Out sets of each BB using only information about |
385 // dominating BBs. | 549 // dominating BBs. |
386 for (auto &BBI : BlockMap) { | 550 for (auto &BBI : BlockMap) { |
387 gatherDominatingDefs(BBI.first, BBI.second->AvailableIn, DT); | 551 gatherDominatingDefs(BBI.first, BBI.second->AvailableIn, DT); |
394 recalculateBBsStates(); | 558 recalculateBBsStates(); |
395 } | 559 } |
396 | 560 |
397 BasicBlockState *GCPtrTracker::getBasicBlockState(const BasicBlock *BB) { | 561 BasicBlockState *GCPtrTracker::getBasicBlockState(const BasicBlock *BB) { |
398 auto it = BlockMap.find(BB); | 562 auto it = BlockMap.find(BB); |
399 assert(it != BlockMap.end() && | 563 return it != BlockMap.end() ? it->second : nullptr; |
400 "No such BB in BlockMap! Probably BB from another function"); | |
401 return it->second; | |
402 } | 564 } |
403 | 565 |
404 const BasicBlockState *GCPtrTracker::getBasicBlockState( | 566 const BasicBlockState *GCPtrTracker::getBasicBlockState( |
405 const BasicBlock *BB) const { | 567 const BasicBlock *BB) const { |
406 return const_cast<GCPtrTracker *>(this)->getBasicBlockState(BB); | 568 return const_cast<GCPtrTracker *>(this)->getBasicBlockState(BB); |
417 // We need RPO here to a) report always the first error b) report errors in | 579 // We need RPO here to a) report always the first error b) report errors in |
418 // same order from run to run. | 580 // same order from run to run. |
419 ReversePostOrderTraversal<const Function *> RPOT(&Tracker.F); | 581 ReversePostOrderTraversal<const Function *> RPOT(&Tracker.F); |
420 for (const BasicBlock *BB : RPOT) { | 582 for (const BasicBlock *BB : RPOT) { |
421 BasicBlockState *BBS = Tracker.getBasicBlockState(BB); | 583 BasicBlockState *BBS = Tracker.getBasicBlockState(BB); |
584 if (!BBS) | |
585 continue; | |
586 | |
422 // We destructively modify AvailableIn as we traverse the block instruction | 587 // We destructively modify AvailableIn as we traverse the block instruction |
423 // by instruction. | 588 // by instruction. |
424 AvailableValueSet &AvailableSet = BBS->AvailableIn; | 589 AvailableValueSet &AvailableSet = BBS->AvailableIn; |
425 for (const Instruction &I : *BB) { | 590 for (const Instruction &I : *BB) { |
426 if (Tracker.instructionMayBeSkipped(&I)) | 591 if (Tracker.instructionMayBeSkipped(&I)) |
446 | 611 |
447 // This loop iterates the AvailableIn/Out sets until it converges. | 612 // This loop iterates the AvailableIn/Out sets until it converges. |
448 // The AvailableIn and AvailableOut sets decrease as we iterate. | 613 // The AvailableIn and AvailableOut sets decrease as we iterate. |
449 while (!Worklist.empty()) { | 614 while (!Worklist.empty()) { |
450 const BasicBlock *BB = Worklist.pop_back_val(); | 615 const BasicBlock *BB = Worklist.pop_back_val(); |
451 BasicBlockState *BBS = BlockMap[BB]; | 616 BasicBlockState *BBS = getBasicBlockState(BB); |
617 if (!BBS) | |
618 continue; // Ignore dead successors. | |
452 | 619 |
453 size_t OldInCount = BBS->AvailableIn.size(); | 620 size_t OldInCount = BBS->AvailableIn.size(); |
454 for (const BasicBlock *PBB : predecessors(BB)) | 621 for (const_pred_iterator PredIt(BB), End(BB, true); PredIt != End; ++PredIt) { |
455 set_intersect(BBS->AvailableIn, BlockMap[PBB]->AvailableOut); | 622 const BasicBlock *PBB = *PredIt; |
623 BasicBlockState *PBBS = getBasicBlockState(PBB); | |
624 if (PBBS && !CD.isDeadEdge(&CFGDeadness::getEdge(PredIt))) | |
625 set_intersect(BBS->AvailableIn, PBBS->AvailableOut); | |
626 } | |
456 | 627 |
457 assert(OldInCount >= BBS->AvailableIn.size() && "invariant!"); | 628 assert(OldInCount >= BBS->AvailableIn.size() && "invariant!"); |
458 | 629 |
459 bool InputsChanged = OldInCount != BBS->AvailableIn.size(); | 630 bool InputsChanged = OldInCount != BBS->AvailableIn.size(); |
460 bool ContributionChanged = | 631 bool ContributionChanged = |
489 // If both is true, output is poisoned. | 660 // If both is true, output is poisoned. |
490 bool HasRelocatedInputs = false; | 661 bool HasRelocatedInputs = false; |
491 bool HasUnrelocatedInputs = false; | 662 bool HasUnrelocatedInputs = false; |
492 for (unsigned i = 0, e = PN->getNumIncomingValues(); i != e; ++i) { | 663 for (unsigned i = 0, e = PN->getNumIncomingValues(); i != e; ++i) { |
493 const BasicBlock *InBB = PN->getIncomingBlock(i); | 664 const BasicBlock *InBB = PN->getIncomingBlock(i); |
665 if (!isMapped(InBB) || | |
666 !CD.hasLiveIncomingEdge(PN, InBB)) | |
667 continue; // Skip dead block or dead edge. | |
668 | |
494 const Value *InValue = PN->getIncomingValue(i); | 669 const Value *InValue = PN->getIncomingValue(i); |
495 | 670 |
496 if (isNotExclusivelyConstantDerived(InValue)) { | 671 if (isNotExclusivelyConstantDerived(InValue)) { |
497 if (isValuePoisoned(InValue)) { | 672 if (isValuePoisoned(InValue)) { |
498 // If any of inputs is poisoned, output is always poisoned too. | 673 // If any of inputs is poisoned, output is always poisoned too. |
533 // Remove def of unrelocated pointer from Contribution of this BB and | 708 // Remove def of unrelocated pointer from Contribution of this BB and |
534 // trigger update of all its successors. | 709 // trigger update of all its successors. |
535 Contribution.erase(&I); | 710 Contribution.erase(&I); |
536 PoisonedDefs.erase(&I); | 711 PoisonedDefs.erase(&I); |
537 ValidUnrelocatedDefs.insert(&I); | 712 ValidUnrelocatedDefs.insert(&I); |
538 DEBUG(dbgs() << "Removing urelocated " << I << " from Contribution of " | 713 LLVM_DEBUG(dbgs() << "Removing urelocated " << I |
539 << BB->getName() << "\n"); | 714 << " from Contribution of " << BB->getName() << "\n"); |
540 ContributionChanged = true; | 715 ContributionChanged = true; |
541 } else if (PoisonedPointerDef) { | 716 } else if (PoisonedPointerDef) { |
542 // Mark pointer as poisoned, remove its def from Contribution and trigger | 717 // Mark pointer as poisoned, remove its def from Contribution and trigger |
543 // update of all successors. | 718 // update of all successors. |
544 Contribution.erase(&I); | 719 Contribution.erase(&I); |
545 PoisonedDefs.insert(&I); | 720 PoisonedDefs.insert(&I); |
546 DEBUG(dbgs() << "Removing poisoned " << I << " from Contribution of " | 721 LLVM_DEBUG(dbgs() << "Removing poisoned " << I << " from Contribution of " |
547 << BB->getName() << "\n"); | 722 << BB->getName() << "\n"); |
548 ContributionChanged = true; | 723 ContributionChanged = true; |
549 } else { | 724 } else { |
550 bool Cleared = false; | 725 bool Cleared = false; |
551 transferInstruction(I, Cleared, AvailableSet); | 726 transferInstruction(I, Cleared, AvailableSet); |
552 (void)Cleared; | 727 (void)Cleared; |
558 void GCPtrTracker::gatherDominatingDefs(const BasicBlock *BB, | 733 void GCPtrTracker::gatherDominatingDefs(const BasicBlock *BB, |
559 AvailableValueSet &Result, | 734 AvailableValueSet &Result, |
560 const DominatorTree &DT) { | 735 const DominatorTree &DT) { |
561 DomTreeNode *DTN = DT[const_cast<BasicBlock *>(BB)]; | 736 DomTreeNode *DTN = DT[const_cast<BasicBlock *>(BB)]; |
562 | 737 |
738 assert(DTN && "Unreachable blocks are ignored"); | |
563 while (DTN->getIDom()) { | 739 while (DTN->getIDom()) { |
564 DTN = DTN->getIDom(); | 740 DTN = DTN->getIDom(); |
565 const auto &Defs = BlockMap[DTN->getBlock()]->Contribution; | 741 auto BBS = getBasicBlockState(DTN->getBlock()); |
742 assert(BBS && "immediate dominator cannot be dead for a live block"); | |
743 const auto &Defs = BBS->Contribution; | |
566 Result.insert(Defs.begin(), Defs.end()); | 744 Result.insert(Defs.begin(), Defs.end()); |
567 // If this block is 'Cleared', then nothing LiveIn to this block can be | 745 // If this block is 'Cleared', then nothing LiveIn to this block can be |
568 // available after this block completes. Note: This turns out to be | 746 // available after this block completes. Note: This turns out to be |
569 // really important for reducing memory consuption of the initial available | 747 // really important for reducing memory consuption of the initial available |
570 // sets and thus peak memory usage by this verifier. | 748 // sets and thus peak memory usage by this verifier. |
571 if (BlockMap[DTN->getBlock()]->Cleared) | 749 if (BBS->Cleared) |
572 return; | 750 return; |
573 } | 751 } |
574 | 752 |
575 for (const Argument &A : BB->getParent()->args()) | 753 for (const Argument &A : BB->getParent()->args()) |
576 if (containsGCPtrType(A.getType())) | 754 if (containsGCPtrType(A.getType())) |
592 AvailableValueSet Temp = BBS.Contribution; | 770 AvailableValueSet Temp = BBS.Contribution; |
593 set_union(Temp, AvailableIn); | 771 set_union(Temp, AvailableIn); |
594 AvailableOut = std::move(Temp); | 772 AvailableOut = std::move(Temp); |
595 } | 773 } |
596 | 774 |
597 DEBUG(dbgs() << "Transfered block " << BB->getName() << " from "; | 775 LLVM_DEBUG(dbgs() << "Transfered block " << BB->getName() << " from "; |
598 PrintValueSet(dbgs(), AvailableIn.begin(), AvailableIn.end()); | 776 PrintValueSet(dbgs(), AvailableIn.begin(), AvailableIn.end()); |
599 dbgs() << " to "; | 777 dbgs() << " to "; |
600 PrintValueSet(dbgs(), AvailableOut.begin(), AvailableOut.end()); | 778 PrintValueSet(dbgs(), AvailableOut.begin(), AvailableOut.end()); |
601 dbgs() << "\n";); | 779 dbgs() << "\n";); |
602 } | 780 } |
603 | 781 |
604 void GCPtrTracker::transferInstruction(const Instruction &I, bool &Cleared, | 782 void GCPtrTracker::transferInstruction(const Instruction &I, bool &Cleared, |
605 AvailableValueSet &Available) { | 783 AvailableValueSet &Available) { |
606 if (isStatepoint(I)) { | 784 if (isStatepoint(I)) { |
615 const AvailableValueSet &AvailableSet) { | 793 const AvailableValueSet &AvailableSet) { |
616 if (const PHINode *PN = dyn_cast<PHINode>(&I)) { | 794 if (const PHINode *PN = dyn_cast<PHINode>(&I)) { |
617 if (containsGCPtrType(PN->getType())) | 795 if (containsGCPtrType(PN->getType())) |
618 for (unsigned i = 0, e = PN->getNumIncomingValues(); i != e; ++i) { | 796 for (unsigned i = 0, e = PN->getNumIncomingValues(); i != e; ++i) { |
619 const BasicBlock *InBB = PN->getIncomingBlock(i); | 797 const BasicBlock *InBB = PN->getIncomingBlock(i); |
798 const BasicBlockState *InBBS = Tracker->getBasicBlockState(InBB); | |
799 if (!InBBS || | |
800 !Tracker->hasLiveIncomingEdge(PN, InBB)) | |
801 continue; // Skip dead block or dead edge. | |
802 | |
620 const Value *InValue = PN->getIncomingValue(i); | 803 const Value *InValue = PN->getIncomingValue(i); |
621 | 804 |
622 if (isNotExclusivelyConstantDerived(InValue) && | 805 if (isNotExclusivelyConstantDerived(InValue) && |
623 !Tracker->getBasicBlockState(InBB)->AvailableOut.count(InValue)) | 806 !InBBS->AvailableOut.count(InValue)) |
624 reportInvalidUse(*InValue, *PN); | 807 reportInvalidUse(*InValue, *PN); |
625 } | 808 } |
626 } else if (isa<CmpInst>(I) && | 809 } else if (isa<CmpInst>(I) && |
627 containsGCPtrType(I.getOperand(0)->getType())) { | 810 containsGCPtrType(I.getOperand(0)->getType())) { |
628 Value *LHS = I.getOperand(0), *RHS = I.getOperand(1); | 811 Value *LHS = I.getOperand(0), *RHS = I.getOperand(1); |
695 if (!PrintOnly) | 878 if (!PrintOnly) |
696 abort(); | 879 abort(); |
697 AnyInvalidUses = true; | 880 AnyInvalidUses = true; |
698 } | 881 } |
699 | 882 |
700 static void Verify(const Function &F, const DominatorTree &DT) { | 883 static void Verify(const Function &F, const DominatorTree &DT, |
701 DEBUG(dbgs() << "Verifying gc pointers in function: " << F.getName() << "\n"); | 884 const CFGDeadness &CD) { |
885 LLVM_DEBUG(dbgs() << "Verifying gc pointers in function: " << F.getName() | |
886 << "\n"); | |
702 if (PrintOnly) | 887 if (PrintOnly) |
703 dbgs() << "Verifying gc pointers in function: " << F.getName() << "\n"; | 888 dbgs() << "Verifying gc pointers in function: " << F.getName() << "\n"; |
704 | 889 |
705 GCPtrTracker Tracker(F, DT); | 890 GCPtrTracker Tracker(F, DT, CD); |
706 | 891 |
707 // We now have all the information we need to decide if the use of a heap | 892 // We now have all the information we need to decide if the use of a heap |
708 // reference is legal or not, given our safepoint semantics. | 893 // reference is legal or not, given our safepoint semantics. |
709 | 894 |
710 InstructionVerifier Verifier; | 895 InstructionVerifier Verifier; |