vs.go

  1package ssa
  2
  3import (
  4	"fmt"
  5	"math"
  6
  7	"github.com/tetratelabs/wazero/internal/engine/wazevo/wazevoapi"
  8)
  9
 10// Variable is a unique identifier for a source program's variable and will correspond to
 11// multiple ssa Value(s).
 12//
 13// For example, `Local 1` is a Variable in WebAssembly, and Value(s) will be created for it
 14// whenever it executes `local.set 1`.
 15//
 16// Variable is useful to track the SSA Values of a variable in the source program, and
 17// can be used to find the corresponding latest SSA Value via Builder.FindValue.
 18//
 19// Higher 4-bit is used to store Type for this variable.
 20type Variable uint32
 21
 22// String implements fmt.Stringer.
 23func (v Variable) String() string {
 24	return fmt.Sprintf("var%d", v&0x0fffffff)
 25}
 26
 27func (v Variable) setType(typ Type) Variable {
 28	if v >= 1<<28 {
 29		panic(fmt.Sprintf("Too large variable: %d", v))
 30	}
 31	return Variable(typ)<<28 | v
 32}
 33
 34func (v Variable) getType() Type {
 35	return Type(v >> 28)
 36}
 37
 38// Value represents an SSA value with a type information. The relationship with Variable is 1: N (including 0),
 39// that means there might be multiple Variable(s) for a Value.
 40//
 41// 32 to 59-bit is used to store the unique identifier of the Instruction that generates this value if any.
 42// 60 to 63-bit is used to store Type for this value.
 43type Value uint64
 44
 45// ValueID is the lower 32bit of Value, which is the pure identifier of Value without type info.
 46type ValueID uint32
 47
 48const (
 49	valueIDInvalid ValueID = math.MaxUint32
 50	ValueInvalid           = Value(valueIDInvalid)
 51)
 52
 53// Format creates a debug string for this Value using the data stored in Builder.
 54func (v Value) Format(b Builder) string {
 55	if annotation, ok := b.(*builder).valueAnnotations[v.ID()]; ok {
 56		return annotation
 57	}
 58	return fmt.Sprintf("v%d", v.ID())
 59}
 60
 61func (v Value) formatWithType(b Builder) (ret string) {
 62	if annotation, ok := b.(*builder).valueAnnotations[v.ID()]; ok {
 63		ret = annotation + ":" + v.Type().String()
 64	} else {
 65		ret = fmt.Sprintf("v%d:%s", v.ID(), v.Type())
 66	}
 67
 68	if wazevoapi.SSALoggingEnabled { // This is useful to check live value analysis bugs.
 69		if bd := b.(*builder); bd.donePostBlockLayoutPasses {
 70			id := v.ID()
 71			ret += fmt.Sprintf("(ref=%d)", bd.valuesInfo[id].RefCount)
 72		}
 73	}
 74	return ret
 75}
 76
 77// Valid returns true if this value is valid.
 78func (v Value) Valid() bool {
 79	return v.ID() != valueIDInvalid
 80}
 81
 82// Type returns the Type of this value.
 83func (v Value) Type() Type {
 84	return Type(v >> 60)
 85}
 86
 87// ID returns the valueID of this value.
 88func (v Value) ID() ValueID {
 89	return ValueID(v)
 90}
 91
 92// setType sets a type to this Value and returns the updated Value.
 93func (v Value) setType(typ Type) Value {
 94	return v | Value(typ)<<60
 95}
 96
 97// setInstructionID sets an Instruction.id to this Value and returns the updated Value.
 98func (v Value) setInstructionID(id int) Value {
 99	if id < 0 || uint(id) >= 1<<28 {
100		panic(fmt.Sprintf("Too large instruction ID: %d", id))
101	}
102	return v | Value(id)<<32
103}
104
105// instructionID() returns the Instruction.id of this Value.
106func (v Value) instructionID() int {
107	return int(v>>32) & 0x0fffffff
108}
109
110// Values is a slice of Value. Use this instead of []Value to reuse the underlying memory.
111type Values = wazevoapi.VarLength[Value]
112
113// ValuesNil is a nil Values.
114var ValuesNil = wazevoapi.NewNilVarLength[Value]()