Skip to content

Commit 6f310f1

Browse files
authored
Merge pull request #71280 from meg-gupta/scopefixup
Add LifetimeDependenceScopeFixup pass
2 parents 4112618 + 75bd5b0 commit 6f310f1

File tree

12 files changed

+317
-5
lines changed

12 files changed

+317
-5
lines changed

SwiftCompilerSources/Sources/Optimizer/FunctionPasses/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ swift_compiler_sources(Optimizer
2020
LetPropertyLowering.swift
2121
LifetimeDependenceDiagnostics.swift
2222
LifetimeDependenceInsertion.swift
23+
LifetimeDependenceScopeFixup.swift
2324
ObjectOutliner.swift
2425
ObjCBridgingOptimization.swift
2526
MergeCondFails.swift
Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
//===--- LifetimeDependenceScopeFixup.swift ----------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2023 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===---------------------------------------------------------------------===//
12+
13+
// For an apply that returns a lifetime dependent value,
14+
// LifetimeDependenceInsertion inserts mark_dependence [unresolved] on parent
15+
// value's access scope. LifetimeDependenceScopeFixup then extends the access
16+
// scope to cover all uses of the dependent value.
17+
18+
// This pass must run after LifetimeDependenceInsertion and before
19+
// LifetimeDependenceDiagnostics.
20+
21+
import SIL
22+
23+
private let verbose = false
24+
25+
private func log(_ message: @autoclosure () -> String) {
26+
if verbose {
27+
print("### \(message())")
28+
}
29+
}
30+
31+
let lifetimeDependenceScopeFixupPass = FunctionPass(
32+
name: "lifetime-dependence-scope-fixup")
33+
{ (function: Function, context: FunctionPassContext) in
34+
log("Scope fixup for lifetime dependence in \(function.name)")
35+
36+
for instruction in function.instructions {
37+
guard let markDep = instruction as? MarkDependenceInst else {
38+
continue
39+
}
40+
if let lifetimeDep = LifetimeDependence(markDep, context) {
41+
fixup(dependence: lifetimeDep, context)
42+
}
43+
}
44+
}
45+
46+
private func fixup(dependence: LifetimeDependence,
47+
_ context: FunctionPassContext) {
48+
log("Scope fixup for lifetime dependent instructions: \(dependence)")
49+
50+
guard case .access(let bai) = dependence.scope else {
51+
return
52+
}
53+
var range = InstructionRange(begin: bai, context)
54+
var walker = LifetimeDependenceScopeFixupWalker(bai.parentFunction, context) {
55+
range.insert($0.instruction)
56+
return .continueWalk
57+
}
58+
defer {walker.deinitialize()}
59+
_ = walker.walkDown(root: dependence.dependentValue)
60+
defer {range.deinitialize()}
61+
62+
var beginAccess = bai
63+
while (true) {
64+
var endAcceses = [Instruction]()
65+
// Collect original end_access instructions
66+
for end in beginAccess.endInstructions {
67+
endAcceses.append(end)
68+
}
69+
70+
// Insert original end_access instructions to prevent access scope shortening
71+
range.insert(contentsOf: endAcceses)
72+
assert(!range.ends.isEmpty)
73+
74+
// Create new end_access at the end of extended uses
75+
for end in range.ends {
76+
let endBuilder = Builder(after: end, context)
77+
_ = endBuilder.createEndAccess(beginAccess: beginAccess)
78+
}
79+
80+
// Delete original end_access instructions
81+
for endAccess in endAcceses {
82+
context.erase(instruction: endAccess)
83+
}
84+
85+
// TODO: Add SIL support for lifetime dependence and write unit test
86+
// for nested access scopes
87+
guard case let .scope(enclosingBeginAccess) = beginAccess.address.enclosingAccessScope else {
88+
break
89+
}
90+
beginAccess = enclosingBeginAccess
91+
}
92+
}
93+
94+
private struct LifetimeDependenceScopeFixupWalker : LifetimeDependenceDefUseWalker {
95+
let function: Function
96+
let context: Context
97+
let visitor: (Operand) -> WalkResult
98+
var visitedValues: ValueSet
99+
100+
init(_ function: Function, _ context: Context, visitor: @escaping (Operand) -> WalkResult) {
101+
self.function = function
102+
self.context = context
103+
self.visitor = visitor
104+
self.visitedValues = ValueSet(context)
105+
}
106+
107+
mutating func deinitialize() {
108+
visitedValues.deinitialize()
109+
}
110+
111+
mutating func needWalk(for value: Value) -> Bool {
112+
visitedValues.insert(value)
113+
}
114+
115+
mutating func deadValue(_ value: Value, using operand: Operand?)
116+
-> WalkResult {
117+
if let operand {
118+
return visitor(operand)
119+
}
120+
return .continueWalk
121+
}
122+
123+
mutating func leafUse(of operand: Operand) -> WalkResult {
124+
return visitor(operand)
125+
}
126+
127+
mutating func escapingDependence(on operand: Operand) -> WalkResult {
128+
_ = visitor(operand)
129+
return .abortWalk
130+
}
131+
132+
mutating func returnedDependence(result: Operand) -> WalkResult {
133+
return .continueWalk
134+
}
135+
136+
mutating func returnedDependence(address: FunctionArgument,
137+
using operand: Operand) -> WalkResult {
138+
return .continueWalk
139+
}
140+
}
141+

SwiftCompilerSources/Sources/Optimizer/PassManager/PassRegistration.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ private func registerSwiftPasses() {
9191
registerPass(deinitDevirtualizer, { deinitDevirtualizer.run($0) })
9292
registerPass(lifetimeDependenceDiagnosticsPass, { lifetimeDependenceDiagnosticsPass.run($0) })
9393
registerPass(lifetimeDependenceInsertionPass, { lifetimeDependenceInsertionPass.run($0) })
94-
94+
registerPass(lifetimeDependenceScopeFixupPass, { lifetimeDependenceScopeFixupPass.run($0) })
9595
// Instruction passes
9696
registerForSILCombine(BeginCOWMutationInst.self, { run(BeginCOWMutationInst.self, $0) })
9797
registerForSILCombine(GlobalValueInst.self, { run(GlobalValueInst.self, $0) })

SwiftCompilerSources/Sources/SIL/Builder.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -419,4 +419,9 @@ public struct Builder {
419419
BridgedInstruction.MarkDependenceKind(rawValue: kind.rawValue)!)
420420
return notifyNew(markDependence.getAs(MarkDependenceInst.self))
421421
}
422+
423+
public func createEndAccess(beginAccess: BeginAccessInst) -> EndAccessInst {
424+
let endAccess = bridged.createEndAccess(beginAccess.bridged)
425+
return notifyNew(endAccess.getAs(EndAccessInst.self))
426+
}
422427
}

