What does Swift support in CMake mean for Swift's build?

Sorry for the fat finger earlier (I was hoping to make this more of a surprise).

But yes, I have a proof of concept that has a SILOptimizer pass written in swift running in the swift compiler in the optimization pipeline. You can use it in sil-opt if you want just like a normal pass. It is available in this branch here:

My hope is that I was able to do the majority of the hard work in terms of the build-system/etc. Bridging new types (and adding attributes/etc/newtype) could be done by others who are not that familiar with c++ but are familiar with swift/objc interop. The nice thing about my design is adding a new SILOptimizer pass is trivial. This is the diff for adding the SILOptimizer pass:

commit d50d06f937d5c219af76e655d91f6cce84ca4eae
Author: Michael Gottesman <mgottesman@apple.com>
Date:   Wed Jun 26 17:58:34 2019 -0700

    [swift] Add the proof of concept ModuleDumper SILOptimizer pass.

diff --git a/include/swift/SILOptimizer/PassManager/Passes.def b/include/swift/SILOptimizer/PassManager/Passes.def
index e205aab571b..5622ca35ae6 100644
--- a/include/swift/SILOptimizer/PassManager/Passes.def
+++ b/include/swift/SILOptimizer/PassManager/Passes.def
@@ -318,6 +318,8 @@ PASS(SerializeSILPass, "serialize-sil",
      "Utility pass. Serializes the current SILModule")
 PASS(YieldOnceCheck, "yield-once-check",
     "Check correct usage of yields in yield-once coroutines")
+BRIDGED_PASS(ModuleDumper, "swift-module-dumper",
+    "Just a proof of concept pass that verifies and dumps a SILModule")
 PASS(OSLogOptimization, "os-log-optimization", "Optimize os log calls")
 PASS(BugReducerTester, "bug-reducer-tester",
      "sil-bug-reducer Tool Testing by Asserting on a Sentinel Function")
diff --git a/lib/SILOptimizer/PassManager/PassPipeline.cpp b/lib/SILOptimizer/PassManager/PassPipeline.cpp
index 60d0948d709..c80c2169ab2 100644
--- a/lib/SILOptimizer/PassManager/PassPipeline.cpp
+++ b/lib/SILOptimizer/PassManager/PassPipeline.cpp
@@ -405,6 +405,7 @@ static void addPerfEarlyModulePassPipeline(SILPassPipelinePlan &P) {
 
 static void addHighLevelEarlyLoopOptPipeline(SILPassPipelinePlan &P) {
   P.startPipeline("HighLevel+EarlyLoopOpt");
+  P.addModuleDumper();
   // FIXME: update this to be a function pass.
   P.addEagerSpecializer();
   addSSAPasses(P, OptimizationLevelKind::HighLevel);
diff --git a/lib/SILOptimizer/UtilityPasses/CMakeLists.txt b/lib/SILOptimizer/UtilityPasses/CMakeLists.txt
index 31887874dd4..7ca941e4cbe 100644
--- a/lib/SILOptimizer/UtilityPasses/CMakeLists.txt
+++ b/lib/SILOptimizer/UtilityPasses/CMakeLists.txt
@@ -30,3 +30,7 @@ silopt_register_sources(
   StripDebugInfo.cpp
   OwnershipDumper.cpp
 )
+
+silopt_register_swift_sources(
+  ModuleDumper.swift
+  )
diff --git a/lib/SILOptimizer/UtilityPasses/ModuleDumper.swift b/lib/SILOptimizer/UtilityPasses/ModuleDumper.swift
new file mode 100644
index 00000000000..858cd1a8a5d
--- /dev/null
+++ b/lib/SILOptimizer/UtilityPasses/ModuleDumper.swift
@@ -0,0 +1,12 @@
+
+import SwiftBridge
+
+@_cdecl("WrapperTransform_EntryPoint_ModuleDumper")
+public func main(module: swiftbridge_sil_SILModule) {
+#if DUMP_MODULE
+  swiftbridge_sil_SILModule_dump(module)
+#else
+  print(" I AM IN SWIFT AND I AM VERIFYING THE MODULE !")
+  swiftbridge_sil_SILModule_verify(module)
+#endif
+}

A few things about the design:

  1. I am taking advantage of the way Swift uses .def files/etc to try to hide all of the badness.

  2. The code is using a new library I wrote called SwiftBridge. This is just a way to use metaprogramming to bridge back and forth in between swift/c++ using c. Since it is in c, any swift program can use it. My hope is that other people can take what I have done here and use newtype, overlays, etc to clean this up. Adding new bridged types is very trivial:

Right now it only supports methods with 0 arguments, but I think the right pieces are there that it should be easy to expand.

  1. I am taking advantage of the way lifetimes are managed in the SILOptimizer (namely that optimizer passes do not manage /any/ IR memory directly) to enable the code to just use value types.

  2. Keep in mind that b/c this is autogenerated via cpp, the code isn't pretty, but with a small bit of work and attributes to rename things (as well as use newtype to make the c structs act like swift structs), it could look a lot prettier.

In terms of the requirements get this to work, you need the cmake release preview AND the most recent swift snapshot from swift.org. The reason why is that Compnerd/Jordan added support for emitting static libraries recently into Swift (not for exporting to users, AFAIKT, but rather for helping move around object files in a sane way) and I needed a swift that supported that. So if one installs that package and then uses a script like the following:

export env TOOLCHAINS=org.swift.50201906231a
./swift/utils/build-script \
    --release-debuginfo \
    --assertions \
    --skip-build-benchmarks \
    --build-subdir \
    swift-cmake-asserts\
    --cmake \
    $PATH_TO_CMAKE/cmake-3.15.0-rc2-Darwin-x86_64/CMake.app/Contents/bin/cmake

one will see something like:

[67/405] Compiling /Volumes/Files/gottesmm/work/solon/build/swift-cmake-asserts-no-distcc/swift-macosxx86_64/stdlib/public/SwiftOnoneSupport/TVOS/arm64/SwiftOnoneSupport.o
I AM IN SWIFT AND I AM VERIFYING THE MODULE !

This is all of the time I have to spend on this now, but I wanted to show that it is possible and (assuming this proof of concept is productized/cleaned up by someone), we could have it way before we have c++ interop.

Michael

(*) In fact, it isn't in the proof of concept now, but I was able to late last night create a Swift Package that linked against SwiftBridge and code in Xcode, get code completion, etc. The best part is that even though it fails to link, if the pass builds, you know that your pass will also build in Swift's cmake quickly, except that since we are just bringing in a module header, it takes no time at all to compile. That was the coolest thing I noticed while working on this.

16 Likes