Skip to content

Commit

Permalink
Add a new simple utility optimization pass for serialization of SILMo…
Browse files Browse the repository at this point in the history
…dules
  • Loading branch information
swiftix committed Oct 14, 2017
1 parent 882d72b commit 53754a7
Show file tree
Hide file tree
Showing 11 changed files with 173 additions and 33 deletions.
2 changes: 2 additions & 0 deletions include/swift/SILOptimizer/PassManager/Passes.def
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,8 @@ PASS(MarkUninitializedFixup, "mark-uninitialized-fixup",
"Temporary pass for staging in mark_uninitialized changes.")
PASS(SimplifyUnreachableContainingBlocks, "simplify-unreachable-containing-blocks",
"Utility pass. Removes all non-term insts from blocks with unreachable terms")
PASS(SerializeSILPass, "serialize-sil",
"Utility pass. Serializes the current SILModule")
PASS(BugReducerTester, "bug-reducer-tester",
"sil-bug-reducer Tool Testing by Asserting on a Sentinel Function")
PASS_RANGE(AllPasses, AADumper, BugReducerTester)
Expand Down
10 changes: 8 additions & 2 deletions lib/SILOptimizer/PassManager/PassPipeline.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -243,10 +243,16 @@ void addSSAPasses(SILPassPipelinePlan &P, OptimizationLevelKind OpLevel) {
P.addEarlyInliner();
break;
case OptimizationLevelKind::MidLevel:
// Does inline semantics-functions (except "availability"), but not
// global-init functions.
P.addGlobalOpt();
P.addLetPropertiesOpt();
// It is important to serialize before any of the @_semantics
// functions are inlined, because otherwise the information about
// uses of such functions inside the module is lost,
// which reduces the ability of the compiler to optimize clients
// importing this module.
P.addSerializeSILPass();
// Does inline semantics-functions (except "availability"), but not
// global-init functions.
P.addPerfInliner();
break;
case OptimizationLevelKind::LowLevel:
Expand Down
1 change: 1 addition & 0 deletions lib/SILOptimizer/UtilityPasses/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ set(UTILITYPASSES_SOURCES
UtilityPasses/LoopRegionPrinter.cpp
UtilityPasses/MemBehaviorDumper.cpp
UtilityPasses/RCIdentityDumper.cpp
UtilityPasses/SerializeSILPass.cpp
UtilityPasses/SILDebugInfoGenerator.cpp
UtilityPasses/SideEffectsDumper.cpp
UtilityPasses/SimplifyUnreachableContainingBlocks.cpp
Expand Down
53 changes: 53 additions & 0 deletions lib/SILOptimizer/UtilityPasses/SerializeSILPass.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
//===--- SerializeSILPass.cpp ---------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "serialize-sil"
#include "swift/Strings.h"
#include "swift/SILOptimizer/PassManager/Passes.h"
#include "swift/SILOptimizer/PassManager/Transforms.h"

using namespace swift;

/// A utility pass to serialize a SILModule at any place inside the optimization
/// pipeline.
class SerializeSILPass : public SILModuleTransform {
/// Removes [serialized] from all functions. This allows for more
/// optimizations and for a better dead function elimination.
void removeSerializedFlagFromAllFunctions(SILModule &M) {
for (auto &F : M) {
F.setSerialized(IsSerialized_t::IsNotSerialized);
}
}

public:
SerializeSILPass() {}
void run() override {
auto &M = *getModule();
// Nothing to do if the module was serialized already.
if (M.isSerialized())
return;

// Mark all reachable functions as "anchors" so that they are not
// removed later by the dead function elimination pass. This
// is required, because clients may reference any of the
// serialized functions or anything referenced from them. Therefore,
// to avoid linker errors, the object file of the current module should
// contain all the symbols which were alive at the time of serialization.
DEBUG(llvm::dbgs() << "Serializing SILModule in SerializeSILPass\n");
getModule()->serialize();
removeSerializedFlagFromAllFunctions(M);
}
};

SILTransform *swift::createSerializeSILPass() {
return new SerializeSILPass();
}
60 changes: 60 additions & 0 deletions test/SILOptimizer/closure_specialize_fragile.sil
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// RUN: %target-sil-opt %s -verify -closure-specialize -assume-parsing-unqualified-ownership-sil -o - | %FileCheck %s

// Make sure we do not specialize resilientCallee.

sil_stage canonical

import Builtin
import Swift
import SwiftShims

@_semantics("optimize.sil.never") public func action()

@inline(__always) public func fragileCaller()

public func resilientCallee(fn: () -> ())

// action()
sil [_semantics "optimize.sil.never"] @_T026closure_specialize_fragile6actionyyF : $@convention(thin) () -> () {
bb0:
%0 = tuple ()
return %0 : $()
} // end sil function '_T026closure_specialize_fragile6actionyyF'

// CHECK-LABEL: sil [serialized] [always_inline] @_T026closure_specialize_fragile0C6CalleryyF : $@convention(thin) () -> ()
// CHECK: function_ref @_T026closure_specialize_fragile15resilientCalleeyyyc2fn_tF : $@convention(thin) (@owned @callee_owned () -> ()) -> ()
// CHECK: return
// fragileCaller()
sil [serialized] [always_inline] @_T026closure_specialize_fragile0C6CalleryyF : $@convention(thin) () -> () {
bb0:
// function_ref resilientCallee(fn:)
%0 = function_ref @_T026closure_specialize_fragile15resilientCalleeyyyc2fn_tF : $@convention(thin) (@owned @callee_owned () -> ()) -> ()
// function_ref closure #1 in fragileCaller()
%1 = function_ref @_T026closure_specialize_fragile0C6CalleryyFyycfU_ : $@convention(thin) () -> ()
%2 = thin_to_thick_function %1 : $@convention(thin) () -> () to $@callee_owned () -> ()
%3 = apply %0(%2) : $@convention(thin) (@owned @callee_owned () -> ()) -> ()
%4 = tuple ()
return %4 : $()
} // end sil function '_T026closure_specialize_fragile0C6CalleryyF'

// CHECK-LABEL: sil @_T026closure_specialize_fragile15resilientCalleeyyyc2fn_tF : $@convention(thin) (@owned @callee_owned () -> ()) -> ()

// resilientCallee(fn:)
sil @_T026closure_specialize_fragile15resilientCalleeyyyc2fn_tF : $@convention(thin) (@owned @callee_owned () -> ()) -> () {
bb0(%0 : $@callee_owned () -> ()):
strong_retain %0 : $@callee_owned () -> ()
%3 = apply %0() : $@callee_owned () -> ()
strong_release %0 : $@callee_owned () -> ()
%5 = tuple ()
return %5 : $()
} // end sil function '_T026closure_specialize_fragile15resilientCalleeyyyc2fn_tF'

// closure #1 in fragileCaller()
sil shared [serialized] @_T026closure_specialize_fragile0C6CalleryyFyycfU_ : $@convention(thin) () -> () {
bb0:
// function_ref action()
%0 = function_ref @_T026closure_specialize_fragile6actionyyF : $@convention(thin) () -> ()
%1 = apply %0() : $@convention(thin) () -> ()
%2 = tuple ()
return %2 : $()
} // end sil function '_T026closure_specialize_fragile0C6CalleryyFyycfU_'
19 changes: 0 additions & 19 deletions test/SILOptimizer/closure_specialize_fragile.swift

This file was deleted.

4 changes: 2 additions & 2 deletions test/SILOptimizer/globalopt_linkage.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ _ = testit()
// CHECK: sil hidden @{{.*}}testit

// CHECK: // MyStruct.StaticVar.getter
// CHECK-NEXT: sil private [serialized] @_{{.*}}StaticVar
// CHECK-NEXT: sil private @_{{.*}}StaticVar

// CHECK: // Global.getter
// CHECK-NEXT: sil private [serialized] @_{{.*}}Global
// CHECK-NEXT: sil private @_{{.*}}Global
8 changes: 4 additions & 4 deletions test/SILOptimizer/let_properties_opts.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
// initialization code could be removed.
// Specifically, the initialization code for Prop1, Prop2 and Prop3 can be removed.

// CHECK-WMO-LABEL: sil [thunk] [always_inline] @_T019let_properties_opts3FooC{{[_0-9a-zA-Z]*}}fc : $@convention(method) (Int32, @owned Foo) -> @owned Foo
// CHECK-WMO-LABEL: sil @_T019let_properties_opts3FooC{{[_0-9a-zA-Z]*}}fc : $@convention(method) (Int32, @owned Foo) -> @owned Foo
// CHECK-WMO-NOT: ref_element_addr %{{[0-9]+}} : $Foo, #Foo.Prop1
// CHECK-WMO-NOT: ref_element_addr %{{[0-9]+}} : $Foo, #Foo.Prop2
// CHECK-WMO-NOT: ref_element_addr %{{[0-9]+}} : $Foo, #Foo.Prop3
Expand All @@ -26,7 +26,7 @@
// CHECK-WMO: ref_element_addr %{{[0-9]+}} : $Foo, #Foo.Prop3
// CHECK-WMO: return

// CHECK-WMO-LABEL: sil [thunk] [always_inline] @_T019let_properties_opts3FooC{{[_0-9a-zA-Z]*}}fc : $@convention(method) (Int64, @owned Foo) -> @owned Foo
// CHECK-WMO-LABEL: sil @_T019let_properties_opts3FooC{{[_0-9a-zA-Z]*}}fc : $@convention(method) (Int64, @owned Foo) -> @owned Foo
// CHECK-WMO-NOT: ref_element_addr %{{[0-9]+}} : $Foo, #Foo.Prop1
// CHECK-WMO-NOT: ref_element_addr %{{[0-9]+}} : $Foo, #Foo.Prop2
// CHECK-WMO-NOT: ref_element_addr %{{[0-9]+}} : $Foo, #Foo.Prop3
Expand All @@ -41,14 +41,14 @@
// from other modules. Therefore the initialization code could be removed.
// Specifically, the initialization code for Prop2 can be removed.

// CHECK-LABEL: sil [thunk] [always_inline] @_T019let_properties_opts3FooC{{[_0-9a-zA-Z]*}}fc : $@convention(method) (Int32, @owned Foo) -> @owned Foo
// CHECK-LABEL: sil @_T019let_properties_opts3FooC{{[_0-9a-zA-Z]*}}fc : $@convention(method) (Int32, @owned Foo) -> @owned Foo
// CHECK: ref_element_addr %{{[0-9]+}} : $Foo, #Foo.Prop0
// CHECK: ref_element_addr %{{[0-9]+}} : $Foo, #Foo.Prop1
// CHECK: ref_element_addr %{{[0-9]+}} : $Foo, #Foo.Prop2
// CHECK: ref_element_addr %{{[0-9]+}} : $Foo, #Foo.Prop3
// CHECK: return

// CHECK-LABEL: sil [thunk] [always_inline] @_T019let_properties_opts3FooC{{[_0-9a-zA-Z]*}}fc : $@convention(method) (Int64, @owned Foo) -> @owned Foo
// CHECK-LABEL: sil @_T019let_properties_opts3FooC{{[_0-9a-zA-Z]*}}fc : $@convention(method) (Int64, @owned Foo) -> @owned Foo
// CHECK: ref_element_addr %{{[0-9]+}} : $Foo, #Foo.Prop0
// CHECK: ref_element_addr %{{[0-9]+}} : $Foo, #Foo.Prop1
// CHECK: ref_element_addr %{{[0-9]+}} : $Foo, #Foo.Prop2
Expand Down
10 changes: 5 additions & 5 deletions test/SILOptimizer/outliner.swift
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ public func testOutlining() {
gizmo.doSomething(arr)
}

// CHECK-LABEL: sil shared [serializable] [noinline] @_T0So5GizmoC14stringPropertySQySSGvgToTeab_ : $@convention(thin) (@in_guaranteed Gizmo) -> @owned Optional<String>
// CHECK-LABEL: sil shared [noinline] @_T0So5GizmoC14stringPropertySQySSGvgToTeab_ : $@convention(thin) (@in_guaranteed Gizmo) -> @owned Optional<String>
// CHECK: bb0(%0 : $*Gizmo):
// CHECK: %1 = load %0 : $*Gizmo
// CHECK: %2 = objc_method %1 : $Gizmo, #Gizmo.stringProperty!getter.1.foreign : (Gizmo) -> () -> String!
Expand All @@ -71,7 +71,7 @@ public func testOutlining() {
// CHECK: bb3(%13 : $Optional<String>):
// CHECK: return %13 : $Optional<String>

// CHECK-LABEL: sil shared [serializable] [noinline] @_T0So5GizmoC14stringPropertySQySSGvgToTepb_ : $@convention(thin) (Gizmo) -> @owned Optional<String>
// CHECK-LABEL: sil shared [noinline] @_T0So5GizmoC14stringPropertySQySSGvgToTepb_ : $@convention(thin) (Gizmo) -> @owned Optional<String>
// CHECK: bb0(%0 : $Gizmo):
// CHECK: %1 = objc_method %0 : $Gizmo, #Gizmo.stringProperty!getter.1.foreign : (Gizmo) -> () -> String!
// CHECK: %2 = apply %1(%0) : $@convention(objc_method) (Gizmo) -> @autoreleased Optional<NSString>
Expand All @@ -88,7 +88,7 @@ public func testOutlining() {
// CHECK:bb3(%12 : $Optional<String>):
// CHECK: return %12 : $Optional<String>

// CHECK-LABEL: sil shared [serializable] [noinline] @_T0So5GizmoC14stringPropertySQySSGvsToTembnn_ : $@convention(thin) (@owned String, Gizmo) -> () {
// CHECK-LABEL: sil shared [noinline] @_T0So5GizmoC14stringPropertySQySSGvsToTembnn_ : $@convention(thin) (@owned String, Gizmo) -> () {
// CHECK: bb0(%0 : $String, %1 : $Gizmo):
// CHECK: %2 = objc_method %1 : $Gizmo, #Gizmo.stringProperty!setter.1.foreign : (Gizmo) -> (String!) -> ()
// CHECK: %3 = function_ref @_T0SS10FoundationE19_bridgeToObjectiveCSo8NSStringCyF : $@convention(method) (@guaranteed String) -> @owned NSString
Expand All @@ -99,7 +99,7 @@ public func testOutlining() {
// CHECK: strong_release %4 : $NSString
// CHECK: return %7 : $()

// CHECK-LABEL: sil shared [serializable] [noinline] @_T0So5GizmoC12modifyStringSQySSGAD_Si10withNumberSQyypG0D6FoobartFToTembnnnb_ : $@convention(thin) (@owned String, Int, Optional<AnyObject>, Gizmo) -> @owned Optional<String> {
// CHECK-LABEL: sil shared [noinline] @_T0So5GizmoC12modifyStringSQySSGAD_Si10withNumberSQyypG0D6FoobartFToTembnnnb_ : $@convention(thin) (@owned String, Int, Optional<AnyObject>, Gizmo) -> @owned Optional<String> {
// CHECK: bb0(%0 : $String, %1 : $Int, %2 : $Optional<AnyObject>, %3 : $Gizmo):
// CHECK: %4 = objc_method %3 : $Gizmo, #Gizmo.modifyString!1.foreign : (Gizmo) -> (String!, Int, Any!) -> String!
// CHECK: %5 = function_ref @_T0SS10FoundationE19_bridgeToObjectiveCSo8NSStringCyF : $@convention(method) (@guaranteed String) -> @owned NSString
Expand All @@ -124,7 +124,7 @@ public func testOutlining() {
// CHECK: bb3(%20 : $Optional<String>):
// CHECK: return %20 : $Optional<String>

// CHECK-LABEL: sil shared [serializable] [noinline] @_T0So5GizmoC11doSomethingSQyypGSQySaySSGGFToTembnn_ : $@convention(thin) (@owned Array<String>, Gizmo) -> @owned Optional<AnyObject> {
// CHECK-LABEL: sil shared [noinline] @_T0So5GizmoC11doSomethingSQyypGSQySaySSGGFToTembnn_ : $@convention(thin) (@owned Array<String>, Gizmo) -> @owned Optional<AnyObject> {
// CHECK: bb0(%0 : $Array<String>, %1 : $Gizmo):
// CHECK: %2 = objc_method %1 : $Gizmo, #Gizmo.doSomething!1.foreign : (Gizmo) -> ([String]!) -> Any!
// CHECK: %3 = function_ref @_T0Sa10FoundationE19_bridgeToObjectiveCSo7NSArrayCyF : $@convention(method) <{{.*}}> (@guaranteed Array<{{.*}}>) -> @owned NSArray
Expand Down
37 changes: 37 additions & 0 deletions test/Serialization/early-serialization.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// RUN: %empty-directory(%t)
// RUN: %target-swift-frontend -emit-module -O -module-name Swift -module-link-name swiftCore -parse-as-library -parse-stdlib -emit-module -sil-serialize-witness-tables -sil-serialize-vtables %s -o %t/Swift.swiftmodule
// RUN: %target-sil-opt -enable-sil-verify-all %t/Swift.swiftmodule -o - | %FileCheck %s

// Test that early serialization works as expected:
// - it happens before the performance inlining and thus preserves @_semantics functions
// - it happens after generic specialization

public struct Int {
@_inlineable
public init() {}
}

public struct Array<T> {
@_inlineable
public init() {}

// Check that the generic version of a @_semantics function is preserved.
// CHECK: sil [serialized] [_semantics "array.get_capacity"] @_T0Sa12_getCapacitySiyF : $@convention(method) <T> (Array<T>) -> Int
// Check that a specialized version of a function is produced
// CHECK: sil shared [serializable] [_semantics "array.get_capacity"] @_T0Sa12_getCapacitySiyFSi_Tgq5 : $@convention(method) (Array<Int>) -> Int
@_inlineable
@_versioned
@_semantics("array.get_capacity")
internal func _getCapacity() -> Int {
return Int()
}
}

// Check that a call of a @_semantics function was not inlined if early-serialization is enabled.
// CHECK: sil [serialized] @_T0s28userOfSemanticsAnnotatedFuncSiSaySiGF
// CHECK: function_ref
// CHECK: apply
@_inlineable
public func userOfSemanticsAnnotatedFunc(_ a: Array<Int>) -> Int {
return a._getCapacity()
}
2 changes: 1 addition & 1 deletion test/sil-opt/sil-opt.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
// CHECK-NEXT: @_inlineable init
// CHECK-NEXT: }

// CHECK: sil @unknown : $@convention(thin) () -> ()
// CHECK: sil{{.*}} @unknown : $@convention(thin) () -> ()

// CHECK-LABEL: sil [serialized] @_T0s1XV4testyyF : $@convention(method) (X) -> ()
// CHECK: bb0
Expand Down

0 comments on commit 53754a7

Please sign in to comment.