Skip to content

Commit 6aa07ff

Browse files
authored
Merge pull request swiftlang#72777 from atrick/fix-lifedep-throw
LifetimeDependence: handle dependent values in throwing calls.
2 parents a81259e + 581010d commit 6aa07ff

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
@@ -8679,6 +8679,11 @@ class DestroyValueInst
86798679
}
86808680

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

87558760
DropDeinitInst(SILDebugLocation DebugLoc, SILValue operand)
8756-
: UnaryInstructionBase(DebugLoc, operand, operand->getType()) {}
8761+
: UnaryInstructionBase(DebugLoc, operand, operand->getType(),
8762+
OwnershipKind::Owned) {}
87578763
};
87588764

87598765
/// Equivalent to a copy_addr to [init] except that it is used for diagnostics
@@ -11134,6 +11140,7 @@ OwnershipForwardingSingleValueInstruction::classof(SILInstructionKind kind) {
1113411140
case SILInstructionKind::ThinToThickFunctionInst:
1113511141
case SILInstructionKind::UnconditionalCheckedCastInst:
1113611142
case SILInstructionKind::FunctionExtractIsolationInst:
11143+
case SILInstructionKind::DropDeinitInst:
1113711144
return true;
1113811145
default:
1113911146
return false;

lib/SIL/IR/SILInstruction.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1885,6 +1885,10 @@ bool MarkDependenceInst::visitNonEscapingLifetimeEnds(
18851885
return !noUsers;
18861886
}
18871887

1888+
bool DestroyValueInst::isFullDeinitialization() {
1889+
return !isa<DropDeinitInst>(lookThroughOwnershipInsts(getOperand()));
1890+
}
1891+
18881892
PartialApplyInst *
18891893
DestroyValueInst::getNonescapingClosureAllocation() const {
18901894
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)