Skip to content

Commit 7aa3b89

Browse files
committed
Merge pull request #2158 from trentxintong/RM
More conservative about when we can move a release across an instruction
2 parents 728d21a + 1a4f567 commit 7aa3b89

File tree

5 files changed

+232
-60
lines changed

5 files changed

+232
-60
lines changed

include/swift/SILOptimizer/Analysis/AliasAnalysis.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,11 @@ class AliasAnalysis : public SILAnalysis {
187187
return alias(V1, V2, TBAAType1, TBAAType2) == AliasResult::MayAlias;
188188
}
189189

190+
/// \returns True if the release of the \p Ptr can access memory accessed by
191+
/// \p User.
192+
bool mayValueReleaseInterfereWithInstruction(SILInstruction *User,
193+
SILValue Ptr);
194+
190195
/// Use the alias analysis to determine the memory behavior of Inst with
191196
/// respect to V.
192197
///

lib/SILOptimizer/Analysis/ARCAnalysis.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -233,8 +233,12 @@ static bool canTerminatorUseValue(TermInst *TI, SILValue Ptr,
233233
return doOperandsAlias(CCBI->getAllOperands(), Ptr, AA);
234234
}
235235

236-
bool swift::mayUseValue(SILInstruction *User, SILValue Ptr,
237-
AliasAnalysis *AA) {
236+
237+
bool swift::mayUseValue(SILInstruction *User, SILValue Ptr, AliasAnalysis *AA) {
238+
// Check whether releasing this value can call deinit and interfere with User.
239+
if (AA->mayValueReleaseInterfereWithInstruction(User, Ptr))
240+
return true;
241+
238242
// If Inst is an instruction that we know can never use values with reference
239243
// semantics, return true.
240244
if (canNeverUseValues(User))

lib/SILOptimizer/Analysis/AliasAnalysis.cpp

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,18 @@ llvm::raw_ostream &swift::operator<<(llvm::raw_ostream &OS, AliasResult R) {
100100
}
101101
}
102102

103+
SILValue getAccessedMemory(SILInstruction *User) {
104+
if (auto *LI = dyn_cast<LoadInst>(User)) {
105+
return LI->getOperand();
106+
}
107+
108+
if (auto *SI = dyn_cast<StoreInst>(User)) {
109+
return SI->getDest();
110+
}
111+
112+
return SILValue();
113+
}
114+
103115
//===----------------------------------------------------------------------===//
104116
// Unequal Base Object AA
105117
//===----------------------------------------------------------------------===//
@@ -672,6 +684,43 @@ bool AliasAnalysis::canBuiltinDecrementRefCount(BuiltinInst *BI, SILValue Ptr) {
672684
return false;
673685
}
674686

687+
688+
bool AliasAnalysis::mayValueReleaseInterfereWithInstruction(SILInstruction *User,
689+
SILValue Ptr) {
690+
// TODO: Its important to make this as precise as possible.
691+
//
692+
// TODO: Eventually we can plug in some analysis on the what the release of
693+
// the Ptr can do, i.e. be more precise about Ptr's deinit.
694+
//
695+
// TODO: If we know the specific release instruction, we can potentially do
696+
// more.
697+
//
698+
// If this instruction can not read or write any memory. Its OK.
699+
if (!User->mayReadOrWriteMemory())
700+
return false;
701+
702+
// These instructions do read or write memory, get memory accessed.
703+
SILValue V = getAccessedMemory(User);
704+
if (!V)
705+
return true;
706+
707+
// Is this a local allocation ?
708+
if (!pointsToLocalObject(V))
709+
return true;
710+
711+
// This is a local allocation.
712+
// The most important check: does the object escape the current function?
713+
auto LO = getUnderlyingObject(V);
714+
auto *ConGraph = EA->getConnectionGraph(User->getFunction());
715+
auto *Node = ConGraph->getNodeOrNull(LO, EA);
716+
if (Node && !Node->escapes())
717+
return false;
718+
719+
// This is either a non-local allocation or a local allocation that escapes.
720+
// We failed to prove anything, it could be read or written by the deinit.
721+
return true;
722+
}
723+
675724
bool swift::isLetPointer(SILValue V) {
676725
// Traverse the "access" path for V and check that it starts with "let"
677726
// and everything along this path is a value-type (i.e. struct or tuple).

test/SILOptimizer/cast_folding_objc.swift

Lines changed: 57 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -58,9 +58,6 @@ func test0() -> Bool {
5858
// Check that this cast does not get eliminated, because
5959
// the compiler does not statically know if this object
6060
// is NSNumber can be converted into Int.
61-
// CHECK-LABEL: sil [noinline] @_TF17cast_folding_objc35testMayBeBridgedCastFromObjCtoSwiftFPs9AnyObject_Si
62-
// CHECK: unconditional_checked_cast_addr
63-
// CHECK: return
6461
@inline(never)
6562
public func testMayBeBridgedCastFromObjCtoSwift(_ o: AnyObject) -> Int {
6663
return o as! Int
@@ -69,9 +66,6 @@ public func testMayBeBridgedCastFromObjCtoSwift(_ o: AnyObject) -> Int {
6966
// Check that this cast does not get eliminated, because
7067
// the compiler does not statically know if this object
7168
// is NSString can be converted into String.
72-
// CHECK-LABEL: sil [noinline] @_TF17cast_folding_objc41testConditionalBridgedCastFromObjCtoSwiftFPs9AnyObject_GSqSS_
73-
// CHECK: unconditional_checked_cast_addr
74-
// CHECK: return
7569
@inline(never)
7670
public func testConditionalBridgedCastFromObjCtoSwift(_ o: AnyObject) -> String? {
7771
return o as? String
@@ -101,174 +95,179 @@ public func testFailingBridgedCastFromSwiftToObjC(_ s: String) -> NSInteger {
10195
return s as! NSInteger
10296
}
10397

104-
// Check that class instances may be cast to potentially-class metatypes.
105-
// CHECK-LABEL: sil [noinline] @{{.*}}testCastNSObjectToAnyClass{{.*}}
106-
// CHECK: unconditional_checked_cast_addr
10798
@inline(never)
10899
public func testCastNSObjectToAnyClass(_ o: NSObject) -> AnyClass {
109100
return o as! AnyClass
110101
}
111102

112-
// CHECK-LABEL: sil [noinline] @{{.*}}testCastNSObjectToClassObject{{.*}}
113-
// CHECK: unconditional_checked_cast_addr
114103
@inline(never)
115104
public func testCastNSObjectToClassObject(_ o: NSObject) -> NSObject.Type {
116105
return o as! NSObject.Type
117106
}
118107

119-
// CHECK-LABEL: sil [noinline] @{{.*}}testCastNSObjectToAnyType{{.*}}
120-
// CHECK: unconditional_checked_cast_addr
121108
@inline(never)
122109
public func testCastNSObjectToAnyType(_ o: NSObject) -> Any.Type {
123110
return o as! Any.Type
124111
}
125112

126-
// CHECK-LABEL: sil [noinline] @{{.*}}testCastNSObjectToEveryType{{.*}}
127-
// CHECK: unconditional_checked_cast_addr
128113
@inline(never)
129114
public func testCastNSObjectToEveryType<T>(_ o: NSObject) -> T.Type {
130115
return o as! T.Type
131116
}
132117

133-
// CHECK-LABEL: sil [noinline] @{{.*}}testCastNSObjectToNonClassType
134-
// CHECK: builtin "int_trap"
135118
@inline(never)
136119
public func testCastNSObjectToNonClassType(_ o: NSObject) -> Int.Type {
137120
return o as! Int.Type
138121
}
139122

140-
// CHECK-LABEL: sil [noinline] @{{.*}}testCastAnyObjectToAnyClass{{.*}}
141-
// CHECK: unconditional_checked_cast_addr
142123
@inline(never)
143124
public func testCastAnyObjectToAnyClass(_ o: AnyObject) -> AnyClass {
144125
return o as! AnyClass
145126
}
146127

147-
// CHECK-LABEL: sil [noinline] @{{.*}}testCastAnyObjectToClassObject{{.*}}
148-
// CHECK: unconditional_checked_cast_addr
149128
@inline(never)
150129
public func testCastAnyObjectToClassObject(_ o: AnyObject) -> AnyObject.Type {
151130
return o as! AnyObject.Type
152131
}
153132

154-
// CHECK-LABEL: sil [noinline] @{{.*}}testCastAnyObjectToAnyType{{.*}}
155-
// CHECK: unconditional_checked_cast_addr
156133
@inline(never)
157134
public func testCastAnyObjectToAnyType(_ o: AnyObject) -> Any.Type {
158135
return o as! Any.Type
159136
}
160137

161-
// CHECK-LABEL: sil [noinline] @{{.*}}testCastAnyObjectToEveryType{{.*}}
162-
// CHECK: unconditional_checked_cast_addr
163138
@inline(never)
164139
public func testCastAnyObjectToEveryType<T>(_ o: AnyObject) -> T.Type {
165140
return o as! T.Type
166141
}
167142

168-
// CHECK-LABEL: sil [noinline] @{{.*}}testCastAnyObjectToNonClassType
169-
// CHECK: builtin "int_trap"
170143
@inline(never)
171144
public func testCastAnyObjectToNonClassType(_ o: AnyObject) -> Int.Type {
172145
return o as! Int.Type
173146
}
174147

175-
// CHECK-LABEL: sil [noinline] @{{.*}}testCastAnyToAnyClass{{.*}}
176-
// CHECK: unconditional_checked_cast_addr
177148
@inline(never)
178149
public func testCastAnyToAnyClass(_ o: Any) -> AnyClass {
179150
return o as! AnyClass
180151
}
181152

182-
// CHECK-LABEL: sil [noinline] @{{.*}}testCastAnyToClassObject{{.*}}
183-
// CHECK: unconditional_checked_cast_addr
184153
@inline(never)
185154
public func testCastAnyToClassObject(_ o: Any) -> AnyObject.Type {
186155
return o as! AnyObject.Type
187156
}
188157

189-
// CHECK-LABEL: sil [noinline] @{{.*}}testCastAnyToAnyType{{.*}}
190-
// CHECK: unconditional_checked_cast_addr
191158
@inline(never)
192159
public func testCastAnyToAnyType(_ o: Any) -> Any.Type {
193160
return o as! Any.Type
194161
}
195162

196-
// CHECK-LABEL: sil [noinline] @{{.*}}testCastAnyToEveryType{{.*}}
197-
// CHECK: unconditional_checked_cast_addr
198163
@inline(never)
199164
public func testCastAnyToEveryType<T>(_ o: Any) -> T.Type {
200165
return o as! T.Type
201166
}
202167

203-
// CHECK-LABEL: sil [noinline] @{{.*}}testCastAnyToNonClassType
204-
// CHECK: unconditional_checked_cast_addr
205168
@inline(never)
206169
public func testCastAnyToNonClassType(_ o: Any) -> Int.Type {
207170
return o as! Int.Type
208171
}
209172

210-
// CHECK-LABEL: sil [noinline] @{{.*}}testCastEveryToAnyClass{{.*}}
211-
// CHECK: unconditional_checked_cast_addr
212173
@inline(never)
213174
public func testCastEveryToAnyClass<T>(_ o: T) -> AnyClass {
214175
return o as! AnyClass
215176
}
216177

217-
// CHECK-LABEL: sil [noinline] @{{.*}}testCastEveryToClassObject{{.*}}
218-
// CHECK: unconditional_checked_cast_addr
219178
@inline(never)
220179
public func testCastEveryToClassObject<T>(_ o: T) -> AnyObject.Type {
221180
return o as! AnyObject.Type
222181
}
223182

224-
// CHECK-LABEL: sil [noinline] @{{.*}}testCastEveryToAnyType{{.*}}
225-
// CHECK: unconditional_checked_cast_addr
226183
@inline(never)
227184
public func testCastEveryToAnyType<T>(_ o: T) -> Any.Type {
228185
return o as! Any.Type
229186
}
230187

231-
// CHECK-LABEL: sil [noinline] @{{.*}}testCastEveryToEveryType{{.*}}
232-
// CHECK: unconditional_checked_cast_addr
233188
@inline(never)
234189
public func testCastEveryToEveryType<T, U>(_ o: U) -> T.Type {
235190
return o as! T.Type
236191
}
237192

238-
// CHECK-LABEL: sil [noinline] @{{.*}}testCastEveryToNonClassType
239-
// CHECK: unconditional_checked_cast_addr
240193
@inline(never)
241194
public func testCastEveryToNonClassType<T>(_ o: T) -> Int.Type {
242195
return o as! Int.Type
243196
}
244197

245198
print("test0=\(test0())")
246199

200+
201+
// CHECK-LABEL: sil [noinline] @{{.*}}testCastNSObjectToEveryType{{.*}}
202+
// CHECK: unconditional_checked_cast_addr
203+
204+
// CHECK-LABEL: sil [noinline] @{{.*}}testCastNSObjectToNonClassType
205+
// CHECK: builtin "int_trap"
206+
207+
// CHECK-LABEL: sil [noinline] @{{.*}}testCastAnyObjectToEveryType{{.*}}
208+
// CHECK: unconditional_checked_cast_addr
209+
210+
// CHECK-LABEL: sil [noinline] @{{.*}}testCastAnyObjectToNonClassType
211+
// CHECK: builtin "int_trap"
212+
213+
// CHECK-LABEL: sil [noinline] @{{.*}}testCastAnyToAnyClass{{.*}}
214+
// CHECK: unconditional_checked_cast_addr
215+
216+
// CHECK-LABEL: sil [noinline] @{{.*}}testCastAnyToClassObject{{.*}}
217+
// CHECK: unconditional_checked_cast_addr
218+
219+
// CHECK-LABEL: sil [noinline] @{{.*}}testCastAnyToAnyType{{.*}}
220+
// CHECK: unconditional_checked_cast_addr
221+
222+
// CHECK-LABEL: sil [noinline] @{{.*}}testCastAnyToEveryType{{.*}}
223+
// CHECK: unconditional_checked_cast_addr
224+
225+
// CHECK-LABEL: sil [noinline] @{{.*}}testCastAnyToNonClassType
226+
// CHECK: unconditional_checked_cast_addr
227+
228+
// CHECK-LABEL: sil [noinline] @{{.*}}testCastEveryToAnyClass{{.*}}
229+
// CHECK: unconditional_checked_cast_addr
230+
231+
// CHECK-LABEL: sil [noinline] @{{.*}}testCastEveryToClassObject{{.*}}
232+
// CHECK: unconditional_checked_cast_addr
233+
234+
// CHECK-LABEL: sil [noinline] @{{.*}}testCastEveryToAnyType{{.*}}
235+
// CHECK: unconditional_checked_cast_addr
236+
237+
// CHECK-LABEL: sil [noinline] @{{.*}}testCastEveryToEveryType{{.*}}
238+
// CHECK: unconditional_checked_cast_addr
239+
240+
// CHECK-LABEL: sil [noinline] @{{.*}}testCastEveryToNonClassType
241+
// CHECK: unconditional_checked_cast_addr
242+
243+
244+
247245
// Check that compiler understands that this cast always succeeds.
248246
// Since it is can be statically proven that NSString is bridgeable to String,
249247
// _forceBridgeFromObjectiveC from String should be invoked instead of
250248
// a more general, but less effective swift_bridgeNonVerbatimFromObjectiveC, which
251249
// also performs conformance checks at runtime.
252-
// CHECK-LABEL: sil [noinline] @_TTSf4g___TF17cast_folding_objc30testBridgedCastFromObjCtoSwiftFCSo8NSStringSS
253-
// CHECK-NOT: {{ cast}}
254-
// CHECK: metatype $@thick String.Type
255-
// CHECK: function_ref @_TTWSSs21_ObjectiveCBridgeable10FoundationZFS_26_forceBridgeFromObjectiveCfTwx15_ObjectiveCType6resultRGSqx__T_
256-
// CHECK: apply
257-
// CHECK: return
258250
@inline(never)
259251
public func testBridgedCastFromObjCtoSwift(_ ns: NSString) -> String {
260252
return ns as String
261253
}
262254

263255
// Check that compiler understands that this cast always succeeds
264-
// CHECK-LABEL: sil [noinline] @_TTSf4gs___TF17cast_folding_objc30testBridgedCastFromSwiftToObjCFSSCSo8NSString
265-
// CHECK-NOT: {{ cast}}
266-
// CHECK: function_ref @_TFE10FoundationSS19_bridgeToObjectiveC
267-
// CHECK: apply
268-
// CHECK: return
269256
@inline(never)
270257
public func testBridgedCastFromSwiftToObjC(_ s: String) -> NSString {
271258
return s as NSString
272259
}
273260

261+
// CHECK-LABEL: sil [noinline] @_TTSf4g___TF17cast_folding_objc35testMayBeBridgedCastFromObjCtoSwiftFPs9AnyObject_Si
262+
// CHECK: unconditional_checked_cast_addr
263+
// CHECK: return
264+
265+
// CHECK-LABEL: sil [noinline] @_TTSf4g___TF17cast_folding_objc41testConditionalBridgedCastFromObjCtoSwiftFPs9AnyObject_GSqSS_
266+
// CHECK: unconditional_checked_cast_addr
267+
// CHECK: return
274268

269+
// CHECK-LABEL: sil [noinline] @_TTSf4gs___TF17cast_folding_objc30testBridgedCastFromSwiftToObjCFSSCSo8NSString
270+
// CHECK-NOT: {{ cast}}
271+
// CHECK: function_ref @_TFE10FoundationSS19_bridgeToObjectiveC
272+
// CHECK: apply
273+
// CHECK: return

0 commit comments

Comments
 (0)