我不确定现在是否有可能触发这个bug,但我认为可能存在一个问题。
考虑如下代码:
func f(x uint32) uint64 {
return uint64(x & 0xFFFFFFFF)
}
最外层操作是 ZeroExt32to64
,它被降低为 MOVLQZX
。最内层操作最终是 (ANDLconst [0xFFFFFFFF] x)
。
然后这条规则触发: (MOVLQZX x) && zeroUpper32Bits(x,3) -> x
。 ANDLconst
是在列表中被列为清零寄存器上32位的操作之一,所以我们消除了零扩展。
然后这条规则触发: (ANDLconst [c] x) && int32(c)==-1 -> x
,消除了 ANDLconst
。
这使我们只剩下 x
,但没有任何零扩展,这可能会在寄存器的上半部分留下垃圾。
就目前而言,这种情况不会发生在这个函数中,因为 And32 在通用优化过程中被消除。但是有办法让 & -1
通过通用优化,例如使用常数移位,这就是我发现这个问题的方式。在这种情况下,我们也得益于使用 MOVL 从参数加载值。但我们也可以使用计算值代替。所以我还没有说服自己,认为对于正确的输入,这实际上不会导致不良的代码生成。
有两种可能的诊断/修复方法:
- zeroUpper32Bits 假设内部操作实际上会被执行,这是错误的,在这种情况下,我们需要减少可接受的操作列表,可能只保留加载操作,我认为在那一点上无法消除(?),因为 dse 发生得更早
- ANDLconst 规则是不可靠的,因为消除它会消除清零寄存器上半部分的副作用
我强烈倾向于第一个诊断和修复方法。你有什么想法吗?
7条答案
按热度按时间watbbzwu1#
我从未对我们的整个符号扩展故事感到非常满意。在与机器无关的空间中,我认为我们做得很好,但在与机器相关的空间中,我们玩得非常随意。也许我们可以找到一些不变性,以便保证只使用值中存在的位数。因此,将有两个有效的
ANDLconst
,一个具有32位类型,另一个具有64位类型。前者可以删除ANDLconst [-1]
,但后者不行。gv8xihay2#
同意。同时,我们也未能移除一堆多余的扩展名
这种方法听起来不错,假设细节工作得当。它可能会导致操作和规则数量的爆炸(这已经是一个问题),并且在转换时可能会很棘手。
我不认为我想加入解决这个问题的行列。:)
kqqjbcuj3#
对我来说也是这样。我也不太高兴看到扩展被移除。
(ANDLconst [c] x) && int32(c)==-1 -> x
我认为我们应该只在类型为32位宽或更小时这样做。但是我们如何保持类型的准确性呢?
(MOVLQZX x) && zeroUpper32Bits(x,3) -> x
LHS是64位宽,而RHS是32位宽。这种规则一直让我感到困扰。也许我们可以有一种保留类型的方法来做这件事?比如
(op x:(op2 ...)) -> (op2 <t> ...)
?(这基本上是在新类型中复制x(不是OpCopy,而是复制x的表达式)。)
puruo6ea4#
https://golang.org/cl/220499提到了这个问题:
cmd/compile: mark Lsyms as readonly earlier
55ooxyrt5#
https://golang.org/cl/226957提到了这个问题:
internal/lsp/regtest: dump gopls logs on test failure
yxyvkwin6#
我猜我们1.15版本没有做任何事情。现在转到1.16里程碑。
5anewei67#
由于目前没有计划处理此问题,将其状态更改为"未计划"。