菜单

Swift 编译器概述

相关源文件

本页面全面概述了 Swift 编译器的架构、关键组件和编译流程。它为理解 Swift 编译器如何将源代码转换为可执行二进制文件提供了基础指南。有关特定组件的更详细信息,请参阅其专用 wiki 页面,例如 类型系统中间表示

编译器架构

Swift 编译器遵循多阶段流水线架构,其中包含多个协同工作的关键组件来处理源代码。

来源:lib/Frontend/CompilerInvocation.cpp114-130 lib/Sema/ConstraintSystem.cpp114-148 lib/Parse/ParseDecl.cpp167-205

组件概览

  1. 前端工具:管理编译过程,处理命令行参数,并配置编译设置。

  2. 解析器:处理 Swift 源代码并构建抽象语法树 (AST),代表程序结构。

  3. 类型检查器:执行语义分析、类型检查、推断和 AST 验证。

  4. SIL 生成器:从类型检查后的 AST 创建 Swift 中间语言 (SIL),为优化做准备。

  5. IRGen:将 SIL 转换为 LLVM 中间表示 (IR)。

  6. LLVM 后端:使用 LLVM 基础架构优化 IR 并生成机器码。

  7. 支持系统:

    • Clang Importer:导入 C、C++ 和 Objective-C 声明
    • 模块加载器:从各种来源加载 Swift 模块

编译流程详解

Swift 编译器通过几个不同的阶段处理源代码

来源:lib/Parse/ParseDecl.cpp167-205 lib/Sema/TypeCheckDecl.cpp74-150 lib/Sema/CSGen.cpp45-77

每个阶段都会执行特定的任务

  1. 词法分析器和解析器:对源代码进行分词并构建 AST 结构
  2. 名称绑定:解析标识符并构建符号表
  3. 类型检查:使用约束验证类型并执行类型推断
  4. SIL 生成:将类型检查后的 AST 转换为 Swift 中间语言
  5. SIL 优化:在 SIL 层面应用各种优化
  6. LLVM IR 生成:将优化后的 SIL 转换为 LLVM IR
  7. 代码生成:使用 LLVM 生成机器码

类型系统与基于约束的类型检查

Swift 编译器最复杂的部分之一是其类型检查器,它使用基于约束的方法来推断类型。

来源:lib/Sema/ConstraintSystem.cpp114-148 lib/Sema/CSSimplify.cpp49-83 lib/Sema/CSGen.cpp45-77 lib/Sema/CSDiagnostics.cpp61-85

基于约束的类型检查过程包括

  1. 约束生成:从 AST 节点创建类型约束

    • 实现在 CSGen.cpp
    • 使用类型变量表示未知类型
    • 生成诸如相等性、子类型、转换等约束
  2. 约束简化:将复杂约束简化为更简单的形式

    • 实现在 CSSimplify.cpp
    • 处理运算符重载、方法查找和类型转换
  3. 约束求解:搜索约束系统的有效解决方案

    • 实现在 CSSolver.cpp
    • 使用回溯算法查找有效的类型赋值
    • 通过分支处理析取(OR 约束)
  4. 解决方案应用:将求解后的类型重新应用到 AST

    • 实现在 CSApply.cpp
    • 用具体类型重写 AST 节点
  5. 诊断生成:在类型检查失败时生成有用的错误消息

    • 实现在 CSDiagnostics.cpp
    • 为不同类型的错误提供具体诊断

声明和 AST

Swift 的 AST 以声明为中心,声明代表命名的程序实体。

来源:include/swift/AST/Decl.h134-217 lib/AST/Decl.cpp156-335

