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
5package ssa
6
7import (
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.
20type 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
60type (
61	blockRewriter func(*Block) bool
62	valueRewriter func(*Value) bool
63)
64
65type 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.
92func NewTypes() *Types {
93	t := new(Types)
94	t.SetTypPtrs()
95	return t
96}
97
98// SetTypPtrs populates t.
99func (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
125type 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	// Fatalf 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
143type 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.
165func 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
406func (c *Config) Ctxt() *obj.Link { return c.ctxt }
407
408func (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