dmd源码指南
原文在此
所有D编译器
分为两部分
:前端和后端
前端:词法和解析d语法,实例化模板
.ldc(llvm)/gdc(gcc)/dmd(boost)
共享.
后端:生成代码,优化,输出目标文件
胶水层:连接前后端
.
编译周期
词法(令牌数组(lexer)
)–构建简单语法树(parser)
–然后三阶段语义处理(mars中,语义1,2,3)
依次接近最终表示(解析类型,实例化模板
)–
阶段 | 任务 |
---|---|
1语义 | 分析所有声明的完整签名 (聚集类型成员,函数参数和返回及变量类型,求值(pragma(msg)) ). |
2语义 | 声明的其他部分 (如变量声明初化器,静断条件下求值 ) |
3语义 | 分析函数声明主体 .如果函数 不在直接声明模块中编译(不在命令行) ,则不分析 |
由于解析前向引用
,每个阶段可能
调用后阶段
函数.
immutable string x = "hello";
static if (x == "hello") { ... }
//static if调用`x`的2语义阶段
auto foo() { ... }
typeof(&foo) fp;
//1阶段`fp`运行`3阶段foo`来推导返回类型
string foo() { ... }
mixin(foo());//ctfe,调用`3阶段foo`.
最后,传递语法树
至胶水层
,然后交给
后端产生机器码/目标文件
.
运行时互操作
在d运行时
中分配内存/操作数组
,编译器用_d_
样的勾挂
函数来整合运行时
.细节在此
细节(可能过时)
类型 | 意义 |
---|---|
符号 | 链接器相关 |
dt_t | 目标文件中待加数据 . |
元素 | 内部表示节点 |
在各种语法树节点
中生成代码
节点类型 | 必须定义方法 |
---|---|
语句类 | toIR , |
表达式 | toElem . |
初化器 和特定式 子类 | toDt . |
声明 | toObjFile . |
D符号 | toSymbol . |
在跑了3个语义段
后,如何快速遍历dmd的ir
.只晓得有个符号表
.
内联器
内联器
是前端
,其遍历语法树来查找函数
.通过计算是否值得
再内联.
其中,一些语句
不能为表达式
(如循环/抛
),因而,内联分两种,分别转换函数为语句(忽略返回值/调用(空/void)函数)/表达式(返回值时)
.这两种按不同路径
内联.因为一些语句
不能转成表达式
.
内联器,分为四部分.
部分 | 细节 |
---|---|
主入口点 | 利用InlineScanVisitor类 和expandInline 函数的inlineScan . |
分析成本(确定是否内联) | canInline和InlineCostVisitor类 |
按语句 | inlineAsStatement 及其嵌入类 |
按表达式 | doInline 及其嵌入类InlineStatement |
inlineScan
为入口
,主要工作由expandInline
完成.InlineScanVisitor
找到可内联函数
时,调用扩展内联
.根据式/语句
来相应内联
.如ExpStatement/CallExp
.最后由inlineAsStatement(语句)/doInline(式)
来搞.
后端
DMD
用el
元素来表示,枚举OPER
看操作.列举表达式
树中所有节点类型
,用-O --c
编译.得到各种优化
.其余未文档标志:
标志 | 意思 |
---|---|
--b | 显示优化块 |
--f | 完整输出 |
--r | 显示分配寄存器 |
--x | 抑制预定义的C++ 内容 |
--y | 显示中间语言(IL) 缓冲区输出 |
前端到后端最重要
入口为优化及生成代码
的writefunc
序号 | 动作 |
---|---|
1 | writefunc 设置参数,然后调用codgen 来生成函数体 代码. |
2 | 为每块生成代码,然后把变量 放进寄存器 . |
3 | 生成启动代码,窥孔 优化. |
4 | 优化跳 |
5 | codout 中发射代码. |
6 | 写开关表 |
7 | 写异常表 |
cgcod
中blcodgen
生成块代码
.处理块结束中/猜/如
生成块中,cod1.gencodelem
,只是调用codelem
.
cgcod.codelem
根据类型,为元素生成代码
.
cod1,cod2, cod3, cod4, and cod5.c
生成x86整
.cg87
生成浮点.x87
比较简单,不能处理公共子表达式
,因而效率低.
优化器
主要在go
中的optfunc
中.调用:
函数 | 作用 |
---|---|
blockopt(iter) | 优化基本块 |
constprop | 常折叠 |
copyprop | 复制 |
rmdeadass | 删死码 |
verybusyexp | 忙式 |
deadvar(gother.c) | 死变量 |
loopopt | 优化循环,删不变归纳变量,旋转循环 |
boolopt | 优化极 |
builddags | 公共子 |
el_convert | 浮串 至数据段 |
el_combine | 合并两表达式 |
localize | 改进式 的本地性 |
pinholeopt | 窥孔优化 |
生成代码
单独生成每个函数
代码.每个函数,放进自己的COMDAT
段.划分函数为块
,按跳/其他控制指令
连接.
注意idgen
用来生成id.h/c
,表示内置符号.
impcvngen
用来描述原语
间转换规则.生成impcnvtab
表.root.h
定义基类.用指针传递
类实例,在堆
上分配.
常见缩写
缩写 | 意思 |
---|---|
stc | 存储类 |
ILS | 内联状态 |
ir | 中间表示 |
AE | 可用式 |
CP | 复制传播 |
CSE | 消公子,消除公共子表达式 |
VBE | 很忙式 |
FFI | 外部接口 |
DbI | 自省设计 |
ICE | 内部编译错误 |
IFTI | 隐式函数模板实例化 |
NVI | 非虚口 |
UDA | 用定属 |
UDT | 用定型 |
技巧
用instantiatingModule(模板字段)
查找,哪个模块实例化了模板
.
-vcg-ast
输出生成代码前
的最后语法树
表示.用来调试模板/查找问题
.dmd -vcg-ast test.d
用resolve
来确定Type
是实际类型/表达式/符号
.traits.d
中有示例.
DSymbol
有toChars/toPrettyChars
来调试.
DSymbol
有kind
来得到类型.
用asttypename
打印语法树
节点动态名.
表达式
有个令牌
的op
字段,可Token.toChars(e.op)
这样输出.
打印浮字面:toReal
.
用isConst
检查式
是否为编译时
已知字面
.
注意编译时
声明与语句的区别.
mixin("int x;");
//上面为声明
void main()
{
mixin("int y;");//为语句.
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现