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