Black Lives Matter. Support the Equal Justice Initiative.

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

Documentation: cmd/compile/internal/ssa

     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.Controls 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  	// Is this value in the per-function constant cache? If so, remove from cache before changing it or recycling it.
    58  	InCache bool
    59  
    60  	// Storage for the first three args
    61  	argstorage [3]*Value
    62  }
    63  
    64  // Examples:
    65  // Opcode          aux   args
    66  //  OpAdd          nil      2
    67  //  OpConst     string      0    string constant
    68  //  OpConst      int64      0    int64 constant
    69  //  OpAddcq      int64      1    amd64 op: v = arg[0] + constant
    70  
    71  // short form print. Just v#.
    72  func (v *Value) String() string {
    73  	if v == nil {
    74  		return "nil" // should never happen, but not panicking helps with debugging
    75  	}
    76  	return fmt.Sprintf("v%d", v.ID)
    77  }
    78  
    79  func (v *Value) AuxInt8() int8 {
    80  	if opcodeTable[v.Op].auxType != auxInt8 {
    81  		v.Fatalf("op %s doesn't have an int8 aux field", v.Op)
    82  	}
    83  	return int8(v.AuxInt)
    84  }
    85  
    86  func (v *Value) AuxInt16() int16 {
    87  	if opcodeTable[v.Op].auxType != auxInt16 {
    88  		v.Fatalf("op %s doesn't have an int16 aux field", v.Op)
    89  	}
    90  	return int16(v.AuxInt)
    91  }
    92  
    93  func (v *Value) AuxInt32() int32 {
    94  	if opcodeTable[v.Op].auxType != auxInt32 {
    95  		v.Fatalf("op %s doesn't have an int32 aux field", v.Op)
    96  	}
    97  	return int32(v.AuxInt)
    98  }
    99  
   100  // AuxUnsigned returns v.AuxInt as an unsigned value for OpConst*.
   101  // v.AuxInt is always sign-extended to 64 bits, even if the
   102  // represented value is unsigned. This undoes that sign extension.
   103  func (v *Value) AuxUnsigned() uint64 {
   104  	c := v.AuxInt
   105  	switch v.Op {
   106  	case OpConst64:
   107  		return uint64(c)
   108  	case OpConst32:
   109  		return uint64(uint32(c))
   110  	case OpConst16:
   111  		return uint64(uint16(c))
   112  	case OpConst8:
   113  		return uint64(uint8(c))
   114  	}
   115  	v.Fatalf("op %s isn't OpConst*", v.Op)
   116  	return 0
   117  }
   118  
   119  func (v *Value) AuxFloat() float64 {
   120  	if opcodeTable[v.Op].auxType != auxFloat32 && opcodeTable[v.Op].auxType != auxFloat64 {
   121  		v.Fatalf("op %s doesn't have a float aux field", v.Op)
   122  	}
   123  	return math.Float64frombits(uint64(v.AuxInt))
   124  }
   125  func (v *Value) AuxValAndOff() ValAndOff {
   126  	if opcodeTable[v.Op].auxType != auxSymValAndOff {
   127  		v.Fatalf("op %s doesn't have a ValAndOff aux field", v.Op)
   128  	}
   129  	return ValAndOff(v.AuxInt)
   130  }
   131  
   132  func (v *Value) AuxArm64BitField() arm64BitField {
   133  	if opcodeTable[v.Op].auxType != auxARM64BitField {
   134  		v.Fatalf("op %s doesn't have a ValAndOff aux field", v.Op)
   135  	}
   136  	return arm64BitField(v.AuxInt)
   137  }
   138  
   139  // long form print.  v# = opcode <type> [aux] args [: reg] (names)
   140  func (v *Value) LongString() string {
   141  	s := fmt.Sprintf("v%d = %s", v.ID, v.Op)
   142  	s += " <" + v.Type.String() + ">"
   143  	s += v.auxString()
   144  	for _, a := range v.Args {
   145  		s += fmt.Sprintf(" %v", a)
   146  	}
   147  	var r []Location
   148  	if v.Block != nil {
   149  		r = v.Block.Func.RegAlloc
   150  	}
   151  	if int(v.ID) < len(r) && r[v.ID] != nil {
   152  		s += " : " + r[v.ID].String()
   153  	}
   154  	var names []string
   155  	if v.Block != nil {
   156  		for name, values := range v.Block.Func.NamedValues {
   157  			for _, value := range values {
   158  				if value == v {
   159  					names = append(names, name.String())
   160  					break // drop duplicates.
   161  				}
   162  			}
   163  		}
   164  	}
   165  	if len(names) != 0 {
   166  		sort.Strings(names) // Otherwise a source of variation in debugging output.
   167  		s += " (" + strings.Join(names, ", ") + ")"
   168  	}
   169  	return s
   170  }
   171  
   172  func (v *Value) auxString() string {
   173  	switch opcodeTable[v.Op].auxType {
   174  	case auxBool:
   175  		if v.AuxInt == 0 {
   176  			return " [false]"
   177  		} else {
   178  			return " [true]"
   179  		}
   180  	case auxInt8:
   181  		return fmt.Sprintf(" [%d]", v.AuxInt8())
   182  	case auxInt16:
   183  		return fmt.Sprintf(" [%d]", v.AuxInt16())
   184  	case auxInt32:
   185  		return fmt.Sprintf(" [%d]", v.AuxInt32())
   186  	case auxInt64, auxInt128:
   187  		return fmt.Sprintf(" [%d]", v.AuxInt)
   188  	case auxARM64BitField:
   189  		lsb := v.AuxArm64BitField().getARM64BFlsb()
   190  		width := v.AuxArm64BitField().getARM64BFwidth()
   191  		return fmt.Sprintf(" [lsb=%d,width=%d]", lsb, width)
   192  	case auxFloat32, auxFloat64:
   193  		return fmt.Sprintf(" [%g]", v.AuxFloat())
   194  	case auxString:
   195  		return fmt.Sprintf(" {%q}", v.Aux)
   196  	case auxSym, auxCall, auxTyp:
   197  		if v.Aux != nil {
   198  			return fmt.Sprintf(" {%v}", v.Aux)
   199  		}
   200  	case auxSymOff, auxCallOff, auxTypSize:
   201  		s := ""
   202  		if v.Aux != nil {
   203  			s = fmt.Sprintf(" {%v}", v.Aux)
   204  		}
   205  		if v.AuxInt != 0 {
   206  			s += fmt.Sprintf(" [%v]", v.AuxInt)
   207  		}
   208  		return s
   209  	case auxSymValAndOff:
   210  		s := ""
   211  		if v.Aux != nil {
   212  			s = fmt.Sprintf(" {%v}", v.Aux)
   213  		}
   214  		return s + fmt.Sprintf(" [%s]", v.AuxValAndOff())
   215  	case auxCCop:
   216  		return fmt.Sprintf(" {%s}", Op(v.AuxInt))
   217  	case auxS390XCCMask, auxS390XRotateParams:
   218  		return fmt.Sprintf(" {%v}", v.Aux)
   219  	case auxFlagConstant:
   220  		return fmt.Sprintf("[%s]", flagConstant(v.AuxInt))
   221  	}
   222  	return ""
   223  }
   224  
   225  // If/when midstack inlining is enabled (-l=4), the compiler gets both larger and slower.
   226  // Not-inlining this method is a help (*Value.reset and *Block.NewValue0 are similar).
   227  //go:noinline
   228  func (v *Value) AddArg(w *Value) {
   229  	if v.Args == nil {
   230  		v.resetArgs() // use argstorage
   231  	}
   232  	v.Args = append(v.Args, w)
   233  	w.Uses++
   234  }
   235  
   236  //go:noinline
   237  func (v *Value) AddArg2(w1, w2 *Value) {
   238  	if v.Args == nil {
   239  		v.resetArgs() // use argstorage
   240  	}
   241  	v.Args = append(v.Args, w1, w2)
   242  	w1.Uses++
   243  	w2.Uses++
   244  }
   245  
   246  //go:noinline
   247  func (v *Value) AddArg3(w1, w2, w3 *Value) {
   248  	if v.Args == nil {
   249  		v.resetArgs() // use argstorage
   250  	}
   251  	v.Args = append(v.Args, w1, w2, w3)
   252  	w1.Uses++
   253  	w2.Uses++
   254  	w3.Uses++
   255  }
   256  
   257  //go:noinline
   258  func (v *Value) AddArg4(w1, w2, w3, w4 *Value) {
   259  	v.Args = append(v.Args, w1, w2, w3, w4)
   260  	w1.Uses++
   261  	w2.Uses++
   262  	w3.Uses++
   263  	w4.Uses++
   264  }
   265  
   266  //go:noinline
   267  func (v *Value) AddArg5(w1, w2, w3, w4, w5 *Value) {
   268  	v.Args = append(v.Args, w1, w2, w3, w4, w5)
   269  	w1.Uses++
   270  	w2.Uses++
   271  	w3.Uses++
   272  	w4.Uses++
   273  	w5.Uses++
   274  }
   275  
   276  //go:noinline
   277  func (v *Value) AddArg6(w1, w2, w3, w4, w5, w6 *Value) {
   278  	v.Args = append(v.Args, w1, w2, w3, w4, w5, w6)
   279  	w1.Uses++
   280  	w2.Uses++
   281  	w3.Uses++
   282  	w4.Uses++
   283  	w5.Uses++
   284  	w6.Uses++
   285  }
   286  
   287  func (v *Value) AddArgs(a ...*Value) {
   288  	if v.Args == nil {
   289  		v.resetArgs() // use argstorage
   290  	}
   291  	v.Args = append(v.Args, a...)
   292  	for _, x := range a {
   293  		x.Uses++
   294  	}
   295  }
   296  func (v *Value) SetArg(i int, w *Value) {
   297  	v.Args[i].Uses--
   298  	v.Args[i] = w
   299  	w.Uses++
   300  }
   301  func (v *Value) RemoveArg(i int) {
   302  	v.Args[i].Uses--
   303  	copy(v.Args[i:], v.Args[i+1:])
   304  	v.Args[len(v.Args)-1] = nil // aid GC
   305  	v.Args = v.Args[:len(v.Args)-1]
   306  }
   307  func (v *Value) SetArgs1(a *Value) {
   308  	v.resetArgs()
   309  	v.AddArg(a)
   310  }
   311  func (v *Value) SetArgs2(a, b *Value) {
   312  	v.resetArgs()
   313  	v.AddArg(a)
   314  	v.AddArg(b)
   315  }
   316  func (v *Value) SetArgs3(a, b, c *Value) {
   317  	v.resetArgs()
   318  	v.AddArg(a)
   319  	v.AddArg(b)
   320  	v.AddArg(c)
   321  }
   322  
   323  func (v *Value) resetArgs() {
   324  	for _, a := range v.Args {
   325  		a.Uses--
   326  	}
   327  	v.argstorage[0] = nil
   328  	v.argstorage[1] = nil
   329  	v.argstorage[2] = nil
   330  	v.Args = v.argstorage[:0]
   331  }
   332  
   333  // reset is called from most rewrite rules.
   334  // Allowing it to be inlined increases the size
   335  // of cmd/compile by almost 10%, and slows it down.
   336  //go:noinline
   337  func (v *Value) reset(op Op) {
   338  	if v.InCache {
   339  		v.Block.Func.unCache(v)
   340  	}
   341  	v.Op = op
   342  	v.resetArgs()
   343  	v.AuxInt = 0
   344  	v.Aux = nil
   345  }
   346  
   347  // copyOf is called from rewrite rules.
   348  // It modifies v to be (Copy a).
   349  //go:noinline
   350  func (v *Value) copyOf(a *Value) {
   351  	if v == a {
   352  		return
   353  	}
   354  	if v.InCache {
   355  		v.Block.Func.unCache(v)
   356  	}
   357  	v.Op = OpCopy
   358  	v.resetArgs()
   359  	v.AddArg(a)
   360  	v.AuxInt = 0
   361  	v.Aux = nil
   362  	v.Type = a.Type
   363  }
   364  
   365  // copyInto makes a new value identical to v and adds it to the end of b.
   366  // unlike copyIntoWithXPos this does not check for v.Pos being a statement.
   367  func (v *Value) copyInto(b *Block) *Value {
   368  	c := b.NewValue0(v.Pos.WithNotStmt(), v.Op, v.Type) // Lose the position, this causes line number churn otherwise.
   369  	c.Aux = v.Aux
   370  	c.AuxInt = v.AuxInt
   371  	c.AddArgs(v.Args...)
   372  	for _, a := range v.Args {
   373  		if a.Type.IsMemory() {
   374  			v.Fatalf("can't move a value with a memory arg %s", v.LongString())
   375  		}
   376  	}
   377  	return c
   378  }
   379  
   380  // copyIntoWithXPos makes a new value identical to v and adds it to the end of b.
   381  // The supplied position is used as the position of the new value.
   382  // Because this is used for rematerialization, check for case that (rematerialized)
   383  // input to value with position 'pos' carried a statement mark, and that the supplied
   384  // position (of the instruction using the rematerialized value) is not marked, and
   385  // preserve that mark if its line matches the supplied position.
   386  func (v *Value) copyIntoWithXPos(b *Block, pos src.XPos) *Value {
   387  	if v.Pos.IsStmt() == src.PosIsStmt && pos.IsStmt() != src.PosIsStmt && v.Pos.SameFileAndLine(pos) {
   388  		pos = pos.WithIsStmt()
   389  	}
   390  	c := b.NewValue0(pos, v.Op, v.Type)
   391  	c.Aux = v.Aux
   392  	c.AuxInt = v.AuxInt
   393  	c.AddArgs(v.Args...)
   394  	for _, a := range v.Args {
   395  		if a.Type.IsMemory() {
   396  			v.Fatalf("can't move a value with a memory arg %s", v.LongString())
   397  		}
   398  	}
   399  	return c
   400  }
   401  
   402  func (v *Value) Logf(msg string, args ...interface{}) { v.Block.Logf(msg, args...) }
   403  func (v *Value) Log() bool                            { return v.Block.Log() }
   404  func (v *Value) Fatalf(msg string, args ...interface{}) {
   405  	v.Block.Func.fe.Fatalf(v.Pos, msg, args...)
   406  }
   407  
   408  // isGenericIntConst reports whether v is a generic integer constant.
   409  func (v *Value) isGenericIntConst() bool {
   410  	return v != nil && (v.Op == OpConst64 || v.Op == OpConst32 || v.Op == OpConst16 || v.Op == OpConst8)
   411  }
   412  
   413  // Reg returns the register assigned to v, in cmd/internal/obj/$ARCH numbering.
   414  func (v *Value) Reg() int16 {
   415  	reg := v.Block.Func.RegAlloc[v.ID]
   416  	if reg == nil {
   417  		v.Fatalf("nil register for value: %s\n%s\n", v.LongString(), v.Block.Func)
   418  	}
   419  	return reg.(*Register).objNum
   420  }
   421  
   422  // Reg0 returns the register assigned to the first output of v, in cmd/internal/obj/$ARCH numbering.
   423  func (v *Value) Reg0() int16 {
   424  	reg := v.Block.Func.RegAlloc[v.ID].(LocPair)[0]
   425  	if reg == nil {
   426  		v.Fatalf("nil first register for value: %s\n%s\n", v.LongString(), v.Block.Func)
   427  	}
   428  	return reg.(*Register).objNum
   429  }
   430  
   431  // Reg1 returns the register assigned to the second output of v, in cmd/internal/obj/$ARCH numbering.
   432  func (v *Value) Reg1() int16 {
   433  	reg := v.Block.Func.RegAlloc[v.ID].(LocPair)[1]
   434  	if reg == nil {
   435  		v.Fatalf("nil second register for value: %s\n%s\n", v.LongString(), v.Block.Func)
   436  	}
   437  	return reg.(*Register).objNum
   438  }
   439  
   440  func (v *Value) RegName() string {
   441  	reg := v.Block.Func.RegAlloc[v.ID]
   442  	if reg == nil {
   443  		v.Fatalf("nil register for value: %s\n%s\n", v.LongString(), v.Block.Func)
   444  	}
   445  	return reg.(*Register).name
   446  }
   447  
   448  // MemoryArg returns the memory argument for the Value.
   449  // The returned value, if non-nil, will be memory-typed (or a tuple with a memory-typed second part).
   450  // Otherwise, nil is returned.
   451  func (v *Value) MemoryArg() *Value {
   452  	if v.Op == OpPhi {
   453  		v.Fatalf("MemoryArg on Phi")
   454  	}
   455  	na := len(v.Args)
   456  	if na == 0 {
   457  		return nil
   458  	}
   459  	if m := v.Args[na-1]; m.Type.IsMemory() {
   460  		return m
   461  	}
   462  	return nil
   463  }
   464  
   465  // LackingPos indicates whether v is a value that is unlikely to have a correct
   466  // position assigned to it.  Ignoring such values leads to more user-friendly positions
   467  // assigned to nearby values and the blocks containing them.
   468  func (v *Value) LackingPos() bool {
   469  	// The exact definition of LackingPos is somewhat heuristically defined and may change
   470  	// in the future, for example if some of these operations are generated more carefully
   471  	// with respect to their source position.
   472  	return v.Op == OpVarDef || v.Op == OpVarKill || v.Op == OpVarLive || v.Op == OpPhi ||
   473  		(v.Op == OpFwdRef || v.Op == OpCopy) && v.Type == types.TypeMem
   474  }
   475  
   476  // removeable reports whether the value v can be removed from the SSA graph entirely
   477  // if its use count drops to 0.
   478  func (v *Value) removeable() bool {
   479  	if v.Type.IsVoid() {
   480  		// Void ops, like nil pointer checks, must stay.
   481  		return false
   482  	}
   483  	if v.Type.IsMemory() {
   484  		// All memory ops aren't needed here, but we do need
   485  		// to keep calls at least (because they might have
   486  		// syncronization operations we can't see).
   487  		return false
   488  	}
   489  	if v.Op.HasSideEffects() {
   490  		// These are mostly synchronization operations.
   491  		return false
   492  	}
   493  	return true
   494  }
   495  

View as plain text