2015-03-03 13:38:14 -08:00
|
|
|
// Copyright 2015 The Go Authors. All rights reserved.
|
|
|
|
|
// Use of this source code is governed by a BSD-style
|
|
|
|
|
// license that can be found in the LICENSE file.
|
|
|
|
|
|
|
|
|
|
package ssa
|
|
|
|
|
|
2015-09-04 06:33:56 -05:00
|
|
|
import (
|
|
|
|
|
"fmt"
|
|
|
|
|
"math"
|
|
|
|
|
)
|
2015-03-03 13:38:14 -08:00
|
|
|
|
|
|
|
|
// A Value represents a value in the SSA representation of the program.
|
|
|
|
|
// The ID and Type fields must not be modified. The remainder may be modified
|
|
|
|
|
// if they preserve the value of the Value (e.g. changing a (mul 2 x) to an (add x x)).
|
|
|
|
|
type Value struct {
|
|
|
|
|
// A unique identifier for the value. For performance we allocate these IDs
|
2015-08-11 12:51:33 -07:00
|
|
|
// densely starting at 1. There is no guarantee that there won't be occasional holes, though.
|
2015-03-03 13:38:14 -08:00
|
|
|
ID ID
|
|
|
|
|
|
|
|
|
|
// The operation that computes this value. See op.go.
|
|
|
|
|
Op Op
|
|
|
|
|
|
|
|
|
|
// The type of this value. Normally this will be a Go type, but there
|
|
|
|
|
// are a few other pseudo-types, see type.go.
|
|
|
|
|
Type Type
|
|
|
|
|
|
2015-03-16 16:31:13 -07:00
|
|
|
// Auxiliary info for this value. The type of this information depends on the opcode and type.
|
2015-06-11 21:29:25 -07:00
|
|
|
// AuxInt is used for integer values, Aux is used for other values.
|
|
|
|
|
AuxInt int64
|
|
|
|
|
Aux interface{}
|
2015-03-03 13:38:14 -08:00
|
|
|
|
|
|
|
|
// Arguments of this value
|
|
|
|
|
Args []*Value
|
|
|
|
|
|
|
|
|
|
// Containing basic block
|
|
|
|
|
Block *Block
|
|
|
|
|
|
2015-05-30 01:03:06 -04:00
|
|
|
// Source line number
|
|
|
|
|
Line int32
|
|
|
|
|
|
2015-03-03 13:38:14 -08:00
|
|
|
// Storage for the first two args
|
|
|
|
|
argstorage [2]*Value
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Examples:
|
|
|
|
|
// Opcode aux args
|
|
|
|
|
// OpAdd nil 2
|
2015-03-26 10:49:03 -07:00
|
|
|
// OpConst string 0 string constant
|
|
|
|
|
// OpConst int64 0 int64 constant
|
2015-03-03 13:38:14 -08:00
|
|
|
// OpAddcq int64 1 amd64 op: v = arg[0] + constant
|
|
|
|
|
|
|
|
|
|
// short form print. Just v#.
|
|
|
|
|
func (v *Value) String() string {
|
2015-08-22 13:30:45 -07:00
|
|
|
if v == nil {
|
|
|
|
|
return "nil" // should never happen, but not panicking helps with debugging
|
|
|
|
|
}
|
2015-03-03 13:38:14 -08:00
|
|
|
return fmt.Sprintf("v%d", v.ID)
|
|
|
|
|
}
|
|
|
|
|
|
2016-01-31 11:39:39 -08:00
|
|
|
func (v *Value) AuxInt8() int8 {
|
|
|
|
|
if opcodeTable[v.Op].auxType != auxInt8 {
|
|
|
|
|
v.Fatalf("op %s doesn't have an int8 aux field", v.Op)
|
|
|
|
|
}
|
|
|
|
|
return int8(v.AuxInt)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (v *Value) AuxInt16() int16 {
|
|
|
|
|
if opcodeTable[v.Op].auxType != auxInt16 {
|
|
|
|
|
v.Fatalf("op %s doesn't have an int16 aux field", v.Op)
|
|
|
|
|
}
|
|
|
|
|
return int16(v.AuxInt)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (v *Value) AuxInt32() int32 {
|
|
|
|
|
if opcodeTable[v.Op].auxType != auxInt32 {
|
|
|
|
|
v.Fatalf("op %s doesn't have an int32 aux field", v.Op)
|
|
|
|
|
}
|
|
|
|
|
return int32(v.AuxInt)
|
|
|
|
|
}
|
2016-02-19 16:58:21 -06:00
|
|
|
|
|
|
|
|
// AuxInt2Int64 is used to sign extend the lower bits of AuxInt according to
|
|
|
|
|
// the size of AuxInt specified in the opcode table.
|
|
|
|
|
func (v *Value) AuxInt2Int64() int64 {
|
|
|
|
|
switch opcodeTable[v.Op].auxType {
|
|
|
|
|
case auxInt64:
|
|
|
|
|
return v.AuxInt
|
|
|
|
|
case auxInt32:
|
|
|
|
|
return int64(int32(v.AuxInt))
|
|
|
|
|
case auxInt16:
|
|
|
|
|
return int64(int16(v.AuxInt))
|
|
|
|
|
case auxInt8:
|
|
|
|
|
return int64(int8(v.AuxInt))
|
|
|
|
|
default:
|
|
|
|
|
v.Fatalf("op %s doesn't have an aux int field", v.Op)
|
|
|
|
|
return -1
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-01-31 11:39:39 -08:00
|
|
|
func (v *Value) AuxFloat() float64 {
|
|
|
|
|
if opcodeTable[v.Op].auxType != auxFloat {
|
|
|
|
|
v.Fatalf("op %s doesn't have a float aux field", v.Op)
|
|
|
|
|
}
|
|
|
|
|
return math.Float64frombits(uint64(v.AuxInt))
|
|
|
|
|
}
|
|
|
|
|
func (v *Value) AuxValAndOff() ValAndOff {
|
|
|
|
|
if opcodeTable[v.Op].auxType != auxSymValAndOff {
|
|
|
|
|
v.Fatalf("op %s doesn't have a ValAndOff aux field", v.Op)
|
|
|
|
|
}
|
|
|
|
|
return ValAndOff(v.AuxInt)
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-03 13:38:14 -08:00
|
|
|
// long form print. v# = opcode <type> [aux] args [: reg]
|
|
|
|
|
func (v *Value) LongString() string {
|
2015-06-06 16:03:33 -07:00
|
|
|
s := fmt.Sprintf("v%d = %s", v.ID, v.Op.String())
|
2015-03-03 13:38:14 -08:00
|
|
|
s += " <" + v.Type.String() + ">"
|
2016-01-31 11:39:39 -08:00
|
|
|
switch opcodeTable[v.Op].auxType {
|
|
|
|
|
case auxBool:
|
2016-01-26 15:47:08 -08:00
|
|
|
if v.AuxInt == 0 {
|
|
|
|
|
s += " [false]"
|
|
|
|
|
} else {
|
|
|
|
|
s += " [true]"
|
|
|
|
|
}
|
2016-01-31 11:39:39 -08:00
|
|
|
case auxInt8:
|
|
|
|
|
s += fmt.Sprintf(" [%d]", v.AuxInt8())
|
|
|
|
|
case auxInt16:
|
|
|
|
|
s += fmt.Sprintf(" [%d]", v.AuxInt16())
|
|
|
|
|
case auxInt32:
|
|
|
|
|
s += fmt.Sprintf(" [%d]", v.AuxInt32())
|
|
|
|
|
case auxInt64:
|
|
|
|
|
s += fmt.Sprintf(" [%d]", v.AuxInt)
|
|
|
|
|
case auxFloat:
|
|
|
|
|
s += fmt.Sprintf(" [%g]", v.AuxFloat())
|
|
|
|
|
case auxString:
|
|
|
|
|
s += fmt.Sprintf(" {%s}", v.Aux)
|
2016-02-11 18:13:17 -06:00
|
|
|
case auxSym:
|
|
|
|
|
if v.Aux != nil {
|
|
|
|
|
s += fmt.Sprintf(" {%s}", v.Aux)
|
|
|
|
|
}
|
2016-01-31 11:39:39 -08:00
|
|
|
case auxSymOff:
|
|
|
|
|
if v.Aux != nil {
|
|
|
|
|
s += fmt.Sprintf(" {%s}", v.Aux)
|
2015-09-04 06:33:56 -05:00
|
|
|
}
|
2016-02-02 11:13:50 -08:00
|
|
|
s += fmt.Sprintf(" [%d]", v.AuxInt)
|
2016-01-31 11:39:39 -08:00
|
|
|
case auxSymValAndOff:
|
|
|
|
|
if v.Aux != nil {
|
|
|
|
|
s += fmt.Sprintf(" {%s}", v.Aux)
|
2015-06-23 16:44:06 -07:00
|
|
|
}
|
2016-01-31 11:39:39 -08:00
|
|
|
s += fmt.Sprintf(" [%s]", v.AuxValAndOff())
|
2015-03-03 13:38:14 -08:00
|
|
|
}
|
|
|
|
|
for _, a := range v.Args {
|
|
|
|
|
s += fmt.Sprintf(" %v", a)
|
|
|
|
|
}
|
|
|
|
|
r := v.Block.Func.RegAlloc
|
2015-08-11 12:51:33 -07:00
|
|
|
if int(v.ID) < len(r) && r[v.ID] != nil {
|
2015-03-03 13:38:14 -08:00
|
|
|
s += " : " + r[v.ID].Name()
|
|
|
|
|
}
|
|
|
|
|
return s
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (v *Value) AddArg(w *Value) {
|
2015-03-16 16:31:13 -07:00
|
|
|
if v.Args == nil {
|
|
|
|
|
v.resetArgs() // use argstorage
|
|
|
|
|
}
|
2015-03-03 13:38:14 -08:00
|
|
|
v.Args = append(v.Args, w)
|
|
|
|
|
}
|
|
|
|
|
func (v *Value) AddArgs(a ...*Value) {
|
2015-03-16 16:31:13 -07:00
|
|
|
if v.Args == nil {
|
|
|
|
|
v.resetArgs() // use argstorage
|
|
|
|
|
}
|
2015-03-03 13:38:14 -08:00
|
|
|
v.Args = append(v.Args, a...)
|
|
|
|
|
}
|
|
|
|
|
func (v *Value) SetArg(i int, w *Value) {
|
|
|
|
|
v.Args[i] = w
|
|
|
|
|
}
|
|
|
|
|
func (v *Value) RemoveArg(i int) {
|
|
|
|
|
copy(v.Args[i:], v.Args[i+1:])
|
2015-03-16 16:31:13 -07:00
|
|
|
v.Args[len(v.Args)-1] = nil // aid GC
|
2015-03-03 13:38:14 -08:00
|
|
|
v.Args = v.Args[:len(v.Args)-1]
|
|
|
|
|
}
|
|
|
|
|
func (v *Value) SetArgs1(a *Value) {
|
|
|
|
|
v.resetArgs()
|
|
|
|
|
v.AddArg(a)
|
|
|
|
|
}
|
|
|
|
|
func (v *Value) SetArgs2(a *Value, b *Value) {
|
|
|
|
|
v.resetArgs()
|
|
|
|
|
v.AddArg(a)
|
|
|
|
|
v.AddArg(b)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (v *Value) resetArgs() {
|
|
|
|
|
v.argstorage[0] = nil
|
|
|
|
|
v.argstorage[1] = nil
|
|
|
|
|
v.Args = v.argstorage[:0]
|
|
|
|
|
}
|
2015-06-12 11:01:13 -07:00
|
|
|
|
2016-02-04 17:21:57 +01:00
|
|
|
func (v *Value) reset(op Op) {
|
|
|
|
|
v.Op = op
|
|
|
|
|
v.resetArgs()
|
|
|
|
|
v.AuxInt = 0
|
|
|
|
|
v.Aux = nil
|
|
|
|
|
}
|
|
|
|
|
|
2015-12-09 15:58:18 -08:00
|
|
|
// copyInto makes a new value identical to v and adds it to the end of b.
|
|
|
|
|
func (v *Value) copyInto(b *Block) *Value {
|
|
|
|
|
c := b.NewValue0(v.Line, v.Op, v.Type)
|
|
|
|
|
c.Aux = v.Aux
|
|
|
|
|
c.AuxInt = v.AuxInt
|
|
|
|
|
c.AddArgs(v.Args...)
|
2016-01-26 15:47:08 -08:00
|
|
|
for _, a := range v.Args {
|
|
|
|
|
if a.Type.IsMemory() {
|
|
|
|
|
v.Fatalf("can't move a value with a memory arg %s", v.LongString())
|
|
|
|
|
}
|
|
|
|
|
}
|
2015-12-09 15:58:18 -08:00
|
|
|
return c
|
|
|
|
|
}
|
|
|
|
|
|
2016-01-13 11:14:57 -08:00
|
|
|
func (v *Value) Logf(msg string, args ...interface{}) { v.Block.Logf(msg, args...) }
|
2016-01-29 14:44:15 -05:00
|
|
|
func (v *Value) Log() bool { return v.Block.Log() }
|
2016-01-13 11:14:57 -08:00
|
|
|
func (v *Value) Fatalf(msg string, args ...interface{}) {
|
|
|
|
|
v.Block.Func.Config.Fatalf(v.Line, msg, args...)
|
|
|
|
|
}
|
|
|
|
|
func (v *Value) Unimplementedf(msg string, args ...interface{}) {
|
|
|
|
|
v.Block.Func.Config.Unimplementedf(v.Line, msg, args...)
|
|
|
|
|
}
|
2015-06-19 21:02:28 -07:00
|
|
|
|
|
|
|
|
// ExternSymbol is an aux value that encodes a variable's
|
|
|
|
|
// constant offset from the static base pointer.
|
|
|
|
|
type ExternSymbol struct {
|
|
|
|
|
Typ Type // Go type
|
|
|
|
|
Sym fmt.Stringer // A *gc.Sym referring to a global variable
|
|
|
|
|
// Note: the offset for an external symbol is not
|
|
|
|
|
// calculated until link time.
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ArgSymbol is an aux value that encodes an argument or result
|
|
|
|
|
// variable's constant offset from FP (FP = SP + framesize).
|
|
|
|
|
type ArgSymbol struct {
|
2015-10-22 14:22:38 -07:00
|
|
|
Typ Type // Go type
|
|
|
|
|
Node GCNode // A *gc.Node referring to the argument/result variable.
|
2015-06-19 21:02:28 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// AutoSymbol is an aux value that encodes a local variable's
|
|
|
|
|
// constant offset from SP.
|
|
|
|
|
type AutoSymbol struct {
|
2015-10-22 14:22:38 -07:00
|
|
|
Typ Type // Go type
|
|
|
|
|
Node GCNode // A *gc.Node referring to a local (auto) variable.
|
2015-06-19 21:02:28 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (s *ExternSymbol) String() string {
|
|
|
|
|
return s.Sym.String()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (s *ArgSymbol) String() string {
|
2015-08-24 02:16:19 -07:00
|
|
|
return s.Node.String()
|
2015-06-19 21:02:28 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (s *AutoSymbol) String() string {
|
2015-08-24 02:16:19 -07:00
|
|
|
return s.Node.String()
|
2015-06-19 21:02:28 -07:00
|
|
|
}
|