Repository: go
Issue: cmd/compile: needlessly early return value loads in runtime.scanobject
Labels: Performance,compiler/runtime

runtime.scanobject contains this bit of code:

```go
// Mark the object.
if obj, hbits, span, objIndex := heapBitsForObject(obj, b, i); obj != 0 {
	greyobject(obj, b, i, hbits, span, gcw, objIndex)
}
```

This compiles to (excerpt):

```
	0x024b 00587 (/Users/josh/go/tip/src/runtime/mgcmark.go:1180)	MOVQ	R11, (SP)
	0x024f 00591 (/Users/josh/go/tip/src/runtime/mgcmark.go:1180)	MOVQ	BX, 8(SP)
	0x0254 00596 (/Users/josh/go/tip/src/runtime/mgcmark.go:1180)	MOVQ	R8, 16(SP)
	0x0259 00601 (/Users/josh/go/tip/src/runtime/mgcmark.go:1180)	PCDATA	$0, $3
	0x0259 00601 (/Users/josh/go/tip/src/runtime/mgcmark.go:1180)	CALL	"".heapBitsForObject(SB)
	0x025e 00606 (/Users/josh/go/tip/src/runtime/mgcmark.go:1180)	MOVL	40(SP), AX
	0x0262 00610 (/Users/josh/go/tip/src/runtime/mgcmark.go:1180)	MOVQ	24(SP), CX
	0x0267 00615 (/Users/josh/go/tip/src/runtime/mgcmark.go:1180)	MOVQ	48(SP), DX
	0x026c 00620 (/Users/josh/go/tip/src/runtime/mgcmark.go:1180)	MOVQ	56(SP), BX
	0x0271 00625 (/Users/josh/go/tip/src/runtime/mgcmark.go:1180)	MOVQ	32(SP), SI
	0x0276 00630 (/Users/josh/go/tip/src/runtime/mgcmark.go:1180)	TESTQ	CX, CX
	0x0279 00633 (/Users/josh/go/tip/src/runtime/mgcmark.go:1180)	JNE	$0, 683
	0x027b 00635 (/Users/josh/go/tip/src/runtime/mgcmark.go:1178)	MOVQ	"".arena_used+96(SP), AX
	0x0280 00640 (/Users/josh/go/tip/src/runtime/mgcmark.go:1160)	MOVL	"".h.shift+68(SP), CX
	0x0284 00644 (/Users/josh/go/tip/src/runtime/mgcmark.go:1178)	MOVQ	""..autotmp_2642+112(SP), DX
	0x0289 00649 (/Users/josh/go/tip/src/runtime/mgcmark.go:1174)	MOVQ	"".b+168(FP), BX
	0x0291 00657 (/Users/josh/go/tip/src/runtime/mgcmark.go:1160)	MOVQ	"".h.bitp+128(SP), SI
	0x0299 00665 (/Users/josh/go/tip/src/runtime/mgcmark.go:1153)	MOVQ	"".n+80(SP), DI
	0x029e 00670 (/Users/josh/go/tip/src/runtime/mgcmark.go:1153)	MOVQ	"".i+88(SP), R8
	0x02a3 00675 (/Users/josh/go/tip/src/runtime/mgcmark.go:1160)	MOVL	CX, R9
	0x02a6 00678 (/Users/josh/go/tip/src/runtime/mgcmark.go:1178)	JMP	548
	0x02ab 00683 (/Users/josh/go/tip/src/runtime/mgcmark.go:1181)	MOVQ	CX, (SP)
	0x02af 00687 (/Users/josh/go/tip/src/runtime/mgcmark.go:1181)	MOVQ	"".b+168(FP), CX
	0x02b7 00695 (/Users/josh/go/tip/src/runtime/mgcmark.go:1181)	MOVQ	CX, 8(SP)
	0x02bc 00700 (/Users/josh/go/tip/src/runtime/mgcmark.go:1181)	MOVQ	"".i+88(SP), DI
	0x02c1 00705 (/Users/josh/go/tip/src/runtime/mgcmark.go:1181)	MOVQ	DI, 16(SP)
	0x02c6 00710 (/Users/josh/go/tip/src/runtime/mgcmark.go:1181)	MOVQ	SI, 24(SP)
	0x02cb 00715 (/Users/josh/go/tip/src/runtime/mgcmark.go:1181)	MOVL	AX, 32(SP)
	0x02cf 00719 (/Users/josh/go/tip/src/runtime/mgcmark.go:1181)	MOVQ	DX, 40(SP)
	0x02d4 00724 (/Users/josh/go/tip/src/runtime/mgcmark.go:1181)	MOVQ	"".gcw+176(FP), AX
	0x02dc 00732 (/Users/josh/go/tip/src/runtime/mgcmark.go:1181)	MOVQ	AX, 48(SP)
	0x02e1 00737 (/Users/josh/go/tip/src/runtime/mgcmark.go:1181)	MOVQ	BX, 56(SP)
	0x02e6 00742 (/Users/josh/go/tip/src/runtime/mgcmark.go:1181)	PCDATA	$0, $3
	0x02e6 00742 (/Users/josh/go/tip/src/runtime/mgcmark.go:1181)	CALL	"".greyobject(SB)
	0x02eb 00747 (/Users/josh/go/tip/src/runtime/mgcmark.go:1180)	JMP	635
```

The loads at instructions 0x025e, 0x0267, 0x026c, and 0x0271 are too early. They're loading return values from heapBitsForObject, but if the call to greyobject isn't necessary (if the jump at 0x0279 isn't taken), their values are unnecessary and will be overwritten. This is easy enough to see in the original code as well.

The loads are scheduled where they are due to memory ordering. But maybe there's something we can do to improve the situation, perhaps using the knowledge that stack slots and function return values are always disjoint in memory?

cc @randall77 @dr2chase @cherrymui