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

View as plain text