mirror of
https://github.com/golang/go.git
synced 2025-05-28 19:02:22 +00:00
[dev.ssa] cmd/compile: implement len/cap(chan)
Change-Id: I1453ba226376ccd4d79780fc0686876d6dde01ee Reviewed-on: https://go-review.googlesource.com/14027 Reviewed-by: Keith Randall <khr@golang.org>
This commit is contained in:
parent
73151067bc
commit
707af252d9
@ -1528,15 +1528,8 @@ func (s *state) expr(n *Node) *ssa.Value {
|
||||
return s.newValue1(op, Types[TINT], s.expr(n.Left))
|
||||
case n.Left.Type.IsString(): // string; not reachable for OCAP
|
||||
return s.newValue1(ssa.OpStringLen, Types[TINT], s.expr(n.Left))
|
||||
case n.Left.Type.IsMap():
|
||||
return s.lenMap(n, s.expr(n.Left))
|
||||
case n.Left.Type.IsChan():
|
||||
if n.Op == OCAP {
|
||||
s.Unimplementedf("unhandled cap(chan)")
|
||||
} else {
|
||||
s.Unimplementedf("unhandled len(chan)")
|
||||
}
|
||||
return nil
|
||||
case n.Left.Type.IsMap(), n.Left.Type.IsChan():
|
||||
return s.referenceTypeBuiltin(n, s.expr(n.Left))
|
||||
default: // array
|
||||
return s.constInt(Types[TINT], n.Left.Type.Bound)
|
||||
}
|
||||
@ -2098,11 +2091,18 @@ func (s *state) uintTofloat(cvttab *u2fcvtTab, n *Node, x *ssa.Value, ft, tt *Ty
|
||||
return s.variable(n, n.Type)
|
||||
}
|
||||
|
||||
func (s *state) lenMap(n *Node, x *ssa.Value) *ssa.Value {
|
||||
// referenceTypeBuiltin generates code for the len/cap builtins for maps and channels.
|
||||
func (s *state) referenceTypeBuiltin(n *Node, x *ssa.Value) *ssa.Value {
|
||||
if !n.Left.Type.IsMap() && !n.Left.Type.IsChan() {
|
||||
s.Fatalf("node must be a map or a channel")
|
||||
}
|
||||
// if n == nil {
|
||||
// return 0
|
||||
// } else {
|
||||
// // len
|
||||
// return *((*int)n)
|
||||
// // cap
|
||||
// return *(((*int)n)+1)
|
||||
// }
|
||||
lenType := n.Type
|
||||
nilValue := s.newValue0(ssa.OpConstNil, Types[TUINTPTR])
|
||||
@ -2116,17 +2116,25 @@ func (s *state) lenMap(n *Node, x *ssa.Value) *ssa.Value {
|
||||
bElse := s.f.NewBlock(ssa.BlockPlain)
|
||||
bAfter := s.f.NewBlock(ssa.BlockPlain)
|
||||
|
||||
// length of a nil map is zero
|
||||
// length/capacity of a nil map/chan is zero
|
||||
addEdge(b, bThen)
|
||||
s.startBlock(bThen)
|
||||
s.vars[n] = s.zeroVal(lenType)
|
||||
s.endBlock()
|
||||
addEdge(bThen, bAfter)
|
||||
|
||||
// the length is stored in the first word
|
||||
addEdge(b, bElse)
|
||||
s.startBlock(bElse)
|
||||
s.vars[n] = s.newValue2(ssa.OpLoad, lenType, x, s.mem())
|
||||
if n.Op == OLEN {
|
||||
// length is stored in the first word for map/chan
|
||||
s.vars[n] = s.newValue2(ssa.OpLoad, lenType, x, s.mem())
|
||||
} else if n.Op == OCAP {
|
||||
// capacity is stored in the second word for chan
|
||||
sw := s.newValue1I(ssa.OpOffPtr, lenType.PtrTo(), lenType.Width, x)
|
||||
s.vars[n] = s.newValue2(ssa.OpLoad, lenType, sw, s.mem())
|
||||
} else {
|
||||
s.Fatalf("op must be OLEN or OCAP")
|
||||
}
|
||||
s.endBlock()
|
||||
addEdge(bElse, bAfter)
|
||||
|
||||
|
76
src/cmd/compile/internal/gc/testdata/chan_ssa.go
vendored
Normal file
76
src/cmd/compile/internal/gc/testdata/chan_ssa.go
vendored
Normal file
@ -0,0 +1,76 @@
|
||||
// Copyright 2015 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// chan_ssa.go tests chan operations.
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
var failed = false
|
||||
|
||||
func lenChan_ssa(v chan int) int {
|
||||
switch { // prevent inlining
|
||||
|
||||
}
|
||||
return len(v)
|
||||
}
|
||||
func capChan_ssa(v chan int) int {
|
||||
switch { // prevent inlining
|
||||
|
||||
}
|
||||
return cap(v)
|
||||
}
|
||||
|
||||
func testLenChan() {
|
||||
|
||||
v := make(chan int, 10)
|
||||
v <- 1
|
||||
v <- 1
|
||||
v <- 1
|
||||
|
||||
if want, got := 3, lenChan_ssa(v); got != want {
|
||||
fmt.Printf("expected len(chan) = %d, got %d", want, got)
|
||||
failed = true
|
||||
}
|
||||
}
|
||||
|
||||
func testLenNilChan() {
|
||||
|
||||
var v chan int
|
||||
if want, got := 0, lenChan_ssa(v); got != want {
|
||||
fmt.Printf("expected len(nil) = %d, got %d", want, got)
|
||||
failed = true
|
||||
}
|
||||
}
|
||||
|
||||
func testCapChan() {
|
||||
|
||||
v := make(chan int, 25)
|
||||
|
||||
if want, got := 25, capChan_ssa(v); got != want {
|
||||
fmt.Printf("expected cap(chan) = %d, got %d", want, got)
|
||||
failed = true
|
||||
}
|
||||
}
|
||||
|
||||
func testCapNilChan() {
|
||||
|
||||
var v chan int
|
||||
if want, got := 0, capChan_ssa(v); got != want {
|
||||
fmt.Printf("expected cap(nil) = %d, got %d", want, got)
|
||||
failed = true
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
testLenChan()
|
||||
testLenNilChan()
|
||||
|
||||
testCapChan()
|
||||
testCapNilChan()
|
||||
|
||||
if failed {
|
||||
panic("failed")
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user