原文在此
所有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;");//为语句.
}