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: combine small loads #14267

Closed
randall77 opened this issue Feb 8, 2016 · 5 comments
Closed

cmd/compile: combine small loads #14267

randall77 opened this issue Feb 8, 2016 · 5 comments

Comments

@randall77
Copy link
Contributor

encoding/binary/binary.go:

func (littleEndian) Uint64(b []byte) uint64 {
    return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 |
        uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56
}

It would be nice to combine the small loads into one larger load, at least for architectures with unaligned loads.

See #14266 for the bug about combining the bounds checks. This bug is about combining the loads themselves. We could use rewrite rules something like:

(Or64 (Load <t> ptr mem) (Shl64x64 (Load <t> (Add64 ptr (Const64 [t.Size()])) mem) (Const64 [8*t.Size()]))) -> (Load ptr mem)

These rules would probably work independent of whether the bounds checks are fixed or not.

Maybe we could do stores also. That would require the bounds checks to go first, and the user to write to the max index first (otherwise partial writes would be observable).

@dsnet
Copy link
Member

dsnet commented Feb 8, 2016

Is this a duplicate of #11819?

@minux
Copy link
Member

minux commented Feb 8, 2016 via email

@dsnet
Copy link
Member

dsnet commented Feb 9, 2016

@minux, I don't see the relationship between memory access order and endianness; you can load from higher or lower address first regardless of the endianness. Unless you mean for code already in production with compatibility agreements?

As in the case of encoding/binary.PutUint64, where the indexes already start from a lower address, can't we do an initial bounds check that the length is >= 8? If yes, combine the stores, otherwise, fall back the original code.

That is, the compiler will implicitly convert the code to be:

func (bigEndian) PutUint64(b []byte, v uint64) {
    if len(b) >= 8 {
        // Combined store version of the code below.
        return
    }
    b[0] = byte(v >> 56)
    b[1] = byte(v >> 48)
    b[2] = byte(v >> 40)
    b[3] = byte(v >> 32)
    b[4] = byte(v >> 24)
    b[5] = byte(v >> 16)
    b[6] = byte(v >> 8)
    b[7] = byte(v)
}

This, ensures that we preserve the behavior of partial stores, but remains fast in the vastly-common case.

@gopherbot
Copy link

CL https://golang.org/cl/20218 mentions this issue.

gopherbot pushed a commit that referenced this issue Mar 6, 2016
This only deals with the loads themselves.  The bounds checks
are a separate issue.  Also doesn't handle stores, those are
harder because we need to make sure intermediate memory states
aren't observed (which is hard to do with rewrite rules).

Use one byte shorter instructions for zero-extending loads.

Update #14267

Change-Id: I40af25ab5208488151ba7db32bf96081878fa7d9
Reviewed-on: https://go-review.googlesource.com/20218
Reviewed-by: Alexandru Moșoi <alexandru@mosoi.ro>
Run-TryBot: Keith Randall <khr@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
@gopherbot
Copy link

CL https://golang.org/cl/22326 mentions this issue.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

4 participants