Skip to content

Commit 98e3253

Browse files
committed
UnsafeGuaranteed Peephole: Handle a release after the UnsafeGuaranteedEnd instruction
We seem to emit this pattern now.
1 parent ad34f89 commit 98e3253

File tree

2 files changed

+130
-16
lines changed

2 files changed

+130
-16
lines changed

lib/SILOptimizer/Transforms/UnsafeGuaranteedPeephole.cpp

Lines changed: 52 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,20 @@ getSingleUnsafeGuaranteedValueResult(BuiltinInst *BI) {
8282
return std::make_pair(GuaranteedValue, Token);
8383
}
8484

85+
static bool hasUnsafeGuarantedOperand(SILValue UnsafeGuaranteedValue,
86+
SILValue UnsafeGuaranteedValueOperand,
87+
RCIdentityFunctionInfo &RCII,
88+
SILBasicBlock::iterator ReleaseIt) {
89+
assert(isa<StrongReleaseInst>(ReleaseIt) ||
90+
isa<ReleaseValueInst>(ReleaseIt) && "Expecting a release");
91+
92+
auto RCRoot =
93+
RCII.getRCIdentityRoot(cast<SILInstruction>(ReleaseIt)->getOperand(0));
94+
95+
return RCRoot == UnsafeGuaranteedValue ||
96+
RCRoot == UnsafeGuaranteedValueOperand;
97+
}
98+
8599
/// Walk backwards from an unsafeGuaranteedEnd builtin instruction looking for a
86100
/// release on the reference returned by the matching unsafeGuaranteed builtin
87101
/// ignoring releases on the way.
@@ -93,35 +107,57 @@ getSingleUnsafeGuaranteedValueResult(BuiltinInst *BI) {
93107
/// strong_release %6 : $Foo // Ignore.
94108
/// %12 = builtin "unsafeGuaranteedEnd"(%6 : $Builtin.Int8) : $()
95109
///
110+
/// Alternatively, look for the release after the unsafeGuaranteedEnd.
96111
static SILBasicBlock::iterator findReleaseToMatchUnsafeGuaranteedValue(
97-
SILInstruction *UnsafeGuaranteedEndI, SILValue UnsafeGuaranteedValue,
98-
SILBasicBlock &BB, RCIdentityFunctionInfo &RCIA) {
112+
SILInstruction *UnsafeGuaranteedEndI, SILInstruction *UnsafeGuaranteedI,
113+
SILValue UnsafeGuaranteedValue, SILBasicBlock &BB,
114+
RCIdentityFunctionInfo &RCIA) {
99115

100116
auto UnsafeGuaranteedEndIIt = SILBasicBlock::iterator(UnsafeGuaranteedEndI);
101117
if (UnsafeGuaranteedEndIIt == BB.begin())
102118
return BB.end();
103119
auto LastReleaseIt = std::prev(UnsafeGuaranteedEndIIt);
104-
auto UnsafeGuaranteedRCIdentityRoot =
105-
RCIA.getRCIdentityRoot(UnsafeGuaranteedValue);
120+
auto UnsafeGuaranteedRoot = RCIA.getRCIdentityRoot(UnsafeGuaranteedValue);
121+
auto UnsafeGuaranteedOpdRoot =
122+
RCIA.getRCIdentityRoot(UnsafeGuaranteedI->getOperand(0));
123+
124+
// Look before the "unsafeGuaranteedEnd".
106125
while (LastReleaseIt != BB.begin() &&
107126
(((isa<StrongReleaseInst>(*LastReleaseIt) ||
108127
isa<ReleaseValueInst>(*LastReleaseIt)) &&
109-
RCIA.getRCIdentityRoot(LastReleaseIt->getOperand(0)) !=
110-
UnsafeGuaranteedRCIdentityRoot &&
111-
LastReleaseIt->getOperand(0) !=
112-
cast<SILInstruction>(UnsafeGuaranteedValue)->getOperand(0)) ||
128+
!hasUnsafeGuarantedOperand(UnsafeGuaranteedRoot,
129+
UnsafeGuaranteedOpdRoot, RCIA,
130+
LastReleaseIt)) ||
113131
!LastReleaseIt->mayHaveSideEffects() ||
114132
isa<DebugValueInst>(*LastReleaseIt) ||
115133
isa<DebugValueInst>(*LastReleaseIt)))
116134
--LastReleaseIt;
135+
if ((isa<StrongReleaseInst>(*LastReleaseIt) ||
136+
isa<ReleaseValueInst>(*LastReleaseIt)) &&
137+
hasUnsafeGuarantedOperand(UnsafeGuaranteedRoot, UnsafeGuaranteedOpdRoot,
138+
RCIA, LastReleaseIt))
139+
return LastReleaseIt;
140+
141+
// Otherwise, try finding it after the "unsafeGuaranteedEnd".
142+
LastReleaseIt = std::next(SILBasicBlock::iterator(UnsafeGuaranteedEndI));
143+
while (LastReleaseIt != BB.end() &&
144+
(((isa<StrongReleaseInst>(*LastReleaseIt) ||
145+
isa<ReleaseValueInst>(*LastReleaseIt)) &&
146+
!hasUnsafeGuarantedOperand(UnsafeGuaranteedRoot,
147+
UnsafeGuaranteedOpdRoot, RCIA,
148+
LastReleaseIt)) ||
149+
!LastReleaseIt->mayHaveSideEffects() ||
150+
isa<DebugValueInst>(*LastReleaseIt) ||
151+
isa<DebugValueInst>(*LastReleaseIt)))
152+
++LastReleaseIt;
153+
if (LastReleaseIt == BB.end())
154+
return LastReleaseIt;
117155
if ((!isa<StrongReleaseInst>(*LastReleaseIt) &&
118156
!isa<ReleaseValueInst>(*LastReleaseIt)) ||
119-
(RCIA.getRCIdentityRoot(LastReleaseIt->getOperand(0)) !=
120-
UnsafeGuaranteedRCIdentityRoot &&
121-
LastReleaseIt->getOperand(0) !=
122-
cast<SILInstruction>(UnsafeGuaranteedValue)->getOperand(0))) {
157+
!hasUnsafeGuarantedOperand(UnsafeGuaranteedRoot, UnsafeGuaranteedOpdRoot,
158+
RCIA, LastReleaseIt))
123159
return BB.end();
124-
}
160+
125161
return LastReleaseIt;
126162
}
127163

