Skip to content

cmd/compile: Use dead code elimination after inlining for escape analysis #76957

@nicholasngai

Description

@nicholasngai

The Go compiler currently appears to be able to eliminate some amount of dead code that can be detected after inlining. However, it appears that escape analysis fails to take this into account. Take this program as an example:

package main

var g any

func foo(ptr *int, b bool) {
	if b {
		g = ptr
	}
}

func main() {
	a := 1
	foo(&a, false)
}

This generates the following assembly:

main.main STEXT size=46 args=0x0 locals=0x18 funcid=0x0 align=0x0
	0x0000 00000 (main.go:11)	TEXT	main.main(SB), ABIInternal, $24-0
	0x0000 00000 (main.go:11)	CMPQ	SP, 16(R14)
	0x0004 00004 (main.go:11)	PCDATA	$0, $-2
	0x0004 00004 (main.go:11)	JLS	39
	0x0006 00006 (main.go:11)	PCDATA	$0, $-1
	0x0006 00006 (main.go:11)	PUSHQ	BP
	0x0007 00007 (main.go:11)	MOVQ	SP, BP
	0x000a 00010 (main.go:11)	SUBQ	$16, SP
	0x000e 00014 (main.go:11)	FUNCDATA	$0, gclocals·FzY36IO2mY0y4dZ1+Izd/w==(SB)
	0x000e 00014 (main.go:11)	FUNCDATA	$1, gclocals·FzY36IO2mY0y4dZ1+Izd/w==(SB)
	0x000e 00014 (main.go:12)	LEAQ	type:int(SB), AX
	0x0015 00021 (main.go:12)	PCDATA	$1, $0
	0x0015 00021 (main.go:12)	CALL	runtime.newobject(SB)
	0x001a 00026 (main.go:12)	MOVQ	$1, (AX)
	0x0021 00033 (main.go:14)	ADDQ	$16, SP
	0x0025 00037 (main.go:14)	POPQ	BP
	0x0026 00038 (main.go:14)	RET
	0x0027 00039 (main.go:14)	NOP
	0x0027 00039 (main.go:11)	PCDATA	$1, $-1
	0x0027 00039 (main.go:11)	PCDATA	$0, $-2
	0x0027 00039 (main.go:11)	CALL	runtime.morestack_noctxt(SB)
	0x002c 00044 (main.go:11)	PCDATA	$0, $-1
	0x002c 00044 (main.go:11)	JMP	0
	0x0000 49 3b 66 10 76 21 55 48 89 e5 48 83 ec 10 48 8d  I;f.v!UH..H...H.
	0x0010 05 00 00 00 00 e8 00 00 00 00 48 c7 00 01 00 00  ..........H.....
	0x0020 00 48 83 c4 10 5d c3 e8 00 00 00 00 eb d2        .H...]........
	rel 2+0 t=R_USEIFACE type:*int+0
	rel 17+4 t=R_PCREL type:int+0
	rel 22+4 t=R_CALL runtime.newobject+0
	rel 40+4 t=R_CALL runtime.morestack_noctxt+0

The assembly indicates that foo is inlined to produce

func main() {
	a := 1
	if false {
		g = &a
	}
}

And g = &a is eliminated from the assembly altogether. However, the allocation (runtime.newobject) remains.

However, escape analysis fails to understand that a no longer escapes after dead code elimination after inlining. #74364 is already filed as a more general issue for control-flow-aware escape analysis, but I filed this as a separate issue because performing escape analysis after inlining + dead code elimination seems to. #74383 is also related as the devirtualized type switch seems to similarly be dead code analysis being ordered after escape analysis. But I still wanted to file this issue to capture the issue more broadly since that issue is fairly specific to devirtualized type switches.

Metadata

Metadata

Assignees

Labels

FeatureRequestIssues asking for a new feature that does not need a proposal.compiler/runtimeIssues related to the Go compiler and/or runtime.

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions