Source file src/cmd/compile/internal/ssacompile/uses.go
1 // Copyright 2025 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 ssacompile 6 7 import "cmd/compile/internal/ssa" 8 9 // useInfo provides a map from a value to the users of that value. 10 // We do not keep track of this data in the IR directly, as it is 11 // expensive to keep updated. But sometimes we need to compute it 12 // temporarily. 13 // 14 // A useInfo is only valid until the next modification of the IR. 15 // 16 // Note that block control uses are not reported. (TODO: add 17 // if needed.) 18 // Also, index of use is not reported. (TODO: add if needed.) 19 // 20 // We keep track of all uses in a single array, and use a 21 // starts array to tell us where to find the sub-array for 22 // each value. 23 // 24 // For a function with 10 values, we would have: 25 // 26 // starts[0] starts[1] starts[2] starts[9] len(uses) 27 // | | | | | 28 // v v v v v 29 // +------------+------------+-...-+------------+ 30 // | uses of v0 | uses of v1 | ... | uses of v9 | 31 // +------------+------------+-...-+------------+ 32 // 33 // We can find all the uses of v by listing all entries 34 // of uses between starts[v.ID] and starts[v.ID+1]. 35 type useInfo struct { 36 starts []int32 37 uses []*ssa.Value 38 } 39 40 // build useInfo for a function. Result only valid until 41 // the next modification of f. 42 func uses(f *ssa.Func) useInfo { 43 // Write down number of uses of each value. 44 idx := f.Cache.AllocInt32Slice(f.NumValues()) 45 for _, b := range f.Blocks { 46 for _, v := range b.Values { 47 idx[v.ID] = v.Uses 48 } 49 } 50 51 // Compute cumulative sum of uses up to and 52 // including each value ID. 53 var cum int32 54 for vid, uses := range idx { 55 cum += uses 56 idx[vid] = cum 57 } 58 59 // Compute uses. 60 uses := f.Cache.AllocValueSlice(int(cum)) 61 for _, b := range f.Blocks { 62 for _, v := range b.Values { 63 for _, a := range v.Args { 64 idx[a.ID]-- 65 uses[idx[a.ID]] = v 66 } 67 } 68 } 69 for _, b := range f.Blocks { 70 for _, c := range b.ControlValues() { 71 // We don't track block control uses, but 72 // we have to decrement idx values here 73 // so that the accounting comes out right. 74 // Each value will have, at the start of its 75 // use list, a bunch of nils that represent 76 // the number of Block.Control uses. 77 idx[c.ID]-- 78 } 79 } 80 81 // The loop above decremented each idx entry 82 // by the number of uses. It now contains 83 // the sum of uses up to, but not including, 84 // each value ID. 85 return useInfo{starts: idx, uses: uses} 86 } 87 88 // get returns a list of uses of v. 89 // Every use in an argument slot is listed (e.g. for 90 // w=(Add v v), w is listed twice in the uses of v). 91 // Uses by Block.Controls are not reported. 92 func (u useInfo) get(v *ssa.Value) []*ssa.Value { 93 i := u.starts[v.ID] 94 var j int32 95 if int(v.ID) < len(u.starts)-1 { 96 j = u.starts[v.ID+1] 97 } else { 98 j = int32(len(u.uses)) 99 } 100 r := u.uses[i:j] 101 // skip nil entries from block control uses 102 for len(r) > 0 && r[0] == nil { 103 r = r[1:] 104 } 105 return r 106 } 107 108 func (u useInfo) free(f *ssa.Func) { 109 f.Cache.FreeInt32Slice(u.starts) 110 f.Cache.FreeValueSlice(u.uses) 111 } 112