@@ -224,10 +260,10 @@ static bool removeGuaranteedRetainReleasePairs(SILFunction &F,
224260
// Find the release to match with the unsafeGuaranteedValue.
225261
auto &UnsafeGuaranteedEndBB = *UnsafeGuaranteedEndI->getParent();
226262
auto LastReleaseIt = findReleaseToMatchUnsafeGuaranteedValue(
227-
UnsafeGuaranteedEndI, UnsafeGuaranteedValue, UnsafeGuaranteedEndBB,
228-
RCIA);
263+
UnsafeGuaranteedEndI, UnsafeGuaranteedI, UnsafeGuaranteedValue,
264+
UnsafeGuaranteedEndBB, RCIA);
229265
if (LastReleaseIt == UnsafeGuaranteedEndBB.end()) {
230-
DEBUG(llvm::dbgs() << " no release before unsafeGuaranteedEnd found\n");
266+
DEBUG(llvm::dbgs() << " no release before/after unsafeGuaranteedEnd found\n");
231267
continue;
232268
}
233269
SILInstruction *LastRelease = &*LastReleaseIt;

test/SILOptimizer/unsafe_guaranteed_peephole.sil

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,84 @@ bb0(%0 : $Foo):
4040
return %17 : $()
4141
}
4242

43+
// CHECK-LABEL: sil @testUnsafeGuaranteed_simple_after
44+
// CHECK: bb0([[P:%.*]] : $Foo):
45+
// CHECK-NOT: retain
46+
// CHECK-NOT: unsafeGuaranteed
47+
// CHECK: [[M:%.*]] = class_method [[P]] : $Foo, #Foo.beep
48+
// CHECK: apply [[M]]([[P]])
49+
// CHECK-NOT: release
50+
// CHECK-NOT: unsafeGuaranteedEnd
51+
// CHECK-NOT: release
52+
// CHECK: [[T:%.*]] = tuple ()
53+
// CHECK: return [[T]]
54+
// CHECK: }
55+
sil @testUnsafeGuaranteed_simple_after : $@convention(method) (@guaranteed Foo) -> () {
56+
bb0(%0 : $Foo):
57+
strong_retain %0 : $Foo
58+
%4 = builtin "unsafeGuaranteed"<Foo>(%0 : $Foo) : $(Foo, Builtin.Int8)
59+
%5 = tuple_extract %4 : $(Foo, Builtin.Int8), 0
60+
%6 = tuple_extract %4 : $(Foo, Builtin.Int8), 1
61+
%19 = class_method %5 : $Foo, #Foo.beep!1 : (Foo) -> () -> () , $@convention(method) (@guaranteed Foo) -> ()
62+
%20 = apply %19(%5) : $@convention(method) (@guaranteed Foo) -> ()
63+
%16 = builtin "unsafeGuaranteedEnd"(%6 : $Builtin.Int8) : $()
64+
strong_release %5 : $Foo
65+
%17 = tuple ()
66+
return %17 : $()
67+
}
68+
69+
// CHECK-LABEL: sil @testUnsafeGuaranteed_simple_after2
70+
// CHECK: bb0([[P:%.*]] : $Foo):
71+
// CHECK-NOT: retain
72+
// CHECK-NOT: unsafeGuaranteed
73+
// CHECK: [[M:%.*]] = class_method [[P]] : $Foo, #Foo.beep
74+
// CHECK: apply [[M]]([[P]])
75+
// CHECK-NOT: release
76+
// CHECK-NOT: unsafeGuaranteedEnd
77+
// CHECK-NOT: release
78+
// CHECK: [[T:%.*]] = tuple ()
79+
// CHECK: return [[T]]
80+
// CHECK: }
81+
sil @testUnsafeGuaranteed_simple_after2 : $@convention(method) (@guaranteed Foo) -> () {
82+
bb0(%0 : $Foo):
83+
strong_retain %0 : $Foo
84+
%4 = builtin "unsafeGuaranteed"<Foo>(%0 : $Foo) : $(Foo, Builtin.Int8)
85+
%5 = tuple_extract %4 : $(Foo, Builtin.Int8), 0
86+
%6 = tuple_extract %4 : $(Foo, Builtin.Int8), 1
87+
%19 = class_method %5 : $Foo, #Foo.beep!1 : (Foo) -> () -> () , $@convention(method) (@guaranteed Foo) -> ()
88+
%20 = apply %19(%5) : $@convention(method) (@guaranteed Foo) -> ()
89+
%16 = builtin "unsafeGuaranteedEnd"(%6 : $Builtin.Int8) : $()
90+
release_value %4 : $(Foo, Builtin.Int8)
91+
%17 = tuple ()
92+
return %17 : $()
93+
}
94+
95+
// CHECK-LABEL: sil @testUnsafeGuaranteed_simple_after3
96+
// CHECK: bb0([[P:%.*]] : $Foo):
97+
// CHECK-NOT: retain
98+
// CHECK-NOT: unsafeGuaranteed
99+
// CHECK: [[M:%.*]] = class_method [[P]] : $Foo, #Foo.beep
100+
// CHECK: apply [[M]]([[P]])
101+
// CHECK-NOT: release
102+
// CHECK-NOT: unsafeGuaranteedEnd
103+
// CHECK-NOT: release
104+
// CHECK: [[T:%.*]] = tuple ()
105+
// CHECK: return [[T]]
106+
// CHECK: }
107+
sil @testUnsafeGuaranteed_simple_after3 : $@convention(method) (@guaranteed Foo) -> () {
108+
bb0(%0 : $Foo):
109+
strong_retain %0 : $Foo
110+
%4 = builtin "unsafeGuaranteed"<Foo>(%0 : $Foo) : $(Foo, Builtin.Int8)
111+
%5 = tuple_extract %4 : $(Foo, Builtin.Int8), 0
112+
%6 = tuple_extract %4 : $(Foo, Builtin.Int8), 1
113+
%19 = class_method %5 : $Foo, #Foo.beep!1 : (Foo) -> () -> () , $@convention(method) (@guaranteed Foo) -> ()
114+
%20 = apply %19(%5) : $@convention(method) (@guaranteed Foo) -> ()
115+
%16 = builtin "unsafeGuaranteedEnd"(%6 : $Builtin.Int8) : $()
116+
release_value %0 : $Foo
117+
%17 = tuple ()
118+
return %17 : $()
119+
}
120+
43121
// CHECK-LABEL: sil @testUnsafeGuaranteed_noretain
44122
// CHECK: bb0([[P:%.*]] : $Foo):
45123
// CHECK: [[G:%.*]] = builtin "unsafeGuaranteed"

0 commit comments

Comments
 (0)