SILCombine: don't sink forwarding instructions with address operands

We don't do memory lifetime analysis for this peephole optimization.
Therefore we can't risk sinking instructions with address operands out of the addressed memory's lifetime.

For example:
```
  %3 = mark_dependence %2 on %1 : $*T  // must not be moved after the destroy_addr
  destroy_addr %1
```

Fixes a verifier crash
rdar://166240751
This commit is contained in:
Erik Eckstein
2025-12-12 16:11:13 +01:00
parent f82cf1ebfb
commit aa4e77a46c
2 changed files with 37 additions and 0 deletions

View File

@@ -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<SingleValueInstruction>(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

View File

@@ -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
}