github.com/goproxy0/go@v0.0.0-20171111080102-49cc0c489d2c/src/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  	"cmd/compile/internal/types"
     9  	"cmd/internal/src"
    10  	"fmt"
    11  	"math"
    12  	"strings"
    13  )
    14  
    15  // A Value represents a value in the SSA representation of the program.
    16  // The ID and Type fields must not be modified. The remainder may be modified
    17  // if they preserve the value of the Value (e.g. changing a (mul 2 x) to an (add x x)).
    18  type Value struct {
    19  	// A unique identifier for the value. For performance we allocate these IDs
    20  	// densely starting at 1.  There is no guarantee that there won't be occasional holes, though.
    21  	ID ID
    22  
    23  	// The operation that computes this value. See op.go.
    24  	Op Op
    25  
    26  	// The type of this value. Normally this will be a Go type, but there
    27  	// are a few other pseudo-types, see type.go.
    28  	Type *types.Type
    29  
    30  	// Auxiliary info for this value. The type of this information depends on the opcode and type.
    31  	// AuxInt is used for integer values, Aux is used for other values.
    32  	// Floats are stored in AuxInt using math.Float64bits(f).
    33  	AuxInt int64
    34  	Aux    interface{}
    35  
    36  	// Arguments of this value
    37  	Args []*Value
    38  
    39  	// Containing basic block
    40  	Block *Block
    41  
    42  	// Source position
    43  	Pos src.XPos
    44  
    45  	// Use count. Each appearance in Value.Args and Block.Control counts once.
    46  	Uses int32
    47  
    48  	// Storage for the first three args
    49  	argstorage [3]*Value
    50  }
    51  
    52  // Examples:
    53  // Opcode          aux   args
    54  //  OpAdd          nil      2
    55  //  OpConst     string      0    string constant
    56  //  OpConst      int64      0    int64 constant
    57  //  OpAddcq      int64      1    amd64 op: v = arg[0] + constant
    58  
    59  // short form print. Just v#.
    60  func (v *Value) String() string {
    61  	if v == nil {
    62  		return "nil" // should never happen, but not panicking helps with debugging
    63  	}
    64  	return fmt.Sprintf("v%d", v.ID)
    65  }
    66  
    67  func (v *Value) AuxInt8() int8 {
    68  	if opcodeTable[v.Op].auxType != auxInt8 {
    69  		v.Fatalf("op %s doesn't have an int8 aux field", v.Op)
    70  	}
    71  	return int8(v.AuxInt)
    72  }
    73  
    74  func (v *Value) AuxInt16() int16 {
    75  	if opcodeTable[v.Op].auxType != auxInt16 {
    76  		v.Fatalf("op %s doesn't have an int16 aux field", v.Op)
    77  	}
    78  	return int16(v.AuxInt)
    79  }
    80  
    81  func (v *Value) AuxInt32() int32 {
    82  	if opcodeTable[v.Op].auxType != auxInt32 {
    83  		v.Fatalf("op %s doesn't have an int32 aux field", v.Op)
    84  	}
    85  	return int32(v.AuxInt)
    86  }
    87  
    88  func (v *Value) AuxFloat() float64 {
    89  	if opcodeTable[v.Op].auxType != auxFloat32 && opcodeTable[v.Op].auxType != auxFloat64 {
    90  		v.Fatalf("op %s doesn't have a float aux field", v.Op)
    91  	}
    92  	return math.Float64frombits(uint64(v.AuxInt))
    93  }
    94  func (v *Value) AuxValAndOff() ValAndOff {
    95  	if opcodeTable[v.Op].auxType != auxSymValAndOff {
    96  		v.Fatalf("op %s doesn't have a ValAndOff aux field", v.Op)
    97  	}
    98  	return ValAndOff(v.AuxInt)
    99  }
   100  
   101  // long form print.  v# = opcode <type> [aux] args [: reg] (names)
   102  func (v *Value) LongString() string {
   103  	s := fmt.Sprintf("v%d = %s", v.ID, v.Op)
   104  	s += " <" + v.Type.String() + ">"
   105  	s += v.auxString()
   106  	for _, a := range v.Args {
   107  		s += fmt.Sprintf(" %v", a)
   108  	}
   109  	r := v.Block.Func.RegAlloc
   110  	if int(v.ID) < len(r) && r[v.ID] != nil {
   111  		s += " : " + r[v.ID].String()
   112  	}
   113  	var names []string
   114  	for name, values := range v.Block.Func.NamedValues {
   115  		for _, value := range values {
   116  			if value == v {
   117  				names = append(names, name.String())
   118  				break // drop duplicates.
   119  			}
   120  		}
   121  	}
   122  	if len(names) != 0 {
   123  		s += " (" + strings.Join(names, ", ") + ")"
   124  	}
   125  	return s
   126  }
   127  
   128  func (v *Value) auxString() string {
   129  	switch opcodeTable[v.Op].auxType {
   130  	case auxBool:
   131  		if v.AuxInt == 0 {
   132  			return " [false]"
   133  		} else {
   134  			return " [true]"
   135  		}
   136  	case auxInt8:
   137  		return fmt.Sprintf(" [%d]", v.AuxInt8())
   138  	case auxInt16:
   139  		return fmt.Sprintf(" [%d]", v.AuxInt16())
   140  	case auxInt32:
   141  		return fmt.Sprintf(" [%d]", v.AuxInt32())
   142  	case auxInt64, auxInt128:
   143  		return fmt.Sprintf(" [%d]", v.AuxInt)
   144  	case auxFloat32, auxFloat64:
   145  		return fmt.Sprintf(" [%g]", v.AuxFloat())
   146  	case auxString:
   147  		return fmt.Sprintf(" {%q}", v.Aux)
   148  	case auxSym, auxTyp:
   149  		if v.Aux != nil {
   150  			return fmt.Sprintf(" {%v}", v.Aux)
   151  		}
   152  	case auxSymOff, auxSymInt32, auxTypSize:
   153  		s := ""
   154  		if v.Aux != nil {
   155  			s = fmt.Sprintf(" {%v}", v.Aux)
   156  		}
   157  		if v.AuxInt != 0 {
   158  			s += fmt.Sprintf(" [%v]", v.AuxInt)
   159  		}
   160  		return s
   161  	case auxSymValAndOff:
   162  		s := ""
   163  		if v.Aux != nil {
   164  			s = fmt.Sprintf(" {%v}", v.Aux)
   165  		}
   166  		return s + fmt.Sprintf(" [%s]", v.AuxValAndOff())
   167  	}
   168  	return ""
   169  }
   170  
   171  func (v *Value) AddArg(w *Value) {
   172  	if v.Args == nil {
   173  		v.resetArgs() // use argstorage
   174  	}
   175  	v.Args = append(v.Args, w)
   176  	w.Uses++
   177  }
   178  func (v *Value) AddArgs(a ...*Value) {
   179  	if v.Args == nil {
   180  		v.resetArgs() // use argstorage
   181  	}
   182  	v.Args = append(v.Args, a...)
   183  	for _, x := range a {
   184  		x.Uses++
   185  	}
   186  }
   187  func (v *Value) SetArg(i int, w *Value) {
   188  	v.Args[i].Uses--
   189  	v.Args[i] = w
   190  	w.Uses++
   191  }
   192  func (v *Value) RemoveArg(i int) {
   193  	v.Args[i].Uses--
   194  	copy(v.Args[i:], v.Args[i+1:])
   195  	v.Args[len(v.Args)-1] = nil // aid GC
   196  	v.Args = v.Args[:len(v.Args)-1]
   197  }
   198  func (v *Value) SetArgs1(a *Value) {
   199  	v.resetArgs()
   200  	v.AddArg(a)
   201  }
   202  func (v *Value) SetArgs2(a *Value, b *Value) {
   203  	v.resetArgs()
   204  	v.AddArg(a)
   205  	v.AddArg(b)
   206  }
   207  
   208  func (v *Value) resetArgs() {
   209  	for _, a := range v.Args {
   210  		a.Uses--
   211  	}
   212  	v.argstorage[0] = nil
   213  	v.argstorage[1] = nil
   214  	v.argstorage[2] = nil
   215  	v.Args = v.argstorage[:0]
   216  }
   217  
   218  func (v *Value) reset(op Op) {
   219  	v.Op = op
   220  	v.resetArgs()
   221  	v.AuxInt = 0
   222  	v.Aux = nil
   223  }
   224  
   225  // copyInto makes a new value identical to v and adds it to the end of b.
   226  func (v *Value) copyInto(b *Block) *Value {
   227  	c := b.NewValue0(v.Pos, v.Op, v.Type) // Lose the position, this causes line number churn otherwise.
   228  	c.Aux = v.Aux
   229  	c.AuxInt = v.AuxInt
   230  	c.AddArgs(v.Args...)
   231  	for _, a := range v.Args {
   232  		if a.Type.IsMemory() {
   233  			v.Fatalf("can't move a value with a memory arg %s", v.LongString())
   234  		}
   235  	}
   236  	return c
   237  }
   238  
   239  // copyIntoNoXPos makes a new value identical to v and adds it to the end of b.
   240  // The copied value receives no source code position to avoid confusing changes
   241  // in debugger information (the intended user is the register allocator).
   242  func (v *Value) copyIntoNoXPos(b *Block) *Value {
   243  	return v.copyIntoWithXPos(b, src.NoXPos)
   244  }
   245  
   246  // copyIntoWithXPos makes a new value identical to v and adds it to the end of b.
   247  // The supplied position is used as the position of the new value.
   248  func (v *Value) copyIntoWithXPos(b *Block, pos src.XPos) *Value {
   249  	c := b.NewValue0(pos, v.Op, v.Type)
   250  	c.Aux = v.Aux
   251  	c.AuxInt = v.AuxInt
   252  	c.AddArgs(v.Args...)
   253  	for _, a := range v.Args {
   254  		if a.Type.IsMemory() {
   255  			v.Fatalf("can't move a value with a memory arg %s", v.LongString())
   256  		}
   257  	}
   258  	return c
   259  }
   260  
   261  func (v *Value) Logf(msg string, args ...interface{}) { v.Block.Logf(msg, args...) }
   262  func (v *Value) Log() bool                            { return v.Block.Log() }
   263  func (v *Value) Fatalf(msg string, args ...interface{}) {
   264  	v.Block.Func.fe.Fatalf(v.Pos, msg, args...)
   265  }
   266  
   267  // isGenericIntConst returns whether v is a generic integer constant.
   268  func (v *Value) isGenericIntConst() bool {
   269  	return v != nil && (v.Op == OpConst64 || v.Op == OpConst32 || v.Op == OpConst16 || v.Op == OpConst8)
   270  }
   271  
   272  // Reg returns the register assigned to v, in cmd/internal/obj/$ARCH numbering.
   273  func (v *Value) Reg() int16 {
   274  	reg := v.Block.Func.RegAlloc[v.ID]
   275  	if reg == nil {
   276  		v.Fatalf("nil register for value: %s\n%s\n", v.LongString(), v.Block.Func)
   277  	}
   278  	return reg.(*Register).objNum
   279  }
   280  
   281  // Reg0 returns the register assigned to the first output of v, in cmd/internal/obj/$ARCH numbering.
   282  func (v *Value) Reg0() int16 {
   283  	reg := v.Block.Func.RegAlloc[v.ID].(LocPair)[0]
   284  	if reg == nil {
   285  		v.Fatalf("nil first register for value: %s\n%s\n", v.LongString(), v.Block.Func)
   286  	}
   287  	return reg.(*Register).objNum
   288  }
   289  
   290  // Reg1 returns the register assigned to the second output of v, in cmd/internal/obj/$ARCH numbering.
   291  func (v *Value) Reg1() int16 {
   292  	reg := v.Block.Func.RegAlloc[v.ID].(LocPair)[1]
   293  	if reg == nil {
   294  		v.Fatalf("nil second register for value: %s\n%s\n", v.LongString(), v.Block.Func)
   295  	}
   296  	return reg.(*Register).objNum
   297  }
   298  
   299  func (v *Value) RegName() string {
   300  	reg := v.Block.Func.RegAlloc[v.ID]
   301  	if reg == nil {
   302  		v.Fatalf("nil register for value: %s\n%s\n", v.LongString(), v.Block.Func)
   303  	}
   304  	return reg.(*Register).name
   305  }
   306  
   307  // MemoryArg returns the memory argument for the Value.
   308  // The returned value, if non-nil, will be memory-typed (or a tuple with a memory-typed second part).
   309  // Otherwise, nil is returned.
   310  func (v *Value) MemoryArg() *Value {
   311  	if v.Op == OpPhi {
   312  		v.Fatalf("MemoryArg on Phi")
   313  	}
   314  	na := len(v.Args)
   315  	if na == 0 {
   316  		return nil
   317  	}
   318  	if m := v.Args[na-1]; m.Type.IsMemory() {
   319  		return m
   320  	}
   321  	return nil
   322  }
   323  
   324  // LackingPos indicates whether v is a value that is unlikely to have a correct
   325  // position assigned to it.  Ignoring such values leads to more user-friendly positions
   326  // assigned to nearby values and the blocks containing them.
   327  func (v *Value) LackingPos() bool {
   328  	// The exact definition of LackingPos is somewhat heuristically defined and may change
   329  	// in the future, for example if some of these operations are generated more carefully
   330  	// with respect to their source position.
   331  	return v.Op == OpVarDef || v.Op == OpVarKill || v.Op == OpVarLive || v.Op == OpPhi ||
   332  		(v.Op == OpFwdRef || v.Op == OpCopy) && v.Type == types.TypeMem
   333  }