github.com/gagliardetto/golang-go@v0.0.0-20201020153340-53909ea70814/cmd/compile/internal/ssa/value.go (about)

     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  	"github.com/gagliardetto/golang-go/cmd/compile/internal/types"
     9  	"github.com/gagliardetto/golang-go/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  	// 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, auxArchSpecific:
   183  		if v.Aux != nil {
   184  			return fmt.Sprintf(" {%v}", v.Aux)
   185  		}
   186  	case auxSymOff, 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  // unlike copyIntoWithXPos this does not check for v.Pos being a statement.
   270  func (v *Value) copyInto(b *Block) *Value {
   271  	c := b.NewValue0(v.Pos.WithNotStmt(), v.Op, v.Type) // Lose the position, this causes line number churn otherwise.
   272  	c.Aux = v.Aux
   273  	c.AuxInt = v.AuxInt
   274  	c.AddArgs(v.Args...)
   275  	for _, a := range v.Args {
   276  		if a.Type.IsMemory() {
   277  			v.Fatalf("can't move a value with a memory arg %s", v.LongString())
   278  		}
   279  	}
   280  	return c
   281  }
   282  
   283  // copyIntoWithXPos makes a new value identical to v and adds it to the end of b.
   284  // The supplied position is used as the position of the new value.
   285  // Because this is used for rematerialization, check for case that (rematerialized)
   286  // input to value with position 'pos' carried a statement mark, and that the supplied
   287  // position (of the instruction using the rematerialized value) is not marked, and
   288  // preserve that mark if its line matches the supplied position.
   289  func (v *Value) copyIntoWithXPos(b *Block, pos src.XPos) *Value {
   290  	if v.Pos.IsStmt() == src.PosIsStmt && pos.IsStmt() != src.PosIsStmt && v.Pos.SameFileAndLine(pos) {
   291  		pos = pos.WithIsStmt()
   292  	}
   293  	c := b.NewValue0(pos, v.Op, v.Type)
   294  	c.Aux = v.Aux
   295  	c.AuxInt = v.AuxInt
   296  	c.AddArgs(v.Args...)
   297  	for _, a := range v.Args {
   298  		if a.Type.IsMemory() {
   299  			v.Fatalf("can't move a value with a memory arg %s", v.LongString())
   300  		}
   301  	}
   302  	return c
   303  }
   304  
   305  func (v *Value) Logf(msg string, args ...interface{}) { v.Block.Logf(msg, args...) }
   306  func (v *Value) Log() bool                            { return v.Block.Log() }
   307  func (v *Value) Fatalf(msg string, args ...interface{}) {
   308  	v.Block.Func.fe.Fatalf(v.Pos, msg, args...)
   309  }
   310  
   311  // isGenericIntConst reports whether v is a generic integer constant.
   312  func (v *Value) isGenericIntConst() bool {
   313  	return v != nil && (v.Op == OpConst64 || v.Op == OpConst32 || v.Op == OpConst16 || v.Op == OpConst8)
   314  }
   315  
   316  // Reg returns the register assigned to v, in cmd/internal/obj/$ARCH numbering.
   317  func (v *Value) Reg() int16 {
   318  	reg := v.Block.Func.RegAlloc[v.ID]
   319  	if reg == nil {
   320  		v.Fatalf("nil register for value: %s\n%s\n", v.LongString(), v.Block.Func)
   321  	}
   322  	return reg.(*Register).objNum
   323  }
   324  
   325  // Reg0 returns the register assigned to the first output of v, in cmd/internal/obj/$ARCH numbering.
   326  func (v *Value) Reg0() int16 {
   327  	reg := v.Block.Func.RegAlloc[v.ID].(LocPair)[0]
   328  	if reg == nil {
   329  		v.Fatalf("nil first register for value: %s\n%s\n", v.LongString(), v.Block.Func)
   330  	}
   331  	return reg.(*Register).objNum
   332  }
   333  
   334  // Reg1 returns the register assigned to the second output of v, in cmd/internal/obj/$ARCH numbering.
   335  func (v *Value) Reg1() int16 {
   336  	reg := v.Block.Func.RegAlloc[v.ID].(LocPair)[1]
   337  	if reg == nil {
   338  		v.Fatalf("nil second register for value: %s\n%s\n", v.LongString(), v.Block.Func)
   339  	}
   340  	return reg.(*Register).objNum
   341  }
   342  
   343  func (v *Value) RegName() string {
   344  	reg := v.Block.Func.RegAlloc[v.ID]
   345  	if reg == nil {
   346  		v.Fatalf("nil register for value: %s\n%s\n", v.LongString(), v.Block.Func)
   347  	}
   348  	return reg.(*Register).name
   349  }
   350  
   351  // MemoryArg returns the memory argument for the Value.
   352  // The returned value, if non-nil, will be memory-typed (or a tuple with a memory-typed second part).
   353  // Otherwise, nil is returned.
   354  func (v *Value) MemoryArg() *Value {
   355  	if v.Op == OpPhi {
   356  		v.Fatalf("MemoryArg on Phi")
   357  	}
   358  	na := len(v.Args)
   359  	if na == 0 {
   360  		return nil
   361  	}
   362  	if m := v.Args[na-1]; m.Type.IsMemory() {
   363  		return m
   364  	}
   365  	return nil
   366  }
   367  
   368  // LackingPos indicates whether v is a value that is unlikely to have a correct
   369  // position assigned to it.  Ignoring such values leads to more user-friendly positions
   370  // assigned to nearby values and the blocks containing them.
   371  func (v *Value) LackingPos() bool {
   372  	// The exact definition of LackingPos is somewhat heuristically defined and may change
   373  	// in the future, for example if some of these operations are generated more carefully
   374  	// with respect to their source position.
   375  	return v.Op == OpVarDef || v.Op == OpVarKill || v.Op == OpVarLive || v.Op == OpPhi ||
   376  		(v.Op == OpFwdRef || v.Op == OpCopy) && v.Type == types.TypeMem
   377  }