github.com/tidwall/go@v0.0.0-20170415222209-6694a6888b7d/src/cmd/compile/internal/ssa/config.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/internal/obj"
     9  	"cmd/internal/src"
    10  	"os"
    11  	"strconv"
    12  )
    13  
    14  // A Config holds readonly compilation information.
    15  // It is created once, early during compilation,
    16  // and shared across all compilations.
    17  type Config struct {
    18  	arch            string // "amd64", etc.
    19  	IntSize         int64  // 4 or 8
    20  	PtrSize         int64  // 4 or 8
    21  	RegSize         int64  // 4 or 8
    22  	Types           Types
    23  	lowerBlock      blockRewriter // lowering function
    24  	lowerValue      valueRewriter // lowering function
    25  	registers       []Register    // machine registers
    26  	gpRegMask       regMask       // general purpose integer register mask
    27  	fpRegMask       regMask       // floating point register mask
    28  	specialRegMask  regMask       // special register mask
    29  	FPReg           int8          // register number of frame pointer, -1 if not used
    30  	LinkReg         int8          // register number of link register if it is a general purpose register, -1 if not used
    31  	hasGReg         bool          // has hardware g register
    32  	ctxt            *obj.Link     // Generic arch information
    33  	optimize        bool          // Do optimization
    34  	noDuffDevice    bool          // Don't use Duff's device
    35  	nacl            bool          // GOOS=nacl
    36  	use387          bool          // GO386=387
    37  	NeedsFpScratch  bool          // No direct move between GP and FP register sets
    38  	BigEndian       bool          //
    39  	sparsePhiCutoff uint64        // Sparse phi location algorithm used above this #blocks*#variables score
    40  }
    41  
    42  type (
    43  	blockRewriter func(*Block) bool
    44  	valueRewriter func(*Value) bool
    45  )
    46  
    47  type Types struct {
    48  	Bool       Type
    49  	Int8       Type
    50  	Int16      Type
    51  	Int32      Type
    52  	Int64      Type
    53  	UInt8      Type
    54  	UInt16     Type
    55  	UInt32     Type
    56  	UInt64     Type
    57  	Int        Type
    58  	Float32    Type
    59  	Float64    Type
    60  	Uintptr    Type
    61  	String     Type
    62  	BytePtr    Type // TODO: use unsafe.Pointer instead?
    63  	Int32Ptr   Type
    64  	UInt32Ptr  Type
    65  	IntPtr     Type
    66  	UintptrPtr Type
    67  	Float32Ptr Type
    68  	Float64Ptr Type
    69  	BytePtrPtr Type
    70  }
    71  
    72  type Logger interface {
    73  	// Logf logs a message from the compiler.
    74  	Logf(string, ...interface{})
    75  
    76  	// Log returns true if logging is not a no-op
    77  	// some logging calls account for more than a few heap allocations.
    78  	Log() bool
    79  
    80  	// Fatal reports a compiler error and exits.
    81  	Fatalf(pos src.XPos, msg string, args ...interface{})
    82  
    83  	// Warnl writes compiler messages in the form expected by "errorcheck" tests
    84  	Warnl(pos src.XPos, fmt_ string, args ...interface{})
    85  
    86  	// Forwards the Debug flags from gc
    87  	Debug_checknil() bool
    88  	Debug_wb() bool
    89  }
    90  
    91  type Frontend interface {
    92  	CanSSA(t Type) bool
    93  
    94  	Logger
    95  
    96  	// StringData returns a symbol pointing to the given string's contents.
    97  	StringData(string) interface{} // returns *gc.Sym
    98  
    99  	// Auto returns a Node for an auto variable of the given type.
   100  	// The SSA compiler uses this function to allocate space for spills.
   101  	Auto(src.XPos, Type) GCNode
   102  
   103  	// Given the name for a compound type, returns the name we should use
   104  	// for the parts of that compound type.
   105  	SplitString(LocalSlot) (LocalSlot, LocalSlot)
   106  	SplitInterface(LocalSlot) (LocalSlot, LocalSlot)
   107  	SplitSlice(LocalSlot) (LocalSlot, LocalSlot, LocalSlot)
   108  	SplitComplex(LocalSlot) (LocalSlot, LocalSlot)
   109  	SplitStruct(LocalSlot, int) LocalSlot
   110  	SplitArray(LocalSlot) LocalSlot              // array must be length 1
   111  	SplitInt64(LocalSlot) (LocalSlot, LocalSlot) // returns (hi, lo)
   112  
   113  	// DerefItab dereferences an itab function
   114  	// entry, given the symbol of the itab and
   115  	// the byte offset of the function pointer.
   116  	// It may return nil.
   117  	DerefItab(sym *obj.LSym, offset int64) *obj.LSym
   118  
   119  	// Line returns a string describing the given position.
   120  	Line(src.XPos) string
   121  
   122  	// AllocFrame assigns frame offsets to all live auto variables.
   123  	AllocFrame(f *Func)
   124  
   125  	// Syslook returns a symbol of the runtime function/variable with the
   126  	// given name.
   127  	Syslook(string) *obj.LSym
   128  
   129  	// UseWriteBarrier returns whether write barrier is enabled
   130  	UseWriteBarrier() bool
   131  }
   132  
   133  // interface used to hold *gc.Node. We'd use *gc.Node directly but
   134  // that would lead to an import cycle.
   135  type GCNode interface {
   136  	Typ() Type
   137  	String() string
   138  }
   139  
   140  // NewConfig returns a new configuration object for the given architecture.
   141  func NewConfig(arch string, types Types, ctxt *obj.Link, optimize bool) *Config {
   142  	c := &Config{arch: arch, Types: types}
   143  	switch arch {
   144  	case "amd64":
   145  		c.IntSize = 8
   146  		c.PtrSize = 8
   147  		c.RegSize = 8
   148  		c.lowerBlock = rewriteBlockAMD64
   149  		c.lowerValue = rewriteValueAMD64
   150  		c.registers = registersAMD64[:]
   151  		c.gpRegMask = gpRegMaskAMD64
   152  		c.fpRegMask = fpRegMaskAMD64
   153  		c.FPReg = framepointerRegAMD64
   154  		c.LinkReg = linkRegAMD64
   155  		c.hasGReg = false
   156  	case "amd64p32":
   157  		c.IntSize = 4
   158  		c.PtrSize = 4
   159  		c.RegSize = 8
   160  		c.lowerBlock = rewriteBlockAMD64
   161  		c.lowerValue = rewriteValueAMD64
   162  		c.registers = registersAMD64[:]
   163  		c.gpRegMask = gpRegMaskAMD64
   164  		c.fpRegMask = fpRegMaskAMD64
   165  		c.FPReg = framepointerRegAMD64
   166  		c.LinkReg = linkRegAMD64
   167  		c.hasGReg = false
   168  		c.noDuffDevice = true
   169  	case "386":
   170  		c.IntSize = 4
   171  		c.PtrSize = 4
   172  		c.RegSize = 4
   173  		c.lowerBlock = rewriteBlock386
   174  		c.lowerValue = rewriteValue386
   175  		c.registers = registers386[:]
   176  		c.gpRegMask = gpRegMask386
   177  		c.fpRegMask = fpRegMask386
   178  		c.FPReg = framepointerReg386
   179  		c.LinkReg = linkReg386
   180  		c.hasGReg = false
   181  	case "arm":
   182  		c.IntSize = 4
   183  		c.PtrSize = 4
   184  		c.RegSize = 4
   185  		c.lowerBlock = rewriteBlockARM
   186  		c.lowerValue = rewriteValueARM
   187  		c.registers = registersARM[:]
   188  		c.gpRegMask = gpRegMaskARM
   189  		c.fpRegMask = fpRegMaskARM
   190  		c.FPReg = framepointerRegARM
   191  		c.LinkReg = linkRegARM
   192  		c.hasGReg = true
   193  	case "arm64":
   194  		c.IntSize = 8
   195  		c.PtrSize = 8
   196  		c.RegSize = 8
   197  		c.lowerBlock = rewriteBlockARM64
   198  		c.lowerValue = rewriteValueARM64
   199  		c.registers = registersARM64[:]
   200  		c.gpRegMask = gpRegMaskARM64
   201  		c.fpRegMask = fpRegMaskARM64
   202  		c.FPReg = framepointerRegARM64
   203  		c.LinkReg = linkRegARM64
   204  		c.hasGReg = true
   205  		c.noDuffDevice = obj.GOOS == "darwin" // darwin linker cannot handle BR26 reloc with non-zero addend
   206  	case "ppc64":
   207  		c.BigEndian = true
   208  		fallthrough
   209  	case "ppc64le":
   210  		c.IntSize = 8
   211  		c.PtrSize = 8
   212  		c.RegSize = 8
   213  		c.lowerBlock = rewriteBlockPPC64
   214  		c.lowerValue = rewriteValuePPC64
   215  		c.registers = registersPPC64[:]
   216  		c.gpRegMask = gpRegMaskPPC64
   217  		c.fpRegMask = fpRegMaskPPC64
   218  		c.FPReg = framepointerRegPPC64
   219  		c.LinkReg = linkRegPPC64
   220  		c.noDuffDevice = true // TODO: Resolve PPC64 DuffDevice (has zero, but not copy)
   221  		c.hasGReg = true
   222  	case "mips64":
   223  		c.BigEndian = true
   224  		fallthrough
   225  	case "mips64le":
   226  		c.IntSize = 8
   227  		c.PtrSize = 8
   228  		c.RegSize = 8
   229  		c.lowerBlock = rewriteBlockMIPS64
   230  		c.lowerValue = rewriteValueMIPS64
   231  		c.registers = registersMIPS64[:]
   232  		c.gpRegMask = gpRegMaskMIPS64
   233  		c.fpRegMask = fpRegMaskMIPS64
   234  		c.specialRegMask = specialRegMaskMIPS64
   235  		c.FPReg = framepointerRegMIPS64
   236  		c.LinkReg = linkRegMIPS64
   237  		c.hasGReg = true
   238  	case "s390x":
   239  		c.IntSize = 8
   240  		c.PtrSize = 8
   241  		c.RegSize = 8
   242  		c.lowerBlock = rewriteBlockS390X
   243  		c.lowerValue = rewriteValueS390X
   244  		c.registers = registersS390X[:]
   245  		c.gpRegMask = gpRegMaskS390X
   246  		c.fpRegMask = fpRegMaskS390X
   247  		c.FPReg = framepointerRegS390X
   248  		c.LinkReg = linkRegS390X
   249  		c.hasGReg = true
   250  		c.noDuffDevice = true
   251  		c.BigEndian = true
   252  	case "mips":
   253  		c.BigEndian = true
   254  		fallthrough
   255  	case "mipsle":
   256  		c.IntSize = 4
   257  		c.PtrSize = 4
   258  		c.RegSize = 4
   259  		c.lowerBlock = rewriteBlockMIPS
   260  		c.lowerValue = rewriteValueMIPS
   261  		c.registers = registersMIPS[:]
   262  		c.gpRegMask = gpRegMaskMIPS
   263  		c.fpRegMask = fpRegMaskMIPS
   264  		c.specialRegMask = specialRegMaskMIPS
   265  		c.FPReg = framepointerRegMIPS
   266  		c.LinkReg = linkRegMIPS
   267  		c.hasGReg = true
   268  		c.noDuffDevice = true
   269  	default:
   270  		ctxt.Diag("arch %s not implemented", arch)
   271  	}
   272  	c.ctxt = ctxt
   273  	c.optimize = optimize
   274  	c.nacl = obj.GOOS == "nacl"
   275  
   276  	// Don't use Duff's device on Plan 9 AMD64, because floating
   277  	// point operations are not allowed in note handler.
   278  	if obj.GOOS == "plan9" && arch == "amd64" {
   279  		c.noDuffDevice = true
   280  	}
   281  
   282  	if c.nacl {
   283  		c.noDuffDevice = true // Don't use Duff's device on NaCl
   284  
   285  		// runtime call clobber R12 on nacl
   286  		opcodeTable[OpARMCALLudiv].reg.clobbers |= 1 << 12 // R12
   287  	}
   288  
   289  	// cutoff is compared with product of numblocks and numvalues,
   290  	// if product is smaller than cutoff, use old non-sparse method.
   291  	// cutoff == 0 implies all sparse.
   292  	// cutoff == -1 implies none sparse.
   293  	// Good cutoff values seem to be O(million) depending on constant factor cost of sparse.
   294  	// TODO: get this from a flag, not an environment variable
   295  	c.sparsePhiCutoff = 2500000 // 0 for testing. // 2500000 determined with crude experiments w/ make.bash
   296  	ev := os.Getenv("GO_SSA_PHI_LOC_CUTOFF")
   297  	if ev != "" {
   298  		v, err := strconv.ParseInt(ev, 10, 64)
   299  		if err != nil {
   300  			ctxt.Diag("Environment variable GO_SSA_PHI_LOC_CUTOFF (value '%s') did not parse as a number", ev)
   301  		}
   302  		c.sparsePhiCutoff = uint64(v) // convert -1 to maxint, for never use sparse
   303  	}
   304  
   305  	return c
   306  }
   307  
   308  func (c *Config) Set387(b bool) {
   309  	c.NeedsFpScratch = b
   310  	c.use387 = b
   311  }
   312  
   313  func (c *Config) SparsePhiCutoff() uint64 { return c.sparsePhiCutoff }
   314  func (c *Config) Ctxt() *obj.Link         { return c.ctxt }