1//
2// Copyright (C) 2024 The Android Open Source Project
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8//      http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15//
16
17package cpp_types
18
19import (
20	"fmt"
21	"strings"
22)
23
24type Type interface {
25	Align(arch Arch) uint
26	Bits(arch Arch) uint
27	DeclareVar(var_name string, arch Arch) string
28	BaseName(arch Arch) string // Name without additional marks: “*”, “[]”, “struct”, “union”, etc. Not defined for function pointers.
29	Name(arch Arch) string
30	// Note: some types are defined differently depending on architecture.
31	// E.g. VK_DEFINE_NON_DISPATCHABLE_HANDLE is pointer on 64-bit platforms and uint64_t on 32-bit ones.
32	Kind(arch Arch) Kind
33	// Only for integer types
34	Signed(arch Arch) bool
35	// Only for Array or Ptr..
36	Elem(arch Arch) Type
37	// Only for Struct and Union
38	NumField(arch Arch) uint
39	Field(i uint, arch Arch) FieldInfo
40}
41
42// This is builder-only interface. Should only be used when you need to build recursive data types.
43type ModifyablePtrType interface {
44	ReplaceElem(pointee_type Type)
45}
46
47// FieldInfo interface can be expanded: StructFieldInfo is used for structs, EnumFieldInfo for enums.
48//
49// But since Go doesn't yet have generics StructFieldInfo carries information calculated in StructType
50// constructor and also includes reference to the builder-provided type which may carry additional data.
51// This creates “love triangle” of sorts:
52//
53//    in cpp_types                     in builder           in cpp_types
54//                                 ┌┄┄┄┐
55//                                 ┆   ▼
56//    StructFieldInfo ─────────────┼─▶ BaseInfo ──────────▶ FieldInfo
57//      Name() ┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┼┄┄┄▶ Name() ┄┄┄┄┄┄┄┄┄┄┄┄▶ Name()
58//      Type() ┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┼┄┄┄▶ Type() ┄┄┄┄┄┄┄┄┄┄┄┄▶ Type()
59//                       (returns) ┆     SomeOtherInfo()
60//      BaseFieldInfo() ┄┄┄┄┄┄┄┄┄┄┄┘
61//      Offset() (calculated during StructFieldInfo construction)
62//
63//
64// This leaves SomeOtherInfo() provided by builder inaccessible directly.
65// To access it one need to call BaseFieldInfo().
66//
67// But this means that we would need to distinguish cases where we have StructFieldInfo()
68// (used for struct types) and other types of FieldInfo (used for unions, enums, functions).
69//
70// To make access consistent BaseFieldInfo() function is provided in FieldInfo, EnumFieldInfo (and
71// is supposed to be provided by extended types).  It just returns pointer to xxxFieldInfo itself
72// (StructFieldInfo is the only exception).
73//
74// Note: all structs fieldInfo, enumFieldInfo and structFieldInfo are constructed by the builder
75// explicitly. Every fieldInfo may get SomeOtherInfo() attached. structFieldInfo may reference
76// SomeOtherInfo through its base type. enumFieldInfo typically doesn't have and doesn't need
77// SomeOtherInfo but can attach it like fieldInfo. To access SomeOtherInfo uniformly for fieldInfo,
78// enumFieldInfo, and structFieldInfo we add BaseFieldInfo() method, which will return itself for
79// fieldInfo and enumFieldInfo, and return base type for structFieldInfo.
80
81// This way calling field_info.BaseFieldInfo().(BaseInfo).SomeOtherInfo() will give us access to
82// SomeOtherInfo. Note: calling it for type which doesn't have it will panic.
83
84type FieldInfo interface {
85	Name() string
86	Type() Type
87	BaseFieldInfo() FieldInfo
88}
89
90type StructFieldInfo interface {
91	Name() string
92	Type() Type
93	BaseFieldInfo() FieldInfo
94	Offset() uint
95}
96
97type EnumFieldInfo interface {
98	Name() string
99	Type() Type
100	BaseFieldInfo() FieldInfo
101	Alias() string
102	Value() int64
103}
104
105// Arches - both host and guest.
106type Arch uint
107
108const (
109	Arm Arch = iota
110	Arm64
111	Riscv32
112	Riscv64
113	X86
114	X86_64
115	FirstArch = Arm
116	LastArch  = X86_64
117)
118
119func Define(arch Arch) string {
120	switch arch {
121	default:
122		panic(fmt.Sprintf("cpp_types: Unknown arch %d", arch))
123	case Arm:
124		return "defined(__arm__)"
125	case Arm64:
126		return "defined(__aarch64__)"
127	case Riscv32:
128		return "defined(__riscv) && (__riscv_xlen == 32)"
129	case Riscv64:
130		return "defined(__riscv) && (__riscv_xlen == 64)"
131	case X86:
132		return "defined(__i386__)"
133	case X86_64:
134		return "defined(__x86_64__)"
135	}
136}
137
138// The zero Kind is Invalid Kind.
139type Kind uint
140
141const (
142	Invalid Kind = iota
143	Opaque
144	Alias
145	Void
146	Bool
147	Char16T
148	Char32T
149	Char
150	SChar
151	UChar
152	Short
153	UShort
154	Int
155	UInt
156	Long
157	ULong
158	LongLong
159	ULongLong
160	SSizeT
161	SizeT
162	IntPtrT
163	UIntPtrT
164	Int8T
165	UInt8T
166	Int16T
167	UInt16T
168	Int32T
169	UInt32T
170	Int64T
171	UInt64T
172	Float32
173	Float64
174	Array
175	Struct
176	Union
177	Ptr
178	Enum
179	Func
180	Const
181)
182
183func AliasType(name string, base_type Type) Type {
184	return &aliasType{name, base_type}
185}
186
187func OpaqueType(name string) Type {
188	return &opaqueType{Opaque, name}
189}
190
191func ArchDependentType(arm_type, arm64_type, riscv32_type, riscv64_type, x86_type, x86_64_type Type) Type {
192	return &archDependentType{arm_type, arm64_type, riscv32_type, riscv64_type, x86_type, x86_64_type}
193}
194
195func ConstType(base_type Type) Type {
196	return &constType{base_type}
197}
198
199func PointerType(pointee_type Type) Type {
200	return &pointerType{pointee_type}
201}
202
203func FunctionType(result Type, field_info []FieldInfo) Type {
204	return &functionType{result, field_info}
205}
206
207func ArrayType(elem_type Type, size uint) Type {
208	return &arrayType{elem_type, size}
209}
210
211// Note that this function should have the following prototype:
212//
213//	func StructType[FieldInfo BaseInfo](name string, fields_info []BaseInfo) Type;
214//
215// This way we may extend BaseInfo (potentially defined in other package) into
216// structFieldInfo[BaseInfo] — which would be a generic type, too.
217// Then out fields would support both StructFieldInfo interface and BaseInfo interface and remove
218// BaseFieldInfo() function and related trick.
219func StructType(name string, fields_info []FieldInfo) Type {
220	arch_dependent_layout := false
221	var struct_fields_info [LastArch + 1][]StructFieldInfo
222	var offset [LastArch + 1]uint
223	var align [LastArch + 1]uint
224	for arch := FirstArch; arch <= LastArch; arch++ {
225		struct_fields_info[arch] = make([]StructFieldInfo, len(fields_info))
226		offset[arch] = 0
227		align[arch] = 0
228	}
229	for i, field_info := range fields_info {
230		for arch := FirstArch; arch <= LastArch; arch++ {
231			field_align := field_info.Type().Align(arch)
232			if align[arch] < field_align {
233				align[arch] = field_align
234			}
235			modulo := offset[arch] % field_align
236			if modulo != 0 {
237				offset[arch] += field_align - modulo
238			}
239			struct_fields_info[arch][i] = &structFieldInfo{field_info, offset[arch]}
240			offset[arch] += field_info.Type().Bits(arch)
241			if align[FirstArch] != align[arch] || offset[FirstArch] != offset[arch] {
242				arch_dependent_layout = true
243			}
244		}
245	}
246	for arch := FirstArch; arch <= LastArch; arch++ {
247		modulo := offset[arch] % align[arch]
248		if modulo != 0 {
249			offset[arch] += align[arch] - modulo
250		}
251		if offset[FirstArch] != offset[arch] {
252			arch_dependent_layout = true
253		}
254	}
255	if arch_dependent_layout {
256		return &archDependentType{
257			&structType{name, struct_fields_info[Arm], align[Arm], offset[Arm]},
258			&structType{name, struct_fields_info[Arm64], align[Arm64], offset[Arm64]},
259			&structType{name, struct_fields_info[Riscv32], align[Riscv32], offset[Riscv32]},
260			&structType{name, struct_fields_info[Riscv64], align[Riscv64], offset[Riscv64]},
261			&structType{name, struct_fields_info[X86], align[X86], offset[X86]},
262			&structType{name, struct_fields_info[X86_64], align[X86_64], offset[X86_64]}}
263	} else {
264		return &structType{name, struct_fields_info[FirstArch], align[FirstArch], offset[FirstArch]}
265	}
266}
267
268func UnionType(name string, fields_info []FieldInfo) Type {
269	arch_dependent_layout := false
270	var bits [LastArch + 1]uint
271	var align [LastArch + 1]uint
272	for arch := FirstArch; arch <= LastArch; arch++ {
273		bits[arch] = 0
274		align[arch] = 0
275		for _, field_info := range fields_info {
276			typе := field_info.Type()
277			if bits[arch] < typе.Bits(arch) {
278				bits[arch] = typе.Bits(arch)
279			}
280			if align[arch] < typе.Align(arch) {
281				align[arch] = typе.Align(arch)
282			}
283		}
284		if align[FirstArch] != align[arch] || bits[FirstArch] != bits[arch] {
285			arch_dependent_layout = true
286		}
287	}
288	if arch_dependent_layout {
289		return &archDependentType{
290			&unionType{name, fields_info, align[Arm], bits[Arm]},
291			&unionType{name, fields_info, align[Arm64], bits[Arm64]},
292			&unionType{name, fields_info, align[Riscv32], bits[Riscv32]},
293			&unionType{name, fields_info, align[Riscv64], bits[Riscv64]},
294			&unionType{name, fields_info, align[X86], bits[X86]},
295			&unionType{name, fields_info, align[X86_64], bits[X86_64]}}
296	} else {
297		return &unionType{name, fields_info, align[FirstArch], bits[FirstArch]}
298	}
299}
300
301func Field(name string, typе Type) FieldInfo {
302	return &fieldInfo{name, typе}
303}
304
305func EnumType(name string, basetype Type, values []EnumFieldInfo) Type {
306	return &enumType{name, basetype, values}
307}
308
309func EnumField(name string, basetype Type, alias string, value int64) EnumFieldInfo {
310	return &enumFieldInfo{name, basetype, alias, value}
311}
312
313var VoidType Type = &opaqueType{Void, "void"}
314
315var BoolType Type = &fixedType{8, 8, Bool, "bool"}
316
317var CharType Type = &archDependentType{
318	&unsignedFixedType{fixedType{8, 8, Char, "char"}},
319	&unsignedFixedType{fixedType{8, 8, Char, "char"}},
320	&unsignedFixedType{fixedType{8, 8, Char, "char"}},
321	&unsignedFixedType{fixedType{8, 8, Char, "char"}},
322	&signedFixedType{fixedType{8, 8, Char, "char"}},
323	&signedFixedType{fixedType{8, 8, Char, "char"}}}
324
325var Char16TType Type = &unsignedFixedType{fixedType{16, 16, Char16T, "char16_t"}}
326
327var Char32TType Type = &unsignedFixedType{fixedType{32, 32, Char32T, "char32_t"}}
328
329var SCharType Type = &signedFixedType{fixedType{8, 8, SChar, "signed char"}}
330
331var UCharType Type = &unsignedFixedType{fixedType{8, 8, UChar, "signed char"}}
332
333var ShortType Type = &signedFixedType{fixedType{16, 16, Short, "short"}}
334
335var UShortType Type = &unsignedFixedType{fixedType{16, 16, UShort, "unisigned short"}}
336
337var IntType Type = &signedFixedType{fixedType{32, 32, Int, "int"}}
338
339var UIntType Type = &unsignedFixedType{fixedType{32, 32, UInt, "unsigned int"}}
340
341var LongType Type = &archDependentType{
342	&signedFixedType{fixedType{32, 32, Long, "long"}},
343	&signedFixedType{fixedType{64, 64, Long, "long"}},
344	&signedFixedType{fixedType{32, 32, Long, "long"}},
345	&signedFixedType{fixedType{64, 64, Long, "long"}},
346	&signedFixedType{fixedType{32, 32, Long, "long"}},
347	&signedFixedType{fixedType{64, 64, Long, "long"}}}
348
349var ULongType Type = &archDependentType{
350	&unsignedFixedType{fixedType{32, 32, ULong, "unsigned long"}},
351	&unsignedFixedType{fixedType{64, 64, ULong, "unsigned long"}},
352	&unsignedFixedType{fixedType{32, 32, ULong, "unsigned long"}},
353	&unsignedFixedType{fixedType{64, 64, ULong, "unsigned long"}},
354	&unsignedFixedType{fixedType{32, 32, ULong, "unsigned long"}},
355	&unsignedFixedType{fixedType{64, 64, ULong, "unsigned long"}}}
356
357var LongLongType Type = &archDependentType{
358	&signedFixedType{fixedType{64, 64, LongLong, "long long"}},
359	&signedFixedType{fixedType{64, 64, LongLong, "long long"}},
360	&signedFixedType{fixedType{64, 64, LongLong, "long long"}},
361	&signedFixedType{fixedType{64, 64, LongLong, "long long"}},
362	&signedFixedType{fixedType{64, 32, LongLong, "long long"}},
363	&signedFixedType{fixedType{64, 64, LongLong, "long long"}}}
364
365var ULongLongType Type = &archDependentType{
366	&unsignedFixedType{fixedType{64, 64, ULongLong, "unsigned long long"}},
367	&unsignedFixedType{fixedType{64, 64, ULongLong, "unsigned long long"}},
368	&unsignedFixedType{fixedType{64, 64, ULongLong, "unsigned long long"}},
369	&unsignedFixedType{fixedType{64, 64, ULongLong, "unsigned long long"}},
370	&unsignedFixedType{fixedType{64, 32, ULongLong, "unsigned long long"}},
371	&unsignedFixedType{fixedType{64, 64, ULongLong, "unsigned long long"}}}
372
373// Note: ssize_t is POSIX, not ISO C/C++! That's why it's not std::ssize_t
374var SSizeTType Type = &archDependentType{
375	&signedFixedType{fixedType{32, 32, SSizeT, "ssize_t"}},
376	&signedFixedType{fixedType{64, 64, SSizeT, "ssize_t"}},
377	&signedFixedType{fixedType{32, 32, SSizeT, "ssize_t"}},
378	&signedFixedType{fixedType{64, 64, SSizeT, "ssize_t"}},
379	&signedFixedType{fixedType{32, 32, SSizeT, "ssize_t"}},
380	&signedFixedType{fixedType{64, 64, SSizeT, "ssize_t"}}}
381
382var SizeTType Type = &archDependentType{
383	&unsignedFixedType{fixedType{32, 32, SizeT, "std::size_t"}},
384	&unsignedFixedType{fixedType{64, 64, SizeT, "std::size_t"}},
385	&unsignedFixedType{fixedType{32, 32, SizeT, "std::size_t"}},
386	&unsignedFixedType{fixedType{64, 64, SizeT, "std::size_t"}},
387	&unsignedFixedType{fixedType{32, 32, SizeT, "std::size_t"}},
388	&unsignedFixedType{fixedType{64, 64, SizeT, "std::size_t"}}}
389
390var IntPtrTType Type = &archDependentType{
391	&signedFixedType{fixedType{32, 32, IntPtrT, "std::intptr_t"}},
392	&signedFixedType{fixedType{64, 64, IntPtrT, "std::intptr_t"}},
393	&signedFixedType{fixedType{32, 32, IntPtrT, "std::intptr_t"}},
394	&signedFixedType{fixedType{64, 64, IntPtrT, "std::intptr_t"}},
395	&signedFixedType{fixedType{32, 32, IntPtrT, "std::intptr_t"}},
396	&signedFixedType{fixedType{64, 64, IntPtrT, "std::intptr_t"}}}
397
398var UintPtrTType Type = &archDependentType{
399	&unsignedFixedType{fixedType{32, 32, UIntPtrT, "std::uintptr_t"}},
400	&unsignedFixedType{fixedType{64, 64, UIntPtrT, "std::uintptr_t"}},
401	&unsignedFixedType{fixedType{32, 32, UIntPtrT, "std::uintptr_t"}},
402	&unsignedFixedType{fixedType{64, 64, UIntPtrT, "std::uintptr_t"}},
403	&unsignedFixedType{fixedType{32, 32, UIntPtrT, "std::uintptr_t"}},
404	&unsignedFixedType{fixedType{64, 64, UIntPtrT, "std::uintptr_t"}}}
405
406var Int8TType Type = &signedFixedType{fixedType{8, 8, Int8T, "std::int8_t"}}
407
408var UInt8TType Type = &unsignedFixedType{fixedType{8, 8, UInt8T, "std::uint8_t"}}
409
410var Int16TType Type = &signedFixedType{fixedType{16, 16, Int16T, "std::int16_t"}}
411
412var UInt16TType Type = &unsignedFixedType{fixedType{16, 16, UInt16T, "std::uint16_t"}}
413
414var Int32TType Type = &signedFixedType{fixedType{32, 32, Int32T, "std::int32_t"}}
415
416var UInt32TType Type = &unsignedFixedType{fixedType{32, 32, UInt32T, "std::uint32_t"}}
417
418var Int64TType Type = &archDependentType{
419	&signedFixedType{fixedType{64, 64, Int64T, "std::int64_t"}},
420	&signedFixedType{fixedType{64, 64, Int64T, "std::int64_t"}},
421	&signedFixedType{fixedType{64, 64, Int64T, "std::int64_t"}},
422	&signedFixedType{fixedType{64, 64, Int64T, "std::int64_t"}},
423	&signedFixedType{fixedType{64, 32, Int64T, "std::int64_t"}},
424	&signedFixedType{fixedType{64, 64, Int64T, "std::int64_t"}}}
425
426var UInt64TType Type = &archDependentType{
427	&unsignedFixedType{fixedType{64, 64, UInt64T, "std::uint64_t"}},
428	&unsignedFixedType{fixedType{64, 64, UInt64T, "std::uint64_t"}},
429	&unsignedFixedType{fixedType{64, 64, UInt64T, "std::uint64_t"}},
430	&unsignedFixedType{fixedType{64, 64, UInt64T, "std::uint64_t"}},
431	&unsignedFixedType{fixedType{64, 32, UInt64T, "std::uint64_t"}},
432	&unsignedFixedType{fixedType{64, 64, UInt64T, "std::uint64_t"}}}
433
434var Float32Type Type = &signedFixedType{fixedType{32, 32, Float32, "float"}}
435
436var Float64Type Type = &archDependentType{
437	&signedFixedType{fixedType{64, 64, Float64, "double"}},
438	&signedFixedType{fixedType{64, 64, Float64, "double"}},
439	&signedFixedType{fixedType{64, 64, Float64, "double"}},
440	&signedFixedType{fixedType{64, 64, Float64, "double"}},
441	&signedFixedType{fixedType{64, 32, Float64, "double"}},
442	&signedFixedType{fixedType{64, 64, Float64, "double"}}}
443
444type opaqueType struct {
445	kind Kind
446	name string
447}
448
449func (typе *opaqueType) Align(Arch) uint {
450	panic("cpp_types: Attempt to find out alignment of opaque type " + typе.name)
451}
452
453func (typе *opaqueType) Bits(Arch) uint {
454	panic("cpp_types: Attempt to find out size of opaque type " + typе.name)
455}
456
457func (typе *opaqueType) DeclareVar(var_name string, arch Arch) string {
458	panic("cpp_types: Attempt to create variable of opaque type " + typе.name)
459}
460
461func (typе *opaqueType) BaseName(Arch) string {
462	return typе.name
463}
464
465func (typе *opaqueType) Name(Arch) string {
466	return typе.name
467}
468
469func (typе *opaqueType) Kind(Arch) Kind {
470	return typе.kind
471}
472
473func (typе *opaqueType) Elem(Arch) Type {
474	panic("cpp_types: Calling Elem() for non-array type " + typе.name)
475}
476
477func (typе *opaqueType) Field(uint, Arch) FieldInfo {
478	panic("cpp_types: Calling Field() for non-struct type " + typе.name)
479}
480
481func (typе *opaqueType) NumField(Arch) uint {
482	panic("cpp_types: Calling NumField() for non-struct type " + typе.name)
483}
484
485func (typе *opaqueType) Signed(Arch) bool {
486	panic("cpp_types: Calling Signed() for non-numeric type " + typе.name)
487}
488
489type aliasType struct {
490	name      string
491	base_type Type
492}
493
494func (typе *aliasType) Align(arch Arch) uint {
495	return typе.base_type.Align(arch)
496}
497
498func (typе *aliasType) Bits(arch Arch) uint {
499	return typе.base_type.Bits(arch)
500}
501
502func (typе *aliasType) DeclareVar(var_name string, arch Arch) string {
503	return typе.name + " " + var_name
504}
505
506func (typе *aliasType) BaseName(Arch) string {
507	return typе.name
508}
509
510func (typе *aliasType) Name(Arch) string {
511	return typе.name
512}
513
514func (*aliasType) Kind(Arch) Kind {
515	return Alias
516}
517
518func (typе *aliasType) Elem(arch Arch) Type {
519	return typе.base_type
520}
521
522func (typе *aliasType) Field(uint, Arch) FieldInfo {
523	panic("cpp_types: Calling Field() for non-struct type " + typе.name)
524}
525
526func (typе *aliasType) NumField(Arch) uint {
527	panic("cpp_types: Calling NumField() for non-struct type " + typе.name)
528}
529
530func (typе *aliasType) Signed(Arch) bool {
531	panic("cpp_types: Calling Signed() for non-numeric type " + typе.name)
532}
533
534type fixedType struct {
535	size  uint
536	align uint
537	kind  Kind
538	name  string
539}
540
541type signedFixedType struct {
542	fixedType
543}
544
545type unsignedFixedType struct {
546	fixedType
547}
548
549func (typе *fixedType) Align(Arch) uint {
550	return typе.align
551}
552
553func (typе *fixedType) Bits(Arch) uint {
554	return typе.size
555}
556
557func (typе *fixedType) DeclareVar(var_name string, arch Arch) string {
558	return typе.name + " " + var_name
559}
560
561func (typе *fixedType) BaseName(Arch) string {
562	return typе.name
563}
564
565func (typе *fixedType) Name(Arch) string {
566	return typе.name
567}
568
569func (typе *fixedType) Kind(Arch) Kind {
570	return typе.kind
571}
572
573func (typе *fixedType) Elem(Arch) Type {
574	panic("cpp_types: Calling Elem() for non-array type " + typе.name)
575}
576
577func (typе *fixedType) Field(uint, Arch) FieldInfo {
578	panic("cpp_types: Calling Field() for non-struct type " + typе.name)
579}
580
581func (typе *fixedType) NumField(Arch) uint {
582	panic("cpp_types: Calling NumField() for non-struct type " + typе.name)
583}
584
585func (typе *fixedType) Signed(Arch) bool {
586	panic("cpp_types: Calling Signed() for non-numeric type " + typе.name)
587}
588
589func (typе *signedFixedType) Signed(Arch) bool {
590	return true
591}
592
593func (typе *unsignedFixedType) Signed(Arch) bool {
594	return false
595}
596
597type archDependentType struct {
598	arm_type     Type
599	arm64_type   Type
600	riscv32_type Type
601	riscv64_type Type
602	x86_type     Type
603	x86_64_type  Type
604}
605
606func (typе *archDependentType) Align(arch Arch) uint {
607	switch arch {
608	default:
609		panic(fmt.Sprintf("cpp_types: Unknown arch %d", arch))
610	case Arm:
611		return typе.arm_type.Align(arch)
612	case Arm64:
613		return typе.arm64_type.Align(arch)
614	case Riscv32:
615		return typе.riscv32_type.Align(arch)
616	case Riscv64:
617		return typе.riscv64_type.Align(arch)
618	case X86:
619		return typе.x86_type.Align(arch)
620	case X86_64:
621		return typе.x86_64_type.Align(arch)
622	}
623}
624
625func (typе *archDependentType) Bits(arch Arch) uint {
626	switch arch {
627	default:
628		panic(fmt.Sprintf("cpp_types: Unknown arch %d", arch))
629	case Arm:
630		return typе.arm_type.Bits(arch)
631	case Arm64:
632		return typе.arm64_type.Bits(arch)
633	case Riscv32:
634		return typе.riscv32_type.Bits(arch)
635	case Riscv64:
636		return typе.riscv64_type.Bits(arch)
637	case X86:
638		return typе.x86_type.Bits(arch)
639	case X86_64:
640		return typе.x86_64_type.Bits(arch)
641	}
642}
643
644func (typе *archDependentType) DeclareVar(var_name string, arch Arch) string {
645	switch arch {
646	default:
647		panic(fmt.Sprintf("cpp_types: Unknown arch %d", arch))
648	case Arm:
649		return typе.arm_type.DeclareVar(var_name, arch)
650	case Arm64:
651		return typе.arm64_type.DeclareVar(var_name, arch)
652	case Riscv32:
653		return typе.riscv32_type.DeclareVar(var_name, arch)
654	case Riscv64:
655		return typе.riscv64_type.DeclareVar(var_name, arch)
656	case X86:
657		return typе.x86_type.DeclareVar(var_name, arch)
658	case X86_64:
659		return typе.x86_64_type.DeclareVar(var_name, arch)
660	}
661}
662
663func (typе *archDependentType) BaseName(arch Arch) string {
664	switch arch {
665	default:
666		panic(fmt.Sprintf("cpp_types: Unknown arch %d", arch))
667	case Arm:
668		return typе.arm_type.BaseName(arch)
669	case Arm64:
670		return typе.arm64_type.BaseName(arch)
671	case Riscv32:
672		return typе.riscv32_type.BaseName(arch)
673	case Riscv64:
674		return typе.riscv64_type.BaseName(arch)
675	case X86:
676		return typе.x86_type.BaseName(arch)
677	case X86_64:
678		return typе.x86_64_type.BaseName(arch)
679	}
680}
681
682func (typе *archDependentType) Name(arch Arch) string {
683	switch arch {
684	default:
685		panic(fmt.Sprintf("cpp_types: Unknown arch %d", arch))
686	case Arm:
687		return typе.arm_type.Name(arch)
688	case Arm64:
689		return typе.arm64_type.Name(arch)
690	case Riscv32:
691		return typе.riscv32_type.Name(arch)
692	case Riscv64:
693		return typе.riscv64_type.Name(arch)
694	case X86:
695		return typе.x86_type.Name(arch)
696	case X86_64:
697		return typе.x86_64_type.Name(arch)
698	}
699}
700
701func (typе *archDependentType) Kind(arch Arch) Kind {
702	switch arch {
703	default:
704		panic(fmt.Sprintf("cpp_types: Unknown arch %d", arch))
705	case Arm:
706		return typе.arm_type.Kind(arch)
707	case Arm64:
708		return typе.arm64_type.Kind(arch)
709	case Riscv32:
710		return typе.riscv32_type.Kind(arch)
711	case Riscv64:
712		return typе.riscv64_type.Kind(arch)
713	case X86:
714		return typе.x86_type.Kind(arch)
715	case X86_64:
716		return typе.x86_64_type.Kind(arch)
717	}
718}
719
720func (typе *archDependentType) Elem(arch Arch) Type {
721	switch arch {
722	default:
723		panic(fmt.Sprintf("cpp_types: Unknown arch %d", arch))
724	case Arm:
725		return typе.arm_type.Elem(arch)
726	case Arm64:
727		return typе.arm64_type.Elem(arch)
728	case Riscv32:
729		return typе.riscv32_type.Elem(arch)
730	case Riscv64:
731		return typе.riscv64_type.Elem(arch)
732	case X86:
733		return typе.x86_type.Elem(arch)
734	case X86_64:
735		return typе.x86_64_type.Elem(arch)
736	}
737}
738
739func (typе *archDependentType) Field(i uint, arch Arch) FieldInfo {
740	switch arch {
741	default:
742		panic(fmt.Sprintf("cpp_types: Unknown arch %d", arch))
743	case Arm:
744		return typе.arm_type.Field(i, arch)
745	case Arm64:
746		return typе.arm64_type.Field(i, arch)
747	case Riscv32:
748		return typе.riscv32_type.Field(i, arch)
749	case Riscv64:
750		return typе.riscv64_type.Field(i, arch)
751	case X86:
752		return typе.x86_type.Field(i, arch)
753	case X86_64:
754		return typе.x86_64_type.Field(i, arch)
755	}
756}
757
758func (typе *archDependentType) NumField(arch Arch) uint {
759	switch arch {
760	default:
761		panic(fmt.Sprintf("cpp_types: Unknown arch %d", arch))
762	case Arm:
763		return typе.arm_type.NumField(arch)
764	case Arm64:
765		return typе.arm64_type.NumField(arch)
766	case Riscv32:
767		return typе.riscv32_type.NumField(arch)
768	case Riscv64:
769		return typе.riscv64_type.NumField(arch)
770	case X86:
771		return typе.x86_type.NumField(arch)
772	case X86_64:
773		return typе.x86_64_type.NumField(arch)
774	}
775}
776
777func (typе *archDependentType) Signed(arch Arch) bool {
778	switch arch {
779	default:
780		panic(fmt.Sprintf("cpp_types: Unknown arch %d", arch))
781	case Arm:
782		return typе.arm_type.Signed(arch)
783	case Arm64:
784		return typе.arm64_type.Signed(arch)
785	case Riscv32:
786		return typе.riscv32_type.Signed(arch)
787	case Riscv64:
788		return typе.riscv64_type.Signed(arch)
789	case X86:
790		return typе.x86_type.Signed(arch)
791	case X86_64:
792		return typе.x86_64_type.Signed(arch)
793	}
794}
795
796type constType struct {
797	base Type
798}
799
800func (typе *constType) Align(arch Arch) uint {
801	return typе.base.Align(arch)
802}
803
804func (typе *constType) Bits(arch Arch) uint {
805	return typе.base.Bits(arch)
806}
807
808func (typе *constType) DeclareVar(var_name string, arch Arch) string {
809	if typе.base.Kind(arch) == Ptr {
810		if len(var_name) >= 1 && (var_name[0] == '(' || var_name[0] == '[') {
811			return typе.base.DeclareVar("const"+var_name, arch)
812		} else {
813			return typе.base.DeclareVar("const "+var_name, arch)
814		}
815	}
816	return "const " + typе.base.DeclareVar(var_name, arch)
817}
818
819func (typе *constType) BaseName(arch Arch) string {
820	return typе.base.BaseName(arch)
821}
822
823func (typе *constType) Name(arch Arch) string {
824	if typе.base.Kind(arch) == Ptr {
825		return typе.base.DeclareVar("const", arch)
826	}
827	return "const " + typе.base.Name(arch)
828}
829
830func (*constType) Kind(Arch) Kind {
831	return Const
832}
833
834func (typе *constType) Elem(Arch) Type {
835	return typе.base
836}
837
838func (typе *constType) Field(i uint, arch Arch) FieldInfo {
839	panic("cpp_types: Calling Field() for non-struct type " + typе.Name(arch))
840}
841
842func (typе *constType) NumField(arch Arch) uint {
843	panic("cpp_types: Calling NumField() for non-struct type " + typе.Name(arch))
844}
845
846func (typе *constType) Signed(arch Arch) bool {
847	panic("cpp_types: Calling Signed() for non-numeric type " + typе.Name(arch))
848}
849
850type pointerType struct {
851	pointee Type
852}
853
854func (*pointerType) Align(arch Arch) uint {
855	switch arch {
856	default:
857		panic(fmt.Sprintf("cpp_types: Unknown arch %d", arch))
858	case Arm:
859		return 32
860	case Arm64:
861		return 64
862	case Riscv32:
863		return 32
864	case Riscv64:
865		return 64
866	case X86:
867		return 32
868	case X86_64:
869		return 64
870	}
871}
872
873func (*pointerType) Bits(arch Arch) uint {
874	switch arch {
875	default:
876		panic(fmt.Sprintf("cpp_types: Unknown arch %d", arch))
877	case Arm:
878		return 32
879	case Arm64:
880		return 64
881	case Riscv32:
882		return 32
883	case Riscv64:
884		return 64
885	case X86:
886		return 32
887	case X86_64:
888		return 64
889	}
890}
891
892func (typе *pointerType) DeclareVar(var_name string, arch Arch) string {
893	switch typе.pointee.Kind(arch) {
894	default:
895		return typе.pointee.Name(arch) + " *" + var_name
896	case Array, Func:
897		return typе.pointee.DeclareVar("(*"+var_name+")", arch)
898	}
899}
900
901func (typе *pointerType) BaseName(arch Arch) string {
902	return typе.pointee.BaseName(arch)
903}
904
905func (typе *pointerType) Name(arch Arch) string {
906	switch typе.pointee.Kind(arch) {
907	default:
908		return typе.pointee.Name(arch) + " *"
909	case Array, Func:
910		return typе.pointee.DeclareVar("(*)", arch)
911	}
912}
913
914func (*pointerType) Kind(Arch) Kind {
915	return Ptr
916}
917
918func (typе *pointerType) Elem(Arch) Type {
919	return typе.pointee
920}
921
922func (typе *pointerType) Field(i uint, arch Arch) FieldInfo {
923	panic("cpp_types: Calling Field() for non-struct type " + typе.Name(arch))
924}
925
926func (typе *pointerType) NumField(arch Arch) uint {
927	panic("cpp_types: Calling NumField() for non-struct type " + typе.Name(arch))
928}
929
930func (typе *pointerType) Signed(arch Arch) bool {
931	panic("cpp_types: Calling Signed() for non-numeric type " + typе.Name(arch))
932}
933
934func (typе *pointerType) ReplaceElem(pointee_type Type) {
935	for arch := FirstArch; arch <= LastArch; arch++ {
936		real_pointee_type_kind := pointee_type.Kind(arch)
937		if typе.pointee.Kind(arch) == Const && typе.pointee.Elem(arch).Kind(arch) == Opaque {
938			if real_pointee_type_kind != Const {
939				panic("cpp_types: Trying to replace const opaque type with non-const " + typе.Name(arch))
940			}
941			real_pointee_type_kind = pointee_type.Elem(arch).Kind(arch)
942		} else if typе.pointee.Kind(arch) != Opaque {
943			panic("cpp_types: Trying to replace non-opaque type " + typе.Name(arch))
944		}
945		if real_pointee_type_kind != Struct && real_pointee_type_kind != Union {
946			panic("cpp_types: Trying to replace type with non-structural type " + typе.Name(arch))
947		}
948	}
949	typе.pointee = pointee_type
950}
951
952type functionType struct {
953	result Type
954	params []FieldInfo
955}
956
957func (*functionType) Align(arch Arch) uint {
958	panic("cpp_types: Calling Align for function type")
959}
960
961func (*functionType) Bits(arch Arch) uint {
962	panic("cpp_types: Calling Align for function type")
963}
964
965func (typе *functionType) DeclareVar(var_name string, arch Arch) string {
966	params := make([]string, len(typе.params))
967	for i, param := range typе.params {
968		params[i] = param.Type().DeclareVar(param.Name(), arch)
969	}
970	// Note: void is opaque type, it's forbidden to declare variable of type "void"
971	if typе.result.Kind(arch) == Void {
972		return "void " + var_name + "(" + strings.Join(params, ", ") + ")"
973	} else {
974		return typе.result.DeclareVar(var_name+"("+strings.Join(params, ", ")+")", arch)
975	}
976}
977
978func (typе *functionType) BaseName(arch Arch) string {
979	panic("cpp_types: Calling BaseName for function type")
980}
981
982func (typе *functionType) Name(arch Arch) string {
983	return typе.DeclareVar("", arch)
984}
985
986func (*functionType) Kind(Arch) Kind {
987	return Func
988}
989
990func (typе *functionType) Elem(Arch) Type {
991	return typе.result
992}
993
994func (typе *functionType) Field(i uint, arch Arch) FieldInfo {
995	return typе.params[i]
996}
997
998func (typе *functionType) NumField(arch Arch) uint {
999	return uint(len(typе.params))
1000}
1001
1002func (typе *functionType) Signed(arch Arch) bool {
1003	panic("cpp_types: Calling Signed() for non-numeric type " + typе.Name(arch))
1004}
1005
1006type arrayType struct {
1007	elem Type
1008	size uint
1009}
1010
1011func (typе *arrayType) Align(arch Arch) uint {
1012	return typе.elem.Align(arch)
1013}
1014
1015func (typе *arrayType) Bits(arch Arch) uint {
1016	return typе.elem.Bits(arch) * typе.size
1017}
1018
1019func (typе *arrayType) DeclareVar(var_name string, arch Arch) string {
1020	return fmt.Sprintf("%s[%d]", typе.elem.DeclareVar(var_name, arch), typе.size)
1021}
1022
1023func (typе *arrayType) BaseName(arch Arch) string {
1024	return typе.elem.Name(arch)
1025}
1026
1027func (typе *arrayType) Name(arch Arch) string {
1028	return fmt.Sprintf("%s[%d]", typе.elem.Name(arch), typе.size)
1029}
1030
1031func (*arrayType) Kind(Arch) Kind {
1032	return Array
1033}
1034
1035func (typе *arrayType) Elem(Arch) Type {
1036	return typе.elem
1037}
1038
1039func (typе *arrayType) Field(i uint, arch Arch) FieldInfo {
1040	panic("cpp_types: Calling Field() for non-struct type " + typе.Name(arch))
1041}
1042
1043func (typе *arrayType) NumField(arch Arch) uint {
1044	return typе.size
1045}
1046
1047func (typе *arrayType) Signed(arch Arch) bool {
1048	panic("cpp_types: Calling Signed() for non-numeric type " + typе.Name(arch))
1049}
1050
1051type structType struct {
1052	name   string
1053	fields []StructFieldInfo
1054	align  uint
1055	bits   uint
1056}
1057
1058func (typе *structType) Align(arch Arch) uint {
1059	return typе.align
1060}
1061
1062func (typе *structType) Bits(arch Arch) uint {
1063	return typе.bits
1064}
1065
1066func (typе *structType) DeclareVar(var_name string, arch Arch) string {
1067	return "struct " + typе.name + " " + var_name
1068}
1069
1070func (typе *structType) BaseName(arch Arch) string {
1071	return typе.name
1072}
1073
1074func (typе *structType) Name(arch Arch) string {
1075	return "struct " + typе.name
1076}
1077
1078func (*structType) Kind(Arch) Kind {
1079	return Struct
1080}
1081
1082func (typе *structType) Elem(Arch) Type {
1083	panic("cpp_types: Calling Elem() for non-array type " + typе.name)
1084}
1085
1086func (typе *structType) Field(i uint, arch Arch) FieldInfo {
1087	return typе.fields[i]
1088}
1089
1090func (typе *structType) NumField(arch Arch) uint {
1091	return uint(len(typе.fields))
1092}
1093
1094func (typе *structType) Signed(arch Arch) bool {
1095	panic("cpp_types: Calling Signed() for non-numeric type " + typе.Name(arch))
1096}
1097
1098type fieldInfo struct {
1099	name string
1100	typе Type
1101}
1102
1103func (field_info *fieldInfo) Name() string {
1104	return field_info.name
1105}
1106
1107func (field_info *fieldInfo) Type() Type {
1108	return field_info.typе
1109}
1110
1111func (field_info *fieldInfo) BaseFieldInfo() FieldInfo {
1112	return field_info
1113}
1114
1115type structFieldInfo struct {
1116	base_field_info FieldInfo
1117	offset          uint
1118}
1119
1120func (field_info *structFieldInfo) Name() string {
1121	return field_info.base_field_info.Name()
1122}
1123
1124func (field_info *structFieldInfo) Type() Type {
1125	return field_info.base_field_info.Type()
1126}
1127
1128func (field_info *structFieldInfo) BaseFieldInfo() FieldInfo {
1129	return field_info.base_field_info
1130}
1131
1132func (field_info *structFieldInfo) Offset() uint {
1133	return field_info.offset
1134}
1135
1136type unionType struct {
1137	name   string
1138	fields []FieldInfo
1139	align  uint
1140	bits   uint
1141}
1142
1143func (typе *unionType) Align(arch Arch) uint {
1144	return typе.align
1145}
1146
1147func (typе *unionType) Bits(arch Arch) uint {
1148	return typе.bits
1149}
1150
1151func (typе *unionType) DeclareVar(var_name string, arch Arch) string {
1152	return "union " + typе.name + " " + var_name
1153}
1154
1155func (typе *unionType) BaseName(arch Arch) string {
1156	return typе.name
1157}
1158
1159func (typе *unionType) Name(arch Arch) string {
1160	return "union " + typе.name
1161}
1162
1163func (*unionType) Kind(Arch) Kind {
1164	return Union
1165}
1166
1167func (typе *unionType) Elem(Arch) Type {
1168	panic("cpp_types: Calling Elem() for non-array type " + typе.name)
1169}
1170
1171func (typе *unionType) Field(i uint, arch Arch) FieldInfo {
1172	return typе.fields[i]
1173}
1174
1175func (typе *unionType) NumField(arch Arch) uint {
1176	return uint(len(typе.fields))
1177}
1178
1179func (typе *unionType) Signed(arch Arch) bool {
1180	panic("cpp_types: Calling Signed() for non-numeric type " + typе.Name(arch))
1181}
1182
1183type enumType struct {
1184	name     string
1185	basetype Type
1186	fields   []EnumFieldInfo
1187}
1188
1189func (typе *enumType) Align(arch Arch) uint {
1190	return typе.basetype.Align(arch)
1191}
1192
1193func (typе *enumType) Bits(arch Arch) uint {
1194	return typе.basetype.Bits(arch)
1195}
1196
1197func (typе *enumType) DeclareVar(var_name string, arch Arch) string {
1198	return typе.name + " " + var_name
1199}
1200
1201func (typе *enumType) BaseName(arch Arch) string {
1202	return typе.name
1203}
1204
1205func (typе *enumType) Name(arch Arch) string {
1206	return typе.name
1207}
1208
1209func (*enumType) Kind(Arch) Kind {
1210	return Enum
1211}
1212
1213func (typе *enumType) Elem(Arch) Type {
1214	return typе.basetype
1215}
1216
1217func (typе *enumType) Field(i uint, arch Arch) FieldInfo {
1218	return typе.fields[i]
1219}
1220
1221func (typе *enumType) NumField(arch Arch) uint {
1222	return uint(len(typе.fields))
1223}
1224
1225func (typе *enumType) Signed(arch Arch) bool {
1226	panic("cpp_types: Calling Signed() for non-numeric type " + typе.Name(arch))
1227}
1228
1229type enumFieldInfo struct {
1230	name  string
1231	typе  Type
1232	alias string
1233	value int64
1234}
1235
1236func (field_info *enumFieldInfo) Name() string {
1237	return field_info.name
1238}
1239
1240func (field_info *enumFieldInfo) Type() Type {
1241	return field_info.typе
1242}
1243
1244func (field_info *enumFieldInfo) BaseFieldInfo() FieldInfo {
1245	return field_info
1246}
1247
1248func (field_info *enumFieldInfo) Alias() string {
1249	return field_info.alias
1250}
1251
1252func (field_info *enumFieldInfo) Value() int64 {
1253	return field_info.value
1254}
1255
1256func IsCompatible(typе Type, host_arch, guest_arch Arch) bool {
1257	return IsInputCompatible(typе, host_arch, guest_arch) && IsInputCompatible(typе, guest_arch, host_arch)
1258}
1259
1260func IsInputCompatible(typе Type, host_arch, guest_arch Arch) bool {
1261	return isInputCompatible(typе, host_arch, typе, guest_arch, make(map[string]Type))
1262}
1263
1264func isInputCompatible(host_type Type, host_arch Arch, guest_type Type, guest_arch Arch, processed_structures map[string]Type) bool {
1265	kind := host_type.Kind(host_arch)
1266	if kind == Alias {
1267		return isInputCompatible(host_type.Elem(host_arch), host_arch, guest_type, guest_arch, processed_structures)
1268	}
1269	kind2 := guest_type.Kind(guest_arch)
1270	if kind2 == Alias {
1271		return isInputCompatible(host_type, host_arch, guest_type.Elem(host_arch), guest_arch, processed_structures)
1272	}
1273	if kind != kind2 {
1274		return false
1275	}
1276	// Functions are never automatically compatible
1277	if kind == Func {
1278		return false
1279	}
1280	// Strip const from both types (handles types like "const Func", "const void").
1281	if kind == Const {
1282		return isInputCompatible(host_type.Elem(host_arch), host_arch, guest_type.Elem(guest_arch), guest_arch, processed_structures)
1283	}
1284	// Opaque types and Void are compatible even if sizes and alignment are unknown
1285	if kind == Void || (kind == Opaque && host_type.Name(host_arch) == guest_type.Name(guest_arch)) {
1286		return true
1287	}
1288	if host_type.Bits(host_arch) != guest_type.Bits(guest_arch) {
1289		return false
1290	}
1291	// Objects in the guest memory should have at least the same alignment as in host to be passed to host functions.
1292	// For objects created in host memory we assume that guest code will never check their alignment.
1293	if guest_type.Align(guest_arch) < host_type.Align(host_arch) {
1294		return false
1295	}
1296	switch kind {
1297	case Array:
1298		return host_type.NumField(host_arch) == host_type.NumField(guest_arch) &&
1299			isInputCompatible(host_type.Elem(host_arch), host_arch, guest_type.Elem(guest_arch), guest_arch, processed_structures)
1300	case Enum:
1301		if !isInputCompatible(host_type.Elem(host_arch), host_arch, guest_type.Elem(guest_arch), guest_arch, processed_structures) {
1302			return false
1303		}
1304		for i := uint(0); i < host_type.NumField(host_arch); i++ {
1305			host_field_enum := host_type.Field(i, host_arch).(EnumFieldInfo)
1306			guest_field_enum := guest_type.Field(i, guest_arch).(EnumFieldInfo)
1307			if host_field_enum.Value() != guest_field_enum.Value() {
1308				return false
1309			}
1310		}
1311	case Ptr:
1312		return isInputCompatible(host_type.Elem(host_arch), host_arch, guest_type.Elem(guest_arch), guest_arch, processed_structures)
1313	case Struct, Union:
1314		name := host_type.Name(host_arch)
1315		if name != guest_type.Name(guest_arch) {
1316			return false
1317		}
1318		if _, ok := processed_structures[name]; ok {
1319			return true
1320		}
1321		processed_structures[name] = host_type
1322		if host_type.NumField(host_arch) != guest_type.NumField(guest_arch) {
1323			return false
1324		}
1325		for i := uint(0); i < host_type.NumField(host_arch); i++ {
1326			host_field := host_type.Field(i, host_arch)
1327			guest_field := guest_type.Field(i, guest_arch)
1328			if kind == Struct {
1329				host_field_struct := host_field.(StructFieldInfo)
1330				guest_field_struct := guest_field.(StructFieldInfo)
1331				if host_field_struct.Offset() != guest_field_struct.Offset() {
1332					return false
1333				}
1334			}
1335			if !isInputCompatible(host_field.Type(), host_arch, guest_field.Type(), guest_arch, processed_structures) {
1336				return false
1337			}
1338		}
1339		break
1340	}
1341	return true
1342}
1343
1344func IsKind(typе Type, kinds []Kind) bool {
1345	for i, kind := range kinds {
1346		for arch := FirstArch; arch < LastArch; arch++ {
1347			if typе.Kind(arch) != typе.Kind(LastArch) {
1348				panic("cpp_types: Calling IsKind() for arch-specific type " + typе.Name(arch) + "/" + typе.Name(LastArch))
1349			}
1350		}
1351		if typе.Kind(FirstArch) != kind {
1352			return false
1353		}
1354		if i+1 != len(kinds) {
1355			typе = typе.Elem(FirstArch)
1356		}
1357	}
1358	return true
1359}
1360