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