diff options
| author | Keith Randall <khr@golang.org> | 2016-03-21 15:24:08 -0700 |
|---|---|---|
| committer | Keith Randall <khr@golang.org> | 2016-03-22 02:21:20 +0000 |
| commit | 69a7c152a72c713032498bfbc6ec7c41d84a4b63 (patch) | |
| tree | aa32e2a2c37d7eeeadaa13dae815b878bbbfa7bf /src | |
| parent | d37d3bdcfc429168adac5bf046172fd9c07bfdc2 (diff) | |
| download | go-69a7c152a72c713032498bfbc6ec7c41d84a4b63.tar.xz | |
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>
Diffstat (limited to 'src')
| -rw-r--r-- | src/cmd/compile/internal/gc/ssa.go | 68 |
1 files changed, 36 insertions, 32 deletions
diff --git a/src/cmd/compile/internal/gc/ssa.go b/src/cmd/compile/internal/gc/ssa.go index 9ee942b8b2..7467acb028 100644 --- a/src/cmd/compile/internal/gc/ssa.go +++ b/src/cmd/compile/internal/gc/ssa.go @@ -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 } |