AST 的结构围绕声明构建,包括

  1. Decl:所有声明的基类

    • 使用 DeclKind 枚举标识声明的种类
    • 维护属性、源代码位置和父上下文
  2. ValueDecl 子类:具有名称和类型的声明

    • 函数、变量、下标、枚举元素等
    • 每个都有接口类型和访问级别
  3. TypeDecl 子类:定义类型的声明

    • 类、结构体、枚举、协议、类型别名
  4. 描述性种类:更细粒度的分类

    • DescriptiveDeclKind 枚举提供详细分类
    • 用于更好的诊断和面向用户的描述
  5. AST 上下文:AST 信息的中央存储库

    • 管理 AST 内存和类型唯一化
    • 维护声明的全局表

约束系统和类型检查实现

ConstraintSystem 类是类型检查表达式的核心组件。

来源:lib/Sema/ConstraintSystem.cpp114-148 include/swift/Sema/ConstraintSystem.h

ConstraintSystem 的关键实现方面

  1. 类型变量:在推断过程中表示未知类型

    • 通过 TypeVariableType 类管理
    • 可以是自由的、绑定到具体类型或绑定到其他类型变量
  2. 约束:表达类型之间的关系

    • 各种类型:相等性、转换、成员查找、析取
    • 存储在约束列表中以供处理
  3. 约束图:跟踪类型变量之间的关系

    • 通过关注相关约束来优化约束求解
    • 有助于确定在类型变量绑定时哪些约束会受到影响
  4. 绑定:将类型变量映射到其解析后的类型

    • 用于在约束求解过程中跟踪解决方案
    • 用于创建最终类型化的表达式
  5. 析取选择:跟踪分支点处的决策

    • 记录为每个析取选择的备选项
    • 用于诊断和解决方案排名

Swift 中间语言 (SIL)

SIL 是 Swift 的主要中间表示,它在高级 AST 和低级 LLVM IR 之间架起了桥梁。

来源:lib/IRGen/IRGenSIL.cpp lib/Sema/CSApply.cpp60-106

SIL 的特点是

  1. 显式内存管理:使 ARC 操作显式化

    • 保留、释放和移动操作有明确的表示
    • 能够优化引用计数操作
  2. 地址类型:左值和右值的独立表示

    • 地址类型与对象类型
    • 使变异和所有权语义显式化
  3. 泛型特化:特化泛型代码的框架

    • 捕获反虚化和特化所需的信息
    • 支持整模块优化
  4. 所有权语义:值的显式所有权表示

    • 支持 Swift 的独占类型和所有权功能
    • 允许编译器验证所有权正确性

编译器调用与前端

Swift 编译器通常通过其前端工具进行调用,该工具配置编译过程。

来源: lib/Frontend/CompilerInvocation.cpp54-91 lib/FrontendTool/FrontendTool.cpp

编译器调用过程包括

  1. 命令行处理:解析参数和选项

    • 设置编译模式(JIT、全模块等)
    • 配置输入和输出文件
  2. 配置设置:初始化编译器设置

    • 目标三元组(平台、架构等)
    • 语言特性和版本
    • 模块和库的搜索路径
  3. 资源路径设置:定位编译器资源

    • 标准库和运行时
    • 用于 C/C++/Objective-C 导入的 Clang 资源
    • 模块缓存目录
  4. 诊断配置:设置诊断系统

    • 警告级别和行为
    • 诊断的输出格式
    • 警告抑制
  5. 编译管道设置:配置处理阶段

    • 要运行的阶段(解析、类型检查、SIL 生成等)
    • 优化级别。
    • 输出文件类型

结论

Swift 编译器是一个复杂的组件管道,它们协同工作,将 Swift 源代码转换为可执行的二进制代码。从解析到代码生成,每个组件在编译过程中都起着特定的作用。理解这种架构为使用 Swift 编译器打下了坚实的基础,无论是用于开发、调试还是扩展其功能。

来源: lib/Sema/ConstraintSystem.cpp lib/Sema/CSSimplify.cpp include/swift/AST/DiagnosticsSema.def lib/AST/Decl.cpp lib/Sema/CSApply.cpp lib/Frontend/CompilerInvocation.cpp lib/Parse/ParseDecl.cpp lib/Sema/CSGen.cpp lib/Sema/TypeCheckType.cpp