blob: 9dd4194d07ad36d9dba5b84e60c01f7c3bec8b83 [file] [log] [blame]
// Copyright 2025 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package ssa
// useInfo provides a map from a value to the users of that value.
// We do not keep track of this data in the IR directly, as it is
// expensive to keep updated. But sometimes we need to compute it
// temporarily.
//
// A useInfo is only valid until the next modification of the IR.
//
// Note that block control uses are not reported. (TODO: add
// if needed.)
// Also, index of use is not reported. (TODO: add if needed.)
//
// We keep track of all uses in a single array, and use a
// starts array to tell us where to find the sub-array for
// each value.
//
// For a function with 10 values, we would have:
//
// starts[0] starts[1] starts[2] starts[9] len(uses)
// | | | | |
// v v v v v
// +------------+------------+-...-+------------+
// | uses of v0 | uses of v1 | ... | uses of v9 |
// +------------+------------+-...-+------------+
//
// We can find all the uses of v by listing all entries
// of uses between starts[v.ID] and starts[v.ID+1].
type useInfo struct {
starts []int32
uses []*Value
}
// build useInfo for a function. Result only valid until
// the next modification of f.
func uses(f *Func) useInfo {
// Write down number of uses of each value.
idx := f.Cache.allocInt32Slice(f.NumValues())
for _, b := range f.Blocks {
for _, v := range b.Values {
idx[v.ID] = v.Uses
}
}
// Compute cumulative sum of uses up to and
// including each value ID.
var cum int32
for vid, uses := range idx {
cum += uses
idx[vid] = cum
}
// Compute uses.
uses := f.Cache.allocValueSlice(int(cum))
for _, b := range f.Blocks {
for _, v := range b.Values {
for _, a := range v.Args {
idx[a.ID]--
uses[idx[a.ID]] = v
}
}
}
for _, b := range f.Blocks {
for _, c := range b.ControlValues() {
// We don't track block control uses, but
// we have to decrement idx values here
// so that the accounting comes out right.
// Each value will have, at the start of its
// use list, a bunch of nils that represent
// the number of Block.Control uses.
idx[c.ID]--
}
}
// The loop above decremented each idx entry
// by the number of uses. It now contains
// the sum of uses up to, but not including,
// each value ID.
return useInfo{starts: idx, uses: uses}
}
// get returns a list of uses of v.
// Every use in an argument slot is listed (e.g. for
// w=(Add v v), w is listed twice in the uses of v).
// Uses by Block.Controls are not reported.
func (u useInfo) get(v *Value) []*Value {
i := u.starts[v.ID]
var j int32
if int(v.ID) < len(u.starts)-1 {
j = u.starts[v.ID+1]
} else {
j = int32(len(u.uses))
}
r := u.uses[i:j]
// skip nil entries from block control uses
for len(r) > 0 && r[0] == nil {
r = r[1:]
}
return r
}
func (u useInfo) free(f *Func) {
f.Cache.freeInt32Slice(u.starts)
f.Cache.freeValueSlice(u.uses)
}