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

View as plain text