diff --git a/include/swift/AST/SILOptions.h b/include/swift/AST/SILOptions.h index 6942602c60e..8e92b4795cf 100644 --- a/include/swift/AST/SILOptions.h +++ b/include/swift/AST/SILOptions.h @@ -149,6 +149,9 @@ public: /// Enable the mandatory semantic arc optimizer. bool EnableMandatorySemanticARCOpts = false; + /// \brief Enable large loadable types IRGen pass. + bool EnableLargeLoadableTypes = false; + SILOptions() : Sanitize(SanitizerKind::None) {} /// Return a hash code of any components from these options that should diff --git a/include/swift/Option/FrontendOptions.td b/include/swift/Option/FrontendOptions.td index baf691b4d20..ea8dc54bc36 100644 --- a/include/swift/Option/FrontendOptions.td +++ b/include/swift/Option/FrontendOptions.td @@ -264,6 +264,9 @@ def suppress_static_exclusivity_swap : Flag<["-"], "suppress-static-exclusivity- def enable_sil_opaque_values : Flag<["-"], "enable-sil-opaque-values">, HelpText<"Enable SIL Opaque Values">; + +def enable_large_loadable_types : Flag<["-"], "enable-large-loadable-types">, + HelpText<"Enable Large Loadable types IRGen pass">; def enable_experimental_property_behaviors : Flag<["-"], "enable-experimental-property-behaviors">, diff --git a/include/swift/SILOptimizer/PassManager/PassPipeline.def b/include/swift/SILOptimizer/PassManager/PassPipeline.def index c0cfcf677e0..afd47de5022 100644 --- a/include/swift/SILOptimizer/PassManager/PassPipeline.def +++ b/include/swift/SILOptimizer/PassManager/PassPipeline.def @@ -37,7 +37,7 @@ PASSPIPELINE_WITH_OPTIONS(Performance, "Passes run at -O") PASSPIPELINE(Onone, "Passes run at -Onone") PASSPIPELINE(InstCount, "Utility pipeline to just run the inst count pass") PASSPIPELINE(Lowering, "SIL Address Lowering") -PASSPIPELINE(IRGenPrepare, "Pipeline to run during IRGen") +PASSPIPELINE_WITH_OPTIONS(IRGenPrepare, "Pipeline to run during IRGen") #undef PASSPIPELINE_WITH_OPTIONS #undef PASSPIPELINE diff --git a/include/swift/SILOptimizer/PassManager/Passes.def b/include/swift/SILOptimizer/PassManager/Passes.def index 17e23aec9a9..647f9e48a89 100644 --- a/include/swift/SILOptimizer/PassManager/Passes.def +++ b/include/swift/SILOptimizer/PassManager/Passes.def @@ -222,6 +222,8 @@ PASS(ReleaseHoisting, "release-hoisting", "SIL release Hoisting") PASS(LateReleaseHoisting, "late-release-hoisting", "Late SIL release Hoisting Preserving Epilogues") +IRGEN_PASS(LoadableByAddress, "loadable-address", + "SIL Large Loadable type by-address lowering.") PASS(RemovePins, "remove-pins", "Remove SIL pin/unpin pairs") PASS(SideEffectsDumper, "side-effects-dump", diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index 9ab8890c1fc..6ece5eba4a2 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -1374,6 +1374,7 @@ static bool ParseSILArgs(SILOptions &Opts, ArgList &Args, |= Args.hasArg(OPT_assume_parsing_unqualified_ownership_sil); Opts.EnableMandatorySemanticARCOpts |= !Args.hasArg(OPT_disable_mandatory_semantic_arc_opts); + Opts.EnableLargeLoadableTypes |= Args.hasArg(OPT_enable_large_loadable_types); if (Args.hasArg(OPT_debug_on_sil)) { // Derive the name of the SIL file for debugging from diff --git a/lib/IRGen/IRGen.cpp b/lib/IRGen/IRGen.cpp index 410cb12a527..d58fed30b5c 100644 --- a/lib/IRGen/IRGen.cpp +++ b/lib/IRGen/IRGen.cpp @@ -646,12 +646,19 @@ void swift::irgen::deleteIRGenModule( static void runIRGenPreparePasses(SILModule &Module, irgen::IRGenModule &IRModule) { SILPassManager PM(&Module, &IRModule); + bool largeLoadable = Module.getOptions().EnableLargeLoadableTypes; #define PASS(ID, Tag, Name) #define IRGEN_PASS(ID, Tag, Name) \ - PM.registerIRGenPass(swift::PassKind::ID, irgen::create##ID()); + if (swift::PassKind::ID == swift::PassKind::LoadableByAddress) { \ + if (largeLoadable) { \ + PM.registerIRGenPass(swift::PassKind::ID, irgen::create##ID()); \ + } \ + } else { \ + PM.registerIRGenPass(swift::PassKind::ID, irgen::create##ID()); \ + } #include "swift/SILOptimizer/PassManager/Passes.def" PM.executePassPipelinePlan( - SILPassPipelinePlan::getIRGenPreparePassPipeline()); + SILPassPipelinePlan::getIRGenPreparePassPipeline(Module.getOptions())); } /// Generates LLVM IR, runs the LLVM passes and produces the output file. diff --git a/lib/SILOptimizer/PassManager/PassPipeline.cpp b/lib/SILOptimizer/PassManager/PassPipeline.cpp index 7b577d40d48..ade95e35eca 100644 --- a/lib/SILOptimizer/PassManager/PassPipeline.cpp +++ b/lib/SILOptimizer/PassManager/PassPipeline.cpp @@ -430,19 +430,17 @@ SILPassPipelinePlan::getLoweringPassPipeline() { return P; } -/// Non-mandatory passes that should run as preparation for IRGen. -static void addIRGenPreparePipeline(SILPassPipelinePlan &P) { +SILPassPipelinePlan +SILPassPipelinePlan::getIRGenPreparePassPipeline(const SILOptions &Options) { + SILPassPipelinePlan P; P.startPipeline("IRGen Preparation"); // Insert SIL passes to run during IRGen. // Hoist generic alloc_stack instructions to the entry block to enable better // llvm-ir generation for dynamic alloca instructions. P.addAllocStackHoisting(); - //P.addLoadableByAddress(); -} - -SILPassPipelinePlan SILPassPipelinePlan::getIRGenPreparePassPipeline() { - SILPassPipelinePlan P; - addIRGenPreparePipeline(P); + if (Options.EnableLargeLoadableTypes) { + P.addLoadableByAddress(); + } return P; } diff --git a/test/IRGen/big_types_corner_cases.swift b/test/IRGen/big_types_corner_cases.swift new file mode 100644 index 00000000000..9ae7eb33f6f --- /dev/null +++ b/test/IRGen/big_types_corner_cases.swift @@ -0,0 +1,113 @@ +// RUN: %target-swift-frontend -assume-parsing-unqualified-ownership-sil -enable-large-loadable-types %s -emit-ir | %FileCheck %s + +public struct BigStruct { + var i0 : Int32 = 0 + var i1 : Int32 = 1 + var i2 : Int32 = 2 + var i3 : Int32 = 3 + var i4 : Int32 = 4 + var i5 : Int32 = 5 + var i6 : Int32 = 6 + var i7 : Int32 = 7 + var i8 : Int32 = 8 +} + +func takeClosure(execute block: () -> Void) { +} + +class OptionalInoutFuncType { + private var lp : BigStruct? + private var _handler : ((BigStruct?, Error?) -> ())? + + func execute(_ error: Error?) { + var p : BigStruct? + var handler: ((BigStruct?, Error?) -> ())? + + takeClosure { + p = self.lp + handler = self._handler + self._handler = nil + } + + handler?(p, error) + } +} + +// CHECK-LABEL: define{{( protected)?}} internal swiftcc void @_T022big_types_corner_cases21OptionalInoutFuncTypeC7executeys5Error_pSgFyycfU_(%T22big_types_corner_cases9BigStructVSg* nocapture dereferenceable({{.*}}), %T22big_types_corner_cases21OptionalInoutFuncTypeC*, %T22big_types_corner_cases9BigStructVSgs5Error_pSgIxcx_Sg* nocapture dereferenceable({{.*}}) +// CHECK: call void @_T0SqWy +// CHECK: call void @_T0SqWe +// CHECK: ret void + +public func f1_returns_BigType(_ x: BigStruct) -> BigStruct { + return x +} + +public func f2_returns_f1() -> (_ x: BigStruct) -> BigStruct { + return f1_returns_BigType +} + +public func f3_uses_f2() { + let x = BigStruct() + let useOfF2 = f2_returns_f1() + let _ = useOfF2(x) +} + +// CHECK-LABEL: define{{( protected)?}} swiftcc void @_T022big_types_corner_cases10f3_uses_f2yyF() +// CHECK: call swiftcc void @_T022big_types_corner_cases9BigStructVACycfC(%T22big_types_corner_cases9BigStructV* noalias nocapture sret +// CHECK: call swiftcc { i8*, %swift.refcounted* } @_T022big_types_corner_cases13f2_returns_f1AA9BigStructVADcyF() +// CHECK: call swiftcc void %16(%T22big_types_corner_cases9BigStructV* noalias nocapture sret %call.aggresult1, %T22big_types_corner_cases9BigStructV* noalias nocapture dereferenceable +// CHECK: ret void + +public func f4_tuple_use_of_f2() { + let x = BigStruct() + let tupleWithFunc = (f2_returns_f1(), x) + let useOfF2 = tupleWithFunc.0 + let _ = useOfF2(x) +} + +// CHECK-LABEL: define{{( protected)?}} swiftcc void @_T022big_types_corner_cases18f4_tuple_use_of_f2yyF() +// CHECK: [[TUPLE:%.*]] = call swiftcc { i8*, %swift.refcounted* } @_T022big_types_corner_cases13f2_returns_f1AA9BigStructVADcyF() +// CHECK: [[TUPLE_EXTRACT:%.*]] = extractvalue { i8*, %swift.refcounted* } [[TUPLE]], 0 +// CHECK: [[CAST_EXTRACT:%.*]] = bitcast i8* [[TUPLE_EXTRACT]] to void (%T22big_types_corner_cases9BigStructV*, %T22big_types_corner_cases9BigStructV*, %swift.refcounted*)* +// CHECK: call swiftcc void [[CAST_EXTRACT]](%T22big_types_corner_cases9BigStructV* noalias nocapture sret %call.aggresult1, %T22big_types_corner_cases9BigStructV* noalias nocapture dereferenceable +// CHECK: ret void + +public class BigClass { + public init() { + } + + public var optVar: ((BigStruct)-> Void)? = nil + + func useBigStruct(bigStruct: BigStruct) { + optVar!(bigStruct) + } +} + +// CHECK-LABEL define{{( protected)?}} hidden swiftcc void @_T022big_types_corner_cases8BigClassC03useE6StructyAA0eH0V0aH0_tF(%T22big_types_corner_cases9BigStructV* noalias nocapture dereferenceable({{.*}}), %T22big_types_corner_cases8BigClassC* swiftself) #0 { +// CHECK: getelementptr inbounds %T22big_types_corner_cases8BigClassC, %T22big_types_corner_cases8BigClassC* +// CHECK: call void @_T0SqWy +// CHECK: [[BITCAST:%.*]] = bitcast i8* {{.*}} to void (%T22big_types_corner_cases9BigStructV*, %swift.refcounted*)* +// CHECK: call swiftcc void [[BITCAST]](%T22big_types_corner_cases9BigStructV* noalias nocapture dereferenceable({{.*}}) %0, %swift.refcounted* swiftself +// CHECK: ret void + +public struct MyStruct { + public let a: Int + public let b: String? + } + +typealias UploadFunction = ((MyStruct, Int?) -> Void) -> Void +func takesUploader(_ u: UploadFunction) { } + +class Foo { + func blam() { + takesUploader(self.myMethod) // crash compiling this + } + + func myMethod(_ callback: (MyStruct, Int) -> Void) -> Void { } +} + +// CHECK-LABEL: define{{( protected)?}} linkonce_odr hidden swiftcc { i8*, %swift.refcounted* } @_T022big_types_corner_cases3FooC8myMethodyyAA8MyStructV_SitcFTc(%T22big_types_corner_cases3FooC*) +// CHECK: getelementptr inbounds %T22big_types_corner_cases3FooC, %T22big_types_corner_cases3FooC* +// CHECK: getelementptr inbounds void (i8*, %swift.refcounted*, %T22big_types_corner_cases3FooC*)*, void (i8*, %swift.refcounted*, %T22big_types_corner_cases3FooC*)** +// CHECK: call noalias %swift.refcounted* @swift_rt_swift_allocObject(%swift.type* getelementptr inbounds (%swift.full_boxmetadata, %swift.full_boxmetadata* +// CHECK: ret { i8*, %swift.refcounted* }