github.com/slayercat/go@v0.0.0-20170428012452-c51559813f61/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/objabi"
    10  	"cmd/internal/src"
    11  	"os"
    12  	"strconv"
    13  )
    14  
    15  // A Config holds readonly compilation information.
    16  // It is created once, early during compilation,
    17  // and shared across all compilations.
    18  type Config struct {
    19  	arch            string // "amd64", etc.
    20  	PtrSize         int64  // 4 or 8; copy of cmd/internal/sys.Arch.PtrSize
    21  	RegSize         int64  // 4 or 8; copy of cmd/internal/sys.Arch.RegSize
    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.PtrSize = 8
   146  		c.RegSize = 8
   147  		c.lowerBlock = rewriteBlockAMD64
   148  		c.lowerValue = rewriteValueAMD64
   149  		c.registers = registersAMD64[:]
   150  		c.gpRegMask = gpRegMaskAMD64
   151  		c.fpRegMask = fpRegMaskAMD64
   152  		c.FPReg = framepointerRegAMD64
   153  		c.LinkReg = linkRegAMD64
   154  		c.hasGReg = false
   155  	case "amd64p32":
   156  		c.PtrSize = 4
   157  		c.RegSize = 8
   158  		c.lowerBlock = rewriteBlockAMD64
   159  		c.lowerValue = rewriteValueAMD64
   160  		c.registers = registersAMD64[:]
   161  		c.gpRegMask = gpRegMaskAMD64
   162  		c.fpRegMask = fpRegMaskAMD64
   163  		c.FPReg = framepointerRegAMD64
   164  		c.LinkReg = linkRegAMD64
   165  		c.hasGReg = false
   166  		c.noDuffDevice = true
   167  	case "386":
   168  		c.PtrSize = 4
   169  		c.RegSize = 4
   170  		c.lowerBlock = rewriteBlock386
   171  		c.lowerValue = rewriteValue386
   172  		c.registers = registers386[:]
   173  		c.gpRegMask = gpRegMask386
   174  		c.fpRegMask = fpRegMask386
   175  		c.FPReg = framepointerReg386
   176  		c.LinkReg = linkReg386
   177  		c.hasGReg = false
   178  	case "arm":
   179  		c.PtrSize = 4
   180  		c.RegSize = 4
   181  		c.lowerBlock = rewriteBlockARM
   182  		c.lowerValue = rewriteValueARM
   183  		c.registers = registersARM[:]
   184  		c.gpRegMask = gpRegMaskARM
   185  		c.fpRegMask = fpRegMaskARM
   186  		c.FPReg = framepointerRegARM
   187  		c.LinkReg = linkRegARM
   188  		c.hasGReg = true
   189  	case "arm64":
   190  		c.PtrSize = 8
   191  		c.RegSize = 8
   192  		c.lowerBlock = rewriteBlockARM64
   193  		c.lowerValue = rewriteValueARM64
   194  		c.registers = registersARM64[:]
   195  		c.gpRegMask = gpRegMaskARM64
   196  		c.fpRegMask = fpRegMaskARM64
   197  		c.FPReg = framepointerRegARM64
   198  		c.LinkReg = linkRegARM64
   199  		c.hasGReg = true
   200  		c.noDuffDevice = objabi.GOOS == "darwin" // darwin linker cannot handle BR26 reloc with non-zero addend
   201  	case "ppc64":
   202  		c.BigEndian = true
   203  		fallthrough
   204  	case "ppc64le":
   205  		c.PtrSize = 8
   206  		c.RegSize = 8
   207  		c.lowerBlock = rewriteBlockPPC64
   208  		c.lowerValue = rewriteValuePPC64
   209  		c.registers = registersPPC64[:]
   210  		c.gpRegMask = gpRegMaskPPC64
   211  		c.fpRegMask = fpRegMaskPPC64
   212  		c.FPReg = framepointerRegPPC64
   213  		c.LinkReg = linkRegPPC64
   214  		c.noDuffDevice = true // TODO: Resolve PPC64 DuffDevice (has zero, but not copy)
   215  		c.hasGReg = true
   216  	case "mips64":
   217  		c.BigEndian = true
   218  		fallthrough
   219  	case "mips64le":
   220  		c.PtrSize = 8
   221  		c.RegSize = 8
   222  		c.lowerBlock = rewriteBlockMIPS64
   223  		c.lowerValue = rewriteValueMIPS64
   224  		c.registers = registersMIPS64[:]
   225  		c.gpRegMask = gpRegMaskMIPS64
   226  		c.fpRegMask = fpRegMaskMIPS64
   227  		c.specialRegMask = specialRegMaskMIPS64
   228  		c.FPReg = framepointerRegMIPS64
   229  		c.LinkReg = linkRegMIPS64
   230  		c.hasGReg = true
   231  	case "s390x":
   232  		c.PtrSize = 8
   233  		c.RegSize = 8
   234  		c.lowerBlock = rewriteBlockS390X
   235  		c.lowerValue = rewriteValueS390X
   236  		c.registers = registersS390X[:]
   237  		c.gpRegMask = gpRegMaskS390X
   238  		c.fpRegMask = fpRegMaskS390X
   239  		c.FPReg = framepointerRegS390X
   240  		c.LinkReg = linkRegS390X
   241  		c.hasGReg = true
   242  		c.noDuffDevice = true
   243  		c.BigEndian = true
   244  	case "mips":
   245  		c.BigEndian = true
   246  		fallthrough
   247  	case "mipsle":
   248  		c.PtrSize = 4
   249  		c.RegSize = 4
   250  		c.lowerBlock = rewriteBlockMIPS
   251  		c.lowerValue = rewriteValueMIPS
   252  		c.registers = registersMIPS[:]
   253  		c.gpRegMask = gpRegMaskMIPS
   254  		c.fpRegMask = fpRegMaskMIPS
   255  		c.specialRegMask = specialRegMaskMIPS
   256  		c.FPReg = framepointerRegMIPS
   257  		c.LinkReg = linkRegMIPS
   258  		c.hasGReg = true
   259  		c.noDuffDevice = true
   260  	default:
   261  		ctxt.Diag("arch %s not implemented", arch)
   262  	}
   263  	c.ctxt = ctxt
   264  	c.optimize = optimize
   265  	c.nacl = objabi.GOOS == "nacl"
   266  
   267  	// Don't use Duff's device on Plan 9 AMD64, because floating
   268  	// point operations are not allowed in note handler.
   269  	if objabi.GOOS == "plan9" && arch == "amd64" {
   270  		c.noDuffDevice = true
   271  	}
   272  
   273  	if c.nacl {
   274  		c.noDuffDevice = true // Don't use Duff's device on NaCl
   275  
   276  		// runtime call clobber R12 on nacl
   277  		opcodeTable[OpARMCALLudiv].reg.clobbers |= 1 << 12 // R12
   278  	}
   279  
   280  	// cutoff is compared with product of numblocks and numvalues,
   281  	// if product is smaller than cutoff, use old non-sparse method.
   282  	// cutoff == 0 implies all sparse.
   283  	// cutoff == -1 implies none sparse.
   284  	// Good cutoff values seem to be O(million) depending on constant factor cost of sparse.
   285  	// TODO: get this from a flag, not an environment variable
   286  	c.sparsePhiCutoff = 2500000 // 0 for testing. // 2500000 determined with crude experiments w/ make.bash
   287  	ev := os.Getenv("GO_SSA_PHI_LOC_CUTOFF")
   288  	if ev != "" {
   289  		v, err := strconv.ParseInt(ev, 10, 64)
   290  		if err != nil {
   291  			ctxt.Diag("Environment variable GO_SSA_PHI_LOC_CUTOFF (value '%s') did not parse as a number", ev)
   292  		}
   293  		c.sparsePhiCutoff = uint64(v) // convert -1 to maxint, for never use sparse
   294  	}
   295  
   296  	return c
   297  }
   298  
   299  func (c *Config) Set387(b bool) {
   300  	c.NeedsFpScratch = b
   301  	c.use387 = b
   302  }
   303  
   304  func (c *Config) SparsePhiCutoff() uint64 { return c.sparsePhiCutoff }
   305  func (c *Config) Ctxt() *obj.Link         { return c.ctxt }