master
1index: CType.Index,
2
3pub const @"void": CType = .{ .index = .void };
4pub const @"bool": CType = .{ .index = .bool };
5pub const @"i8": CType = .{ .index = .int8_t };
6pub const @"u8": CType = .{ .index = .uint8_t };
7pub const @"i16": CType = .{ .index = .int16_t };
8pub const @"u16": CType = .{ .index = .uint16_t };
9pub const @"i32": CType = .{ .index = .int32_t };
10pub const @"u32": CType = .{ .index = .uint32_t };
11pub const @"i64": CType = .{ .index = .int64_t };
12pub const @"u64": CType = .{ .index = .uint64_t };
13pub const @"i128": CType = .{ .index = .zig_i128 };
14pub const @"u128": CType = .{ .index = .zig_u128 };
15pub const @"isize": CType = .{ .index = .intptr_t };
16pub const @"usize": CType = .{ .index = .uintptr_t };
17pub const @"f16": CType = .{ .index = .zig_f16 };
18pub const @"f32": CType = .{ .index = .zig_f32 };
19pub const @"f64": CType = .{ .index = .zig_f64 };
20pub const @"f80": CType = .{ .index = .zig_f80 };
21pub const @"f128": CType = .{ .index = .zig_f128 };
22
23pub fn fromPoolIndex(pool_index: usize) CType {
24 return .{ .index = @enumFromInt(CType.Index.first_pool_index + pool_index) };
25}
26
27pub fn toPoolIndex(ctype: CType) ?u32 {
28 const pool_index, const is_null =
29 @subWithOverflow(@intFromEnum(ctype.index), CType.Index.first_pool_index);
30 return switch (is_null) {
31 0 => pool_index,
32 1 => null,
33 };
34}
35
36pub fn eql(lhs: CType, rhs: CType) bool {
37 return lhs.index == rhs.index;
38}
39
40pub fn isBool(ctype: CType) bool {
41 return switch (ctype.index) {
42 ._Bool, .bool => true,
43 else => false,
44 };
45}
46
47pub fn isInteger(ctype: CType) bool {
48 return switch (ctype.index) {
49 .char,
50 .@"signed char",
51 .short,
52 .int,
53 .long,
54 .@"long long",
55 .@"unsigned char",
56 .@"unsigned short",
57 .@"unsigned int",
58 .@"unsigned long",
59 .@"unsigned long long",
60 .size_t,
61 .ptrdiff_t,
62 .uint8_t,
63 .int8_t,
64 .uint16_t,
65 .int16_t,
66 .uint32_t,
67 .int32_t,
68 .uint64_t,
69 .int64_t,
70 .uintptr_t,
71 .intptr_t,
72 .zig_u128,
73 .zig_i128,
74 => true,
75 else => false,
76 };
77}
78
79pub fn signedness(ctype: CType, mod: *Module) std.builtin.Signedness {
80 return switch (ctype.index) {
81 .char => mod.resolved_target.result.cCharSignedness(),
82 .@"signed char",
83 .short,
84 .int,
85 .long,
86 .@"long long",
87 .ptrdiff_t,
88 .int8_t,
89 .int16_t,
90 .int32_t,
91 .int64_t,
92 .intptr_t,
93 .zig_i128,
94 => .signed,
95 .@"unsigned char",
96 .@"unsigned short",
97 .@"unsigned int",
98 .@"unsigned long",
99 .@"unsigned long long",
100 .size_t,
101 .uint8_t,
102 .uint16_t,
103 .uint32_t,
104 .uint64_t,
105 .uintptr_t,
106 .zig_u128,
107 => .unsigned,
108 else => unreachable,
109 };
110}
111
112pub fn isFloat(ctype: CType) bool {
113 return switch (ctype.index) {
114 .float,
115 .double,
116 .@"long double",
117 .zig_f16,
118 .zig_f32,
119 .zig_f64,
120 .zig_f80,
121 .zig_f128,
122 .zig_c_longdouble,
123 => true,
124 else => false,
125 };
126}
127
128pub fn toSigned(ctype: CType) CType {
129 return switch (ctype.index) {
130 .char, .@"signed char", .@"unsigned char" => .{ .index = .@"signed char" },
131 .short, .@"unsigned short" => .{ .index = .short },
132 .int, .@"unsigned int" => .{ .index = .int },
133 .long, .@"unsigned long" => .{ .index = .long },
134 .@"long long", .@"unsigned long long" => .{ .index = .@"long long" },
135 .size_t, .ptrdiff_t => .{ .index = .ptrdiff_t },
136 .uint8_t, .int8_t => .{ .index = .int8_t },
137 .uint16_t, .int16_t => .{ .index = .int16_t },
138 .uint32_t, .int32_t => .{ .index = .int32_t },
139 .uint64_t, .int64_t => .{ .index = .int64_t },
140 .uintptr_t, .intptr_t => .{ .index = .intptr_t },
141 .zig_u128, .zig_i128 => .{ .index = .zig_i128 },
142 .float,
143 .double,
144 .@"long double",
145 .zig_f16,
146 .zig_f32,
147 .zig_f80,
148 .zig_f128,
149 .zig_c_longdouble,
150 => ctype,
151 else => unreachable,
152 };
153}
154
155pub fn toUnsigned(ctype: CType) CType {
156 return switch (ctype.index) {
157 .char, .@"signed char", .@"unsigned char" => .{ .index = .@"unsigned char" },
158 .short, .@"unsigned short" => .{ .index = .@"unsigned short" },
159 .int, .@"unsigned int" => .{ .index = .@"unsigned int" },
160 .long, .@"unsigned long" => .{ .index = .@"unsigned long" },
161 .@"long long", .@"unsigned long long" => .{ .index = .@"unsigned long long" },
162 .size_t, .ptrdiff_t => .{ .index = .size_t },
163 .uint8_t, .int8_t => .{ .index = .uint8_t },
164 .uint16_t, .int16_t => .{ .index = .uint16_t },
165 .uint32_t, .int32_t => .{ .index = .uint32_t },
166 .uint64_t, .int64_t => .{ .index = .uint64_t },
167 .uintptr_t, .intptr_t => .{ .index = .uintptr_t },
168 .zig_u128, .zig_i128 => .{ .index = .zig_u128 },
169 else => unreachable,
170 };
171}
172
173pub fn toSignedness(ctype: CType, s: std.builtin.Signedness) CType {
174 return switch (s) {
175 .unsigned => ctype.toUnsigned(),
176 .signed => ctype.toSigned(),
177 };
178}
179
180pub fn isAnyChar(ctype: CType) bool {
181 return switch (ctype.index) {
182 else => false,
183 .char, .@"signed char", .@"unsigned char", .uint8_t, .int8_t => true,
184 };
185}
186
187pub fn isString(ctype: CType, pool: *const Pool) bool {
188 return info: switch (ctype.info(pool)) {
189 .basic, .fwd_decl, .aggregate, .function => false,
190 .pointer => |pointer_info| pointer_info.elem_ctype.isAnyChar(),
191 .aligned => |aligned_info| continue :info aligned_info.ctype.info(pool),
192 .array, .vector => |sequence_info| sequence_info.elem_type.isAnyChar(),
193 };
194}
195
196pub fn isNonString(ctype: CType, pool: *const Pool) bool {
197 var allow_pointer = true;
198 return info: switch (ctype.info(pool)) {
199 .basic, .fwd_decl, .aggregate, .function => false,
200 .pointer => |pointer_info| allow_pointer and pointer_info.nonstring,
201 .aligned => |aligned_info| continue :info aligned_info.ctype.info(pool),
202 .array, .vector => |sequence_info| sequence_info.nonstring or {
203 allow_pointer = false;
204 continue :info sequence_info.elem_ctype.info(pool);
205 },
206 };
207}
208
209pub fn getStandardDefineAbbrev(ctype: CType) ?[]const u8 {
210 return switch (ctype.index) {
211 .char => "CHAR",
212 .@"signed char" => "SCHAR",
213 .short => "SHRT",
214 .int => "INT",
215 .long => "LONG",
216 .@"long long" => "LLONG",
217 .@"unsigned char" => "UCHAR",
218 .@"unsigned short" => "USHRT",
219 .@"unsigned int" => "UINT",
220 .@"unsigned long" => "ULONG",
221 .@"unsigned long long" => "ULLONG",
222 .float => "FLT",
223 .double => "DBL",
224 .@"long double" => "LDBL",
225 .size_t => "SIZE",
226 .ptrdiff_t => "PTRDIFF",
227 .uint8_t => "UINT8",
228 .int8_t => "INT8",
229 .uint16_t => "UINT16",
230 .int16_t => "INT16",
231 .uint32_t => "UINT32",
232 .int32_t => "INT32",
233 .uint64_t => "UINT64",
234 .int64_t => "INT64",
235 .uintptr_t => "UINTPTR",
236 .intptr_t => "INTPTR",
237 else => null,
238 };
239}
240
241pub fn renderLiteralPrefix(ctype: CType, w: *Writer, kind: Kind, pool: *const Pool) Writer.Error!void {
242 switch (ctype.info(pool)) {
243 .basic => |basic_info| switch (basic_info) {
244 .void => unreachable,
245 ._Bool,
246 .char,
247 .@"signed char",
248 .short,
249 .@"unsigned short",
250 .bool,
251 .size_t,
252 .ptrdiff_t,
253 .uintptr_t,
254 .intptr_t,
255 => switch (kind) {
256 else => try w.print("({s})", .{@tagName(basic_info)}),
257 .global => {},
258 },
259 .int,
260 .long,
261 .@"long long",
262 .@"unsigned char",
263 .@"unsigned int",
264 .@"unsigned long",
265 .@"unsigned long long",
266 .float,
267 .double,
268 .@"long double",
269 => {},
270 .uint8_t,
271 .int8_t,
272 .uint16_t,
273 .int16_t,
274 .uint32_t,
275 .int32_t,
276 .uint64_t,
277 .int64_t,
278 => try w.print("{s}_C(", .{ctype.getStandardDefineAbbrev().?}),
279 .zig_u128,
280 .zig_i128,
281 .zig_f16,
282 .zig_f32,
283 .zig_f64,
284 .zig_f80,
285 .zig_f128,
286 .zig_c_longdouble,
287 => try w.print("zig_{s}_{s}(", .{
288 switch (kind) {
289 else => "make",
290 .global => "init",
291 },
292 @tagName(basic_info)["zig_".len..],
293 }),
294 .va_list => unreachable,
295 _ => unreachable,
296 },
297 .array, .vector => try w.writeByte('{'),
298 else => unreachable,
299 }
300}
301
302pub fn renderLiteralSuffix(ctype: CType, w: *Writer, pool: *const Pool) Writer.Error!void {
303 switch (ctype.info(pool)) {
304 .basic => |basic_info| switch (basic_info) {
305 .void => unreachable,
306 ._Bool => {},
307 .char,
308 .@"signed char",
309 .short,
310 .int,
311 => {},
312 .long => try w.writeByte('l'),
313 .@"long long" => try w.writeAll("ll"),
314 .@"unsigned char",
315 .@"unsigned short",
316 .@"unsigned int",
317 => try w.writeByte('u'),
318 .@"unsigned long",
319 .size_t,
320 .uintptr_t,
321 => try w.writeAll("ul"),
322 .@"unsigned long long" => try w.writeAll("ull"),
323 .float => try w.writeByte('f'),
324 .double => {},
325 .@"long double" => try w.writeByte('l'),
326 .bool,
327 .ptrdiff_t,
328 .intptr_t,
329 => {},
330 .uint8_t,
331 .int8_t,
332 .uint16_t,
333 .int16_t,
334 .uint32_t,
335 .int32_t,
336 .uint64_t,
337 .int64_t,
338 .zig_u128,
339 .zig_i128,
340 .zig_f16,
341 .zig_f32,
342 .zig_f64,
343 .zig_f80,
344 .zig_f128,
345 .zig_c_longdouble,
346 => try w.writeByte(')'),
347 .va_list => unreachable,
348 _ => unreachable,
349 },
350 .array, .vector => try w.writeByte('}'),
351 else => unreachable,
352 }
353}
354
355pub fn floatActiveBits(ctype: CType, mod: *Module) u16 {
356 const target = &mod.resolved_target.result;
357 return switch (ctype.index) {
358 .float => target.cTypeBitSize(.float),
359 .double => target.cTypeBitSize(.double),
360 .@"long double", .zig_c_longdouble => target.cTypeBitSize(.longdouble),
361 .zig_f16 => 16,
362 .zig_f32 => 32,
363 .zig_f64 => 64,
364 .zig_f80 => 80,
365 .zig_f128 => 128,
366 else => unreachable,
367 };
368}
369
370pub fn byteSize(ctype: CType, pool: *const Pool, mod: *Module) u64 {
371 const target = &mod.resolved_target.result;
372 return switch (ctype.info(pool)) {
373 .basic => |basic_info| switch (basic_info) {
374 .void => 0,
375 .char, .@"signed char", ._Bool, .@"unsigned char", .bool, .uint8_t, .int8_t => 1,
376 .short => target.cTypeByteSize(.short),
377 .int => target.cTypeByteSize(.int),
378 .long => target.cTypeByteSize(.long),
379 .@"long long" => target.cTypeByteSize(.longlong),
380 .@"unsigned short" => target.cTypeByteSize(.ushort),
381 .@"unsigned int" => target.cTypeByteSize(.uint),
382 .@"unsigned long" => target.cTypeByteSize(.ulong),
383 .@"unsigned long long" => target.cTypeByteSize(.ulonglong),
384 .float => target.cTypeByteSize(.float),
385 .double => target.cTypeByteSize(.double),
386 .@"long double" => target.cTypeByteSize(.longdouble),
387 .size_t,
388 .ptrdiff_t,
389 .uintptr_t,
390 .intptr_t,
391 => @divExact(target.ptrBitWidth(), 8),
392 .uint16_t, .int16_t, .zig_f16 => 2,
393 .uint32_t, .int32_t, .zig_f32 => 4,
394 .uint64_t, .int64_t, .zig_f64 => 8,
395 .zig_u128, .zig_i128, .zig_f128 => 16,
396 .zig_f80 => if (target.cTypeBitSize(.longdouble) == 80)
397 target.cTypeByteSize(.longdouble)
398 else
399 16,
400 .zig_c_longdouble => target.cTypeByteSize(.longdouble),
401 .va_list => unreachable,
402 _ => unreachable,
403 },
404 .pointer => @divExact(target.ptrBitWidth(), 8),
405 .array, .vector => |sequence_info| sequence_info.elem_ctype.byteSize(pool, mod) * sequence_info.len,
406 else => unreachable,
407 };
408}
409
410pub fn info(ctype: CType, pool: *const Pool) Info {
411 const pool_index = ctype.toPoolIndex() orelse return .{ .basic = ctype.index };
412 const item = pool.items.get(pool_index);
413 switch (item.tag) {
414 .basic => unreachable,
415 .pointer => return .{ .pointer = .{
416 .elem_ctype = .{ .index = @enumFromInt(item.data) },
417 } },
418 .pointer_const => return .{ .pointer = .{
419 .elem_ctype = .{ .index = @enumFromInt(item.data) },
420 .@"const" = true,
421 } },
422 .pointer_volatile => return .{ .pointer = .{
423 .elem_ctype = .{ .index = @enumFromInt(item.data) },
424 .@"volatile" = true,
425 } },
426 .pointer_const_volatile => return .{ .pointer = .{
427 .elem_ctype = .{ .index = @enumFromInt(item.data) },
428 .@"const" = true,
429 .@"volatile" = true,
430 } },
431 .aligned => {
432 const extra = pool.getExtra(Pool.Aligned, item.data);
433 return .{ .aligned = .{
434 .ctype = .{ .index = extra.ctype },
435 .alignas = extra.flags.alignas,
436 } };
437 },
438 .array_small => {
439 const extra = pool.getExtra(Pool.SequenceSmall, item.data);
440 return .{ .array = .{
441 .elem_ctype = .{ .index = extra.elem_ctype },
442 .len = extra.len,
443 } };
444 },
445 .array_large => {
446 const extra = pool.getExtra(Pool.SequenceLarge, item.data);
447 return .{ .array = .{
448 .elem_ctype = .{ .index = extra.elem_ctype },
449 .len = extra.len(),
450 } };
451 },
452 .vector => {
453 const extra = pool.getExtra(Pool.SequenceSmall, item.data);
454 return .{ .vector = .{
455 .elem_ctype = .{ .index = extra.elem_ctype },
456 .len = extra.len,
457 } };
458 },
459 .nonstring => {
460 var child_info = info(.{ .index = @enumFromInt(item.data) }, pool);
461 switch (child_info) {
462 else => unreachable,
463 .pointer => |*pointer_info| pointer_info.nonstring = true,
464 .array, .vector => |*sequence_info| sequence_info.nonstring = true,
465 }
466 return child_info;
467 },
468 .fwd_decl_struct_anon => {
469 const extra_trail = pool.getExtraTrail(Pool.FwdDeclAnon, item.data);
470 return .{ .fwd_decl = .{
471 .tag = .@"struct",
472 .name = .{ .anon = .{
473 .extra_index = extra_trail.trail.extra_index,
474 .len = extra_trail.extra.fields_len,
475 } },
476 } };
477 },
478 .fwd_decl_union_anon => {
479 const extra_trail = pool.getExtraTrail(Pool.FwdDeclAnon, item.data);
480 return .{ .fwd_decl = .{
481 .tag = .@"union",
482 .name = .{ .anon = .{
483 .extra_index = extra_trail.trail.extra_index,
484 .len = extra_trail.extra.fields_len,
485 } },
486 } };
487 },
488 .fwd_decl_struct => return .{ .fwd_decl = .{
489 .tag = .@"struct",
490 .name = .{ .index = @enumFromInt(item.data) },
491 } },
492 .fwd_decl_union => return .{ .fwd_decl = .{
493 .tag = .@"union",
494 .name = .{ .index = @enumFromInt(item.data) },
495 } },
496 .aggregate_struct_anon => {
497 const extra_trail = pool.getExtraTrail(Pool.AggregateAnon, item.data);
498 return .{ .aggregate = .{
499 .tag = .@"struct",
500 .name = .{ .anon = .{
501 .index = extra_trail.extra.index,
502 .id = extra_trail.extra.id,
503 } },
504 .fields = .{
505 .extra_index = extra_trail.trail.extra_index,
506 .len = extra_trail.extra.fields_len,
507 },
508 } };
509 },
510 .aggregate_union_anon => {
511 const extra_trail = pool.getExtraTrail(Pool.AggregateAnon, item.data);
512 return .{ .aggregate = .{
513 .tag = .@"union",
514 .name = .{ .anon = .{
515 .index = extra_trail.extra.index,
516 .id = extra_trail.extra.id,
517 } },
518 .fields = .{
519 .extra_index = extra_trail.trail.extra_index,
520 .len = extra_trail.extra.fields_len,
521 },
522 } };
523 },
524 .aggregate_struct_packed_anon => {
525 const extra_trail = pool.getExtraTrail(Pool.AggregateAnon, item.data);
526 return .{ .aggregate = .{
527 .tag = .@"struct",
528 .@"packed" = true,
529 .name = .{ .anon = .{
530 .index = extra_trail.extra.index,
531 .id = extra_trail.extra.id,
532 } },
533 .fields = .{
534 .extra_index = extra_trail.trail.extra_index,
535 .len = extra_trail.extra.fields_len,
536 },
537 } };
538 },
539 .aggregate_union_packed_anon => {
540 const extra_trail = pool.getExtraTrail(Pool.AggregateAnon, item.data);
541 return .{ .aggregate = .{
542 .tag = .@"union",
543 .@"packed" = true,
544 .name = .{ .anon = .{
545 .index = extra_trail.extra.index,
546 .id = extra_trail.extra.id,
547 } },
548 .fields = .{
549 .extra_index = extra_trail.trail.extra_index,
550 .len = extra_trail.extra.fields_len,
551 },
552 } };
553 },
554 .aggregate_struct => {
555 const extra_trail = pool.getExtraTrail(Pool.Aggregate, item.data);
556 return .{ .aggregate = .{
557 .tag = .@"struct",
558 .name = .{ .fwd_decl = .{ .index = extra_trail.extra.fwd_decl } },
559 .fields = .{
560 .extra_index = extra_trail.trail.extra_index,
561 .len = extra_trail.extra.fields_len,
562 },
563 } };
564 },
565 .aggregate_union => {
566 const extra_trail = pool.getExtraTrail(Pool.Aggregate, item.data);
567 return .{ .aggregate = .{
568 .tag = .@"union",
569 .name = .{ .fwd_decl = .{ .index = extra_trail.extra.fwd_decl } },
570 .fields = .{
571 .extra_index = extra_trail.trail.extra_index,
572 .len = extra_trail.extra.fields_len,
573 },
574 } };
575 },
576 .aggregate_struct_packed => {
577 const extra_trail = pool.getExtraTrail(Pool.Aggregate, item.data);
578 return .{ .aggregate = .{
579 .tag = .@"struct",
580 .@"packed" = true,
581 .name = .{ .fwd_decl = .{ .index = extra_trail.extra.fwd_decl } },
582 .fields = .{
583 .extra_index = extra_trail.trail.extra_index,
584 .len = extra_trail.extra.fields_len,
585 },
586 } };
587 },
588 .aggregate_union_packed => {
589 const extra_trail = pool.getExtraTrail(Pool.Aggregate, item.data);
590 return .{ .aggregate = .{
591 .tag = .@"union",
592 .@"packed" = true,
593 .name = .{ .fwd_decl = .{ .index = extra_trail.extra.fwd_decl } },
594 .fields = .{
595 .extra_index = extra_trail.trail.extra_index,
596 .len = extra_trail.extra.fields_len,
597 },
598 } };
599 },
600 .function => {
601 const extra_trail = pool.getExtraTrail(Pool.Function, item.data);
602 return .{ .function = .{
603 .return_ctype = .{ .index = extra_trail.extra.return_ctype },
604 .param_ctypes = .{
605 .extra_index = extra_trail.trail.extra_index,
606 .len = extra_trail.extra.param_ctypes_len,
607 },
608 .varargs = false,
609 } };
610 },
611 .function_varargs => {
612 const extra_trail = pool.getExtraTrail(Pool.Function, item.data);
613 return .{ .function = .{
614 .return_ctype = .{ .index = extra_trail.extra.return_ctype },
615 .param_ctypes = .{
616 .extra_index = extra_trail.trail.extra_index,
617 .len = extra_trail.extra.param_ctypes_len,
618 },
619 .varargs = true,
620 } };
621 },
622 }
623}
624
625pub fn hash(ctype: CType, pool: *const Pool) Pool.Map.Hash {
626 return if (ctype.toPoolIndex()) |pool_index|
627 pool.map.entries.items(.hash)[pool_index]
628 else
629 CType.Index.basic_hashes[@intFromEnum(ctype.index)];
630}
631
632fn toForward(ctype: CType, pool: *Pool, allocator: std.mem.Allocator) !CType {
633 return switch (ctype.info(pool)) {
634 .basic, .pointer, .fwd_decl => ctype,
635 .aligned => |aligned_info| pool.getAligned(allocator, .{
636 .ctype = try aligned_info.ctype.toForward(pool, allocator),
637 .alignas = aligned_info.alignas,
638 }),
639 .array => |array_info| pool.getArray(allocator, .{
640 .elem_ctype = try array_info.elem_ctype.toForward(pool, allocator),
641 .len = array_info.len,
642 .nonstring = array_info.nonstring,
643 }),
644 .vector => |vector_info| pool.getVector(allocator, .{
645 .elem_ctype = try vector_info.elem_ctype.toForward(pool, allocator),
646 .len = vector_info.len,
647 .nonstring = vector_info.nonstring,
648 }),
649 .aggregate => |aggregate_info| switch (aggregate_info.name) {
650 .anon => ctype,
651 .fwd_decl => |fwd_decl| fwd_decl,
652 },
653 .function => unreachable,
654 };
655}
656
657const Index = enum(u32) {
658 void,
659
660 // C basic types
661 char,
662
663 @"signed char",
664 short,
665 int,
666 long,
667 @"long long",
668
669 _Bool,
670 @"unsigned char",
671 @"unsigned short",
672 @"unsigned int",
673 @"unsigned long",
674 @"unsigned long long",
675
676 float,
677 double,
678 @"long double",
679
680 // C header types
681 // - stdbool.h
682 bool,
683 // - stddef.h
684 size_t,
685 ptrdiff_t,
686 // - stdint.h
687 uint8_t,
688 int8_t,
689 uint16_t,
690 int16_t,
691 uint32_t,
692 int32_t,
693 uint64_t,
694 int64_t,
695 uintptr_t,
696 intptr_t,
697 // - stdarg.h
698 va_list,
699
700 // zig.h types
701 zig_u128,
702 zig_i128,
703 zig_f16,
704 zig_f32,
705 zig_f64,
706 zig_f80,
707 zig_f128,
708 zig_c_longdouble,
709
710 _,
711
712 const first_pool_index: u32 = @typeInfo(CType.Index).@"enum".fields.len;
713 const basic_hashes = init: {
714 @setEvalBranchQuota(1_600);
715 var basic_hashes_init: [first_pool_index]Pool.Map.Hash = undefined;
716 for (&basic_hashes_init, 0..) |*basic_hash, index| {
717 const ctype_index: CType.Index = @enumFromInt(index);
718 var hasher = Pool.Hasher.init;
719 hasher.update(@intFromEnum(ctype_index));
720 basic_hash.* = hasher.final(.basic);
721 }
722 break :init basic_hashes_init;
723 };
724};
725
726const Slice = struct {
727 extra_index: Pool.ExtraIndex,
728 len: u32,
729
730 pub fn at(slice: CType.Slice, index: usize, pool: *const Pool) CType {
731 var extra: Pool.ExtraTrail = .{ .extra_index = slice.extra_index };
732 return .{ .index = extra.next(slice.len, CType.Index, pool)[index] };
733 }
734};
735
736pub const Kind = enum {
737 forward,
738 forward_parameter,
739 complete,
740 global,
741 parameter,
742
743 pub fn isForward(kind: Kind) bool {
744 return switch (kind) {
745 .forward, .forward_parameter => true,
746 .complete, .global, .parameter => false,
747 };
748 }
749
750 pub fn isParameter(kind: Kind) bool {
751 return switch (kind) {
752 .forward_parameter, .parameter => true,
753 .forward, .complete, .global => false,
754 };
755 }
756
757 pub fn asParameter(kind: Kind) Kind {
758 return switch (kind) {
759 .forward, .forward_parameter => .forward_parameter,
760 .complete, .parameter, .global => .parameter,
761 };
762 }
763
764 pub fn noParameter(kind: Kind) Kind {
765 return switch (kind) {
766 .forward, .forward_parameter => .forward,
767 .complete, .parameter => .complete,
768 .global => .global,
769 };
770 }
771
772 pub fn asComplete(kind: Kind) Kind {
773 return switch (kind) {
774 .forward, .complete => .complete,
775 .forward_parameter, .parameter => .parameter,
776 .global => .global,
777 };
778 }
779};
780
781pub const Info = union(enum) {
782 basic: CType.Index,
783 pointer: Pointer,
784 aligned: Aligned,
785 array: Sequence,
786 vector: Sequence,
787 fwd_decl: FwdDecl,
788 aggregate: Aggregate,
789 function: Function,
790
791 const Tag = @typeInfo(Info).@"union".tag_type.?;
792
793 pub const Pointer = struct {
794 elem_ctype: CType,
795 @"const": bool = false,
796 @"volatile": bool = false,
797 nonstring: bool = false,
798
799 fn tag(pointer_info: Pointer) Pool.Tag {
800 return @enumFromInt(@intFromEnum(Pool.Tag.pointer) +
801 @as(u2, @bitCast(packed struct(u2) {
802 @"const": bool,
803 @"volatile": bool,
804 }{
805 .@"const" = pointer_info.@"const",
806 .@"volatile" = pointer_info.@"volatile",
807 })));
808 }
809 };
810
811 pub const Aligned = struct {
812 ctype: CType,
813 alignas: AlignAs,
814 };
815
816 pub const Sequence = struct {
817 elem_ctype: CType,
818 len: u64,
819 nonstring: bool = false,
820 };
821
822 pub const AggregateTag = enum { @"enum", @"struct", @"union" };
823
824 pub const Field = struct {
825 name: Pool.String,
826 ctype: CType,
827 alignas: AlignAs,
828
829 pub const Slice = struct {
830 extra_index: Pool.ExtraIndex,
831 len: u32,
832
833 pub fn at(slice: Field.Slice, index: usize, pool: *const Pool) Field {
834 assert(index < slice.len);
835 const extra = pool.getExtra(Pool.Field, @intCast(slice.extra_index +
836 index * @typeInfo(Pool.Field).@"struct".fields.len));
837 return .{
838 .name = .{ .index = extra.name },
839 .ctype = .{ .index = extra.ctype },
840 .alignas = extra.flags.alignas,
841 };
842 }
843
844 fn eqlAdapted(
845 lhs_slice: Field.Slice,
846 lhs_pool: *const Pool,
847 rhs_slice: Field.Slice,
848 rhs_pool: *const Pool,
849 pool_adapter: anytype,
850 ) bool {
851 if (lhs_slice.len != rhs_slice.len) return false;
852 for (0..lhs_slice.len) |index| {
853 if (!lhs_slice.at(index, lhs_pool).eqlAdapted(
854 lhs_pool,
855 rhs_slice.at(index, rhs_pool),
856 rhs_pool,
857 pool_adapter,
858 )) return false;
859 }
860 return true;
861 }
862 };
863
864 fn eqlAdapted(
865 lhs_field: Field,
866 lhs_pool: *const Pool,
867 rhs_field: Field,
868 rhs_pool: *const Pool,
869 pool_adapter: anytype,
870 ) bool {
871 if (!std.meta.eql(lhs_field.alignas, rhs_field.alignas)) return false;
872 if (!pool_adapter.eql(lhs_field.ctype, rhs_field.ctype)) return false;
873 return if (lhs_field.name.toPoolSlice(lhs_pool)) |lhs_name|
874 if (rhs_field.name.toPoolSlice(rhs_pool)) |rhs_name|
875 std.mem.eql(u8, lhs_name, rhs_name)
876 else
877 false
878 else
879 lhs_field.name.index == rhs_field.name.index;
880 }
881 };
882
883 pub const FwdDecl = struct {
884 tag: AggregateTag,
885 name: union(enum) {
886 anon: Field.Slice,
887 index: InternPool.Index,
888 },
889 };
890
891 pub const Aggregate = struct {
892 tag: AggregateTag,
893 @"packed": bool = false,
894 name: union(enum) {
895 anon: struct {
896 index: InternPool.Index,
897 id: u32,
898 },
899 fwd_decl: CType,
900 },
901 fields: Field.Slice,
902 };
903
904 pub const Function = struct {
905 return_ctype: CType,
906 param_ctypes: CType.Slice,
907 varargs: bool = false,
908 };
909
910 pub fn eqlAdapted(
911 lhs_info: Info,
912 lhs_pool: *const Pool,
913 rhs_ctype: CType,
914 rhs_pool: *const Pool,
915 pool_adapter: anytype,
916 ) bool {
917 const rhs_info = rhs_ctype.info(rhs_pool);
918 if (@as(Info.Tag, lhs_info) != @as(Info.Tag, rhs_info)) return false;
919 return switch (lhs_info) {
920 .basic => |lhs_basic_info| lhs_basic_info == rhs_info.basic,
921 .pointer => |lhs_pointer_info| lhs_pointer_info.@"const" == rhs_info.pointer.@"const" and
922 lhs_pointer_info.@"volatile" == rhs_info.pointer.@"volatile" and
923 lhs_pointer_info.nonstring == rhs_info.pointer.nonstring and
924 pool_adapter.eql(lhs_pointer_info.elem_ctype, rhs_info.pointer.elem_ctype),
925 .aligned => |lhs_aligned_info| std.meta.eql(lhs_aligned_info.alignas, rhs_info.aligned.alignas) and
926 pool_adapter.eql(lhs_aligned_info.ctype, rhs_info.aligned.ctype),
927 .array => |lhs_array_info| lhs_array_info.len == rhs_info.array.len and
928 lhs_array_info.nonstring == rhs_info.array.nonstring and
929 pool_adapter.eql(lhs_array_info.elem_ctype, rhs_info.array.elem_ctype),
930 .vector => |lhs_vector_info| lhs_vector_info.len == rhs_info.vector.len and
931 lhs_vector_info.nonstring == rhs_info.vector.nonstring and
932 pool_adapter.eql(lhs_vector_info.elem_ctype, rhs_info.vector.elem_ctype),
933 .fwd_decl => |lhs_fwd_decl_info| lhs_fwd_decl_info.tag == rhs_info.fwd_decl.tag and
934 switch (lhs_fwd_decl_info.name) {
935 .anon => |lhs_anon| rhs_info.fwd_decl.name == .anon and lhs_anon.eqlAdapted(
936 lhs_pool,
937 rhs_info.fwd_decl.name.anon,
938 rhs_pool,
939 pool_adapter,
940 ),
941 .index => |lhs_index| rhs_info.fwd_decl.name == .index and
942 lhs_index == rhs_info.fwd_decl.name.index,
943 },
944 .aggregate => |lhs_aggregate_info| lhs_aggregate_info.tag == rhs_info.aggregate.tag and
945 lhs_aggregate_info.@"packed" == rhs_info.aggregate.@"packed" and
946 switch (lhs_aggregate_info.name) {
947 .anon => |lhs_anon| rhs_info.aggregate.name == .anon and
948 lhs_anon.index == rhs_info.aggregate.name.anon.index and
949 lhs_anon.id == rhs_info.aggregate.name.anon.id,
950 .fwd_decl => |lhs_fwd_decl| rhs_info.aggregate.name == .fwd_decl and
951 pool_adapter.eql(lhs_fwd_decl, rhs_info.aggregate.name.fwd_decl),
952 } and lhs_aggregate_info.fields.eqlAdapted(
953 lhs_pool,
954 rhs_info.aggregate.fields,
955 rhs_pool,
956 pool_adapter,
957 ),
958 .function => |lhs_function_info| lhs_function_info.param_ctypes.len ==
959 rhs_info.function.param_ctypes.len and
960 pool_adapter.eql(lhs_function_info.return_ctype, rhs_info.function.return_ctype) and
961 for (0..lhs_function_info.param_ctypes.len) |param_index| {
962 if (!pool_adapter.eql(
963 lhs_function_info.param_ctypes.at(param_index, lhs_pool),
964 rhs_info.function.param_ctypes.at(param_index, rhs_pool),
965 )) break false;
966 } else true,
967 };
968 }
969};
970
971pub const Pool = struct {
972 map: Map,
973 items: std.MultiArrayList(Item),
974 extra: std.ArrayList(u32),
975
976 string_map: Map,
977 string_indices: std.ArrayList(u32),
978 string_bytes: std.ArrayList(u8),
979
980 const Map = std.AutoArrayHashMapUnmanaged(void, void);
981
982 pub const String = struct {
983 index: String.Index,
984
985 const FormatData = struct { string: String, pool: *const Pool };
986 fn format(data: FormatData, writer: *Writer) Writer.Error!void {
987 if (data.string.toSlice(data.pool)) |slice|
988 try writer.writeAll(slice)
989 else
990 try writer.print("f{d}", .{@intFromEnum(data.string.index)});
991 }
992 pub fn fmt(str: String, pool: *const Pool) std.fmt.Alt(FormatData, format) {
993 return .{ .data = .{ .string = str, .pool = pool } };
994 }
995
996 fn fromUnnamed(index: u31) String {
997 return .{ .index = @enumFromInt(index) };
998 }
999
1000 fn isNamed(str: String) bool {
1001 return @intFromEnum(str.index) >= String.Index.first_named_index;
1002 }
1003
1004 pub fn toSlice(str: String, pool: *const Pool) ?[]const u8 {
1005 return str.toPoolSlice(pool) orelse if (str.isNamed()) @tagName(str.index) else null;
1006 }
1007
1008 fn toPoolSlice(str: String, pool: *const Pool) ?[]const u8 {
1009 if (str.toPoolIndex()) |pool_index| {
1010 const start = pool.string_indices.items[pool_index + 0];
1011 const end = pool.string_indices.items[pool_index + 1];
1012 return pool.string_bytes.items[start..end];
1013 } else return null;
1014 }
1015
1016 fn fromPoolIndex(pool_index: usize) String {
1017 return .{ .index = @enumFromInt(String.Index.first_pool_index + pool_index) };
1018 }
1019
1020 fn toPoolIndex(str: String) ?u32 {
1021 const pool_index, const is_null =
1022 @subWithOverflow(@intFromEnum(str.index), String.Index.first_pool_index);
1023 return switch (is_null) {
1024 0 => pool_index,
1025 1 => null,
1026 };
1027 }
1028
1029 const Index = enum(u32) {
1030 array = first_named_index,
1031 @"error",
1032 is_null,
1033 len,
1034 payload,
1035 ptr,
1036 tag,
1037 _,
1038
1039 const first_named_index: u32 = 1 << 31;
1040 const first_pool_index: u32 = first_named_index + @typeInfo(String.Index).@"enum".fields.len;
1041 };
1042
1043 const Adapter = struct {
1044 pool: *const Pool,
1045 pub fn hash(_: @This(), slice: []const u8) Map.Hash {
1046 return @truncate(Hasher.Impl.hash(1, slice));
1047 }
1048 pub fn eql(string_adapter: @This(), lhs_slice: []const u8, _: void, rhs_index: usize) bool {
1049 const rhs_string = String.fromPoolIndex(rhs_index);
1050 const rhs_slice = rhs_string.toPoolSlice(string_adapter.pool).?;
1051 return std.mem.eql(u8, lhs_slice, rhs_slice);
1052 }
1053 };
1054 };
1055
1056 pub const empty: Pool = .{
1057 .map = .{},
1058 .items = .{},
1059 .extra = .{},
1060
1061 .string_map = .{},
1062 .string_indices = .{},
1063 .string_bytes = .{},
1064 };
1065
1066 pub fn init(pool: *Pool, allocator: std.mem.Allocator) !void {
1067 if (pool.string_indices.items.len == 0)
1068 try pool.string_indices.append(allocator, 0);
1069 }
1070
1071 pub fn deinit(pool: *Pool, allocator: std.mem.Allocator) void {
1072 pool.map.deinit(allocator);
1073 pool.items.deinit(allocator);
1074 pool.extra.deinit(allocator);
1075
1076 pool.string_map.deinit(allocator);
1077 pool.string_indices.deinit(allocator);
1078 pool.string_bytes.deinit(allocator);
1079
1080 pool.* = undefined;
1081 }
1082
1083 pub fn move(pool: *Pool) Pool {
1084 defer pool.* = empty;
1085 return pool.*;
1086 }
1087
1088 pub fn clearRetainingCapacity(pool: *Pool) void {
1089 pool.map.clearRetainingCapacity();
1090 pool.items.shrinkRetainingCapacity(0);
1091 pool.extra.clearRetainingCapacity();
1092
1093 pool.string_map.clearRetainingCapacity();
1094 pool.string_indices.shrinkRetainingCapacity(1);
1095 pool.string_bytes.clearRetainingCapacity();
1096 }
1097
1098 pub fn freeUnusedCapacity(pool: *Pool, allocator: std.mem.Allocator) void {
1099 pool.map.shrinkAndFree(allocator, pool.map.count());
1100 pool.items.shrinkAndFree(allocator, pool.items.len);
1101 pool.extra.shrinkAndFree(allocator, pool.extra.items.len);
1102
1103 pool.string_map.shrinkAndFree(allocator, pool.string_map.count());
1104 pool.string_indices.shrinkAndFree(allocator, pool.string_indices.items.len);
1105 pool.string_bytes.shrinkAndFree(allocator, pool.string_bytes.items.len);
1106 }
1107
1108 pub fn getPointer(pool: *Pool, allocator: std.mem.Allocator, pointer_info: Info.Pointer) !CType {
1109 var hasher = Hasher.init;
1110 hasher.update(pointer_info.elem_ctype.hash(pool));
1111 return pool.getNonString(allocator, try pool.tagData(
1112 allocator,
1113 hasher,
1114 pointer_info.tag(),
1115 @intFromEnum(pointer_info.elem_ctype.index),
1116 ), pointer_info.nonstring);
1117 }
1118
1119 pub fn getAligned(pool: *Pool, allocator: std.mem.Allocator, aligned_info: Info.Aligned) !CType {
1120 return pool.tagExtra(allocator, .aligned, Aligned, .{
1121 .ctype = aligned_info.ctype.index,
1122 .flags = .{ .alignas = aligned_info.alignas },
1123 });
1124 }
1125
1126 pub fn getArray(pool: *Pool, allocator: std.mem.Allocator, array_info: Info.Sequence) !CType {
1127 return pool.getNonString(allocator, if (std.math.cast(u32, array_info.len)) |small_len|
1128 try pool.tagExtra(allocator, .array_small, SequenceSmall, .{
1129 .elem_ctype = array_info.elem_ctype.index,
1130 .len = small_len,
1131 })
1132 else
1133 try pool.tagExtra(allocator, .array_large, SequenceLarge, .{
1134 .elem_ctype = array_info.elem_ctype.index,
1135 .len_lo = @truncate(array_info.len >> 0),
1136 .len_hi = @truncate(array_info.len >> 32),
1137 }), array_info.nonstring);
1138 }
1139
1140 pub fn getVector(pool: *Pool, allocator: std.mem.Allocator, vector_info: Info.Sequence) !CType {
1141 return pool.getNonString(allocator, try pool.tagExtra(allocator, .vector, SequenceSmall, .{
1142 .elem_ctype = vector_info.elem_ctype.index,
1143 .len = @intCast(vector_info.len),
1144 }), vector_info.nonstring);
1145 }
1146
1147 pub fn getNonString(
1148 pool: *Pool,
1149 allocator: std.mem.Allocator,
1150 child_ctype: CType,
1151 nonstring: bool,
1152 ) !CType {
1153 if (!nonstring) return child_ctype;
1154 var hasher = Hasher.init;
1155 hasher.update(child_ctype.hash(pool));
1156 return pool.tagData(allocator, hasher, .nonstring, @intFromEnum(child_ctype.index));
1157 }
1158
1159 pub fn getFwdDecl(
1160 pool: *Pool,
1161 allocator: std.mem.Allocator,
1162 fwd_decl_info: struct {
1163 tag: Info.AggregateTag,
1164 name: union(enum) {
1165 anon: []const Info.Field,
1166 index: InternPool.Index,
1167 },
1168 },
1169 ) !CType {
1170 var hasher = Hasher.init;
1171 switch (fwd_decl_info.name) {
1172 .anon => |fields| {
1173 const ExpectedContents = [32]CType;
1174 var stack align(@max(
1175 @alignOf(std.heap.StackFallbackAllocator(0)),
1176 @alignOf(ExpectedContents),
1177 )) = std.heap.stackFallback(@sizeOf(ExpectedContents), allocator);
1178 const stack_allocator = stack.get();
1179 const field_ctypes = try stack_allocator.alloc(CType, fields.len);
1180 defer stack_allocator.free(field_ctypes);
1181 for (field_ctypes, fields) |*field_ctype, field|
1182 field_ctype.* = try field.ctype.toForward(pool, allocator);
1183 const extra: FwdDeclAnon = .{ .fields_len = @intCast(fields.len) };
1184 const extra_index = try pool.addExtra(
1185 allocator,
1186 FwdDeclAnon,
1187 extra,
1188 fields.len * @typeInfo(Field).@"struct".fields.len,
1189 );
1190 for (fields, field_ctypes) |field, field_ctype| pool.addHashedExtraAssumeCapacity(
1191 &hasher,
1192 Field,
1193 .{
1194 .name = field.name.index,
1195 .ctype = field_ctype.index,
1196 .flags = .{ .alignas = field.alignas },
1197 },
1198 );
1199 hasher.updateExtra(FwdDeclAnon, extra, pool);
1200 return pool.tagTrailingExtra(allocator, hasher, switch (fwd_decl_info.tag) {
1201 .@"struct" => .fwd_decl_struct_anon,
1202 .@"union" => .fwd_decl_union_anon,
1203 .@"enum" => unreachable,
1204 }, extra_index);
1205 },
1206 .index => |index| {
1207 hasher.update(index);
1208 return pool.tagData(allocator, hasher, switch (fwd_decl_info.tag) {
1209 .@"struct" => .fwd_decl_struct,
1210 .@"union" => .fwd_decl_union,
1211 .@"enum" => unreachable,
1212 }, @intFromEnum(index));
1213 },
1214 }
1215 }
1216
1217 pub fn getAggregate(
1218 pool: *Pool,
1219 allocator: std.mem.Allocator,
1220 aggregate_info: struct {
1221 tag: Info.AggregateTag,
1222 @"packed": bool = false,
1223 name: union(enum) {
1224 anon: struct {
1225 index: InternPool.Index,
1226 id: u32,
1227 },
1228 fwd_decl: CType,
1229 },
1230 fields: []const Info.Field,
1231 },
1232 ) !CType {
1233 var hasher = Hasher.init;
1234 switch (aggregate_info.name) {
1235 .anon => |anon| {
1236 const extra: AggregateAnon = .{
1237 .index = anon.index,
1238 .id = anon.id,
1239 .fields_len = @intCast(aggregate_info.fields.len),
1240 };
1241 const extra_index = try pool.addExtra(
1242 allocator,
1243 AggregateAnon,
1244 extra,
1245 aggregate_info.fields.len * @typeInfo(Field).@"struct".fields.len,
1246 );
1247 for (aggregate_info.fields) |field| pool.addHashedExtraAssumeCapacity(&hasher, Field, .{
1248 .name = field.name.index,
1249 .ctype = field.ctype.index,
1250 .flags = .{ .alignas = field.alignas },
1251 });
1252 hasher.updateExtra(AggregateAnon, extra, pool);
1253 return pool.tagTrailingExtra(allocator, hasher, switch (aggregate_info.tag) {
1254 .@"struct" => switch (aggregate_info.@"packed") {
1255 false => .aggregate_struct_anon,
1256 true => .aggregate_struct_packed_anon,
1257 },
1258 .@"union" => switch (aggregate_info.@"packed") {
1259 false => .aggregate_union_anon,
1260 true => .aggregate_union_packed_anon,
1261 },
1262 .@"enum" => unreachable,
1263 }, extra_index);
1264 },
1265 .fwd_decl => |fwd_decl| {
1266 const extra: Aggregate = .{
1267 .fwd_decl = fwd_decl.index,
1268 .fields_len = @intCast(aggregate_info.fields.len),
1269 };
1270 const extra_index = try pool.addExtra(
1271 allocator,
1272 Aggregate,
1273 extra,
1274 aggregate_info.fields.len * @typeInfo(Field).@"struct".fields.len,
1275 );
1276 for (aggregate_info.fields) |field| pool.addHashedExtraAssumeCapacity(&hasher, Field, .{
1277 .name = field.name.index,
1278 .ctype = field.ctype.index,
1279 .flags = .{ .alignas = field.alignas },
1280 });
1281 hasher.updateExtra(Aggregate, extra, pool);
1282 return pool.tagTrailingExtra(allocator, hasher, switch (aggregate_info.tag) {
1283 .@"struct" => switch (aggregate_info.@"packed") {
1284 false => .aggregate_struct,
1285 true => .aggregate_struct_packed,
1286 },
1287 .@"union" => switch (aggregate_info.@"packed") {
1288 false => .aggregate_union,
1289 true => .aggregate_union_packed,
1290 },
1291 .@"enum" => unreachable,
1292 }, extra_index);
1293 },
1294 }
1295 }
1296
1297 pub fn getFunction(
1298 pool: *Pool,
1299 allocator: std.mem.Allocator,
1300 function_info: struct {
1301 return_ctype: CType,
1302 param_ctypes: []const CType,
1303 varargs: bool = false,
1304 },
1305 ) !CType {
1306 var hasher = Hasher.init;
1307 const extra: Function = .{
1308 .return_ctype = function_info.return_ctype.index,
1309 .param_ctypes_len = @intCast(function_info.param_ctypes.len),
1310 };
1311 const extra_index = try pool.addExtra(allocator, Function, extra, function_info.param_ctypes.len);
1312 for (function_info.param_ctypes) |param_ctype| {
1313 hasher.update(param_ctype.hash(pool));
1314 pool.extra.appendAssumeCapacity(@intFromEnum(param_ctype.index));
1315 }
1316 hasher.updateExtra(Function, extra, pool);
1317 return pool.tagTrailingExtra(allocator, hasher, switch (function_info.varargs) {
1318 false => .function,
1319 true => .function_varargs,
1320 }, extra_index);
1321 }
1322
1323 pub fn fromFields(
1324 pool: *Pool,
1325 allocator: std.mem.Allocator,
1326 tag: Info.AggregateTag,
1327 fields: []Info.Field,
1328 kind: Kind,
1329 ) !CType {
1330 sortFields(fields);
1331 const fwd_decl = try pool.getFwdDecl(allocator, .{
1332 .tag = tag,
1333 .name = .{ .anon = fields },
1334 });
1335 return if (kind.isForward()) fwd_decl else pool.getAggregate(allocator, .{
1336 .tag = tag,
1337 .name = .{ .fwd_decl = fwd_decl },
1338 .fields = fields,
1339 });
1340 }
1341
1342 pub fn fromIntInfo(
1343 pool: *Pool,
1344 allocator: std.mem.Allocator,
1345 int_info: std.builtin.Type.Int,
1346 mod: *Module,
1347 kind: Kind,
1348 ) !CType {
1349 switch (int_info.bits) {
1350 0 => return .void,
1351 1...8 => switch (int_info.signedness) {
1352 .signed => return .i8,
1353 .unsigned => return .u8,
1354 },
1355 9...16 => switch (int_info.signedness) {
1356 .signed => return .i16,
1357 .unsigned => return .u16,
1358 },
1359 17...32 => switch (int_info.signedness) {
1360 .signed => return .i32,
1361 .unsigned => return .u32,
1362 },
1363 33...64 => switch (int_info.signedness) {
1364 .signed => return .i64,
1365 .unsigned => return .u64,
1366 },
1367 65...128 => switch (int_info.signedness) {
1368 .signed => return .i128,
1369 .unsigned => return .u128,
1370 },
1371 else => {
1372 const target = &mod.resolved_target.result;
1373 const abi_align_bytes = std.zig.target.intAlignment(target, int_info.bits);
1374 const limb_ctype = try pool.fromIntInfo(allocator, .{
1375 .signedness = .unsigned,
1376 .bits = @intCast(abi_align_bytes * 8),
1377 }, mod, kind.noParameter());
1378 const array_ctype = try pool.getArray(allocator, .{
1379 .len = @divExact(std.zig.target.intByteSize(target, int_info.bits), abi_align_bytes),
1380 .elem_ctype = limb_ctype,
1381 .nonstring = limb_ctype.isAnyChar(),
1382 });
1383 if (!kind.isParameter()) return array_ctype;
1384 var fields = [_]Info.Field{
1385 .{
1386 .name = .{ .index = .array },
1387 .ctype = array_ctype,
1388 .alignas = AlignAs.fromAbiAlignment(.fromByteUnits(abi_align_bytes)),
1389 },
1390 };
1391 return pool.fromFields(allocator, .@"struct", &fields, kind);
1392 },
1393 }
1394 }
1395
1396 pub fn fromType(
1397 pool: *Pool,
1398 allocator: std.mem.Allocator,
1399 scratch: *std.ArrayList(u32),
1400 ty: Type,
1401 pt: Zcu.PerThread,
1402 mod: *Module,
1403 kind: Kind,
1404 ) !CType {
1405 const ip = &pt.zcu.intern_pool;
1406 const zcu = pt.zcu;
1407 switch (ty.toIntern()) {
1408 .u0_type,
1409 .i0_type,
1410 .anyopaque_type,
1411 .void_type,
1412 .empty_tuple_type,
1413 .type_type,
1414 .comptime_int_type,
1415 .comptime_float_type,
1416 .null_type,
1417 .undefined_type,
1418 .enum_literal_type,
1419 .optional_type_type,
1420 .manyptr_const_type_type,
1421 .slice_const_type_type,
1422 => return .void,
1423 .u1_type, .u8_type => return .u8,
1424 .i8_type => return .i8,
1425 .u16_type => return .u16,
1426 .i16_type => return .i16,
1427 .u29_type, .u32_type => return .u32,
1428 .i32_type => return .i32,
1429 .u64_type => return .u64,
1430 .i64_type => return .i64,
1431 .u80_type, .u128_type => return .u128,
1432 .i128_type => return .i128,
1433 .u256_type => return pool.fromIntInfo(allocator, .{
1434 .signedness = .unsigned,
1435 .bits = 256,
1436 }, mod, kind),
1437 .usize_type => return .usize,
1438 .isize_type => return .isize,
1439 .c_char_type => return .{ .index = .char },
1440 .c_short_type => return .{ .index = .short },
1441 .c_ushort_type => return .{ .index = .@"unsigned short" },
1442 .c_int_type => return .{ .index = .int },
1443 .c_uint_type => return .{ .index = .@"unsigned int" },
1444 .c_long_type => return .{ .index = .long },
1445 .c_ulong_type => return .{ .index = .@"unsigned long" },
1446 .c_longlong_type => return .{ .index = .@"long long" },
1447 .c_ulonglong_type => return .{ .index = .@"unsigned long long" },
1448 .c_longdouble_type => return .{ .index = .@"long double" },
1449 .f16_type => return .f16,
1450 .f32_type => return .f32,
1451 .f64_type => return .f64,
1452 .f80_type => return .f80,
1453 .f128_type => return .f128,
1454 .bool_type, .optional_noreturn_type => return .bool,
1455 .noreturn_type,
1456 .anyframe_type,
1457 .generic_poison_type,
1458 => unreachable,
1459 .anyerror_type,
1460 .anyerror_void_error_union_type,
1461 .adhoc_inferred_error_set_type,
1462 => return pool.fromIntInfo(allocator, .{
1463 .signedness = .unsigned,
1464 .bits = pt.zcu.errorSetBits(),
1465 }, mod, kind),
1466
1467 .ptr_usize_type => return pool.getPointer(allocator, .{
1468 .elem_ctype = .usize,
1469 }),
1470 .ptr_const_comptime_int_type => return pool.getPointer(allocator, .{
1471 .elem_ctype = .void,
1472 .@"const" = true,
1473 }),
1474 .manyptr_u8_type => return pool.getPointer(allocator, .{
1475 .elem_ctype = .u8,
1476 .nonstring = true,
1477 }),
1478 .manyptr_const_u8_type => return pool.getPointer(allocator, .{
1479 .elem_ctype = .u8,
1480 .@"const" = true,
1481 .nonstring = true,
1482 }),
1483 .manyptr_const_u8_sentinel_0_type => return pool.getPointer(allocator, .{
1484 .elem_ctype = .u8,
1485 .@"const" = true,
1486 }),
1487 .slice_const_u8_type => {
1488 const target = &mod.resolved_target.result;
1489 var fields = [_]Info.Field{
1490 .{
1491 .name = .{ .index = .ptr },
1492 .ctype = try pool.getPointer(allocator, .{
1493 .elem_ctype = .u8,
1494 .@"const" = true,
1495 .nonstring = true,
1496 }),
1497 .alignas = AlignAs.fromAbiAlignment(Type.ptrAbiAlignment(target)),
1498 },
1499 .{
1500 .name = .{ .index = .len },
1501 .ctype = .usize,
1502 .alignas = AlignAs.fromAbiAlignment(
1503 .fromByteUnits(std.zig.target.intAlignment(target, target.ptrBitWidth())),
1504 ),
1505 },
1506 };
1507 return pool.fromFields(allocator, .@"struct", &fields, kind);
1508 },
1509 .slice_const_u8_sentinel_0_type => {
1510 const target = &mod.resolved_target.result;
1511 var fields = [_]Info.Field{
1512 .{
1513 .name = .{ .index = .ptr },
1514 .ctype = try pool.getPointer(allocator, .{
1515 .elem_ctype = .u8,
1516 .@"const" = true,
1517 }),
1518 .alignas = AlignAs.fromAbiAlignment(Type.ptrAbiAlignment(target)),
1519 },
1520 .{
1521 .name = .{ .index = .len },
1522 .ctype = .usize,
1523 .alignas = AlignAs.fromAbiAlignment(
1524 .fromByteUnits(std.zig.target.intAlignment(target, target.ptrBitWidth())),
1525 ),
1526 },
1527 };
1528 return pool.fromFields(allocator, .@"struct", &fields, kind);
1529 },
1530
1531 .manyptr_const_slice_const_u8_type => {
1532 const target = &mod.resolved_target.result;
1533 var fields: [2]Info.Field = .{
1534 .{
1535 .name = .{ .index = .ptr },
1536 .ctype = try pool.getPointer(allocator, .{
1537 .elem_ctype = .u8,
1538 .@"const" = true,
1539 .nonstring = true,
1540 }),
1541 .alignas = AlignAs.fromAbiAlignment(Type.ptrAbiAlignment(target)),
1542 },
1543 .{
1544 .name = .{ .index = .len },
1545 .ctype = .usize,
1546 .alignas = AlignAs.fromAbiAlignment(
1547 .fromByteUnits(std.zig.target.intAlignment(target, target.ptrBitWidth())),
1548 ),
1549 },
1550 };
1551 const slice_const_u8 = try pool.fromFields(allocator, .@"struct", &fields, kind);
1552 return pool.getPointer(allocator, .{
1553 .elem_ctype = slice_const_u8,
1554 .@"const" = true,
1555 });
1556 },
1557 .slice_const_slice_const_u8_type => {
1558 const target = &mod.resolved_target.result;
1559 var fields: [2]Info.Field = .{
1560 .{
1561 .name = .{ .index = .ptr },
1562 .ctype = try pool.getPointer(allocator, .{
1563 .elem_ctype = .u8,
1564 .@"const" = true,
1565 .nonstring = true,
1566 }),
1567 .alignas = AlignAs.fromAbiAlignment(Type.ptrAbiAlignment(target)),
1568 },
1569 .{
1570 .name = .{ .index = .len },
1571 .ctype = .usize,
1572 .alignas = AlignAs.fromAbiAlignment(
1573 .fromByteUnits(std.zig.target.intAlignment(target, target.ptrBitWidth())),
1574 ),
1575 },
1576 };
1577 const slice_const_u8 = try pool.fromFields(allocator, .@"struct", &fields, .forward);
1578 fields = .{
1579 .{
1580 .name = .{ .index = .ptr },
1581 .ctype = try pool.getPointer(allocator, .{
1582 .elem_ctype = slice_const_u8,
1583 .@"const" = true,
1584 }),
1585 .alignas = AlignAs.fromAbiAlignment(Type.ptrAbiAlignment(target)),
1586 },
1587 .{
1588 .name = .{ .index = .len },
1589 .ctype = .usize,
1590 .alignas = AlignAs.fromAbiAlignment(
1591 .fromByteUnits(std.zig.target.intAlignment(target, target.ptrBitWidth())),
1592 ),
1593 },
1594 };
1595 return pool.fromFields(allocator, .@"struct", &fields, kind);
1596 },
1597
1598 .vector_8_i8_type => {
1599 const vector_ctype = try pool.getVector(allocator, .{
1600 .elem_ctype = .i8,
1601 .len = 8,
1602 .nonstring = true,
1603 });
1604 if (!kind.isParameter()) return vector_ctype;
1605 var fields = [_]Info.Field{
1606 .{
1607 .name = .{ .index = .array },
1608 .ctype = vector_ctype,
1609 .alignas = AlignAs.fromAbiAlignment(Type.i8.abiAlignment(zcu)),
1610 },
1611 };
1612 return pool.fromFields(allocator, .@"struct", &fields, kind);
1613 },
1614 .vector_16_i8_type => {
1615 const vector_ctype = try pool.getVector(allocator, .{
1616 .elem_ctype = .i8,
1617 .len = 16,
1618 .nonstring = true,
1619 });
1620 if (!kind.isParameter()) return vector_ctype;
1621 var fields = [_]Info.Field{
1622 .{
1623 .name = .{ .index = .array },
1624 .ctype = vector_ctype,
1625 .alignas = AlignAs.fromAbiAlignment(Type.i8.abiAlignment(zcu)),
1626 },
1627 };
1628 return pool.fromFields(allocator, .@"struct", &fields, kind);
1629 },
1630 .vector_32_i8_type => {
1631 const vector_ctype = try pool.getVector(allocator, .{
1632 .elem_ctype = .i8,
1633 .len = 32,
1634 .nonstring = true,
1635 });
1636 if (!kind.isParameter()) return vector_ctype;
1637 var fields = [_]Info.Field{
1638 .{
1639 .name = .{ .index = .array },
1640 .ctype = vector_ctype,
1641 .alignas = AlignAs.fromAbiAlignment(Type.i8.abiAlignment(zcu)),
1642 },
1643 };
1644 return pool.fromFields(allocator, .@"struct", &fields, kind);
1645 },
1646 .vector_64_i8_type => {
1647 const vector_ctype = try pool.getVector(allocator, .{
1648 .elem_ctype = .i8,
1649 .len = 64,
1650 .nonstring = true,
1651 });
1652 if (!kind.isParameter()) return vector_ctype;
1653 var fields = [_]Info.Field{
1654 .{
1655 .name = .{ .index = .array },
1656 .ctype = vector_ctype,
1657 .alignas = AlignAs.fromAbiAlignment(Type.i8.abiAlignment(zcu)),
1658 },
1659 };
1660 return pool.fromFields(allocator, .@"struct", &fields, kind);
1661 },
1662 .vector_1_u8_type => {
1663 const vector_ctype = try pool.getVector(allocator, .{
1664 .elem_ctype = .u8,
1665 .len = 1,
1666 .nonstring = true,
1667 });
1668 if (!kind.isParameter()) return vector_ctype;
1669 var fields = [_]Info.Field{
1670 .{
1671 .name = .{ .index = .array },
1672 .ctype = vector_ctype,
1673 .alignas = AlignAs.fromAbiAlignment(Type.u8.abiAlignment(zcu)),
1674 },
1675 };
1676 return pool.fromFields(allocator, .@"struct", &fields, kind);
1677 },
1678 .vector_2_u8_type => {
1679 const vector_ctype = try pool.getVector(allocator, .{
1680 .elem_ctype = .u8,
1681 .len = 2,
1682 .nonstring = true,
1683 });
1684 if (!kind.isParameter()) return vector_ctype;
1685 var fields = [_]Info.Field{
1686 .{
1687 .name = .{ .index = .array },
1688 .ctype = vector_ctype,
1689 .alignas = AlignAs.fromAbiAlignment(Type.u8.abiAlignment(zcu)),
1690 },
1691 };
1692 return pool.fromFields(allocator, .@"struct", &fields, kind);
1693 },
1694 .vector_4_u8_type => {
1695 const vector_ctype = try pool.getVector(allocator, .{
1696 .elem_ctype = .u8,
1697 .len = 4,
1698 .nonstring = true,
1699 });
1700 if (!kind.isParameter()) return vector_ctype;
1701 var fields = [_]Info.Field{
1702 .{
1703 .name = .{ .index = .array },
1704 .ctype = vector_ctype,
1705 .alignas = AlignAs.fromAbiAlignment(Type.u8.abiAlignment(zcu)),
1706 },
1707 };
1708 return pool.fromFields(allocator, .@"struct", &fields, kind);
1709 },
1710 .vector_8_u8_type => {
1711 const vector_ctype = try pool.getVector(allocator, .{
1712 .elem_ctype = .u8,
1713 .len = 8,
1714 .nonstring = true,
1715 });
1716 if (!kind.isParameter()) return vector_ctype;
1717 var fields = [_]Info.Field{
1718 .{
1719 .name = .{ .index = .array },
1720 .ctype = vector_ctype,
1721 .alignas = AlignAs.fromAbiAlignment(Type.u8.abiAlignment(zcu)),
1722 },
1723 };
1724 return pool.fromFields(allocator, .@"struct", &fields, kind);
1725 },
1726 .vector_16_u8_type => {
1727 const vector_ctype = try pool.getVector(allocator, .{
1728 .elem_ctype = .u8,
1729 .len = 16,
1730 .nonstring = true,
1731 });
1732 if (!kind.isParameter()) return vector_ctype;
1733 var fields = [_]Info.Field{
1734 .{
1735 .name = .{ .index = .array },
1736 .ctype = vector_ctype,
1737 .alignas = AlignAs.fromAbiAlignment(Type.u8.abiAlignment(zcu)),
1738 },
1739 };
1740 return pool.fromFields(allocator, .@"struct", &fields, kind);
1741 },
1742 .vector_32_u8_type => {
1743 const vector_ctype = try pool.getVector(allocator, .{
1744 .elem_ctype = .u8,
1745 .len = 32,
1746 .nonstring = true,
1747 });
1748 if (!kind.isParameter()) return vector_ctype;
1749 var fields = [_]Info.Field{
1750 .{
1751 .name = .{ .index = .array },
1752 .ctype = vector_ctype,
1753 .alignas = AlignAs.fromAbiAlignment(Type.u8.abiAlignment(zcu)),
1754 },
1755 };
1756 return pool.fromFields(allocator, .@"struct", &fields, kind);
1757 },
1758 .vector_64_u8_type => {
1759 const vector_ctype = try pool.getVector(allocator, .{
1760 .elem_ctype = .u8,
1761 .len = 64,
1762 .nonstring = true,
1763 });
1764 if (!kind.isParameter()) return vector_ctype;
1765 var fields = [_]Info.Field{
1766 .{
1767 .name = .{ .index = .array },
1768 .ctype = vector_ctype,
1769 .alignas = AlignAs.fromAbiAlignment(Type.u8.abiAlignment(zcu)),
1770 },
1771 };
1772 return pool.fromFields(allocator, .@"struct", &fields, kind);
1773 },
1774 .vector_2_i16_type => {
1775 const vector_ctype = try pool.getVector(allocator, .{
1776 .elem_ctype = .i16,
1777 .len = 2,
1778 });
1779 if (!kind.isParameter()) return vector_ctype;
1780 var fields = [_]Info.Field{
1781 .{
1782 .name = .{ .index = .array },
1783 .ctype = vector_ctype,
1784 .alignas = AlignAs.fromAbiAlignment(Type.i16.abiAlignment(zcu)),
1785 },
1786 };
1787 return pool.fromFields(allocator, .@"struct", &fields, kind);
1788 },
1789 .vector_4_i16_type => {
1790 const vector_ctype = try pool.getVector(allocator, .{
1791 .elem_ctype = .i16,
1792 .len = 4,
1793 });
1794 if (!kind.isParameter()) return vector_ctype;
1795 var fields = [_]Info.Field{
1796 .{
1797 .name = .{ .index = .array },
1798 .ctype = vector_ctype,
1799 .alignas = AlignAs.fromAbiAlignment(Type.i16.abiAlignment(zcu)),
1800 },
1801 };
1802 return pool.fromFields(allocator, .@"struct", &fields, kind);
1803 },
1804 .vector_8_i16_type => {
1805 const vector_ctype = try pool.getVector(allocator, .{
1806 .elem_ctype = .i16,
1807 .len = 8,
1808 });
1809 if (!kind.isParameter()) return vector_ctype;
1810 var fields = [_]Info.Field{
1811 .{
1812 .name = .{ .index = .array },
1813 .ctype = vector_ctype,
1814 .alignas = AlignAs.fromAbiAlignment(Type.i16.abiAlignment(zcu)),
1815 },
1816 };
1817 return pool.fromFields(allocator, .@"struct", &fields, kind);
1818 },
1819 .vector_16_i16_type => {
1820 const vector_ctype = try pool.getVector(allocator, .{
1821 .elem_ctype = .i16,
1822 .len = 16,
1823 });
1824 if (!kind.isParameter()) return vector_ctype;
1825 var fields = [_]Info.Field{
1826 .{
1827 .name = .{ .index = .array },
1828 .ctype = vector_ctype,
1829 .alignas = AlignAs.fromAbiAlignment(Type.i16.abiAlignment(zcu)),
1830 },
1831 };
1832 return pool.fromFields(allocator, .@"struct", &fields, kind);
1833 },
1834 .vector_32_i16_type => {
1835 const vector_ctype = try pool.getVector(allocator, .{
1836 .elem_ctype = .i16,
1837 .len = 32,
1838 });
1839 if (!kind.isParameter()) return vector_ctype;
1840 var fields = [_]Info.Field{
1841 .{
1842 .name = .{ .index = .array },
1843 .ctype = vector_ctype,
1844 .alignas = AlignAs.fromAbiAlignment(Type.i16.abiAlignment(zcu)),
1845 },
1846 };
1847 return pool.fromFields(allocator, .@"struct", &fields, kind);
1848 },
1849 .vector_4_u16_type => {
1850 const vector_ctype = try pool.getVector(allocator, .{
1851 .elem_ctype = .u16,
1852 .len = 4,
1853 });
1854 if (!kind.isParameter()) return vector_ctype;
1855 var fields = [_]Info.Field{
1856 .{
1857 .name = .{ .index = .array },
1858 .ctype = vector_ctype,
1859 .alignas = AlignAs.fromAbiAlignment(Type.u16.abiAlignment(zcu)),
1860 },
1861 };
1862 return pool.fromFields(allocator, .@"struct", &fields, kind);
1863 },
1864 .vector_8_u16_type => {
1865 const vector_ctype = try pool.getVector(allocator, .{
1866 .elem_ctype = .u16,
1867 .len = 8,
1868 });
1869 if (!kind.isParameter()) return vector_ctype;
1870 var fields = [_]Info.Field{
1871 .{
1872 .name = .{ .index = .array },
1873 .ctype = vector_ctype,
1874 .alignas = AlignAs.fromAbiAlignment(Type.u16.abiAlignment(zcu)),
1875 },
1876 };
1877 return pool.fromFields(allocator, .@"struct", &fields, kind);
1878 },
1879 .vector_16_u16_type => {
1880 const vector_ctype = try pool.getVector(allocator, .{
1881 .elem_ctype = .u16,
1882 .len = 16,
1883 });
1884 if (!kind.isParameter()) return vector_ctype;
1885 var fields = [_]Info.Field{
1886 .{
1887 .name = .{ .index = .array },
1888 .ctype = vector_ctype,
1889 .alignas = AlignAs.fromAbiAlignment(Type.u16.abiAlignment(zcu)),
1890 },
1891 };
1892 return pool.fromFields(allocator, .@"struct", &fields, kind);
1893 },
1894 .vector_32_u16_type => {
1895 const vector_ctype = try pool.getVector(allocator, .{
1896 .elem_ctype = .u16,
1897 .len = 32,
1898 });
1899 if (!kind.isParameter()) return vector_ctype;
1900 var fields = [_]Info.Field{
1901 .{
1902 .name = .{ .index = .array },
1903 .ctype = vector_ctype,
1904 .alignas = AlignAs.fromAbiAlignment(Type.u16.abiAlignment(zcu)),
1905 },
1906 };
1907 return pool.fromFields(allocator, .@"struct", &fields, kind);
1908 },
1909 .vector_2_i32_type => {
1910 const vector_ctype = try pool.getVector(allocator, .{
1911 .elem_ctype = .i32,
1912 .len = 2,
1913 });
1914 if (!kind.isParameter()) return vector_ctype;
1915 var fields = [_]Info.Field{
1916 .{
1917 .name = .{ .index = .array },
1918 .ctype = vector_ctype,
1919 .alignas = AlignAs.fromAbiAlignment(Type.i32.abiAlignment(zcu)),
1920 },
1921 };
1922 return pool.fromFields(allocator, .@"struct", &fields, kind);
1923 },
1924 .vector_4_i32_type => {
1925 const vector_ctype = try pool.getVector(allocator, .{
1926 .elem_ctype = .i32,
1927 .len = 4,
1928 });
1929 if (!kind.isParameter()) return vector_ctype;
1930 var fields = [_]Info.Field{
1931 .{
1932 .name = .{ .index = .array },
1933 .ctype = vector_ctype,
1934 .alignas = AlignAs.fromAbiAlignment(Type.i32.abiAlignment(zcu)),
1935 },
1936 };
1937 return pool.fromFields(allocator, .@"struct", &fields, kind);
1938 },
1939 .vector_8_i32_type => {
1940 const vector_ctype = try pool.getVector(allocator, .{
1941 .elem_ctype = .i32,
1942 .len = 8,
1943 });
1944 if (!kind.isParameter()) return vector_ctype;
1945 var fields = [_]Info.Field{
1946 .{
1947 .name = .{ .index = .array },
1948 .ctype = vector_ctype,
1949 .alignas = AlignAs.fromAbiAlignment(Type.i32.abiAlignment(zcu)),
1950 },
1951 };
1952 return pool.fromFields(allocator, .@"struct", &fields, kind);
1953 },
1954 .vector_16_i32_type => {
1955 const vector_ctype = try pool.getVector(allocator, .{
1956 .elem_ctype = .i32,
1957 .len = 16,
1958 });
1959 if (!kind.isParameter()) return vector_ctype;
1960 var fields = [_]Info.Field{
1961 .{
1962 .name = .{ .index = .array },
1963 .ctype = vector_ctype,
1964 .alignas = AlignAs.fromAbiAlignment(Type.i32.abiAlignment(zcu)),
1965 },
1966 };
1967 return pool.fromFields(allocator, .@"struct", &fields, kind);
1968 },
1969 .vector_4_u32_type => {
1970 const vector_ctype = try pool.getVector(allocator, .{
1971 .elem_ctype = .u32,
1972 .len = 4,
1973 });
1974 if (!kind.isParameter()) return vector_ctype;
1975 var fields = [_]Info.Field{
1976 .{
1977 .name = .{ .index = .array },
1978 .ctype = vector_ctype,
1979 .alignas = AlignAs.fromAbiAlignment(Type.u32.abiAlignment(zcu)),
1980 },
1981 };
1982 return pool.fromFields(allocator, .@"struct", &fields, kind);
1983 },
1984 .vector_8_u32_type => {
1985 const vector_ctype = try pool.getVector(allocator, .{
1986 .elem_ctype = .u32,
1987 .len = 8,
1988 });
1989 if (!kind.isParameter()) return vector_ctype;
1990 var fields = [_]Info.Field{
1991 .{
1992 .name = .{ .index = .array },
1993 .ctype = vector_ctype,
1994 .alignas = AlignAs.fromAbiAlignment(Type.u32.abiAlignment(zcu)),
1995 },
1996 };
1997 return pool.fromFields(allocator, .@"struct", &fields, kind);
1998 },
1999 .vector_16_u32_type => {
2000 const vector_ctype = try pool.getVector(allocator, .{
2001 .elem_ctype = .u32,
2002 .len = 16,
2003 });
2004 if (!kind.isParameter()) return vector_ctype;
2005 var fields = [_]Info.Field{
2006 .{
2007 .name = .{ .index = .array },
2008 .ctype = vector_ctype,
2009 .alignas = AlignAs.fromAbiAlignment(Type.u32.abiAlignment(zcu)),
2010 },
2011 };
2012 return pool.fromFields(allocator, .@"struct", &fields, kind);
2013 },
2014 .vector_2_i64_type => {
2015 const vector_ctype = try pool.getVector(allocator, .{
2016 .elem_ctype = .i64,
2017 .len = 2,
2018 });
2019 if (!kind.isParameter()) return vector_ctype;
2020 var fields = [_]Info.Field{
2021 .{
2022 .name = .{ .index = .array },
2023 .ctype = vector_ctype,
2024 .alignas = AlignAs.fromAbiAlignment(Type.i64.abiAlignment(zcu)),
2025 },
2026 };
2027 return pool.fromFields(allocator, .@"struct", &fields, kind);
2028 },
2029 .vector_4_i64_type => {
2030 const vector_ctype = try pool.getVector(allocator, .{
2031 .elem_ctype = .i64,
2032 .len = 4,
2033 });
2034 if (!kind.isParameter()) return vector_ctype;
2035 var fields = [_]Info.Field{
2036 .{
2037 .name = .{ .index = .array },
2038 .ctype = vector_ctype,
2039 .alignas = AlignAs.fromAbiAlignment(Type.i64.abiAlignment(zcu)),
2040 },
2041 };
2042 return pool.fromFields(allocator, .@"struct", &fields, kind);
2043 },
2044 .vector_8_i64_type => {
2045 const vector_ctype = try pool.getVector(allocator, .{
2046 .elem_ctype = .i64,
2047 .len = 8,
2048 });
2049 if (!kind.isParameter()) return vector_ctype;
2050 var fields = [_]Info.Field{
2051 .{
2052 .name = .{ .index = .array },
2053 .ctype = vector_ctype,
2054 .alignas = AlignAs.fromAbiAlignment(Type.i64.abiAlignment(zcu)),
2055 },
2056 };
2057 return pool.fromFields(allocator, .@"struct", &fields, kind);
2058 },
2059 .vector_2_u64_type => {
2060 const vector_ctype = try pool.getVector(allocator, .{
2061 .elem_ctype = .u64,
2062 .len = 2,
2063 });
2064 if (!kind.isParameter()) return vector_ctype;
2065 var fields = [_]Info.Field{
2066 .{
2067 .name = .{ .index = .array },
2068 .ctype = vector_ctype,
2069 .alignas = AlignAs.fromAbiAlignment(Type.u64.abiAlignment(zcu)),
2070 },
2071 };
2072 return pool.fromFields(allocator, .@"struct", &fields, kind);
2073 },
2074 .vector_4_u64_type => {
2075 const vector_ctype = try pool.getVector(allocator, .{
2076 .elem_ctype = .u64,
2077 .len = 4,
2078 });
2079 if (!kind.isParameter()) return vector_ctype;
2080 var fields = [_]Info.Field{
2081 .{
2082 .name = .{ .index = .array },
2083 .ctype = vector_ctype,
2084 .alignas = AlignAs.fromAbiAlignment(Type.u64.abiAlignment(zcu)),
2085 },
2086 };
2087 return pool.fromFields(allocator, .@"struct", &fields, kind);
2088 },
2089 .vector_8_u64_type => {
2090 const vector_ctype = try pool.getVector(allocator, .{
2091 .elem_ctype = .u64,
2092 .len = 8,
2093 });
2094 if (!kind.isParameter()) return vector_ctype;
2095 var fields = [_]Info.Field{
2096 .{
2097 .name = .{ .index = .array },
2098 .ctype = vector_ctype,
2099 .alignas = AlignAs.fromAbiAlignment(Type.u64.abiAlignment(zcu)),
2100 },
2101 };
2102 return pool.fromFields(allocator, .@"struct", &fields, kind);
2103 },
2104 .vector_1_u128_type => {
2105 const vector_ctype = try pool.getVector(allocator, .{
2106 .elem_ctype = .u128,
2107 .len = 1,
2108 });
2109 if (!kind.isParameter()) return vector_ctype;
2110 var fields = [_]Info.Field{
2111 .{
2112 .name = .{ .index = .array },
2113 .ctype = vector_ctype,
2114 .alignas = AlignAs.fromAbiAlignment(Type.u128.abiAlignment(zcu)),
2115 },
2116 };
2117 return pool.fromFields(allocator, .@"struct", &fields, kind);
2118 },
2119 .vector_2_u128_type => {
2120 const vector_ctype = try pool.getVector(allocator, .{
2121 .elem_ctype = .u128,
2122 .len = 2,
2123 });
2124 if (!kind.isParameter()) return vector_ctype;
2125 var fields = [_]Info.Field{
2126 .{
2127 .name = .{ .index = .array },
2128 .ctype = vector_ctype,
2129 .alignas = AlignAs.fromAbiAlignment(Type.u128.abiAlignment(zcu)),
2130 },
2131 };
2132 return pool.fromFields(allocator, .@"struct", &fields, kind);
2133 },
2134 .vector_1_u256_type => {
2135 const vector_ctype = try pool.getVector(allocator, .{
2136 .elem_ctype = try pool.fromIntInfo(allocator, .{
2137 .signedness = .unsigned,
2138 .bits = 256,
2139 }, mod, kind),
2140 .len = 1,
2141 });
2142 if (!kind.isParameter()) return vector_ctype;
2143 var fields = [_]Info.Field{
2144 .{
2145 .name = .{ .index = .array },
2146 .ctype = vector_ctype,
2147 .alignas = AlignAs.fromAbiAlignment(Type.u256.abiAlignment(zcu)),
2148 },
2149 };
2150 return pool.fromFields(allocator, .@"struct", &fields, kind);
2151 },
2152 .vector_4_f16_type => {
2153 const vector_ctype = try pool.getVector(allocator, .{
2154 .elem_ctype = .f16,
2155 .len = 4,
2156 });
2157 if (!kind.isParameter()) return vector_ctype;
2158 var fields = [_]Info.Field{
2159 .{
2160 .name = .{ .index = .array },
2161 .ctype = vector_ctype,
2162 .alignas = AlignAs.fromAbiAlignment(Type.f16.abiAlignment(zcu)),
2163 },
2164 };
2165 return pool.fromFields(allocator, .@"struct", &fields, kind);
2166 },
2167 .vector_8_f16_type => {
2168 const vector_ctype = try pool.getVector(allocator, .{
2169 .elem_ctype = .f16,
2170 .len = 8,
2171 });
2172 if (!kind.isParameter()) return vector_ctype;
2173 var fields = [_]Info.Field{
2174 .{
2175 .name = .{ .index = .array },
2176 .ctype = vector_ctype,
2177 .alignas = AlignAs.fromAbiAlignment(Type.f16.abiAlignment(zcu)),
2178 },
2179 };
2180 return pool.fromFields(allocator, .@"struct", &fields, kind);
2181 },
2182 .vector_16_f16_type => {
2183 const vector_ctype = try pool.getVector(allocator, .{
2184 .elem_ctype = .f16,
2185 .len = 16,
2186 });
2187 if (!kind.isParameter()) return vector_ctype;
2188 var fields = [_]Info.Field{
2189 .{
2190 .name = .{ .index = .array },
2191 .ctype = vector_ctype,
2192 .alignas = AlignAs.fromAbiAlignment(Type.f16.abiAlignment(zcu)),
2193 },
2194 };
2195 return pool.fromFields(allocator, .@"struct", &fields, kind);
2196 },
2197 .vector_32_f16_type => {
2198 const vector_ctype = try pool.getVector(allocator, .{
2199 .elem_ctype = .f16,
2200 .len = 32,
2201 });
2202 if (!kind.isParameter()) return vector_ctype;
2203 var fields = [_]Info.Field{
2204 .{
2205 .name = .{ .index = .array },
2206 .ctype = vector_ctype,
2207 .alignas = AlignAs.fromAbiAlignment(Type.f16.abiAlignment(zcu)),
2208 },
2209 };
2210 return pool.fromFields(allocator, .@"struct", &fields, kind);
2211 },
2212 .vector_2_f32_type => {
2213 const vector_ctype = try pool.getVector(allocator, .{
2214 .elem_ctype = .f32,
2215 .len = 2,
2216 });
2217 if (!kind.isParameter()) return vector_ctype;
2218 var fields = [_]Info.Field{
2219 .{
2220 .name = .{ .index = .array },
2221 .ctype = vector_ctype,
2222 .alignas = AlignAs.fromAbiAlignment(Type.f32.abiAlignment(zcu)),
2223 },
2224 };
2225 return pool.fromFields(allocator, .@"struct", &fields, kind);
2226 },
2227 .vector_4_f32_type => {
2228 const vector_ctype = try pool.getVector(allocator, .{
2229 .elem_ctype = .f32,
2230 .len = 4,
2231 });
2232 if (!kind.isParameter()) return vector_ctype;
2233 var fields = [_]Info.Field{
2234 .{
2235 .name = .{ .index = .array },
2236 .ctype = vector_ctype,
2237 .alignas = AlignAs.fromAbiAlignment(Type.f32.abiAlignment(zcu)),
2238 },
2239 };
2240 return pool.fromFields(allocator, .@"struct", &fields, kind);
2241 },
2242 .vector_8_f32_type => {
2243 const vector_ctype = try pool.getVector(allocator, .{
2244 .elem_ctype = .f32,
2245 .len = 8,
2246 });
2247 if (!kind.isParameter()) return vector_ctype;
2248 var fields = [_]Info.Field{
2249 .{
2250 .name = .{ .index = .array },
2251 .ctype = vector_ctype,
2252 .alignas = AlignAs.fromAbiAlignment(Type.f32.abiAlignment(zcu)),
2253 },
2254 };
2255 return pool.fromFields(allocator, .@"struct", &fields, kind);
2256 },
2257 .vector_16_f32_type => {
2258 const vector_ctype = try pool.getVector(allocator, .{
2259 .elem_ctype = .f32,
2260 .len = 16,
2261 });
2262 if (!kind.isParameter()) return vector_ctype;
2263 var fields = [_]Info.Field{
2264 .{
2265 .name = .{ .index = .array },
2266 .ctype = vector_ctype,
2267 .alignas = AlignAs.fromAbiAlignment(Type.f32.abiAlignment(zcu)),
2268 },
2269 };
2270 return pool.fromFields(allocator, .@"struct", &fields, kind);
2271 },
2272 .vector_2_f64_type => {
2273 const vector_ctype = try pool.getVector(allocator, .{
2274 .elem_ctype = .f64,
2275 .len = 2,
2276 });
2277 if (!kind.isParameter()) return vector_ctype;
2278 var fields = [_]Info.Field{
2279 .{
2280 .name = .{ .index = .array },
2281 .ctype = vector_ctype,
2282 .alignas = AlignAs.fromAbiAlignment(Type.f64.abiAlignment(zcu)),
2283 },
2284 };
2285 return pool.fromFields(allocator, .@"struct", &fields, kind);
2286 },
2287 .vector_4_f64_type => {
2288 const vector_ctype = try pool.getVector(allocator, .{
2289 .elem_ctype = .f64,
2290 .len = 4,
2291 });
2292 if (!kind.isParameter()) return vector_ctype;
2293 var fields = [_]Info.Field{
2294 .{
2295 .name = .{ .index = .array },
2296 .ctype = vector_ctype,
2297 .alignas = AlignAs.fromAbiAlignment(Type.f64.abiAlignment(zcu)),
2298 },
2299 };
2300 return pool.fromFields(allocator, .@"struct", &fields, kind);
2301 },
2302 .vector_8_f64_type => {
2303 const vector_ctype = try pool.getVector(allocator, .{
2304 .elem_ctype = .f64,
2305 .len = 8,
2306 });
2307 if (!kind.isParameter()) return vector_ctype;
2308 var fields = [_]Info.Field{
2309 .{
2310 .name = .{ .index = .array },
2311 .ctype = vector_ctype,
2312 .alignas = AlignAs.fromAbiAlignment(Type.f64.abiAlignment(zcu)),
2313 },
2314 };
2315 return pool.fromFields(allocator, .@"struct", &fields, kind);
2316 },
2317
2318 .undef,
2319 .undef_bool,
2320 .undef_usize,
2321 .undef_u1,
2322 .zero,
2323 .zero_usize,
2324 .zero_u1,
2325 .zero_u8,
2326 .one,
2327 .one_usize,
2328 .one_u1,
2329 .one_u8,
2330 .four_u8,
2331 .negative_one,
2332 .void_value,
2333 .unreachable_value,
2334 .null_value,
2335 .bool_true,
2336 .bool_false,
2337 .empty_tuple,
2338 .none,
2339 => unreachable, // values, not types
2340
2341 _ => |ip_index| switch (ip.indexToKey(ip_index)) {
2342 .int_type => |int_info| return pool.fromIntInfo(allocator, int_info, mod, kind),
2343 .ptr_type => |ptr_info| switch (ptr_info.flags.size) {
2344 .one, .many, .c => {
2345 const elem_ctype = elem_ctype: {
2346 if (ptr_info.packed_offset.host_size > 0 and
2347 ptr_info.flags.vector_index == .none)
2348 break :elem_ctype try pool.fromIntInfo(allocator, .{
2349 .signedness = .unsigned,
2350 .bits = ptr_info.packed_offset.host_size * 8,
2351 }, mod, .forward);
2352 const elem: Info.Aligned = .{
2353 .ctype = try pool.fromType(
2354 allocator,
2355 scratch,
2356 Type.fromInterned(ptr_info.child),
2357 pt,
2358 mod,
2359 .forward,
2360 ),
2361 .alignas = AlignAs.fromAlignment(.{
2362 .@"align" = ptr_info.flags.alignment,
2363 .abi = Type.fromInterned(ptr_info.child).abiAlignment(zcu),
2364 }),
2365 };
2366 break :elem_ctype if (elem.alignas.abiOrder().compare(.gte))
2367 elem.ctype
2368 else
2369 try pool.getAligned(allocator, elem);
2370 };
2371 const elem_tag: Info.Tag = switch (elem_ctype.info(pool)) {
2372 .aligned => |aligned_info| aligned_info.ctype.info(pool),
2373 else => |elem_tag| elem_tag,
2374 };
2375 return pool.getPointer(allocator, .{
2376 .elem_ctype = elem_ctype,
2377 .@"const" = switch (elem_tag) {
2378 .basic,
2379 .pointer,
2380 .aligned,
2381 .array,
2382 .vector,
2383 .fwd_decl,
2384 .aggregate,
2385 => ptr_info.flags.is_const,
2386 .function => false,
2387 },
2388 .@"volatile" = ptr_info.flags.is_volatile,
2389 .nonstring = elem_ctype.isAnyChar() and switch (ptr_info.sentinel) {
2390 .none => true,
2391 .zero_u8 => false,
2392 else => |sentinel| Value.fromInterned(sentinel).orderAgainstZero(zcu).compare(.neq),
2393 },
2394 });
2395 },
2396 .slice => {
2397 const target = &mod.resolved_target.result;
2398 var fields = [_]Info.Field{
2399 .{
2400 .name = .{ .index = .ptr },
2401 .ctype = try pool.fromType(
2402 allocator,
2403 scratch,
2404 Type.fromInterned(ip.slicePtrType(ip_index)),
2405 pt,
2406 mod,
2407 kind,
2408 ),
2409 .alignas = AlignAs.fromAbiAlignment(Type.ptrAbiAlignment(target)),
2410 },
2411 .{
2412 .name = .{ .index = .len },
2413 .ctype = .usize,
2414 .alignas = AlignAs.fromAbiAlignment(
2415 .fromByteUnits(std.zig.target.intAlignment(target, target.ptrBitWidth())),
2416 ),
2417 },
2418 };
2419 return pool.fromFields(allocator, .@"struct", &fields, kind);
2420 },
2421 },
2422 .array_type => |array_info| {
2423 const len = array_info.lenIncludingSentinel();
2424 if (len == 0) return .void;
2425 const elem_type = Type.fromInterned(array_info.child);
2426 const elem_ctype = try pool.fromType(
2427 allocator,
2428 scratch,
2429 elem_type,
2430 pt,
2431 mod,
2432 kind.noParameter().asComplete(),
2433 );
2434 if (elem_ctype.index == .void) return .void;
2435 const array_ctype = try pool.getArray(allocator, .{
2436 .elem_ctype = elem_ctype,
2437 .len = len,
2438 .nonstring = elem_ctype.isAnyChar() and switch (array_info.sentinel) {
2439 .none => true,
2440 .zero_u8 => false,
2441 else => |sentinel| Value.fromInterned(sentinel).orderAgainstZero(zcu).compare(.neq),
2442 },
2443 });
2444 if (!kind.isParameter()) return array_ctype;
2445 var fields = [_]Info.Field{
2446 .{
2447 .name = .{ .index = .array },
2448 .ctype = array_ctype,
2449 .alignas = AlignAs.fromAbiAlignment(elem_type.abiAlignment(zcu)),
2450 },
2451 };
2452 return pool.fromFields(allocator, .@"struct", &fields, kind);
2453 },
2454 .vector_type => |vector_info| {
2455 if (vector_info.len == 0) return .void;
2456 const elem_type = Type.fromInterned(vector_info.child);
2457 const elem_ctype = try pool.fromType(
2458 allocator,
2459 scratch,
2460 elem_type,
2461 pt,
2462 mod,
2463 kind.noParameter().asComplete(),
2464 );
2465 if (elem_ctype.index == .void) return .void;
2466 const vector_ctype = try pool.getVector(allocator, .{
2467 .elem_ctype = elem_ctype,
2468 .len = vector_info.len,
2469 .nonstring = elem_ctype.isAnyChar(),
2470 });
2471 if (!kind.isParameter()) return vector_ctype;
2472 var fields = [_]Info.Field{
2473 .{
2474 .name = .{ .index = .array },
2475 .ctype = vector_ctype,
2476 .alignas = AlignAs.fromAbiAlignment(elem_type.abiAlignment(zcu)),
2477 },
2478 };
2479 return pool.fromFields(allocator, .@"struct", &fields, kind);
2480 },
2481 .opt_type => |payload_type| {
2482 if (ip.isNoReturn(payload_type)) return .void;
2483 const payload_ctype = try pool.fromType(
2484 allocator,
2485 scratch,
2486 Type.fromInterned(payload_type),
2487 pt,
2488 mod,
2489 kind.noParameter(),
2490 );
2491 if (payload_ctype.index == .void) return .bool;
2492 switch (payload_type) {
2493 .anyerror_type => return payload_ctype,
2494 else => switch (ip.indexToKey(payload_type)) {
2495 .ptr_type => |payload_ptr_info| if (payload_ptr_info.flags.size != .c and
2496 !payload_ptr_info.flags.is_allowzero) return payload_ctype,
2497 .error_set_type, .inferred_error_set_type => return payload_ctype,
2498 else => {},
2499 },
2500 }
2501 var fields = [_]Info.Field{
2502 .{
2503 .name = .{ .index = .is_null },
2504 .ctype = .bool,
2505 .alignas = AlignAs.fromAbiAlignment(.@"1"),
2506 },
2507 .{
2508 .name = .{ .index = .payload },
2509 .ctype = payload_ctype,
2510 .alignas = AlignAs.fromAbiAlignment(
2511 Type.fromInterned(payload_type).abiAlignment(zcu),
2512 ),
2513 },
2514 };
2515 return pool.fromFields(allocator, .@"struct", &fields, kind);
2516 },
2517 .anyframe_type => unreachable,
2518 .error_union_type => |error_union_info| {
2519 const error_set_bits = pt.zcu.errorSetBits();
2520 const error_set_ctype = try pool.fromIntInfo(allocator, .{
2521 .signedness = .unsigned,
2522 .bits = error_set_bits,
2523 }, mod, kind);
2524 if (ip.isNoReturn(error_union_info.payload_type)) return error_set_ctype;
2525 const payload_type = Type.fromInterned(error_union_info.payload_type);
2526 const payload_ctype = try pool.fromType(
2527 allocator,
2528 scratch,
2529 payload_type,
2530 pt,
2531 mod,
2532 kind.noParameter(),
2533 );
2534 if (payload_ctype.index == .void) return error_set_ctype;
2535 const target = &mod.resolved_target.result;
2536 var fields = [_]Info.Field{
2537 .{
2538 .name = .{ .index = .@"error" },
2539 .ctype = error_set_ctype,
2540 .alignas = AlignAs.fromAbiAlignment(
2541 .fromByteUnits(std.zig.target.intAlignment(target, error_set_bits)),
2542 ),
2543 },
2544 .{
2545 .name = .{ .index = .payload },
2546 .ctype = payload_ctype,
2547 .alignas = AlignAs.fromAbiAlignment(payload_type.abiAlignment(zcu)),
2548 },
2549 };
2550 return pool.fromFields(allocator, .@"struct", &fields, kind);
2551 },
2552 .simple_type => unreachable,
2553 .struct_type => {
2554 const loaded_struct = ip.loadStructType(ip_index);
2555 switch (loaded_struct.layout) {
2556 .auto, .@"extern" => {
2557 const fwd_decl = try pool.getFwdDecl(allocator, .{
2558 .tag = .@"struct",
2559 .name = .{ .index = ip_index },
2560 });
2561 if (kind.isForward()) return if (ty.hasRuntimeBitsIgnoreComptime(zcu))
2562 fwd_decl
2563 else
2564 .void;
2565 const scratch_top = scratch.items.len;
2566 defer scratch.shrinkRetainingCapacity(scratch_top);
2567 try scratch.ensureUnusedCapacity(
2568 allocator,
2569 loaded_struct.field_types.len * @typeInfo(Field).@"struct".fields.len,
2570 );
2571 var hasher = Hasher.init;
2572 var tag: Pool.Tag = .aggregate_struct;
2573 var field_it = loaded_struct.iterateRuntimeOrder(ip);
2574 while (field_it.next()) |field_index| {
2575 const field_type = Type.fromInterned(
2576 loaded_struct.field_types.get(ip)[field_index],
2577 );
2578 const field_ctype = try pool.fromType(
2579 allocator,
2580 scratch,
2581 field_type,
2582 pt,
2583 mod,
2584 kind.noParameter(),
2585 );
2586 if (field_ctype.index == .void) continue;
2587 const field_name = try pool.string(allocator, loaded_struct.fieldName(ip, field_index).toSlice(ip));
2588 const field_alignas = AlignAs.fromAlignment(.{
2589 .@"align" = loaded_struct.fieldAlign(ip, field_index),
2590 .abi = field_type.abiAlignment(zcu),
2591 });
2592 pool.addHashedExtraAssumeCapacityTo(scratch, &hasher, Field, .{
2593 .name = field_name.index,
2594 .ctype = field_ctype.index,
2595 .flags = .{ .alignas = field_alignas },
2596 });
2597 if (field_alignas.abiOrder().compare(.lt))
2598 tag = .aggregate_struct_packed;
2599 }
2600 const fields_len: u32 = @intCast(@divExact(
2601 scratch.items.len - scratch_top,
2602 @typeInfo(Field).@"struct".fields.len,
2603 ));
2604 if (fields_len == 0) return .void;
2605 try pool.ensureUnusedCapacity(allocator, 1);
2606 const extra_index = try pool.addHashedExtra(allocator, &hasher, Aggregate, .{
2607 .fwd_decl = fwd_decl.index,
2608 .fields_len = fields_len,
2609 }, fields_len * @typeInfo(Field).@"struct".fields.len);
2610 pool.extra.appendSliceAssumeCapacity(scratch.items[scratch_top..]);
2611 return pool.tagTrailingExtraAssumeCapacity(hasher, tag, extra_index);
2612 },
2613 .@"packed" => return pool.fromType(
2614 allocator,
2615 scratch,
2616 Type.fromInterned(loaded_struct.backingIntTypeUnordered(ip)),
2617 pt,
2618 mod,
2619 kind,
2620 ),
2621 }
2622 },
2623 .tuple_type => |tuple_info| {
2624 const scratch_top = scratch.items.len;
2625 defer scratch.shrinkRetainingCapacity(scratch_top);
2626 try scratch.ensureUnusedCapacity(allocator, tuple_info.types.len *
2627 @typeInfo(Field).@"struct".fields.len);
2628 var hasher = Hasher.init;
2629 for (0..tuple_info.types.len) |field_index| {
2630 if (tuple_info.values.get(ip)[field_index] != .none) continue;
2631 const field_type = Type.fromInterned(
2632 tuple_info.types.get(ip)[field_index],
2633 );
2634 const field_ctype = try pool.fromType(
2635 allocator,
2636 scratch,
2637 field_type,
2638 pt,
2639 mod,
2640 kind.noParameter(),
2641 );
2642 if (field_ctype.index == .void) continue;
2643 const field_name = try pool.fmt(allocator, "f{d}", .{field_index});
2644 pool.addHashedExtraAssumeCapacityTo(scratch, &hasher, Field, .{
2645 .name = field_name.index,
2646 .ctype = field_ctype.index,
2647 .flags = .{ .alignas = AlignAs.fromAbiAlignment(
2648 field_type.abiAlignment(zcu),
2649 ) },
2650 });
2651 }
2652 const fields_len: u32 = @intCast(@divExact(
2653 scratch.items.len - scratch_top,
2654 @typeInfo(Field).@"struct".fields.len,
2655 ));
2656 if (fields_len == 0) return .void;
2657 if (kind.isForward()) {
2658 try pool.ensureUnusedCapacity(allocator, 1);
2659 const extra_index = try pool.addHashedExtra(
2660 allocator,
2661 &hasher,
2662 FwdDeclAnon,
2663 .{ .fields_len = fields_len },
2664 fields_len * @typeInfo(Field).@"struct".fields.len,
2665 );
2666 pool.extra.appendSliceAssumeCapacity(scratch.items[scratch_top..]);
2667 return pool.tagTrailingExtra(
2668 allocator,
2669 hasher,
2670 .fwd_decl_struct_anon,
2671 extra_index,
2672 );
2673 }
2674 const fwd_decl = try pool.fromType(allocator, scratch, ty, pt, mod, .forward);
2675 try pool.ensureUnusedCapacity(allocator, 1);
2676 const extra_index = try pool.addHashedExtra(allocator, &hasher, Aggregate, .{
2677 .fwd_decl = fwd_decl.index,
2678 .fields_len = fields_len,
2679 }, fields_len * @typeInfo(Field).@"struct".fields.len);
2680 pool.extra.appendSliceAssumeCapacity(scratch.items[scratch_top..]);
2681 return pool.tagTrailingExtraAssumeCapacity(hasher, .aggregate_struct, extra_index);
2682 },
2683 .union_type => {
2684 const loaded_union = ip.loadUnionType(ip_index);
2685 switch (loaded_union.flagsUnordered(ip).layout) {
2686 .auto, .@"extern" => {
2687 const has_tag = loaded_union.hasTag(ip);
2688 const fwd_decl = try pool.getFwdDecl(allocator, .{
2689 .tag = if (has_tag) .@"struct" else .@"union",
2690 .name = .{ .index = ip_index },
2691 });
2692 if (kind.isForward()) return if (ty.hasRuntimeBitsIgnoreComptime(zcu))
2693 fwd_decl
2694 else
2695 .void;
2696 const loaded_tag = loaded_union.loadTagType(ip);
2697 const scratch_top = scratch.items.len;
2698 defer scratch.shrinkRetainingCapacity(scratch_top);
2699 try scratch.ensureUnusedCapacity(
2700 allocator,
2701 loaded_union.field_types.len * @typeInfo(Field).@"struct".fields.len,
2702 );
2703 var hasher = Hasher.init;
2704 var tag: Pool.Tag = .aggregate_union;
2705 var payload_align: InternPool.Alignment = .@"1";
2706 for (0..loaded_union.field_types.len) |field_index| {
2707 const field_type = Type.fromInterned(
2708 loaded_union.field_types.get(ip)[field_index],
2709 );
2710 if (ip.isNoReturn(field_type.toIntern())) continue;
2711 const field_ctype = try pool.fromType(
2712 allocator,
2713 scratch,
2714 field_type,
2715 pt,
2716 mod,
2717 kind.noParameter(),
2718 );
2719 if (field_ctype.index == .void) continue;
2720 const field_name = try pool.string(
2721 allocator,
2722 loaded_tag.names.get(ip)[field_index].toSlice(ip),
2723 );
2724 const field_alignas = AlignAs.fromAlignment(.{
2725 .@"align" = loaded_union.fieldAlign(ip, field_index),
2726 .abi = field_type.abiAlignment(zcu),
2727 });
2728 pool.addHashedExtraAssumeCapacityTo(scratch, &hasher, Field, .{
2729 .name = field_name.index,
2730 .ctype = field_ctype.index,
2731 .flags = .{ .alignas = field_alignas },
2732 });
2733 if (field_alignas.abiOrder().compare(.lt))
2734 tag = .aggregate_union_packed;
2735 payload_align = payload_align.maxStrict(field_alignas.@"align");
2736 }
2737 const fields_len: u32 = @intCast(@divExact(
2738 scratch.items.len - scratch_top,
2739 @typeInfo(Field).@"struct".fields.len,
2740 ));
2741 if (!has_tag) {
2742 if (fields_len == 0) return .void;
2743 try pool.ensureUnusedCapacity(allocator, 1);
2744 const extra_index = try pool.addHashedExtra(
2745 allocator,
2746 &hasher,
2747 Aggregate,
2748 .{ .fwd_decl = fwd_decl.index, .fields_len = fields_len },
2749 fields_len * @typeInfo(Field).@"struct".fields.len,
2750 );
2751 pool.extra.appendSliceAssumeCapacity(scratch.items[scratch_top..]);
2752 return pool.tagTrailingExtraAssumeCapacity(hasher, tag, extra_index);
2753 }
2754 try pool.ensureUnusedCapacity(allocator, 2);
2755 var struct_fields: [2]Info.Field = undefined;
2756 var struct_fields_len: usize = 0;
2757 if (loaded_tag.tag_ty != .comptime_int_type) {
2758 const tag_type = Type.fromInterned(loaded_tag.tag_ty);
2759 const tag_ctype: CType = try pool.fromType(
2760 allocator,
2761 scratch,
2762 tag_type,
2763 pt,
2764 mod,
2765 kind.noParameter(),
2766 );
2767 if (tag_ctype.index != .void) {
2768 struct_fields[struct_fields_len] = .{
2769 .name = .{ .index = .tag },
2770 .ctype = tag_ctype,
2771 .alignas = AlignAs.fromAbiAlignment(tag_type.abiAlignment(zcu)),
2772 };
2773 struct_fields_len += 1;
2774 }
2775 }
2776 if (fields_len > 0) {
2777 const payload_ctype = payload_ctype: {
2778 const extra_index = try pool.addHashedExtra(
2779 allocator,
2780 &hasher,
2781 AggregateAnon,
2782 .{
2783 .index = ip_index,
2784 .id = 0,
2785 .fields_len = fields_len,
2786 },
2787 fields_len * @typeInfo(Field).@"struct".fields.len,
2788 );
2789 pool.extra.appendSliceAssumeCapacity(scratch.items[scratch_top..]);
2790 break :payload_ctype pool.tagTrailingExtraAssumeCapacity(
2791 hasher,
2792 switch (tag) {
2793 .aggregate_union => .aggregate_union_anon,
2794 .aggregate_union_packed => .aggregate_union_packed_anon,
2795 else => unreachable,
2796 },
2797 extra_index,
2798 );
2799 };
2800 if (payload_ctype.index != .void) {
2801 struct_fields[struct_fields_len] = .{
2802 .name = .{ .index = .payload },
2803 .ctype = payload_ctype,
2804 .alignas = AlignAs.fromAbiAlignment(payload_align),
2805 };
2806 struct_fields_len += 1;
2807 }
2808 }
2809 if (struct_fields_len == 0) return .void;
2810 sortFields(struct_fields[0..struct_fields_len]);
2811 return pool.getAggregate(allocator, .{
2812 .tag = .@"struct",
2813 .name = .{ .fwd_decl = fwd_decl },
2814 .fields = struct_fields[0..struct_fields_len],
2815 });
2816 },
2817 .@"packed" => return pool.fromIntInfo(allocator, .{
2818 .signedness = .unsigned,
2819 .bits = @intCast(ty.bitSize(zcu)),
2820 }, mod, kind),
2821 }
2822 },
2823 .opaque_type => return .void,
2824 .enum_type => return pool.fromType(
2825 allocator,
2826 scratch,
2827 Type.fromInterned(ip.loadEnumType(ip_index).tag_ty),
2828 pt,
2829 mod,
2830 kind,
2831 ),
2832 .func_type => |func_info| if (func_info.is_generic) return .void else {
2833 const scratch_top = scratch.items.len;
2834 defer scratch.shrinkRetainingCapacity(scratch_top);
2835 try scratch.ensureUnusedCapacity(allocator, func_info.param_types.len);
2836 var hasher = Hasher.init;
2837 const return_type = Type.fromInterned(func_info.return_type);
2838 const return_ctype: CType =
2839 if (!ip.isNoReturn(func_info.return_type)) try pool.fromType(
2840 allocator,
2841 scratch,
2842 return_type,
2843 pt,
2844 mod,
2845 kind.asParameter(),
2846 ) else .void;
2847 for (0..func_info.param_types.len) |param_index| {
2848 const param_type = Type.fromInterned(
2849 func_info.param_types.get(ip)[param_index],
2850 );
2851 const param_ctype = try pool.fromType(
2852 allocator,
2853 scratch,
2854 param_type,
2855 pt,
2856 mod,
2857 kind.asParameter(),
2858 );
2859 if (param_ctype.index == .void) continue;
2860 hasher.update(param_ctype.hash(pool));
2861 scratch.appendAssumeCapacity(@intFromEnum(param_ctype.index));
2862 }
2863 const param_ctypes_len: u32 = @intCast(scratch.items.len - scratch_top);
2864 try pool.ensureUnusedCapacity(allocator, 1);
2865 const extra_index = try pool.addHashedExtra(allocator, &hasher, Function, .{
2866 .return_ctype = return_ctype.index,
2867 .param_ctypes_len = param_ctypes_len,
2868 }, param_ctypes_len);
2869 pool.extra.appendSliceAssumeCapacity(scratch.items[scratch_top..]);
2870 return pool.tagTrailingExtraAssumeCapacity(hasher, switch (func_info.is_var_args) {
2871 false => .function,
2872 true => .function_varargs,
2873 }, extra_index);
2874 },
2875 .error_set_type,
2876 .inferred_error_set_type,
2877 => return pool.fromIntInfo(allocator, .{
2878 .signedness = .unsigned,
2879 .bits = pt.zcu.errorSetBits(),
2880 }, mod, kind),
2881
2882 .undef,
2883 .simple_value,
2884 .variable,
2885 .@"extern",
2886 .func,
2887 .int,
2888 .err,
2889 .error_union,
2890 .enum_literal,
2891 .enum_tag,
2892 .empty_enum_value,
2893 .float,
2894 .ptr,
2895 .slice,
2896 .opt,
2897 .aggregate,
2898 .un,
2899 .memoized_call,
2900 => unreachable, // values, not types
2901 },
2902 }
2903 }
2904
2905 pub fn getOrPutAdapted(
2906 pool: *Pool,
2907 allocator: std.mem.Allocator,
2908 source_pool: *const Pool,
2909 source_ctype: CType,
2910 pool_adapter: anytype,
2911 ) !struct { CType, bool } {
2912 const tag = source_pool.items.items(.tag)[
2913 source_ctype.toPoolIndex() orelse return .{ source_ctype, true }
2914 ];
2915 try pool.ensureUnusedCapacity(allocator, 1);
2916 const CTypeAdapter = struct {
2917 pool: *const Pool,
2918 source_pool: *const Pool,
2919 source_info: Info,
2920 pool_adapter: @TypeOf(pool_adapter),
2921 pub fn hash(map_adapter: @This(), key_ctype: CType) Map.Hash {
2922 return key_ctype.hash(map_adapter.source_pool);
2923 }
2924 pub fn eql(map_adapter: @This(), _: CType, _: void, pool_index: usize) bool {
2925 return map_adapter.source_info.eqlAdapted(
2926 map_adapter.source_pool,
2927 .fromPoolIndex(pool_index),
2928 map_adapter.pool,
2929 map_adapter.pool_adapter,
2930 );
2931 }
2932 };
2933 const source_info = source_ctype.info(source_pool);
2934 const gop = pool.map.getOrPutAssumeCapacityAdapted(source_ctype, CTypeAdapter{
2935 .pool = pool,
2936 .source_pool = source_pool,
2937 .source_info = source_info,
2938 .pool_adapter = pool_adapter,
2939 });
2940 errdefer _ = pool.map.pop();
2941 const ctype: CType = .fromPoolIndex(gop.index);
2942 if (!gop.found_existing) switch (source_info) {
2943 .basic => unreachable,
2944 .pointer => |pointer_info| pool.items.appendAssumeCapacity(switch (pointer_info.nonstring) {
2945 false => .{
2946 .tag = tag,
2947 .data = @intFromEnum(pool_adapter.copy(pointer_info.elem_ctype).index),
2948 },
2949 true => .{
2950 .tag = .nonstring,
2951 .data = @intFromEnum(pool_adapter.copy(.{ .index = @enumFromInt(
2952 source_pool.items.items(.data)[source_ctype.toPoolIndex().?],
2953 ) }).index),
2954 },
2955 }),
2956 .aligned => |aligned_info| pool.items.appendAssumeCapacity(.{
2957 .tag = tag,
2958 .data = try pool.addExtra(allocator, Aligned, .{
2959 .ctype = pool_adapter.copy(aligned_info.ctype).index,
2960 .flags = .{ .alignas = aligned_info.alignas },
2961 }, 0),
2962 }),
2963 .array, .vector => |sequence_info| pool.items.appendAssumeCapacity(switch (sequence_info.nonstring) {
2964 false => .{
2965 .tag = tag,
2966 .data = switch (tag) {
2967 .array_small, .vector => try pool.addExtra(allocator, SequenceSmall, .{
2968 .elem_ctype = pool_adapter.copy(sequence_info.elem_ctype).index,
2969 .len = @intCast(sequence_info.len),
2970 }, 0),
2971 .array_large => try pool.addExtra(allocator, SequenceLarge, .{
2972 .elem_ctype = pool_adapter.copy(sequence_info.elem_ctype).index,
2973 .len_lo = @truncate(sequence_info.len >> 0),
2974 .len_hi = @truncate(sequence_info.len >> 32),
2975 }, 0),
2976 else => unreachable,
2977 },
2978 },
2979 true => .{
2980 .tag = .nonstring,
2981 .data = @intFromEnum(pool_adapter.copy(.{ .index = @enumFromInt(
2982 source_pool.items.items(.data)[source_ctype.toPoolIndex().?],
2983 ) }).index),
2984 },
2985 }),
2986 .fwd_decl => |fwd_decl_info| switch (fwd_decl_info.name) {
2987 .anon => |fields| {
2988 pool.items.appendAssumeCapacity(.{
2989 .tag = tag,
2990 .data = try pool.addExtra(allocator, FwdDeclAnon, .{
2991 .fields_len = fields.len,
2992 }, fields.len * @typeInfo(Field).@"struct".fields.len),
2993 });
2994 for (0..fields.len) |field_index| {
2995 const field = fields.at(field_index, source_pool);
2996 const field_name = if (field.name.toPoolSlice(source_pool)) |slice|
2997 try pool.string(allocator, slice)
2998 else
2999 field.name;
3000 pool.addExtraAssumeCapacity(Field, .{
3001 .name = field_name.index,
3002 .ctype = pool_adapter.copy(field.ctype).index,
3003 .flags = .{ .alignas = field.alignas },
3004 });
3005 }
3006 },
3007 .index => |index| pool.items.appendAssumeCapacity(.{
3008 .tag = tag,
3009 .data = @intFromEnum(index),
3010 }),
3011 },
3012 .aggregate => |aggregate_info| {
3013 pool.items.appendAssumeCapacity(.{
3014 .tag = tag,
3015 .data = switch (aggregate_info.name) {
3016 .anon => |anon| try pool.addExtra(allocator, AggregateAnon, .{
3017 .index = anon.index,
3018 .id = anon.id,
3019 .fields_len = aggregate_info.fields.len,
3020 }, aggregate_info.fields.len * @typeInfo(Field).@"struct".fields.len),
3021 .fwd_decl => |fwd_decl| try pool.addExtra(allocator, Aggregate, .{
3022 .fwd_decl = pool_adapter.copy(fwd_decl).index,
3023 .fields_len = aggregate_info.fields.len,
3024 }, aggregate_info.fields.len * @typeInfo(Field).@"struct".fields.len),
3025 },
3026 });
3027 for (0..aggregate_info.fields.len) |field_index| {
3028 const field = aggregate_info.fields.at(field_index, source_pool);
3029 const field_name = if (field.name.toPoolSlice(source_pool)) |slice|
3030 try pool.string(allocator, slice)
3031 else
3032 field.name;
3033 pool.addExtraAssumeCapacity(Field, .{
3034 .name = field_name.index,
3035 .ctype = pool_adapter.copy(field.ctype).index,
3036 .flags = .{ .alignas = field.alignas },
3037 });
3038 }
3039 },
3040 .function => |function_info| {
3041 pool.items.appendAssumeCapacity(.{
3042 .tag = tag,
3043 .data = try pool.addExtra(allocator, Function, .{
3044 .return_ctype = pool_adapter.copy(function_info.return_ctype).index,
3045 .param_ctypes_len = function_info.param_ctypes.len,
3046 }, function_info.param_ctypes.len),
3047 });
3048 for (0..function_info.param_ctypes.len) |param_index| pool.extra.appendAssumeCapacity(
3049 @intFromEnum(pool_adapter.copy(
3050 function_info.param_ctypes.at(param_index, source_pool),
3051 ).index),
3052 );
3053 },
3054 };
3055 assert(source_info.eqlAdapted(source_pool, ctype, pool, pool_adapter));
3056 assert(source_ctype.hash(source_pool) == ctype.hash(pool));
3057 return .{ ctype, gop.found_existing };
3058 }
3059
3060 pub fn string(pool: *Pool, allocator: std.mem.Allocator, slice: []const u8) !String {
3061 try pool.string_bytes.appendSlice(allocator, slice);
3062 return pool.trailingString(allocator);
3063 }
3064
3065 pub fn fmt(
3066 pool: *Pool,
3067 allocator: std.mem.Allocator,
3068 comptime fmt_str: []const u8,
3069 fmt_args: anytype,
3070 ) !String {
3071 try pool.string_bytes.print(allocator, fmt_str, fmt_args);
3072 return pool.trailingString(allocator);
3073 }
3074
3075 fn ensureUnusedCapacity(pool: *Pool, allocator: std.mem.Allocator, len: u32) !void {
3076 try pool.map.ensureUnusedCapacity(allocator, len);
3077 try pool.items.ensureUnusedCapacity(allocator, len);
3078 }
3079
3080 const Hasher = struct {
3081 const Impl = std.hash.Wyhash;
3082 impl: Impl,
3083
3084 const init: Hasher = .{ .impl = Impl.init(0) };
3085
3086 fn updateExtra(hasher: *Hasher, comptime Extra: type, extra: Extra, pool: *const Pool) void {
3087 inline for (@typeInfo(Extra).@"struct".fields) |field| {
3088 const value = @field(extra, field.name);
3089 switch (field.type) {
3090 Pool.Tag, String, CType => unreachable,
3091 CType.Index => hasher.update((CType{ .index = value }).hash(pool)),
3092 String.Index => if ((String{ .index = value }).toPoolSlice(pool)) |slice|
3093 hasher.update(slice)
3094 else
3095 hasher.update(@intFromEnum(value)),
3096 else => hasher.update(value),
3097 }
3098 }
3099 }
3100 fn update(hasher: *Hasher, data: anytype) void {
3101 switch (@TypeOf(data)) {
3102 Pool.Tag => @compileError("pass tag to final"),
3103 CType, CType.Index => @compileError("hash ctype.hash(pool) instead"),
3104 String, String.Index => @compileError("hash string.slice(pool) instead"),
3105 u32, InternPool.Index, Aligned.Flags => hasher.impl.update(std.mem.asBytes(&data)),
3106 []const u8 => hasher.impl.update(data),
3107 else => @compileError("unhandled type: " ++ @typeName(@TypeOf(data))),
3108 }
3109 }
3110
3111 fn final(hasher: Hasher, tag: Pool.Tag) Map.Hash {
3112 var impl = hasher.impl;
3113 impl.update(std.mem.asBytes(&tag));
3114 return @truncate(impl.final());
3115 }
3116 };
3117
3118 fn tagData(
3119 pool: *Pool,
3120 allocator: std.mem.Allocator,
3121 hasher: Hasher,
3122 tag: Pool.Tag,
3123 data: u32,
3124 ) !CType {
3125 try pool.ensureUnusedCapacity(allocator, 1);
3126 const Key = struct { hash: Map.Hash, tag: Pool.Tag, data: u32 };
3127 const CTypeAdapter = struct {
3128 pool: *const Pool,
3129 pub fn hash(_: @This(), key: Key) Map.Hash {
3130 return key.hash;
3131 }
3132 pub fn eql(ctype_adapter: @This(), lhs_key: Key, _: void, rhs_index: usize) bool {
3133 const rhs_item = ctype_adapter.pool.items.get(rhs_index);
3134 return lhs_key.tag == rhs_item.tag and lhs_key.data == rhs_item.data;
3135 }
3136 };
3137 const gop = pool.map.getOrPutAssumeCapacityAdapted(
3138 Key{ .hash = hasher.final(tag), .tag = tag, .data = data },
3139 CTypeAdapter{ .pool = pool },
3140 );
3141 if (!gop.found_existing) pool.items.appendAssumeCapacity(.{ .tag = tag, .data = data });
3142 return .fromPoolIndex(gop.index);
3143 }
3144
3145 fn tagExtra(
3146 pool: *Pool,
3147 allocator: std.mem.Allocator,
3148 tag: Pool.Tag,
3149 comptime Extra: type,
3150 extra: Extra,
3151 ) !CType {
3152 var hasher = Hasher.init;
3153 hasher.updateExtra(Extra, extra, pool);
3154 return pool.tagTrailingExtra(
3155 allocator,
3156 hasher,
3157 tag,
3158 try pool.addExtra(allocator, Extra, extra, 0),
3159 );
3160 }
3161
3162 fn tagTrailingExtra(
3163 pool: *Pool,
3164 allocator: std.mem.Allocator,
3165 hasher: Hasher,
3166 tag: Pool.Tag,
3167 extra_index: ExtraIndex,
3168 ) !CType {
3169 try pool.ensureUnusedCapacity(allocator, 1);
3170 return pool.tagTrailingExtraAssumeCapacity(hasher, tag, extra_index);
3171 }
3172
3173 fn tagTrailingExtraAssumeCapacity(
3174 pool: *Pool,
3175 hasher: Hasher,
3176 tag: Pool.Tag,
3177 extra_index: ExtraIndex,
3178 ) CType {
3179 const Key = struct { hash: Map.Hash, tag: Pool.Tag, extra: []const u32 };
3180 const CTypeAdapter = struct {
3181 pool: *const Pool,
3182 pub fn hash(_: @This(), key: Key) Map.Hash {
3183 return key.hash;
3184 }
3185 pub fn eql(ctype_adapter: @This(), lhs_key: Key, _: void, rhs_index: usize) bool {
3186 const rhs_item = ctype_adapter.pool.items.get(rhs_index);
3187 if (lhs_key.tag != rhs_item.tag) return false;
3188 const rhs_extra = ctype_adapter.pool.extra.items[rhs_item.data..];
3189 return std.mem.startsWith(u32, rhs_extra, lhs_key.extra);
3190 }
3191 };
3192 const gop = pool.map.getOrPutAssumeCapacityAdapted(
3193 Key{ .hash = hasher.final(tag), .tag = tag, .extra = pool.extra.items[extra_index..] },
3194 CTypeAdapter{ .pool = pool },
3195 );
3196 if (gop.found_existing)
3197 pool.extra.shrinkRetainingCapacity(extra_index)
3198 else
3199 pool.items.appendAssumeCapacity(.{ .tag = tag, .data = extra_index });
3200 return .fromPoolIndex(gop.index);
3201 }
3202
3203 fn sortFields(fields: []Info.Field) void {
3204 std.mem.sort(Info.Field, fields, {}, struct {
3205 fn before(_: void, lhs_field: Info.Field, rhs_field: Info.Field) bool {
3206 return lhs_field.alignas.order(rhs_field.alignas).compare(.gt);
3207 }
3208 }.before);
3209 }
3210
3211 fn trailingString(pool: *Pool, allocator: std.mem.Allocator) !String {
3212 const start = pool.string_indices.getLast();
3213 const slice: []const u8 = pool.string_bytes.items[start..];
3214 if (slice.len >= 2 and slice[0] == 'f' and switch (slice[1]) {
3215 '0' => slice.len == 2,
3216 '1'...'9' => true,
3217 else => false,
3218 }) if (std.fmt.parseInt(u31, slice[1..], 10)) |unnamed| {
3219 pool.string_bytes.shrinkRetainingCapacity(start);
3220 return String.fromUnnamed(unnamed);
3221 } else |_| {};
3222 if (std.meta.stringToEnum(String.Index, slice)) |index| {
3223 pool.string_bytes.shrinkRetainingCapacity(start);
3224 return .{ .index = index };
3225 }
3226
3227 try pool.string_map.ensureUnusedCapacity(allocator, 1);
3228 try pool.string_indices.ensureUnusedCapacity(allocator, 1);
3229
3230 const gop = pool.string_map.getOrPutAssumeCapacityAdapted(slice, String.Adapter{ .pool = pool });
3231 if (gop.found_existing)
3232 pool.string_bytes.shrinkRetainingCapacity(start)
3233 else
3234 pool.string_indices.appendAssumeCapacity(@intCast(pool.string_bytes.items.len));
3235 return String.fromPoolIndex(gop.index);
3236 }
3237
3238 const Item = struct {
3239 tag: Pool.Tag,
3240 data: u32,
3241 };
3242
3243 const ExtraIndex = u32;
3244
3245 const Tag = enum(u8) {
3246 basic,
3247 pointer,
3248 pointer_const,
3249 pointer_volatile,
3250 pointer_const_volatile,
3251 aligned,
3252 array_small,
3253 array_large,
3254 vector,
3255 nonstring,
3256 fwd_decl_struct_anon,
3257 fwd_decl_union_anon,
3258 fwd_decl_struct,
3259 fwd_decl_union,
3260 aggregate_struct_anon,
3261 aggregate_struct_packed_anon,
3262 aggregate_union_anon,
3263 aggregate_union_packed_anon,
3264 aggregate_struct,
3265 aggregate_struct_packed,
3266 aggregate_union,
3267 aggregate_union_packed,
3268 function,
3269 function_varargs,
3270 };
3271
3272 const Aligned = struct {
3273 ctype: CType.Index,
3274 flags: Flags,
3275
3276 const Flags = packed struct(u32) {
3277 alignas: AlignAs,
3278 _: u20 = 0,
3279 };
3280 };
3281
3282 const SequenceSmall = struct {
3283 elem_ctype: CType.Index,
3284 len: u32,
3285 };
3286
3287 const SequenceLarge = struct {
3288 elem_ctype: CType.Index,
3289 len_lo: u32,
3290 len_hi: u32,
3291
3292 fn len(extra: SequenceLarge) u64 {
3293 return @as(u64, extra.len_lo) << 0 |
3294 @as(u64, extra.len_hi) << 32;
3295 }
3296 };
3297
3298 const Field = struct {
3299 name: String.Index,
3300 ctype: CType.Index,
3301 flags: Flags,
3302
3303 const Flags = Aligned.Flags;
3304 };
3305
3306 const FwdDeclAnon = struct {
3307 fields_len: u32,
3308 };
3309
3310 const AggregateAnon = struct {
3311 index: InternPool.Index,
3312 id: u32,
3313 fields_len: u32,
3314 };
3315
3316 const Aggregate = struct {
3317 fwd_decl: CType.Index,
3318 fields_len: u32,
3319 };
3320
3321 const Function = struct {
3322 return_ctype: CType.Index,
3323 param_ctypes_len: u32,
3324 };
3325
3326 fn addExtra(
3327 pool: *Pool,
3328 allocator: std.mem.Allocator,
3329 comptime Extra: type,
3330 extra: Extra,
3331 trailing_len: usize,
3332 ) !ExtraIndex {
3333 try pool.extra.ensureUnusedCapacity(
3334 allocator,
3335 @typeInfo(Extra).@"struct".fields.len + trailing_len,
3336 );
3337 defer pool.addExtraAssumeCapacity(Extra, extra);
3338 return @intCast(pool.extra.items.len);
3339 }
3340 fn addExtraAssumeCapacity(pool: *Pool, comptime Extra: type, extra: Extra) void {
3341 addExtraAssumeCapacityTo(&pool.extra, Extra, extra);
3342 }
3343 fn addExtraAssumeCapacityTo(
3344 array: *std.ArrayList(u32),
3345 comptime Extra: type,
3346 extra: Extra,
3347 ) void {
3348 inline for (@typeInfo(Extra).@"struct".fields) |field| {
3349 const value = @field(extra, field.name);
3350 array.appendAssumeCapacity(switch (field.type) {
3351 u32 => value,
3352 CType.Index, String.Index, InternPool.Index => @intFromEnum(value),
3353 Aligned.Flags => @bitCast(value),
3354 else => @compileError("bad field type: " ++ field.name ++ ": " ++
3355 @typeName(field.type)),
3356 });
3357 }
3358 }
3359
3360 fn addHashedExtra(
3361 pool: *Pool,
3362 allocator: std.mem.Allocator,
3363 hasher: *Hasher,
3364 comptime Extra: type,
3365 extra: Extra,
3366 trailing_len: usize,
3367 ) !ExtraIndex {
3368 hasher.updateExtra(Extra, extra, pool);
3369 return pool.addExtra(allocator, Extra, extra, trailing_len);
3370 }
3371 fn addHashedExtraAssumeCapacity(
3372 pool: *Pool,
3373 hasher: *Hasher,
3374 comptime Extra: type,
3375 extra: Extra,
3376 ) void {
3377 hasher.updateExtra(Extra, extra, pool);
3378 pool.addExtraAssumeCapacity(Extra, extra);
3379 }
3380 fn addHashedExtraAssumeCapacityTo(
3381 pool: *Pool,
3382 array: *std.ArrayList(u32),
3383 hasher: *Hasher,
3384 comptime Extra: type,
3385 extra: Extra,
3386 ) void {
3387 hasher.updateExtra(Extra, extra, pool);
3388 addExtraAssumeCapacityTo(array, Extra, extra);
3389 }
3390
3391 const ExtraTrail = struct {
3392 extra_index: ExtraIndex,
3393
3394 fn next(
3395 extra_trail: *ExtraTrail,
3396 len: u32,
3397 comptime Extra: type,
3398 pool: *const Pool,
3399 ) []const Extra {
3400 defer extra_trail.extra_index += @intCast(len);
3401 return @ptrCast(pool.extra.items[extra_trail.extra_index..][0..len]);
3402 }
3403 };
3404
3405 fn getExtraTrail(
3406 pool: *const Pool,
3407 comptime Extra: type,
3408 extra_index: ExtraIndex,
3409 ) struct { extra: Extra, trail: ExtraTrail } {
3410 var extra: Extra = undefined;
3411 const fields = @typeInfo(Extra).@"struct".fields;
3412 inline for (fields, pool.extra.items[extra_index..][0..fields.len]) |field, value|
3413 @field(extra, field.name) = switch (field.type) {
3414 u32 => value,
3415 CType.Index, String.Index, InternPool.Index => @enumFromInt(value),
3416 Aligned.Flags => @bitCast(value),
3417 else => @compileError("bad field type: " ++ field.name ++ ": " ++ @typeName(field.type)),
3418 };
3419 return .{
3420 .extra = extra,
3421 .trail = .{ .extra_index = extra_index + @as(ExtraIndex, @intCast(fields.len)) },
3422 };
3423 }
3424
3425 fn getExtra(pool: *const Pool, comptime Extra: type, extra_index: ExtraIndex) Extra {
3426 return pool.getExtraTrail(Extra, extra_index).extra;
3427 }
3428};
3429
3430pub const AlignAs = packed struct {
3431 @"align": InternPool.Alignment,
3432 abi: InternPool.Alignment,
3433
3434 pub fn fromAlignment(alignas: AlignAs) AlignAs {
3435 assert(alignas.abi != .none);
3436 return .{
3437 .@"align" = if (alignas.@"align" != .none) alignas.@"align" else alignas.abi,
3438 .abi = alignas.abi,
3439 };
3440 }
3441 pub fn fromAbiAlignment(abi: InternPool.Alignment) AlignAs {
3442 assert(abi != .none);
3443 return .{ .@"align" = abi, .abi = abi };
3444 }
3445 pub fn fromByteUnits(@"align": u64, abi: u64) AlignAs {
3446 return fromAlignment(.{
3447 .@"align" = InternPool.Alignment.fromByteUnits(@"align"),
3448 .abi = InternPool.Alignment.fromNonzeroByteUnits(abi),
3449 });
3450 }
3451
3452 pub fn order(lhs: AlignAs, rhs: AlignAs) std.math.Order {
3453 return lhs.@"align".order(rhs.@"align");
3454 }
3455 pub fn abiOrder(alignas: AlignAs) std.math.Order {
3456 return alignas.@"align".order(alignas.abi);
3457 }
3458 pub fn toByteUnits(alignas: AlignAs) u64 {
3459 return alignas.@"align".toByteUnits().?;
3460 }
3461};
3462
3463const std = @import("std");
3464const assert = std.debug.assert;
3465const Writer = std.Io.Writer;
3466
3467const CType = @This();
3468const InternPool = @import("../../InternPool.zig");
3469const Module = @import("../../Package/Module.zig");
3470const Type = @import("../../Type.zig");
3471const Value = @import("../../Value.zig");
3472const Zcu = @import("../../Zcu.zig");