include/swift/SIL/SILBridging.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1227,6 +1227,8 @@ struct BridgedBuilder{
12271227
bool keepUnique) const;
12281228
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedInstruction createMarkDependence(
12291229
BridgedValue value, BridgedValue base, BridgedInstruction::MarkDependenceKind dependenceKind) const;
1230+
1231+
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedInstruction createEndAccess(BridgedValue value) const;
12301232
};
12311233

12321234
// Passmanager and Context

include/swift/SIL/SILBridgingImpl.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1739,6 +1739,10 @@ BridgedInstruction BridgedBuilder::createMarkDependence(BridgedValue value, Brid
17391739
return {unbridged().createMarkDependence(regularLoc(), value.getSILValue(), base.getSILValue(), swift::MarkDependenceKind(kind))};
17401740
}
17411741

1742+
BridgedInstruction BridgedBuilder::createEndAccess(BridgedValue value) const {
1743+
return {unbridged().createEndAccess(regularLoc(), value.getSILValue(), false)};
1744+
}
1745+
17421746
SWIFT_END_NULLABILITY_ANNOTATIONS
17431747

17441748
#endif

include/swift/SILOptimizer/PassManager/Passes.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -290,6 +290,9 @@ SWIFT_FUNCTION_PASS(LifetimeDependenceDiagnostics,
290290
SWIFT_FUNCTION_PASS(LifetimeDependenceInsertion,
291291
"lifetime-dependence-insertion",
292292
"Insert Lifetime Dependence Markers")
293+
SWIFT_FUNCTION_PASS(LifetimeDependenceScopeFixup,
294+
"lifetime-dependence-scope-fixup",
295+
"Fixup scope for lifetime dependence")
293296
PASS(LoopCanonicalizer, "loop-canonicalizer",
294297
"Loop Canonicalization")
295298
PASS(LoopInfoPrinter, "loop-info-printer",

lib/SILOptimizer/PassManager/PassPipeline.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,9 @@ SILPassPipelinePlan::getSILGenPassPipeline(const SILOptions &Options) {
301301
if (EnableLifetimeDependenceDiagnostics || EnableLifetimeDependenceInsertion) {
302302
P.addLifetimeDependenceInsertion();
303303
}
304+
if (EnableLifetimeDependenceDiagnostics) {
305+
P.addLifetimeDependenceScopeFixup();
306+
}
304307
if (SILViewSILGenCFG) {
305308
addCFGPrinterPipeline(P, "SIL View SILGen CFG");
306309
}

test/SIL/implicit_lifetime_dependence.swift

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@ struct MutableBufferView : ~Escapable, ~Copyable {
3434
}
3535
}
3636

37-
/*
3837
// rdar://121983770
3938
func testBasic() {
4039
let capacity = 4
@@ -46,7 +45,6 @@ func testBasic() {
4645
use(newView)
4746
}
4847
}
49-
*/
5048

5149
// CHECK-LABEL: sil hidden @$s28implicit_lifetime_dependence6deriveyAA10BufferViewVADF : $@convention(thin) (@guaranteed BufferView) -> _scope(1) @owned BufferView {
5250
func derive(_ x: borrowing BufferView) -> BufferView {

test/SILOptimizer/lifetime_dependence_borrow_fail.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@
55
// RUN: -module-name test \
66
// RUN: -disable-experimental-parser-round-trip \
77
// RUN: -enable-experimental-feature NonescapableTypes \
8-
// RUN: -Xllvm -enable-lifetime-dependence-diagnostics
8+
// RUN: -Xllvm -enable-lifetime-dependence-diagnostics \
9+
// RUN: -enable-experimental-lifetime-dependence-inference
910

1011
// REQUIRES: swift_in_compiler
1112

0 commit comments

Comments
 (0)