github.com/miolini/go@v0.0.0-20160405192216-fca68c8cb408/src/cmd/compile/internal/ssa/func.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  	"fmt"
     9  	"math"
    10  )
    11  
    12  // A Func represents a Go func declaration (or function literal) and
    13  // its body. This package compiles each Func independently.
    14  type Func struct {
    15  	Config     *Config     // architecture information
    16  	pass       *pass       // current pass information (name, options, etc.)
    17  	Name       string      // e.g. bytes·Compare
    18  	Type       Type        // type signature of the function.
    19  	StaticData interface{} // associated static data, untouched by the ssa package
    20  	Blocks     []*Block    // unordered set of all basic blocks (note: not indexable by ID)
    21  	Entry      *Block      // the entry basic block
    22  	bid        idAlloc     // block ID allocator
    23  	vid        idAlloc     // value ID allocator
    24  
    25  	scheduled bool // Values in Blocks are in final order
    26  
    27  	// when register allocation is done, maps value ids to locations
    28  	RegAlloc []Location
    29  
    30  	// map from LocalSlot to set of Values that we want to store in that slot.
    31  	NamedValues map[LocalSlot][]*Value
    32  	// Names is a copy of NamedValues.Keys. We keep a separate list
    33  	// of keys to make iteration order deterministic.
    34  	Names []LocalSlot
    35  
    36  	freeValues *Value // free Values linked by argstorage[0].  All other fields except ID are 0/nil.
    37  	freeBlocks *Block // free Blocks linked by succstorage[0].  All other fields except ID are 0/nil.
    38  
    39  	constants map[int64][]*Value // constants cache, keyed by constant value; users must check value's Op and Type
    40  }
    41  
    42  // NumBlocks returns an integer larger than the id of any Block in the Func.
    43  func (f *Func) NumBlocks() int {
    44  	return f.bid.num()
    45  }
    46  
    47  // NumValues returns an integer larger than the id of any Value in the Func.
    48  func (f *Func) NumValues() int {
    49  	return f.vid.num()
    50  }
    51  
    52  // newSparseSet returns a sparse set that can store at least up to n integers.
    53  func (f *Func) newSparseSet(n int) *sparseSet {
    54  	for i, scr := range f.Config.scrSparse {
    55  		if scr != nil && scr.cap() >= n {
    56  			f.Config.scrSparse[i] = nil
    57  			scr.clear()
    58  			return scr
    59  		}
    60  	}
    61  	return newSparseSet(n)
    62  }
    63  
    64  // retSparseSet returns a sparse set to the config's cache of sparse sets to be reused by f.newSparseSet.
    65  func (f *Func) retSparseSet(ss *sparseSet) {
    66  	for i, scr := range f.Config.scrSparse {
    67  		if scr == nil {
    68  			f.Config.scrSparse[i] = ss
    69  			return
    70  		}
    71  	}
    72  	f.Config.scrSparse = append(f.Config.scrSparse, ss)
    73  }
    74  
    75  // newValue allocates a new Value with the given fields and places it at the end of b.Values.
    76  func (f *Func) newValue(op Op, t Type, b *Block, line int32) *Value {
    77  	var v *Value
    78  	if f.freeValues != nil {
    79  		v = f.freeValues
    80  		f.freeValues = v.argstorage[0]
    81  		v.argstorage[0] = nil
    82  	} else {
    83  		ID := f.vid.get()
    84  		if int(ID) < len(f.Config.values) {
    85  			v = &f.Config.values[ID]
    86  		} else {
    87  			v = &Value{ID: ID}
    88  		}
    89  	}
    90  	v.Op = op
    91  	v.Type = t
    92  	v.Block = b
    93  	v.Line = line
    94  	b.Values = append(b.Values, v)
    95  	return v
    96  }
    97  
    98  // logPassStat writes a string key and int value as a warning in a
    99  // tab-separated format easily handled by spreadsheets or awk.
   100  // file names, lines, and function names are included to provide enough (?)
   101  // context to allow item-by-item comparisons across runs.
   102  // For example:
   103  // awk 'BEGIN {FS="\t"} $3~/TIME/{sum+=$4} END{print "t(ns)=",sum}' t.log
   104  func (f *Func) logStat(key string, args ...interface{}) {
   105  	value := ""
   106  	for _, a := range args {
   107  		value += fmt.Sprintf("\t%v", a)
   108  	}
   109  	f.Config.Warnl(f.Entry.Line, "\t%s\t%s%s\t%s", f.pass.name, key, value, f.Name)
   110  }
   111  
   112  // freeValue frees a value. It must no longer be referenced.
   113  func (f *Func) freeValue(v *Value) {
   114  	if v.Block == nil {
   115  		f.Fatalf("trying to free an already freed value")
   116  	}
   117  	if v.Uses != 0 {
   118  		f.Fatalf("value %s still has %d uses", v, v.Uses)
   119  	}
   120  	// Clear everything but ID (which we reuse).
   121  	id := v.ID
   122  
   123  	// Zero argument values might be cached, so remove them there.
   124  	nArgs := opcodeTable[v.Op].argLen
   125  	if nArgs == 0 {
   126  		vv := f.constants[v.AuxInt]
   127  		for i, cv := range vv {
   128  			if v == cv {
   129  				vv[i] = vv[len(vv)-1]
   130  				f.constants[v.AuxInt] = vv[0 : len(vv)-1]
   131  				break
   132  			}
   133  		}
   134  	}
   135  	*v = Value{}
   136  	v.ID = id
   137  	v.argstorage[0] = f.freeValues
   138  	f.freeValues = v
   139  }
   140  
   141  // newBlock allocates a new Block of the given kind and places it at the end of f.Blocks.
   142  func (f *Func) NewBlock(kind BlockKind) *Block {
   143  	var b *Block
   144  	if f.freeBlocks != nil {
   145  		b = f.freeBlocks
   146  		f.freeBlocks = b.succstorage[0]
   147  		b.succstorage[0] = nil
   148  	} else {
   149  		ID := f.bid.get()
   150  		if int(ID) < len(f.Config.blocks) {
   151  			b = &f.Config.blocks[ID]
   152  		} else {
   153  			b = &Block{ID: ID}
   154  		}
   155  	}
   156  	b.Kind = kind
   157  	b.Func = f
   158  	b.Preds = b.predstorage[:0]
   159  	b.Succs = b.succstorage[:0]
   160  	b.Values = b.valstorage[:0]
   161  	f.Blocks = append(f.Blocks, b)
   162  	return b
   163  }
   164  
   165  func (f *Func) freeBlock(b *Block) {
   166  	if b.Func == nil {
   167  		f.Fatalf("trying to free an already freed block")
   168  	}
   169  	// Clear everything but ID (which we reuse).
   170  	id := b.ID
   171  	*b = Block{}
   172  	b.ID = id
   173  	b.succstorage[0] = f.freeBlocks
   174  	f.freeBlocks = b
   175  }
   176  
   177  // NewValue0 returns a new value in the block with no arguments and zero aux values.
   178  func (b *Block) NewValue0(line int32, op Op, t Type) *Value {
   179  	v := b.Func.newValue(op, t, b, line)
   180  	v.AuxInt = 0
   181  	v.Args = v.argstorage[:0]
   182  	return v
   183  }
   184  
   185  // NewValue returns a new value in the block with no arguments and an auxint value.
   186  func (b *Block) NewValue0I(line int32, op Op, t Type, auxint int64) *Value {
   187  	v := b.Func.newValue(op, t, b, line)
   188  	v.AuxInt = auxint
   189  	v.Args = v.argstorage[:0]
   190  	return v
   191  }
   192  
   193  // NewValue returns a new value in the block with no arguments and an aux value.
   194  func (b *Block) NewValue0A(line int32, op Op, t Type, aux interface{}) *Value {
   195  	if _, ok := aux.(int64); ok {
   196  		// Disallow int64 aux values. They should be in the auxint field instead.
   197  		// Maybe we want to allow this at some point, but for now we disallow it
   198  		// to prevent errors like using NewValue1A instead of NewValue1I.
   199  		b.Fatalf("aux field has int64 type op=%s type=%s aux=%v", op, t, aux)
   200  	}
   201  	v := b.Func.newValue(op, t, b, line)
   202  	v.AuxInt = 0
   203  	v.Aux = aux
   204  	v.Args = v.argstorage[:0]
   205  	return v
   206  }
   207  
   208  // NewValue returns a new value in the block with no arguments and both an auxint and aux values.
   209  func (b *Block) NewValue0IA(line int32, op Op, t Type, auxint int64, aux interface{}) *Value {
   210  	v := b.Func.newValue(op, t, b, line)
   211  	v.AuxInt = auxint
   212  	v.Aux = aux
   213  	v.Args = v.argstorage[:0]
   214  	return v
   215  }
   216  
   217  // NewValue1 returns a new value in the block with one argument and zero aux values.
   218  func (b *Block) NewValue1(line int32, op Op, t Type, arg *Value) *Value {
   219  	v := b.Func.newValue(op, t, b, line)
   220  	v.AuxInt = 0
   221  	v.Args = v.argstorage[:1]
   222  	v.argstorage[0] = arg
   223  	arg.Uses++
   224  	return v
   225  }
   226  
   227  // NewValue1I returns a new value in the block with one argument and an auxint value.
   228  func (b *Block) NewValue1I(line int32, op Op, t Type, auxint int64, arg *Value) *Value {
   229  	v := b.Func.newValue(op, t, b, line)
   230  	v.AuxInt = auxint
   231  	v.Args = v.argstorage[:1]
   232  	v.argstorage[0] = arg
   233  	arg.Uses++
   234  	return v
   235  }
   236  
   237  // NewValue1A returns a new value in the block with one argument and an aux value.
   238  func (b *Block) NewValue1A(line int32, op Op, t Type, aux interface{}, arg *Value) *Value {
   239  	v := b.Func.newValue(op, t, b, line)
   240  	v.AuxInt = 0
   241  	v.Aux = aux
   242  	v.Args = v.argstorage[:1]
   243  	v.argstorage[0] = arg
   244  	arg.Uses++
   245  	return v
   246  }
   247  
   248  // NewValue1IA returns a new value in the block with one argument and both an auxint and aux values.
   249  func (b *Block) NewValue1IA(line int32, op Op, t Type, auxint int64, aux interface{}, arg *Value) *Value {
   250  	v := b.Func.newValue(op, t, b, line)
   251  	v.AuxInt = auxint
   252  	v.Aux = aux
   253  	v.Args = v.argstorage[:1]
   254  	v.argstorage[0] = arg
   255  	arg.Uses++
   256  	return v
   257  }
   258  
   259  // NewValue2 returns a new value in the block with two arguments and zero aux values.
   260  func (b *Block) NewValue2(line int32, op Op, t Type, arg0, arg1 *Value) *Value {
   261  	v := b.Func.newValue(op, t, b, line)
   262  	v.AuxInt = 0
   263  	v.Args = v.argstorage[:2]
   264  	v.argstorage[0] = arg0
   265  	v.argstorage[1] = arg1
   266  	arg0.Uses++
   267  	arg1.Uses++
   268  	return v
   269  }
   270  
   271  // NewValue2I returns a new value in the block with two arguments and an auxint value.
   272  func (b *Block) NewValue2I(line int32, op Op, t Type, auxint int64, arg0, arg1 *Value) *Value {
   273  	v := b.Func.newValue(op, t, b, line)
   274  	v.AuxInt = auxint
   275  	v.Args = v.argstorage[:2]
   276  	v.argstorage[0] = arg0
   277  	v.argstorage[1] = arg1
   278  	arg0.Uses++
   279  	arg1.Uses++
   280  	return v
   281  }
   282  
   283  // NewValue3 returns a new value in the block with three arguments and zero aux values.
   284  func (b *Block) NewValue3(line int32, op Op, t Type, arg0, arg1, arg2 *Value) *Value {
   285  	v := b.Func.newValue(op, t, b, line)
   286  	v.AuxInt = 0
   287  	v.Args = []*Value{arg0, arg1, arg2}
   288  	arg0.Uses++
   289  	arg1.Uses++
   290  	arg2.Uses++
   291  	return v
   292  }
   293  
   294  // NewValue3I returns a new value in the block with three arguments and an auxint value.
   295  func (b *Block) NewValue3I(line int32, op Op, t Type, auxint int64, arg0, arg1, arg2 *Value) *Value {
   296  	v := b.Func.newValue(op, t, b, line)
   297  	v.AuxInt = auxint
   298  	v.Args = []*Value{arg0, arg1, arg2}
   299  	arg0.Uses++
   300  	arg1.Uses++
   301  	arg2.Uses++
   302  	return v
   303  }
   304  
   305  // constVal returns a constant value for c.
   306  func (f *Func) constVal(line int32, op Op, t Type, c int64, setAux bool) *Value {
   307  	if f.constants == nil {
   308  		f.constants = make(map[int64][]*Value)
   309  	}
   310  	vv := f.constants[c]
   311  	for _, v := range vv {
   312  		if v.Op == op && v.Type.Equal(t) {
   313  			if setAux && v.AuxInt != c {
   314  				panic(fmt.Sprintf("cached const %s should have AuxInt of %d", v.LongString(), c))
   315  			}
   316  			return v
   317  		}
   318  	}
   319  	var v *Value
   320  	if setAux {
   321  		v = f.Entry.NewValue0I(line, op, t, c)
   322  	} else {
   323  		v = f.Entry.NewValue0(line, op, t)
   324  	}
   325  	f.constants[c] = append(vv, v)
   326  	return v
   327  }
   328  
   329  // These magic auxint values let us easily cache non-numeric constants
   330  // using the same constants map while making collisions unlikely.
   331  // These values are unlikely to occur in regular code and
   332  // are easy to grep for in case of bugs.
   333  const (
   334  	constSliceMagic       = 1122334455
   335  	constInterfaceMagic   = 2233445566
   336  	constNilMagic         = 3344556677
   337  	constEmptyStringMagic = 4455667788
   338  )
   339  
   340  // ConstInt returns an int constant representing its argument.
   341  func (f *Func) ConstBool(line int32, t Type, c bool) *Value {
   342  	i := int64(0)
   343  	if c {
   344  		i = 1
   345  	}
   346  	return f.constVal(line, OpConstBool, t, i, true)
   347  }
   348  func (f *Func) ConstInt8(line int32, t Type, c int8) *Value {
   349  	return f.constVal(line, OpConst8, t, int64(c), true)
   350  }
   351  func (f *Func) ConstInt16(line int32, t Type, c int16) *Value {
   352  	return f.constVal(line, OpConst16, t, int64(c), true)
   353  }
   354  func (f *Func) ConstInt32(line int32, t Type, c int32) *Value {
   355  	return f.constVal(line, OpConst32, t, int64(c), true)
   356  }
   357  func (f *Func) ConstInt64(line int32, t Type, c int64) *Value {
   358  	return f.constVal(line, OpConst64, t, c, true)
   359  }
   360  func (f *Func) ConstFloat32(line int32, t Type, c float64) *Value {
   361  	return f.constVal(line, OpConst32F, t, int64(math.Float64bits(float64(float32(c)))), true)
   362  }
   363  func (f *Func) ConstFloat64(line int32, t Type, c float64) *Value {
   364  	return f.constVal(line, OpConst64F, t, int64(math.Float64bits(c)), true)
   365  }
   366  
   367  func (f *Func) ConstSlice(line int32, t Type) *Value {
   368  	return f.constVal(line, OpConstSlice, t, constSliceMagic, false)
   369  }
   370  func (f *Func) ConstInterface(line int32, t Type) *Value {
   371  	return f.constVal(line, OpConstInterface, t, constInterfaceMagic, false)
   372  }
   373  func (f *Func) ConstNil(line int32, t Type) *Value {
   374  	return f.constVal(line, OpConstNil, t, constNilMagic, false)
   375  }
   376  func (f *Func) ConstEmptyString(line int32, t Type) *Value {
   377  	v := f.constVal(line, OpConstString, t, constEmptyStringMagic, false)
   378  	v.Aux = ""
   379  	return v
   380  }
   381  
   382  func (f *Func) Logf(msg string, args ...interface{})   { f.Config.Logf(msg, args...) }
   383  func (f *Func) Log() bool                              { return f.Config.Log() }
   384  func (f *Func) Fatalf(msg string, args ...interface{}) { f.Config.Fatalf(f.Entry.Line, msg, args...) }
   385  func (f *Func) Unimplementedf(msg string, args ...interface{}) {
   386  	f.Config.Unimplementedf(f.Entry.Line, msg, args...)
   387  }
   388  
   389  func (f *Func) Free() {
   390  	// Clear values.
   391  	n := f.vid.num()
   392  	if n > len(f.Config.values) {
   393  		n = len(f.Config.values)
   394  	}
   395  	for i := 1; i < n; i++ {
   396  		f.Config.values[i] = Value{}
   397  		f.Config.values[i].ID = ID(i)
   398  	}
   399  
   400  	// Clear blocks.
   401  	n = f.bid.num()
   402  	if n > len(f.Config.blocks) {
   403  		n = len(f.Config.blocks)
   404  	}
   405  	for i := 1; i < n; i++ {
   406  		f.Config.blocks[i] = Block{}
   407  		f.Config.blocks[i].ID = ID(i)
   408  	}
   409  
   410  	// Unregister from config.
   411  	if f.Config.curFunc != f {
   412  		f.Fatalf("free of function which isn't the last one allocated")
   413  	}
   414  	f.Config.curFunc = nil
   415  	*f = Func{} // just in case
   416  }