mirror of https://github.com/golang/go.git
cmd/compile: change the way SSA does slice zero-cap detection
There is a special case for slicing s[i:j] when the resulting slice has zero capacity, to prevent pointing to the next object in memory. Change this special case code from: rptr := rcap == 0 ? ptr : ptr+i*elemsize to rptr := ptr + (rcap == 0 ? 0 : i) * elemsize This change leads to slightly smaller generated code, replacing a load with a register zero. old: 0x002e 00046 (slice.go:8) CMPQ BX, $0 0x0032 00050 (slice.go:8) JEQ $0, 78 0x0034 00052 (slice.go:8) MOVQ "".a+8(FP), BP 0x0039 00057 (slice.go:8) LEAQ (BP)(CX*8), AX 0x003e 00062 ... rest of function ... 0x004e 00078 (slice.go:7) MOVQ "".a+8(FP), AX 0x0053 00083 (slice.go:8) JMP 62 new: 0x002e 00046 (slice.go:8) CMPQ BX, $0 0x0032 00050 (slice.go:8) JEQ $0, 78 0x0034 00052 (slice.go:8) MOVQ "".a+8(FP), BP 0x0039 00057 (slice.go:8) LEAQ (BP)(CX*8), AX 0x003e 00062 ... rest of function... 0x004e 00078 (slice.go:8) MOVQ $0, CX 0x0050 00080 (slice.go:8) JMP 52 Change-Id: I2a396616b0d7b090c226a47c92a7ba14b128401f Reviewed-on: https://go-review.googlesource.com/20994 Reviewed-by: David Chase <drchase@google.com>
This commit is contained in:
parent
d37d3bdcfc
commit
69a7c152a7
|
|
@ -335,6 +335,7 @@ var (
|
|||
typVar = Node{Op: ONAME, Class: Pxxx, Sym: &Sym{Name: "typ"}}
|
||||
idataVar = Node{Op: ONAME, Class: Pxxx, Sym: &Sym{Name: "idata"}}
|
||||
okVar = Node{Op: ONAME, Class: Pxxx, Sym: &Sym{Name: "ok"}}
|
||||
deltaVar = Node{Op: ONAME, Class: Pxxx, Sym: &Sym{Name: "delta"}}
|
||||
)
|
||||
|
||||
// startBlock sets the current block we're generating code in to b.
|
||||
|
|
@ -3104,15 +3105,16 @@ func (s *state) slice(t *Type, v, i, j, k *ssa.Value) (p, l, c *ssa.Value) {
|
|||
// Generate the following code assuming that indexes are in bounds.
|
||||
// The conditional is to make sure that we don't generate a slice
|
||||
// that points to the next object in memory.
|
||||
// rlen = (Sub64 j i)
|
||||
// rcap = (Sub64 k i)
|
||||
// p = ptr
|
||||
// if rcap != 0 {
|
||||
// p = (AddPtr ptr (Mul64 low (Const64 size)))
|
||||
// rlen = j-i
|
||||
// rcap = k-i
|
||||
// delta = i*elemsize
|
||||
// if rcap == 0 {
|
||||
// delta = 0
|
||||
// }
|
||||
// result = (SliceMake p size)
|
||||
// rptr = p+delta
|
||||
// result = (SliceMake rptr rlen rcap)
|
||||
subOp := s.ssaOp(OSUB, Types[TINT])
|
||||
neqOp := s.ssaOp(ONE, Types[TINT])
|
||||
eqOp := s.ssaOp(OEQ, Types[TINT])
|
||||
mulOp := s.ssaOp(OMUL, Types[TINT])
|
||||
rlen := s.newValue2(subOp, Types[TINT], j, i)
|
||||
var rcap *ssa.Value
|
||||
|
|
@ -3128,36 +3130,38 @@ func (s *state) slice(t *Type, v, i, j, k *ssa.Value) (p, l, c *ssa.Value) {
|
|||
rcap = s.newValue2(subOp, Types[TINT], k, i)
|
||||
}
|
||||
|
||||
s.vars[&ptrVar] = ptr
|
||||
// delta = # of elements to offset pointer by.
|
||||
s.vars[&deltaVar] = i
|
||||
|
||||
// Generate code to test the resulting slice length.
|
||||
cmp := s.newValue2(neqOp, Types[TBOOL], rcap, s.constInt(Types[TINT], 0))
|
||||
// Generate code to set delta=0 if the resulting capacity is zero.
|
||||
if !((i.Op == ssa.OpConst64 && i.AuxInt == 0) ||
|
||||
(i.Op == ssa.OpConst32 && int32(i.AuxInt) == 0)) {
|
||||
cmp := s.newValue2(eqOp, Types[TBOOL], rcap, zero)
|
||||
|
||||
b := s.endBlock()
|
||||
b.Kind = ssa.BlockIf
|
||||
b.Likely = ssa.BranchLikely
|
||||
b.SetControl(cmp)
|
||||
b := s.endBlock()
|
||||
b.Kind = ssa.BlockIf
|
||||
b.Likely = ssa.BranchUnlikely
|
||||
b.SetControl(cmp)
|
||||
|
||||
// Generate code for non-zero length slice case.
|
||||
nz := s.f.NewBlock(ssa.BlockPlain)
|
||||
b.AddEdgeTo(nz)
|
||||
s.startBlock(nz)
|
||||
var inc *ssa.Value
|
||||
if elemtype.Width == 1 {
|
||||
inc = i
|
||||
} else {
|
||||
inc = s.newValue2(mulOp, Types[TINT], i, s.constInt(Types[TINT], elemtype.Width))
|
||||
// Generate block which zeros the delta variable.
|
||||
nz := s.f.NewBlock(ssa.BlockPlain)
|
||||
b.AddEdgeTo(nz)
|
||||
s.startBlock(nz)
|
||||
s.vars[&deltaVar] = zero
|
||||
s.endBlock()
|
||||
|
||||
// All done.
|
||||
merge := s.f.NewBlock(ssa.BlockPlain)
|
||||
b.AddEdgeTo(merge)
|
||||
nz.AddEdgeTo(merge)
|
||||
s.startBlock(merge)
|
||||
|
||||
// TODO: use conditional moves somehow?
|
||||
}
|
||||
s.vars[&ptrVar] = s.newValue2(ssa.OpAddPtr, ptrtype, ptr, inc)
|
||||
s.endBlock()
|
||||
|
||||
// All done.
|
||||
merge := s.f.NewBlock(ssa.BlockPlain)
|
||||
b.AddEdgeTo(merge)
|
||||
nz.AddEdgeTo(merge)
|
||||
s.startBlock(merge)
|
||||
rptr := s.variable(&ptrVar, ptrtype)
|
||||
delete(s.vars, &ptrVar)
|
||||
// Compute rptr = ptr + delta * elemsize
|
||||
rptr := s.newValue2(ssa.OpAddPtr, ptrtype, ptr, s.newValue2(mulOp, Types[TINT], s.variable(&deltaVar, Types[TINT]), s.constInt(Types[TINT], elemtype.Width)))
|
||||
delete(s.vars, &deltaVar)
|
||||
return rptr, rlen, rcap
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue