diff options
Diffstat (limited to 'src/cmd/compile/internal/walk/expr.go')
| -rw-r--r-- | src/cmd/compile/internal/walk/expr.go | 67 |
1 files changed, 41 insertions, 26 deletions
diff --git a/src/cmd/compile/internal/walk/expr.go b/src/cmd/compile/internal/walk/expr.go index f73b5d9503..8c36e03aa0 100644 --- a/src/cmd/compile/internal/walk/expr.go +++ b/src/cmd/compile/internal/walk/expr.go @@ -273,7 +273,7 @@ func walkExpr1(n ir.Node, init *ir.Nodes) ir.Node { return walkNew(n, init) case ir.OADDSTR: - return walkAddString(n.(*ir.AddStringExpr), init) + return walkAddString(n.Type(), n.(*ir.AddStringExpr), init) case ir.OAPPEND: // order should make sure we only see OAS(node, OAPPEND), which we handle above. @@ -464,49 +464,64 @@ func copyExpr(n ir.Node, t *types.Type, init *ir.Nodes) ir.Node { return l } -func walkAddString(n *ir.AddStringExpr, init *ir.Nodes) ir.Node { +func walkAddString(typ *types.Type, n *ir.AddStringExpr, init *ir.Nodes) ir.Node { c := len(n.List) if c < 2 { base.Fatalf("walkAddString count %d too small", c) } - buf := typecheck.NodNil() - if n.Esc() == ir.EscNone { - sz := int64(0) - for _, n1 := range n.List { - if n1.Op() == ir.OLITERAL { - sz += int64(len(ir.StringVal(n1))) + // list of string arguments + var args []ir.Node + + var fn, fnsmall, fnbig string + + switch { + default: + base.FatalfAt(n.Pos(), "unexpected type: %v", typ) + case typ.IsString(): + buf := typecheck.NodNil() + if n.Esc() == ir.EscNone { + sz := int64(0) + for _, n1 := range n.List { + if n1.Op() == ir.OLITERAL { + sz += int64(len(ir.StringVal(n1))) + } } - } - // Don't allocate the buffer if the result won't fit. - if sz < tmpstringbufsize { - // Create temporary buffer for result string on stack. - buf = stackBufAddr(tmpstringbufsize, types.Types[types.TUINT8]) + // Don't allocate the buffer if the result won't fit. + if sz < tmpstringbufsize { + // Create temporary buffer for result string on stack. + buf = stackBufAddr(tmpstringbufsize, types.Types[types.TUINT8]) + } } - } - // build list of string arguments - args := []ir.Node{buf} - for _, n2 := range n.List { - args = append(args, typecheck.Conv(n2, types.Types[types.TSTRING])) + args = []ir.Node{buf} + fnsmall, fnbig = "concatstring%d", "concatstrings" + case typ.IsSlice() && typ.Elem().IsKind(types.TUINT8): // Optimize []byte(str1+str2+...) + fnsmall, fnbig = "concatbyte%d", "concatbytes" } - var fn string if c <= 5 { // small numbers of strings use direct runtime helpers. // note: order.expr knows this cutoff too. - fn = fmt.Sprintf("concatstring%d", c) + fn = fmt.Sprintf(fnsmall, c) + + for _, n2 := range n.List { + args = append(args, typecheck.Conv(n2, types.Types[types.TSTRING])) + } } else { // large numbers of strings are passed to the runtime as a slice. - fn = "concatstrings" - + fn = fnbig t := types.NewSlice(types.Types[types.TSTRING]) - // args[1:] to skip buf arg - slice := ir.NewCompLitExpr(base.Pos, ir.OCOMPLIT, t, args[1:]) + + slargs := make([]ir.Node, len(n.List)) + for i, n2 := range n.List { + slargs[i] = typecheck.Conv(n2, types.Types[types.TSTRING]) + } + slice := ir.NewCompLitExpr(base.Pos, ir.OCOMPLIT, t, slargs) slice.Prealloc = n.Prealloc - args = []ir.Node{buf, slice} + args = append(args, slice) slice.SetEsc(ir.EscNone) } @@ -515,7 +530,7 @@ func walkAddString(n *ir.AddStringExpr, init *ir.Nodes) ir.Node { r.Args = args r1 := typecheck.Expr(r) r1 = walkExpr(r1, init) - r1.SetType(n.Type()) + r1.SetType(typ) return r1 } |
