...
Run Format

Source file src/cmd/compile/internal/ssa/config.go

Documentation: cmd/compile/internal/ssa

     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  )
    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  	PtrSize        int64  // 4 or 8; copy of cmd/internal/sys.Arch.PtrSize
    20  	RegSize        int64  // 4 or 8; copy of cmd/internal/sys.Arch.RegSize
    21  	Types          Types
    22  	lowerBlock     blockRewriter // lowering function
    23  	lowerValue     valueRewriter // lowering function
    24  	registers      []Register    // machine registers
    25  	gpRegMask      regMask       // general purpose integer register mask
    26  	fpRegMask      regMask       // floating point register mask
    27  	specialRegMask regMask       // special register mask
    28  	GCRegMap       []*Register   // garbage collector register map, by GC register index
    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  	useSSE         bool          // Use SSE for non-float operations
    36  	useAvg         bool          // Use optimizations that need Avg* operations
    37  	useHmul        bool          // Use optimizations that need Hmul* operations
    38  	nacl           bool          // GOOS=nacl
    39  	use387         bool          // GO386=387
    40  	SoftFloat      bool          //
    41  	Race           bool          // race detector enabled
    42  	NeedsFpScratch bool          // No direct move between GP and FP register sets
    43  	BigEndian      bool          //
    44  }
    45  
    46  type (
    47  	blockRewriter func(*Block) bool
    48  	valueRewriter func(*Value) bool
    49  )
    50  
    51  type Types struct {
    52  	Bool       *types.Type
    53  	Int8       *types.Type
    54  	Int16      *types.Type
    55  	Int32      *types.Type
    56  	Int64      *types.Type
    57  	UInt8      *types.Type
    58  	UInt16     *types.Type
    59  	UInt32     *types.Type
    60  	UInt64     *types.Type
    61  	Int        *types.Type
    62  	Float32    *types.Type
    63  	Float64    *types.Type
    64  	UInt       *types.Type
    65  	Uintptr    *types.Type
    66  	String     *types.Type
    67  	BytePtr    *types.Type // TODO: use unsafe.Pointer instead?
    68  	Int32Ptr   *types.Type
    69  	UInt32Ptr  *types.Type
    70  	IntPtr     *types.Type
    71  	UintptrPtr *types.Type
    72  	Float32Ptr *types.Type
    73  	Float64Ptr *types.Type
    74  	BytePtrPtr *types.Type
    75  }
    76  
    77  // NewTypes creates and populates a Types.
    78  func NewTypes() *Types {
    79  	t := new(Types)
    80  	t.SetTypPtrs()
    81  	return t
    82  }
    83  
    84  // SetTypPtrs populates t.
    85  func (t *Types) SetTypPtrs() {
    86  	t.Bool = types.Types[types.TBOOL]
    87  	t.Int8 = types.Types[types.TINT8]
    88  	t.Int16 = types.Types[types.TINT16]
    89  	t.Int32 = types.Types[types.TINT32]
    90  	t.Int64 = types.Types[types.TINT64]
    91  	t.UInt8 = types.Types[types.TUINT8]
    92  	t.UInt16 = types.Types[types.TUINT16]
    93  	t.UInt32 = types.Types[types.TUINT32]
    94  	t.UInt64 = types.Types[types.TUINT64]
    95  	t.Int = types.Types[types.TINT]
    96  	t.Float32 = types.Types[types.TFLOAT32]
    97  	t.Float64 = types.Types[types.TFLOAT64]
    98  	t.UInt = types.Types[types.TUINT]
    99  	t.Uintptr = types.Types[types.TUINTPTR]
   100  	t.String = types.Types[types.TSTRING]
   101  	t.BytePtr = types.NewPtr(types.Types[types.TUINT8])
   102  	t.Int32Ptr = types.NewPtr(types.Types[types.TINT32])
   103  	t.UInt32Ptr = types.NewPtr(types.Types[types.TUINT32])
   104  	t.IntPtr = types.NewPtr(types.Types[types.TINT])
   105  	t.UintptrPtr = types.NewPtr(types.Types[types.TUINTPTR])
   106  	t.Float32Ptr = types.NewPtr(types.Types[types.TFLOAT32])
   107  	t.Float64Ptr = types.NewPtr(types.Types[types.TFLOAT64])
   108  	t.BytePtrPtr = types.NewPtr(types.NewPtr(types.Types[types.TUINT8]))
   109  }
   110  
   111  type Logger interface {
   112  	// Logf logs a message from the compiler.
   113  	Logf(string, ...interface{})
   114  
   115  	// Log reports whether logging is not a no-op
   116  	// some logging calls account for more than a few heap allocations.
   117  	Log() bool
   118  
   119  	// Fatal reports a compiler error and exits.
   120  	Fatalf(pos src.XPos, msg string, args ...interface{})
   121  
   122  	// Warnl writes compiler messages in the form expected by "errorcheck" tests
   123  	Warnl(pos src.XPos, fmt_ string, args ...interface{})
   124  
   125  	// Forwards the Debug flags from gc
   126  	Debug_checknil() bool
   127  }
   128  
   129  type Frontend interface {
   130  	CanSSA(t *types.Type) bool
   131  
   132  	Logger
   133  
   134  	// StringData returns a symbol pointing to the given string's contents.
   135  	StringData(string) interface{} // returns *gc.Sym
   136  
   137  	// Auto returns a Node for an auto variable of the given type.
   138  	// The SSA compiler uses this function to allocate space for spills.
   139  	Auto(src.XPos, *types.Type) GCNode
   140  
   141  	// Given the name for a compound type, returns the name we should use
   142  	// for the parts of that compound type.
   143  	SplitString(LocalSlot) (LocalSlot, LocalSlot)
   144  	SplitInterface(LocalSlot) (LocalSlot, LocalSlot)
   145  	SplitSlice(LocalSlot) (LocalSlot, LocalSlot, LocalSlot)
   146  	SplitComplex(LocalSlot) (LocalSlot, LocalSlot)
   147  	SplitStruct(LocalSlot, int) LocalSlot
   148  	SplitArray(LocalSlot) LocalSlot              // array must be length 1
   149  	SplitInt64(LocalSlot) (LocalSlot, LocalSlot) // returns (hi, lo)
   150  
   151  	// DerefItab dereferences an itab function
   152  	// entry, given the symbol of the itab and
   153  	// the byte offset of the function pointer.
   154  	// It may return nil.
   155  	DerefItab(sym *obj.LSym, offset int64) *obj.LSym
   156  
   157  	// Line returns a string describing the given position.
   158  	Line(src.XPos) string
   159  
   160  	// AllocFrame assigns frame offsets to all live auto variables.
   161  	AllocFrame(f *Func)
   162  
   163  	// Syslook returns a symbol of the runtime function/variable with the
   164  	// given name.
   165  	Syslook(string) *obj.LSym
   166  
   167  	// UseWriteBarrier reports whether write barrier is enabled
   168  	UseWriteBarrier() bool
   169  
   170  	// SetWBPos indicates that a write barrier has been inserted
   171  	// in this function at position pos.
   172  	SetWBPos(pos src.XPos)
   173  }
   174  
   175  // interface used to hold a *gc.Node (a stack variable).
   176  // We'd use *gc.Node directly but that would lead to an import cycle.
   177  type GCNode interface {
   178  	Typ() *types.Type
   179  	String() string
   180  	IsSynthetic() bool
   181  	IsAutoTmp() bool
   182  	StorageClass() StorageClass
   183  }
   184  
   185  type StorageClass uint8
   186  
   187  const (
   188  	ClassAuto     StorageClass = iota // local stack variable
   189  	ClassParam                        // argument
   190  	ClassParamOut                     // return value
   191  )
   192  
   193  // NewConfig returns a new configuration object for the given architecture.
   194  func NewConfig(arch string, types Types, ctxt *obj.Link, optimize bool) *Config {
   195  	c := &Config{arch: arch, Types: types}
   196  	c.useAvg = true
   197  	c.useHmul = true
   198  	switch arch {
   199  	case "amd64":
   200  		c.PtrSize = 8
   201  		c.RegSize = 8
   202  		c.lowerBlock = rewriteBlockAMD64
   203  		c.lowerValue = rewriteValueAMD64
   204  		c.registers = registersAMD64[:]
   205  		c.gpRegMask = gpRegMaskAMD64
   206  		c.fpRegMask = fpRegMaskAMD64
   207  		c.FPReg = framepointerRegAMD64
   208  		c.LinkReg = linkRegAMD64
   209  		c.hasGReg = false
   210  	case "amd64p32":
   211  		c.PtrSize = 4
   212  		c.RegSize = 8
   213  		c.lowerBlock = rewriteBlockAMD64
   214  		c.lowerValue = rewriteValueAMD64
   215  		c.registers = registersAMD64[:]
   216  		c.gpRegMask = gpRegMaskAMD64
   217  		c.fpRegMask = fpRegMaskAMD64
   218  		c.FPReg = framepointerRegAMD64
   219  		c.LinkReg = linkRegAMD64
   220  		c.hasGReg = false
   221  		c.noDuffDevice = true
   222  	case "386":
   223  		c.PtrSize = 4
   224  		c.RegSize = 4
   225  		c.lowerBlock = rewriteBlock386
   226  		c.lowerValue = rewriteValue386
   227  		c.registers = registers386[:]
   228  		c.gpRegMask = gpRegMask386
   229  		c.fpRegMask = fpRegMask386
   230  		c.FPReg = framepointerReg386
   231  		c.LinkReg = linkReg386
   232  		c.hasGReg = false
   233  	case "arm":
   234  		c.PtrSize = 4
   235  		c.RegSize = 4
   236  		c.lowerBlock = rewriteBlockARM
   237  		c.lowerValue = rewriteValueARM
   238  		c.registers = registersARM[:]
   239  		c.gpRegMask = gpRegMaskARM
   240  		c.fpRegMask = fpRegMaskARM
   241  		c.FPReg = framepointerRegARM
   242  		c.LinkReg = linkRegARM
   243  		c.hasGReg = true
   244  	case "arm64":
   245  		c.PtrSize = 8
   246  		c.RegSize = 8
   247  		c.lowerBlock = rewriteBlockARM64
   248  		c.lowerValue = rewriteValueARM64
   249  		c.registers = registersARM64[:]
   250  		c.gpRegMask = gpRegMaskARM64
   251  		c.fpRegMask = fpRegMaskARM64
   252  		c.FPReg = framepointerRegARM64
   253  		c.LinkReg = linkRegARM64
   254  		c.hasGReg = true
   255  		c.noDuffDevice = objabi.GOOS == "darwin" // darwin linker cannot handle BR26 reloc with non-zero addend
   256  	case "ppc64":
   257  		c.BigEndian = true
   258  		fallthrough
   259  	case "ppc64le":
   260  		c.PtrSize = 8
   261  		c.RegSize = 8
   262  		c.lowerBlock = rewriteBlockPPC64
   263  		c.lowerValue = rewriteValuePPC64
   264  		c.registers = registersPPC64[:]
   265  		c.gpRegMask = gpRegMaskPPC64
   266  		c.fpRegMask = fpRegMaskPPC64
   267  		c.FPReg = framepointerRegPPC64
   268  		c.LinkReg = linkRegPPC64
   269  		c.noDuffDevice = true // TODO: Resolve PPC64 DuffDevice (has zero, but not copy)
   270  		c.hasGReg = true
   271  	case "mips64":
   272  		c.BigEndian = true
   273  		fallthrough
   274  	case "mips64le":
   275  		c.PtrSize = 8
   276  		c.RegSize = 8
   277  		c.lowerBlock = rewriteBlockMIPS64
   278  		c.lowerValue = rewriteValueMIPS64
   279  		c.registers = registersMIPS64[:]
   280  		c.gpRegMask = gpRegMaskMIPS64
   281  		c.fpRegMask = fpRegMaskMIPS64
   282  		c.specialRegMask = specialRegMaskMIPS64
   283  		c.FPReg = framepointerRegMIPS64
   284  		c.LinkReg = linkRegMIPS64
   285  		c.hasGReg = true
   286  	case "s390x":
   287  		c.PtrSize = 8
   288  		c.RegSize = 8
   289  		c.lowerBlock = rewriteBlockS390X
   290  		c.lowerValue = rewriteValueS390X
   291  		c.registers = registersS390X[:]
   292  		c.gpRegMask = gpRegMaskS390X
   293  		c.fpRegMask = fpRegMaskS390X
   294  		c.FPReg = framepointerRegS390X
   295  		c.LinkReg = linkRegS390X
   296  		c.hasGReg = true
   297  		c.noDuffDevice = true
   298  		c.BigEndian = true
   299  	case "mips":
   300  		c.BigEndian = true
   301  		fallthrough
   302  	case "mipsle":
   303  		c.PtrSize = 4
   304  		c.RegSize = 4
   305  		c.lowerBlock = rewriteBlockMIPS
   306  		c.lowerValue = rewriteValueMIPS
   307  		c.registers = registersMIPS[:]
   308  		c.gpRegMask = gpRegMaskMIPS
   309  		c.fpRegMask = fpRegMaskMIPS
   310  		c.specialRegMask = specialRegMaskMIPS
   311  		c.FPReg = framepointerRegMIPS
   312  		c.LinkReg = linkRegMIPS
   313  		c.hasGReg = true
   314  		c.noDuffDevice = true
   315  	case "wasm":
   316  		c.PtrSize = 8
   317  		c.RegSize = 8
   318  		c.lowerBlock = rewriteBlockWasm
   319  		c.lowerValue = rewriteValueWasm
   320  		c.registers = registersWasm[:]
   321  		c.gpRegMask = gpRegMaskWasm
   322  		c.fpRegMask = fpRegMaskWasm
   323  		c.FPReg = framepointerRegWasm
   324  		c.LinkReg = linkRegWasm
   325  		c.hasGReg = true
   326  		c.noDuffDevice = true
   327  		c.useAvg = false
   328  		c.useHmul = false
   329  	default:
   330  		ctxt.Diag("arch %s not implemented", arch)
   331  	}
   332  	c.ctxt = ctxt
   333  	c.optimize = optimize
   334  	c.nacl = objabi.GOOS == "nacl"
   335  	c.useSSE = true
   336  
   337  	// Don't use Duff's device nor SSE on Plan 9 AMD64, because
   338  	// floating point operations are not allowed in note handler.
   339  	if objabi.GOOS == "plan9" && arch == "amd64" {
   340  		c.noDuffDevice = true
   341  		c.useSSE = false
   342  	}
   343  
   344  	if c.nacl {
   345  		c.noDuffDevice = true // Don't use Duff's device on NaCl
   346  
   347  		// Returns clobber BP on nacl/386, so the write
   348  		// barrier does.
   349  		opcodeTable[Op386LoweredWB].reg.clobbers |= 1 << 5 // BP
   350  
   351  		// ... and SI on nacl/amd64.
   352  		opcodeTable[OpAMD64LoweredWB].reg.clobbers |= 1 << 6 // SI
   353  	}
   354  
   355  	if ctxt.Flag_shared {
   356  		// LoweredWB is secretly a CALL and CALLs on 386 in
   357  		// shared mode get rewritten by obj6.go to go through
   358  		// the GOT, which clobbers BX.
   359  		opcodeTable[Op386LoweredWB].reg.clobbers |= 1 << 3 // BX
   360  	}
   361  
   362  	// Create the GC register map index.
   363  	// TODO: This is only used for debug printing. Maybe export config.registers?
   364  	gcRegMapSize := int16(0)
   365  	for _, r := range c.registers {
   366  		if r.gcNum+1 > gcRegMapSize {
   367  			gcRegMapSize = r.gcNum + 1
   368  		}
   369  	}
   370  	c.GCRegMap = make([]*Register, gcRegMapSize)
   371  	for i, r := range c.registers {
   372  		if r.gcNum != -1 {
   373  			c.GCRegMap[r.gcNum] = &c.registers[i]
   374  		}
   375  	}
   376  
   377  	return c
   378  }
   379  
   380  func (c *Config) Set387(b bool) {
   381  	c.NeedsFpScratch = b
   382  	c.use387 = b
   383  }
   384  
   385  func (c *Config) Ctxt() *obj.Link { return c.ctxt }
   386  

View as plain text