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(式)来搞.

后端

DMDel元素来表示,枚举OPER看操作.列举表达式树中所有节点类型,用-O --c编译.得到各种优化.其余未文档标志:

标志意思
--b显示优化块
--f完整输出
--r显示分配寄存器
--x抑制预定义的C++内容
--y显示中间语言(IL)缓冲区输出

前端到后端最重要入口为优化及生成代码writefunc

序号动作
1writefunc设置参数,然后调用codgen来生成函数体代码.
2为每块生成代码,然后把变量放进寄存器.
3生成启动代码,窥孔优化.
4优化跳
5codout中发射代码.
6开关表
7异常表

cgcodblcodgen生成块代码.处理块结束中/猜/如
生成块中,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中有示例.
DSymboltoChars/toPrettyChars来调试.
DSymbolkind来得到类型.
asttypename打印语法树节点动态名.
表达式有个令牌op字段,可Token.toChars(e.op)这样输出.
打印浮字面:toReal.
isConst检查是否为编译时已知字面.
注意编译时声明与语句的区别.

mixin("int x;");
//上面为声明
void main()
{
    mixin("int y;");//为语句.
}
posted @   zjh6  阅读(36)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示