How do you look at what the compiler produced at each stage?

5.1.3 · L3 · Learning

Predict first

Which flag prints SIL after the mandatory passes but without optimisation?

// A: -emit-silgen
// B: -emit-sil
// C: -emit-ir
  • A
  • B
  • C

Mental model. Each flag is a window into a different room of the factory. You can stand at the one you care about and see exactly what is being built.

Ask the compiler to stop and print. swiftc -dump-ast shows the type-checked tree. -emit-silgen shows raw SIL, -emit-sil SIL after the mandatory passes, and -emit-sil -O SIL after optimisation. -emit-ir shows LLVM IR, and -S the assembly. Add -wmo to see whole-module results, and -module-name if you want readable symbol names. swift demangle '$s4main3addyS2i_SitF' turns a mangled name into main.add(Swift.Int, Swift.Int) -> Swift.Int.

For build time rather than output: -Xfrontend -debug-time-function-bodies lists the slowest function bodies, -Xfrontend -warn-long-function-bodies=200 and -warn-long-expression-type-checking=200 warn above a threshold in milliseconds, and Xcode’s Build Timeline shows parallelism. Online, Compiler Explorer shows SIL and assembly side by side. Reading even a few lines of SIL is the fastest way to settle “is this call direct?” without guessing.

-emit-silgen stops before the passes, and -emit-ir is already LLVM IR. Plain -emit-sil is SIL with the mandatory passes applied.

Shows
-dump-astthe type-checked syntax tree
-emit-silgenraw SIL, before the mandatory passes
-emit-silSIL after the passes; add -O for optimised SIL
-emit-irLLVM IR
-Sassembly
-Xfrontend -debug-time-function-bodiestype-checking time per function

Common traps

  • Reading Debug-build assembly and drawing performance conclusions. Always inspect the optimised output of the configuration you ship.
  • Forgetting -wmo. Without it, per-file output omits optimisations that need the whole module.

They might follow up with

  • How do you name symbols readably? Compile a single file with -module-name Demo, then demangle what you see.
  • Is SIL stable? No. Its text format changes between compiler versions, so treat it as a debugging aid, not an interface.

Related questions

  • 5.1.4 How do you read SIL to tell static dispatch from dynamic dispatch?
  • 5.6.1 A Swift file takes forever to compile. How do you find the cause and fix it?

← What does the compiler guarantee through its mandatory SIL passes?   How do you read SIL to tell static dispatch from dynamic dispatch? →