]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile: change the way SSA does slice zero-cap detection
authorKeith Randall <khr@golang.org>
Mon, 21 Mar 2016 22:24:08 +0000 (15:24 -0700)
committerKeith Randall <khr@golang.org>
Tue, 22 Mar 2016 02:21:20 +0000 (02:21 +0000)
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>
src/cmd/compile/internal/gc/ssa.go

index 9ee942b8b23a8c4232b9f7349ca1a6b91446cd08..7467acb02891d7c2f6921a482afcd90b90f808ea 100644 (file)
@@ -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
 }