Swift编译过程
苹果为swift代码单独写了swiftc来编译前端代码,所以swift在编译时需要对Objetive-C
和Swift
分开编译,整个流程大致示意图
源代码经过clang编译器和swiftc编译器分别编译后生成中间代码,然后由LLVM后端对代码进行一步加工处理生成.o
文件并进行链接,绑定对应的arch最终生成可执行文件
LLVM
LLVM是一款跨平台编译器基础设施,包含了系列的模块化编译组件和工具链,用于开发编译器前端和后端,在iOS工程中前端中间代码由苹果定制化开发,这里主要是利用了其后端的功能,将IR转换为不同平台的汇编代码.
Clang
Clang一个C语言、C++、Objective-C语言的编译器, Objective-C正是采用它来进行编译的
主要流程如下:
- 预处理: 首先进行宏模版替换, 然后对词法分析,主要是按照代码格式中的标识符号,数字,字符串,标点符号将代码进行分割,逐个单词或符号进行检查看看代码是否书写正确,也被称作为
Tokenizatioon,从语文学上来将就是检查错别字 通过
-E和
-dump-tokens`命令可以查看替换后的宏模版和词法分析源码 - Paser: 将代码解析为对应的数据结构,即抽象的语法树AST(Abstract Tree)
- Sema: 语意分析,从语文的角度来将就是检查病句,对代码格式和类型进行检查, CFG(Control Flow Graphic)流程控制分析,检查无用的变量,未初始化的代码,静态分析( Static Analyzer),静态分析基于设定的分析规则来检查的,可以通过
clang -cc1 -analyzer-checker-help
和-enable-checker
来开启某些规则,比如除0,越界,typeCastd等 - CodeGen: 生成中间代码
- LLVM: 生成对应的可执行文件
- 通过
clang
的-ccc-print-phases
命令可以看看到基本的流程如下,从backend以后部分为LLVM后端的工作
jiodg45@jiodg45s-MacBook-Pro SwiftCompile % clang -ccc-print-phases hello2.m
+- 0: input, "hello2.m", objective-c
+- 1: preprocessor, {0}, objective-c-cpp-output //宏模版替换
+- 2: compiler, {1}, ir //生成中间代码
+- 3: backend, {2}, assembler //汇编
+- 4: assembler, {3}, object //生成可执行.o文件
+- 5: linker, {4}, image //链接镜像文件
6: bind-arch, "x86_64", {5}, image //生成指定架构的文件
Tips: 在Xcode7之后评估提供了一种bitcode技术,及直接发布bitcode(.bc的中间代码,也称IR)
到AppStore,然后由appStore根据用户手机架构生成对应的执行文件以此来减少用户手机空间的占用
- IR: 全称
Intermediate Representation
,中间代码,它是我们生成的最终代码的完整展示,也是LLVM后端优化器的唯一入口
swiftc
swiftc是apple单独为swift代码开发的一款编译器,相比较clang它有更多的约束来保证swift的代码安全。 比如未初始化的变变量,边界和溢出检查
- Parse: 词法分析,同上。错别字标点符号检查
- Sema: Semantic Analysis, 语法格式检查,导出
Objective-C
到swift的api中 - SILGen: 这里先生成Raw SIL,忽略类型检查,算术等机器码级别的操作(如: Int32当作Int看待,不会直接体现机器码位数)
sil @fibonacci: $(Swift.Int) -> () {
entry(%limi: $Swift.Int):
- Analytics: SIL代码检查流程检查,未初始化的变量和无用的代码,内存优化,生成 SIL Opt Canonical SIL
- IRGen: 将SIL转化为IR提供给LLVM继续优化并生成机器码
Clang 与 Swiftc在IR处理过程
- Clang
源代码和LLVM IR之间存在较大的抽象差距IR不适合进行源代码级分析
CFG缺乏保真度
CFG脱离热通道
CFG和IR下降过程中的重复工作
- Swifc
完全表示程序语义
设计用于代码生成和分析
位于编译器管道的热路径上
源代码和LLVM之间的抽象桥梁
SIL的设计特点
- 保持高层级的类型系统
- 保持机器级类型布局抽象
- 类型相关信息是隐式的•TBAA
- 泛型专门化的类型参数
- 设备化的类和协议一致性强类型IR有助于验证编译器的正确性
- 内置的对象
内置不透明地表示SIL Swift标准库下面层的类型和操作,在内置层之上实现用户级界面,同俗来讲就是和机器架构相关的类型在底层进行封装和自动转换
struct Int { var value: Builtin.Int64 }
struct Bool { var value: Builtin.Int1 }
func ==(lhs: Int, rhs: Int) -> Bool {
return Bool(value: Builtin.icmp_eq_Word(lhs.value, rhs.value))
}
- 指令,SIL中定义了很多的语意思化文字指令,方便理解,完美转换成LLVM的IR以及机器码
- class method lookup,通过虚函数表动态查找方法实现并调用
entry(%c: $SomeClass):
%foo = class_method %c: $SomeClass, #SomeClass.foo : $(SomeClass) -> ()
apply %foo(%c) : $(SomeClass) -> ()
sil_vtable SomeClass {
#SomeClass.foo : @SomeClass_foo
}
sil @SomeClass_foo: $(SomeClass) -> ()
- operator method lookup,通过协议表查找函数函数地址并调用,这个
Addable
协议对应的Int
类型,可以兼容多种类型的Int操作
entry(%x: $Int, %y: $Int):
%plus = function_ref @Int_plus : $(Int, Int) -> Int
%z = apply %plus(%x, %y) : $(Int, Int) -> Int
...
sil_witness_table Int: Addable {
#Addable.+ : @Int_plus
}
可以通过swiftc
提供的更多命令来研究SIL
MODES:
-dump-ast Parse and type-check input file(s) and dump AST(s)
-dump-parse Parse input file(s) and dump AST(s)
-dump-pcm Dump debugging information about a precompiled Clang module
-dump-scope-maps <expanded-or-list-of-line:column>
Parse and type-check input file(s) and dump the scope map(s)
-dump-type-info Output YAML dump of fixed-size types from all imported modules
-dump-type-refinement-contexts
Type-check input file(s) and dump type refinement contexts(s)
-emit-assembly Emit assembly file(s) (-S)
-emit-bc Emit LLVM BC file(s)
-emit-executable Emit a linked executable
-emit-imported-modules Emit a list of the imported modules
-emit-irgen Emit LLVM IR file(s) before LLVM optimizations
-emit-ir Emit LLVM IR file(s) after LLVM optimizations
-emit-library Emit a linked library
-emit-object Emit object file(s) (-c)
-emit-pcm Emit a precompiled Clang module from a module map
-emit-sibgen Emit serialized AST + raw SIL file(s)
-emit-sib Emit serialized AST + canonical SIL file(s)
-emit-silgen Emit raw SIL file(s)
-emit-sil Emit canonical SIL file(s)
-emit-supported-features
Emit a JSON file including all supported compiler features
-index-file Produce index data for a source file
-parse Parse input file(s)
-print-ast Parse and type-check input file(s) and pretty print AST(s)
-resolve-imports Parse and resolve imports in input file(s)
-scan-dependencies Scan dependencies of the given Swift sources
-typecheck Parse and type-check input file(s)
关于SIL详细介绍建议看看这个视频
https://www.youtube.com/watch?v=Ntj8ab-5cvE