A Brief Overview of Swift Compiler
Swift is a compiled language from Apple for developing mobile apps. In this article, you'll learn about how the Swift compiler works.
Join the DZone community and get the full member experience.
Join For FreeApple's open-sourced Swift programming language and its whole source code are now available on GitHub. There are thousands of programming languages available in the world and hundreds on the way, but the underlying basics of programming languages remains the same. It's very important to understand the roots so that you can learn programming languages easily. The languages are either compiled or interpreted. You can read the difference between them here. An interpreted language takes input and produces output directly, however, compiled languages first prepare executables and then, according to the data, they produce output.
Swift is a compiled language, meaning before producing the actual output, Swift performs various activities. These activities are generally performed by the Swift compiler. In this post, we will see a brief overview of the Swift compiler.
Phases of Compiler
In computer science, you might have learned the theory of compilers. A compiler has five basic phases. Before diving into the Swift compiler, we will see those phases in brief:
- Lexical Analysis
The job of the lexical analyzer is to take the program text and convert it into words and tokens. So what the heck are tokens? They are literally everything apart from the words. It might be white spaces, semicolon, braces, etc. The lexical analyzer takes everything - literally everything - and passes it to the Parser, which is the next phase.
- Parsing
The main job of parsers is to take everything from the lexical analyzer, identify the roles, and group them together so that programmers' code makes sense. The parser might know about the white spaces, braces, and some branching logic, etc. The parser then passes this code to the Semantic Analyser.
- Semantic Analyser
The process of semantic analysis can be important in a language, as it might identify types and logic of programs. It can also do some program bindings. Once all these activities are done, then it passes to the optimization phase
- Optimization
This compiler phase tries to clean your mess that you added to the code. This phase will decide whether to perform optimization for certain code or not. At the end of this phase, your crappy code will be optimized for performance and memory-related issues.
- Code Generation
This is the final phase of the compiler, where all your program code turns into one giant binary file, also known as an executable. We can then execute this file set of data.
In summary, at the end, the compiler converts all your code into a giant file that nobody understands.
Swift Compiler
The Swift compiler is very interesting. It not only does all the things mentioned above, but adds some salt and pepper that makes Swift a different programming language than the others. We will now understand the bigger picture of Swift Compiler. Obviously, we won't go deep inside unless you want your hair to turn grey, or completely lose it. However, the main role of the compiler is to turn Swift into executable machine code.
The Swift compiler has two dimensions, like web or mobile applications, i.e. Frontend and Backend. Now we will see what happens at these two levels.
Swift Compiler - Frontend
The Swift compiler does lexical analysis, parsing, and semantic analysis from the frontend and passes the rest of the phases to the backend. Let's consider the following Swift code:
Struct SwiftWTF {}
This is the declaration of the struct; it doesn't have anything inside it. The lexical analyzer takes this code as text with everything and produces something like this. Note that below is pseudo code:
[kw_struct, ident("SwiftWTF"), l_brace, r_brace]
As you can see, the lexical analyzer take everything and then passes it to the parser. The parser is smart enough to understand that it's a structure and accept all the words and tokens from the lexical analyzer. The parser then converts lexical data into the structured representation of the program. This representation is then passed to semantic analysis and then to the backend.
The frontend is also responsible for features like Xcode integration, code completion, and syntax highlighting.
Swift Compiler - Backend
The real power of Swift comes when the programs come to the backend at compile time. Swift does some very smart things at the backend to deal with the optimization and code generation phase. The Swift compiler uses LLVM for optimization and binary generation. When Swift code is parsed, it's in the form of AST stands for (Abstract Syntax Tree) which then goes through semantic analysis and is converted into Swift Intermediate Language (SIL). This is the place where additional Swift optimization takes place; other programming languages don't have this kind of optimization. This code goes through analysis and the optimizer along with LLVM IR (Intermediate Representation). The LLVM performs some magic and converts our original Swift code into assembly code, and finally ends up as an executable file.
This is the basic flow of the Swift compilation process. I would love to draw a diagram, but you won't read this if there is a diagram.
Where Is Swift Compiler Code?
The process mentioned above is technically documented in the Swift compiler architecture here. There is no point in duplicating that information here, but I would strongly recommend reading that page if you want to understand where the code is for each compiler phase in the Apple Swift GitHub repository. However, here are quick links:
- Parser: lib/Parse
- Semantic Analysis: lib/Sema
- SIL Gen: lib/SILGen
- Optimisation: lib/Analysis, lib/ARC, lib/LoopTransforms, lib/Transforms
- LLVM IR: lib/IRGen
Conclusion
The Swift compiler seems smarter than any other language's compiler in terms of optimization and analysis. Those who are experienced Swift developers wanting to optimize their programs on Apple platforms must know how the Swift compiler works. I will cover a practical example with various compiler tools in the next post. Please comment if I am missing or misrepresenting something.
Published at DZone with permission of Shashikant Jagtap, DZone MVB. See the original article here.
Opinions expressed by DZone contributors are their own.
Comments