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

     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/abi"
     9  	"cmd/compile/internal/base"
    10  	"cmd/compile/internal/ir"
    11  	"cmd/compile/internal/types"
    12  	"cmd/internal/obj"
    13  	"cmd/internal/src"
    14  	"internal/buildcfg"
    15  )
    16  
    17  // A Config holds readonly compilation information.
    18  // It is created once, early during compilation,
    19  // and shared across all compilations.
    20  type Config struct {
    21  	arch           string // "amd64", etc.
    22  	PtrSize        int64  // 4 or 8; copy of cmd/internal/sys.Arch.PtrSize
    23  	RegSize        int64  // 4 or 8; copy of cmd/internal/sys.Arch.RegSize
    24  	Types          Types
    25  	lowerBlock     blockRewriter  // block lowering function, first round
    26  	lowerValue     valueRewriter  // value lowering function, first round
    27  	lateLowerBlock blockRewriter  // block lowering function that needs to be run after the first round; only used on some architectures
    28  	lateLowerValue valueRewriter  // value lowering function that needs to be run after the first round; only used on some architectures
    29  	splitLoad      valueRewriter  // function for splitting merged load ops; only used on some architectures
    30  	registers      []Register     // machine registers
    31  	gpRegMask      regMask        // general purpose integer register mask
    32  	fpRegMask      regMask        // floating point register mask
    33  	fp32RegMask    regMask        // floating point register mask
    34  	fp64RegMask    regMask        // floating point register mask
    35  	specialRegMask regMask        // special register mask
    36  	intParamRegs   []int8         // register numbers of integer param (in/out) registers
    37  	floatParamRegs []int8         // register numbers of floating param (in/out) registers
    38  	ABI1           *abi.ABIConfig // "ABIInternal" under development // TODO change comment when this becomes current
    39  	ABI0           *abi.ABIConfig
    40  	GCRegMap       []*Register // garbage collector register map, by GC register index
    41  	FPReg          int8        // register number of frame pointer, -1 if not used
    42  	LinkReg        int8        // register number of link register if it is a general purpose register, -1 if not used
    43  	hasGReg        bool        // has hardware g register
    44  	ctxt           *obj.Link   // Generic arch information
    45  	optimize       bool        // Do optimization
    46  	noDuffDevice   bool        // Don't use Duff's device
    47  	useSSE         bool        // Use SSE for non-float operations
    48  	useAvg         bool        // Use optimizations that need Avg* operations
    49  	useHmul        bool        // Use optimizations that need Hmul* operations
    50  	SoftFloat      bool        //
    51  	Race           bool        // race detector enabled
    52  	BigEndian      bool        //
    53  	UseFMA         bool        // Use hardware FMA operation
    54  	unalignedOK    bool        // Unaligned loads/stores are ok
    55  	haveBswap64    bool        // architecture implements Bswap64
    56  	haveBswap32    bool        // architecture implements Bswap32
    57  	haveBswap16    bool        // architecture implements Bswap16
    58  }
    59  
    60  type (
    61  	blockRewriter func(*Block) bool
    62  	valueRewriter func(*Value) bool
    63  )
    64  
    65  type Types struct {
    66  	Bool       *types.Type
    67  	Int8       *types.Type
    68  	Int16      *types.Type
    69  	Int32      *types.Type
    70  	Int64      *types.Type
    71  	UInt8      *types.Type
    72  	UInt16     *types.Type
    73  	UInt32     *types.Type
    74  	UInt64     *types.Type
    75  	Int        *types.Type
    76  	Float32    *types.Type
    77  	Float64    *types.Type
    78  	UInt       *types.Type
    79  	Uintptr    *types.Type
    80  	String     *types.Type
    81  	BytePtr    *types.Type // TODO: use unsafe.Pointer instead?
    82  	Int32Ptr   *types.Type
    83  	UInt32Ptr  *types.Type
    84  	IntPtr     *types.Type
    85  	UintptrPtr *types.Type
    86  	Float32Ptr *types.Type
    87  	Float64Ptr *types.Type
    88  	BytePtrPtr *types.Type
    89  }
    90  
    91  // NewTypes creates and populates a Types.
    92  func NewTypes() *Types {
    93  	t := new(Types)
    94  	t.SetTypPtrs()
    95  	return t
    96  }
    97  
    98  // SetTypPtrs populates t.
    99  func (t *Types) SetTypPtrs() {
   100  	t.Bool = types.Types[types.TBOOL]
   101  	t.Int8 = types.Types[types.TINT8]
   102  	t.Int16 = types.Types[types.TINT16]
   103  	t.Int32 = types.Types[types.TINT32]
   104  	t.Int64 = types.Types[types.TINT64]
   105  	t.UInt8 = types.Types[types.TUINT8]
   106  	t.UInt16 = types.Types[types.TUINT16]
   107  	t.UInt32 = types.Types[types.TUINT32]
   108  	t.UInt64 = types.Types[types.TUINT64]
   109  	t.Int = types.Types[types.TINT]
   110  	t.Float32 = types.Types[types.TFLOAT32]
   111  	t.Float64 = types.Types[types.TFLOAT64]
   112  	t.UInt = types.Types[types.TUINT]
   113  	t.Uintptr = types.Types[types.TUINTPTR]
   114  	t.String = types.Types[types.TSTRING]
   115  	t.BytePtr = types.NewPtr(types.Types[types.TUINT8])
   116  	t.Int32Ptr = types.NewPtr(types.Types[types.TINT32])
   117  	t.UInt32Ptr = types.NewPtr(types.Types[types.TUINT32])
   118  	t.IntPtr = types.NewPtr(types.Types[types.TINT])
   119  	t.UintptrPtr = types.NewPtr(types.Types[types.TUINTPTR])
   120  	t.Float32Ptr = types.NewPtr(types.Types[types.TFLOAT32])
   121  	t.Float64Ptr = types.NewPtr(types.Types[types.TFLOAT64])
   122  	t.BytePtrPtr = types.NewPtr(types.NewPtr(types.Types[types.TUINT8]))
   123  }
   124  
   125  type Logger interface {
   126  	// Logf logs a message from the compiler.
   127  	Logf(string, ...interface{})
   128  
   129  	// Log reports whether logging is not a no-op
   130  	// some logging calls account for more than a few heap allocations.
   131  	Log() bool
   132  
   133  	// Fatal reports a compiler error and exits.
   134  	Fatalf(pos src.XPos, msg string, args ...interface{})
   135  
   136  	// Warnl writes compiler messages in the form expected by "errorcheck" tests
   137  	Warnl(pos src.XPos, fmt_ string, args ...interface{})
   138  
   139  	// Forwards the Debug flags from gc
   140  	Debug_checknil() bool
   141  }
   142  
   143  type Frontend interface {
   144  	Logger
   145  
   146  	// StringData returns a symbol pointing to the given string's contents.
   147  	StringData(string) *obj.LSym
   148  
   149  	// Given the name for a compound type, returns the name we should use
   150  	// for the parts of that compound type.
   151  	SplitSlot(parent *LocalSlot, suffix string, offset int64, t *types.Type) LocalSlot
   152  
   153  	// Syslook returns a symbol of the runtime function/variable with the
   154  	// given name.
   155  	Syslook(string) *obj.LSym
   156  
   157  	// UseWriteBarrier reports whether write barrier is enabled
   158  	UseWriteBarrier() bool
   159  
   160  	// Func returns the ir.Func of the function being compiled.
   161  	Func() *ir.Func
   162  }
   163  
   164  // NewConfig returns a new configuration object for the given architecture.
   165  func NewConfig(arch string, types Types, ctxt *obj.Link, optimize, softfloat bool) *Config {
   166  	c := &Config{arch: arch, Types: types}
   167  	c.useAvg = true
   168  	c.useHmul = true
   169  	switch arch {
   170  	case "amd64":
   171  		c.PtrSize = 8
   172  		c.RegSize = 8
   173  		c.lowerBlock = rewriteBlockAMD64
   174  		c.lowerValue = rewriteValueAMD64
   175  		c.lateLowerBlock = rewriteBlockAMD64latelower
   176  		c.lateLowerValue = rewriteValueAMD64latelower
   177  		c.splitLoad = rewriteValueAMD64splitload
   178  		c.registers = registersAMD64[:]
   179  		c.gpRegMask = gpRegMaskAMD64
   180  		c.fpRegMask = fpRegMaskAMD64
   181  		c.specialRegMask = specialRegMaskAMD64
   182  		c.intParamRegs = paramIntRegAMD64
   183  		c.floatParamRegs = paramFloatRegAMD64
   184  		c.FPReg = framepointerRegAMD64
   185  		c.LinkReg = linkRegAMD64
   186  		c.hasGReg = true
   187  		c.unalignedOK = true
   188  		c.haveBswap64 = true
   189  		c.haveBswap32 = true
   190  		c.haveBswap16 = true
   191  	case "386":
   192  		c.PtrSize = 4
   193  		c.RegSize = 4
   194  		c.lowerBlock = rewriteBlock386
   195  		c.lowerValue = rewriteValue386
   196  		c.splitLoad = rewriteValue386splitload
   197  		c.registers = registers386[:]
   198  		c.gpRegMask = gpRegMask386
   199  		c.fpRegMask = fpRegMask386
   200  		c.FPReg = framepointerReg386
   201  		c.LinkReg = linkReg386
   202  		c.hasGReg = false
   203  		c.unalignedOK = true
   204  		c.haveBswap32 = true
   205  		c.haveBswap16 = true
   206  	case "arm":
   207  		c.PtrSize = 4
   208  		c.RegSize = 4
   209  		c.lowerBlock = rewriteBlockARM
   210  		c.lowerValue = rewriteValueARM
   211  		c.registers = registersARM[:]
   212  		c.gpRegMask = gpRegMaskARM
   213  		c.fpRegMask = fpRegMaskARM
   214  		c.FPReg = framepointerRegARM
   215  		c.LinkReg = linkRegARM
   216  		c.hasGReg = true
   217  	case "arm64":
   218  		c.PtrSize = 8
   219  		c.RegSize = 8
   220  		c.lowerBlock = rewriteBlockARM64
   221  		c.lowerValue = rewriteValueARM64
   222  		c.lateLowerBlock = rewriteBlockARM64latelower
   223  		c.lateLowerValue = rewriteValueARM64latelower
   224  		c.registers = registersARM64[:]
   225  		c.gpRegMask = gpRegMaskARM64
   226  		c.fpRegMask = fpRegMaskARM64
   227  		c.intParamRegs = paramIntRegARM64
   228  		c.floatParamRegs = paramFloatRegARM64
   229  		c.FPReg = framepointerRegARM64
   230  		c.LinkReg = linkRegARM64
   231  		c.hasGReg = true
   232  		c.unalignedOK = true
   233  		c.haveBswap64 = true
   234  		c.haveBswap32 = true
   235  		c.haveBswap16 = true
   236  	case "ppc64":
   237  		c.BigEndian = true
   238  		fallthrough
   239  	case "ppc64le":
   240  		c.PtrSize = 8
   241  		c.RegSize = 8
   242  		c.lowerBlock = rewriteBlockPPC64
   243  		c.lowerValue = rewriteValuePPC64
   244  		c.lateLowerBlock = rewriteBlockPPC64latelower
   245  		c.lateLowerValue = rewriteValuePPC64latelower
   246  		c.registers = registersPPC64[:]
   247  		c.gpRegMask = gpRegMaskPPC64
   248  		c.fpRegMask = fpRegMaskPPC64
   249  		c.specialRegMask = specialRegMaskPPC64
   250  		c.intParamRegs = paramIntRegPPC64
   251  		c.floatParamRegs = paramFloatRegPPC64
   252  		c.FPReg = framepointerRegPPC64
   253  		c.LinkReg = linkRegPPC64
   254  		c.hasGReg = true
   255  		c.unalignedOK = true
   256  		// Note: ppc64 has register bswap ops only when GOPPC64>=10.
   257  		// But it has bswap+load and bswap+store ops for all ppc64 variants.
   258  		// That is the sense we're using them here - they are only used
   259  		// in contexts where they can be merged with a load or store.
   260  		c.haveBswap64 = true
   261  		c.haveBswap32 = true
   262  		c.haveBswap16 = true
   263  	case "mips64":
   264  		c.BigEndian = true
   265  		fallthrough
   266  	case "mips64le":
   267  		c.PtrSize = 8
   268  		c.RegSize = 8
   269  		c.lowerBlock = rewriteBlockMIPS64
   270  		c.lowerValue = rewriteValueMIPS64
   271  		c.registers = registersMIPS64[:]
   272  		c.gpRegMask = gpRegMaskMIPS64
   273  		c.fpRegMask = fpRegMaskMIPS64
   274  		c.specialRegMask = specialRegMaskMIPS64
   275  		c.FPReg = framepointerRegMIPS64
   276  		c.LinkReg = linkRegMIPS64
   277  		c.hasGReg = true
   278  	case "loong64":
   279  		c.PtrSize = 8
   280  		c.RegSize = 8
   281  		c.lowerBlock = rewriteBlockLOONG64
   282  		c.lowerValue = rewriteValueLOONG64
   283  		c.registers = registersLOONG64[:]
   284  		c.gpRegMask = gpRegMaskLOONG64
   285  		c.fpRegMask = fpRegMaskLOONG64
   286  		c.intParamRegs = paramIntRegLOONG64
   287  		c.floatParamRegs = paramFloatRegLOONG64
   288  		c.FPReg = framepointerRegLOONG64
   289  		c.LinkReg = linkRegLOONG64
   290  		c.hasGReg = true
   291  	case "s390x":
   292  		c.PtrSize = 8
   293  		c.RegSize = 8
   294  		c.lowerBlock = rewriteBlockS390X
   295  		c.lowerValue = rewriteValueS390X
   296  		c.registers = registersS390X[:]
   297  		c.gpRegMask = gpRegMaskS390X
   298  		c.fpRegMask = fpRegMaskS390X
   299  		c.FPReg = framepointerRegS390X
   300  		c.LinkReg = linkRegS390X
   301  		c.hasGReg = true
   302  		c.noDuffDevice = true
   303  		c.BigEndian = true
   304  		c.unalignedOK = true
   305  		c.haveBswap64 = true
   306  		c.haveBswap32 = true
   307  		c.haveBswap16 = true // only for loads&stores, see ppc64 comment
   308  	case "mips":
   309  		c.BigEndian = true
   310  		fallthrough
   311  	case "mipsle":
   312  		c.PtrSize = 4
   313  		c.RegSize = 4
   314  		c.lowerBlock = rewriteBlockMIPS
   315  		c.lowerValue = rewriteValueMIPS
   316  		c.registers = registersMIPS[:]
   317  		c.gpRegMask = gpRegMaskMIPS
   318  		c.fpRegMask = fpRegMaskMIPS
   319  		c.specialRegMask = specialRegMaskMIPS
   320  		c.FPReg = framepointerRegMIPS
   321  		c.LinkReg = linkRegMIPS
   322  		c.hasGReg = true
   323  		c.noDuffDevice = true
   324  	case "riscv64":
   325  		c.PtrSize = 8
   326  		c.RegSize = 8
   327  		c.lowerBlock = rewriteBlockRISCV64
   328  		c.lowerValue = rewriteValueRISCV64
   329  		c.lateLowerBlock = rewriteBlockRISCV64latelower
   330  		c.lateLowerValue = rewriteValueRISCV64latelower
   331  		c.registers = registersRISCV64[:]
   332  		c.gpRegMask = gpRegMaskRISCV64
   333  		c.fpRegMask = fpRegMaskRISCV64
   334  		c.intParamRegs = paramIntRegRISCV64
   335  		c.floatParamRegs = paramFloatRegRISCV64
   336  		c.FPReg = framepointerRegRISCV64
   337  		c.hasGReg = true
   338  	case "wasm":
   339  		c.PtrSize = 8
   340  		c.RegSize = 8
   341  		c.lowerBlock = rewriteBlockWasm
   342  		c.lowerValue = rewriteValueWasm
   343  		c.registers = registersWasm[:]
   344  		c.gpRegMask = gpRegMaskWasm
   345  		c.fpRegMask = fpRegMaskWasm
   346  		c.fp32RegMask = fp32RegMaskWasm
   347  		c.fp64RegMask = fp64RegMaskWasm
   348  		c.FPReg = framepointerRegWasm
   349  		c.LinkReg = linkRegWasm
   350  		c.hasGReg = true
   351  		c.noDuffDevice = true
   352  		c.useAvg = false
   353  		c.useHmul = false
   354  	default:
   355  		ctxt.Diag("arch %s not implemented", arch)
   356  	}
   357  	c.ctxt = ctxt
   358  	c.optimize = optimize
   359  	c.useSSE = true
   360  	c.UseFMA = true
   361  	c.SoftFloat = softfloat
   362  	if softfloat {
   363  		c.floatParamRegs = nil // no FP registers in softfloat mode
   364  	}
   365  
   366  	c.ABI0 = abi.NewABIConfig(0, 0, ctxt.Arch.FixedFrameSize, 0)
   367  	c.ABI1 = abi.NewABIConfig(len(c.intParamRegs), len(c.floatParamRegs), ctxt.Arch.FixedFrameSize, 1)
   368  
   369  	// On Plan 9, floating point operations are not allowed in note handler.
   370  	if buildcfg.GOOS == "plan9" {
   371  		// Don't use FMA on Plan 9
   372  		c.UseFMA = false
   373  
   374  		// Don't use Duff's device and SSE on Plan 9 AMD64.
   375  		if arch == "amd64" {
   376  			c.noDuffDevice = true
   377  			c.useSSE = false
   378  		}
   379  	}
   380  
   381  	if ctxt.Flag_shared {
   382  		// LoweredWB is secretly a CALL and CALLs on 386 in
   383  		// shared mode get rewritten by obj6.go to go through
   384  		// the GOT, which clobbers BX.
   385  		opcodeTable[Op386LoweredWB].reg.clobbers |= 1 << 3 // BX
   386  	}
   387  
   388  	// Create the GC register map index.
   389  	// TODO: This is only used for debug printing. Maybe export config.registers?
   390  	gcRegMapSize := int16(0)
   391  	for _, r := range c.registers {
   392  		if r.gcNum+1 > gcRegMapSize {
   393  			gcRegMapSize = r.gcNum + 1
   394  		}
   395  	}
   396  	c.GCRegMap = make([]*Register, gcRegMapSize)
   397  	for i, r := range c.registers {
   398  		if r.gcNum != -1 {
   399  			c.GCRegMap[r.gcNum] = &c.registers[i]
   400  		}
   401  	}
   402  
   403  	return c
   404  }
   405  
   406  func (c *Config) Ctxt() *obj.Link { return c.ctxt }
   407  
   408  func (c *Config) haveByteSwap(size int64) bool {
   409  	switch size {
   410  	case 8:
   411  		return c.haveBswap64
   412  	case 4:
   413  		return c.haveBswap32
   414  	case 2:
   415  		return c.haveBswap16
   416  	default:
   417  		base.Fatalf("bad size %d\n", size)
   418  		return false
   419  	}
   420  }
   421  

View as plain text