diff --git a/SwiftCompilerSources/Sources/Optimizer/FunctionPasses/LetPropertyLowering.swift b/SwiftCompilerSources/Sources/Optimizer/FunctionPasses/LetPropertyLowering.swift index 65142837b4d56..ad456de533ef8 100644 --- a/SwiftCompilerSources/Sources/Optimizer/FunctionPasses/LetPropertyLowering.swift +++ b/SwiftCompilerSources/Sources/Optimizer/FunctionPasses/LetPropertyLowering.swift @@ -122,6 +122,8 @@ private func insertEndInitInstructions( use.set(to: ssaUpdater.getValue(atEndOf: use.instruction.parentBlock), context) } } + // This peephole optimization is required to avoid ownership errors. + replacePhisWithIncomingValues(phis: ssaUpdater.insertedPhis, context) } private func constructLetInitRegion( diff --git a/SwiftCompilerSources/Sources/Optimizer/Utilities/SSAUpdater.swift b/SwiftCompilerSources/Sources/Optimizer/Utilities/SSAUpdater.swift index 7b1d0f88c4d28..60e2803d34ac0 100644 --- a/SwiftCompilerSources/Sources/Optimizer/Utilities/SSAUpdater.swift +++ b/SwiftCompilerSources/Sources/Optimizer/Utilities/SSAUpdater.swift @@ -50,4 +50,14 @@ struct SSAUpdater { context.notifyInstructionsChanged() return context._bridged.SSAUpdater_getValueInMiddleOfBlock(block.bridged).value } + + var insertedPhis: [Phi] { + var phis = [Phi]() + let numPhis = context._bridged.SSAUpdater_getNumInsertedPhis() + phis.reserveCapacity(numPhis) + for idx in 0..getSSAUpdater()->getValueInMiddleOfBlock(block.unbridged())}; } +SwiftInt BridgedPassContext::SSAUpdater_getNumInsertedPhis() const { + return (SwiftInt)invocation->getInsertedPhisBySSAUpdater().size(); +} + +BridgedValue BridgedPassContext::SSAUpdater_getInsertedPhi(SwiftInt idx) const { + return {invocation->getInsertedPhisBySSAUpdater()[idx]}; +} + bool BridgedPassContext::enableStackProtection() const { swift::SILModule *mod = invocation->getPassManager()->getModule(); return mod->getOptions().EnableStackProtection; diff --git a/include/swift/SILOptimizer/PassManager/PassManager.h b/include/swift/SILOptimizer/PassManager/PassManager.h index 734a2456f45f9..b46f47ba662bd 100644 --- a/include/swift/SILOptimizer/PassManager/PassManager.h +++ b/include/swift/SILOptimizer/PassManager/PassManager.h @@ -75,6 +75,7 @@ class SwiftPassInvocation { SILModule::SlabList allocatedSlabs; SILSSAUpdater *ssaUpdater = nullptr; + SmallVector insertedPhisBySSAUpdater; SwiftPassInvocation *nestedSwiftPassInvocation = nullptr; @@ -178,8 +179,9 @@ class SwiftPassInvocation { void initializeSSAUpdater(SILFunction *fn, SILType type, ValueOwnershipKind ownership) { + insertedPhisBySSAUpdater.clear(); if (!ssaUpdater) - ssaUpdater = new SILSSAUpdater; + ssaUpdater = new SILSSAUpdater(&insertedPhisBySSAUpdater); ssaUpdater->initialize(fn, type, ownership); } @@ -188,6 +190,8 @@ class SwiftPassInvocation { return ssaUpdater; } + ArrayRef getInsertedPhisBySSAUpdater() { return insertedPhisBySSAUpdater; } + SwiftPassInvocation *initializeNestedSwiftPassInvocation(SILFunction *newFunction) { assert(!nestedSwiftPassInvocation && "Nested Swift pass invocation already initialized"); nestedSwiftPassInvocation = new SwiftPassInvocation(passManager, transform, newFunction); diff --git a/lib/SILOptimizer/PassManager/PassManager.cpp b/lib/SILOptimizer/PassManager/PassManager.cpp index f01e663412e92..c97a777353772 100644 --- a/lib/SILOptimizer/PassManager/PassManager.cpp +++ b/lib/SILOptimizer/PassManager/PassManager.cpp @@ -1562,6 +1562,7 @@ irgen::IRGenModule *SwiftPassInvocation::getIRGenModule() { } void SwiftPassInvocation::endPass() { + insertedPhisBySSAUpdater.clear(); assert(allocatedSlabs.empty() && "StackList is leaking slabs"); assert(numBlockSetsAllocated == 0 && "Not all BasicBlockSets deallocated"); assert(numNodeSetsAllocated == 0 && "Not all NodeSets deallocated"); diff --git a/test/SILOptimizer/let-property-lowering.sil b/test/SILOptimizer/let-property-lowering.sil index f0f37107ead50..01fb24cc872f8 100644 --- a/test/SILOptimizer/let-property-lowering.sil +++ b/test/SILOptimizer/let-property-lowering.sil @@ -311,3 +311,34 @@ bb1(%3a : @reborrow $C): return %2 : $C } + +// CHECK-LABEL: sil [ossa] @test_no_phis : +// CHECK: %3 = end_init_let_ref %2 +// CHECK: return %3 +// CHECK: } // end sil function 'test_no_phis' +sil [ossa] @test_no_phis : $@convention(thin) (Int, @owned C) -> @owned C { +bb0(%0 : $Int, %1 : @owned $C): + %2 = mark_uninitialized [rootself] %1 + %3 = begin_borrow %2 + cond_br undef, bb1, bb2 +bb1: + br bb7 +bb2: + cond_br undef, bb3, bb8 +bb3: + cond_br undef, bb4, bb5 +bb4: + br bb7 +bb5: + br bb6 +bb6: + end_borrow %3 + return %2 +bb7: + br bb6 +bb8: + end_borrow %3 + destroy_value [dead_end] %2 + unreachable +} +