Skip to content

Commit 72e63d7

Browse files
committed
Optimizer: simplify load_borrow
* Remove dead `load_borrow` instructions (replaces the old peephole optimization in SILCombine) * If the `load_borrow` is followed by a `copy_value`, combine both into a `load [copy]` Also, run the simplification of `begin_borrow` in SILCombine by adding it as SILCombine-pass.
1 parent 524eb01 commit 72e63d7

File tree

7 files changed

+148
-18
lines changed

7 files changed

+148
-18
lines changed

SwiftCompilerSources/Sources/Optimizer/InstructionSimplification/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
swift_compiler_sources(Optimizer
1010
SimplifyAllocRefDynamic.swift
1111
SimplifyApply.swift
12-
SimplifyBeginBorrow.swift
12+
SimplifyBeginAndLoadBorrow.swift
1313
SimplifyBeginCOWMutation.swift
1414
SimplifyBranch.swift
1515
SimplifyBuiltin.swift

SwiftCompilerSources/Sources/Optimizer/InstructionSimplification/SimplifyBeginBorrow.swift renamed to SwiftCompilerSources/Sources/Optimizer/InstructionSimplification/SimplifyBeginAndLoadBorrow.swift

Lines changed: 48 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//===--- SimplifyBeginBorrow.swift ----------------------------------------===//
1+
//===--- SimplifyBeginAndLoadBorrow.swift ---------------------------------===//
22
//
33
// This source file is part of the Swift.org open source project
44
//
@@ -12,7 +12,7 @@
1212

1313
import SIL
1414

15-
extension BeginBorrowInst : OnoneSimplifyable {
15+
extension BeginBorrowInst : OnoneSimplifyable, SILCombineSimplifyable {
1616
func simplify(_ context: SimplifyContext) {
1717
if borrowedValue.ownership == .owned,
1818
// We need to keep lexical lifetimes in place.
@@ -21,7 +21,52 @@ extension BeginBorrowInst : OnoneSimplifyable {
2121
!findPointerEscapingUse(of: borrowedValue)
2222
{
2323
tryReplaceBorrowWithOwnedOperand(beginBorrow: self, context)
24+
25+
} else if let thin2thickFn = borrowedValue as? ThinToThickFunctionInst,
26+
uses.filterUsers(ofType: BranchInst.self).isEmpty
27+
{
28+
uses.ignoreUsers(ofType: EndBorrowInst.self).replaceAll(with: thin2thickFn, context)
29+
context.erase(instructionIncludingAllUsers: self)
30+
}
31+
}
32+
}
33+
34+
extension LoadBorrowInst : Simplifyable, SILCombineSimplifyable {
35+
func simplify(_ context: SimplifyContext) {
36+
if uses.ignoreDebugUses.ignoreUsers(ofType: EndBorrowInst.self).isEmpty {
37+
context.erase(instructionIncludingAllUsers: self)
38+
return
2439
}
40+
41+
// If the load_borrow is followed by a copy_value, combine both into a `load [copy]`:
42+
// ```
43+
// %1 = load_borrow %0
44+
// %2 = some_forwarding_instruction %1 // zero or more forwarding instructions
45+
// %3 = copy_value %2
46+
// end_borrow %1
47+
// ```
48+
// ->
49+
// ```
50+
// %1 = load [copy] %0
51+
// %3 = some_forwarding_instruction %1 // zero or more forwarding instructions
52+
// ```
53+
//
54+
tryCombineWithCopy(context)
55+
}
56+
57+
private func tryCombineWithCopy(_ context: SimplifyContext) {
58+
let forwardedValue = lookThroughSingleForwardingUses()
59+
guard let singleUser = forwardedValue.uses.ignoreUsers(ofType: EndBorrowInst.self).singleUse?.instruction,
60+
let copy = singleUser as? CopyValueInst,
61+
copy.parentBlock == self.parentBlock else {
62+
return
63+
}
64+
let builder = Builder(before: self, context)
65+
let loadCopy = builder.createLoad(fromAddress: address, ownership: .copy)
66+
let forwardedOwnedValue = replace(guaranteedValue: self, withOwnedValue: loadCopy, context)
67+
copy.uses.replaceAll(with: forwardedOwnedValue, context)
68+
context.erase(instruction: copy)
69+
context.erase(instructionIncludingAllUsers: self)
2570
}
2671
}
2772

@@ -156,7 +201,7 @@ private extension ForwardingInstruction {
156201
}
157202

158203
/// Replaces a guaranteed value with an owned value.
159-
///
204+
///
160205
/// If the `guaranteedValue`'s use is a ForwardingInstruction (or forwarding instruction chain),
161206
/// it is converted to an owned version of the forwarding instruction (or instruction chain).
162207
///

SwiftCompilerSources/Sources/Optimizer/PassManager/PassRegistration.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,13 +100,15 @@ private func registerSwiftPasses() {
100100
registerPass(autodiffClosureSpecialization, { autodiffClosureSpecialization.run($0) })
101101

102102
// Instruction passes
103+
registerForSILCombine(BeginBorrowInst.self, { run(BeginBorrowInst.self, $0) })
103104
registerForSILCombine(BeginCOWMutationInst.self, { run(BeginCOWMutationInst.self, $0) })
104105
registerForSILCombine(GlobalValueInst.self, { run(GlobalValueInst.self, $0) })
105106
registerForSILCombine(StrongRetainInst.self, { run(StrongRetainInst.self, $0) })
106107
registerForSILCombine(StrongReleaseInst.self, { run(StrongReleaseInst.self, $0) })
107108
registerForSILCombine(RetainValueInst.self, { run(RetainValueInst.self, $0) })
108109
registerForSILCombine(ReleaseValueInst.self, { run(ReleaseValueInst.self, $0) })
109110
registerForSILCombine(LoadInst.self, { run(LoadInst.self, $0) })
111+
registerForSILCombine(LoadBorrowInst.self, { run(LoadBorrowInst.self, $0) })
110112
registerForSILCombine(CopyValueInst.self, { run(CopyValueInst.self, $0) })
111113
registerForSILCombine(DestroyValueInst.self, { run(DestroyValueInst.self, $0) })
112114
registerForSILCombine(DestructureStructInst.self, { run(DestructureStructInst.self, $0) })

include/swift/SILOptimizer/PassManager/Passes.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -516,6 +516,7 @@ PASS(PruneVTables, "prune-vtables",
516516
"Mark class methods that do not require vtable dispatch")
517517
PASS_RANGE(AllPasses, AliasInfoDumper, PruneVTables)
518518

519+
SWIFT_SILCOMBINE_PASS(BeginBorrowInst)
519520
SWIFT_SILCOMBINE_PASS(BeginCOWMutationInst)
520521
SWIFT_SILCOMBINE_PASS(ClassifyBridgeObjectInst)
521522
SWIFT_SILCOMBINE_PASS(GlobalValueInst)
@@ -524,6 +525,7 @@ SWIFT_SILCOMBINE_PASS(StrongReleaseInst)
524525
SWIFT_SILCOMBINE_PASS(RetainValueInst)
525526
SWIFT_SILCOMBINE_PASS(ReleaseValueInst)
526527
SWIFT_SILCOMBINE_PASS(LoadInst)
528+
SWIFT_SILCOMBINE_PASS(LoadBorrowInst)
527529
SWIFT_SILCOMBINE_PASS(CopyValueInst)
528530
SWIFT_SILCOMBINE_PASS(DestroyValueInst)
529531
SWIFT_SILCOMBINE_PASS(DestructureStructInst)

lib/SILOptimizer/SILCombiner/SILCombiner.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -252,7 +252,6 @@ class SILCombiner :
252252
// NOTE: The load optimized in this method is a load [trivial].
253253
SILInstruction *optimizeLoadFromStringLiteral(LoadInst *li);
254254

255-
SILInstruction *visitLoadBorrowInst(LoadBorrowInst *LI);
256255
SILInstruction *visitIndexAddrInst(IndexAddrInst *IA);
257256
bool optimizeStackAllocatedEnum(AllocStackInst *AS);
258257
SILInstruction *visitAllocStackInst(AllocStackInst *AS);

lib/SILOptimizer/SILCombiner/SILCombinerMiscVisitors.cpp

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -779,19 +779,6 @@ static SILValue isConstIndexAddr(SILValue val, unsigned &index) {
779779
return IA->getBase();
780780
}
781781

782-
SILInstruction *SILCombiner::visitLoadBorrowInst(LoadBorrowInst *lbi) {
783-
// If we have a load_borrow that only has non_debug end_borrow uses, delete
784-
// it.
785-
if (llvm::all_of(getNonDebugUses(lbi), [](Operand *use) {
786-
return isa<EndBorrowInst>(use->getUser());
787-
})) {
788-
eraseInstIncludingUsers(lbi);
789-
return nullptr;
790-
}
791-
792-
return nullptr;
793-
}
794-
795782
/// Optimize nested index_addr instructions:
796783
/// Example in SIL pseudo code:
797784
/// %1 = index_addr %ptr, x
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
// RUN: %target-sil-opt %s -simplification -simplify-instruction=load_borrow | %FileCheck %s
2+
3+
import Swift
4+
import Builtin
5+
6+
class B { }
7+
8+
class E : B {
9+
@_hasStorage var i: Int
10+
}
11+
12+
// CHECK-LABEL: sil [ossa] @load_borrow_and_copy :
13+
// CHECK: %1 = load [copy] %0
14+
// CHECK: %2 = begin_borrow %1
15+
// CHECK: %3 = ref_element_addr %2, #E.i
16+
// CHECK: %4 = load [trivial] %3
17+
// CHECK: end_borrow %2
18+
// CHECK: destroy_value %1
19+
// CHECK: return %4
20+
// CHEKCK } // end sil function '@load_borrow_and_copy'
21+
sil [ossa] @load_borrow_and_copy : $@convention(thin) (@inout E) -> Int {
22+
bb0(%0 : $*E):
23+
%1 = load_borrow %0
24+
%2 = copy_value %1
25+
end_borrow %1
26+
%4 = begin_borrow %2
27+
%5 = ref_element_addr %4, #E.i
28+
%6 = load [trivial] %5
29+
end_borrow %4
30+
destroy_value %2
31+
return %6
32+
}
33+
34+
// CHECK-LABEL: sil [ossa] @load_borrow_and_copy_forwarding :
35+
// CHECK: %1 = load [copy] %0
36+
// CHECK: %2 = unchecked_ref_cast %1 to $E
37+
// CHECK: %3 = begin_borrow %2
38+
// CHECK: %4 = ref_element_addr %3, #E.i
39+
// CHECK: %5 = load [trivial] %4
40+
// CHECK: end_borrow %3
41+
// CHECK: destroy_value %2
42+
// CHECK: return %5
43+
// CHEKCK } // end sil function '@load_borrow_and_copy_forwarding'
44+
sil [ossa] @load_borrow_and_copy_forwarding : $@convention(thin) (@inout B) -> Int {
45+
bb0(%0 : $*B):
46+
%1 = load_borrow %0
47+
%2 = unchecked_ref_cast %1 to $E
48+
%3 = copy_value %2
49+
end_borrow %1
50+
%5 = begin_borrow %3
51+
%6 = ref_element_addr %5, #E.i
52+
%7 = load [trivial] %6
53+
end_borrow %5
54+
destroy_value %3
55+
return %7
56+
}
57+
58+
// CHECK-LABEL: sil [ossa] @load_borrow_and_copy_different_block :
59+
// CHECK: %1 = load_borrow %0
60+
// CHECK: %3 = copy_value %1
61+
// CHEKCK } // end sil function '@load_borrow_and_copy_different_block'
62+
sil [ossa] @load_borrow_and_copy_different_block : $@convention(thin) (@inout E) -> () {
63+
bb0(%0 : $*E):
64+
%1 = load_borrow %0
65+
cond_br undef, bb1, bb2
66+
bb1:
67+
%3 = copy_value %1
68+
%4 = begin_borrow %3
69+
%5 = ref_element_addr %4, #E.i
70+
%6 = load [trivial] %5
71+
fix_lifetime %6
72+
end_borrow %4
73+
destroy_value %3
74+
br bb3
75+
bb2:
76+
br bb3
77+
bb3:
78+
end_borrow %1
79+
%r = tuple ()
80+
return %r
81+
}
82+
83+
// CHECK-LABEL: sil [ossa] @dead_load_borrow :
84+
// CHECK-NOT: load_borrow
85+
// CHECK: %1 = tuple ()
86+
// CHECK: return %1
87+
// CHEKCK } // end sil function '@dead_load_borrow'
88+
sil [ossa] @dead_load_borrow : $@convention(thin) (@inout B) -> () {
89+
bb0(%0 : $*B):
90+
%1 = load_borrow %0
91+
debug_value %1, var, name "x"
92+
end_borrow %1
93+
%4 = tuple ()
94+
return %4
95+
}

0 commit comments

Comments
 (0)