]> Cypherpunks repositories - gostls13.git/commitdiff
[dev.ssa] cmd/compile: implement len(map)
authorTodd Neal <todd@tneal.org>
Wed, 26 Aug 2015 23:40:52 +0000 (18:40 -0500)
committerTodd Neal <todd@tneal.org>
Fri, 28 Aug 2015 20:12:47 +0000 (20:12 +0000)
Implement len(map) values.

Change-Id: If92be96ec9a7a86aeb3ce566d6758aab01c2fa7d
Reviewed-on: https://go-review.googlesource.com/13961
Reviewed-by: Keith Randall <khr@golang.org>
src/cmd/compile/internal/gc/ssa.go
src/cmd/compile/internal/gc/testdata/map_ssa.go [new file with mode: 0644]
src/cmd/compile/internal/gc/testdata/string_ssa.go

index 0c0a6a36dad07cf7d9fd2e8d68f2038f4b1e6d7c..d672eb58e00e49fc53680ebc1d2650e4f6f7fcf3 100644 (file)
@@ -1440,8 +1440,7 @@ func (s *state) expr(n *Node) *ssa.Value {
                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():
-                       s.Unimplementedf("unhandled len(map)")
-                       return nil
+                       return s.lenMap(n, s.expr(n.Left))
                case n.Left.Type.IsChan():
                        if n.Op == OCAP {
                                s.Unimplementedf("unhandled cap(chan)")
@@ -1998,6 +1997,41 @@ 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 {
+       // if n == nil {
+       //   return 0
+       // } else {
+       //   return *((*int)n)
+       // }
+       lenType := n.Type
+       cmp := s.newValue2(ssa.OpEqPtr, Types[TBOOL], x, s.zeroVal(lenType))
+       b := s.endBlock()
+       b.Kind = ssa.BlockIf
+       b.Control = cmp
+       b.Likely = ssa.BranchUnlikely
+
+       bThen := s.f.NewBlock(ssa.BlockPlain)
+       bElse := s.f.NewBlock(ssa.BlockPlain)
+       bAfter := s.f.NewBlock(ssa.BlockPlain)
+
+       // length of a nil map 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())
+       s.endBlock()
+       addEdge(bElse, bAfter)
+
+       s.startBlock(bAfter)
+       return s.variable(n, lenType)
+}
+
 // checkgoto checks that a goto from from to to does not
 // jump into a block or jump over variable declarations.
 // It is a copy of checkgoto in the pre-SSA backend,
diff --git a/src/cmd/compile/internal/gc/testdata/map_ssa.go b/src/cmd/compile/internal/gc/testdata/map_ssa.go
new file mode 100644 (file)
index 0000000..41c949a
--- /dev/null
@@ -0,0 +1,47 @@
+// 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.
+
+// map_ssa.go tests map operations.
+package main
+
+import "fmt"
+
+var failed = false
+
+func lenMap_ssa(v map[int]int) int {
+       switch { // prevent inlining
+
+       }
+       return len(v)
+}
+
+func testLenMap() {
+
+       v := make(map[int]int)
+       v[0] = 0
+       v[1] = 0
+       v[2] = 0
+
+       if want, got := 3, lenMap_ssa(v); got != want {
+               fmt.Printf("expected len(map) = %d, got %d", want, got)
+               failed = true
+       }
+}
+
+func testLenNilMap() {
+
+       var v map[int]int
+       if want, got := 0, lenMap_ssa(v); got != want {
+               fmt.Printf("expected len(nil) = %d, got %d", want, got)
+               failed = true
+       }
+}
+func main() {
+       testLenMap()
+       testLenNilMap()
+
+       if failed {
+               panic("failed")
+       }
+}
index 59874129338a38607b48dbb79423566d8730f78b..efc734e1a235f582cbef6bedf689210f9a2ed7a4 100644 (file)
@@ -1,3 +1,7 @@
+// 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.
+
 // string_ssa.go tests string operations.
 package main