Help us shape the future of Go! Take the 2026 Go Developer Survey

Source file src/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  	"fmt"
     9  	"internal/buildcfg"
    10  	"math"
    11  	"sort"
    12  	"strings"
    13  
    14  	"cmd/compile/internal/ir"
    15  	"cmd/compile/internal/ssa/ssabase"
    16  	"cmd/compile/internal/ssa/ssaop"
    17  	"cmd/compile/internal/types"
    18  	"cmd/internal/src"
    19  )
    20  
    21  // A Value represents a value in the SSA representation of the program.
    22  // The ID and Type fields must not be modified. The remainder may be modified
    23  // if they preserve the value of the Value (e.g. changing a (mul 2 x) to an (add x x)).
    24  type Value struct {
    25  	// A unique identifier for the value. For performance we allocate these IDs
    26  	// densely starting at 1.  There is no guarantee that there won't be occasional holes, though.
    27  	ID ID
    28  
    29  	// The operation that computes this value. See op.go.
    30  	Op ssaop.Op
    31  
    32  	// The type of this value. Normally this will be a Go type, but there
    33  	// are a few other pseudo-types, see ../types/type.go.
    34  	Type *types.Type
    35  
    36  	// Auxiliary info for this value. The type of this information depends on the opcode and type.
    37  	// AuxInt is used for integer values, Aux is used for other values.
    38  	// Floats are stored in AuxInt using math.Float64bits(f).
    39  	// Unused portions of AuxInt are filled by sign-extending the used portion,
    40  	// even if the represented value is unsigned.
    41  	// Users of AuxInt which interpret AuxInt as unsigned (e.g. shifts) must be careful.
    42  	// Use Value.AuxUnsigned to get the zero-extended value of AuxInt.
    43  	AuxInt int64
    44  	Aux    Aux
    45  
    46  	// Arguments of this value
    47  	Args []*Value
    48  
    49  	// Containing basic block
    50  	Block *Block
    51  
    52  	// Source position
    53  	Pos src.XPos
    54  
    55  	// Use count. Each appearance in Value.Args and Block.Controls counts once.
    56  	Uses int32
    57  
    58  	// wasm: Value stays on the WebAssembly stack. This value will not get a "register" (WebAssembly variable)
    59  	// nor a slot on Go stack, and the generation of this value is delayed to its use time.
    60  	OnWasmStack bool
    61  
    62  	// Is this value in the per-function constant cache? If so, remove from cache before changing it or recycling it.
    63  	InCache bool
    64  
    65  	// Storage for the first three args
    66  	Argstorage [3]*Value
    67  }
    68  
    69  // CanSSA reports whether values of type t can be represented as a Value.
    70  func CanSSA(t *types.Type) bool {
    71  	types.CalcSize(t)
    72  	if t.IsSIMD() {
    73  		return true
    74  	}
    75  	if t.Size() == 0 {
    76  		return true
    77  	}
    78  	sizeLimit := int64(MaxStruct * types.PtrSize)
    79  	if t.Size() > sizeLimit {
    80  		// 4*Widthptr is an arbitrary constant. We want it
    81  		// to be at least 3*Widthptr so slices can be registerized.
    82  		// Too big and we'll introduce too much register pressure.
    83  		if !buildcfg.Experiment.SIMD {
    84  			return false
    85  		}
    86  	}
    87  	switch t.Kind() {
    88  	case types.TARRAY:
    89  		// We can't do larger arrays because dynamic indexing is
    90  		// not supported on SSA variables.
    91  		// TODO: allow if all indexes are constant.
    92  		if t.NumElem() <= 1 {
    93  			return CanSSA(t.Elem())
    94  		}
    95  		return false
    96  	case types.TSTRUCT:
    97  		if types.IsDirectIface(t) {
    98  			// Note: even if t.NumFields()>MaxStruct! See issue 77534.
    99  			return true
   100  		}
   101  		if t.NumFields() > MaxStruct {
   102  			return false
   103  		}
   104  		for _, t1 := range t.Fields() {
   105  			if !CanSSA(t1.Type) {
   106  				return false
   107  			}
   108  		}
   109  		// Special check for SIMD. If the composite type
   110  		// contains SIMD vectors we can return true
   111  		// if it pass the checks below.
   112  		if !buildcfg.Experiment.SIMD {
   113  			return true
   114  		}
   115  		if t.Size() <= sizeLimit {
   116  			return true
   117  		}
   118  		i, f := t.Registers()
   119  		return i+f <= MaxStruct
   120  	default:
   121  		return true
   122  	}
   123  }
   124  
   125  // AutoVar returns a *Name and int64 representing the auto variable and offset within it
   126  // where v should be spilled.
   127  func AutoVar(v *Value) (*ir.Name, int64) {
   128  	if loc, ok := v.Block.Func.RegAlloc[v.ID].(LocalSlot); ok {
   129  		if v.Type.Size() > loc.Type.Size() {
   130  			v.Fatalf("v%d: spill/restore type %v doesn't fit in slot type %v", v.ID, v.Type, loc.Type)
   131  		}
   132  		return loc.N, loc.Off
   133  	}
   134  	// Assume it is a register, return its spill slot, which needs to be live
   135  	nameOff := v.Aux.(*AuxNameOffset)
   136  	return nameOff.Name, nameOff.Offset
   137  }
   138  
   139  // Examples:
   140  // Opcode          aux   args
   141  //  OpAdd          nil      2
   142  //  OpConst     string      0    string constant
   143  //  OpConst      int64      0    int64 constant
   144  //  OpAddcq      int64      1    amd64 op: v = arg[0] + constant
   145  
   146  // short form print. Just v#.
   147  func (v *Value) String() string {
   148  	if v == nil {
   149  		return "nil" // should never happen, but not panicking helps with debugging
   150  	}
   151  	return fmt.Sprintf("v%d", v.ID)
   152  }
   153  
   154  func (v *Value) AuxInt8() int8 {
   155  	if ssaop.OpcodeTable[v.Op].AuxType != ssaop.AuxTypeInt8 && ssaop.OpcodeTable[v.Op].AuxType != ssaop.AuxTypeNameOffsetInt8 {
   156  		v.Fatalf("op %s doesn't have an int8 aux field", v.Op)
   157  	}
   158  	return int8(v.AuxInt)
   159  }
   160  
   161  func (v *Value) AuxUInt8() uint8 {
   162  	if ssaop.OpcodeTable[v.Op].AuxType != ssaop.AuxTypeUInt8 {
   163  		v.Fatalf("op %s doesn't have a uint8 aux field", v.Op)
   164  	}
   165  	return uint8(v.AuxInt)
   166  }
   167  
   168  func (v *Value) AuxInt16() int16 {
   169  	if ssaop.OpcodeTable[v.Op].AuxType != ssaop.AuxTypeInt16 {
   170  		v.Fatalf("op %s doesn't have an int16 aux field", v.Op)
   171  	}
   172  	return int16(v.AuxInt)
   173  }
   174  
   175  func (v *Value) AuxInt32() int32 {
   176  	if ssaop.OpcodeTable[v.Op].AuxType != ssaop.AuxTypeInt32 {
   177  		v.Fatalf("op %s doesn't have an int32 aux field", v.Op)
   178  	}
   179  	return int32(v.AuxInt)
   180  }
   181  
   182  // AuxUnsigned returns v.AuxInt as an unsigned value for OpConst*.
   183  // v.AuxInt is always sign-extended to 64 bits, even if the
   184  // represented value is unsigned. This undoes that sign extension.
   185  func (v *Value) AuxUnsigned() uint64 {
   186  	c := v.AuxInt
   187  	switch v.Op {
   188  	case ssaop.OpConst64:
   189  		return uint64(c)
   190  	case ssaop.OpConst32:
   191  		return uint64(uint32(c))
   192  	case ssaop.OpConst16:
   193  		return uint64(uint16(c))
   194  	case ssaop.OpConst8:
   195  		return uint64(uint8(c))
   196  	}
   197  	v.Fatalf("op %s isn't OpConst*", v.Op)
   198  	return 0
   199  }
   200  
   201  func (v *Value) AuxFloat() float64 {
   202  	if ssaop.OpcodeTable[v.Op].AuxType != ssaop.AuxTypeFloat32 && ssaop.OpcodeTable[v.Op].AuxType != ssaop.AuxTypeFloat64 {
   203  		v.Fatalf("op %s doesn't have a float aux field", v.Op)
   204  	}
   205  	return math.Float64frombits(uint64(v.AuxInt))
   206  }
   207  
   208  func (v *Value) AuxValAndOff() ValAndOff {
   209  	if ssaop.OpcodeTable[v.Op].AuxType != ssaop.AuxTypeSymValAndOff {
   210  		v.Fatalf("op %s doesn't have a ValAndOff aux field", v.Op)
   211  	}
   212  	return ValAndOff(v.AuxInt)
   213  }
   214  
   215  func (v *Value) AuxArm64BitField() Arm64BitField {
   216  	if ssaop.OpcodeTable[v.Op].AuxType != ssaop.AuxTypeARM64BitField {
   217  		v.Fatalf("op %s doesn't have a ARM64BitField aux field", v.Op)
   218  	}
   219  	return Arm64BitField(v.AuxInt)
   220  }
   221  
   222  func (v *Value) AuxArm64ConditionalParams() Arm64ConditionalParams {
   223  	if ssaop.OpcodeTable[v.Op].AuxType != ssaop.AuxTypeARM64ConditionalParams {
   224  		v.Fatalf("op %s doesn't have a ARM64ConditionalParams aux field", v.Op)
   225  	}
   226  	return AuxIntToArm64ConditionalParams(v.AuxInt)
   227  }
   228  
   229  func (v *Value) AuxSizeAndAlign() (int64, int64) {
   230  	return v.AuxInt, int64(v.Aux.(Int64Aux))
   231  }
   232  
   233  // long form print.  v# = opcode <type> [aux] args [: reg] (names)
   234  func (v *Value) LongString() string {
   235  	if v == nil {
   236  		return "<NIL VALUE>"
   237  	}
   238  	s := fmt.Sprintf("v%d = %s", v.ID, v.Op)
   239  	s += " <" + v.Type.String() + ">"
   240  	s += v.AuxString()
   241  	for _, a := range v.Args {
   242  		s += fmt.Sprintf(" %v", a)
   243  	}
   244  	if v.Block == nil {
   245  		return s
   246  	}
   247  	r := v.Block.Func.RegAlloc
   248  	if int(v.ID) < len(r) && r[v.ID] != nil {
   249  		s += " : " + r[v.ID].String()
   250  	}
   251  	if reg := v.Block.Func.TempRegs[v.ID]; reg != nil {
   252  		s += " tmp=" + reg.String()
   253  	}
   254  	var names []string
   255  	for name, values := range v.Block.Func.NamedValues {
   256  		for _, value := range values {
   257  			if value == v {
   258  				names = append(names, name.String())
   259  				break // drop duplicates.
   260  			}
   261  		}
   262  	}
   263  	if len(names) != 0 {
   264  		sort.Strings(names) // Otherwise a source of variation in debugging output.
   265  		s += " (" + strings.Join(names, ", ") + ")"
   266  	}
   267  	return s
   268  }
   269  
   270  func (v *Value) AuxString() string {
   271  	switch ssaop.OpcodeTable[v.Op].AuxType {
   272  	case ssaop.AuxTypeBool:
   273  		if v.AuxInt == 0 {
   274  			return " [false]"
   275  		} else {
   276  			return " [true]"
   277  		}
   278  	case ssaop.AuxTypeInt8:
   279  		return fmt.Sprintf(" [%d]", v.AuxInt8())
   280  	case ssaop.AuxTypeInt16:
   281  		return fmt.Sprintf(" [%d]", v.AuxInt16())
   282  	case ssaop.AuxTypeInt32:
   283  		return fmt.Sprintf(" [%d]", v.AuxInt32())
   284  	case ssaop.AuxTypeInt64, ssaop.AuxTypeInt128:
   285  		return fmt.Sprintf(" [%d]", v.AuxInt)
   286  	case ssaop.AuxTypeUInt8:
   287  		return fmt.Sprintf(" [%d]", v.AuxUInt8())
   288  	case ssaop.AuxTypeARM64BitField:
   289  		lsb := v.AuxArm64BitField().Lsb()
   290  		width := v.AuxArm64BitField().Width()
   291  		return fmt.Sprintf(" [lsb=%d,width=%d]", lsb, width)
   292  	case ssaop.AuxTypeARM64ConditionalParams:
   293  		params := v.AuxArm64ConditionalParams()
   294  		cond := params.Cond
   295  		nzcv := params.Nzcv()
   296  		imm, ok := params.ConstValue()
   297  		if ok {
   298  			return fmt.Sprintf(" [cond=%s,nzcv=%d,imm=%d]", cond, nzcv, imm)
   299  		}
   300  		return fmt.Sprintf(" [cond=%s,nzcv=%d]", cond, nzcv)
   301  	case ssaop.AuxTypeFloat32, ssaop.AuxTypeFloat64:
   302  		return fmt.Sprintf(" [%g]", v.AuxFloat())
   303  	case ssaop.AuxTypeString:
   304  		return fmt.Sprintf(" {%q}", v.Aux)
   305  	case ssaop.AuxTypeSym, ssaop.AuxTypeCall, ssaop.AuxTypeTyp:
   306  		if v.Aux != nil {
   307  			return fmt.Sprintf(" {%v}", v.Aux)
   308  		}
   309  		return ""
   310  	case ssaop.AuxTypeSymOff, ssaop.AuxTypeCallOff, ssaop.AuxTypeTypSize, ssaop.AuxTypeNameOffsetInt8:
   311  		s := ""
   312  		if v.Aux != nil {
   313  			s = fmt.Sprintf(" {%v}", v.Aux)
   314  		}
   315  		if v.AuxInt != 0 || ssaop.OpcodeTable[v.Op].AuxType == ssaop.AuxTypeNameOffsetInt8 {
   316  			s += fmt.Sprintf(" [%v]", v.AuxInt)
   317  		}
   318  		return s
   319  	case ssaop.AuxTypeSymValAndOff:
   320  		s := ""
   321  		if v.Aux != nil {
   322  			s = fmt.Sprintf(" {%v}", v.Aux)
   323  		}
   324  		return s + fmt.Sprintf(" [%s]", v.AuxValAndOff())
   325  	case ssaop.AuxTypeCCop:
   326  		return fmt.Sprintf(" [%s]", ssaop.Op(v.AuxInt))
   327  	case ssaop.AuxTypeS390XCCMask, ssaop.AuxTypeS390XRotateParams:
   328  		return fmt.Sprintf(" {%v}", v.Aux)
   329  	case ssaop.AuxTypeFlagConstant:
   330  		return fmt.Sprintf("[%s]", FlagConstant(v.AuxInt))
   331  	case ssaop.AuxTypeSizeAndAlign:
   332  		return fmt.Sprintf(" [size=%d] {align=%d}", v.AuxInt, v.Aux)
   333  	case ssaop.AuxTypeNone:
   334  		return ""
   335  	default:
   336  		// If you see this, add a case above instead.
   337  		return fmt.Sprintf("[auxtype=%d AuxInt=%d Aux=%v]", ssaop.OpcodeTable[v.Op].AuxType, v.AuxInt, v.Aux)
   338  	}
   339  }
   340  
   341  // If/when midstack inlining is enabled (-l=4), the compiler gets both larger and slower.
   342  // Not-inlining this method is a help (*Value.reset and *Block.NewValue0 are similar).
   343  //
   344  //go:noinline
   345  func (v *Value) AddArg(w *Value) {
   346  	if v.Args == nil {
   347  		v.ResetArgs() // use argstorage
   348  	}
   349  	v.Args = append(v.Args, w)
   350  	w.Uses++
   351  }
   352  
   353  //go:noinline
   354  func (v *Value) AddArg2(w1, w2 *Value) {
   355  	if v.Args == nil {
   356  		v.ResetArgs() // use argstorage
   357  	}
   358  	v.Args = append(v.Args, w1, w2)
   359  	w1.Uses++
   360  	w2.Uses++
   361  }
   362  
   363  //go:noinline
   364  func (v *Value) AddArg3(w1, w2, w3 *Value) {
   365  	if v.Args == nil {
   366  		v.ResetArgs() // use argstorage
   367  	}
   368  	v.Args = append(v.Args, w1, w2, w3)
   369  	w1.Uses++
   370  	w2.Uses++
   371  	w3.Uses++
   372  }
   373  
   374  //go:noinline
   375  func (v *Value) AddArg4(w1, w2, w3, w4 *Value) {
   376  	v.Args = append(v.Args, w1, w2, w3, w4)
   377  	w1.Uses++
   378  	w2.Uses++
   379  	w3.Uses++
   380  	w4.Uses++
   381  }
   382  
   383  //go:noinline
   384  func (v *Value) AddArg5(w1, w2, w3, w4, w5 *Value) {
   385  	v.Args = append(v.Args, w1, w2, w3, w4, w5)
   386  	w1.Uses++
   387  	w2.Uses++
   388  	w3.Uses++
   389  	w4.Uses++
   390  	w5.Uses++
   391  }
   392  
   393  //go:noinline
   394  func (v *Value) AddArg6(w1, w2, w3, w4, w5, w6 *Value) {
   395  	v.Args = append(v.Args, w1, w2, w3, w4, w5, w6)
   396  	w1.Uses++
   397  	w2.Uses++
   398  	w3.Uses++
   399  	w4.Uses++
   400  	w5.Uses++
   401  	w6.Uses++
   402  }
   403  
   404  func (v *Value) AddArgs(a ...*Value) {
   405  	if v.Args == nil {
   406  		v.ResetArgs() // use argstorage
   407  	}
   408  	v.Args = append(v.Args, a...)
   409  	for _, x := range a {
   410  		x.Uses++
   411  	}
   412  }
   413  
   414  func (v *Value) SetArg(i int, w *Value) {
   415  	v.Args[i].Uses--
   416  	v.Args[i] = w
   417  	w.Uses++
   418  }
   419  
   420  func (v *Value) SetArgs1(a *Value) {
   421  	v.ResetArgs()
   422  	v.AddArg(a)
   423  }
   424  
   425  func (v *Value) SetArgs2(a, b *Value) {
   426  	v.ResetArgs()
   427  	v.AddArg(a)
   428  	v.AddArg(b)
   429  }
   430  
   431  func (v *Value) SetArgs3(a, b, c *Value) {
   432  	v.ResetArgs()
   433  	v.AddArg(a)
   434  	v.AddArg(b)
   435  	v.AddArg(c)
   436  }
   437  
   438  func (v *Value) SetArgs4(a, b, c, d *Value) {
   439  	v.ResetArgs()
   440  	v.AddArg(a)
   441  	v.AddArg(b)
   442  	v.AddArg(c)
   443  	v.AddArg(d)
   444  }
   445  
   446  func (v *Value) ResetArgs() {
   447  	for _, a := range v.Args {
   448  		a.Uses--
   449  	}
   450  	v.Argstorage[0] = nil
   451  	v.Argstorage[1] = nil
   452  	v.Argstorage[2] = nil
   453  	v.Args = v.Argstorage[:0]
   454  }
   455  
   456  // Reset is called from most rewrite rules.
   457  // Allowing it to be inlined increases the size
   458  // of cmd/compile by almost 10%, and slows it down.
   459  //
   460  //go:noinline
   461  func (v *Value) Reset(op ssaop.Op) {
   462  	if v.InCache {
   463  		v.Block.Func.UnCache(v)
   464  	}
   465  	v.Op = op
   466  	v.ResetArgs()
   467  	v.AuxInt = 0
   468  	v.Aux = nil
   469  }
   470  
   471  // InvalidateRecursively marks a value as invalid (unused)
   472  // and after decrementing reference counts on its Args,
   473  // also recursively invalidates any of those whose use
   474  // count goes to zero.  It returns whether any of the
   475  // invalidated values was marked with IsStmt.
   476  //
   477  // BEWARE of doing this *before* you've applied intended
   478  // updates to SSA.
   479  func (v *Value) InvalidateRecursively() bool {
   480  	lostStmt := v.Pos.IsStmt() == src.PosIsStmt
   481  	if v.InCache {
   482  		v.Block.Func.UnCache(v)
   483  	}
   484  	v.Op = ssaop.OpInvalid
   485  
   486  	for _, a := range v.Args {
   487  		a.Uses--
   488  		if a.Uses == 0 {
   489  			lost := a.InvalidateRecursively()
   490  			lostStmt = lost || lostStmt
   491  		}
   492  	}
   493  
   494  	v.Argstorage[0] = nil
   495  	v.Argstorage[1] = nil
   496  	v.Argstorage[2] = nil
   497  	v.Args = v.Argstorage[:0]
   498  
   499  	v.AuxInt = 0
   500  	v.Aux = nil
   501  	return lostStmt
   502  }
   503  
   504  // CopyOf is called from rewrite rules.
   505  // It modifies v to be (Copy a).
   506  //
   507  //go:noinline
   508  func (v *Value) CopyOf(a *Value) {
   509  	if v == a {
   510  		return
   511  	}
   512  	if v.InCache {
   513  		v.Block.Func.UnCache(v)
   514  	}
   515  	v.Op = ssaop.OpCopy
   516  	v.ResetArgs()
   517  	v.AddArg(a)
   518  	v.AuxInt = 0
   519  	v.Aux = nil
   520  	v.Type = a.Type
   521  }
   522  
   523  // CopyInto makes a new value identical to v and adds it to the end of b.
   524  // unlike copyIntoWithXPos this does not check for v.Pos being a statement.
   525  func (v *Value) CopyInto(b *Block) *Value {
   526  	c := b.NewValue0(v.Pos.WithNotStmt(), v.Op, v.Type) // Lose the position, this causes line number churn otherwise.
   527  	c.Aux = v.Aux
   528  	c.AuxInt = v.AuxInt
   529  	c.AddArgs(v.Args...)
   530  	for _, a := range v.Args {
   531  		if a.Type.IsMemory() {
   532  			v.Fatalf("can't move a value with a memory arg %s", v.LongString())
   533  		}
   534  	}
   535  	return c
   536  }
   537  
   538  // CopyIntoWithXPos makes a new value identical to v and adds it to the end of b.
   539  // The supplied position is used as the position of the new value.
   540  // Because this is used for rematerialization, check for case that (rematerialized)
   541  // input to value with position 'pos' carried a statement mark, and that the supplied
   542  // position (of the instruction using the rematerialized value) is not marked, and
   543  // preserve that mark if its line matches the supplied position.
   544  func (v *Value) CopyIntoWithXPos(b *Block, pos src.XPos) *Value {
   545  	if v.Pos.IsStmt() == src.PosIsStmt && pos.IsStmt() != src.PosIsStmt && v.Pos.SameFileAndLine(pos) {
   546  		pos = pos.WithIsStmt()
   547  	}
   548  	c := b.NewValue0(pos, v.Op, v.Type)
   549  	c.Aux = v.Aux
   550  	c.AuxInt = v.AuxInt
   551  	c.AddArgs(v.Args...)
   552  	for _, a := range v.Args {
   553  		if a.Type.IsMemory() {
   554  			v.Fatalf("can't move a value with a memory arg %s", v.LongString())
   555  		}
   556  	}
   557  	return c
   558  }
   559  
   560  func (v *Value) Logf(msg string, args ...any) { v.Block.Logf(msg, args...) }
   561  
   562  func (v *Value) Log() bool { return v.Block.Log() }
   563  
   564  func (v *Value) Fatalf(msg string, args ...any) {
   565  	v.Block.Func.FatalfWithPos(v.Pos, msg, args...)
   566  }
   567  
   568  // IsGenericIntConst reports whether v is a generic integer constant.
   569  func (v *Value) IsGenericIntConst() bool {
   570  	return v != nil && (v.Op == ssaop.OpConst64 || v.Op == ssaop.OpConst32 || v.Op == ssaop.OpConst16 || v.Op == ssaop.OpConst8)
   571  }
   572  
   573  // ResultReg returns the result register assigned to v, in cmd/internal/obj/$ARCH numbering.
   574  // It is similar to Reg and Reg0, except that it is usable interchangeably for all Value Ops.
   575  // If you know v.Op, using Reg or Reg0 (as appropriate) will be more efficient.
   576  func (v *Value) ResultReg() int16 {
   577  	reg := v.Block.Func.RegAlloc[v.ID]
   578  	if reg == nil {
   579  		v.Fatalf("nil reg for value: %s\n%s\n", v.LongString(), v.Block.Func)
   580  	}
   581  	if pair, ok := reg.(LocPair); ok {
   582  		reg = pair[0]
   583  	}
   584  	if reg == nil {
   585  		v.Fatalf("nil reg0 for value: %s\n%s\n", v.LongString(), v.Block.Func)
   586  	}
   587  	return reg.(*ssabase.Register).ObjNum
   588  }
   589  
   590  // Reg returns the register assigned to v, in cmd/internal/obj/$ARCH numbering.
   591  func (v *Value) Reg() int16 {
   592  	reg := v.Block.Func.RegAlloc[v.ID]
   593  	if reg == nil {
   594  		v.Fatalf("nil register for value: %s\n%s\n", v.LongString(), v.Block.Func)
   595  	}
   596  	return reg.(*ssabase.Register).ObjNum
   597  }
   598  
   599  // Reg0 returns the register assigned to the first output of v, in cmd/internal/obj/$ARCH numbering.
   600  func (v *Value) Reg0() int16 {
   601  	reg := v.Block.Func.RegAlloc[v.ID].(LocPair)[0]
   602  	if reg == nil {
   603  		v.Fatalf("nil first register for value: %s\n%s\n", v.LongString(), v.Block.Func)
   604  	}
   605  	return reg.(*ssabase.Register).ObjNum
   606  }
   607  
   608  // Reg1 returns the register assigned to the second output of v, in cmd/internal/obj/$ARCH numbering.
   609  func (v *Value) Reg1() int16 {
   610  	reg := v.Block.Func.RegAlloc[v.ID].(LocPair)[1]
   611  	if reg == nil {
   612  		v.Fatalf("nil second register for value: %s\n%s\n", v.LongString(), v.Block.Func)
   613  	}
   614  	return reg.(*ssabase.Register).ObjNum
   615  }
   616  
   617  // RegTmp returns the temporary register assigned to v, in cmd/internal/obj/$ARCH numbering.
   618  func (v *Value) RegTmp() int16 {
   619  	reg := v.Block.Func.TempRegs[v.ID]
   620  	if reg == nil {
   621  		v.Fatalf("nil tmp register for value: %s\n%s\n", v.LongString(), v.Block.Func)
   622  	}
   623  	return reg.ObjNum
   624  }
   625  
   626  func (v *Value) RegName() string {
   627  	reg := v.Block.Func.RegAlloc[v.ID]
   628  	if reg == nil {
   629  		v.Fatalf("nil register for value: %s\n%s\n", v.LongString(), v.Block.Func)
   630  	}
   631  	return reg.(*ssabase.Register).Name
   632  }
   633  
   634  // MemoryArg returns the memory argument for the Value.
   635  // The returned value, if non-nil, will be memory-typed (or a tuple with a memory-typed second part).
   636  // Otherwise, nil is returned.
   637  func (v *Value) MemoryArg() *Value {
   638  	if v.Op == ssaop.OpPhi {
   639  		if v.Type.IsMemory() {
   640  			v.Fatalf("MemoryArg on Phi<mem> is ambiguous")
   641  		}
   642  
   643  		// The logic below would also return nil for non-memory Phis,
   644  		// since their arguments have the same non-memory type.
   645  		// But return explicitly to make this behavior clear.
   646  		return nil
   647  	}
   648  
   649  	na := len(v.Args)
   650  	if na == 0 {
   651  		return nil
   652  	}
   653  	if m := v.Args[na-1]; m.Type.IsMemory() {
   654  		return m
   655  	}
   656  	return nil
   657  }
   658  
   659  // LackingPos indicates whether v is a value that is unlikely to have a correct
   660  // position assigned to it.  Ignoring such values leads to more user-friendly positions
   661  // assigned to nearby values and the blocks containing them.
   662  func (v *Value) LackingPos() bool {
   663  	// The exact definition of LackingPos is somewhat heuristically defined and may change
   664  	// in the future, for example if some of these operations are generated more carefully
   665  	// with respect to their source position.
   666  	return v.Op == ssaop.OpVarDef || v.Op == ssaop.OpVarLive || v.Op == ssaop.OpPhi ||
   667  		(v.Op == ssaop.OpFwdRef || v.Op == ssaop.OpCopy) && v.Type == types.TypeMem
   668  }
   669  
   670  // Removeable reports whether the value v can be removed from the SSA graph entirely
   671  // if its use count drops to 0.
   672  func (v *Value) Removeable() bool {
   673  	if v.Type.IsVoid() {
   674  		// Void ops (inline marks), must stay.
   675  		return false
   676  	}
   677  	if ssaop.OpcodeTable[v.Op].NilCheck {
   678  		// Nil pointer checks must stay.
   679  		return false
   680  	}
   681  	if v.Type.IsMemory() {
   682  		// We don't need to preserve all memory ops, but we do need
   683  		// to keep calls at least (because they might have
   684  		// synchronization operations we can't see).
   685  		return false
   686  	}
   687  	if v.Op.HasSideEffects() {
   688  		// These are mostly synchronization operations.
   689  		return false
   690  	}
   691  	return true
   692  }
   693  
   694  // AddrSinkArg reports whether the idx'th argument is known
   695  // to not propagate to the output value.
   696  func (v *Value) AddrSinkArg(idx int) bool {
   697  	if idx == 0 {
   698  		return ssaop.OpcodeTable[v.Op].AddrSinkArg0
   699  	}
   700  	if idx == 1 {
   701  		return ssaop.OpcodeTable[v.Op].AddrSinkArg1
   702  	}
   703  	return false
   704  }
   705  

View as plain text