我是一只可爱的土拨鼠,专注于分享 Go 职场、招聘和求职,解 Gopher 之忧!欢迎关注我。
欢迎大家加入Go招聘交流群,来这里找志同道合的小伙伴!跟土拨鼠们一起交流学习。
大家好,今天土拨鼠给大家带来一篇关于Go编译器的四个阶段的文章,大家可以学习一下,正好为后续一篇文章做一下铺垫。原文见https://golang.org/src/cmd/compile/README
,由于本人翻译水平有限,翻译不当之处烦请指出。
Go 编译器简介
cmd/compile
目录包含构成 Go 编译器的主包。编译器在逻辑上可以分为四个阶段,我们将在包含其代码的包列表中简要描述这四个阶段。
在提到编译器时,有时可能会听到术语front-end|前端
和back-end|后端
。粗略地说,这些转化为我们将在此列出的前两个和后两个阶段。第三个术语,“middle-end|中间端”,通常指的是在第二阶段进行的大部分工作。
请注意go/*
路径下的包系列,例如go/parser
和go/types
,与编译器没有关系。由于编译器最初是用 C编写的,所以开发go/*
包是为了支持编写使用 Go 代码的工具,比如gofmt
和vet
。
需要澄清一下,名称gc
这里代表Go compiler
,与大写的GC
(garbage collection垃圾回收
)没有什么关系。
1. 语法分析
cmd/compile/internal/syntax
(词法分析器,解析器,语法树)
在编译的第一阶段,对每个源文件代码进行标记(词法分析) ,解析(语法分析) ,并构建一个语法树。
每个语法树都精准地展现了源文件相对应的内容,其中的节点对应于源文件的各种元素,如表达式、声明和语句。语法树还包括了用于错误报告和创建调试信息的位置信息。
2. 类型检查和 AST 转换
cmd/compile/internal/gc
(创建编译器AST
、类型检查、AST
转换)
gc
包包含一个AST
定义,是用C语言编写的。所有代码都是用它编写的,所以gc
包必须做的第一件事就是将语法包的语法树转换为编译器的AST
表示。这个额外的步骤将来可能会被重构。
然后对AST
进行类型检查。第一步是名称解析和类型推断,确定哪个对象属于哪个标识符,以及每个表达式具有哪个类型。类型检查包括某些额外的检查,例如“声明了且未使用的”的变量检查,以及确定函数是否停止。
某些转换也在AST
上完成的。有些节点根据类型信息进行了细化,例如将字符串添加从算术加法节点类型中分离出来。其他一些例子包括无效代码删除分析、函数调用内联和逃逸分析。
3. 通用 SSA
cmd/compile/internal/gc
(转换为SSA
)cmd/compile/internal/ssa
(SSA
传递和规则)
在这个阶段,AST
被转换为Static Single Assignment (SSA)
形式,这是一种具有特定属性的较低级的中间表现形式,可以更容易地实现优化并最终从中生成机器代码。
在此转换过程中,将会使用函数的内置函数。这些都是特殊的函数,编译器已经学会了在个别例子的基础上使用经过大量优化的代码来替代它。
在AST
到SSA
的转换过程中,某些节点也会被降级为更简单的组件,这样编译器的其余部分就可以使用它们。例如,内置的copy
函数会被内存移动替代,range
循环被重写为for
循环。由于历史原因,其中一些情况目前是发生在转换为SSA
之前,但长期计划是将所有这些放到这里处理。
然后,应用一系列与机器无关的通行证和规则。它们不会涉及任何单一的计算机体系结构,因此可以在所有GOARCH
变体上运行。
这些通用通过的一些例子包括无效代码删除,移除不必要的零值检查,以及移除未使用的分支。通用重写规则主要涉及表达式,例如用常量值替换某些表达式,以及优化乘法和浮点运算。
4. 生成机器代码
cmd/compile/internal/ssa
(SSA 降低和特定架构传递)cmd/internal/obj
(机器代码生成)
编译器与机器相关的阶段从lower
开始,它将通用的值重写为它们与机器相关的变量。例如,在amd64
架构上可以使用内存操作数,因此可以组合很多负载存储操作。
请注意,下层的传递运行所有特定机器的重写规则,因此它当前也做了许多优化。
一旦SSA
被lower
且更特定于目标体系架构,就会运行最终的代码优化传递。这包括另一个无效代码删除/值传递,移动更接近其用途的值,删除永远不会读取的本地变量,以及寄存器分配。
作为这个步骤的一部分,其他重要的工作还包括栈帧布局,该布局为局部变量分配堆栈偏移量,以及指针存活分析,它计算堆栈上哪些指针在每个GC
安全点处于活跃状态。
在SSA
生成阶段的末尾,Go 函数会被转换为一系列obj
程序指令。它们被传递给汇编程序(cmd/internal/obj
) ,然后将它们转换为机器代码并写出最终的目标文件。对象文件还将包含反射数据、导出数据和调试信息。
进一步阅读
如果你想要更深入了解 SSA 包的工作原理,包括它的传递和规则,请访问cmd/compile/internal/ssa/README.md[1].
参考资料
[1]
cmd/compile/internal/ssa/README.md:https://golang.org/src/cmd/compile/internal/ssa/README.md
欢迎关注Go招聘公众号,获取更多精彩内容。
后台资料分享
(后台回复以下数字获取对应资源)
100:Go简历模板 | 101:Go最全面试集锦 | 102:Go超级简历 |103:Go安全指南| 1024:LeetCode刷题指南 | 6379:redis集锦
往期精彩回顾
(点击关键词查看文章)
城市内推
北京 | 上海 | 深圳 | 杭州 | 广州 | 成都 | 西安| 重庆 | 珠海 | 非996 | 外企.远程办公
大厂招聘
百度 | 阿里 | 腾讯 | 字节跳动 | 360 | 安全企业| 京东 | 贝壳 | 滴滴 | 搜狗 | 新浪 | 探探|好未来 | 金山云 | 伴鱼 | 联通数科| ApiSix |AiBee |游戏公司 | 区块链 | 跨境电商| 电商
资源分享
Go项目| Go资源| Rust项目| Python项目| 前端项目|
面试专题
Golang专题