...

Source file src/pkg/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/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