Skip to content

Commit 00dac23

Browse files
authored
Merge pull request swiftlang#72839 from atrick/60-fix-lifedep-throw
[6.0] LifetimeDependence: handle dependent values in throwing calls.
2 parents 5d7ae8a + 2e3e85d commit 00dac23

File tree

13 files changed

+137
-24
lines changed

13 files changed

+137
-24
lines changed

SwiftCompilerSources/Sources/Optimizer/DataStructures/InstructionRange.swift

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -64,10 +64,8 @@ struct InstructionRange : CustomStringConvertible, NoReflectionChildren {
6464
}
6565

6666
static func beginningInstruction(for value: Value) -> Instruction {
67-
if let def = value.definingInstruction {
67+
if let def = value.definingInstructionOrTerminator {
6868
return def
69-
} else if let result = TerminatorResult(value) {
70-
return result.terminator
7169
}
7270
assert(Phi(value) != nil || value is FunctionArgument)
7371
return value.parentBlock.instructions.first!

SwiftCompilerSources/Sources/Optimizer/FunctionPasses/LifetimeDependenceInsertion.swift

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -105,15 +105,13 @@ extension LifetimeDependentApply {
105105
/// dependent value within each scope.
106106
private func insertDependencies(for apply: LifetimeDependentApply,
107107
_ context: FunctionPassContext ) {
108-
precondition(apply.applySite.results.count > 0,
109-
"a lifetime-dependent instruction must have at least one result")
110-
111108
let bases = findDependenceBases(of: apply, context)
112-
let builder = Builder(after: apply.applySite, context)
113109
for dependentValue in apply.applySite.resultOrYields {
110+
let builder = Builder(before: dependentValue.nextInstruction, context)
114111
insertMarkDependencies(value: dependentValue, initializer: nil,
115112
bases: bases, builder: builder, context)
116113
}
114+
let builder = Builder(after: apply.applySite, context)
117115
for resultOper in apply.applySite.indirectResultOperands {
118116
let accessBase = resultOper.value.accessBase
119117
guard let (initialAddress, initializingStore) =

SwiftCompilerSources/Sources/Optimizer/Utilities/LifetimeDependenceUtils.swift

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -222,7 +222,7 @@ extension LifetimeDependence {
222222
if value.isEscapable {
223223
return nil
224224
}
225-
if (value.definingInstruction as! FullApplySite).hasResultDependence {
225+
if (value.definingInstructionOrTerminator as! FullApplySite).hasResultDependence {
226226
return nil
227227
}
228228
assert(value.ownership == .owned, "apply result must be owned")
@@ -766,11 +766,12 @@ extension LifetimeDependenceUseDefWalker {
766766

767767
/// Walk down dependent values.
768768
///
769-
/// Delegates value def-use walking to the ForwardingUseDefWalker and
770-
/// overrides copy, move, borrow, and mark_dependence.
769+
/// First classifies all values using OwnershipUseVisitor. Delegates forwarding uses to the ForwardingUseDefWalker.
770+
/// Transitively follows OwnershipTransitionInstructions (copy, move, borrow, and mark_dependence). Transitively
771+
/// follows interior pointers using AddressUseVisitor. Handles stores to and loads from local variables using
772+
/// LocalVariableReachabilityCache.
771773
///
772-
/// Ignores trivial values (~Escapable types are never
773-
/// trivial. Escapable types may only be lifetime-depenent values if
774+
/// Ignores trivial values (~Escapable types are never trivial. Escapable types may only be lifetime-depenent values if
774775
/// they are non-trivial).
775776
///
776777
/// Skips uses within nested borrow scopes.

SwiftCompilerSources/Sources/SIL/ForwardingInstruction.swift

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -66,12 +66,9 @@ extension Value {
6666
// If this value is produced by a ForwardingInstruction, return that instruction. This is convenient for following the forwarded value chain.
6767
// Unlike definingInstruction, a value's forwardingInstruction is not necessarily a valid insertion point.
6868
public var forwardingInstruction: ForwardingInstruction? {
69-
if let inst = definingInstruction {
69+
if let inst = definingInstructionOrTerminator {
7070
return inst as? ForwardingInstruction
7171
}
72-
if let termResult = TerminatorResult(self) {
73-
return termResult.terminator as? ForwardingInstruction
74-
}
7572
return nil
7673
}
7774
}
@@ -319,6 +316,12 @@ extension UncheckedValueCastInst : ConversionInstruction {
319316
public var canForwardOwnedValues: Bool { true }
320317
}
321318

319+
extension DropDeinitInst : ConversionInstruction {
320+
public var preservesRepresentation: Bool { true }
321+
public var canForwardGuaranteedValues: Bool { false }
322+
public var canForwardOwnedValues: Bool { true }
323+
}
324+
322325
// -----------------------------------------------------------------------------
323326
// other forwarding instructions
324327

SwiftCompilerSources/Sources/SIL/Value.swift

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,15 @@ extension Value {
138138
}
139139
}
140140

141+
public var definingInstructionOrTerminator: Instruction? {
142+
if let def = definingInstruction {
143+
return def
144+
} else if let result = TerminatorResult(self) {
145+
return result.terminator
146+
}
147+
return nil
148+
}
149+
141150
public var nextInstruction: Instruction {
142151
if self is Argument {
143152
return parentBlock.instructions.first!

include/swift/SIL/InstWrappers.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,7 @@ struct ConversionOperation {
140140
case SILInstructionKind::CopyableToMoveOnlyWrapperValueInst:
141141
case SILInstructionKind::MoveOnlyWrapperToCopyableValueInst:
142142
case SILInstructionKind::MoveOnlyWrapperToCopyableBoxInst:
143+
case SILInstructionKind::DropDeinitInst:
143144
return true;
144145
default:
145146
return false;

include/swift/SIL/SILInstruction.h

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8678,6 +8678,11 @@ class DestroyValueInst
86788678
}
86798679

86808680
public:
8681+
/// True if this destroy fully deinitializes the type by invoking the
8682+
/// user-defined deinitializer if present. This returns false if a prior
8683+
/// drop_deinit is present.
8684+
bool isFullDeinitialization();
8685+
86818686
/// If true, then all references within the destroyed value will be
86828687
/// overwritten with a sentinel. This is used in debug builds when shortening
86838688
/// non-trivial value lifetimes to ensure the debugger cannot inspect invalid
@@ -8748,11 +8753,12 @@ class MoveValueInst
87488753
/// for details. See SILVerifier.cpp for constraints on valid uses.
87498754
class DropDeinitInst
87508755
: public UnaryInstructionBase<SILInstructionKind::DropDeinitInst,
8751-
SingleValueInstruction> {
8756+
OwnershipForwardingSingleValueInstruction> {
87528757
friend class SILBuilder;
87538758

87548759
DropDeinitInst(SILDebugLocation DebugLoc, SILValue operand)
8755-
: UnaryInstructionBase(DebugLoc, operand, operand->getType()) {}
8760+
: UnaryInstructionBase(DebugLoc, operand, operand->getType(),
8761+
OwnershipKind::Owned) {}
87568762
};
87578763

87588764
/// Equivalent to a copy_addr to [init] except that it is used for diagnostics
@@ -11133,6 +11139,7 @@ OwnershipForwardingSingleValueInstruction::classof(SILInstructionKind kind) {
1113311139
case SILInstructionKind::ThinToThickFunctionInst:
1113411140
case SILInstructionKind::UnconditionalCheckedCastInst:
1113511141
case SILInstructionKind::FunctionExtractIsolationInst:
11142+
case SILInstructionKind::DropDeinitInst:
1113611143
return true;
1113711144
default:
1113811145
return false;

lib/SIL/IR/SILInstruction.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1882,6 +1882,10 @@ bool MarkDependenceInst::visitNonEscapingLifetimeEnds(
18821882
return !noUsers;
18831883
}
18841884

1885+
bool DestroyValueInst::isFullDeinitialization() {
1886+
return !isa<DropDeinitInst>(lookThroughOwnershipInsts(getOperand()));
1887+
}
1888+
18851889
PartialApplyInst *
18861890
DestroyValueInst::getNonescapingClosureAllocation() const {
18871891
SILValue operand = getOperand();

lib/SILOptimizer/Utils/CanonicalizeInstruction.cpp

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -547,10 +547,13 @@ static SILBasicBlock::iterator
547547
eliminateUnneededForwardingUnarySingleValueInst(SingleValueInstruction *inst,
548548
CanonicalizeInstruction &pass) {
549549
auto next = std::next(inst->getIterator());
550-
551-
for (auto *use : getNonDebugUses(inst))
552-
if (!isa<DestroyValueInst>(use->getUser()))
553-
return next;
550+
for (auto *use : getNonDebugUses(inst)) {
551+
if (auto *destroy = dyn_cast<DestroyValueInst>(use->getUser())) {
552+
if (destroy->isFullDeinitialization())
553+
continue;
554+
}
555+
return next;
556+
}
554557
deleteAllDebugUses(inst, pass.callbacks);
555558
SILValue op = inst->getOperand(0);
556559
inst->replaceAllUsesWith(op);

test/SILOptimizer/lifetime_dependence_diagnostics.swift

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,3 +80,19 @@ func bv_borrow_borrow(bv: borrowing BV) -> dependsOn(scoped bv) BV {
8080
func ncint_capture(ncInt: inout NCInt) {
8181
takeClosure { _ = ncInt.i }
8282
}
83+
84+
func neint_throws(ncInt: borrowing NCInt) throws -> NEInt {
85+
return NEInt(owner: ncInt)
86+
}
87+
88+
// CHECK-LABEL: sil hidden @$s4test9neint_try5ncIntAA5NEIntVAA5NCIntVYls_tKF : $@convention(thin) (@guaranteed NCInt) -> _scope(1) (@owned NEInt, @error any Error) {
89+
// CHECK: try_apply %{{.*}}(%0) : $@convention(thin) (@guaranteed NCInt) -> _scope(1) (@owned NEInt, @error any Error), normal bb1, error bb2
90+
// CHECK: bb1([[R:%.*]] : $NEInt):
91+
// CHECK: [[MD:%.*]] = mark_dependence [nonescaping] %5 : $NEInt on %0 : $NCInt
92+
// CHECK: return [[MD]] : $NEInt
93+
// CHECK: bb2([[E:%.*]] : $any Error):
94+
// CHECK: throw [[E]] : $any Error
95+
// CHECK-LABEL: } // end sil function '$s4test9neint_try5ncIntAA5NEIntVAA5NCIntVYls_tKF'
96+
func neint_try(ncInt: borrowing NCInt) throws -> NEInt {
97+
try neint_throws(ncInt: ncInt)
98+
}

0 commit comments

Comments
 (0)