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
|
|
@ -320,6 +320,8 @@ func rewriteValuegeneric(v *Value, config *Config) bool {
|
|||
return rewriteValuegeneric_OpSliceLen(v, config)
|
||||
case OpSlicePtr:
|
||||
return rewriteValuegeneric_OpSlicePtr(v, config)
|
||||
case OpSlicemask:
|
||||
return rewriteValuegeneric_OpSlicemask(v, config)
|
||||
case OpSqrt:
|
||||
return rewriteValuegeneric_OpSqrt(v, config)
|
||||
case OpStore:
|
||||
|
|
@ -9793,6 +9795,73 @@ func rewriteValuegeneric_OpSlicePtr(v *Value, config *Config) bool {
|
|||
}
|
||||
return false
|
||||
}
|
||||
func rewriteValuegeneric_OpSlicemask(v *Value, config *Config) bool {
|
||||
b := v.Block
|
||||
_ = b
|
||||
// match: (Slicemask (Const32 [x]))
|
||||
// cond: x > 0
|
||||
// result: (Const32 [-1])
|
||||
for {
|
||||
v_0 := v.Args[0]
|
||||
if v_0.Op != OpConst32 {
|
||||
break
|
||||
}
|
||||
x := v_0.AuxInt
|
||||
if !(x > 0) {
|
||||
break
|
||||
}
|
||||
v.reset(OpConst32)
|
||||
v.AuxInt = -1
|
||||
return true
|
||||
}
|
||||
// match: (Slicemask (Const32 [0]))
|
||||
// cond:
|
||||
// result: (Const32 [0])
|
||||
for {
|
||||
v_0 := v.Args[0]
|
||||
if v_0.Op != OpConst32 {
|
||||
break
|
||||
}
|
||||
if v_0.AuxInt != 0 {
|
||||
break
|
||||
}
|
||||
v.reset(OpConst32)
|
||||
v.AuxInt = 0
|
||||
return true
|
||||
}
|
||||
// match: (Slicemask (Const64 [x]))
|
||||
// cond: x > 0
|
||||
// result: (Const64 [-1])
|
||||
for {
|
||||
v_0 := v.Args[0]
|
||||
if v_0.Op != OpConst64 {
|
||||
break
|
||||
}
|
||||
x := v_0.AuxInt
|
||||
if !(x > 0) {
|
||||
break
|
||||
}
|
||||
v.reset(OpConst64)
|
||||
v.AuxInt = -1
|
||||
return true
|
||||
}
|
||||
// match: (Slicemask (Const64 [0]))
|
||||
// cond:
|
||||
// result: (Const64 [0])
|
||||
for {
|
||||
v_0 := v.Args[0]
|
||||
if v_0.Op != OpConst64 {
|
||||
break
|
||||
}
|
||||
if v_0.AuxInt != 0 {
|
||||
break
|
||||
}
|
||||
v.reset(OpConst64)
|
||||
v.AuxInt = 0
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
func rewriteValuegeneric_OpSqrt(v *Value, config *Config) bool {
|
||||
b := v.Block
|
||||
_ = b
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue