diff --git a/include/swift/SILOptimizer/Analysis/RegionAnalysis.h b/include/swift/SILOptimizer/Analysis/RegionAnalysis.h index fb4154383ac9e..9a5c41dc5199a 100644 --- a/include/swift/SILOptimizer/Analysis/RegionAnalysis.h +++ b/include/swift/SILOptimizer/Analysis/RegionAnalysis.h @@ -61,6 +61,12 @@ class BlockPartitionState { /// Set if this block in the next iteration needs to be visited. bool needsUpdate = false; + /// Set if this block is live. + /// + /// If the block is not live, then we shouldnt try to emit diagnostics for it + /// since we will not have performed dataflow upon it. + bool isLive = false; + /// The partition of elements into regions at the top of the block. Partition entryPartition; @@ -81,6 +87,8 @@ class BlockPartitionState { TransferringOperandSetFactory &ptrSetFactory); public: + bool getLiveness() const { return isLive; } + ArrayRef getPartitionOps() const { return blockPartitionOps; } const Partition &getEntryPartition() const { return entryPartition; } diff --git a/lib/SILOptimizer/Analysis/RegionAnalysis.cpp b/lib/SILOptimizer/Analysis/RegionAnalysis.cpp index 66758a1f52e89..f2944048c340c 100644 --- a/lib/SILOptimizer/Analysis/RegionAnalysis.cpp +++ b/lib/SILOptimizer/Analysis/RegionAnalysis.cpp @@ -3057,6 +3057,7 @@ void RegionAnalysisFunctionInfo::runDataflow() { for (auto *block : pofi->getReversePostOrder()) { auto &blockState = (*blockStates)[block]; + blockState.isLive = true; LLVM_DEBUG(llvm::dbgs() << "Block: bb" << block->getDebugID() << "\n"); if (!blockState.needsUpdate) { diff --git a/lib/SILOptimizer/Mandatory/TransferNonSendable.cpp b/lib/SILOptimizer/Mandatory/TransferNonSendable.cpp index 55487212ede45..a657ea17a0678 100644 --- a/lib/SILOptimizer/Mandatory/TransferNonSendable.cpp +++ b/lib/SILOptimizer/Mandatory/TransferNonSendable.cpp @@ -1324,6 +1324,12 @@ void TransferNonSendableImpl::runDiagnosticEvaluator() { LLVM_DEBUG(llvm::dbgs() << "Walking blocks for diagnostics.\n"); for (auto [block, blockState] : regionInfo->getRange()) { LLVM_DEBUG(llvm::dbgs() << "|--> Block bb" << block.getDebugID() << "\n"); + + if (!blockState.getLiveness()) { + LLVM_DEBUG(llvm::dbgs() << "Dead block... skipping!\n"); + continue; + } + LLVM_DEBUG(llvm::dbgs() << "Entry Partition: "; blockState.getEntryPartition().print(llvm::dbgs())); diff --git a/test/Concurrency/transfernonsendable.sil b/test/Concurrency/transfernonsendable.sil index d60551f1ce2e3..dd84c4c927b39 100644 --- a/test/Concurrency/transfernonsendable.sil +++ b/test/Concurrency/transfernonsendable.sil @@ -174,4 +174,28 @@ bb0: dealloc_stack %2 : $*NonSendableKlass %19 = tuple () return %19 : $() -} \ No newline at end of file +} + +// Dead block crasher +// +// We used to crash here since we attempted to process /all/ blocks for +// diagnostic even for non-dead blocks. This is a problem since the dataflow +// uses a reverse post order traversal to get quick convergence and that skips +// dead blocks. +sil [ossa] @dead_block_crasher : $@convention(thin) @async () -> () { +bb0: + %0 = function_ref @constructNonSendableKlass : $@convention(thin) () -> @owned NonSendableKlass + %1 = apply %0() : $@convention(thin) () -> @owned NonSendableKlass + br bb1 + +bbDeadBlock: + %transfer = function_ref @transferNonSendableKlass : $@convention(thin) @async (@guaranteed NonSendableKlass) -> () + apply [caller_isolation=nonisolated] [callee_isolation=global_actor] %transfer(%1) : $@convention(thin) @async (@guaranteed NonSendableKlass) -> () + br bb1 + +bb1: + destroy_value %1 : $NonSendableKlass + %9999 = tuple () + return %9999 : $() +} +