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