你做了什么?
你好。我正在编写一些代码,并决定检查它生成的汇编指令。
https://godbolt.org/z/zFjGRF
你期望看到什么?
我期望看到没有冗余指令。
你看到了什么?
在第31行有一个冗余的条件跳转。
它是冗余的,因为从第24行到第31行的跳转发生在AX不等于0(即err不等于nil)的情况下。但是在第31行,条件跳转测试的是AX是否等于0,这是永远不会为真的。
你做了什么?
你好。我正在编写一些代码,并决定检查它生成的汇编指令。
https://godbolt.org/z/zFjGRF
你期望看到什么?
我期望看到没有冗余指令。
你看到了什么?
在第31行有一个冗余的条件跳转。
它是冗余的,因为从第24行到第31行的跳转发生在AX不等于0(即err不等于nil)的情况下。但是在第31行,条件跳转测试的是AX是否等于0,这是永远不会为真的。
7条答案
按热度按时间i5desfxk1#
是的,看起来很糟糕。
在SSA中查找,看起来我们没有为itabs使用一致的类型。有些是
uintptr
,有些是*uintptr
。这使得itabs不会被CSE(Common Subexpression Elimination,公共子表达式消除),从而保持分支的统一性。应该不难修复。留给1.13版本。
jtoj6r0c2#
这将保持itabs不被CSE,从而保持分支不被统一。
嗯。我看到了一些不同的东西。
uintptr
/*uint8
不匹配是因为一个 itab 与从该 itab 加载的类型描述符不匹配。在SSA的末尾,我们有一个完全为空的块,其种类和控制完全与其前驱匹配。我认为我们根本没有任何机制来处理这种情况中的块。我在trim
传递中添加了一个增强来处理这些情况中最明显的情况,它在 make.bash 期间触发了800多次。如果有人想在我做之前再看一眼(不知道什么时候会这样),这是我为可修剪块替换的替代方案:
在这里需要做的事情包括:使代码更美观,修复生成调试信息时引发的恐慌,处理倒置的块种类(即 NE b1 b2 === EQ b2 b1),并处理重复块不是其前驱的第一个后继者的情况(这需要在
trim
中修复调用代码)。cc @ysmolsky @mvdan
r9f1avp53#
代码:
经过CSE后,我们得到以下SSA:
v9
和v13
应该被CSE,我认为。但它们没有被合并,一个是uintptr
,另一个是*uintptr
。然后
IsNonNil
和NeqPtr
也需要被CSE。不确定这是否是一个单独的问题,还是在v9
和v13
统一后自然解决。3hvapo4f4#
Right. But after
decompose builtin
, bothv9
andv13
have been eliminated in favor ofv14
:Then lowered CSE manages to combine the
IsNonNil
andNeqPtr
into v19:(This dump is from two passes later, to eliminate the dead values)
So all is well, except that we don't eliminate the duplicate conditional block.
qcbq4gxm5#
我猜想如果比较是冗余的,那么证明过程会消除重复的代码块。这需要在降低阶段足够早地发生CSE(Common Subexpression Elimination)。你在降低之后修复它,而当前的CSE发生在这个时候,但到那时证明过程已经太晚了。所以你提议在修剪过程中添加一个简单的证明过程。当然,这会起作用,但我认为如果我们可以的话,最好能更早地捕获这个问题。
mdfafbf16#
有道理。似乎需要进行一些实验。顺便说一下,我可以告诉你,将特定的
*uint8
切换为uintptr
并不困难——我做了这个操作并发现它本身并没有解决这个问题,这就是为什么我进一步深入研究的原因。:)xwmevbvl7#
https://golang.org/cl/229984提到了这个问题:
cmd/compile: fix type of ssa OpITab Values