Black Lives Matter. Support the Equal Justice Initiative.

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  	fp32RegMask    regMask       // floating point register mask
    29  	fp64RegMask    regMask       // floating point register mask
    30  	specialRegMask regMask       // special register mask
    31  	GCRegMap       []*Register   // garbage collector register map, by GC register index
    32  	FPReg          int8          // register number of frame pointer, -1 if not used
    33  	LinkReg        int8          // register number of link register if it is a general purpose register, -1 if not used
    34  	hasGReg        bool          // has hardware g register
    35  	ctxt           *obj.Link     // Generic arch information
    36  	optimize       bool          // Do optimization
    37  	noDuffDevice   bool          // Don't use Duff's device
    38  	useSSE         bool          // Use SSE for non-float operations
    39  	useAvg         bool          // Use optimizations that need Avg* operations
    40  	useHmul        bool          // Use optimizations that need Hmul* operations
    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  	UseFMA         bool          // Use hardware FMA operation
    46  }
    47  
    48  type (
    49  	blockRewriter func(*Block) bool
    50  	valueRewriter func(*Value) bool
    51  )
    52  
    53  type Types struct {
    54  	Bool       *types.Type
    55  	Int8       *types.Type
    56  	Int16      *types.Type
    57  	Int32      *types.Type
    58  	Int64      *types.Type
    59  	UInt8      *types.Type
    60  	UInt16     *types.Type
    61  	UInt32     *types.Type
    62  	UInt64     *types.Type
    63  	Int        *types.Type
    64  	Float32    *types.Type
    65  	Float64    *types.Type
    66  	UInt       *types.Type
    67  	Uintptr    *types.Type
    68  	String     *types.Type
    69  	BytePtr    *types.Type // TODO: use unsafe.Pointer instead?
    70  	Int32Ptr   *types.Type
    71  	UInt32Ptr  *types.Type
    72  	IntPtr     *types.Type
    73  	UintptrPtr *types.Type
    74  	Float32Ptr *types.Type
    75  	Float64Ptr *types.Type
    76  	BytePtrPtr *types.Type
    77  }
    78  
    79  // NewTypes creates and populates a Types.
    80  func NewTypes() *Types {
    81  	t := new(Types)
    82  	t.SetTypPtrs()
    83  	return t
    84  }
    85  
    86  // SetTypPtrs populates t.
    87  func (t *Types) SetTypPtrs() {
    88  	t.Bool = types.Types[types.TBOOL]
    89  	t.Int8 = types.Types[types.TINT8]
    90  	t.Int16 = types.Types[types.TINT16]
    91  	t.Int32 = types.Types[types.TINT32]
    92  	t.Int64 = types.Types[types.TINT64]
    93  	t.UInt8 = types.Types[types.TUINT8]
    94  	t.UInt16 = types.Types[types.TUINT16]
    95  	t.UInt32 = types.Types[types.TUINT32]
    96  	t.UInt64 = types.Types[types.TUINT64]
    97  	t.Int = types.Types[types.TINT]
    98  	t.Float32 = types.Types[types.TFLOAT32]
    99  	t.Float64 = types.Types[types.TFLOAT64]
   100  	t.UInt = types.Types[types.TUINT]
   101  	t.Uintptr = types.Types[types.TUINTPTR]
   102  	t.String = types.Types[types.TSTRING]
   103  	t.BytePtr = types.NewPtr(types.Types[types.TUINT8])
   104  	t.Int32Ptr = types.NewPtr(types.Types[types.TINT32])
   105  	t.UInt32Ptr = types.NewPtr(types.Types[types.TUINT32])
   106  	t.IntPtr = types.NewPtr(types.Types[types.TINT])
   107  	t.UintptrPtr = types.NewPtr(types.Types[types.TUINTPTR])
   108  	t.Float32Ptr = types.NewPtr(types.Types[types.TFLOAT32])
   109  	t.Float64Ptr = types.NewPtr(types.Types[types.TFLOAT64])
   110  	t.BytePtrPtr = types.NewPtr(types.NewPtr(types.Types[types.TUINT8]))
   111  }
   112  
   113  type Logger interface {
   114  	// Logf logs a message from the compiler.
   115  	Logf(string, ...interface{})
   116  
   117  	// Log reports whether logging is not a no-op
   118  	// some logging calls account for more than a few heap allocations.
   119  	Log() bool
   120  
   121  	// Fatal reports a compiler error and exits.
   122  	Fatalf(pos src.XPos, msg string, args ...interface{})
   123  
   124  	// Warnl writes compiler messages in the form expected by "errorcheck" tests
   125  	Warnl(pos src.XPos, fmt_ string, args ...interface{})
   126  
   127  	// Forwards the Debug flags from gc
   128  	Debug_checknil() bool
   129  }
   130  
   131  type Frontend interface {
   132  	CanSSA(t *types.Type) bool
   133  
   134  	Logger
   135  
   136  	// StringData returns a symbol pointing to the given string's contents.
   137  	StringData(string) *obj.LSym
   138  
   139  	// Auto returns a Node for an auto variable of the given type.
   140  	// The SSA compiler uses this function to allocate space for spills.
   141  	Auto(src.XPos, *types.Type) GCNode
   142  
   143  	// Given the name for a compound type, returns the name we should use
   144  	// for the parts of that compound type.
   145  	SplitString(LocalSlot) (LocalSlot, LocalSlot)
   146  	SplitInterface(LocalSlot) (LocalSlot, LocalSlot)
   147  	SplitSlice(LocalSlot) (LocalSlot, LocalSlot, LocalSlot)
   148  	SplitComplex(LocalSlot) (LocalSlot, LocalSlot)
   149  	SplitStruct(LocalSlot, int) LocalSlot
   150  	SplitArray(LocalSlot) LocalSlot              // array must be length 1
   151  	SplitInt64(LocalSlot) (LocalSlot, LocalSlot) // returns (hi, lo)
   152  	SplitSlot(parent *LocalSlot, suffix string, offset int64, t *types.Type) LocalSlot
   153  
   154  	// DerefItab dereferences an itab function
   155  	// entry, given the symbol of the itab and
   156  	// the byte offset of the function pointer.
   157  	// It may return nil.
   158  	DerefItab(sym *obj.LSym, offset int64) *obj.LSym
   159  
   160  	// Line returns a string describing the given position.
   161  	Line(src.XPos) string
   162  
   163  	// AllocFrame assigns frame offsets to all live auto variables.
   164  	AllocFrame(f *Func)
   165  
   166  	// Syslook returns a symbol of the runtime function/variable with the
   167  	// given name.
   168  	Syslook(string) *obj.LSym
   169  
   170  	// UseWriteBarrier reports whether write barrier is enabled
   171  	UseWriteBarrier() bool
   172  
   173  	// SetWBPos indicates that a write barrier has been inserted
   174  	// in this function at position pos.
   175  	SetWBPos(pos src.XPos)
   176  
   177  	// MyImportPath provides the import name (roughly, the package) for the function being compiled.
   178  	MyImportPath() string
   179  }
   180  
   181  // interface used to hold a *gc.Node (a stack variable).
   182  // We'd use *gc.Node directly but that would lead to an import cycle.
   183  type GCNode interface {
   184  	Typ() *types.Type
   185  	String() string
   186  	IsSynthetic() bool
   187  	IsAutoTmp() bool
   188  	StorageClass() StorageClass
   189  }
   190  
   191  type StorageClass uint8
   192  
   193  const (
   194  	ClassAuto     StorageClass = iota // local stack variable
   195  	ClassParam                        // argument
   196  	ClassParamOut                     // return value
   197  )
   198  
   199  const go116lateCallExpansion = true
   200  
   201  // LateCallExpansionEnabledWithin returns true if late call expansion should be tested
   202  // within compilation of a function/method.
   203  func LateCallExpansionEnabledWithin(f *Func) bool {
   204  	return go116lateCallExpansion
   205  }
   206  
   207  // NewConfig returns a new configuration object for the given architecture.
   208  func NewConfig(arch string, types Types, ctxt *obj.Link, optimize bool) *Config {
   209  	c := &Config{arch: arch, Types: types}
   210  	c.useAvg = true
   211  	c.useHmul = true
   212  	switch arch {
   213  	case "amd64":
   214  		c.PtrSize = 8
   215  		c.RegSize = 8
   216  		c.lowerBlock = rewriteBlockAMD64
   217  		c.lowerValue = rewriteValueAMD64
   218  		c.splitLoad = rewriteValueAMD64splitload
   219  		c.registers = registersAMD64[:]
   220  		c.gpRegMask = gpRegMaskAMD64
   221  		c.fpRegMask = fpRegMaskAMD64
   222  		c.FPReg = framepointerRegAMD64
   223  		c.LinkReg = linkRegAMD64
   224  		c.hasGReg = false
   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" || objabi.GOOS == "ios" // 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 "riscv64":
   320  		c.PtrSize = 8
   321  		c.RegSize = 8
   322  		c.lowerBlock = rewriteBlockRISCV64
   323  		c.lowerValue = rewriteValueRISCV64
   324  		c.registers = registersRISCV64[:]
   325  		c.gpRegMask = gpRegMaskRISCV64
   326  		c.fpRegMask = fpRegMaskRISCV64
   327  		c.FPReg = framepointerRegRISCV64
   328  		c.hasGReg = true
   329  	case "wasm":
   330  		c.PtrSize = 8
   331  		c.RegSize = 8
   332  		c.lowerBlock = rewriteBlockWasm
   333  		c.lowerValue = rewriteValueWasm
   334  		c.registers = registersWasm[:]
   335  		c.gpRegMask = gpRegMaskWasm
   336  		c.fpRegMask = fpRegMaskWasm
   337  		c.fp32RegMask = fp32RegMaskWasm
   338  		c.fp64RegMask = fp64RegMaskWasm
   339  		c.FPReg = framepointerRegWasm
   340  		c.LinkReg = linkRegWasm
   341  		c.hasGReg = true
   342  		c.noDuffDevice = true
   343  		c.useAvg = false
   344  		c.useHmul = false
   345  	default:
   346  		ctxt.Diag("arch %s not implemented", arch)
   347  	}
   348  	c.ctxt = ctxt
   349  	c.optimize = optimize
   350  	c.useSSE = true
   351  	c.UseFMA = true
   352  
   353  	// On Plan 9, floating point operations are not allowed in note handler.
   354  	if objabi.GOOS == "plan9" {
   355  		// Don't use FMA on Plan 9
   356  		c.UseFMA = false
   357  
   358  		// Don't use Duff's device and SSE on Plan 9 AMD64.
   359  		if arch == "amd64" {
   360  			c.noDuffDevice = true
   361  			c.useSSE = false
   362  		}
   363  	}
   364  
   365  	if ctxt.Flag_shared {
   366  		// LoweredWB is secretly a CALL and CALLs on 386 in
   367  		// shared mode get rewritten by obj6.go to go through
   368  		// the GOT, which clobbers BX.
   369  		opcodeTable[Op386LoweredWB].reg.clobbers |= 1 << 3 // BX
   370  	}
   371  
   372  	// Create the GC register map index.
   373  	// TODO: This is only used for debug printing. Maybe export config.registers?
   374  	gcRegMapSize := int16(0)
   375  	for _, r := range c.registers {
   376  		if r.gcNum+1 > gcRegMapSize {
   377  			gcRegMapSize = r.gcNum + 1
   378  		}
   379  	}
   380  	c.GCRegMap = make([]*Register, gcRegMapSize)
   381  	for i, r := range c.registers {
   382  		if r.gcNum != -1 {
   383  			c.GCRegMap[r.gcNum] = &c.registers[i]
   384  		}
   385  	}
   386  
   387  	return c
   388  }
   389  
   390  func (c *Config) Ctxt() *obj.Link { return c.ctxt }
   391  

View as plain text