1// Copyright 2016 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 sys
6
7import "encoding/binary"
8
9// ArchFamily represents a family of one or more related architectures.
10// For example, ppc64 and ppc64le are both members of the PPC64 family.
11type ArchFamily byte
12
13const (
14	NoArch ArchFamily = iota
15	AMD64
16	ARM
17	ARM64
18	I386
19	Loong64
20	MIPS
21	MIPS64
22	PPC64
23	RISCV64
24	S390X
25	Wasm
26)
27
28// Arch represents an individual architecture.
29type Arch struct {
30	Name   string
31	Family ArchFamily
32
33	ByteOrder binary.ByteOrder
34
35	// PtrSize is the size in bytes of pointers and the
36	// predeclared "int", "uint", and "uintptr" types.
37	PtrSize int
38
39	// RegSize is the size in bytes of general purpose registers.
40	RegSize int
41
42	// MinLC is the minimum length of an instruction code.
43	MinLC int
44
45	// Alignment is maximum alignment required by the architecture
46	// for any (compiler-generated) load or store instruction.
47	// Loads or stores smaller than Alignment must be naturally aligned.
48	// Loads or stores larger than Alignment need only be Alignment-aligned.
49	Alignment int8
50
51	// CanMergeLoads reports whether the backend optimization passes
52	// can combine adjacent loads into a single larger, possibly unaligned, load.
53	// Note that currently the optimizations must be able to handle little endian byte order.
54	CanMergeLoads bool
55
56	// CanJumpTable reports whether the backend can handle
57	// compiling a jump table.
58	CanJumpTable bool
59
60	// HasLR indicates that this architecture uses a link register
61	// for calls.
62	HasLR bool
63
64	// FixedFrameSize is the smallest possible offset from the
65	// hardware stack pointer to a local variable on the stack.
66	// Architectures that use a link register save its value on
67	// the stack in the function prologue and so always have a
68	// pointer between the hardware stack pointer and the local
69	// variable area.
70	FixedFrameSize int64
71}
72
73// InFamily reports whether a is a member of any of the specified
74// architecture families.
75func (a *Arch) InFamily(xs ...ArchFamily) bool {
76	for _, x := range xs {
77		if a.Family == x {
78			return true
79		}
80	}
81	return false
82}
83
84var Arch386 = &Arch{
85	Name:           "386",
86	Family:         I386,
87	ByteOrder:      binary.LittleEndian,
88	PtrSize:        4,
89	RegSize:        4,
90	MinLC:          1,
91	Alignment:      1,
92	CanMergeLoads:  true,
93	HasLR:          false,
94	FixedFrameSize: 0,
95}
96
97var ArchAMD64 = &Arch{
98	Name:           "amd64",
99	Family:         AMD64,
100	ByteOrder:      binary.LittleEndian,
101	PtrSize:        8,
102	RegSize:        8,
103	MinLC:          1,
104	Alignment:      1,
105	CanMergeLoads:  true,
106	CanJumpTable:   true,
107	HasLR:          false,
108	FixedFrameSize: 0,
109}
110
111var ArchARM = &Arch{
112	Name:           "arm",
113	Family:         ARM,
114	ByteOrder:      binary.LittleEndian,
115	PtrSize:        4,
116	RegSize:        4,
117	MinLC:          4,
118	Alignment:      4, // TODO: just for arm5?
119	CanMergeLoads:  false,
120	HasLR:          true,
121	FixedFrameSize: 4, // LR
122}
123
124var ArchARM64 = &Arch{
125	Name:           "arm64",
126	Family:         ARM64,
127	ByteOrder:      binary.LittleEndian,
128	PtrSize:        8,
129	RegSize:        8,
130	MinLC:          4,
131	Alignment:      1,
132	CanMergeLoads:  true,
133	CanJumpTable:   true,
134	HasLR:          true,
135	FixedFrameSize: 8, // LR
136}
137
138var ArchLoong64 = &Arch{
139	Name:           "loong64",
140	Family:         Loong64,
141	ByteOrder:      binary.LittleEndian,
142	PtrSize:        8,
143	RegSize:        8,
144	MinLC:          4,
145	Alignment:      8, // Unaligned accesses are not guaranteed to be fast
146	CanMergeLoads:  false,
147	HasLR:          true,
148	FixedFrameSize: 8, // LR
149}
150
151var ArchMIPS = &Arch{
152	Name:           "mips",
153	Family:         MIPS,
154	ByteOrder:      binary.BigEndian,
155	PtrSize:        4,
156	RegSize:        4,
157	MinLC:          4,
158	Alignment:      4,
159	CanMergeLoads:  false,
160	HasLR:          true,
161	FixedFrameSize: 4, // LR
162}
163
164var ArchMIPSLE = &Arch{
165	Name:           "mipsle",
166	Family:         MIPS,
167	ByteOrder:      binary.LittleEndian,
168	PtrSize:        4,
169	RegSize:        4,
170	MinLC:          4,
171	Alignment:      4,
172	CanMergeLoads:  false,
173	HasLR:          true,
174	FixedFrameSize: 4, // LR
175}
176
177var ArchMIPS64 = &Arch{
178	Name:           "mips64",
179	Family:         MIPS64,
180	ByteOrder:      binary.BigEndian,
181	PtrSize:        8,
182	RegSize:        8,
183	MinLC:          4,
184	Alignment:      8,
185	CanMergeLoads:  false,
186	HasLR:          true,
187	FixedFrameSize: 8, // LR
188}
189
190var ArchMIPS64LE = &Arch{
191	Name:           "mips64le",
192	Family:         MIPS64,
193	ByteOrder:      binary.LittleEndian,
194	PtrSize:        8,
195	RegSize:        8,
196	MinLC:          4,
197	Alignment:      8,
198	CanMergeLoads:  false,
199	HasLR:          true,
200	FixedFrameSize: 8, // LR
201}
202
203var ArchPPC64 = &Arch{
204	Name:          "ppc64",
205	Family:        PPC64,
206	ByteOrder:     binary.BigEndian,
207	PtrSize:       8,
208	RegSize:       8,
209	MinLC:         4,
210	Alignment:     1,
211	CanMergeLoads: false,
212	HasLR:         true,
213	// PIC code on ppc64le requires 32 bytes of stack, and it's
214	// easier to just use that much stack always.
215	FixedFrameSize: 4 * 8,
216}
217
218var ArchPPC64LE = &Arch{
219	Name:           "ppc64le",
220	Family:         PPC64,
221	ByteOrder:      binary.LittleEndian,
222	PtrSize:        8,
223	RegSize:        8,
224	MinLC:          4,
225	Alignment:      1,
226	CanMergeLoads:  true,
227	HasLR:          true,
228	FixedFrameSize: 4 * 8,
229}
230
231var ArchRISCV64 = &Arch{
232	Name:           "riscv64",
233	Family:         RISCV64,
234	ByteOrder:      binary.LittleEndian,
235	PtrSize:        8,
236	RegSize:        8,
237	MinLC:          4,
238	Alignment:      8, // riscv unaligned loads work, but are really slow (trap + simulated by OS)
239	CanMergeLoads:  false,
240	HasLR:          true,
241	FixedFrameSize: 8, // LR
242}
243
244var ArchS390X = &Arch{
245	Name:           "s390x",
246	Family:         S390X,
247	ByteOrder:      binary.BigEndian,
248	PtrSize:        8,
249	RegSize:        8,
250	MinLC:          2,
251	Alignment:      1,
252	CanMergeLoads:  true,
253	HasLR:          true,
254	FixedFrameSize: 8, // LR
255}
256
257var ArchWasm = &Arch{
258	Name:           "wasm",
259	Family:         Wasm,
260	ByteOrder:      binary.LittleEndian,
261	PtrSize:        8,
262	RegSize:        8,
263	MinLC:          1,
264	Alignment:      1,
265	CanMergeLoads:  false,
266	HasLR:          false,
267	FixedFrameSize: 0,
268}
269
270var Archs = [...]*Arch{
271	Arch386,
272	ArchAMD64,
273	ArchARM,
274	ArchARM64,
275	ArchLoong64,
276	ArchMIPS,
277	ArchMIPSLE,
278	ArchMIPS64,
279	ArchMIPS64LE,
280	ArchPPC64,
281	ArchPPC64LE,
282	ArchRISCV64,
283	ArchS390X,
284	ArchWasm,
285}
286