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