Commit 726a9398 authored by Michael Munday's avatar Michael Munday

cmd/compile/internal/gc: minor cleanup of slicing

Tidy the code up a little bit to move variable definitions closer
to uses, prefer early return to else branches and some other minor
tweaks.

I'd like to make some more changes to this code in the near future
and this CL should make those changes cleaner.

Change-Id: Ie7d7f2e4bb1e670347941e255c9cdc1703282db5
Reviewed-on: https://go-review.googlesource.com/c/go/+/170120
Run-TryBot: Michael Munday <mike.munday@ibm.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: default avatarJosh Bleecher Snyder <josharian@gmail.com>
parent 5fc55b31
...@@ -2415,7 +2415,7 @@ func (s *state) expr(n *Node) *ssa.Value { ...@@ -2415,7 +2415,7 @@ func (s *state) expr(n *Node) *ssa.Value {
if max != nil { if max != nil {
k = s.expr(max) k = s.expr(max)
} }
p, l, c := s.slice(n.Left.Type, v, i, j, k, n.Bounded()) p, l, c := s.slice(v, i, j, k, n.Bounded())
return s.newValue3(ssa.OpSliceMake, n.Type, p, l, c) return s.newValue3(ssa.OpSliceMake, n.Type, p, l, c)
case OSLICESTR: case OSLICESTR:
...@@ -2428,7 +2428,7 @@ func (s *state) expr(n *Node) *ssa.Value { ...@@ -2428,7 +2428,7 @@ func (s *state) expr(n *Node) *ssa.Value {
if high != nil { if high != nil {
j = s.expr(high) j = s.expr(high)
} }
p, l, _ := s.slice(n.Left.Type, v, i, j, nil, n.Bounded()) p, l, _ := s.slice(v, i, j, nil, n.Bounded())
return s.newValue2(ssa.OpStringMake, n.Type, p, l) return s.newValue2(ssa.OpStringMake, n.Type, p, l)
case OCALLFUNC: case OCALLFUNC:
...@@ -4359,35 +4359,25 @@ func (s *state) storeArg(n *Node, t *types.Type, off int64) { ...@@ -4359,35 +4359,25 @@ func (s *state) storeArg(n *Node, t *types.Type, off int64) {
// slice computes the slice v[i:j:k] and returns ptr, len, and cap of result. // slice computes the slice v[i:j:k] and returns ptr, len, and cap of result.
// i,j,k may be nil, in which case they are set to their default value. // i,j,k may be nil, in which case they are set to their default value.
// t is a slice, ptr to array, or string type. // v may be a slice, string or pointer to an array.
func (s *state) slice(t *types.Type, v, i, j, k *ssa.Value, bounded bool) (p, l, c *ssa.Value) { func (s *state) slice(v, i, j, k *ssa.Value, bounded bool) (p, l, c *ssa.Value) {
var elemtype *types.Type t := v.Type
var ptrtype *types.Type var ptr, len, cap *ssa.Value
var ptr *ssa.Value
var len *ssa.Value
var cap *ssa.Value
zero := s.constInt(types.Types[TINT], 0)
switch { switch {
case t.IsSlice(): case t.IsSlice():
elemtype = t.Elem() ptr = s.newValue1(ssa.OpSlicePtr, types.NewPtr(t.Elem()), v)
ptrtype = types.NewPtr(elemtype)
ptr = s.newValue1(ssa.OpSlicePtr, ptrtype, v)
len = s.newValue1(ssa.OpSliceLen, types.Types[TINT], v) len = s.newValue1(ssa.OpSliceLen, types.Types[TINT], v)
cap = s.newValue1(ssa.OpSliceCap, types.Types[TINT], v) cap = s.newValue1(ssa.OpSliceCap, types.Types[TINT], v)
case t.IsString(): case t.IsString():
elemtype = types.Types[TUINT8] ptr = s.newValue1(ssa.OpStringPtr, types.NewPtr(types.Types[TUINT8]), v)
ptrtype = types.NewPtr(elemtype)
ptr = s.newValue1(ssa.OpStringPtr, ptrtype, v)
len = s.newValue1(ssa.OpStringLen, types.Types[TINT], v) len = s.newValue1(ssa.OpStringLen, types.Types[TINT], v)
cap = len cap = len
case t.IsPtr(): case t.IsPtr():
if !t.Elem().IsArray() { if !t.Elem().IsArray() {
s.Fatalf("bad ptr to array in slice %v\n", t) s.Fatalf("bad ptr to array in slice %v\n", t)
} }
elemtype = t.Elem().Elem()
ptrtype = types.NewPtr(elemtype)
s.nilCheck(v) s.nilCheck(v)
ptr = v ptr = s.newValue1(ssa.OpCopy, types.NewPtr(t.Elem().Elem()), v)
len = s.constInt(types.Types[TINT], t.Elem().NumElem()) len = s.constInt(types.Types[TINT], t.Elem().NumElem())
cap = len cap = len
default: default:
...@@ -4396,7 +4386,7 @@ func (s *state) slice(t *types.Type, v, i, j, k *ssa.Value, bounded bool) (p, l, ...@@ -4396,7 +4386,7 @@ func (s *state) slice(t *types.Type, v, i, j, k *ssa.Value, bounded bool) (p, l,
// Set default values // Set default values
if i == nil { if i == nil {
i = zero i = s.constInt(types.Types[TINT], 0)
} }
if j == nil { if j == nil {
j = len j = len
...@@ -4433,46 +4423,52 @@ func (s *state) slice(t *types.Type, v, i, j, k *ssa.Value, bounded bool) (p, l, ...@@ -4433,46 +4423,52 @@ func (s *state) slice(t *types.Type, v, i, j, k *ssa.Value, bounded bool) (p, l,
i = s.boundsCheck(i, j, ssa.BoundsSliceB, bounded) i = s.boundsCheck(i, j, ssa.BoundsSliceB, bounded)
} }
// Generate the following code assuming that indexes are in bounds. // Word-sized integer operations.
// The masking is to make sure that we don't generate a slice
// that points to the next object in memory.
// rlen = j - i
// rcap = k - i
// delta = i * elemsize
// rptr = p + delta&mask(rcap)
// result = (SliceMake rptr rlen rcap)
// where mask(x) is 0 if x==0 and -1 if x>0.
subOp := s.ssaOp(OSUB, types.Types[TINT]) subOp := s.ssaOp(OSUB, types.Types[TINT])
mulOp := s.ssaOp(OMUL, types.Types[TINT]) mulOp := s.ssaOp(OMUL, types.Types[TINT])
andOp := s.ssaOp(OAND, types.Types[TINT]) andOp := s.ssaOp(OAND, types.Types[TINT])
rlen := s.newValue2(subOp, types.Types[TINT], j, i)
var rcap *ssa.Value // Calculate the length (rlen) and capacity (rcap) of the new slice.
switch { // For strings the capacity of the result is unimportant. However,
case t.IsString(): // we use rcap to test if we've generated a zero-length slice.
// Capacity of the result is unimportant. However, we use
// rcap to test if we've generated a zero-length slice.
// Use length of strings for that. // Use length of strings for that.
rcap = rlen rlen := s.newValue2(subOp, types.Types[TINT], j, i)
case j == k: rcap := rlen
rcap = rlen if j != k && !t.IsString() {
default:
rcap = s.newValue2(subOp, types.Types[TINT], k, i) rcap = s.newValue2(subOp, types.Types[TINT], k, i)
} }
var rptr *ssa.Value
if (i.Op == ssa.OpConst64 || i.Op == ssa.OpConst32) && i.AuxInt == 0 { if (i.Op == ssa.OpConst64 || i.Op == ssa.OpConst32) && i.AuxInt == 0 {
// No pointer arithmetic necessary. // No pointer arithmetic necessary.
rptr = ptr return ptr, rlen, rcap
} else { }
// delta = # of bytes to offset pointer by.
delta := s.newValue2(mulOp, types.Types[TINT], i, s.constInt(types.Types[TINT], elemtype.Width)) // Calculate the base pointer (rptr) for the new slice.
//
// Generate the following code assuming that indexes are in bounds.
// The masking is to make sure that we don't generate a slice
// that points to the next object in memory. We cannot just set
// the pointer to nil because then we would create a nil slice or
// string.
//
// rcap = k - i
// rlen = j - i
// rptr = ptr + (mask(rcap) & (i * stride))
//
// Where mask(x) is 0 if x==0 and -1 if x>0 and stride is the width
// of the element type.
stride := s.constInt(types.Types[TINT], ptr.Type.Elem().Width)
// The delta is the number of bytes to offset ptr by.
delta := s.newValue2(mulOp, types.Types[TINT], i, stride)
// If we're slicing to the point where the capacity is zero, // If we're slicing to the point where the capacity is zero,
// zero out the delta. // zero out the delta.
mask := s.newValue1(ssa.OpSlicemask, types.Types[TINT], rcap) mask := s.newValue1(ssa.OpSlicemask, types.Types[TINT], rcap)
delta = s.newValue2(andOp, types.Types[TINT], delta, mask) delta = s.newValue2(andOp, types.Types[TINT], delta, mask)
// Compute rptr = ptr + delta
rptr = s.newValue2(ssa.OpAddPtr, ptrtype, ptr, delta) // Compute rptr = ptr + delta.
} rptr := s.newValue2(ssa.OpAddPtr, ptr.Type, ptr, delta)
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