]> Cypherpunks.ru repositories - gostls13.git/blob - src/cmd/compile/internal/walk/builtin.go
5c924a90c5cbe848d8363dcc66adbd23c876afa3
[gostls13.git] / src / cmd / compile / internal / walk / builtin.go
1 // Copyright 2009 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4
5 package walk
6
7 import (
8         "fmt"
9         "go/constant"
10         "go/token"
11         "strings"
12
13         "cmd/compile/internal/base"
14         "cmd/compile/internal/escape"
15         "cmd/compile/internal/ir"
16         "cmd/compile/internal/reflectdata"
17         "cmd/compile/internal/typecheck"
18         "cmd/compile/internal/types"
19 )
20
21 // Rewrite append(src, x, y, z) so that any side effects in
22 // x, y, z (including runtime panics) are evaluated in
23 // initialization statements before the append.
24 // For normal code generation, stop there and leave the
25 // rest to ssagen.
26 //
27 // For race detector, expand append(src, a [, b]* ) to
28 //
29 //      init {
30 //        s := src
31 //        const argc = len(args) - 1
32 //        newLen := s.len + argc
33 //        if uint(newLen) <= uint(s.cap) {
34 //          s = s[:newLen]
35 //        } else {
36 //          s = growslice(s.ptr, newLen, s.cap, argc, elemType)
37 //        }
38 //        s[s.len - argc] = a
39 //        s[s.len - argc + 1] = b
40 //        ...
41 //      }
42 //      s
43 func walkAppend(n *ir.CallExpr, init *ir.Nodes, dst ir.Node) ir.Node {
44         if !ir.SameSafeExpr(dst, n.Args[0]) {
45                 n.Args[0] = safeExpr(n.Args[0], init)
46                 n.Args[0] = walkExpr(n.Args[0], init)
47         }
48         walkExprListSafe(n.Args[1:], init)
49
50         nsrc := n.Args[0]
51
52         // walkExprListSafe will leave OINDEX (s[n]) alone if both s
53         // and n are name or literal, but those may index the slice we're
54         // modifying here. Fix explicitly.
55         // Using cheapExpr also makes sure that the evaluation
56         // of all arguments (and especially any panics) happen
57         // before we begin to modify the slice in a visible way.
58         ls := n.Args[1:]
59         for i, n := range ls {
60                 n = cheapExpr(n, init)
61                 if !types.Identical(n.Type(), nsrc.Type().Elem()) {
62                         n = typecheck.AssignConv(n, nsrc.Type().Elem(), "append")
63                         n = walkExpr(n, init)
64                 }
65                 ls[i] = n
66         }
67
68         argc := len(n.Args) - 1
69         if argc < 1 {
70                 return nsrc
71         }
72
73         // General case, with no function calls left as arguments.
74         // Leave for ssagen, except that instrumentation requires the old form.
75         if !base.Flag.Cfg.Instrumenting || base.Flag.CompilingRuntime {
76                 return n
77         }
78
79         var l []ir.Node
80
81         // s = slice to append to
82         s := typecheck.Temp(nsrc.Type())
83         l = append(l, ir.NewAssignStmt(base.Pos, s, nsrc))
84
85         // num = number of things to append
86         num := ir.NewInt(base.Pos, int64(argc))
87
88         // newLen := s.len + num
89         newLen := typecheck.Temp(types.Types[types.TINT])
90         l = append(l, ir.NewAssignStmt(base.Pos, newLen, ir.NewBinaryExpr(base.Pos, ir.OADD, ir.NewUnaryExpr(base.Pos, ir.OLEN, s), num)))
91
92         // if uint(newLen) <= uint(s.cap)
93         nif := ir.NewIfStmt(base.Pos, nil, nil, nil)
94         nif.Cond = ir.NewBinaryExpr(base.Pos, ir.OLE, typecheck.Conv(newLen, types.Types[types.TUINT]), typecheck.Conv(ir.NewUnaryExpr(base.Pos, ir.OCAP, s), types.Types[types.TUINT]))
95         nif.Likely = true
96
97         // then { s = s[:n] }
98         slice := ir.NewSliceExpr(base.Pos, ir.OSLICE, s, nil, newLen, nil)
99         slice.SetBounded(true)
100         nif.Body = []ir.Node{
101                 ir.NewAssignStmt(base.Pos, s, slice),
102         }
103
104         fn := typecheck.LookupRuntime("growslice") //   growslice(ptr *T, newLen, oldCap, num int, <type>) (ret []T)
105         fn = typecheck.SubstArgTypes(fn, s.Type().Elem(), s.Type().Elem())
106
107         // else { s = growslice(s.ptr, n, s.cap, a, T) }
108         nif.Else = []ir.Node{
109                 ir.NewAssignStmt(base.Pos, s, mkcall1(fn, s.Type(), nif.PtrInit(),
110                         ir.NewUnaryExpr(base.Pos, ir.OSPTR, s),
111                         newLen,
112                         ir.NewUnaryExpr(base.Pos, ir.OCAP, s),
113                         num,
114                         reflectdata.TypePtr(s.Type().Elem()))),
115         }
116
117         l = append(l, nif)
118
119         ls = n.Args[1:]
120         for i, n := range ls {
121                 // s[s.len-argc+i] = arg
122                 ix := ir.NewIndexExpr(base.Pos, s, ir.NewBinaryExpr(base.Pos, ir.OSUB, newLen, ir.NewInt(base.Pos, int64(argc-i))))
123                 ix.SetBounded(true)
124                 l = append(l, ir.NewAssignStmt(base.Pos, ix, n))
125         }
126
127         typecheck.Stmts(l)
128         walkStmtList(l)
129         init.Append(l...)
130         return s
131 }
132
133 // walkClear walks an OCLEAR node.
134 func walkClear(n *ir.UnaryExpr) ir.Node {
135         typ := n.X.Type()
136         switch {
137         case typ.IsSlice():
138                 return arrayClear(n.X.Pos(), n.X, nil)
139         case typ.IsMap():
140                 return mapClear(n.X, reflectdata.TypePtrAt(n.X.Pos(), n.X.Type()))
141         }
142         panic("unreachable")
143 }
144
145 // walkClose walks an OCLOSE node.
146 func walkClose(n *ir.UnaryExpr, init *ir.Nodes) ir.Node {
147         // cannot use chanfn - closechan takes any, not chan any
148         fn := typecheck.LookupRuntime("closechan")
149         fn = typecheck.SubstArgTypes(fn, n.X.Type())
150         return mkcall1(fn, nil, init, n.X)
151 }
152
153 // Lower copy(a, b) to a memmove call or a runtime call.
154 //
155 //      init {
156 //        n := len(a)
157 //        if n > len(b) { n = len(b) }
158 //        if a.ptr != b.ptr { memmove(a.ptr, b.ptr, n*sizeof(elem(a))) }
159 //      }
160 //      n;
161 //
162 // Also works if b is a string.
163 func walkCopy(n *ir.BinaryExpr, init *ir.Nodes, runtimecall bool) ir.Node {
164         if n.X.Type().Elem().HasPointers() {
165                 ir.CurFunc.SetWBPos(n.Pos())
166                 fn := writebarrierfn("typedslicecopy", n.X.Type().Elem(), n.Y.Type().Elem())
167                 n.X = cheapExpr(n.X, init)
168                 ptrL, lenL := backingArrayPtrLen(n.X)
169                 n.Y = cheapExpr(n.Y, init)
170                 ptrR, lenR := backingArrayPtrLen(n.Y)
171                 return mkcall1(fn, n.Type(), init, reflectdata.CopyElemRType(base.Pos, n), ptrL, lenL, ptrR, lenR)
172         }
173
174         if runtimecall {
175                 // rely on runtime to instrument:
176                 //  copy(n.Left, n.Right)
177                 // n.Right can be a slice or string.
178
179                 n.X = cheapExpr(n.X, init)
180                 ptrL, lenL := backingArrayPtrLen(n.X)
181                 n.Y = cheapExpr(n.Y, init)
182                 ptrR, lenR := backingArrayPtrLen(n.Y)
183
184                 fn := typecheck.LookupRuntime("slicecopy")
185                 fn = typecheck.SubstArgTypes(fn, ptrL.Type().Elem(), ptrR.Type().Elem())
186
187                 return mkcall1(fn, n.Type(), init, ptrL, lenL, ptrR, lenR, ir.NewInt(base.Pos, n.X.Type().Elem().Size()))
188         }
189
190         n.X = walkExpr(n.X, init)
191         n.Y = walkExpr(n.Y, init)
192         nl := typecheck.Temp(n.X.Type())
193         nr := typecheck.Temp(n.Y.Type())
194         var l []ir.Node
195         l = append(l, ir.NewAssignStmt(base.Pos, nl, n.X))
196         l = append(l, ir.NewAssignStmt(base.Pos, nr, n.Y))
197
198         nfrm := ir.NewUnaryExpr(base.Pos, ir.OSPTR, nr)
199         nto := ir.NewUnaryExpr(base.Pos, ir.OSPTR, nl)
200
201         nlen := typecheck.Temp(types.Types[types.TINT])
202
203         // n = len(to)
204         l = append(l, ir.NewAssignStmt(base.Pos, nlen, ir.NewUnaryExpr(base.Pos, ir.OLEN, nl)))
205
206         // if n > len(frm) { n = len(frm) }
207         nif := ir.NewIfStmt(base.Pos, nil, nil, nil)
208
209         nif.Cond = ir.NewBinaryExpr(base.Pos, ir.OGT, nlen, ir.NewUnaryExpr(base.Pos, ir.OLEN, nr))
210         nif.Body.Append(ir.NewAssignStmt(base.Pos, nlen, ir.NewUnaryExpr(base.Pos, ir.OLEN, nr)))
211         l = append(l, nif)
212
213         // if to.ptr != frm.ptr { memmove( ... ) }
214         ne := ir.NewIfStmt(base.Pos, ir.NewBinaryExpr(base.Pos, ir.ONE, nto, nfrm), nil, nil)
215         ne.Likely = true
216         l = append(l, ne)
217
218         fn := typecheck.LookupRuntime("memmove")
219         fn = typecheck.SubstArgTypes(fn, nl.Type().Elem(), nl.Type().Elem())
220         nwid := ir.Node(typecheck.Temp(types.Types[types.TUINTPTR]))
221         setwid := ir.NewAssignStmt(base.Pos, nwid, typecheck.Conv(nlen, types.Types[types.TUINTPTR]))
222         ne.Body.Append(setwid)
223         nwid = ir.NewBinaryExpr(base.Pos, ir.OMUL, nwid, ir.NewInt(base.Pos, nl.Type().Elem().Size()))
224         call := mkcall1(fn, nil, init, nto, nfrm, nwid)
225         ne.Body.Append(call)
226
227         typecheck.Stmts(l)
228         walkStmtList(l)
229         init.Append(l...)
230         return nlen
231 }
232
233 // walkDelete walks an ODELETE node.
234 func walkDelete(init *ir.Nodes, n *ir.CallExpr) ir.Node {
235         init.Append(ir.TakeInit(n)...)
236         map_ := n.Args[0]
237         key := n.Args[1]
238         map_ = walkExpr(map_, init)
239         key = walkExpr(key, init)
240
241         t := map_.Type()
242         fast := mapfast(t)
243         key = mapKeyArg(fast, n, key, false)
244         return mkcall1(mapfndel(mapdelete[fast], t), nil, init, reflectdata.DeleteMapRType(base.Pos, n), map_, key)
245 }
246
247 // walkLenCap walks an OLEN or OCAP node.
248 func walkLenCap(n *ir.UnaryExpr, init *ir.Nodes) ir.Node {
249         if isRuneCount(n) {
250                 // Replace len([]rune(string)) with runtime.countrunes(string).
251                 return mkcall("countrunes", n.Type(), init, typecheck.Conv(n.X.(*ir.ConvExpr).X, types.Types[types.TSTRING]))
252         }
253         if isByteCount(n) {
254                 _, len := backingArrayPtrLen(cheapExpr(n.X.(*ir.ConvExpr).X, init))
255                 return len
256         }
257
258         n.X = walkExpr(n.X, init)
259
260         // replace len(*[10]int) with 10.
261         // delayed until now to preserve side effects.
262         t := n.X.Type()
263
264         if t.IsPtr() {
265                 t = t.Elem()
266         }
267         if t.IsArray() {
268                 safeExpr(n.X, init)
269                 con := typecheck.OrigInt(n, t.NumElem())
270                 con.SetTypecheck(1)
271                 return con
272         }
273         return n
274 }
275
276 // walkMakeChan walks an OMAKECHAN node.
277 func walkMakeChan(n *ir.MakeExpr, init *ir.Nodes) ir.Node {
278         // When size fits into int, use makechan instead of
279         // makechan64, which is faster and shorter on 32 bit platforms.
280         size := n.Len
281         fnname := "makechan64"
282         argtype := types.Types[types.TINT64]
283
284         // Type checking guarantees that TIDEAL size is positive and fits in an int.
285         // The case of size overflow when converting TUINT or TUINTPTR to TINT
286         // will be handled by the negative range checks in makechan during runtime.
287         if size.Type().IsKind(types.TIDEAL) || size.Type().Size() <= types.Types[types.TUINT].Size() {
288                 fnname = "makechan"
289                 argtype = types.Types[types.TINT]
290         }
291
292         return mkcall1(chanfn(fnname, 1, n.Type()), n.Type(), init, reflectdata.MakeChanRType(base.Pos, n), typecheck.Conv(size, argtype))
293 }
294
295 // walkMakeMap walks an OMAKEMAP node.
296 func walkMakeMap(n *ir.MakeExpr, init *ir.Nodes) ir.Node {
297         t := n.Type()
298         hmapType := reflectdata.MapType(t)
299         hint := n.Len
300
301         // var h *hmap
302         var h ir.Node
303         if n.Esc() == ir.EscNone {
304                 // Allocate hmap on stack.
305
306                 // var hv hmap
307                 // h = &hv
308                 h = stackTempAddr(init, hmapType)
309
310                 // Allocate one bucket pointed to by hmap.buckets on stack if hint
311                 // is not larger than BUCKETSIZE. In case hint is larger than
312                 // BUCKETSIZE runtime.makemap will allocate the buckets on the heap.
313                 // Maximum key and elem size is 128 bytes, larger objects
314                 // are stored with an indirection. So max bucket size is 2048+eps.
315                 if !ir.IsConst(hint, constant.Int) ||
316                         constant.Compare(hint.Val(), token.LEQ, constant.MakeInt64(reflectdata.BUCKETSIZE)) {
317
318                         // In case hint is larger than BUCKETSIZE runtime.makemap
319                         // will allocate the buckets on the heap, see #20184
320                         //
321                         // if hint <= BUCKETSIZE {
322                         //     var bv bmap
323                         //     b = &bv
324                         //     h.buckets = b
325                         // }
326
327                         nif := ir.NewIfStmt(base.Pos, ir.NewBinaryExpr(base.Pos, ir.OLE, hint, ir.NewInt(base.Pos, reflectdata.BUCKETSIZE)), nil, nil)
328                         nif.Likely = true
329
330                         // var bv bmap
331                         // b = &bv
332                         b := stackTempAddr(&nif.Body, reflectdata.MapBucketType(t))
333
334                         // h.buckets = b
335                         bsym := hmapType.Field(5).Sym // hmap.buckets see reflect.go:hmap
336                         na := ir.NewAssignStmt(base.Pos, ir.NewSelectorExpr(base.Pos, ir.ODOT, h, bsym), b)
337                         nif.Body.Append(na)
338                         appendWalkStmt(init, nif)
339                 }
340         }
341
342         if ir.IsConst(hint, constant.Int) && constant.Compare(hint.Val(), token.LEQ, constant.MakeInt64(reflectdata.BUCKETSIZE)) {
343                 // Handling make(map[any]any) and
344                 // make(map[any]any, hint) where hint <= BUCKETSIZE
345                 // special allows for faster map initialization and
346                 // improves binary size by using calls with fewer arguments.
347                 // For hint <= BUCKETSIZE overLoadFactor(hint, 0) is false
348                 // and no buckets will be allocated by makemap. Therefore,
349                 // no buckets need to be allocated in this code path.
350                 if n.Esc() == ir.EscNone {
351                         // Only need to initialize h.hash0 since
352                         // hmap h has been allocated on the stack already.
353                         // h.hash0 = fastrand()
354                         rand := mkcall("fastrand", types.Types[types.TUINT32], init)
355                         hashsym := hmapType.Field(4).Sym // hmap.hash0 see reflect.go:hmap
356                         appendWalkStmt(init, ir.NewAssignStmt(base.Pos, ir.NewSelectorExpr(base.Pos, ir.ODOT, h, hashsym), rand))
357                         return typecheck.ConvNop(h, t)
358                 }
359                 // Call runtime.makehmap to allocate an
360                 // hmap on the heap and initialize hmap's hash0 field.
361                 fn := typecheck.LookupRuntime("makemap_small")
362                 fn = typecheck.SubstArgTypes(fn, t.Key(), t.Elem())
363                 return mkcall1(fn, n.Type(), init)
364         }
365
366         if n.Esc() != ir.EscNone {
367                 h = typecheck.NodNil()
368         }
369         // Map initialization with a variable or large hint is
370         // more complicated. We therefore generate a call to
371         // runtime.makemap to initialize hmap and allocate the
372         // map buckets.
373
374         // When hint fits into int, use makemap instead of
375         // makemap64, which is faster and shorter on 32 bit platforms.
376         fnname := "makemap64"
377         argtype := types.Types[types.TINT64]
378
379         // Type checking guarantees that TIDEAL hint is positive and fits in an int.
380         // See checkmake call in TMAP case of OMAKE case in OpSwitch in typecheck1 function.
381         // The case of hint overflow when converting TUINT or TUINTPTR to TINT
382         // will be handled by the negative range checks in makemap during runtime.
383         if hint.Type().IsKind(types.TIDEAL) || hint.Type().Size() <= types.Types[types.TUINT].Size() {
384                 fnname = "makemap"
385                 argtype = types.Types[types.TINT]
386         }
387
388         fn := typecheck.LookupRuntime(fnname)
389         fn = typecheck.SubstArgTypes(fn, hmapType, t.Key(), t.Elem())
390         return mkcall1(fn, n.Type(), init, reflectdata.MakeMapRType(base.Pos, n), typecheck.Conv(hint, argtype), h)
391 }
392
393 // walkMakeSlice walks an OMAKESLICE node.
394 func walkMakeSlice(n *ir.MakeExpr, init *ir.Nodes) ir.Node {
395         l := n.Len
396         r := n.Cap
397         if r == nil {
398                 r = safeExpr(l, init)
399                 l = r
400         }
401         t := n.Type()
402         if t.Elem().NotInHeap() {
403                 base.Errorf("%v can't be allocated in Go; it is incomplete (or unallocatable)", t.Elem())
404         }
405         if n.Esc() == ir.EscNone {
406                 if why := escape.HeapAllocReason(n); why != "" {
407                         base.Fatalf("%v has EscNone, but %v", n, why)
408                 }
409                 // var arr [r]T
410                 // n = arr[:l]
411                 i := typecheck.IndexConst(r)
412                 if i < 0 {
413                         base.Fatalf("walkExpr: invalid index %v", r)
414                 }
415
416                 // cap is constrained to [0,2^31) or [0,2^63) depending on whether
417                 // we're in 32-bit or 64-bit systems. So it's safe to do:
418                 //
419                 // if uint64(len) > cap {
420                 //     if len < 0 { panicmakeslicelen() }
421                 //     panicmakeslicecap()
422                 // }
423                 nif := ir.NewIfStmt(base.Pos, ir.NewBinaryExpr(base.Pos, ir.OGT, typecheck.Conv(l, types.Types[types.TUINT64]), ir.NewInt(base.Pos, i)), nil, nil)
424                 niflen := ir.NewIfStmt(base.Pos, ir.NewBinaryExpr(base.Pos, ir.OLT, l, ir.NewInt(base.Pos, 0)), nil, nil)
425                 niflen.Body = []ir.Node{mkcall("panicmakeslicelen", nil, init)}
426                 nif.Body.Append(niflen, mkcall("panicmakeslicecap", nil, init))
427                 init.Append(typecheck.Stmt(nif))
428
429                 t = types.NewArray(t.Elem(), i) // [r]T
430                 var_ := typecheck.Temp(t)
431                 appendWalkStmt(init, ir.NewAssignStmt(base.Pos, var_, nil))  // zero temp
432                 r := ir.NewSliceExpr(base.Pos, ir.OSLICE, var_, nil, l, nil) // arr[:l]
433                 // The conv is necessary in case n.Type is named.
434                 return walkExpr(typecheck.Expr(typecheck.Conv(r, n.Type())), init)
435         }
436
437         // n escapes; set up a call to makeslice.
438         // When len and cap can fit into int, use makeslice instead of
439         // makeslice64, which is faster and shorter on 32 bit platforms.
440
441         len, cap := l, r
442
443         fnname := "makeslice64"
444         argtype := types.Types[types.TINT64]
445
446         // Type checking guarantees that TIDEAL len/cap are positive and fit in an int.
447         // The case of len or cap overflow when converting TUINT or TUINTPTR to TINT
448         // will be handled by the negative range checks in makeslice during runtime.
449         if (len.Type().IsKind(types.TIDEAL) || len.Type().Size() <= types.Types[types.TUINT].Size()) &&
450                 (cap.Type().IsKind(types.TIDEAL) || cap.Type().Size() <= types.Types[types.TUINT].Size()) {
451                 fnname = "makeslice"
452                 argtype = types.Types[types.TINT]
453         }
454         fn := typecheck.LookupRuntime(fnname)
455         ptr := mkcall1(fn, types.Types[types.TUNSAFEPTR], init, reflectdata.MakeSliceElemRType(base.Pos, n), typecheck.Conv(len, argtype), typecheck.Conv(cap, argtype))
456         ptr.MarkNonNil()
457         len = typecheck.Conv(len, types.Types[types.TINT])
458         cap = typecheck.Conv(cap, types.Types[types.TINT])
459         sh := ir.NewSliceHeaderExpr(base.Pos, t, ptr, len, cap)
460         return walkExpr(typecheck.Expr(sh), init)
461 }
462
463 // walkMakeSliceCopy walks an OMAKESLICECOPY node.
464 func walkMakeSliceCopy(n *ir.MakeExpr, init *ir.Nodes) ir.Node {
465         if n.Esc() == ir.EscNone {
466                 base.Fatalf("OMAKESLICECOPY with EscNone: %v", n)
467         }
468
469         t := n.Type()
470         if t.Elem().NotInHeap() {
471                 base.Errorf("%v can't be allocated in Go; it is incomplete (or unallocatable)", t.Elem())
472         }
473
474         length := typecheck.Conv(n.Len, types.Types[types.TINT])
475         copylen := ir.NewUnaryExpr(base.Pos, ir.OLEN, n.Cap)
476         copyptr := ir.NewUnaryExpr(base.Pos, ir.OSPTR, n.Cap)
477
478         if !t.Elem().HasPointers() && n.Bounded() {
479                 // When len(to)==len(from) and elements have no pointers:
480                 // replace make+copy with runtime.mallocgc+runtime.memmove.
481
482                 // We do not check for overflow of len(to)*elem.Width here
483                 // since len(from) is an existing checked slice capacity
484                 // with same elem.Width for the from slice.
485                 size := ir.NewBinaryExpr(base.Pos, ir.OMUL, typecheck.Conv(length, types.Types[types.TUINTPTR]), typecheck.Conv(ir.NewInt(base.Pos, t.Elem().Size()), types.Types[types.TUINTPTR]))
486
487                 // instantiate mallocgc(size uintptr, typ *byte, needszero bool) unsafe.Pointer
488                 fn := typecheck.LookupRuntime("mallocgc")
489                 ptr := mkcall1(fn, types.Types[types.TUNSAFEPTR], init, size, typecheck.NodNil(), ir.NewBool(base.Pos, false))
490                 ptr.MarkNonNil()
491                 sh := ir.NewSliceHeaderExpr(base.Pos, t, ptr, length, length)
492
493                 s := typecheck.Temp(t)
494                 r := typecheck.Stmt(ir.NewAssignStmt(base.Pos, s, sh))
495                 r = walkExpr(r, init)
496                 init.Append(r)
497
498                 // instantiate memmove(to *any, frm *any, size uintptr)
499                 fn = typecheck.LookupRuntime("memmove")
500                 fn = typecheck.SubstArgTypes(fn, t.Elem(), t.Elem())
501                 ncopy := mkcall1(fn, nil, init, ir.NewUnaryExpr(base.Pos, ir.OSPTR, s), copyptr, size)
502                 init.Append(walkExpr(typecheck.Stmt(ncopy), init))
503
504                 return s
505         }
506         // Replace make+copy with runtime.makeslicecopy.
507         // instantiate makeslicecopy(typ *byte, tolen int, fromlen int, from unsafe.Pointer) unsafe.Pointer
508         fn := typecheck.LookupRuntime("makeslicecopy")
509         ptr := mkcall1(fn, types.Types[types.TUNSAFEPTR], init, reflectdata.MakeSliceElemRType(base.Pos, n), length, copylen, typecheck.Conv(copyptr, types.Types[types.TUNSAFEPTR]))
510         ptr.MarkNonNil()
511         sh := ir.NewSliceHeaderExpr(base.Pos, t, ptr, length, length)
512         return walkExpr(typecheck.Expr(sh), init)
513 }
514
515 // walkNew walks an ONEW node.
516 func walkNew(n *ir.UnaryExpr, init *ir.Nodes) ir.Node {
517         t := n.Type().Elem()
518         if t.NotInHeap() {
519                 base.Errorf("%v can't be allocated in Go; it is incomplete (or unallocatable)", n.Type().Elem())
520         }
521         if n.Esc() == ir.EscNone {
522                 if t.Size() > ir.MaxImplicitStackVarSize {
523                         base.Fatalf("large ONEW with EscNone: %v", n)
524                 }
525                 return stackTempAddr(init, t)
526         }
527         types.CalcSize(t)
528         n.MarkNonNil()
529         return n
530 }
531
532 func walkMinMax(n *ir.CallExpr, init *ir.Nodes) ir.Node {
533         init.Append(ir.TakeInit(n)...)
534         walkExprList(n.Args, init)
535         return n
536 }
537
538 // generate code for print.
539 func walkPrint(nn *ir.CallExpr, init *ir.Nodes) ir.Node {
540         // Hoist all the argument evaluation up before the lock.
541         walkExprListCheap(nn.Args, init)
542
543         // For println, add " " between elements and "\n" at the end.
544         if nn.Op() == ir.OPRINTN {
545                 s := nn.Args
546                 t := make([]ir.Node, 0, len(s)*2)
547                 for i, n := range s {
548                         if i != 0 {
549                                 t = append(t, ir.NewString(base.Pos, " "))
550                         }
551                         t = append(t, n)
552                 }
553                 t = append(t, ir.NewString(base.Pos, "\n"))
554                 nn.Args = t
555         }
556
557         // Collapse runs of constant strings.
558         s := nn.Args
559         t := make([]ir.Node, 0, len(s))
560         for i := 0; i < len(s); {
561                 var strs []string
562                 for i < len(s) && ir.IsConst(s[i], constant.String) {
563                         strs = append(strs, ir.StringVal(s[i]))
564                         i++
565                 }
566                 if len(strs) > 0 {
567                         t = append(t, ir.NewString(base.Pos, strings.Join(strs, "")))
568                 }
569                 if i < len(s) {
570                         t = append(t, s[i])
571                         i++
572                 }
573         }
574         nn.Args = t
575
576         calls := []ir.Node{mkcall("printlock", nil, init)}
577         for i, n := range nn.Args {
578                 if n.Op() == ir.OLITERAL {
579                         if n.Type() == types.UntypedRune {
580                                 n = typecheck.DefaultLit(n, types.RuneType)
581                         }
582
583                         switch n.Val().Kind() {
584                         case constant.Int:
585                                 n = typecheck.DefaultLit(n, types.Types[types.TINT64])
586
587                         case constant.Float:
588                                 n = typecheck.DefaultLit(n, types.Types[types.TFLOAT64])
589                         }
590                 }
591
592                 if n.Op() != ir.OLITERAL && n.Type() != nil && n.Type().Kind() == types.TIDEAL {
593                         n = typecheck.DefaultLit(n, types.Types[types.TINT64])
594                 }
595                 n = typecheck.DefaultLit(n, nil)
596                 nn.Args[i] = n
597                 if n.Type() == nil || n.Type().Kind() == types.TFORW {
598                         continue
599                 }
600
601                 var on *ir.Name
602                 switch n.Type().Kind() {
603                 case types.TINTER:
604                         if n.Type().IsEmptyInterface() {
605                                 on = typecheck.LookupRuntime("printeface")
606                         } else {
607                                 on = typecheck.LookupRuntime("printiface")
608                         }
609                         on = typecheck.SubstArgTypes(on, n.Type()) // any-1
610                 case types.TPTR:
611                         if n.Type().Elem().NotInHeap() {
612                                 on = typecheck.LookupRuntime("printuintptr")
613                                 n = ir.NewConvExpr(base.Pos, ir.OCONV, nil, n)
614                                 n.SetType(types.Types[types.TUNSAFEPTR])
615                                 n = ir.NewConvExpr(base.Pos, ir.OCONV, nil, n)
616                                 n.SetType(types.Types[types.TUINTPTR])
617                                 break
618                         }
619                         fallthrough
620                 case types.TCHAN, types.TMAP, types.TFUNC, types.TUNSAFEPTR:
621                         on = typecheck.LookupRuntime("printpointer")
622                         on = typecheck.SubstArgTypes(on, n.Type()) // any-1
623                 case types.TSLICE:
624                         on = typecheck.LookupRuntime("printslice")
625                         on = typecheck.SubstArgTypes(on, n.Type()) // any-1
626                 case types.TUINT, types.TUINT8, types.TUINT16, types.TUINT32, types.TUINT64, types.TUINTPTR:
627                         if types.IsRuntimePkg(n.Type().Sym().Pkg) && n.Type().Sym().Name == "hex" {
628                                 on = typecheck.LookupRuntime("printhex")
629                         } else {
630                                 on = typecheck.LookupRuntime("printuint")
631                         }
632                 case types.TINT, types.TINT8, types.TINT16, types.TINT32, types.TINT64:
633                         on = typecheck.LookupRuntime("printint")
634                 case types.TFLOAT32, types.TFLOAT64:
635                         on = typecheck.LookupRuntime("printfloat")
636                 case types.TCOMPLEX64, types.TCOMPLEX128:
637                         on = typecheck.LookupRuntime("printcomplex")
638                 case types.TBOOL:
639                         on = typecheck.LookupRuntime("printbool")
640                 case types.TSTRING:
641                         cs := ""
642                         if ir.IsConst(n, constant.String) {
643                                 cs = ir.StringVal(n)
644                         }
645                         switch cs {
646                         case " ":
647                                 on = typecheck.LookupRuntime("printsp")
648                         case "\n":
649                                 on = typecheck.LookupRuntime("printnl")
650                         default:
651                                 on = typecheck.LookupRuntime("printstring")
652                         }
653                 default:
654                         badtype(ir.OPRINT, n.Type(), nil)
655                         continue
656                 }
657
658                 r := ir.NewCallExpr(base.Pos, ir.OCALL, on, nil)
659                 if params := on.Type().Params().FieldSlice(); len(params) > 0 {
660                         t := params[0].Type
661                         n = typecheck.Conv(n, t)
662                         r.Args.Append(n)
663                 }
664                 calls = append(calls, r)
665         }
666
667         calls = append(calls, mkcall("printunlock", nil, init))
668
669         typecheck.Stmts(calls)
670         walkExprList(calls, init)
671
672         r := ir.NewBlockStmt(base.Pos, nil)
673         r.List = calls
674         return walkStmt(typecheck.Stmt(r))
675 }
676
677 // walkRecoverFP walks an ORECOVERFP node.
678 func walkRecoverFP(nn *ir.CallExpr, init *ir.Nodes) ir.Node {
679         return mkcall("gorecover", nn.Type(), init, walkExpr(nn.Args[0], init))
680 }
681
682 // walkUnsafeData walks an OUNSAFESLICEDATA or OUNSAFESTRINGDATA expression.
683 func walkUnsafeData(n *ir.UnaryExpr, init *ir.Nodes) ir.Node {
684         slice := walkExpr(n.X, init)
685         res := typecheck.Expr(ir.NewUnaryExpr(n.Pos(), ir.OSPTR, slice))
686         res.SetType(n.Type())
687         return walkExpr(res, init)
688 }
689
690 func walkUnsafeSlice(n *ir.BinaryExpr, init *ir.Nodes) ir.Node {
691         ptr := safeExpr(n.X, init)
692         len := safeExpr(n.Y, init)
693         sliceType := n.Type()
694
695         lenType := types.Types[types.TINT64]
696         unsafePtr := typecheck.Conv(ptr, types.Types[types.TUNSAFEPTR])
697
698         // If checkptr enabled, call runtime.unsafeslicecheckptr to check ptr and len.
699         // for simplicity, unsafeslicecheckptr always uses int64.
700         // Type checking guarantees that TIDEAL len/cap are positive and fit in an int.
701         // The case of len or cap overflow when converting TUINT or TUINTPTR to TINT
702         // will be handled by the negative range checks in unsafeslice during runtime.
703         if ir.ShouldCheckPtr(ir.CurFunc, 1) {
704                 fnname := "unsafeslicecheckptr"
705                 fn := typecheck.LookupRuntime(fnname)
706                 init.Append(mkcall1(fn, nil, init, reflectdata.UnsafeSliceElemRType(base.Pos, n), unsafePtr, typecheck.Conv(len, lenType)))
707         } else {
708                 // Otherwise, open code unsafe.Slice to prevent runtime call overhead.
709                 // Keep this code in sync with runtime.unsafeslice{,64}
710                 if len.Type().IsKind(types.TIDEAL) || len.Type().Size() <= types.Types[types.TUINT].Size() {
711                         lenType = types.Types[types.TINT]
712                 } else {
713                         // len64 := int64(len)
714                         // if int64(int(len64)) != len64 {
715                         //     panicunsafeslicelen()
716                         // }
717                         len64 := typecheck.Conv(len, lenType)
718                         nif := ir.NewIfStmt(base.Pos, nil, nil, nil)
719                         nif.Cond = ir.NewBinaryExpr(base.Pos, ir.ONE, typecheck.Conv(typecheck.Conv(len64, types.Types[types.TINT]), lenType), len64)
720                         nif.Body.Append(mkcall("panicunsafeslicelen", nil, &nif.Body))
721                         appendWalkStmt(init, nif)
722                 }
723
724                 // if len < 0 { panicunsafeslicelen() }
725                 nif := ir.NewIfStmt(base.Pos, nil, nil, nil)
726                 nif.Cond = ir.NewBinaryExpr(base.Pos, ir.OLT, typecheck.Conv(len, lenType), ir.NewInt(base.Pos, 0))
727                 nif.Body.Append(mkcall("panicunsafeslicelen", nil, &nif.Body))
728                 appendWalkStmt(init, nif)
729
730                 if sliceType.Elem().Size() == 0 {
731                         // if ptr == nil && len > 0  {
732                         //      panicunsafesliceptrnil()
733                         // }
734                         nifPtr := ir.NewIfStmt(base.Pos, nil, nil, nil)
735                         isNil := ir.NewBinaryExpr(base.Pos, ir.OEQ, unsafePtr, typecheck.NodNil())
736                         gtZero := ir.NewBinaryExpr(base.Pos, ir.OGT, typecheck.Conv(len, lenType), ir.NewInt(base.Pos, 0))
737                         nifPtr.Cond =
738                                 ir.NewLogicalExpr(base.Pos, ir.OANDAND, isNil, gtZero)
739                         nifPtr.Body.Append(mkcall("panicunsafeslicenilptr", nil, &nifPtr.Body))
740                         appendWalkStmt(init, nifPtr)
741
742                         h := ir.NewSliceHeaderExpr(n.Pos(), sliceType,
743                                 typecheck.Conv(ptr, types.Types[types.TUNSAFEPTR]),
744                                 typecheck.Conv(len, types.Types[types.TINT]),
745                                 typecheck.Conv(len, types.Types[types.TINT]))
746                         return walkExpr(typecheck.Expr(h), init)
747                 }
748
749                 // mem, overflow := runtime.mulUintptr(et.size, len)
750                 mem := typecheck.Temp(types.Types[types.TUINTPTR])
751                 overflow := typecheck.Temp(types.Types[types.TBOOL])
752                 fn := typecheck.LookupRuntime("mulUintptr")
753                 call := mkcall1(fn, fn.Type().Results(), init, ir.NewInt(base.Pos, sliceType.Elem().Size()), typecheck.Conv(typecheck.Conv(len, lenType), types.Types[types.TUINTPTR]))
754                 appendWalkStmt(init, ir.NewAssignListStmt(base.Pos, ir.OAS2, []ir.Node{mem, overflow}, []ir.Node{call}))
755
756                 // if overflow || mem > -uintptr(ptr) {
757                 //     if ptr == nil {
758                 //         panicunsafesliceptrnil()
759                 //     }
760                 //     panicunsafeslicelen()
761                 // }
762                 nif = ir.NewIfStmt(base.Pos, nil, nil, nil)
763                 memCond := ir.NewBinaryExpr(base.Pos, ir.OGT, mem, ir.NewUnaryExpr(base.Pos, ir.ONEG, typecheck.Conv(unsafePtr, types.Types[types.TUINTPTR])))
764                 nif.Cond = ir.NewLogicalExpr(base.Pos, ir.OOROR, overflow, memCond)
765                 nifPtr := ir.NewIfStmt(base.Pos, nil, nil, nil)
766                 nifPtr.Cond = ir.NewBinaryExpr(base.Pos, ir.OEQ, unsafePtr, typecheck.NodNil())
767                 nifPtr.Body.Append(mkcall("panicunsafeslicenilptr", nil, &nifPtr.Body))
768                 nif.Body.Append(nifPtr, mkcall("panicunsafeslicelen", nil, &nif.Body))
769                 appendWalkStmt(init, nif)
770         }
771
772         h := ir.NewSliceHeaderExpr(n.Pos(), sliceType,
773                 typecheck.Conv(ptr, types.Types[types.TUNSAFEPTR]),
774                 typecheck.Conv(len, types.Types[types.TINT]),
775                 typecheck.Conv(len, types.Types[types.TINT]))
776         return walkExpr(typecheck.Expr(h), init)
777 }
778
779 func walkUnsafeString(n *ir.BinaryExpr, init *ir.Nodes) ir.Node {
780         ptr := safeExpr(n.X, init)
781         len := safeExpr(n.Y, init)
782
783         lenType := types.Types[types.TINT64]
784         unsafePtr := typecheck.Conv(ptr, types.Types[types.TUNSAFEPTR])
785
786         // If checkptr enabled, call runtime.unsafestringcheckptr to check ptr and len.
787         // for simplicity, unsafestringcheckptr always uses int64.
788         // Type checking guarantees that TIDEAL len are positive and fit in an int.
789         if ir.ShouldCheckPtr(ir.CurFunc, 1) {
790                 fnname := "unsafestringcheckptr"
791                 fn := typecheck.LookupRuntime(fnname)
792                 init.Append(mkcall1(fn, nil, init, unsafePtr, typecheck.Conv(len, lenType)))
793         } else {
794                 // Otherwise, open code unsafe.String to prevent runtime call overhead.
795                 // Keep this code in sync with runtime.unsafestring{,64}
796                 if len.Type().IsKind(types.TIDEAL) || len.Type().Size() <= types.Types[types.TUINT].Size() {
797                         lenType = types.Types[types.TINT]
798                 } else {
799                         // len64 := int64(len)
800                         // if int64(int(len64)) != len64 {
801                         //     panicunsafestringlen()
802                         // }
803                         len64 := typecheck.Conv(len, lenType)
804                         nif := ir.NewIfStmt(base.Pos, nil, nil, nil)
805                         nif.Cond = ir.NewBinaryExpr(base.Pos, ir.ONE, typecheck.Conv(typecheck.Conv(len64, types.Types[types.TINT]), lenType), len64)
806                         nif.Body.Append(mkcall("panicunsafestringlen", nil, &nif.Body))
807                         appendWalkStmt(init, nif)
808                 }
809
810                 // if len < 0 { panicunsafestringlen() }
811                 nif := ir.NewIfStmt(base.Pos, nil, nil, nil)
812                 nif.Cond = ir.NewBinaryExpr(base.Pos, ir.OLT, typecheck.Conv(len, lenType), ir.NewInt(base.Pos, 0))
813                 nif.Body.Append(mkcall("panicunsafestringlen", nil, &nif.Body))
814                 appendWalkStmt(init, nif)
815
816                 // if uintpr(len) > -uintptr(ptr) {
817                 //    if ptr == nil {
818                 //       panicunsafestringnilptr()
819                 //    }
820                 //    panicunsafeslicelen()
821                 // }
822                 nifLen := ir.NewIfStmt(base.Pos, nil, nil, nil)
823                 nifLen.Cond = ir.NewBinaryExpr(base.Pos, ir.OGT, typecheck.Conv(len, types.Types[types.TUINTPTR]), ir.NewUnaryExpr(base.Pos, ir.ONEG, typecheck.Conv(unsafePtr, types.Types[types.TUINTPTR])))
824                 nifPtr := ir.NewIfStmt(base.Pos, nil, nil, nil)
825                 nifPtr.Cond = ir.NewBinaryExpr(base.Pos, ir.OEQ, unsafePtr, typecheck.NodNil())
826                 nifPtr.Body.Append(mkcall("panicunsafestringnilptr", nil, &nifPtr.Body))
827                 nifLen.Body.Append(nifPtr, mkcall("panicunsafestringlen", nil, &nifLen.Body))
828                 appendWalkStmt(init, nifLen)
829         }
830         h := ir.NewStringHeaderExpr(n.Pos(),
831                 typecheck.Conv(ptr, types.Types[types.TUNSAFEPTR]),
832                 typecheck.Conv(len, types.Types[types.TINT]),
833         )
834         return walkExpr(typecheck.Expr(h), init)
835 }
836
837 func badtype(op ir.Op, tl, tr *types.Type) {
838         var s string
839         if tl != nil {
840                 s += fmt.Sprintf("\n\t%v", tl)
841         }
842         if tr != nil {
843                 s += fmt.Sprintf("\n\t%v", tr)
844         }
845
846         // common mistake: *struct and *interface.
847         if tl != nil && tr != nil && tl.IsPtr() && tr.IsPtr() {
848                 if tl.Elem().IsStruct() && tr.Elem().IsInterface() {
849                         s += "\n\t(*struct vs *interface)"
850                 } else if tl.Elem().IsInterface() && tr.Elem().IsStruct() {
851                         s += "\n\t(*interface vs *struct)"
852                 }
853         }
854
855         base.Errorf("illegal types for operand: %v%s", op, s)
856 }
857
858 func writebarrierfn(name string, l *types.Type, r *types.Type) ir.Node {
859         fn := typecheck.LookupRuntime(name)
860         fn = typecheck.SubstArgTypes(fn, l, r)
861         return fn
862 }
863
864 // isRuneCount reports whether n is of the form len([]rune(string)).
865 // These are optimized into a call to runtime.countrunes.
866 func isRuneCount(n ir.Node) bool {
867         return base.Flag.N == 0 && !base.Flag.Cfg.Instrumenting && n.Op() == ir.OLEN && n.(*ir.UnaryExpr).X.Op() == ir.OSTR2RUNES
868 }
869
870 // isByteCount reports whether n is of the form len(string([]byte)).
871 func isByteCount(n ir.Node) bool {
872         return base.Flag.N == 0 && !base.Flag.Cfg.Instrumenting && n.Op() == ir.OLEN &&
873                 (n.(*ir.UnaryExpr).X.Op() == ir.OBYTES2STR || n.(*ir.UnaryExpr).X.Op() == ir.OBYTES2STRTMP)
874 }