[疑难] [dmd bug]大家帮忙看一下if表达式内赋值为何失败

lifc 2009-08-07
这几天同事移植了一段代码到D,这一段反复调试都断言失败,各位帮忙看一下什么原因。

class ByteBuffer {
	uint idx, limit;
}

void main () {
	ByteBuffer bb = new ByteBuffer;
	uint offset;
	with (bb) {
		limit = idx;
		idx = 0;
		if (idx <= limit && (idx + (offset = 18) <= 100))
			assert(offset == 18);
	}
}


这是精简后的代码,里面加了一些无关语句为的是重现问题。若去掉一些语句或者调换顺序断言通过,所以怀疑又是编译器bug,因为只有用dmd -O编译才出现断言失败。
lifc 2009-08-07
看了反编译代码,确认是编译器问题,试过近几年的D1/D2各种版本只要加-O优化编译就统统有这个bug。ldc和gdc没问题,上面的简单程序因它们太聪明,直接优化省略掉了全部代码。

                cmp     EBX,0Ch[ESI]
                ja      L45
                push    EBX
                mov     EBX,012h
                mov     ECX,EBX
                pop     EBX ; <-------- 这里提前pop出ebx,覆盖了if里面赋值的18
                lea     EDX,[ECX][EBX]
                cmp     EDX,064h
                ja      L45
                cmp     EBX,012h
                je      L45
                mov     EAX,0Ch
                call    near ptr _D12assign_in_if8__assertFiZv@PC32
L45:            pop     ESI

最近遇到此类bug太多懒得上报了。刚刚在部门内部通报,不要把赋值语句写在if/while里面。大家以后写代码时自己小心吧!
lifc 2009-08-07
上面反编译代码也可以看出,dmd优化编译效率和它的胞兄dmc一样需要大大提高。我这里有些稍微复杂一点的函数逻辑用dmd -O编译2~3KB,而ldc/gdc -O2才6~7百字节。
tomqyp 2009-08-07
要说目标文件体积的话,出错的这段代码我感觉实在是没法再压缩了,可以说要结果正确话还非加两行不可了。

呵呵,再说你这表达式也太长了。我估计编译到你出错的地方编译器肯定想:“糟了,寄存器不够了!怎么办,用内存寻址?现在可是加了-O命令的啊,太折WB老人家的面子了吧,干脆给这小子省两行代码得了!”

其实我也就用D1写过几个自己用的小工具也经常遇到许多问题,不知道经常用D的高人们怎么看,我是觉得不能让WB无休止的把精力都放到新特性上去了。

再说我们遇到bug不能懒得上报,上报了是不知道什么时候会修补,不上报可能就没机会被修补了,特别是这么严重的bug。
lifc 2009-08-07
上面的代码只是一个最小化重现代码,但已经有几处无谓的寄存器迁移和stack访问了。比如说这几行汇编:
push    EBX
mov     EBX,012h
mov     ECX,EBX
pop     EBX ;
为何先push ebx再用ebx做中间寄存器向ecx传递,然后弹出ebx呢?虽没有仔细看过dmd、dmc的寄存器分配代码,但过去搞过集中单片机、dsp和假想机的编译器和JIT仿真器,感觉dmd和dmc缺少类似gcc必要的中间代码生成能力,致使它难以对操作码进行宏观优化。
对于gcc、lvm这样的高级编译器来说,上述代码完全可以优化成一句assert(true),如果编译器中加入了对assert的built in描述(例如gcc)甚至可以生成空输出。
lifc 2009-08-07
tomqyp 写道

再说我们遇到bug不能懒得上报,上报了是不知道什么时候会修补,不上报可能就没机会被修补了,特别是这么严重的bug。

从gdc还活跃的年代(06、07)年代就开始积极提交gdc和dmd的bug,这两个月我们组又报过4、5个。但是每次看到那几条3年前提交bug现躺还在bugzilla里面睡觉,就感觉提不起劲来...
tomqyp 2009-08-07
仔细看了一下,从编译器(WB)的思路来看pop ebx是有用的,之前ebx是初始化为0的,这时idx刚好也等于0,如果idx不等于0肯定也不会生成这样的代码,所以pop ebx不算提前也不能放到后面。

不过这时唯一能用的寄存器edx却没有善加利用,这段代码还是有优化的潜力的。
lifc 2009-08-07
有点好奇Walter难道没有基本的编译器测试套件吗?像寄存器分配、表达式评估顺序、参数传递这类测试对编译器开发者来说是最基本的助手,我这样的菜鸟当年都下载了一批gcc的套件来测试自己的编译器,是不是成了大牛的人就可以脱俗?前两天看到这里朋友发帖问最希望D做什么,对于这个问题我目前最直接的答案就是稳定,进一步说应该调整之前的开发策略,不要反复在类似问题上吃亏。
tomqyp 2009-08-07
lifc 写道
感觉dmd和dmc缺少类似gcc必要的中间代码生成能力,致使它难以对操作码进行宏观优化。
对于gcc、lvm这样的高级编译器来说,上述代码完全可以优化成一句assert(true),如果编译器中加入了对assert的built in描述(例如gcc)甚至可以生成空输出。


对,我只希望LDC快发布windows版了
lifc 2009-08-07
tomqyp 写道

对,我只希望LDC快发布windows版了

windows下的ldc至今缺少seh异常掌握,只能说明群众(特别是高手)对d的信心不足。至于内联汇编,和linux下应该没有什么区别,似乎只是缺少x64的inline汇编。
但愿ldc能成为一股使d腾飞的东风,不过最终结果还要看老大对ldc的态度和重视程度。
Global site tag (gtag.js) - Google Analytics