...

Source file src/pkg/cmd/compile/internal/ssa/value.go

     1	// Copyright 2015 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 ssa
     6	
     7	import (
     8		"cmd/compile/internal/types"
     9		"cmd/internal/src"
    10		"fmt"
    11		"math"
    12		"sort"
    13		"strings"
    14	)
    15	
    16	// A Value represents a value in the SSA representation of the program.
    17	// The ID and Type fields must not be modified. The remainder may be modified
    18	// if they preserve the value of the Value (e.g. changing a (mul 2 x) to an (add x x)).
    19	type Value struct {
    20		// A unique identifier for the value. For performance we allocate these IDs
    21		// densely starting at 1.  There is no guarantee that there won't be occasional holes, though.
    22		ID ID
    23	
    24		// The operation that computes this value. See op.go.
    25		Op Op
    26	
    27		// The type of this value. Normally this will be a Go type, but there
    28		// are a few other pseudo-types, see ../types/type.go.
    29		Type *types.Type
    30	
    31		// Auxiliary info for this value. The type of this information depends on the opcode and type.
    32		// AuxInt is used for integer values, Aux is used for other values.
    33		// Floats are stored in AuxInt using math.Float64bits(f).
    34		// Unused portions of AuxInt are filled by sign-extending the used portion,
    35		// even if the represented value is unsigned.
    36		// Users of AuxInt which interpret AuxInt as unsigned (e.g. shifts) must be careful.
    37		// Use Value.AuxUnsigned to get the zero-extended value of AuxInt.
    38		AuxInt int64
    39		Aux    interface{}
    40	
    41		// Arguments of this value
    42		Args []*Value
    43	
    44		// Containing basic block
    45		Block *Block
    46	
    47		// Source position
    48		Pos src.XPos
    49	
    50		// Use count. Each appearance in Value.Args and Block.Control counts once.
    51		Uses int32
    52	
    53		// wasm: Value stays on the WebAssembly stack. This value will not get a "register" (WebAssembly variable)
    54		// nor a slot on Go stack, and the generation of this value is delayed to its use time.
    55		OnWasmStack bool
    56	
    57		// Storage for the first three args
    58		argstorage [3]*Value
    59	}
    60	
    61	// Examples:
    62	// Opcode          aux   args
    63	//  OpAdd          nil      2
    64	//  OpConst     string      0    string constant
    65	//  OpConst      int64      0    int64 constant
    66	//  OpAddcq      int64      1    amd64 op: v = arg[0] + constant
    67	
    68	// short form print. Just v#.
    69	func (v *Value) String() string {
    70		if v == nil {
    71			return "nil" // should never happen, but not panicking helps with debugging
    72		}
    73		return fmt.Sprintf("v%d", v.ID)
    74	}
    75	
    76	func (v *Value) AuxInt8() int8 {
    77		if opcodeTable[v.Op].auxType != auxInt8 {
    78			v.Fatalf("op %s doesn't have an int8 aux field", v.Op)
    79		}
    80		return int8(v.AuxInt)
    81	}
    82	
    83	func (v *Value) AuxInt16() int16 {
    84		if opcodeTable[v.Op].auxType != auxInt16 {
    85			v.Fatalf("op %s doesn't have an int16 aux field", v.Op)
    86		}
    87		return int16(v.AuxInt)
    88	}
    89	
    90	func (v *Value) AuxInt32() int32 {
    91		if opcodeTable[v.Op].auxType != auxInt32 {
    92			v.Fatalf("op %s doesn't have an int32 aux field", v.Op)
    93		}
    94		return int32(v.AuxInt)
    95	}
    96	
    97	// AuxUnsigned returns v.AuxInt as an unsigned value for OpConst*.
    98	// v.AuxInt is always sign-extended to 64 bits, even if the
    99	// represented value is unsigned. This undoes that sign extension.
   100	func (v *Value) AuxUnsigned() uint64 {
   101		c := v.AuxInt
   102		switch v.Op {
   103		case OpConst64:
   104			return uint64(c)
   105		case OpConst32:
   106			return uint64(uint32(c))
   107		case OpConst16:
   108			return uint64(uint16(c))
   109		case OpConst8:
   110			return uint64(uint8(c))
   111		}
   112		v.Fatalf("op %s isn't OpConst*", v.Op)
   113		return 0
   114	}
   115	
   116	func (v *Value) AuxFloat() float64 {
   117		if opcodeTable[v.Op].auxType != auxFloat32 && opcodeTable[v.Op].auxType != auxFloat64 {
   118			v.Fatalf("op %s doesn't have a float aux field", v.Op)
   119		}
   120		return math.Float64frombits(uint64(v.AuxInt))
   121	}
   122	func (v *Value) AuxValAndOff() ValAndOff {
   123		if opcodeTable[v.Op].auxType != auxSymValAndOff {
   124			v.Fatalf("op %s doesn't have a ValAndOff aux field", v.Op)
   125		}
   126		return ValAndOff(v.AuxInt)
   127	}
   128	
   129	// long form print.  v# = opcode <type> [aux] args [: reg] (names)
   130	func (v *Value) LongString() string {
   131		s := fmt.Sprintf("v%d = %s", v.ID, v.Op)
   132		s += " <" + v.Type.String() + ">"
   133		s += v.auxString()
   134		for _, a := range v.Args {
   135			s += fmt.Sprintf(" %v", a)
   136		}
   137		var r []Location
   138		if v.Block != nil {
   139			r = v.Block.Func.RegAlloc
   140		}
   141		if int(v.ID) < len(r) && r[v.ID] != nil {
   142			s += " : " + r[v.ID].String()
   143		}
   144		var names []string
   145		if v.Block != nil {
   146			for name, values := range v.Block.Func.NamedValues {
   147				for _, value := range values {
   148					if value == v {
   149						names = append(names, name.String())
   150						break // drop duplicates.
   151					}
   152				}
   153			}
   154		}
   155		if len(names) != 0 {
   156			sort.Strings(names) // Otherwise a source of variation in debugging output.
   157			s += " (" + strings.Join(names, ", ") + ")"
   158		}
   159		return s
   160	}
   161	
   162	func (v *Value) auxString() string {
   163		switch opcodeTable[v.Op].auxType {
   164		case auxBool:
   165			if v.AuxInt == 0 {
   166				return " [false]"
   167			} else {
   168				return " [true]"
   169			}
   170		case auxInt8:
   171			return fmt.Sprintf(" [%d]", v.AuxInt8())
   172		case auxInt16:
   173			return fmt.Sprintf(" [%d]", v.AuxInt16())
   174		case auxInt32:
   175			return fmt.Sprintf(" [%d]", v.AuxInt32())
   176		case auxInt64, auxInt128:
   177			return fmt.Sprintf(" [%d]", v.AuxInt)
   178		case auxFloat32, auxFloat64:
   179			return fmt.Sprintf(" [%g]", v.AuxFloat())
   180		case auxString:
   181			return fmt.Sprintf(" {%q}", v.Aux)
   182		case auxSym, auxTyp:
   183			if v.Aux != nil {
   184				return fmt.Sprintf(" {%v}", v.Aux)
   185			}
   186		case auxSymOff, auxSymInt32, auxTypSize:
   187			s := ""
   188			if v.Aux != nil {
   189				s = fmt.Sprintf(" {%v}", v.Aux)
   190			}
   191			if v.AuxInt != 0 {
   192				s += fmt.Sprintf(" [%v]", v.AuxInt)
   193			}
   194			return s
   195		case auxSymValAndOff:
   196			s := ""
   197			if v.Aux != nil {
   198				s = fmt.Sprintf(" {%v}", v.Aux)
   199			}
   200			return s + fmt.Sprintf(" [%s]", v.AuxValAndOff())
   201		case auxCCop:
   202			return fmt.Sprintf(" {%s}", v.Aux.(Op))
   203		}
   204		return ""
   205	}
   206	
   207	// If/when midstack inlining is enabled (-l=4), the compiler gets both larger and slower.
   208	// Not-inlining this method is a help (*Value.reset and *Block.NewValue0 are similar).
   209	//go:noinline
   210	func (v *Value) AddArg(w *Value) {
   211		if v.Args == nil {
   212			v.resetArgs() // use argstorage
   213		}
   214		v.Args = append(v.Args, w)
   215		w.Uses++
   216	}
   217	func (v *Value) AddArgs(a ...*Value) {
   218		if v.Args == nil {
   219			v.resetArgs() // use argstorage
   220		}
   221		v.Args = append(v.Args, a...)
   222		for _, x := range a {
   223			x.Uses++
   224		}
   225	}
   226	func (v *Value) SetArg(i int, w *Value) {
   227		v.Args[i].Uses--
   228		v.Args[i] = w
   229		w.Uses++
   230	}
   231	func (v *Value) RemoveArg(i int) {
   232		v.Args[i].Uses--
   233		copy(v.Args[i:], v.Args[i+1:])
   234		v.Args[len(v.Args)-1] = nil // aid GC
   235		v.Args = v.Args[:len(v.Args)-1]
   236	}
   237	func (v *Value) SetArgs1(a *Value) {
   238		v.resetArgs()
   239		v.AddArg(a)
   240	}
   241	func (v *Value) SetArgs2(a *Value, b *Value) {
   242		v.resetArgs()
   243		v.AddArg(a)
   244		v.AddArg(b)
   245	}
   246	
   247	func (v *Value) resetArgs() {
   248		for _, a := range v.Args {
   249			a.Uses--
   250		}
   251		v.argstorage[0] = nil
   252		v.argstorage[1] = nil
   253		v.argstorage[2] = nil
   254		v.Args = v.argstorage[:0]
   255	}
   256	
   257	func (v *Value) reset(op Op) {
   258		v.Op = op
   259		if op != OpCopy && notStmtBoundary(op) {
   260			// Special case for OpCopy because of how it is used in rewrite
   261			v.Pos = v.Pos.WithNotStmt()
   262		}
   263		v.resetArgs()
   264		v.AuxInt = 0
   265		v.Aux = nil
   266	}
   267	
   268	// copyInto makes a new value identical to v and adds it to the end of b.
   269	func (v *Value) copyInto(b *Block) *Value {
   270		c := b.NewValue0(v.Pos.WithNotStmt(), v.Op, v.Type) // Lose the position, this causes line number churn otherwise.
   271		c.Aux = v.Aux
   272		c.AuxInt = v.AuxInt
   273		c.AddArgs(v.Args...)
   274		for _, a := range v.Args {
   275			if a.Type.IsMemory() {
   276				v.Fatalf("can't move a value with a memory arg %s", v.LongString())
   277			}
   278		}
   279		return c
   280	}
   281	
   282	// copyIntoWithXPos makes a new value identical to v and adds it to the end of b.
   283	// The supplied position is used as the position of the new value.
   284	func (v *Value) copyIntoWithXPos(b *Block, pos src.XPos) *Value {
   285		c := b.NewValue0(pos, v.Op, v.Type)
   286		c.Aux = v.Aux
   287		c.AuxInt = v.AuxInt
   288		c.AddArgs(v.Args...)
   289		for _, a := range v.Args {
   290			if a.Type.IsMemory() {
   291				v.Fatalf("can't move a value with a memory arg %s", v.LongString())
   292			}
   293		}
   294		return c
   295	}
   296	
   297	func (v *Value) Logf(msg string, args ...interface{}) { v.Block.Logf(msg, args...) }
   298	func (v *Value) Log() bool                            { return v.Block.Log() }
   299	func (v *Value) Fatalf(msg string, args ...interface{}) {
   300		v.Block.Func.fe.Fatalf(v.Pos, msg, args...)
   301	}
   302	
   303	// isGenericIntConst reports whether v is a generic integer constant.
   304	func (v *Value) isGenericIntConst() bool {
   305		return v != nil && (v.Op == OpConst64 || v.Op == OpConst32 || v.Op == OpConst16 || v.Op == OpConst8)
   306	}
   307	
   308	// Reg returns the register assigned to v, in cmd/internal/obj/$ARCH numbering.
   309	func (v *Value) Reg() int16 {
   310		reg := v.Block.Func.RegAlloc[v.ID]
   311		if reg == nil {
   312			v.Fatalf("nil register for value: %s\n%s\n", v.LongString(), v.Block.Func)
   313		}
   314		return reg.(*Register).objNum
   315	}
   316	
   317	// Reg0 returns the register assigned to the first output of v, in cmd/internal/obj/$ARCH numbering.
   318	func (v *Value) Reg0() int16 {
   319		reg := v.Block.Func.RegAlloc[v.ID].(LocPair)[0]
   320		if reg == nil {
   321			v.Fatalf("nil first register for value: %s\n%s\n", v.LongString(), v.Block.Func)
   322		}
   323		return reg.(*Register).objNum
   324	}
   325	
   326	// Reg1 returns the register assigned to the second output of v, in cmd/internal/obj/$ARCH numbering.
   327	func (v *Value) Reg1() int16 {
   328		reg := v.Block.Func.RegAlloc[v.ID].(LocPair)[1]
   329		if reg == nil {
   330			v.Fatalf("nil second register for value: %s\n%s\n", v.LongString(), v.Block.Func)
   331		}
   332		return reg.(*Register).objNum
   333	}
   334	
   335	func (v *Value) RegName() string {
   336		reg := v.Block.Func.RegAlloc[v.ID]
   337		if reg == nil {
   338			v.Fatalf("nil register for value: %s\n%s\n", v.LongString(), v.Block.Func)
   339		}
   340		return reg.(*Register).name
   341	}
   342	
   343	// MemoryArg returns the memory argument for the Value.
   344	// The returned value, if non-nil, will be memory-typed (or a tuple with a memory-typed second part).
   345	// Otherwise, nil is returned.
   346	func (v *Value) MemoryArg() *Value {
   347		if v.Op == OpPhi {
   348			v.Fatalf("MemoryArg on Phi")
   349		}
   350		na := len(v.Args)
   351		if na == 0 {
   352			return nil
   353		}
   354		if m := v.Args[na-1]; m.Type.IsMemory() {
   355			return m
   356		}
   357		return nil
   358	}
   359	
   360	// LackingPos indicates whether v is a value that is unlikely to have a correct
   361	// position assigned to it.  Ignoring such values leads to more user-friendly positions
   362	// assigned to nearby values and the blocks containing them.
   363	func (v *Value) LackingPos() bool {
   364		// The exact definition of LackingPos is somewhat heuristically defined and may change
   365		// in the future, for example if some of these operations are generated more carefully
   366		// with respect to their source position.
   367		return v.Op == OpVarDef || v.Op == OpVarKill || v.Op == OpVarLive || v.Op == OpPhi ||
   368			(v.Op == OpFwdRef || v.Op == OpCopy) && v.Type == types.TypeMem
   369	}
   370	

View as plain text