New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cmd/compile: same global variable loaded twice for function call argument #28484

Open
martisch opened this Issue Oct 30, 2018 · 5 comments

Comments

Projects
None yet
3 participants
@martisch
Member

martisch commented Oct 30, 2018

What version of Go are you using (go version)?

go version devel +2e9f0817f0 Tue Oct 30 04:39:53 2018 +0000 darwin/amd64

found this when benchmarking runtime.makeslice with make([]T, LenVar, LenVar) where LenVar was a global variable. However the issue can be shown with any function call where two arguments are loaded from the same global variable. The issue of unnecessary loading variables to often might come up in other contexts too. Filling for further investigation and possible general optimization.

Example:

var L = 0
var B bool

//go:noinline
func takesTwo(i, j int) bool {
	return i < j
}

func main() {
	B = takesTwo(L, L)
}

main.L is loaded twice to write the arguments for takesTwo to the stack:

  MOVQ main.L(SB), AX			
  MOVQ AX, 0(SP)				
  MOVQ main.L(SB), AX // Can be avoided	
  MOVQ AX, 0x8(SP)			
  CALL main.takesTwo(SB)			

expected:

  MOVQ main.L(SB), AX			
  MOVQ AX, 0(SP)				
  MOVQ AX, 0x8(SP)			
  CALL main.takesTwo(SB)			
@martisch

This comment has been minimized.

Member

martisch commented Oct 30, 2018

@agnivade

This comment has been minimized.

Member

agnivade commented Nov 9, 2018

This seems like a great issue to get one's hands dirty with the compiler during the freeze.

@josharian @martisch - Could you throw me a bone on where to start looking to investigate something like this ?

godoc is pretty much frozen, so I am ramping up on the dark arts of SSA. And I have passing familiarity with rewrite rules. But nothing more I'm afraid.

Apologies for a couple of beginner questions -

Should this be in some SSA pass ? (if so, which one ?) Should this be in a rewrite rule ? Should this be a new pass ?

@josharian

This comment has been minimized.

Contributor

josharian commented Nov 9, 2018

Hard to say without digging into it. I'd hope it could be a generic rewrite rule. I'd start by poking around ssa.html and understanding in detail the example code and seeing if you see a clear, generalizable way to fix it. However, as I was recently reminded by @mundaym, rewriting rule (and any SSA work) around memory operations are really tricky to get right. So this might prove not to be an ideal first place to experiment.

@agnivade

This comment has been minimized.

Member

agnivade commented Nov 9, 2018

Thanks ! Yes I have been looking into the ssa.html.

Essentially, we have something like this -

v4 (?) = Addr <*int> {"".L} v3
v5 (13) = Load <int> v4 v1
v6 (?) = OffPtr <*int> [0] v2
v7 (13) = Store <mem> {int} v6 v5 v1
v8 (?) = Addr <*int> {"".L} v3
v9 (13) = Load <int> v8 v7
v10 (?) = OffPtr <*int> [8] v2
v11 (13) = Store <mem> {int} v10 v9 v7
v12 (13) = StaticCall <mem> {"".takesTwo} [24] v11

What we would want is something like this -

v4 (?) = Addr <*int> {"".L} v3
v5 (13) = Load <int> v4 v1
v6 (?) = OffPtr <*int> [0] v2
v7 (13) = Store <mem> {int} v6 v5 v1 // v8 and v9 are redundant. So remove them.
v10 (?) = OffPtr <*int> [8] v2
v11 (13) = Store <mem> {int} v10 v5 v7 // replace v9 by v5
v12 (13) = StaticCall <mem> {"".takesTwo} [24] v11

I am not sure if this can be a rewrite rule. IIUC, we would need to check all params of a StaticCall and then replace a Load-Store with a Store using the already Loaded value.

As you say, will leave it for somebody else.

@josharian

This comment has been minimized.

Contributor

josharian commented Nov 9, 2018

At a glance, it seems to me that one route is to use alias analysis (currently called func disjoint) to recognize that v7 and v9 don’t overlap, then float the load before the store, and then eliminate the duplicate loads. Or some such memory re-ordering.

Related: It might also be worth looking at Philip Hofer’s old CL that brings alias analysis to the tighten pass. I wanted to get that revived this cycle but didn’t get to it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment