go cmd/compile: elide useless type assertion

vyswwuz2  于 6个月前  发布在  Go
关注(0)|答案(5)|浏览(47)

考虑以下情况:

type CustomUnmarshaler interface {
	CustomUnmarshal([]byte) error
}

type MyMessage struct{}

func (m *MyMessage) Unmarshal(b []byte) error {
	if u, ok := (interface{})(m).(CustomUnmarshaler); ok {
		return u.CustomUnmarshal(b)
	}
	return nil
}

在这种情况下,编译器知道 MyMessage 类型没有 CustomUnmarshal 方法,因此类型Assert不可能成功。在这种情况下,if语句的条件可以静态确定,并且可以认为代码块是死代码。
然而,一个提示构建的编译器仍然会为Assert发出代码。

0x0021 00033 (/tmp/main.go:10)	LEAQ	type."".CustomUnmarshaler(SB), AX
0x0028 00040 (/tmp/main.go:10)	MOVQ	AX, (SP)
0x002c 00044 (/tmp/main.go:10)	LEAQ	type.*"".Foo(SB), AX
0x0033 00051 (/tmp/main.go:10)	MOVQ	AX, 8(SP)
0x0038 00056 (/tmp/main.go:9)	MOVQ	"".f+64(SP), AX
0x003d 00061 (/tmp/main.go:10)	MOVQ	AX, 16(SP)
0x0042 00066 (/tmp/main.go:10)	PCDATA	$0, $1
0x0042 00066 (/tmp/main.go:10)	CALL	runtime.assertE2I2(SB)
0x0047 00071 (/tmp/main.go:10)	MOVQ	24(SP), AX
0x004c 00076 (/tmp/main.go:10)	MOVQ	32(SP), CX
0x0051 00081 (/tmp/main.go:10)	LEAQ	40(SP), DX
0x0056 00086 (/tmp/main.go:10)	CMPB	(DX), $0
0x0059 00089 (/tmp/main.go:10)	JEQ	161
0x005b 00091 (/tmp/main.go:11)	MOVQ	24(AX), AX
0x005f 00095 (/tmp/main.go:11)	MOVQ	"".b+72(SP), DX
0x0064 00100 (/tmp/main.go:11)	MOVQ	DX, 8(SP)
0x0069 00105 (/tmp/main.go:11)	MOVQ	"".b+80(SP), DX
0x006e 00110 (/tmp/main.go:11)	MOVQ	DX, 16(SP)
0x0073 00115 (/tmp/main.go:11)	MOVQ	"".b+88(SP), DX
0x0078 00120 (/tmp/main.go:11)	MOVQ	DX, 24(SP)
0x007d 00125 (/tmp/main.go:11)	MOVQ	CX, (SP)
0x0081 00129 (/tmp/main.go:11)	PCDATA	$0, $2
0x0081 00129 (/tmp/main.go:11)	CALL	AX
0x0083 00131 (/tmp/main.go:11)	MOVQ	32(SP), AX
0x0088 00136 (/tmp/main.go:11)	MOVQ	40(SP), CX
0x008d 00141 (/tmp/main.go:11)	MOVQ	AX, "".~r1+96(SP)
0x0092 00146 (/tmp/main.go:11)	MOVQ	CX, "".~r1+104(SP)
0x0097 00151 (/tmp/main.go:11)	MOVQ	48(SP), BP
0x009c 00156 (/tmp/main.go:11)	ADDQ	$56, SP
0x00a0 00160 (/tmp/main.go:11)	RET
lpwwtiir

lpwwtiir1#

我假设这些事情发生在内联过程中(随着我们对内联的更激进,它们将变得越来越常见)。
在构建SSA到运行时调用的过程中,类型转换会被降低。我已经尝试编写一些代码来延迟在类似情况下降低,但我找不到一个好的方法来布局运行时函数调用(例如:堆栈插槽)。这超出了我的能力范围。
如果有人更熟悉编译器,能提出一些实用工具,在SSA传递过程中添加一个函数调用,那将对我非常有帮助,以便开始努力延迟运行时调用的降低,利用高级语义带来的优化机会。

qlzsbp2j

qlzsbp2j2#

这些不可能的Assert在实际代码中到底有多少作用?(即优化可能产生的影响是什么?)
我假设这种情况主要发生在生成的代码中,但如果是这样的话,为了提高编译时间,避免一开始就发出多余的Assert不是更好吗?

k3bvogb1

k3bvogb13#

@bcmills 和 @rasky 关于内联导致这种情况发生的观点,我认为可能是今天这些事件的主要来源。例如,查看 https://godbolt.org/g/GzDvaUhttps://godbolt.org/g/N5W6Ua(在这两种情况下,对 f() 的调用都被内联了,但类型Assert仍然存在)。

(此外,但这在一个讨论的背景下是一个重要性较小的论点,要求代码生成器如此智能会大大复杂化它们)

uz75evzq

uz75evzq4#

跟踪接口背后的具体类型也将有助于#19361,从而降低调用开销,如果方法被调用,并且可能通过不让调用参数逃逸来降低GC开销。

ukdjmx9f

ukdjmx9f5#

我认为,关于内联,我们处于一种进退两难的境地:内联似乎并没有带来太大帮助,因为我们在优化器中并不擅长利用这些机会;而添加这样的优化可能会对工具速度产生影响,但收益不大,因为我们没有内联到应有的程度。

相关问题