github.com/llvm-mirror/llgo@v0.0.0-20190322182713-bf6f0a60fce1/third_party/gotools/go/pointer/opt.go (about) 1 // Copyright 2013 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 pointer 6 7 // This file implements renumbering, a pre-solver optimization to 8 // improve the efficiency of the solver's points-to set representation. 9 // 10 // TODO(adonovan): rename file "renumber.go" 11 12 import "fmt" 13 14 // renumber permutes a.nodes so that all nodes within an addressable 15 // object appear before all non-addressable nodes, maintaining the 16 // order of nodes within the same object (as required by offsetAddr). 17 // 18 // renumber must update every nodeid in the analysis (constraints, 19 // Pointers, callgraph, etc) to reflect the new ordering. 20 // 21 // This is an optimisation to increase the locality and efficiency of 22 // sparse representations of points-to sets. (Typically only about 23 // 20% of nodes are within an object.) 24 // 25 // NB: nodes added during solving (e.g. for reflection, SetFinalizer) 26 // will be appended to the end. 27 // 28 // Renumbering makes the PTA log inscrutable. To aid debugging, later 29 // phases (e.g. HVN) must not rely on it having occurred. 30 // 31 func (a *analysis) renumber() { 32 if a.log != nil { 33 fmt.Fprintf(a.log, "\n\n==== Renumbering\n\n") 34 } 35 36 N := nodeid(len(a.nodes)) 37 newNodes := make([]*node, N, N) 38 renumbering := make([]nodeid, N, N) // maps old to new 39 40 var i, j nodeid 41 42 // The zero node is special. 43 newNodes[j] = a.nodes[i] 44 renumbering[i] = j 45 i++ 46 j++ 47 48 // Pass 1: object nodes. 49 for i < N { 50 obj := a.nodes[i].obj 51 if obj == nil { 52 i++ 53 continue 54 } 55 56 end := i + nodeid(obj.size) 57 for i < end { 58 newNodes[j] = a.nodes[i] 59 renumbering[i] = j 60 i++ 61 j++ 62 } 63 } 64 nobj := j 65 66 // Pass 2: non-object nodes. 67 for i = 1; i < N; { 68 obj := a.nodes[i].obj 69 if obj != nil { 70 i += nodeid(obj.size) 71 continue 72 } 73 74 newNodes[j] = a.nodes[i] 75 renumbering[i] = j 76 i++ 77 j++ 78 } 79 80 if j != N { 81 panic(fmt.Sprintf("internal error: j=%d, N=%d", j, N)) 82 } 83 84 // Log the remapping table. 85 if a.log != nil { 86 fmt.Fprintf(a.log, "Renumbering nodes to improve density:\n") 87 fmt.Fprintf(a.log, "(%d object nodes of %d total)\n", nobj, N) 88 for old, new := range renumbering { 89 fmt.Fprintf(a.log, "\tn%d -> n%d\n", old, new) 90 } 91 } 92 93 // Now renumber all existing nodeids to use the new node permutation. 94 // It is critical that all reachable nodeids are accounted for! 95 96 // Renumber nodeids in queried Pointers. 97 for v, ptr := range a.result.Queries { 98 ptr.n = renumbering[ptr.n] 99 a.result.Queries[v] = ptr 100 } 101 for v, ptr := range a.result.IndirectQueries { 102 ptr.n = renumbering[ptr.n] 103 a.result.IndirectQueries[v] = ptr 104 } 105 106 // Renumber nodeids in global objects. 107 for v, id := range a.globalobj { 108 a.globalobj[v] = renumbering[id] 109 } 110 111 // Renumber nodeids in constraints. 112 for _, c := range a.constraints { 113 c.renumber(renumbering) 114 } 115 116 // Renumber nodeids in the call graph. 117 for _, cgn := range a.cgnodes { 118 cgn.obj = renumbering[cgn.obj] 119 for _, site := range cgn.sites { 120 site.targets = renumbering[site.targets] 121 } 122 } 123 124 a.nodes = newNodes 125 }