Commit 69a7c152 authored by Keith Randall's avatar Keith Randall

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/20994Reviewed-by: default avatarDavid Chase <drchase@google.com>
parent d37d3bdc
...@@ -335,6 +335,7 @@ var ( ...@@ -335,6 +335,7 @@ var (
typVar = Node{Op: ONAME, Class: Pxxx, Sym: &Sym{Name: "typ"}} typVar = Node{Op: ONAME, Class: Pxxx, Sym: &Sym{Name: "typ"}}
idataVar = Node{Op: ONAME, Class: Pxxx, Sym: &Sym{Name: "idata"}} idataVar = Node{Op: ONAME, Class: Pxxx, Sym: &Sym{Name: "idata"}}
okVar = Node{Op: ONAME, Class: Pxxx, Sym: &Sym{Name: "ok"}} 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. // 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) { ...@@ -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. // Generate the following code assuming that indexes are in bounds.
// The conditional is to make sure that we don't generate a slice // The conditional is to make sure that we don't generate a slice
// that points to the next object in memory. // that points to the next object in memory.
// rlen = (Sub64 j i) // rlen = j-i
// rcap = (Sub64 k i) // rcap = k-i
// p = ptr // delta = i*elemsize
// if rcap != 0 { // if rcap == 0 {
// p = (AddPtr ptr (Mul64 low (Const64 size))) // delta = 0
// } // }
// result = (SliceMake p size) // rptr = p+delta
// result = (SliceMake rptr rlen rcap)
subOp := s.ssaOp(OSUB, Types[TINT]) subOp := s.ssaOp(OSUB, Types[TINT])
neqOp := s.ssaOp(ONE, Types[TINT]) eqOp := s.ssaOp(OEQ, Types[TINT])
mulOp := s.ssaOp(OMUL, Types[TINT]) mulOp := s.ssaOp(OMUL, Types[TINT])
rlen := s.newValue2(subOp, Types[TINT], j, i) rlen := s.newValue2(subOp, Types[TINT], j, i)
var rcap *ssa.Value 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) { ...@@ -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) 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. // Generate code to set delta=0 if the resulting capacity is zero.
cmp := s.newValue2(neqOp, Types[TBOOL], rcap, s.constInt(Types[TINT], 0)) 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 := s.endBlock()
b.Kind = ssa.BlockIf b.Kind = ssa.BlockIf
b.Likely = ssa.BranchLikely b.Likely = ssa.BranchUnlikely
b.SetControl(cmp) b.SetControl(cmp)
// Generate code for non-zero length slice case. // Generate block which zeros the delta variable.
nz := s.f.NewBlock(ssa.BlockPlain) nz := s.f.NewBlock(ssa.BlockPlain)
b.AddEdgeTo(nz) b.AddEdgeTo(nz)
s.startBlock(nz) s.startBlock(nz)
var inc *ssa.Value s.vars[&deltaVar] = zero
if elemtype.Width == 1 { s.endBlock()
inc = i
} else { // All done.
inc = s.newValue2(mulOp, Types[TINT], i, s.constInt(Types[TINT], elemtype.Width)) 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. // Compute rptr = ptr + delta * elemsize
merge := s.f.NewBlock(ssa.BlockPlain) rptr := s.newValue2(ssa.OpAddPtr, ptrtype, ptr, s.newValue2(mulOp, Types[TINT], s.variable(&deltaVar, Types[TINT]), s.constInt(Types[TINT], elemtype.Width)))
b.AddEdgeTo(merge) delete(s.vars, &deltaVar)
nz.AddEdgeTo(merge)
s.startBlock(merge)
rptr := s.variable(&ptrVar, ptrtype)
delete(s.vars, &ptrVar)
return rptr, rlen, rcap return rptr, rlen, rcap
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment