diff --git a/lib/SILOptimizer/SILCombiner/SILCombine.cpp b/lib/SILOptimizer/SILCombiner/SILCombine.cpp index 51eab585e2770..8669e569b9ad8 100644 --- a/lib/SILOptimizer/SILCombiner/SILCombine.cpp +++ b/lib/SILOptimizer/SILCombiner/SILCombine.cpp @@ -429,6 +429,14 @@ bool SILCombiner::doOneIteration(SILFunction &F, unsigned Iteration) { return MadeChange; } +static bool hasAddressOperands(SILInstruction *inst) { + for (Operand *op : inst->getRealOperands()) { + if (op->get()->getType().isAddress()) + return true; + } + return false; +} + void SILCombiner::processInstruction(SILInstruction *I, SILCombineCanonicalize &scCanonicalize, bool &MadeChange) { @@ -467,6 +475,15 @@ void SILCombiner::processInstruction(SILInstruction *I, if (auto *svi = dyn_cast(I)) { if (auto fwdOp = ForwardingOperation(svi)) { if (fwdOp.getSingleForwardingOperand() && + + // Don't risk sinking instructions with address operands out of the + // addressed memory's lifetime. E.g: + // ``` + // %3 = mark_dependence %2 on %1 : $*T // must not be moved after the destroy_addr + // destroy_addr %1 + // ``` + !hasAddressOperands(svi) && + SILValue(svi)->getOwnershipKind() == OwnershipKind::Owned) { // Try to sink the value. If we sank the value and deleted it, // return. If we didn't optimize or sank but we are still able to diff --git a/test/SILOptimizer/sil_combine_ossa.sil b/test/SILOptimizer/sil_combine_ossa.sil index d2d07af89bb97..5f3c2b82e89b2 100644 --- a/test/SILOptimizer/sil_combine_ossa.sil +++ b/test/SILOptimizer/sil_combine_ossa.sil @@ -5577,4 +5577,24 @@ bb0(%0 : @guaranteed $String): return %1 } +// CHECK-LABEL: sil [ossa] @dont_sink_mark_dependence_out_of_memory_lifetime : +// CHECK: mark_dependence +// CHECK: bb1: +// CHECK: } // end sil function 'dont_sink_mark_dependence_out_of_memory_lifetime' +sil [ossa] @dont_sink_mark_dependence_out_of_memory_lifetime : $@convention(thin) (@owned Klass, @owned Klass) -> () { +bb0(%0 : @owned $Klass, %1 : @owned $Klass): + %2 = alloc_stack $Klass + store %1 to [init] %2 + %4 = mark_dependence %0 on %2 + destroy_addr %2 + br bb1 + +bb1: + destroy_value %4 + dealloc_stack %2 + %9 = tuple () + return %9 +} + +