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

View as plain text