Commit f12bd8a5 authored by Josh Bleecher Snyder's avatar Josh Bleecher Snyder

cmd/compile: encapsulate OSLICE* representation

As a nice side-effect, this allows us to
unify several code paths.

The terminology (low, high, max, simple slice expr,
full slice expr) is taken from the spec and
the examples in the spec.

This is a trial run. The plan, probably for Go 1.8,
is to change slice expressions to use Node.List
instead of OKEY, and to do some similar
tree structure changes for other ops.

Passes toolstash -cmp. No performance change.
all.bash passes with GO_GCFLAGS=-newexport.

Updates #15350

Change-Id: Ic1efdc36e79cdb95ae1636e9817a3ac8f83ab1ac
Reviewed-on: https://go-review.googlesource.com/22425Reviewed-by: 's avatarMatthew Dempsky <mdempsky@google.com>
parent 2bf7034d
...@@ -1191,12 +1191,15 @@ func (p *exporter) expr(n *Node) { ...@@ -1191,12 +1191,15 @@ func (p *exporter) expr(n *Node) {
case OSLICE, OSLICESTR, OSLICEARR: case OSLICE, OSLICESTR, OSLICEARR:
p.op(OSLICE) p.op(OSLICE)
p.expr(n.Left) p.expr(n.Left)
p.expr(n.Right) low, high, _ := n.SliceBounds()
p.exprsOrNil(low, high)
case OSLICE3, OSLICE3ARR: case OSLICE3, OSLICE3ARR:
p.op(OSLICE3) p.op(OSLICE3)
p.expr(n.Left) p.expr(n.Left)
p.expr(n.Right) low, high, max := n.SliceBounds()
p.exprsOrNil(low, high)
p.expr(max)
case OCOPY, OCOMPLEX: case OCOPY, OCOMPLEX:
p.op(op) p.op(op)
......
...@@ -822,9 +822,19 @@ func (p *importer) node() *Node { ...@@ -822,9 +822,19 @@ func (p *importer) node() *Node {
// case OINDEX, OINDEXMAP, OSLICE, OSLICESTR, OSLICEARR, OSLICE3, OSLICE3ARR: // case OINDEX, OINDEXMAP, OSLICE, OSLICESTR, OSLICEARR, OSLICE3, OSLICE3ARR:
// unreachable - mapped to cases below by exporter // unreachable - mapped to cases below by exporter
case OINDEX, OSLICE, OSLICE3: case OINDEX:
return Nod(op, p.expr(), p.expr()) return Nod(op, p.expr(), p.expr())
case OSLICE, OSLICE3:
n := Nod(op, p.expr(), nil)
low, high := p.exprsOrNil()
var max *Node
if n.Op.IsSlice3() {
max = p.expr()
}
n.SetSliceBounds(low, high, max)
return n
case OCOPY, OCOMPLEX: case OCOPY, OCOMPLEX:
n := builtinCall(op) n := builtinCall(op)
n.List.Set([]*Node{p.expr(), p.expr()}) n.List.Set([]*Node{p.expr(), p.expr()})
......
...@@ -3106,15 +3106,7 @@ func cgen_slice(n, res *Node, wb bool) { ...@@ -3106,15 +3106,7 @@ func cgen_slice(n, res *Node, wb bool) {
x.Xoffset -= 2 * int64(Widthptr) x.Xoffset -= 2 * int64(Widthptr)
} }
var x1, x2, x3 *Node // unevaluated index arguments x1, x2, x3 := n.SliceBounds() // unevaluated index arguments
x1 = n.Right.Left
switch n.Op {
default:
x2 = n.Right.Right
case OSLICE3, OSLICE3ARR:
x2 = n.Right.Right.Left
x3 = n.Right.Right.Right
}
// load computes src into targ, but if src refers to the len or cap of n.Left, // load computes src into targ, but if src refers to the len or cap of n.Left,
// load copies those from xlen, xcap, loading xlen if needed. // load copies those from xlen, xcap, loading xlen if needed.
......
...@@ -1312,17 +1312,29 @@ func exprfmt(n *Node, prec int) string { ...@@ -1312,17 +1312,29 @@ func exprfmt(n *Node, prec int) string {
f += fmt.Sprintf(".(%v)", n.Type) f += fmt.Sprintf(".(%v)", n.Type)
return f return f
case OINDEX, case OINDEX, OINDEXMAP:
OINDEXMAP, return fmt.Sprintf("%s[%v]", exprfmt(n.Left, nprec), n.Right)
OSLICE,
OSLICESTR, case OSLICE, OSLICESTR, OSLICEARR, OSLICE3, OSLICE3ARR:
OSLICEARR, var buf bytes.Buffer
OSLICE3, buf.WriteString(exprfmt(n.Left, nprec))
OSLICE3ARR: buf.WriteString("[")
var f string low, high, max := n.SliceBounds()
f += exprfmt(n.Left, nprec) if low != nil {
f += fmt.Sprintf("[%v]", n.Right) buf.WriteString(low.String())
return f }
buf.WriteString(":")
if high != nil {
buf.WriteString(high.String())
}
if n.Op.IsSlice3() {
buf.WriteString(":")
if max != nil {
buf.WriteString(max.String())
}
}
buf.WriteString("]")
return buf.String()
case OCOPY, OCOMPLEX: case OCOPY, OCOMPLEX:
return fmt.Sprintf("%v(%v, %v)", Oconv(n.Op, FmtSharp), n.Left, n.Right) return fmt.Sprintf("%v(%v, %v)", Oconv(n.Op, FmtSharp), n.Left, n.Right)
......
...@@ -754,7 +754,7 @@ func mkinlcall1(n *Node, fn *Node, isddd bool) *Node { ...@@ -754,7 +754,7 @@ func mkinlcall1(n *Node, fn *Node, isddd bool) *Node {
vararrtype := typArray(varargtype.Elem(), int64(varargcount)) vararrtype := typArray(varargtype.Elem(), int64(varargcount))
as.Right = Nod(OCOMPLIT, nil, typenod(vararrtype)) as.Right = Nod(OCOMPLIT, nil, typenod(vararrtype))
as.Right.List.Set(varargs) as.Right.List.Set(varargs)
as.Right = Nod(OSLICE, as.Right, Nod(OKEY, nil, nil)) as.Right = Nod(OSLICE, as.Right, nil)
} }
as = typecheck(as, Etop) as = typecheck(as, Etop)
......
...@@ -1123,24 +1123,16 @@ func orderexpr(n *Node, order *Order, lhs *Node) *Node { ...@@ -1123,24 +1123,16 @@ func orderexpr(n *Node, order *Order, lhs *Node) *Node {
n = ordercopyexpr(n, n.Type, order, 0) n = ordercopyexpr(n, n.Type, order, 0)
} }
case OSLICE, OSLICEARR, OSLICESTR: case OSLICE, OSLICEARR, OSLICESTR, OSLICE3, OSLICE3ARR:
n.Left = orderexpr(n.Left, order, nil) n.Left = orderexpr(n.Left, order, nil)
n.Right.Left = orderexpr(n.Right.Left, order, nil) low, high, max := n.SliceBounds()
n.Right.Left = ordercheapexpr(n.Right.Left, order) low = orderexpr(low, order, nil)
n.Right.Right = orderexpr(n.Right.Right, order, nil) low = ordercheapexpr(low, order)
n.Right.Right = ordercheapexpr(n.Right.Right, order) high = orderexpr(high, order, nil)
if lhs == nil || lhs.Op != ONAME && !samesafeexpr(lhs, n.Left) { high = ordercheapexpr(high, order)
n = ordercopyexpr(n, n.Type, order, 0) max = orderexpr(max, order, nil)
} max = ordercheapexpr(max, order)
n.SetSliceBounds(low, high, max)
case OSLICE3, OSLICE3ARR:
n.Left = orderexpr(n.Left, order, nil)
n.Right.Left = orderexpr(n.Right.Left, order, nil)
n.Right.Left = ordercheapexpr(n.Right.Left, order)
n.Right.Right.Left = orderexpr(n.Right.Right.Left, order, nil)
n.Right.Right.Left = ordercheapexpr(n.Right.Right.Left, order)
n.Right.Right.Right = orderexpr(n.Right.Right.Right, order, nil)
n.Right.Right.Right = ordercheapexpr(n.Right.Right.Right, order)
if lhs == nil || lhs.Op != ONAME && !samesafeexpr(lhs, n.Left) { if lhs == nil || lhs.Op != ONAME && !samesafeexpr(lhs, n.Left) {
n = ordercopyexpr(n, n.Type, order, 0) n = ordercopyexpr(n, n.Type, order, 0)
} }
......
...@@ -1408,20 +1408,17 @@ loop: ...@@ -1408,20 +1408,17 @@ loop:
} }
x = Nod(OINDEX, x, i) x = Nod(OINDEX, x, i)
case 1: case 1:
i := index[0] x = Nod(OSLICE, x, nil)
j := index[1] x.SetSliceBounds(index[0], index[1], nil)
x = Nod(OSLICE, x, Nod(OKEY, i, j))
case 2: case 2:
i := index[0] if index[1] == nil {
j := index[1]
k := index[2]
if j == nil {
Yyerror("middle index required in 3-index slice") Yyerror("middle index required in 3-index slice")
} }
if k == nil { if index[2] == nil {
Yyerror("final index required in 3-index slice") Yyerror("final index required in 3-index slice")
} }
x = Nod(OSLICE3, x, Nod(OKEY, i, Nod(OKEY, j, k))) x = Nod(OSLICE3, x, nil)
x.SetSliceBounds(index[0], index[1], index[2])
default: default:
panic("unreachable") panic("unreachable")
......
...@@ -307,7 +307,11 @@ func instrumentnode(np **Node, init *Nodes, wr int, skip int) { ...@@ -307,7 +307,11 @@ func instrumentnode(np **Node, init *Nodes, wr int, skip int) {
case OSLICE, OSLICEARR, OSLICE3, OSLICE3ARR, OSLICESTR: case OSLICE, OSLICEARR, OSLICE3, OSLICE3ARR, OSLICESTR:
instrumentnode(&n.Left, init, 0, 0) instrumentnode(&n.Left, init, 0, 0)
instrumentnode(&n.Right, init, 0, 0) low, high, max := n.SliceBounds()
instrumentnode(&low, init, 0, 0)
instrumentnode(&high, init, 0, 0)
instrumentnode(&max, init, 0, 0)
n.SetSliceBounds(low, high, max)
goto ret goto ret
case OKEY: case OKEY:
......
...@@ -727,7 +727,7 @@ func slicelit(ctxt int, n *Node, var_ *Node, init *Nodes) { ...@@ -727,7 +727,7 @@ func slicelit(ctxt int, n *Node, var_ *Node, init *Nodes) {
arraylit(ctxt, 2, n, vstat, init) arraylit(ctxt, 2, n, vstat, init)
// copy static to slice // copy static to slice
a := Nod(OSLICE, vstat, Nod(OKEY, nil, nil)) a := Nod(OSLICE, vstat, nil)
a = Nod(OAS, var_, a) a = Nod(OAS, var_, a)
a = typecheck(a, Etop) a = typecheck(a, Etop)
...@@ -851,7 +851,7 @@ func slicelit(ctxt int, n *Node, var_ *Node, init *Nodes) { ...@@ -851,7 +851,7 @@ func slicelit(ctxt int, n *Node, var_ *Node, init *Nodes) {
} }
// make slice out of heap (6) // make slice out of heap (6)
a = Nod(OAS, var_, Nod(OSLICE, vauto, Nod(OKEY, nil, nil))) a = Nod(OAS, var_, Nod(OSLICE, vauto, nil))
a = typecheck(a, Etop) a = typecheck(a, Etop)
a = orderstmtinplace(a) a = orderstmtinplace(a)
...@@ -1391,7 +1391,8 @@ func genAsInitNoCheck(n *Node, reportOnly bool) bool { ...@@ -1391,7 +1391,8 @@ func genAsInitNoCheck(n *Node, reportOnly bool) bool {
fallthrough fallthrough
case OSLICEARR: case OSLICEARR:
if nr.Right.Op != OKEY || nr.Right.Left != nil || nr.Right.Right != nil { low, high, _ := nr.SliceBounds()
if low != nil || high != nil {
return false return false
} }
nr = nr.Left nr = nr.Left
......
...@@ -736,14 +736,7 @@ func (s *state) stmt(n *Node) { ...@@ -736,14 +736,7 @@ func (s *state) stmt(n *Node) {
if rhs != nil && (rhs.Op == OSLICE || rhs.Op == OSLICE3 || rhs.Op == OSLICESTR) && samesafeexpr(rhs.Left, n.Left) { if rhs != nil && (rhs.Op == OSLICE || rhs.Op == OSLICE3 || rhs.Op == OSLICESTR) && samesafeexpr(rhs.Left, n.Left) {
// We're assigning a slicing operation back to its source. // We're assigning a slicing operation back to its source.
// Don't write back fields we aren't changing. See issue #14855. // Don't write back fields we aren't changing. See issue #14855.
i := rhs.Right.Left i, j, k := rhs.SliceBounds()
var j, k *Node
if rhs.Op == OSLICE3 {
j = rhs.Right.Right.Left
k = rhs.Right.Right.Right
} else {
j = rhs.Right.Right
}
if i != nil && (i.Op == OLITERAL && i.Val().Ctype() == CTINT && i.Int64() == 0) { if i != nil && (i.Op == OLITERAL && i.Val().Ctype() == CTINT && i.Int64() == 0) {
// [0:...] is the same as [:...] // [0:...] is the same as [:...]
i = nil i = nil
...@@ -2038,38 +2031,34 @@ func (s *state) expr(n *Node) *ssa.Value { ...@@ -2038,38 +2031,34 @@ func (s *state) expr(n *Node) *ssa.Value {
} }
return s.newValue2(ssa.OpIMake, n.Type, tab, data) return s.newValue2(ssa.OpIMake, n.Type, tab, data)
case OSLICE, OSLICEARR: case OSLICE, OSLICEARR, OSLICE3, OSLICE3ARR:
v := s.expr(n.Left) v := s.expr(n.Left)
var i, j *ssa.Value var i, j, k *ssa.Value
if n.Right.Left != nil { low, high, max := n.SliceBounds()
i = s.extendIndex(s.expr(n.Right.Left)) if low != nil {
i = s.extendIndex(s.expr(low))
} }
if n.Right.Right != nil { if high != nil {
j = s.extendIndex(s.expr(n.Right.Right)) j = s.extendIndex(s.expr(high))
} }
p, l, c := s.slice(n.Left.Type, v, i, j, nil) if max != nil {
k = s.extendIndex(s.expr(max))
}
p, l, c := s.slice(n.Left.Type, v, i, j, k)
return s.newValue3(ssa.OpSliceMake, n.Type, p, l, c) return s.newValue3(ssa.OpSliceMake, n.Type, p, l, c)
case OSLICESTR: case OSLICESTR:
v := s.expr(n.Left) v := s.expr(n.Left)
var i, j *ssa.Value var i, j *ssa.Value
if n.Right.Left != nil { low, high, _ := n.SliceBounds()
i = s.extendIndex(s.expr(n.Right.Left)) if low != nil {
i = s.extendIndex(s.expr(low))
} }
if n.Right.Right != nil { if high != nil {
j = s.extendIndex(s.expr(n.Right.Right)) j = s.extendIndex(s.expr(high))
} }
p, l, _ := s.slice(n.Left.Type, v, i, j, nil) p, l, _ := s.slice(n.Left.Type, v, i, j, nil)
return s.newValue2(ssa.OpStringMake, n.Type, p, l) return s.newValue2(ssa.OpStringMake, n.Type, p, l)
case OSLICE3, OSLICE3ARR:
v := s.expr(n.Left)
var i *ssa.Value
if n.Right.Left != nil {
i = s.extendIndex(s.expr(n.Right.Left))
}
j := s.extendIndex(s.expr(n.Right.Right.Left))
k := s.extendIndex(s.expr(n.Right.Right.Right))
p, l, c := s.slice(n.Left.Type, v, i, j, k)
return s.newValue3(ssa.OpSliceMake, n.Type, p, l, c)
case OCALLFUNC: case OCALLFUNC:
if isIntrinsicCall1(n) { if isIntrinsicCall1(n) {
......
...@@ -1024,6 +1024,68 @@ func Is64(t *Type) bool { ...@@ -1024,6 +1024,68 @@ func Is64(t *Type) bool {
return false return false
} }
// SliceBounds returns n's slice bounds: low, high, and max in expr[low:high:max].
// n must be a slice expression. max is nil if n is a simple slice expression.
func (n *Node) SliceBounds() (low, high, max *Node) {
switch n.Op {
case OSLICE, OSLICEARR, OSLICESTR:
if n.Right == nil {
return nil, nil, nil
}
if n.Right.Op != OKEY {
Fatalf("SliceBounds right %s", opnames[n.Right.Op])
}
return n.Right.Left, n.Right.Right, nil
case OSLICE3, OSLICE3ARR:
if n.Right.Op != OKEY || n.Right.Right.Op != OKEY {
Fatalf("SliceBounds right %s %s", opnames[n.Right.Op], opnames[n.Right.Right.Op])
}
return n.Right.Left, n.Right.Right.Left, n.Right.Right.Right
}
Fatalf("SliceBounds op %s: %v", n.Op, n)
return nil, nil, nil
}
// SetSliceBounds sets n's slice bounds, where n is a slice expression.
// n must be a slice expression. If max is non-nil, n must be a full slice expression.
func (n *Node) SetSliceBounds(low, high, max *Node) {
switch n.Op {
case OSLICE, OSLICEARR, OSLICESTR:
if max != nil {
Fatalf("SetSliceBounds %s given three bounds", n.Op)
}
if n.Right == nil {
n.Right = Nod(OKEY, low, high)
return
}
n.Right.Left = low
n.Right.Right = high
return
case OSLICE3, OSLICE3ARR:
if n.Right == nil {
n.Right = Nod(OKEY, low, Nod(OKEY, high, max))
}
n.Right.Left = low
n.Right.Right.Left = high
n.Right.Right.Right = max
return
}
Fatalf("SetSliceBounds op %s: %v", n.Op, n)
}
// IsSlice3 reports whether o is a slice3 op (OSLICE3, OSLICE3ARR).
// o must be a slicing op.
func (o Op) IsSlice3() bool {
switch o {
case OSLICE, OSLICEARR, OSLICESTR:
return false
case OSLICE3, OSLICE3ARR:
return true
}
Fatalf("IsSlice3 op %v", o)
return false
}
// Is a conversion between t1 and t2 a no-op? // Is a conversion between t1 and t2 a no-op?
func Noconv(t1 *Type, t2 *Type) bool { func Noconv(t1 *Type, t2 *Type) bool {
e1 := Simtype[t1.Etype] e1 := Simtype[t1.Etype]
......
...@@ -1105,14 +1105,19 @@ OpSwitch: ...@@ -1105,14 +1105,19 @@ OpSwitch:
n.Type = nil n.Type = nil
break OpSwitch break OpSwitch
case OSLICE: case OSLICE, OSLICE3:
ok |= Erv ok |= Erv
n.Left = typecheck(n.Left, top) n.Left = typecheck(n.Left, top)
n.Right.Left = typecheck(n.Right.Left, Erv) low, high, max := n.SliceBounds()
n.Right.Right = typecheck(n.Right.Right, Erv) hasmax := n.Op.IsSlice3()
low = typecheck(low, Erv)
high = typecheck(high, Erv)
max = typecheck(max, Erv)
n.Left = defaultlit(n.Left, nil) n.Left = defaultlit(n.Left, nil)
n.Right.Left = indexlit(n.Right.Left) low = indexlit(low)
n.Right.Right = indexlit(n.Right.Right) high = indexlit(high)
max = indexlit(max)
n.SetSliceBounds(low, high, max)
l := n.Left l := n.Left
if l.Type.IsArray() { if l.Type.IsArray() {
if !islvalue(n.Left) { if !islvalue(n.Left) {
...@@ -1134,78 +1139,22 @@ OpSwitch: ...@@ -1134,78 +1139,22 @@ OpSwitch:
} }
var tp *Type var tp *Type
if t.IsString() { if t.IsString() {
n.Type = t if hasmax {
n.Op = OSLICESTR
} else if t.IsPtr() && t.Elem().IsArray() {
tp = t.Elem()
n.Type = typSlice(tp.Elem())
dowidth(n.Type)
n.Op = OSLICEARR
} else if t.IsSlice() {
n.Type = t
} else {
Yyerror("cannot slice %v (type %v)", l, t)
n.Type = nil
return n
}
lo := n.Right.Left
if lo != nil && !checksliceindex(l, lo, tp) {
n.Type = nil
return n
}
hi := n.Right.Right
if hi != nil && !checksliceindex(l, hi, tp) {
n.Type = nil
return n
}
if !checksliceconst(lo, hi) {
n.Type = nil
return n
}
break OpSwitch
case OSLICE3:
ok |= Erv
n.Left = typecheck(n.Left, top)
n.Right.Left = typecheck(n.Right.Left, Erv)
n.Right.Right.Left = typecheck(n.Right.Right.Left, Erv)
n.Right.Right.Right = typecheck(n.Right.Right.Right, Erv)
n.Left = defaultlit(n.Left, nil)
n.Right.Left = indexlit(n.Right.Left)
n.Right.Right.Left = indexlit(n.Right.Right.Left)
n.Right.Right.Right = indexlit(n.Right.Right.Right)
l := n.Left
if l.Type.IsArray() {
if !islvalue(n.Left) {
Yyerror("invalid operation %v (slice of unaddressable value)", n)
n.Type = nil
return n
}
n.Left = Nod(OADDR, n.Left, nil)
n.Left.Implicit = true
n.Left = typecheck(n.Left, Erv)
l = n.Left
}
t := l.Type
if t == nil {
n.Type = nil
return n
}
if t.IsString() {
Yyerror("invalid operation %v (3-index slice of string)", n) Yyerror("invalid operation %v (3-index slice of string)", n)
n.Type = nil n.Type = nil
return n return n
} }
n.Type = t
var tp *Type n.Op = OSLICESTR
if t.IsPtr() && t.Elem().IsArray() { } else if t.IsPtr() && t.Elem().IsArray() {
tp = t.Elem() tp = t.Elem()
n.Type = typSlice(tp.Elem()) n.Type = typSlice(tp.Elem())
dowidth(n.Type) dowidth(n.Type)
if hasmax {
n.Op = OSLICE3ARR n.Op = OSLICE3ARR
} else {
n.Op = OSLICEARR
}
} else if t.IsSlice() { } else if t.IsSlice() {
n.Type = t n.Type = t
} else { } else {
...@@ -1214,22 +1163,19 @@ OpSwitch: ...@@ -1214,22 +1163,19 @@ OpSwitch:
return n return n
} }
lo := n.Right.Left if low != nil && !checksliceindex(l, low, tp) {
if lo != nil && !checksliceindex(l, lo, tp) {
n.Type = nil n.Type = nil
return n return n
} }
mid := n.Right.Right.Left if high != nil && !checksliceindex(l, high, tp) {
if mid != nil && !checksliceindex(l, mid, tp) {
n.Type = nil n.Type = nil
return n return n
} }
hi := n.Right.Right.Right if max != nil && !checksliceindex(l, max, tp) {
if hi != nil && !checksliceindex(l, hi, tp) {
n.Type = nil n.Type = nil
return n return n
} }
if !checksliceconst(lo, hi) || !checksliceconst(lo, mid) || !checksliceconst(mid, hi) { if !checksliceconst(low, high) || !checksliceconst(low, max) || !checksliceconst(high, max) {
n.Type = nil n.Type = nil
return n return n
} }
......
...@@ -1241,30 +1241,20 @@ opswitch: ...@@ -1241,30 +1241,20 @@ opswitch:
case ORECV: case ORECV:
Fatalf("walkexpr ORECV") // should see inside OAS only Fatalf("walkexpr ORECV") // should see inside OAS only
case OSLICE, OSLICEARR, OSLICESTR: case OSLICE, OSLICEARR, OSLICESTR, OSLICE3, OSLICE3ARR:
n.Left = walkexpr(n.Left, init) n.Left = walkexpr(n.Left, init)
n.Right.Left = walkexpr(n.Right.Left, init) low, high, max := n.SliceBounds()
if n.Right.Left != nil && iszero(n.Right.Left) { low = walkexpr(low, init)
// Reduce x[0:j] to x[:j]. if low != nil && iszero(low) {
n.Right.Left = nil // Reduce x[0:j] to x[:j] and x[0:j:k] to x[:j:k].
} low = nil
n.Right.Right = walkexpr(n.Right.Right, init) }
n = reduceSlice(n) high = walkexpr(high, init)
max = walkexpr(max, init)
case OSLICE3, OSLICE3ARR: n.SetSliceBounds(low, high, max)
n.Left = walkexpr(n.Left, init) if n.Op.IsSlice3() {
n.Right.Left = walkexpr(n.Right.Left, init) if max != nil && max.Op == OCAP && samesafeexpr(n.Left, max.Left) {
if n.Right.Left != nil && iszero(n.Right.Left) {
// Reduce x[0:j:k] to x[:j:k].
n.Right.Left = nil
}
n.Right.Right.Left = walkexpr(n.Right.Right.Left, init)
n.Right.Right.Right = walkexpr(n.Right.Right.Right, init)
r := n.Right.Right.Right
if r != nil && r.Op == OCAP && samesafeexpr(n.Left, r.Left) {
// Reduce x[i:j:cap(x)] to x[i:j]. // Reduce x[i:j:cap(x)] to x[i:j].
n.Right.Right = n.Right.Right.Left
if n.Op == OSLICE3 { if n.Op == OSLICE3 {
n.Op = OSLICE n.Op = OSLICE
} else { } else {
...@@ -1272,6 +1262,9 @@ opswitch: ...@@ -1272,6 +1262,9 @@ opswitch:
} }
n = reduceSlice(n) n = reduceSlice(n)
} }
} else {
n = reduceSlice(n)
}
case OADDR: case OADDR:
n.Left = walkexpr(n.Left, init) n.Left = walkexpr(n.Left, init)
...@@ -1425,7 +1418,8 @@ opswitch: ...@@ -1425,7 +1418,8 @@ opswitch:
a := Nod(OAS, var_, nil) // zero temp a := Nod(OAS, var_, nil) // zero temp
a = typecheck(a, Etop) a = typecheck(a, Etop)
init.Append(a) init.Append(a)
r := Nod(OSLICE, var_, Nod(OKEY, nil, l)) // arr[:l] r := Nod(OSLICE, var_, nil) // arr[:l]
r.SetSliceBounds(nil, l, nil)
r = conv(r, n.Type) // in case n.Type is named. r = conv(r, n.Type) // in case n.Type is named.
r = typecheck(r, Erv) r = typecheck(r, Erv)
r = walkexpr(r, init) r = walkexpr(r, init)
...@@ -1596,13 +1590,15 @@ opswitch: ...@@ -1596,13 +1590,15 @@ opswitch:
return n return n
} }
// TODO(josharian): combine this with its caller and simplify
func reduceSlice(n *Node) *Node { func reduceSlice(n *Node) *Node {
r := n.Right.Right low, high, max := n.SliceBounds()
if r != nil && r.Op == OLEN && samesafeexpr(n.Left, r.Left) { if high != nil && high.Op == OLEN && samesafeexpr(n.Left, high.Left) {
// Reduce x[i:len(x)] to x[i:]. // Reduce x[i:len(x)] to x[i:].
n.Right.Right = nil high = nil
} }
if (n.Op == OSLICE || n.Op == OSLICESTR) && n.Right.Left == nil && n.Right.Right == nil { n.SetSliceBounds(low, high, max)
if (n.Op == OSLICE || n.Op == OSLICESTR) && low == nil && high == nil {
// Reduce x[:] to x. // Reduce x[:] to x.
if Debug_slice > 0 { if Debug_slice > 0 {
Warn("slice: omit slice operation") Warn("slice: omit slice operation")
...@@ -2816,14 +2812,15 @@ func appendslice(n *Node, init *Nodes) *Node { ...@@ -2816,14 +2812,15 @@ func appendslice(n *Node, init *Nodes) *Node {
l = append(l, nif) l = append(l, nif)
// s = s[:n] // s = s[:n]
nt := Nod(OSLICE, s, Nod(OKEY, nil, nn)) nt := Nod(OSLICE, s, nil)
nt.SetSliceBounds(nil, nn, nil)
nt.Etype = 1 nt.Etype = 1
l = append(l, Nod(OAS, s, nt)) l = append(l, Nod(OAS, s, nt))
if haspointers(l1.Type.Elem()) { if haspointers(l1.Type.Elem()) {
// copy(s[len(l1):], l2) // copy(s[len(l1):], l2)
nptr1 := Nod(OSLICE, s, Nod(OKEY, Nod(OLEN, l1, nil), nil)) nptr1 := Nod(OSLICE, s, nil)
nptr1.SetSliceBounds(Nod(OLEN, l1, nil), nil, nil)
nptr1.Etype = 1 nptr1.Etype = 1
nptr2 := l2 nptr2 := l2
fn := syslook("typedslicecopy") fn := syslook("typedslicecopy")
...@@ -2835,8 +2832,8 @@ func appendslice(n *Node, init *Nodes) *Node { ...@@ -2835,8 +2832,8 @@ func appendslice(n *Node, init *Nodes) *Node {
} else if instrumenting { } else if instrumenting {
// rely on runtime to instrument copy. // rely on runtime to instrument copy.
// copy(s[len(l1):], l2) // copy(s[len(l1):], l2)
nptr1 := Nod(OSLICE, s, Nod(OKEY, Nod(OLEN, l1, nil), nil)) nptr1 := Nod(OSLICE, s, nil)
nptr1.SetSliceBounds(Nod(OLEN, l1, nil), nil, nil)
nptr1.Etype = 1 nptr1.Etype = 1
nptr2 := l2 nptr2 := l2
var fn *Node var fn *Node
...@@ -2950,7 +2947,8 @@ func walkappend(n *Node, init *Nodes, dst *Node) *Node { ...@@ -2950,7 +2947,8 @@ func walkappend(n *Node, init *Nodes, dst *Node) *Node {
nn := temp(Types[TINT]) nn := temp(Types[TINT])
l = append(l, Nod(OAS, nn, Nod(OLEN, ns, nil))) // n = len(s) l = append(l, Nod(OAS, nn, Nod(OLEN, ns, nil))) // n = len(s)
nx = Nod(OSLICE, ns, Nod(OKEY, nil, Nod(OADD, nn, na))) // ...s[:n+argc] nx = Nod(OSLICE, ns, nil) // ...s[:n+argc]
nx.SetSliceBounds(nil, Nod(OADD, nn, na), nil)
nx.Etype = 1 nx.Etype = 1
l = append(l, Nod(OAS, ns, nx)) // s = s[:n+argc] l = append(l, Nod(OAS, ns, nx)) // s = s[:n+argc]
......
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