1 // Copyright 2018 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.
8 "cmd/compile/internal/base"
9 "cmd/compile/internal/ir"
12 // addr evaluates an addressable expression n and returns a hole
13 // that represents storing into the represented location.
14 func (e *escape) addr(n ir.Node) hole {
15 if n == nil || ir.IsBlank(n) {
16 // Can happen in select case, range, maybe others.
17 return e.discardHole()
24 base.Fatalf("unexpected addr: %v", n)
27 if n.Class == ir.PEXTERN {
30 k = e.oldLoc(n).asHole()
31 case ir.OLINKSYMOFFSET:
34 n := n.(*ir.SelectorExpr)
37 n := n.(*ir.IndexExpr)
39 if n.X.Type().IsArray() {
44 case ir.ODEREF, ir.ODOTPTR:
47 n := n.(*ir.IndexExpr)
49 e.assignHeap(n.Index, "key of map put", n)
55 func (e *escape) addrs(l ir.Nodes) []hole {
58 ks = append(ks, e.addr(n))
63 func (e *escape) assignHeap(src ir.Node, why string, where ir.Node) {
64 e.expr(e.heapHole().note(where, why), src)
67 // assignList evaluates the assignment dsts... = srcs....
68 func (e *escape) assignList(dsts, srcs []ir.Node, why string, where ir.Node) {
70 for i, k := range ks {
76 if dst := dsts[i]; dst != nil {
77 // Detect implicit conversion of uintptr to unsafe.Pointer when
78 // storing into reflect.{Slice,String}Header.
79 if dst.Op() == ir.ODOTPTR && ir.IsReflectHeaderDataField(dst) {
80 e.unsafeValue(e.heapHole().note(where, why), src)
84 // Filter out some no-op assignments for escape analysis.
85 if src != nil && isSelfAssign(dst, src) {
86 if base.Flag.LowerM != 0 {
87 base.WarnfAt(where.Pos(), "%v ignoring self-assignment in %v", e.curfn, where)
93 e.expr(k.note(where, why), src)
96 e.reassigned(ks, where)
99 // reassigned marks the locations associated with the given holes as
100 // reassigned, unless the location represents a variable declared and
101 // assigned exactly once by where.
102 func (e *escape) reassigned(ks []hole, where ir.Node) {
103 if as, ok := where.(*ir.AssignStmt); ok && as.Op() == ir.OAS && as.Y == nil {
104 if dst, ok := as.X.(*ir.Name); ok && dst.Op() == ir.ONAME && dst.Defn == nil {
105 // Zero-value assignment for variable declared without an
106 // explicit initial value. Assume this is its initialization
112 for _, k := range ks {
114 // Variables declared by range statements are assigned on every iteration.
115 if n, ok := loc.n.(*ir.Name); ok && n.Defn == where && where.Op() != ir.ORANGE {
118 loc.reassigned = true