mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
cmd/compile: use masks instead of branches for slicing
When we do
var x []byte = ...
y := x[i:]
We can't just use y.ptr = x.ptr + i, as the new pointer may point to the
next object in memory after the backing array.
We used to fix this by doing:
y.cap = x.cap - i
delta := i
if y.cap == 0 {
delta = 0
}
y.ptr = x.ptr + delta
That generates a branch in what is otherwise straight-line code.
Better to do:
y.cap = x.cap - i
mask := (y.cap - 1) >> 63 // -1 if y.cap==0, 0 otherwise
y.ptr = x.ptr + i &^ mask
It's about the same number of instructions (~4, depending on what
parts are constant, and the target architecture), but it is all
inline. It plays nicely with CSE, and the mask can be computed
in parallel with the index (in cases where a multiply is required).
It is a minor win in both speed and space.
Change-Id: Ied60465a0b8abb683c02208402e5bb7ac0e8370f
Reviewed-on: https://go-review.googlesource.com/32022
Run-TryBot: Keith Randall <khr@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Cherry Zhang <cherryyz@google.com>
This commit is contained in:
parent
50f66fbb66
commit
deb4177cf0
21 changed files with 325 additions and 56 deletions
|
|
@ -568,6 +568,44 @@ func updateRestrictions(parent *Block, ft *factsTable, t domain, v, w *Value, r
|
|||
// simplifyBlock simplifies block known the restrictions in ft.
|
||||
// Returns which branch must always be taken.
|
||||
func simplifyBlock(ft *factsTable, b *Block) branch {
|
||||
for _, v := range b.Values {
|
||||
if v.Op != OpSlicemask {
|
||||
continue
|
||||
}
|
||||
add := v.Args[0]
|
||||
if add.Op != OpAdd64 && add.Op != OpAdd32 {
|
||||
continue
|
||||
}
|
||||
// Note that the arg of slicemask was originally a sub, but
|
||||
// was rewritten to an add by generic.rules (if the thing
|
||||
// being subtracted was a constant).
|
||||
x := add.Args[0]
|
||||
y := add.Args[1]
|
||||
if x.Op == OpConst64 || x.Op == OpConst32 {
|
||||
x, y = y, x
|
||||
}
|
||||
if y.Op != OpConst64 && y.Op != OpConst32 {
|
||||
continue
|
||||
}
|
||||
// slicemask(x + y)
|
||||
// if x is larger than -y (y is negative), then slicemask is -1.
|
||||
lim, ok := ft.limits[x.ID]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
if lim.umin > uint64(-y.AuxInt) {
|
||||
if v.Args[0].Op == OpAdd64 {
|
||||
v.reset(OpConst64)
|
||||
} else {
|
||||
v.reset(OpConst32)
|
||||
}
|
||||
if b.Func.pass.debug > 0 {
|
||||
b.Func.Config.Warnl(v.Line, "Proved slicemask not needed")
|
||||
}
|
||||
v.AuxInt = -1
|
||||
}
|
||||
}
|
||||
|
||||
if b.Kind != BlockIf {
|
||||
return unknown
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue