mirror of
https://github.com/golang/go
synced 2024-07-25 03:55:34 +00:00
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/22425 Reviewed-by: Matthew Dempsky <mdempsky@google.com>
This commit is contained in:
parent
2bf7034d87
commit
f12bd8a5a8
|
@ -1191,12 +1191,15 @@ func (p *exporter) expr(n *Node) {
|
|||
case OSLICE, OSLICESTR, OSLICEARR:
|
||||
p.op(OSLICE)
|
||||
p.expr(n.Left)
|
||||
p.expr(n.Right)
|
||||
low, high, _ := n.SliceBounds()
|
||||
p.exprsOrNil(low, high)
|
||||
|
||||
case OSLICE3, OSLICE3ARR:
|
||||
p.op(OSLICE3)
|
||||
p.expr(n.Left)
|
||||
p.expr(n.Right)
|
||||
low, high, max := n.SliceBounds()
|
||||
p.exprsOrNil(low, high)
|
||||
p.expr(max)
|
||||
|
||||
case OCOPY, OCOMPLEX:
|
||||
p.op(op)
|
||||
|
|
|
@ -822,9 +822,19 @@ func (p *importer) node() *Node {
|
|||
// case OINDEX, OINDEXMAP, OSLICE, OSLICESTR, OSLICEARR, OSLICE3, OSLICE3ARR:
|
||||
// unreachable - mapped to cases below by exporter
|
||||
|
||||
case OINDEX, OSLICE, OSLICE3:
|
||||
case OINDEX:
|
||||
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:
|
||||
n := builtinCall(op)
|
||||
n.List.Set([]*Node{p.expr(), p.expr()})
|
||||
|
|
|
@ -3106,15 +3106,7 @@ func cgen_slice(n, res *Node, wb bool) {
|
|||
x.Xoffset -= 2 * int64(Widthptr)
|
||||
}
|
||||
|
||||
var x1, x2, x3 *Node // 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
|
||||
}
|
||||
x1, x2, x3 := n.SliceBounds() // unevaluated index arguments
|
||||
|
||||
// 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.
|
||||
|
|
|
@ -1312,17 +1312,29 @@ func exprfmt(n *Node, prec int) string {
|
|||
f += fmt.Sprintf(".(%v)", n.Type)
|
||||
return f
|
||||
|
||||
case OINDEX,
|
||||
OINDEXMAP,
|
||||
OSLICE,
|
||||
OSLICESTR,
|
||||
OSLICEARR,
|
||||
OSLICE3,
|
||||
OSLICE3ARR:
|
||||
var f string
|
||||
f += exprfmt(n.Left, nprec)
|
||||
f += fmt.Sprintf("[%v]", n.Right)
|
||||
return f
|
||||
case OINDEX, OINDEXMAP:
|
||||
return fmt.Sprintf("%s[%v]", exprfmt(n.Left, nprec), n.Right)
|
||||
|
||||
case OSLICE, OSLICESTR, OSLICEARR, OSLICE3, OSLICE3ARR:
|
||||
var buf bytes.Buffer
|
||||
buf.WriteString(exprfmt(n.Left, nprec))
|
||||
buf.WriteString("[")
|
||||
low, high, max := n.SliceBounds()
|
||||
if low != nil {
|
||||
buf.WriteString(low.String())
|
||||
}
|
||||
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:
|
||||
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 {
|
|||
vararrtype := typArray(varargtype.Elem(), int64(varargcount))
|
||||
as.Right = Nod(OCOMPLIT, nil, typenod(vararrtype))
|
||||
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)
|
||||
|
|
|
@ -1123,24 +1123,16 @@ func orderexpr(n *Node, order *Order, lhs *Node) *Node {
|
|||
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.Right.Left = orderexpr(n.Right.Left, order, nil)
|
||||
n.Right.Left = ordercheapexpr(n.Right.Left, order)
|
||||
n.Right.Right = orderexpr(n.Right.Right, order, nil)
|
||||
n.Right.Right = ordercheapexpr(n.Right.Right, order)
|
||||
if lhs == nil || lhs.Op != ONAME && !samesafeexpr(lhs, n.Left) {
|
||||
n = ordercopyexpr(n, n.Type, order, 0)
|
||||
}
|
||||
|
||||
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)
|
||||
low, high, max := n.SliceBounds()
|
||||
low = orderexpr(low, order, nil)
|
||||
low = ordercheapexpr(low, order)
|
||||
high = orderexpr(high, order, nil)
|
||||
high = ordercheapexpr(high, order)
|
||||
max = orderexpr(max, order, nil)
|
||||
max = ordercheapexpr(max, order)
|
||||
n.SetSliceBounds(low, high, max)
|
||||
if lhs == nil || lhs.Op != ONAME && !samesafeexpr(lhs, n.Left) {
|
||||
n = ordercopyexpr(n, n.Type, order, 0)
|
||||
}
|
||||
|
|
|
@ -1408,20 +1408,17 @@ loop:
|
|||
}
|
||||
x = Nod(OINDEX, x, i)
|
||||
case 1:
|
||||
i := index[0]
|
||||
j := index[1]
|
||||
x = Nod(OSLICE, x, Nod(OKEY, i, j))
|
||||
x = Nod(OSLICE, x, nil)
|
||||
x.SetSliceBounds(index[0], index[1], nil)
|
||||
case 2:
|
||||
i := index[0]
|
||||
j := index[1]
|
||||
k := index[2]
|
||||
if j == nil {
|
||||
if index[1] == nil {
|
||||
Yyerror("middle index required in 3-index slice")
|
||||
}
|
||||
if k == nil {
|
||||
if index[2] == nil {
|
||||
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:
|
||||
panic("unreachable")
|
||||
|
|
|
@ -307,7 +307,11 @@ func instrumentnode(np **Node, init *Nodes, wr int, skip int) {
|
|||
|
||||
case OSLICE, OSLICEARR, OSLICE3, OSLICE3ARR, OSLICESTR:
|
||||
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
|
||||
|
||||
case OKEY:
|
||||
|
|
|
@ -727,7 +727,7 @@ func slicelit(ctxt int, n *Node, var_ *Node, init *Nodes) {
|
|||
arraylit(ctxt, 2, n, vstat, init)
|
||||
|
||||
// copy static to slice
|
||||
a := Nod(OSLICE, vstat, Nod(OKEY, nil, nil))
|
||||
a := Nod(OSLICE, vstat, nil)
|
||||
|
||||
a = Nod(OAS, var_, a)
|
||||
a = typecheck(a, Etop)
|
||||
|
@ -851,7 +851,7 @@ func slicelit(ctxt int, n *Node, var_ *Node, init *Nodes) {
|
|||
}
|
||||
|
||||
// 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 = orderstmtinplace(a)
|
||||
|
@ -1391,7 +1391,8 @@ func genAsInitNoCheck(n *Node, reportOnly bool) bool {
|
|||
fallthrough
|
||||
|
||||
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
|
||||
}
|
||||
nr = nr.Left
|
||||
|
|
|
@ -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) {
|
||||
// We're assigning a slicing operation back to its source.
|
||||
// Don't write back fields we aren't changing. See issue #14855.
|
||||
i := rhs.Right.Left
|
||||
var j, k *Node
|
||||
if rhs.Op == OSLICE3 {
|
||||
j = rhs.Right.Right.Left
|
||||
k = rhs.Right.Right.Right
|
||||
} else {
|
||||
j = rhs.Right.Right
|
||||
}
|
||||
i, j, k := rhs.SliceBounds()
|
||||
if i != nil && (i.Op == OLITERAL && i.Val().Ctype() == CTINT && i.Int64() == 0) {
|
||||
// [0:...] is the same as [:...]
|
||||
i = nil
|
||||
|
@ -2038,38 +2031,34 @@ func (s *state) expr(n *Node) *ssa.Value {
|
|||
}
|
||||
return s.newValue2(ssa.OpIMake, n.Type, tab, data)
|
||||
|
||||
case OSLICE, OSLICEARR:
|
||||
case OSLICE, OSLICEARR, OSLICE3, OSLICE3ARR:
|
||||
v := s.expr(n.Left)
|
||||
var i, j *ssa.Value
|
||||
if n.Right.Left != nil {
|
||||
i = s.extendIndex(s.expr(n.Right.Left))
|
||||
var i, j, k *ssa.Value
|
||||
low, high, max := n.SliceBounds()
|
||||
if low != nil {
|
||||
i = s.extendIndex(s.expr(low))
|
||||
}
|
||||
if n.Right.Right != nil {
|
||||
j = s.extendIndex(s.expr(n.Right.Right))
|
||||
if high != nil {
|
||||
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)
|
||||
|
||||
case OSLICESTR:
|
||||
v := s.expr(n.Left)
|
||||
var i, j *ssa.Value
|
||||
if n.Right.Left != nil {
|
||||
i = s.extendIndex(s.expr(n.Right.Left))
|
||||
low, high, _ := n.SliceBounds()
|
||||
if low != nil {
|
||||
i = s.extendIndex(s.expr(low))
|
||||
}
|
||||
if n.Right.Right != nil {
|
||||
j = s.extendIndex(s.expr(n.Right.Right))
|
||||
if high != nil {
|
||||
j = s.extendIndex(s.expr(high))
|
||||
}
|
||||
p, l, _ := s.slice(n.Left.Type, v, i, j, nil)
|
||||
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:
|
||||
if isIntrinsicCall1(n) {
|
||||
|
|
|
@ -1024,6 +1024,68 @@ func Is64(t *Type) bool {
|
|||
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?
|
||||
func Noconv(t1 *Type, t2 *Type) bool {
|
||||
e1 := Simtype[t1.Etype]
|
||||
|
|
|
@ -1105,14 +1105,19 @@ OpSwitch:
|
|||
n.Type = nil
|
||||
break OpSwitch
|
||||
|
||||
case OSLICE:
|
||||
case OSLICE, OSLICE3:
|
||||
ok |= Erv
|
||||
n.Left = typecheck(n.Left, top)
|
||||
n.Right.Left = typecheck(n.Right.Left, Erv)
|
||||
n.Right.Right = typecheck(n.Right.Right, Erv)
|
||||
low, high, max := n.SliceBounds()
|
||||
hasmax := n.Op.IsSlice3()
|
||||
low = typecheck(low, Erv)
|
||||
high = typecheck(high, Erv)
|
||||
max = typecheck(max, Erv)
|
||||
n.Left = defaultlit(n.Left, nil)
|
||||
n.Right.Left = indexlit(n.Right.Left)
|
||||
n.Right.Right = indexlit(n.Right.Right)
|
||||
low = indexlit(low)
|
||||
high = indexlit(high)
|
||||
max = indexlit(max)
|
||||
n.SetSliceBounds(low, high, max)
|
||||
l := n.Left
|
||||
if l.Type.IsArray() {
|
||||
if !islvalue(n.Left) {
|
||||
|
@ -1134,78 +1139,22 @@ OpSwitch:
|
|||
}
|
||||
var tp *Type
|
||||
if t.IsString() {
|
||||
if hasmax {
|
||||
Yyerror("invalid operation %v (3-index slice of string)", n)
|
||||
n.Type = nil
|
||||
return n
|
||||
}
|
||||
n.Type = t
|
||||
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
|
||||
if hasmax {
|
||||
n.Op = OSLICE3ARR
|
||||
} else {
|
||||
n.Op = OSLICEARR
|
||||
}
|
||||
|
||||
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)
|
||||
n.Type = nil
|
||||
return n
|
||||
}
|
||||
|
||||
var tp *Type
|
||||
if t.IsPtr() && t.Elem().IsArray() {
|
||||
tp = t.Elem()
|
||||
n.Type = typSlice(tp.Elem())
|
||||
dowidth(n.Type)
|
||||
n.Op = OSLICE3ARR
|
||||
} else if t.IsSlice() {
|
||||
n.Type = t
|
||||
} else {
|
||||
|
@ -1214,22 +1163,19 @@ OpSwitch:
|
|||
return n
|
||||
}
|
||||
|
||||
lo := n.Right.Left
|
||||
if lo != nil && !checksliceindex(l, lo, tp) {
|
||||
if low != nil && !checksliceindex(l, low, tp) {
|
||||
n.Type = nil
|
||||
return n
|
||||
}
|
||||
mid := n.Right.Right.Left
|
||||
if mid != nil && !checksliceindex(l, mid, tp) {
|
||||
if high != nil && !checksliceindex(l, high, tp) {
|
||||
n.Type = nil
|
||||
return n
|
||||
}
|
||||
hi := n.Right.Right.Right
|
||||
if hi != nil && !checksliceindex(l, hi, tp) {
|
||||
if max != nil && !checksliceindex(l, max, tp) {
|
||||
n.Type = nil
|
||||
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
|
||||
return n
|
||||
}
|
||||
|
|
|
@ -1241,35 +1241,28 @@ opswitch:
|
|||
case ORECV:
|
||||
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.Right.Left = walkexpr(n.Right.Left, init)
|
||||
if n.Right.Left != nil && iszero(n.Right.Left) {
|
||||
// Reduce x[0:j] to x[:j].
|
||||
n.Right.Left = nil
|
||||
low, high, max := n.SliceBounds()
|
||||
low = walkexpr(low, init)
|
||||
if low != nil && iszero(low) {
|
||||
// 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)
|
||||
|
||||
case OSLICE3, OSLICE3ARR:
|
||||
n.Left = walkexpr(n.Left, init)
|
||||
n.Right.Left = walkexpr(n.Right.Left, init)
|
||||
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].
|
||||
n.Right.Right = n.Right.Right.Left
|
||||
if n.Op == OSLICE3 {
|
||||
n.Op = OSLICE
|
||||
} else {
|
||||
n.Op = OSLICEARR
|
||||
high = walkexpr(high, init)
|
||||
max = walkexpr(max, init)
|
||||
n.SetSliceBounds(low, high, max)
|
||||
if n.Op.IsSlice3() {
|
||||
if max != nil && max.Op == OCAP && samesafeexpr(n.Left, max.Left) {
|
||||
// Reduce x[i:j:cap(x)] to x[i:j].
|
||||
if n.Op == OSLICE3 {
|
||||
n.Op = OSLICE
|
||||
} else {
|
||||
n.Op = OSLICEARR
|
||||
}
|
||||
n = reduceSlice(n)
|
||||
}
|
||||
} else {
|
||||
n = reduceSlice(n)
|
||||
}
|
||||
|
||||
|
@ -1425,8 +1418,9 @@ opswitch:
|
|||
a := Nod(OAS, var_, nil) // zero temp
|
||||
a = typecheck(a, Etop)
|
||||
init.Append(a)
|
||||
r := Nod(OSLICE, var_, Nod(OKEY, nil, l)) // arr[:l]
|
||||
r = conv(r, n.Type) // in case n.Type is named.
|
||||
r := Nod(OSLICE, var_, nil) // arr[:l]
|
||||
r.SetSliceBounds(nil, l, nil)
|
||||
r = conv(r, n.Type) // in case n.Type is named.
|
||||
r = typecheck(r, Erv)
|
||||
r = walkexpr(r, init)
|
||||
n = r
|
||||
|
@ -1596,13 +1590,15 @@ opswitch:
|
|||
return n
|
||||
}
|
||||
|
||||
// TODO(josharian): combine this with its caller and simplify
|
||||
func reduceSlice(n *Node) *Node {
|
||||
r := n.Right.Right
|
||||
if r != nil && r.Op == OLEN && samesafeexpr(n.Left, r.Left) {
|
||||
low, high, max := n.SliceBounds()
|
||||
if high != nil && high.Op == OLEN && samesafeexpr(n.Left, high.Left) {
|
||||
// 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.
|
||||
if Debug_slice > 0 {
|
||||
Warn("slice: omit slice operation")
|
||||
|
@ -2816,14 +2812,15 @@ func appendslice(n *Node, init *Nodes) *Node {
|
|||
l = append(l, nif)
|
||||
|
||||
// s = s[:n]
|
||||
nt := Nod(OSLICE, s, Nod(OKEY, nil, nn))
|
||||
nt := Nod(OSLICE, s, nil)
|
||||
nt.SetSliceBounds(nil, nn, nil)
|
||||
nt.Etype = 1
|
||||
l = append(l, Nod(OAS, s, nt))
|
||||
|
||||
if haspointers(l1.Type.Elem()) {
|
||||
// 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
|
||||
nptr2 := l2
|
||||
fn := syslook("typedslicecopy")
|
||||
|
@ -2835,8 +2832,8 @@ func appendslice(n *Node, init *Nodes) *Node {
|
|||
} else if instrumenting {
|
||||
// rely on runtime to instrument copy.
|
||||
// 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
|
||||
nptr2 := l2
|
||||
var fn *Node
|
||||
|
@ -2950,7 +2947,8 @@ func walkappend(n *Node, init *Nodes, dst *Node) *Node {
|
|||
nn := temp(Types[TINT])
|
||||
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
|
||||
l = append(l, Nod(OAS, ns, nx)) // s = s[:n+argc]
|
||||
|
||||
|
|
Loading…
Reference in a new issue