Skip to content

Commit 4183d97

Browse files
committed
Merge pull request #1946 from trentxintong/FS
Change FSO heuristic.
2 parents 27f97c0 + f95d9b3 commit 4183d97

11 files changed

+149
-128
lines changed

include/swift/SILOptimizer/Utils/FunctionSignatureOptUtils.h

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,12 @@ struct ResultDescriptor {
172172
};
173173

174174
class FunctionSignatureInfo {
175+
/// Should this function be optimized.
176+
bool ShouldOptimize;
177+
178+
/// Optimizing this function may lead to good performance potential.
179+
bool HighlyProfitable;
180+
175181
/// Function currently analyzing.
176182
SILFunction *F;
177183

@@ -204,10 +210,15 @@ class FunctionSignatureInfo {
204210
public:
205211
FunctionSignatureInfo(SILFunction *F, llvm::BumpPtrAllocator &BPA,
206212
AliasAnalysis *AA, RCIdentityFunctionInfo *RCFI) :
207-
F(F), Allocator(BPA), AA(AA), RCFI(RCFI),
208-
MayBindDynamicSelf(computeMayBindDynamicSelf(F)) {}
213+
ShouldOptimize(false), HighlyProfitable(false), F(F), Allocator(BPA),
214+
AA(AA), RCFI(RCFI), MayBindDynamicSelf(computeMayBindDynamicSelf(F)) {
215+
analyze();
216+
}
217+
218+
bool shouldOptimize() const { return ShouldOptimize; }
219+
bool profitableOptimize() const { return HighlyProfitable; }
209220

210-
bool analyze();
221+
void analyze();
211222
bool analyzeParameters();
212223
bool analyzeResult();
213224

lib/SILOptimizer/Transforms/FunctionSignatureOpts.cpp

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -486,10 +486,6 @@ static SILFunction*
486486
createOptimizedFunction(RCIdentityFunctionInfo *RCIA,
487487
FunctionSignatureInfo *FSI,
488488
AliasAnalysis *AA, SILFunction *F) {
489-
// Analyze function arguments. If there is no work to be done, exit early.
490-
if (!FSI->analyze())
491-
return nullptr;
492-
493489
// This is the new function name.
494490
auto NewFName = FSI->getOptimizedName();
495491

@@ -551,10 +547,21 @@ class FunctionSignatureOpts : public SILFunctionTransform {
551547
if (!F->shouldOptimize())
552548
return;
553549

554-
// If this function does not have a caller in the current module. We do not
555-
// function signature specialize it.
556-
if (!CA->hasCaller(F))
557-
return;
550+
// If there is no opportunity on the signature, simply return.
551+
if (!FSI.shouldOptimize())
552+
return;
553+
554+
// If this function does not have a caller in the current module.
555+
if (!CA->hasCaller(F)) {
556+
// If this function maybe called indirectly, e.g. from virtual table
557+
// do not function signature specialize it, as this will introduce a thunk.
558+
if (canBeCalledIndirectly(F->getRepresentation()))
559+
return;
560+
// if its not highly profitable to optimize this function. We do not
561+
// function signature specialize it.
562+
if (!FSI.profitableOptimize())
563+
return;
564+
}
558565

559566
// Check the signature of F to make sure that it is a function that we
560567
// can specialize. These are conditions independent of the call graph.

lib/SILOptimizer/Utils/FunctionSignatureOptUtils.cpp

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -345,11 +345,19 @@ bool FunctionSignatureInfo::analyzeResult() {
345345
/// This function goes through the arguments of F and sees if we have anything
346346
/// to optimize in which case it returns true. If we have nothing to optimize,
347347
/// it returns false.
348-
bool FunctionSignatureInfo::analyze() {
348+
void FunctionSignatureInfo::analyze() {
349349
// Compute the signature optimization.
350350
bool OptimizedParams = analyzeParameters();
351351
bool OptimizedResult = analyzeResult();
352-
return OptimizedParams || OptimizedResult;
352+
ShouldOptimize = OptimizedParams || OptimizedResult;
353+
// We set this function to highly profitable if we have a O2G on one of its
354+
// parameters or results.
355+
for (auto &X : ArgDescList) {
356+
HighlyProfitable |= !X.CalleeRelease.empty();
357+
}
358+
for (auto &X : ResultDescList) {
359+
HighlyProfitable |= !X.CalleeRetain.empty();
360+
}
353361
}
354362

355363
//===----------------------------------------------------------------------===//

test/SILOptimizer/cast_folding_objc.swift

Lines changed: 29 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -55,33 +55,6 @@ func test0() -> Bool {
5555
return cast0(NSNumber(integer:1))
5656
}
5757

58-
// Check that compiler understands that this cast always succeeds.
59-
// Since it is can be statically proven that NSString is bridgeable to String,
60-
// _forceBridgeFromObjectiveC from String should be invoked instead of
61-
// a more general, but less effective swift_bridgeNonVerbatimFromObjectiveC, which
62-
// also performs conformance checks at runtime.
63-
// CHECK-LABEL: sil [noinline] @_TF17cast_folding_objc30testBridgedCastFromObjCtoSwiftFCSo8NSStringSS
64-
// CHECK-NOT: {{ cast}}
65-
// CHECK: metatype $@thick String.Type
66-
// CHECK: function_ref @_TTWSSs21_ObjectiveCBridgeable10FoundationZFS_26_forceBridgeFromObjectiveCfTwx15_ObjectiveCType6resultRGSqx__T_
67-
// CHECK: apply
68-
// CHECK: return
69-
@inline(never)
70-
public func testBridgedCastFromObjCtoSwift(ns: NSString) -> String {
71-
return ns as String
72-
}
73-
74-
// Check that compiler understands that this cast always succeeds
75-
// CHECK-LABEL: sil [noinline] @_TF17cast_folding_objc30testBridgedCastFromSwiftToObjCFSSCSo8NSString
76-
// CHECK-NOT: {{ cast}}
77-
// CHECK: function_ref @_TFE10FoundationSS19_bridgeToObjectiveC
78-
// CHECK: apply
79-
// CHECK: return
80-
@inline(never)
81-
public func testBridgedCastFromSwiftToObjC(s: String) -> NSString {
82-
return s as NSString
83-
}
84-
8558
// Check that this cast does not get eliminated, because
8659
// the compiler does not statically know if this object
8760
// is NSNumber can be converted into Int.
@@ -270,3 +243,32 @@ public func testCastEveryToNonClassType<T>(o: T) -> Int.Type {
270243
}
271244

272245
print("test0=\(test0())")
246+
247+
// Check that compiler understands that this cast always succeeds.
248+
// Since it is can be statically proven that NSString is bridgeable to String,
249+
// _forceBridgeFromObjectiveC from String should be invoked instead of
250+
// a more general, but less effective swift_bridgeNonVerbatimFromObjectiveC, which
251+
// 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
258+
@inline(never)
259+
public func testBridgedCastFromObjCtoSwift(ns: NSString) -> String {
260+
return ns as String
261+
}
262+
263+
// 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
269+
@inline(never)
270+
public func testBridgedCastFromSwiftToObjC(s: String) -> NSString {
271+
return s as NSString
272+
}
273+
274+

test/SILOptimizer/devirt_access_other_module.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ public func getExternalClass() -> ExternalClass {
1818
// Note: This will eventually be illegal (to have a public @_transparent function
1919
// referring to a private method), but for now it lets us test what can and
2020
// can't be optimized.
21-
// CHECK-LABEL: sil [transparent] [fragile] @_TF26devirt_access_other_module9invokeFooFCS_13ExternalClassT_
21+
// CHECK-LABEL: sil [transparent] [fragile] @_TTSf4g___TF26devirt_access_other_module9invokeFooFCS_13ExternalClassT_
2222
// CHECK-NOT: function_ref
2323
// CHECK: class_method
2424
// CHECK-NOT: function_ref

test/SILOptimizer/devirt_covariant_return.swift

Lines changed: 46 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,37 @@ func driver() -> () {
105105

106106
driver()
107107

108+
public class Bear {
109+
public init?(fail: Bool) {
110+
if fail { return nil }
111+
}
112+
113+
// Check that devirtualizer can handle convenience initializers, which have covariant optional
114+
// return types.
115+
// CHECK-LABEL: sil @_TFC23devirt_covariant_return4Bearc
116+
// CHECK: checked_cast_br [exact] %{{.*}} : $Bear to $PolarBear
117+
// CHECK: upcast %{{.*}} : $Optional<PolarBear> to $Optional<Bear>
118+
// CHECK: }
119+
public convenience init?(delegateFailure: Bool, failAfter: Bool) {
120+
self.init(fail: delegateFailure)
121+
if failAfter { return nil }
122+
}
123+
}
124+
125+
final class PolarBear: Bear {
126+
127+
override init?(fail: Bool) {
128+
super.init(fail: fail)
129+
}
130+
131+
init?(chainFailure: Bool, failAfter: Bool) {
132+
super.init(fail: chainFailure)
133+
if failAfter { return nil }
134+
}
135+
}
136+
137+
138+
108139

109140
class Payload {
110141
let value: Int32
@@ -148,7 +179,7 @@ final class C2:C {
148179
// Check that the Optional return value from doSomething
149180
// gets properly unwrapped into a Payload object and then further
150181
// devirtualized.
151-
// CHECK-LABEL: sil hidden @_TF23devirt_covariant_return7driver1FCS_2C1Vs5Int32 :
182+
// CHECK-LABEL: sil hidden @_TTSf4dg___TF23devirt_covariant_return7driver1FCS_2C1Vs5Int32
152183
// CHECK: integer_literal $Builtin.Int32, 2
153184
// CHECK: struct $Int32 (%{{.*}} : $Builtin.Int32)
154185
// CHECK-NOT: class_method
@@ -161,7 +192,7 @@ func driver1(c: C1) -> Int32 {
161192
// Check that the Optional return value from doSomething
162193
// gets properly unwrapped into a Payload object and then further
163194
// devirtualized.
164-
// CHECK-LABEL: sil hidden @_TF23devirt_covariant_return7driver3FCS_1CVs5Int32 :
195+
// CHECK-LABEL: sil hidden @_TTSf4g___TF23devirt_covariant_return7driver3FCS_1CVs5Int32
165196
// CHECK: bb{{[0-9]+}}(%{{[0-9]+}} : $C2):
166197
// CHECK-NOT: bb{{.*}}:
167198
// check that for C2, we convert the non-optional result into an optional and then cast.
@@ -172,35 +203,6 @@ func driver3(c: C) -> Int32 {
172203
return c.doSomething()!.getValue()
173204
}
174205

175-
public class Bear {
176-
public init?(fail: Bool) {
177-
if fail { return nil }
178-
}
179-
180-
// Check that devirtualizer can handle convenience initializers, which have covariant optional
181-
// return types.
182-
// CHECK-LABEL: sil @_TFC23devirt_covariant_return4Bearc
183-
// CHECK: checked_cast_br [exact] %{{.*}} : $Bear to $PolarBear
184-
// CHECK: upcast %{{.*}} : $Optional<PolarBear> to $Optional<Bear>
185-
// CHECK: }
186-
public convenience init?(delegateFailure: Bool, failAfter: Bool) {
187-
self.init(fail: delegateFailure)
188-
if failAfter { return nil }
189-
}
190-
}
191-
192-
final class PolarBear: Bear {
193-
194-
override init?(fail: Bool) {
195-
super.init(fail: fail)
196-
}
197-
198-
init?(chainFailure: Bool, failAfter: Bool) {
199-
super.init(fail: chainFailure)
200-
if failAfter { return nil }
201-
}
202-
}
203-
204206
public class D {
205207
let v: Int32
206208
init(_ n: Int32) {
@@ -230,7 +232,7 @@ public class D2: D1 {
230232

231233
// Check that the boo call gets properly devirtualized and that
232234
// that D2.foo() is inlined thanks to this.
233-
// CHECK-LABEL: sil hidden @_TF23devirt_covariant_return7driver2FCS_2D2Vs5Int32
235+
// CHECK-LABEL: sil hidden @_TTSf4g___TF23devirt_covariant_return7driver2FCS_2D2Vs5Int32
234236
// CHECK-NOT: class_method
235237
// CHECK: checked_cast_br [exact] %{{.*}} : $D1 to $D2
236238
// CHECK: bb2
@@ -274,7 +276,7 @@ class EEE : CCC {
274276

275277
// Check that c.foo() is devirtualized, because the optimizer can handle the casting the return type
276278
// correctly, i.e. it can cast (BBB, BBB) into (AAA, AAA)
277-
// CHECK-LABEL: sil hidden @_TF23devirt_covariant_return37testDevirtOfMethodReturningTupleTypesFTCS_3CCC1bCS_2BB_TCS_2AAS2__
279+
// CHECK-LABEL: sil hidden @_TTSf4g_n___TF23devirt_covariant_return37testDevirtOfMethodReturningTupleTypesFTCS_3CCC1bCS_2BB_TCS_2AAS2__
278280
// CHECK: checked_cast_br [exact] %{{.*}} : $CCC to $CCC
279281
// CHECK: checked_cast_br [exact] %{{.*}} : $CCC to $DDD
280282
// CHECK: checked_cast_br [exact] %{{.*}} : $CCC to $EEE
@@ -311,17 +313,19 @@ class DDDD : CCCC {
311313
}
312314
}
313315

314-
// Check that c.foo OSX 10.9 be devirtualized, because the optimizer can handle the casting the return type
315-
// correctly, i.e. it cannot cast (BBBB, BBBB) into (AAAA, AAAA)
316-
// CHECK-LABEL: sil hidden @_TF23devirt_covariant_return38testDevirtOfMethodReturningTupleTypes2FCS_4CCCCTCS_4AAAAS1__
317-
// CHECK: checked_cast_br [exact] %{{.*}} : $CCCC to $CCCC
318-
// CHECK: checked_cast_br [exact] %{{.*}} : $CCCC to $DDDD
319-
// CHECK: class_method
320-
// CHECK: }
321-
func testDevirtOfMethodReturningTupleTypes2(c: CCCC) -> (AAAA, AAAA) {
322-
return c.foo
316+
// Check devirtualization of methods with optional results, where
317+
// optional results need to be casted.
318+
// CHECK-LABEL: sil @{{.*}}testOverridingMethodWithOptionalResult
319+
// CHECK: checked_cast_br [exact] %{{.*}} : $F to $F
320+
// CHECK: checked_cast_br [exact] %{{.*}} : $F to $G
321+
// CHECK: switch_enum
322+
// CHECK: checked_cast_br [exact] %{{.*}} : $F to $H
323+
// CHECK: switch_enum
324+
public func testOverridingMethodWithOptionalResult(f: F) -> (F?, Int)? {
325+
return f.foo()
323326
}
324327

328+
325329
public class F {
326330
@inline(never)
327331
public func foo() -> (F?, Int)? {
@@ -342,16 +346,3 @@ public class H: F {
342346
return nil
343347
}
344348
}
345-
346-
// Check devirtualization of methods with optional results, where
347-
// optional results need to be casted.
348-
// CHECK-LABEL: sil @{{.*}}testOverridingMethodWithOptionalResult
349-
// CHECK: checked_cast_br [exact] %{{.*}} : $F to $F
350-
// CHECK: checked_cast_br [exact] %{{.*}} : $F to $G
351-
// CHECK: switch_enum
352-
// CHECK: checked_cast_br [exact] %{{.*}} : $F to $H
353-
// CHECK: switch_enum
354-
public func testOverridingMethodWithOptionalResult(f: F) -> (F?, Int)? {
355-
return f.foo()
356-
}
357-

0 commit comments

Comments
 (0)