[dev.ssa] cmd/compile: implement len(map)
Implement len(map) values.
Change-Id: If92be96ec9a7a86aeb3ce566d6758aab01c2fa7d
Reviewed-on: https://go-review.googlesource.com/13961
Reviewed-by: Keith Randall <khr@golang.org>
diff --git a/src/cmd/compile/internal/gc/ssa.go b/src/cmd/compile/internal/gc/ssa.go
index 0c0a6a3..d672eb5 100644
--- a/src/cmd/compile/internal/gc/ssa.go
+++ b/src/cmd/compile/internal/gc/ssa.go
@@ -1440,8 +1440,7 @@
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 @@
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,