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