Skip to content
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: weird asymmetry in when constants get registers #33580

Closed
seebs opened this issue Aug 10, 2019 · 3 comments
Closed

cmd/compile: weird asymmetry in when constants get registers #33580

seebs opened this issue Aug 10, 2019 · 3 comments
Labels
FrozenDueToAge NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one. Performance
Milestone

Comments

@seebs
Copy link
Contributor

seebs commented Aug 10, 2019

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

1.12.

Does this issue reproduce with the latest release?

Seems to.

What operating system and processor architecture are you using (go env)?

amd64

What did you do?

STUPID THINGS. I got hypnotized by trying to mess with the code for a bit of bit-swizzling in order to improve compiler output. A helpful person in #performance on gopher slack pointed out that the compiler did a better job with constants if you assigned them to variables, and indeed, this is so.

Sometimes.

https://godbolt.org/z/ISgMpH

In this code, the relevant bits are four constants:

	hi16 = uint64(0xFFFF0000FFFF0000)
	lo16 = uint64(0x0000FFFF0000FFFF)
	hi8  = uint64(0xFF00FF00FF00FF00)
	lo8  = uint64(0x00FF00FF00FF00FF)

and some assignments to them:

    // uncommenting this produces shorter code
    // hi16, hi8 := hi16, hi8
    // uncommenting this has no effect
    // lo16, lo8 := lo16, lo8

and then a bunch of code using those values.

The code ends at line 174 of the assembly with both lines uncommented, or only the second uncommented. If the first is uncommented, it ends at line 160. But what's going on appears to be non-obvious; uncommenting that line isn't necessarily replacing instances of that value in the code with register references. If you split it out, each of the two "hi" values appears to cause a reduction of about 7 lines of code. Uncommenting the "lo" values has no effect.

Changing which value is which, or which kinds of shifts each value is used with, doesn't seem to change this, nor does changing the order they're used in. So it's not the sign bit, it's not "is used with left (or right) shifts", it's not "the one that gets used first gets priority"... I have no idea why they behave differently.

What did you expect to see?

I would expect the lines to have essentially interchangeable effects.

What did you see instead?

Lots of repeated loads of some values but not others.

@randall77
Copy link
Contributor

Looks like this kind of depends on luck of the draw. The results of the ANDQ must go into one of the input registers. If the register allocator picks the constant input, then that constant must be reloaded when it is used again. If it picks the variable input, then the constant is still in a register for the next use.

There's code in there to pick the input that is dead over the one that isn't. For some reason that code isn't doing the right thing. We'll look at this for 1.14.

bad

	0x00d2 00210 (issue33580.go:48)	MOVQ	$-71777214294589696, R11
	0x00dc 00220 (issue33580.go:48)	ANDQ	R13, R11
	0x00df 00223 (issue33580.go:48)	SHRQ	$8, R11
	0x00e3 00227 (issue33580.go:48)	MOVQ	$-71777214294589696, R12
	0x00ed 00237 (issue33580.go:48)	ANDQ	R15, R12
	0x00f0 00240 (issue33580.go:48)	ORQ	R12, R11
	0x00f3 00243 (issue33580.go:48)	MOVQ	R11, 8(AX)

good

	0x00d2 00210 (issue33580.go:48)	MOVQ	$-71777214294589696, R11
	0x00dc 00220 (issue33580.go:48)	ANDQ	R11, R13
	0x00df 00223 (issue33580.go:48)	SHRQ	$8, R13
	0x00e3 00227 (issue33580.go:48)	ANDQ	R11, R15
	0x00e6 00230 (issue33580.go:48)	ORQ	R15, R13
	0x00e9 00233 (issue33580.go:48)	MOVQ	R13, 8(AX)

@randall77 randall77 added this to the Go1.14 milestone Aug 10, 2019
@seebs
Copy link
Contributor Author

seebs commented Aug 10, 2019

Ohhh, interesting. I had been thinking of this as two separate issues -- one being reloading the constant for each set of uses, one being reloading it immediately for two consecutive uses -- but if the constant were inclined to stick around, it'd probably end up getting loaded once and used eight times, which would presumably affect performance at all.

Some of what's happening seems to be that the two sets of operations (one on the first four words, one on the second four words) are written interleaved, but the compiler quite reasonably collates them. Which I assume reduces register pressure, but also means that all the uses of a given constant aren't together.

There's some other weird stuff in here; moving the constant declarations to right above where they're used almost always makes them not get registers. I doubt that's related, but who knows, maybe it is.

@odeke-em odeke-em changed the title compiler: weird asymmetry in when constants get registers cmd/compile: weird asymmetry in when constants get registers Aug 11, 2019
@andybons andybons added the NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one. label Aug 12, 2019
@gopherbot
Copy link

Change https://golang.org/cl/199559 mentions this issue: cmd/compile: reuse dead register before reusing register holding constant

@golang golang locked and limited conversation to collaborators Oct 6, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
FrozenDueToAge NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one. Performance
Projects
None yet
Development

No branches or pull requests

4 participants