Swift工程编译

梁丘宏硕
2023-12-01

Swift编译过程

苹果为swift代码单独写了swiftc来编译前端代码,所以swift在编译时需要对Objetive-CSwift分开编译,整个流程大致示意图

compiler
proocess
compiler
process
*.swift
swiftc
IR
*.m
clang
LLVM-Backend

源代码经过clang编译器和swiftc编译器分别编译后生成中间代码,然后由LLVM后端对代码进行一步加工处理生成.o文件并进行链接,绑定对应的arch最终生成可执行文件

LLVM

LLVM是一款跨平台编译器基础设施,包含了系列的模块化编译组件和工具链,用于开发编译器前端和后端,在iOS工程中前端中间代码由苹果定制化开发,这里主要是利用了其后端的功能,将IR转换为不同平台的汇编代码.

Clang

Clang一个C语言、C++、Objective-C语言的编译器, Objective-C正是采用它来进行编译的

主要流程如下:

AST
*,c
Parse
Sema
CodeGen
Analysis
CFG
`-Wunreachable-code`
`-Wuninitializated`
StaticAnalyzer
IR
LLVM
.o
  1. 预处理: 首先进行宏模版替换, 然后对词法分析,主要是按照代码格式中的标识符号,数字,字符串,标点符号将代码进行分割,逐个单词或符号进行检查看看代码是否书写正确,也被称作为Tokenizatioon,从语文学上来将就是检查错别字 通过-E-dump-tokens`命令可以查看替换后的宏模版和词法分析源码
  2. Paser: 将代码解析为对应的数据结构,即抽象的语法树AST(Abstract Tree)
  3. Sema: 语意分析,从语文的角度来将就是检查病句,对代码格式和类型进行检查, CFG(Control Flow Graphic)流程控制分析,检查无用的变量,未初始化的代码,静态分析( Static Analyzer),静态分析基于设定的分析规则来检查的,可以通过clang -cc1 -analyzer-checker-help-enable-checker来开启某些规则,比如除0,越界,typeCastd等
  4. CodeGen: 生成中间代码
  5. 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的代码安全。 比如未初始化的变变量,边界和溢出检查

AST
*swift
Parse
Sema
SILGen
SIL
Analytics
IRGen
IR
LLVM
  1. Parse: 词法分析,同上。错别字标点符号检查
  2. Sema: Semantic Analysis, 语法格式检查,导出Objective-C到swift的api中
  3. SILGen: 这里先生成Raw SIL,忽略类型检查,算术等机器码级别的操作(如: Int32当作Int看待,不会直接体现机器码位数)
  sil @fibonacci: $(Swift.Int) -> () {
  entry(%limi: $Swift.Int):
  1. Analytics: SIL代码检查流程检查,未初始化的变量和无用的代码,内存优化,生成 SIL Opt Canonical SIL
  2. IRGen: 将SIL转化为IR提供给LLVM继续优化并生成机器码

Clang 与 Swiftc在IR处理过程

  • Clang

源代码和LLVM IR之间存在较大的抽象差距IR不适合进行源代码级分析

CFG缺乏保真度

CFG脱离热通道

CFG和IR下降过程中的重复工作

  • Swifc

完全表示程序语义

设计用于代码生成和分析

位于编译器管道的热路径上

源代码和LLVM之间的抽象桥梁

SIL的设计特点

  1. 保持高层级的类型系统
  • 保持机器级类型布局抽象
  • 类型相关信息是隐式的•TBAA
    • 泛型专门化的类型参数
    • 设备化的类和协议一致性强类型IR有助于验证编译器的正确性
  1. 内置的对象

内置不透明地表示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))
    }
  1. 指令,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

 类似资料: