authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2024-03-28 20:41:58-04:00
committergravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2024-03-30 20:50:48-04:00
log5a41704f7ec2c472897f955ecfe1feafa697ff68
tree62984e96e61c367ce7ad304fc532051c10e6921d
parent6f10b11658c002b26341bff10e1dd522f2465b5a

cbe: rewrite `CType`

Closes #14904

45 files changed, 3658 insertions(+), 3604 deletions(-)

CMakeLists.txt+1-1
......@@ -564,7 +564,7 @@ set(ZIG_STAGE2_SOURCES
564564 "${CMAKE_SOURCE_DIR}/src/clang_options_data.zig"
565565 "${CMAKE_SOURCE_DIR}/src/codegen.zig"
566566 "${CMAKE_SOURCE_DIR}/src/codegen/c.zig"
567 "${CMAKE_SOURCE_DIR}/src/codegen/c/type.zig"
567 "${CMAKE_SOURCE_DIR}/src/codegen/c/Type.zig"
568568 "${CMAKE_SOURCE_DIR}/src/codegen/llvm.zig"
569569 "${CMAKE_SOURCE_DIR}/src/codegen/llvm/bindings.zig"
570570 "${CMAKE_SOURCE_DIR}/src/glibc.zig"
build.zig+1-3
......@@ -16,9 +16,7 @@ pub fn build(b: *std.Build) !void {
1616 const only_c = b.option(bool, "only-c", "Translate the Zig compiler to C code, with only the C backend enabled") orelse false;
1717 const target = t: {
1818 var default_target: std.zig.CrossTarget = .{};
19 if (only_c) {
20 default_target.ofmt = .c;
21 }
19 default_target.ofmt = b.option(std.Target.ObjectFormat, "ofmt", "Object format to target") orelse if (only_c) .c else null;
2220 break :t b.standardTargetOptions(.{ .default_target = default_target });
2321 };
2422
lib/std/c/darwin.zig+2-2
......@@ -1150,8 +1150,8 @@ pub const siginfo_t = extern struct {
11501150
11511151/// Renamed from `sigaction` to `Sigaction` to avoid conflict with function name.
11521152pub const Sigaction = extern struct {
1153 pub const handler_fn = *align(1) const fn (c_int) callconv(.C) void;
1154 pub const sigaction_fn = *const fn (c_int, *const siginfo_t, ?*anyopaque) callconv(.C) void;
1153 pub const handler_fn = *align(1) const fn (i32) callconv(.C) void;
1154 pub const sigaction_fn = *const fn (i32, *const siginfo_t, ?*anyopaque) callconv(.C) void;
11551155
11561156 handler: extern union {
11571157 handler: ?handler_fn,
lib/std/c/dragonfly.zig+3-3
......@@ -690,8 +690,8 @@ pub const empty_sigset = sigset_t{ .__bits = [_]c_uint{0} ** _SIG_WORDS };
690690pub const sig_atomic_t = c_int;
691691
692692pub const Sigaction = extern struct {
693 pub const handler_fn = *align(1) const fn (c_int) callconv(.C) void;
694 pub const sigaction_fn = *const fn (c_int, *const siginfo_t, ?*anyopaque) callconv(.C) void;
693 pub const handler_fn = *align(1) const fn (i32) callconv(.C) void;
694 pub const sigaction_fn = *const fn (i32, *const siginfo_t, ?*anyopaque) callconv(.C) void;
695695
696696 /// signal handler
697697 handler: extern union {
......@@ -702,7 +702,7 @@ pub const Sigaction = extern struct {
702702 mask: sigset_t,
703703};
704704
705pub const sig_t = *const fn (c_int) callconv(.C) void;
705pub const sig_t = *const fn (i32) callconv(.C) void;
706706
707707pub const SOCK = struct {
708708 pub const STREAM = 1;
lib/std/c/freebsd.zig+2-2
......@@ -1171,8 +1171,8 @@ const NSIG = 32;
11711171
11721172/// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall.
11731173pub const Sigaction = extern struct {
1174 pub const handler_fn = *align(1) const fn (c_int) callconv(.C) void;
1175 pub const sigaction_fn = *const fn (c_int, *const siginfo_t, ?*anyopaque) callconv(.C) void;
1174 pub const handler_fn = *align(1) const fn (i32) callconv(.C) void;
1175 pub const sigaction_fn = *const fn (i32, *const siginfo_t, ?*anyopaque) callconv(.C) void;
11761176
11771177 /// signal handler
11781178 handler: extern union {
lib/std/c/haiku.zig+1-1
......@@ -501,7 +501,7 @@ pub const siginfo_t = extern struct {
501501/// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall.
502502pub const Sigaction = extern struct {
503503 pub const handler_fn = *align(1) const fn (i32) callconv(.C) void;
504 pub const sigaction_fn = *const fn (c_int, *allowzero anyopaque, ?*anyopaque) callconv(.C) void;
504 pub const sigaction_fn = *const fn (i32, *const siginfo_t, ?*anyopaque) callconv(.C) void;
505505
506506 /// signal handler
507507 handler: extern union {
lib/std/c/netbsd.zig+2-2
......@@ -864,8 +864,8 @@ pub const SIG = struct {
864864
865865/// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall.
866866pub const Sigaction = extern struct {
867 pub const handler_fn = *align(1) const fn (c_int) callconv(.C) void;
868 pub const sigaction_fn = *const fn (c_int, *const siginfo_t, ?*anyopaque) callconv(.C) void;
867 pub const handler_fn = *align(1) const fn (i32) callconv(.C) void;
868 pub const sigaction_fn = *const fn (i32, *const siginfo_t, ?*anyopaque) callconv(.C) void;
869869
870870 /// signal handler
871871 handler: extern union {
lib/std/c/openbsd.zig+2-2
......@@ -842,8 +842,8 @@ pub const SIG = struct {
842842
843843/// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall.
844844pub const Sigaction = extern struct {
845 pub const handler_fn = *align(1) const fn (c_int) callconv(.C) void;
846 pub const sigaction_fn = *const fn (c_int, *const siginfo_t, ?*anyopaque) callconv(.C) void;
845 pub const handler_fn = *align(1) const fn (i32) callconv(.C) void;
846 pub const sigaction_fn = *const fn (i32, *const siginfo_t, ?*anyopaque) callconv(.C) void;
847847
848848 /// signal handler
849849 handler: extern union {
lib/std/c/solaris.zig+2-2
......@@ -874,8 +874,8 @@ pub const SIG = struct {
874874
875875/// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall.
876876pub const Sigaction = extern struct {
877 pub const handler_fn = *align(1) const fn (c_int) callconv(.C) void;
878 pub const sigaction_fn = *const fn (c_int, *const siginfo_t, ?*anyopaque) callconv(.C) void;
877 pub const handler_fn = *align(1) const fn (i32) callconv(.C) void;
878 pub const sigaction_fn = *const fn (i32, *const siginfo_t, ?*anyopaque) callconv(.C) void;
879879
880880 /// signal options
881881 flags: c_uint,
lib/std/debug.zig+1-1
......@@ -2570,7 +2570,7 @@ fn resetSegfaultHandler() void {
25702570 updateSegfaultHandler(&act) catch {};
25712571}
25722572
2573fn handleSegfaultPosix(sig: i32, info: *const posix.siginfo_t, ctx_ptr: ?*const anyopaque) callconv(.C) noreturn {
2573fn handleSegfaultPosix(sig: i32, info: *const posix.siginfo_t, ctx_ptr: ?*anyopaque) callconv(.C) noreturn {
25742574 // Reset to the default handler so that if a segfault happens in this handler it will crash
25752575 // the process. Also when this handler returns, the original instruction will be repeated
25762576 // and the resulting segfault will crash the process rather than continually dump stack traces.
lib/std/os/emscripten.zig+2-2
......@@ -695,8 +695,8 @@ pub const SIG = struct {
695695};
696696
697697pub const Sigaction = extern struct {
698 pub const handler_fn = *align(1) const fn (c_int) callconv(.C) void;
699 pub const sigaction_fn = *const fn (c_int, *const siginfo_t, ?*anyopaque) callconv(.C) void;
698 pub const handler_fn = *align(1) const fn (i32) callconv(.C) void;
699 pub const sigaction_fn = *const fn (i32, *const siginfo_t, ?*anyopaque) callconv(.C) void;
700700
701701 handler: extern union {
702702 handler: ?handler_fn,
lib/std/os/linux.zig+3-3
......@@ -4301,7 +4301,7 @@ pub const all_mask: sigset_t = [_]u32{0xffffffff} ** @typeInfo(sigset_t).Array.l
43014301pub const app_mask: sigset_t = [2]u32{ 0xfffffffc, 0x7fffffff } ++ [_]u32{0xffffffff} ** 30;
43024302
43034303const k_sigaction_funcs = struct {
4304 const handler = ?*align(1) const fn (c_int) callconv(.C) void;
4304 const handler = ?*align(1) const fn (i32) callconv(.C) void;
43054305 const restorer = *const fn () callconv(.C) void;
43064306};
43074307
......@@ -4328,8 +4328,8 @@ pub const k_sigaction = switch (native_arch) {
43284328
43294329/// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall.
43304330pub const Sigaction = extern struct {
4331 pub const handler_fn = *align(1) const fn (c_int) callconv(.C) void;
4332 pub const sigaction_fn = *const fn (c_int, *const siginfo_t, ?*anyopaque) callconv(.C) void;
4331 pub const handler_fn = *align(1) const fn (i32) callconv(.C) void;
4332 pub const sigaction_fn = *const fn (i32, *const siginfo_t, ?*anyopaque) callconv(.C) void;
43334333
43344334 handler: extern union {
43354335 handler: ?handler_fn,
lib/std/os/plan9.zig+2-2
......@@ -186,8 +186,8 @@ pub const empty_sigset = 0;
186186pub const siginfo_t = c_long;
187187// TODO plan9 doesn't have sigaction_fn. Sigaction is not a union, but we incude it here to be compatible.
188188pub const Sigaction = extern struct {
189 pub const handler_fn = *const fn (c_int) callconv(.C) void;
190 pub const sigaction_fn = *const fn (c_int, *const siginfo_t, ?*anyopaque) callconv(.C) void;
189 pub const handler_fn = *const fn (i32) callconv(.C) void;
190 pub const sigaction_fn = *const fn (i32, *const siginfo_t, ?*anyopaque) callconv(.C) void;
191191
192192 handler: extern union {
193193 handler: ?handler_fn,
lib/std/start.zig+1-1
......@@ -597,4 +597,4 @@ fn maybeIgnoreSigpipe() void {
597597 }
598598}
599599
600fn noopSigHandler(_: c_int) callconv(.C) void {}
600fn noopSigHandler(_: i32) callconv(.C) void {}
src/Compilation.zig+7-6
......@@ -3457,14 +3457,18 @@ fn processOneJob(comp: *Compilation, job: Job, prog_node: *std.Progress.Node) !v
34573457 .pass = .{ .decl = decl_index },
34583458 .is_naked_fn = false,
34593459 .fwd_decl = fwd_decl.toManaged(gpa),
3460 .ctypes = .{},
3460 .ctype_pool = c_codegen.CType.Pool.empty,
3461 .scratch = .{},
34613462 .anon_decl_deps = .{},
34623463 .aligned_anon_decls = .{},
34633464 };
34643465 defer {
3465 dg.ctypes.deinit(gpa);
3466 dg.fwd_decl.deinit();
3466 fwd_decl.* = dg.fwd_decl.moveToUnmanaged();
3467 fwd_decl.shrinkAndFree(gpa, fwd_decl.items.len);
3468 dg.ctype_pool.deinit(gpa);
3469 dg.scratch.deinit(gpa);
34673470 }
3471 try dg.ctype_pool.init(gpa);
34683472
34693473 c_codegen.genHeader(&dg) catch |err| switch (err) {
34703474 error.AnalysisFail => {
......@@ -3473,9 +3477,6 @@ fn processOneJob(comp: *Compilation, job: Job, prog_node: *std.Progress.Node) !v
34733477 },
34743478 else => |e| return e,
34753479 };
3476
3477 fwd_decl.* = dg.fwd_decl.moveToUnmanaged();
3478 fwd_decl.shrinkAndFree(gpa, fwd_decl.items.len);
34793480 },
34803481 }
34813482 },
src/InternPool.zig+2-9
......@@ -712,7 +712,7 @@ pub const Key = union(enum) {
712712 pub fn fieldName(
713713 self: AnonStructType,
714714 ip: *const InternPool,
715 index: u32,
715 index: usize,
716716 ) OptionalNullTerminatedString {
717717 if (self.names.len == 0)
718718 return .none;
......@@ -3879,20 +3879,13 @@ pub const Alignment = enum(u6) {
38793879 none = std.math.maxInt(u6),
38803880 _,
38813881
3882 pub fn toByteUnitsOptional(a: Alignment) ?u64 {
3882 pub fn toByteUnits(a: Alignment) ?u64 {
38833883 return switch (a) {
38843884 .none => null,
38853885 else => @as(u64, 1) << @intFromEnum(a),
38863886 };
38873887 }
38883888
3889 pub fn toByteUnits(a: Alignment, default: u64) u64 {
3890 return switch (a) {
3891 .none => default,
3892 else => @as(u64, 1) << @intFromEnum(a),
3893 };
3894 }
3895
38963889 pub fn fromByteUnits(n: u64) Alignment {
38973890 if (n == 0) return .none;
38983891 assert(std.math.isPowerOfTwo(n));
src/Module.zig+1-1
......@@ -5846,7 +5846,7 @@ pub fn intBitsForValue(mod: *Module, val: Value, sign: bool) u16 {
58465846 return @as(u16, @intCast(big.bitCountTwosComp()));
58475847 },
58485848 .lazy_align => |lazy_ty| {
5849 return Type.smallestUnsignedBits(Type.fromInterned(lazy_ty).abiAlignment(mod).toByteUnits(0)) + @intFromBool(sign);
5849 return Type.smallestUnsignedBits(Type.fromInterned(lazy_ty).abiAlignment(mod).toByteUnits() orelse 0) + @intFromBool(sign);
58505850 },
58515851 .lazy_size => |lazy_ty| {
58525852 return Type.smallestUnsignedBits(Type.fromInterned(lazy_ty).abiSize(mod)) + @intFromBool(sign);
src/Sema.zig+14-14
......@@ -6508,7 +6508,7 @@ fn zirSetAlignStack(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.Inst
65086508 const alignment = try sema.resolveAlign(block, operand_src, extra.operand);
65096509 if (alignment.order(Alignment.fromNonzeroByteUnits(256)).compare(.gt)) {
65106510 return sema.fail(block, src, "attempt to @setAlignStack({d}); maximum is 256", .{
6511 alignment.toByteUnitsOptional().?,
6511 alignment.toByteUnits().?,
65126512 });
65136513 }
65146514
......@@ -17804,7 +17804,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1780417804 },
1780517805 .Pointer => {
1780617806 const info = ty.ptrInfo(mod);
17807 const alignment = if (info.flags.alignment.toByteUnitsOptional()) |alignment|
17807 const alignment = if (info.flags.alignment.toByteUnits()) |alignment|
1780817808 try mod.intValue(Type.comptime_int, alignment)
1780917809 else
1781017810 try Type.fromInterned(info.child).lazyAbiAlignment(mod);
......@@ -18279,7 +18279,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1827918279 // type: type,
1828018280 field_ty,
1828118281 // alignment: comptime_int,
18282 (try mod.intValue(Type.comptime_int, alignment.toByteUnits(0))).toIntern(),
18282 (try mod.intValue(Type.comptime_int, alignment.toByteUnits() orelse 0)).toIntern(),
1828318283 };
1828418284 field_val.* = try mod.intern(.{ .aggregate = .{
1828518285 .ty = union_field_ty.toIntern(),
......@@ -18436,7 +18436,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1843618436 // is_comptime: bool,
1843718437 Value.makeBool(is_comptime).toIntern(),
1843818438 // alignment: comptime_int,
18439 (try mod.intValue(Type.comptime_int, Type.fromInterned(field_ty).abiAlignment(mod).toByteUnits(0))).toIntern(),
18439 (try mod.intValue(Type.comptime_int, Type.fromInterned(field_ty).abiAlignment(mod).toByteUnits() orelse 0)).toIntern(),
1844018440 };
1844118441 struct_field_val.* = try mod.intern(.{ .aggregate = .{
1844218442 .ty = struct_field_ty.toIntern(),
......@@ -18505,7 +18505,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1850518505 // is_comptime: bool,
1850618506 Value.makeBool(field_is_comptime).toIntern(),
1850718507 // alignment: comptime_int,
18508 (try mod.intValue(Type.comptime_int, alignment.toByteUnits(0))).toIntern(),
18508 (try mod.intValue(Type.comptime_int, alignment.toByteUnits() orelse 0)).toIntern(),
1850918509 };
1851018510 field_val.* = try mod.intern(.{ .aggregate = .{
1851118511 .ty = struct_field_ty.toIntern(),
......@@ -22552,7 +22552,7 @@ fn zirPtrFromInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!
2255222552 try sema.addSafetyCheck(block, src, is_non_zero, .cast_to_null);
2255322553 }
2255422554 if (ptr_align.compare(.gt, .@"1")) {
22555 const align_bytes_minus_1 = ptr_align.toByteUnitsOptional().? - 1;
22555 const align_bytes_minus_1 = ptr_align.toByteUnits().? - 1;
2255622556 const align_minus_1 = Air.internedToRef((try mod.intValue(Type.usize, align_bytes_minus_1)).toIntern());
2255722557 const remainder = try block.addBinOp(.bit_and, operand_coerced, align_minus_1);
2255822558 const is_aligned = try block.addBinOp(.cmp_eq, remainder, .zero_usize);
......@@ -22572,7 +22572,7 @@ fn zirPtrFromInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!
2257222572 try sema.addSafetyCheck(block, src, is_non_zero, .cast_to_null);
2257322573 }
2257422574 if (ptr_align.compare(.gt, .@"1")) {
22575 const align_bytes_minus_1 = ptr_align.toByteUnitsOptional().? - 1;
22575 const align_bytes_minus_1 = ptr_align.toByteUnits().? - 1;
2257622576 const align_minus_1 = Air.internedToRef((try mod.intValue(Type.usize, align_bytes_minus_1)).toIntern());
2257722577 const remainder = try block.addBinOp(.bit_and, elem_coerced, align_minus_1);
2257822578 const is_aligned = try block.addBinOp(.cmp_eq, remainder, .zero_usize);
......@@ -22970,10 +22970,10 @@ fn ptrCastFull(
2297022970 const msg = try sema.errMsg(block, src, "cast increases pointer alignment", .{});
2297122971 errdefer msg.destroy(sema.gpa);
2297222972 try sema.errNote(block, operand_src, msg, "'{}' has alignment '{d}'", .{
22973 operand_ty.fmt(mod), src_align.toByteUnits(0),
22973 operand_ty.fmt(mod), src_align.toByteUnits() orelse 0,
2297422974 });
2297522975 try sema.errNote(block, src, msg, "'{}' has alignment '{d}'", .{
22976 dest_ty.fmt(mod), dest_align.toByteUnits(0),
22976 dest_ty.fmt(mod), dest_align.toByteUnits() orelse 0,
2297722977 });
2297822978 try sema.errNote(block, src, msg, "use @alignCast to assert pointer alignment", .{});
2297922979 break :msg msg;
......@@ -23067,7 +23067,7 @@ fn ptrCastFull(
2306723067 if (!dest_align.check(addr)) {
2306823068 return sema.fail(block, operand_src, "pointer address 0x{X} is not aligned to {d} bytes", .{
2306923069 addr,
23070 dest_align.toByteUnitsOptional().?,
23070 dest_align.toByteUnits().?,
2307123071 });
2307223072 }
2307323073 }
......@@ -23110,7 +23110,7 @@ fn ptrCastFull(
2311023110 dest_align.compare(.gt, src_align) and
2311123111 try sema.typeHasRuntimeBits(Type.fromInterned(dest_info.child)))
2311223112 {
23113 const align_bytes_minus_1 = dest_align.toByteUnitsOptional().? - 1;
23113 const align_bytes_minus_1 = dest_align.toByteUnits().? - 1;
2311423114 const align_minus_1 = Air.internedToRef((try mod.intValue(Type.usize, align_bytes_minus_1)).toIntern());
2311523115 const ptr_int = try block.addUnOp(.int_from_ptr, ptr);
2311623116 const remainder = try block.addBinOp(.bit_and, ptr_int, align_minus_1);
......@@ -27837,7 +27837,7 @@ fn structFieldPtrByIndex(
2783727837 const elem_size_bits = Type.fromInterned(ptr_ty_data.child).bitSize(mod);
2783827838 if (elem_size_bytes * 8 == elem_size_bits) {
2783927839 const byte_offset = ptr_ty_data.packed_offset.bit_offset / 8;
27840 const new_align: Alignment = @enumFromInt(@ctz(byte_offset | parent_align.toByteUnitsOptional().?));
27840 const new_align: Alignment = @enumFromInt(@ctz(byte_offset | parent_align.toByteUnits().?));
2784127841 assert(new_align != .none);
2784227842 ptr_ty_data.flags.alignment = new_align;
2784327843 ptr_ty_data.packed_offset = .{ .host_size = 0, .bit_offset = 0 };
......@@ -29132,7 +29132,7 @@ fn coerceExtra(
2913229132 .addr = .{ .int = if (dest_info.flags.alignment != .none)
2913329133 (try mod.intValue(
2913429134 Type.usize,
29135 dest_info.flags.alignment.toByteUnitsOptional().?,
29135 dest_info.flags.alignment.toByteUnits().?,
2913629136 )).toIntern()
2913729137 else
2913829138 try mod.intern_pool.getCoercedInts(
......@@ -29800,7 +29800,7 @@ const InMemoryCoercionResult = union(enum) {
2980029800 },
2980129801 .ptr_alignment => |pair| {
2980229802 try sema.errNote(block, src, msg, "pointer alignment '{d}' cannot cast into pointer alignment '{d}'", .{
29803 pair.actual.toByteUnits(0), pair.wanted.toByteUnits(0),
29803 pair.actual.toByteUnits() orelse 0, pair.wanted.toByteUnits() orelse 0,
2980429804 });
2980529805 break;
2980629806 },
src/Value.zig+8-8
......@@ -176,7 +176,7 @@ pub fn toBigIntAdvanced(
176176 if (opt_sema) |sema| try sema.resolveTypeLayout(Type.fromInterned(ty));
177177 const x = switch (int.storage) {
178178 else => unreachable,
179 .lazy_align => Type.fromInterned(ty).abiAlignment(mod).toByteUnits(0),
179 .lazy_align => Type.fromInterned(ty).abiAlignment(mod).toByteUnits() orelse 0,
180180 .lazy_size => Type.fromInterned(ty).abiSize(mod),
181181 };
182182 return BigIntMutable.init(&space.limbs, x).toConst();
......@@ -237,9 +237,9 @@ pub fn getUnsignedIntAdvanced(val: Value, mod: *Module, opt_sema: ?*Sema) !?u64
237237 .u64 => |x| x,
238238 .i64 => |x| std.math.cast(u64, x),
239239 .lazy_align => |ty| if (opt_sema) |sema|
240 (try Type.fromInterned(ty).abiAlignmentAdvanced(mod, .{ .sema = sema })).scalar.toByteUnits(0)
240 (try Type.fromInterned(ty).abiAlignmentAdvanced(mod, .{ .sema = sema })).scalar.toByteUnits() orelse 0
241241 else
242 Type.fromInterned(ty).abiAlignment(mod).toByteUnits(0),
242 Type.fromInterned(ty).abiAlignment(mod).toByteUnits() orelse 0,
243243 .lazy_size => |ty| if (opt_sema) |sema|
244244 (try Type.fromInterned(ty).abiSizeAdvanced(mod, .{ .sema = sema })).scalar
245245 else
......@@ -289,7 +289,7 @@ pub fn toSignedInt(val: Value, mod: *Module) i64 {
289289 .big_int => |big_int| big_int.to(i64) catch unreachable,
290290 .i64 => |x| x,
291291 .u64 => |x| @intCast(x),
292 .lazy_align => |ty| @intCast(Type.fromInterned(ty).abiAlignment(mod).toByteUnits(0)),
292 .lazy_align => |ty| @intCast(Type.fromInterned(ty).abiAlignment(mod).toByteUnits() orelse 0),
293293 .lazy_size => |ty| @intCast(Type.fromInterned(ty).abiSize(mod)),
294294 },
295295 else => unreachable,
......@@ -497,7 +497,7 @@ pub fn writeToPackedMemory(
497497 inline .u64, .i64 => |int| std.mem.writeVarPackedInt(buffer, bit_offset, bits, int, endian),
498498 .big_int => |bigint| bigint.writePackedTwosComplement(buffer, bit_offset, bits, endian),
499499 .lazy_align => |lazy_align| {
500 const num = Type.fromInterned(lazy_align).abiAlignment(mod).toByteUnits(0);
500 const num = Type.fromInterned(lazy_align).abiAlignment(mod).toByteUnits() orelse 0;
501501 std.mem.writeVarPackedInt(buffer, bit_offset, bits, num, endian);
502502 },
503503 .lazy_size => |lazy_size| {
......@@ -890,7 +890,7 @@ pub fn toFloat(val: Value, comptime T: type, mod: *Module) T {
890890 }
891891 return @floatFromInt(x);
892892 },
893 .lazy_align => |ty| @floatFromInt(Type.fromInterned(ty).abiAlignment(mod).toByteUnits(0)),
893 .lazy_align => |ty| @floatFromInt(Type.fromInterned(ty).abiAlignment(mod).toByteUnits() orelse 0),
894894 .lazy_size => |ty| @floatFromInt(Type.fromInterned(ty).abiSize(mod)),
895895 },
896896 .float => |float| switch (float.storage) {
......@@ -1529,9 +1529,9 @@ pub fn floatFromIntScalar(val: Value, float_ty: Type, mod: *Module, opt_sema: ?*
15291529 },
15301530 inline .u64, .i64 => |x| floatFromIntInner(x, float_ty, mod),
15311531 .lazy_align => |ty| if (opt_sema) |sema| {
1532 return floatFromIntInner((try Type.fromInterned(ty).abiAlignmentAdvanced(mod, .{ .sema = sema })).scalar.toByteUnits(0), float_ty, mod);
1532 return floatFromIntInner((try Type.fromInterned(ty).abiAlignmentAdvanced(mod, .{ .sema = sema })).scalar.toByteUnits() orelse 0, float_ty, mod);
15331533 } else {
1534 return floatFromIntInner(Type.fromInterned(ty).abiAlignment(mod).toByteUnits(0), float_ty, mod);
1534 return floatFromIntInner(Type.fromInterned(ty).abiAlignment(mod).toByteUnits() orelse 0, float_ty, mod);
15351535 },
15361536 .lazy_size => |ty| if (opt_sema) |sema| {
15371537 return floatFromIntInner((try Type.fromInterned(ty).abiSizeAdvanced(mod, .{ .sema = sema })).scalar, float_ty, mod);
src/arch/wasm/CodeGen.zig+15-15
......@@ -1296,7 +1296,7 @@ fn genFunc(func: *CodeGen) InnerError!void {
12961296 // subtract it from the current stack pointer
12971297 try prologue.append(.{ .tag = .i32_sub, .data = .{ .tag = {} } });
12981298 // Get negative stack aligment
1299 try prologue.append(.{ .tag = .i32_const, .data = .{ .imm32 = @as(i32, @intCast(func.stack_alignment.toByteUnitsOptional().?)) * -1 } });
1299 try prologue.append(.{ .tag = .i32_const, .data = .{ .imm32 = @as(i32, @intCast(func.stack_alignment.toByteUnits().?)) * -1 } });
13001300 // Bitwise-and the value to get the new stack pointer to ensure the pointers are aligned with the abi alignment
13011301 try prologue.append(.{ .tag = .i32_and, .data = .{ .tag = {} } });
13021302 // store the current stack pointer as the bottom, which will be used to calculate all stack pointer offsets
......@@ -2107,7 +2107,7 @@ fn airRet(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
21072107 });
21082108 try func.addMemArg(Mir.Inst.Tag.fromOpcode(opcode), .{
21092109 .offset = operand.offset(),
2110 .alignment = @intCast(scalar_type.abiAlignment(mod).toByteUnitsOptional().?),
2110 .alignment = @intCast(scalar_type.abiAlignment(mod).toByteUnits().?),
21112111 });
21122112 },
21132113 else => try func.emitWValue(operand),
......@@ -2384,7 +2384,7 @@ fn store(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerE
23842384 try func.mir_extra.appendSlice(func.gpa, &[_]u32{
23852385 std.wasm.simdOpcode(.v128_store),
23862386 offset + lhs.offset(),
2387 @intCast(ty.abiAlignment(mod).toByteUnits(0)),
2387 @intCast(ty.abiAlignment(mod).toByteUnits() orelse 0),
23882388 });
23892389 return func.addInst(.{ .tag = .simd_prefix, .data = .{ .payload = extra_index } });
23902390 },
......@@ -2440,7 +2440,7 @@ fn store(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerE
24402440 Mir.Inst.Tag.fromOpcode(opcode),
24412441 .{
24422442 .offset = offset + lhs.offset(),
2443 .alignment = @intCast(ty.abiAlignment(mod).toByteUnitsOptional().?),
2443 .alignment = @intCast(ty.abiAlignment(mod).toByteUnits().?),
24442444 },
24452445 );
24462446}
......@@ -2500,7 +2500,7 @@ fn load(func: *CodeGen, operand: WValue, ty: Type, offset: u32) InnerError!WValu
25002500 try func.mir_extra.appendSlice(func.gpa, &[_]u32{
25012501 std.wasm.simdOpcode(.v128_load),
25022502 offset + operand.offset(),
2503 @intCast(ty.abiAlignment(mod).toByteUnitsOptional().?),
2503 @intCast(ty.abiAlignment(mod).toByteUnits().?),
25042504 });
25052505 try func.addInst(.{ .tag = .simd_prefix, .data = .{ .payload = extra_index } });
25062506 return WValue{ .stack = {} };
......@@ -2518,7 +2518,7 @@ fn load(func: *CodeGen, operand: WValue, ty: Type, offset: u32) InnerError!WValu
25182518 Mir.Inst.Tag.fromOpcode(opcode),
25192519 .{
25202520 .offset = offset + operand.offset(),
2521 .alignment = @intCast(ty.abiAlignment(mod).toByteUnitsOptional().?),
2521 .alignment = @intCast(ty.abiAlignment(mod).toByteUnits().?),
25222522 },
25232523 );
25242524
......@@ -3456,7 +3456,7 @@ fn intStorageAsI32(storage: InternPool.Key.Int.Storage, mod: *Module) i32 {
34563456 .i64 => |x| @as(i32, @intCast(x)),
34573457 .u64 => |x| @as(i32, @bitCast(@as(u32, @intCast(x)))),
34583458 .big_int => unreachable,
3459 .lazy_align => |ty| @as(i32, @bitCast(@as(u32, @intCast(Type.fromInterned(ty).abiAlignment(mod).toByteUnits(0))))),
3459 .lazy_align => |ty| @as(i32, @bitCast(@as(u32, @intCast(Type.fromInterned(ty).abiAlignment(mod).toByteUnits() orelse 0)))),
34603460 .lazy_size => |ty| @as(i32, @bitCast(@as(u32, @intCast(Type.fromInterned(ty).abiSize(mod))))),
34613461 };
34623462}
......@@ -4204,7 +4204,7 @@ fn airIsErr(func: *CodeGen, inst: Air.Inst.Index, opcode: wasm.Opcode) InnerErro
42044204 if (pl_ty.hasRuntimeBitsIgnoreComptime(mod)) {
42054205 try func.addMemArg(.i32_load16_u, .{
42064206 .offset = operand.offset() + @as(u32, @intCast(errUnionErrorOffset(pl_ty, mod))),
4207 .alignment = @intCast(Type.anyerror.abiAlignment(mod).toByteUnitsOptional().?),
4207 .alignment = @intCast(Type.anyerror.abiAlignment(mod).toByteUnits().?),
42084208 });
42094209 }
42104210
......@@ -5141,7 +5141,7 @@ fn airSplat(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
51415141 try func.mir_extra.appendSlice(func.gpa, &[_]u32{
51425142 opcode,
51435143 operand.offset(),
5144 @intCast(elem_ty.abiAlignment(mod).toByteUnitsOptional().?),
5144 @intCast(elem_ty.abiAlignment(mod).toByteUnits().?),
51455145 });
51465146 try func.addInst(.{ .tag = .simd_prefix, .data = .{ .payload = extra_index } });
51475147 try func.addLabel(.local_set, result.local.value);
......@@ -6552,7 +6552,7 @@ fn lowerTry(
65526552 const err_offset = @as(u32, @intCast(errUnionErrorOffset(pl_ty, mod)));
65536553 try func.addMemArg(.i32_load16_u, .{
65546554 .offset = err_union.offset() + err_offset,
6555 .alignment = @intCast(Type.anyerror.abiAlignment(mod).toByteUnitsOptional().?),
6555 .alignment = @intCast(Type.anyerror.abiAlignment(mod).toByteUnits().?),
65566556 });
65576557 }
65586558 try func.addTag(.i32_eqz);
......@@ -7499,7 +7499,7 @@ fn airCmpxchg(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
74997499 else => |size| return func.fail("TODO: implement `@cmpxchg` for types with abi size '{d}'", .{size}),
75007500 }, .{
75017501 .offset = ptr_operand.offset(),
7502 .alignment = @intCast(ty.abiAlignment(mod).toByteUnitsOptional().?),
7502 .alignment = @intCast(ty.abiAlignment(mod).toByteUnits().?),
75037503 });
75047504 try func.addLabel(.local_tee, val_local.local.value);
75057505 _ = try func.cmp(.stack, expected_val, ty, .eq);
......@@ -7561,7 +7561,7 @@ fn airAtomicLoad(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
75617561 try func.emitWValue(ptr);
75627562 try func.addAtomicMemArg(tag, .{
75637563 .offset = ptr.offset(),
7564 .alignment = @intCast(ty.abiAlignment(mod).toByteUnitsOptional().?),
7564 .alignment = @intCast(ty.abiAlignment(mod).toByteUnits().?),
75657565 });
75667566 } else {
75677567 _ = try func.load(ptr, ty, 0);
......@@ -7622,7 +7622,7 @@ fn airAtomicRmw(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
76227622 },
76237623 .{
76247624 .offset = ptr.offset(),
7625 .alignment = @intCast(ty.abiAlignment(mod).toByteUnitsOptional().?),
7625 .alignment = @intCast(ty.abiAlignment(mod).toByteUnits().?),
76267626 },
76277627 );
76287628 const select_res = try func.allocLocal(ty);
......@@ -7682,7 +7682,7 @@ fn airAtomicRmw(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
76827682 };
76837683 try func.addAtomicMemArg(tag, .{
76847684 .offset = ptr.offset(),
7685 .alignment = @intCast(ty.abiAlignment(mod).toByteUnitsOptional().?),
7685 .alignment = @intCast(ty.abiAlignment(mod).toByteUnits().?),
76867686 });
76877687 const result = try WValue.toLocal(.stack, func, ty);
76887688 return func.finishAir(inst, result, &.{ pl_op.operand, extra.operand });
......@@ -7781,7 +7781,7 @@ fn airAtomicStore(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
77817781 try func.lowerToStack(operand);
77827782 try func.addAtomicMemArg(tag, .{
77837783 .offset = ptr.offset(),
7784 .alignment = @intCast(ty.abiAlignment(mod).toByteUnitsOptional().?),
7784 .alignment = @intCast(ty.abiAlignment(mod).toByteUnits().?),
77857785 });
77867786 } else {
77877787 try func.store(ptr, operand, ty, 0);
src/arch/x86_64/CodeGen.zig+3-3
......@@ -18959,7 +18959,7 @@ fn resolveCallingConventionValues(
1895918959
1896018960 const param_size: u31 = @intCast(ty.abiSize(mod));
1896118961 const param_align: u31 =
18962 @intCast(@max(ty.abiAlignment(mod).toByteUnitsOptional().?, 8));
18962 @intCast(@max(ty.abiAlignment(mod).toByteUnits().?, 8));
1896318963 result.stack_byte_count =
1896418964 mem.alignForward(u31, result.stack_byte_count, param_align);
1896518965 arg.* = .{ .load_frame = .{
......@@ -19003,7 +19003,7 @@ fn resolveCallingConventionValues(
1900319003 continue;
1900419004 }
1900519005 const param_size: u31 = @intCast(ty.abiSize(mod));
19006 const param_align: u31 = @intCast(ty.abiAlignment(mod).toByteUnitsOptional().?);
19006 const param_align: u31 = @intCast(ty.abiAlignment(mod).toByteUnits().?);
1900719007 result.stack_byte_count =
1900819008 mem.alignForward(u31, result.stack_byte_count, param_align);
1900919009 arg.* = .{ .load_frame = .{
......@@ -19096,7 +19096,7 @@ fn splitType(self: *Self, ty: Type) ![2]Type {
1909619096 .integer => switch (part_i) {
1909719097 0 => Type.u64,
1909819098 1 => part: {
19099 const elem_size = ty.abiAlignment(mod).minStrict(.@"8").toByteUnitsOptional().?;
19099 const elem_size = ty.abiAlignment(mod).minStrict(.@"8").toByteUnits().?;
1910019100 const elem_ty = try mod.intType(.unsigned, @intCast(elem_size * 8));
1910119101 break :part switch (@divExact(ty.abiSize(mod) - 8, elem_size)) {
1910219102 1 => elem_ty,
src/codegen.zig+3-3
......@@ -548,7 +548,7 @@ pub fn generateSymbol(
548548 }
549549
550550 const size = struct_type.size(ip).*;
551 const alignment = struct_type.flagsPtr(ip).alignment.toByteUnitsOptional().?;
551 const alignment = struct_type.flagsPtr(ip).alignment.toByteUnits().?;
552552
553553 const padding = math.cast(
554554 usize,
......@@ -893,12 +893,12 @@ fn genDeclRef(
893893 // TODO this feels clunky. Perhaps we should check for it in `genTypedValue`?
894894 if (ty.castPtrToFn(zcu)) |fn_ty| {
895895 if (zcu.typeToFunc(fn_ty).?.is_generic) {
896 return GenResult.mcv(.{ .immediate = fn_ty.abiAlignment(zcu).toByteUnitsOptional().? });
896 return GenResult.mcv(.{ .immediate = fn_ty.abiAlignment(zcu).toByteUnits().? });
897897 }
898898 } else if (ty.zigTypeTag(zcu) == .Pointer) {
899899 const elem_ty = ty.elemType2(zcu);
900900 if (!elem_ty.hasRuntimeBits(zcu)) {
901 return GenResult.mcv(.{ .immediate = elem_ty.abiAlignment(zcu).toByteUnitsOptional().? });
901 return GenResult.mcv(.{ .immediate = elem_ty.abiAlignment(zcu).toByteUnits().? });
902902 }
903903 }
904904
src/codegen/c.zig+926-983
......@@ -22,7 +22,7 @@ const Alignment = InternPool.Alignment;
2222const BigIntLimb = std.math.big.Limb;
2323const BigInt = std.math.big.int;
2424
25pub const CType = @import("c/type.zig").CType;
25pub const CType = @import("c/Type.zig");
2626
2727pub const CValue = union(enum) {
2828 none: void,
......@@ -62,7 +62,7 @@ pub const LazyFnKey = union(enum) {
6262 never_inline: InternPool.DeclIndex,
6363};
6464pub const LazyFnValue = struct {
65 fn_name: []const u8,
65 fn_name: CType.String,
6666 data: Data,
6767
6868 pub const Data = union {
......@@ -74,19 +74,19 @@ pub const LazyFnValue = struct {
7474pub const LazyFnMap = std.AutoArrayHashMapUnmanaged(LazyFnKey, LazyFnValue);
7575
7676const Local = struct {
77 cty_idx: CType.Index,
77 ctype: CType,
7878 flags: packed struct(u32) {
7979 alignas: CType.AlignAs,
8080 _: u20 = undefined,
8181 },
8282
8383 pub fn getType(local: Local) LocalType {
84 return .{ .cty_idx = local.cty_idx, .alignas = local.flags.alignas };
84 return .{ .ctype = local.ctype, .alignas = local.flags.alignas };
8585 }
8686};
8787
8888const LocalIndex = u16;
89const LocalType = struct { cty_idx: CType.Index, alignas: CType.AlignAs };
89const LocalType = struct { ctype: CType, alignas: CType.AlignAs };
9090const LocalsList = std.AutoArrayHashMapUnmanaged(LocalIndex, void);
9191const LocalsMap = std.AutoArrayHashMapUnmanaged(LocalType, LocalsList);
9292
......@@ -193,6 +193,7 @@ const reserved_idents = std.ComptimeStringMap(void, .{
193193 .{ "switch", {} },
194194 .{ "thread_local", {} },
195195 .{ "typedef", {} },
196 .{ "typeof", {} },
196197 .{ "uint16_t", {} },
197198 .{ "uint32_t", {} },
198199 .{ "uint64_t", {} },
......@@ -309,12 +310,14 @@ pub const Function = struct {
309310
310311 const result: CValue = if (lowersToArray(ty, zcu)) result: {
311312 const writer = f.object.codeHeaderWriter();
312 const alignment: Alignment = .none;
313 const decl_c_value = try f.allocLocalValue(ty, alignment);
313 const decl_c_value = try f.allocLocalValue(.{
314 .ctype = try f.ctypeFromType(ty, .complete),
315 .alignas = CType.AlignAs.fromAbiAlignment(ty.abiAlignment(zcu)),
316 });
314317 const gpa = f.object.dg.gpa;
315318 try f.allocs.put(gpa, decl_c_value.new_local, false);
316319 try writer.writeAll("static ");
317 try f.object.dg.renderTypeAndName(writer, ty, decl_c_value, Const, alignment, .complete);
320 try f.object.dg.renderTypeAndName(writer, ty, decl_c_value, Const, .none, .complete);
318321 try writer.writeAll(" = ");
319322 try f.object.dg.renderValue(writer, val, .StaticInitializer);
320323 try writer.writeAll(";\n ");
......@@ -335,42 +338,39 @@ pub const Function = struct {
335338 /// Skips the reuse logic. This function should be used for any persistent allocation, i.e.
336339 /// those which go into `allocs`. This function does not add the resulting local into `allocs`;
337340 /// that responsibility lies with the caller.
338 fn allocLocalValue(f: *Function, ty: Type, alignment: Alignment) !CValue {
339 const zcu = f.object.dg.zcu;
340 const gpa = f.object.dg.gpa;
341 try f.locals.append(gpa, .{
342 .cty_idx = try f.typeToIndex(ty, .complete),
343 .flags = .{
344 .alignas = CType.AlignAs.init(alignment, ty.abiAlignment(zcu)),
345 },
341 fn allocLocalValue(f: *Function, local_type: LocalType) !CValue {
342 try f.locals.ensureUnusedCapacity(f.object.dg.gpa, 1);
343 defer f.locals.appendAssumeCapacity(.{
344 .ctype = local_type.ctype,
345 .flags = .{ .alignas = local_type.alignas },
346346 });
347 return .{ .new_local = @intCast(f.locals.items.len - 1) };
347 return .{ .new_local = @intCast(f.locals.items.len) };
348348 }
349349
350350 fn allocLocal(f: *Function, inst: ?Air.Inst.Index, ty: Type) !CValue {
351 const result = try f.allocAlignedLocal(ty, .{}, .none);
352 if (inst) |i| {
353 log.debug("%{d}: allocating t{d}", .{ i, result.new_local });
354 } else {
355 log.debug("allocating t{d}", .{result.new_local});
356 }
357 return result;
351 return f.allocAlignedLocal(inst, .{
352 .ctype = try f.ctypeFromType(ty, .complete),
353 .alignas = CType.AlignAs.fromAbiAlignment(ty.abiAlignment(f.object.dg.zcu)),
354 });
358355 }
359356
360357 /// Only allocates the local; does not print anything. Will attempt to re-use locals, so should
361358 /// not be used for persistent locals (i.e. those in `allocs`).
362 fn allocAlignedLocal(f: *Function, ty: Type, _: CQualifiers, alignment: Alignment) !CValue {
363 const zcu = f.object.dg.zcu;
364 if (f.free_locals_map.getPtr(.{
365 .cty_idx = try f.typeToIndex(ty, .complete),
366 .alignas = CType.AlignAs.init(alignment, ty.abiAlignment(zcu)),
367 })) |locals_list| {
368 if (locals_list.popOrNull()) |local_entry| {
369 return .{ .new_local = local_entry.key };
359 fn allocAlignedLocal(f: *Function, inst: ?Air.Inst.Index, local_type: LocalType) !CValue {
360 const result: CValue = result: {
361 if (f.free_locals_map.getPtr(local_type)) |locals_list| {
362 if (locals_list.popOrNull()) |local_entry| {
363 break :result .{ .new_local = local_entry.key };
364 }
370365 }
366 break :result try f.allocLocalValue(local_type);
367 };
368 if (inst) |i| {
369 log.debug("%{d}: allocating t{d}", .{ i, result.new_local });
370 } else {
371 log.debug("allocating t{d}", .{result.new_local});
371372 }
372
373 return f.allocLocalValue(ty, alignment);
373 return result;
374374 }
375375
376376 fn writeCValue(f: *Function, w: anytype, c_value: CValue, location: ValueRenderLocation) !void {
......@@ -380,15 +380,20 @@ pub const Function = struct {
380380 .local_ref => |i| {
381381 const local = &f.locals.items[i];
382382 if (local.flags.alignas.abiOrder().compare(.lt)) {
383 const zcu = f.object.dg.zcu;
384 const pointee_ty = try zcu.intType(.unsigned, @min(
385 local.flags.alignas.@"align".toByteUnitsOptional().?,
386 f.object.dg.mod.resolved_target.result.maxIntAlignment(),
387 ) * 8);
388 const ptr_ty = try zcu.singleMutPtrType(pointee_ty);
383 const gpa = f.object.dg.gpa;
384 const mod = f.object.dg.mod;
385 const ctype_pool = &f.object.dg.ctype_pool;
389386
390387 try w.writeByte('(');
391 try f.renderType(w, ptr_ty);
388 try f.renderCType(w, try ctype_pool.getPointer(gpa, .{
389 .elem_ctype = try ctype_pool.fromIntInfo(gpa, .{
390 .signedness = .unsigned,
391 .bits = @min(
392 local.flags.alignas.toByteUnits(),
393 mod.resolved_target.result.maxIntAlignment(),
394 ) * 8,
395 }, mod, .forward),
396 }));
392397 try w.writeByte(')');
393398 }
394399 try w.print("&t{d}", .{i});
......@@ -460,28 +465,20 @@ pub const Function = struct {
460465 return f.object.dg.fail(format, args);
461466 }
462467
463 fn indexToCType(f: *Function, idx: CType.Index) CType {
464 return f.object.dg.indexToCType(idx);
465 }
466
467 fn typeToIndex(f: *Function, ty: Type, kind: CType.Kind) !CType.Index {
468 return f.object.dg.typeToIndex(ty, kind);
468 fn ctypeFromType(f: *Function, ty: Type, kind: CType.Kind) !CType {
469 return f.object.dg.ctypeFromType(ty, kind);
469470 }
470471
471 fn typeToCType(f: *Function, ty: Type, kind: CType.Kind) !CType {
472 return f.object.dg.typeToCType(ty, kind);
472 fn byteSize(f: *Function, ctype: CType) u64 {
473 return f.object.dg.byteSize(ctype);
473474 }
474475
475 fn byteSize(f: *Function, cty: CType) u64 {
476 return f.object.dg.byteSize(cty);
476 fn renderType(f: *Function, w: anytype, ctype: Type) !void {
477 return f.object.dg.renderType(w, ctype);
477478 }
478479
479 fn renderType(f: *Function, w: anytype, t: Type) !void {
480 return f.object.dg.renderType(w, t);
481 }
482
483 fn renderCType(f: *Function, w: anytype, t: CType.Index) !void {
484 return f.object.dg.renderCType(w, t);
480 fn renderCType(f: *Function, w: anytype, ctype: CType) !void {
481 return f.object.dg.renderCType(w, ctype);
485482 }
486483
487484 fn renderIntCast(f: *Function, w: anytype, dest_ty: Type, src: CValue, v: Vectorize, src_ty: Type, location: ValueRenderLocation) !void {
......@@ -494,21 +491,19 @@ pub const Function = struct {
494491
495492 fn getLazyFnName(f: *Function, key: LazyFnKey, data: LazyFnValue.Data) ![]const u8 {
496493 const gpa = f.object.dg.gpa;
494 const zcu = f.object.dg.zcu;
495 const ctype_pool = &f.object.dg.ctype_pool;
496
497497 const gop = try f.lazy_fns.getOrPut(gpa, key);
498498 if (!gop.found_existing) {
499499 errdefer _ = f.lazy_fns.pop();
500500
501 var promoted = f.object.dg.ctypes.promote(gpa);
502 defer f.object.dg.ctypes.demote(promoted);
503 const arena = promoted.arena.allocator();
504 const zcu = f.object.dg.zcu;
505
506501 gop.value_ptr.* = .{
507502 .fn_name = switch (key) {
508503 .tag_name,
509504 .never_tail,
510505 .never_inline,
511 => |owner_decl| try std.fmt.allocPrint(arena, "zig_{s}_{}__{d}", .{
506 => |owner_decl| try ctype_pool.fmt(gpa, "zig_{s}_{}__{d}", .{
512507 @tagName(key),
513508 fmtIdent(zcu.intern_pool.stringToSlice(zcu.declPtr(owner_decl).name)),
514509 @intFromEnum(owner_decl),
......@@ -521,7 +516,7 @@ pub const Function = struct {
521516 },
522517 };
523518 }
524 return gop.value_ptr.fn_name;
519 return gop.value_ptr.fn_name.slice(ctype_pool);
525520 }
526521
527522 pub fn deinit(f: *Function) void {
......@@ -532,7 +527,6 @@ pub const Function = struct {
532527 f.blocks.deinit(gpa);
533528 f.value_map.deinit();
534529 f.lazy_fns.deinit(gpa);
535 f.object.dg.ctypes.deinit(gpa);
536530 }
537531
538532 fn typeOf(f: *Function, inst: Air.Inst.Ref) Type {
......@@ -575,7 +569,8 @@ pub const DeclGen = struct {
575569 /// This is a borrowed reference from `link.C`.
576570 fwd_decl: std.ArrayList(u8),
577571 error_msg: ?*Zcu.ErrorMsg,
578 ctypes: CType.Store,
572 ctype_pool: CType.Pool,
573 scratch: std.ArrayListUnmanaged(u32),
579574 /// Keeps track of anonymous decls that need to be rendered before this
580575 /// (named) Decl in the output C code.
581576 anon_decl_deps: std.AutoArrayHashMapUnmanaged(InternPool.Index, C.DeclBlock),
......@@ -610,6 +605,7 @@ pub const DeclGen = struct {
610605 ) error{ OutOfMemory, AnalysisFail }!void {
611606 const zcu = dg.zcu;
612607 const ip = &zcu.intern_pool;
608 const ctype_pool = &dg.ctype_pool;
613609 const decl_val = Value.fromInterned(anon_decl.val);
614610 const decl_ty = decl_val.typeOf(zcu);
615611
......@@ -631,10 +627,10 @@ pub const DeclGen = struct {
631627 // them). The analysis until now should ensure that the C function
632628 // pointers are compatible. If they are not, then there is a bug
633629 // somewhere and we should let the C compiler tell us about it.
634 const child_cty = (try dg.typeToCType(ptr_ty, .complete)).cast(CType.Payload.Child).?.data;
635 const decl_cty = try dg.typeToIndex(decl_ty, .complete);
636 const need_cast = child_cty != decl_cty and
637 (dg.indexToCType(child_cty).tag() != .function or dg.indexToCType(decl_cty).tag() != .function);
630 const elem_ctype = (try dg.ctypeFromType(ptr_ty, .complete)).info(ctype_pool).pointer.elem_ctype;
631 const decl_ctype = try dg.ctypeFromType(decl_ty, .complete);
632 const need_cast = !elem_ctype.eql(decl_ctype) and
633 (elem_ctype.info(ctype_pool) != .function or decl_ctype.info(ctype_pool) != .function);
638634 if (need_cast) {
639635 try writer.writeAll("((");
640636 try dg.renderType(writer, ptr_ty);
......@@ -655,7 +651,7 @@ pub const DeclGen = struct {
655651 const explicit_alignment = ptr_type.flags.alignment;
656652 if (explicit_alignment != .none) {
657653 const abi_alignment = Type.fromInterned(ptr_type.child).abiAlignment(zcu);
658 if (explicit_alignment.compareStrict(.gt, abi_alignment)) {
654 if (explicit_alignment.order(abi_alignment).compare(.gt)) {
659655 const aligned_gop = try dg.aligned_anon_decls.getOrPut(dg.gpa, anon_decl.val);
660656 aligned_gop.value_ptr.* = if (aligned_gop.found_existing)
661657 aligned_gop.value_ptr.maxStrict(explicit_alignment)
......@@ -673,6 +669,7 @@ pub const DeclGen = struct {
673669 location: ValueRenderLocation,
674670 ) error{ OutOfMemory, AnalysisFail }!void {
675671 const zcu = dg.zcu;
672 const ctype_pool = &dg.ctype_pool;
676673 const decl = zcu.declPtr(decl_index);
677674 assert(decl.has_tv);
678675
......@@ -695,10 +692,10 @@ pub const DeclGen = struct {
695692 // them). The analysis until now should ensure that the C function
696693 // pointers are compatible. If they are not, then there is a bug
697694 // somewhere and we should let the C compiler tell us about it.
698 const child_cty = (try dg.typeToCType(ty, .complete)).cast(CType.Payload.Child).?.data;
699 const decl_cty = try dg.typeToIndex(decl_ty, .complete);
700 const need_cast = child_cty != decl_cty and
701 (dg.indexToCType(child_cty).tag() != .function or dg.indexToCType(decl_cty).tag() != .function);
695 const elem_ctype = (try dg.ctypeFromType(ty, .complete)).info(ctype_pool).pointer.elem_ctype;
696 const decl_ctype = try dg.ctypeFromType(decl_ty, .complete);
697 const need_cast = !elem_ctype.eql(decl_ctype) and
698 (elem_ctype.info(ctype_pool) != .function or decl_ctype.info(ctype_pool) != .function);
702699 if (need_cast) {
703700 try writer.writeAll("((");
704701 try dg.renderType(writer, ty);
......@@ -720,31 +717,31 @@ pub const DeclGen = struct {
720717 const zcu = dg.zcu;
721718 const ip = &zcu.intern_pool;
722719 const ptr_ty = Type.fromInterned(ip.typeOf(ptr_val));
723 const ptr_cty = try dg.typeToIndex(ptr_ty, .complete);
724 const ptr_child_cty = dg.indexToCType(ptr_cty).cast(CType.Payload.Child).?.data;
720 const ptr_ctype = try dg.ctypeFromType(ptr_ty, .complete);
721 const ptr_child_ctype = ptr_ctype.info(&dg.ctype_pool).pointer.elem_ctype;
725722 const ptr = ip.indexToKey(ptr_val).ptr;
726723 switch (ptr.addr) {
727724 .decl => |d| try dg.renderDeclValue(writer, Value.fromInterned(ptr_val), d, location),
728725 .anon_decl => |anon_decl| try dg.renderAnonDeclValue(writer, Value.fromInterned(ptr_val), anon_decl, location),
729726 .int => |int| {
730727 try writer.writeByte('(');
731 try dg.renderCType(writer, ptr_cty);
728 try dg.renderCType(writer, ptr_ctype);
732729 try writer.print("){x}", .{try dg.fmtIntLiteral(Value.fromInterned(int), .Other)});
733730 },
734731 .eu_payload, .opt_payload => |base| {
735732 const ptr_base_ty = Type.fromInterned(ip.typeOf(base));
736733 const base_ty = ptr_base_ty.childType(zcu);
737734 // Ensure complete type definition is visible before accessing fields.
738 _ = try dg.typeToIndex(base_ty, .complete);
735 _ = try dg.ctypeFromType(base_ty, .complete);
739736 const payload_ty = switch (ptr.addr) {
740737 .eu_payload => base_ty.errorUnionPayload(zcu),
741738 .opt_payload => base_ty.optionalChild(zcu),
742739 else => unreachable,
743740 };
744 const payload_cty = try dg.typeToIndex(payload_ty, .forward);
745 if (ptr_child_cty != payload_cty) {
741 const payload_ctype = try dg.ctypeFromType(payload_ty, .forward);
742 if (!ptr_child_ctype.eql(payload_ctype)) {
746743 try writer.writeByte('(');
747 try dg.renderCType(writer, ptr_cty);
744 try dg.renderCType(writer, ptr_ctype);
748745 try writer.writeByte(')');
749746 }
750747 try writer.writeAll("&(");
......@@ -754,10 +751,10 @@ pub const DeclGen = struct {
754751 .elem => |elem| {
755752 const ptr_base_ty = Type.fromInterned(ip.typeOf(elem.base));
756753 const elem_ty = ptr_base_ty.elemType2(zcu);
757 const elem_cty = try dg.typeToIndex(elem_ty, .forward);
758 if (ptr_child_cty != elem_cty) {
754 const elem_ctype = try dg.ctypeFromType(elem_ty, .forward);
755 if (!ptr_child_ctype.eql(elem_ctype)) {
759756 try writer.writeByte('(');
760 try dg.renderCType(writer, ptr_cty);
757 try dg.renderCType(writer, ptr_ctype);
761758 try writer.writeByte(')');
762759 }
763760 try writer.writeAll("&(");
......@@ -769,14 +766,14 @@ pub const DeclGen = struct {
769766 .field => |field| {
770767 const ptr_base_ty = Type.fromInterned(ip.typeOf(field.base));
771768 const base_ty = ptr_base_ty.childType(zcu);
772 // Ensure complete type definition is visible before accessing fields.
773 _ = try dg.typeToIndex(base_ty, .complete);
769 // Ensure complete type definition is available before accessing fields.
770 _ = try dg.ctypeFromType(base_ty, .complete);
774771 switch (fieldLocation(ptr_base_ty, ptr_ty, @as(u32, @intCast(field.index)), zcu)) {
775772 .begin => {
776 const ptr_base_cty = try dg.typeToIndex(ptr_base_ty, .complete);
777 if (ptr_cty != ptr_base_cty) {
773 const ptr_base_ctype = try dg.ctypeFromType(ptr_base_ty, .complete);
774 if (!ptr_ctype.eql(ptr_base_ctype)) {
778775 try writer.writeByte('(');
779 try dg.renderCType(writer, ptr_cty);
776 try dg.renderCType(writer, ptr_ctype);
780777 try writer.writeByte(')');
781778 }
782779 try dg.renderParentPtr(writer, field.base, location);
......@@ -797,10 +794,10 @@ pub const DeclGen = struct {
797794 },
798795 else => unreachable,
799796 };
800 const field_cty = try dg.typeToIndex(field_ty, .forward);
801 if (ptr_child_cty != field_cty) {
797 const field_ctype = try dg.ctypeFromType(field_ty, .forward);
798 if (!ptr_child_ctype.eql(field_ctype)) {
802799 try writer.writeByte('(');
803 try dg.renderCType(writer, ptr_cty);
800 try dg.renderCType(writer, ptr_ctype);
804801 try writer.writeByte(')');
805802 }
806803 try writer.writeAll("&(");
......@@ -810,15 +807,15 @@ pub const DeclGen = struct {
810807 },
811808 .byte_offset => |byte_offset| {
812809 const u8_ptr_ty = try zcu.adjustPtrTypeChild(ptr_ty, Type.u8);
813 const u8_ptr_cty = try dg.typeToIndex(u8_ptr_ty, .complete);
810 const u8_ptr_ctype = try dg.ctypeFromType(u8_ptr_ty, .complete);
814811
815 if (ptr_cty != u8_ptr_cty) {
812 if (!ptr_ctype.eql(u8_ptr_ctype)) {
816813 try writer.writeByte('(');
817 try dg.renderCType(writer, ptr_cty);
814 try dg.renderCType(writer, ptr_ctype);
818815 try writer.writeByte(')');
819816 }
820817 try writer.writeAll("((");
821 try dg.renderCType(writer, u8_ptr_cty);
818 try dg.renderCType(writer, u8_ptr_ctype);
822819 try writer.writeByte(')');
823820 try dg.renderParentPtr(writer, field.base, location);
824821 try writer.print(" + {})", .{
......@@ -826,10 +823,10 @@ pub const DeclGen = struct {
826823 });
827824 },
828825 .end => {
829 const ptr_base_cty = try dg.typeToIndex(ptr_base_ty, .complete);
830 if (ptr_cty != ptr_base_cty) {
826 const ptr_base_ctype = try dg.ctypeFromType(ptr_base_ty, .complete);
827 if (!ptr_ctype.eql(ptr_base_ctype)) {
831828 try writer.writeByte('(');
832 try dg.renderCType(writer, ptr_cty);
829 try dg.renderCType(writer, ptr_ctype);
833830 try writer.writeByte(')');
834831 }
835832 try writer.writeAll("((");
......@@ -1207,8 +1204,8 @@ pub const DeclGen = struct {
12071204 try writer.writeByte('}');
12081205 },
12091206 .struct_type => {
1210 const struct_type = ip.loadStructType(ty.toIntern());
1211 switch (struct_type.layout) {
1207 const loaded_struct = ip.loadStructType(ty.toIntern());
1208 switch (loaded_struct.layout) {
12121209 .auto, .@"extern" => {
12131210 if (!location.isInitializer()) {
12141211 try writer.writeByte('(');
......@@ -1217,13 +1214,14 @@ pub const DeclGen = struct {
12171214 }
12181215
12191216 try writer.writeByte('{');
1220 var empty = true;
1221 for (0..struct_type.field_types.len) |field_index| {
1222 const field_ty = Type.fromInterned(struct_type.field_types.get(ip)[field_index]);
1223 if (struct_type.fieldIsComptime(ip, field_index)) continue;
1217 var field_it = loaded_struct.iterateRuntimeOrder(ip);
1218 var need_comma = false;
1219 while (field_it.next()) |field_index| {
1220 const field_ty = Type.fromInterned(loaded_struct.field_types.get(ip)[field_index]);
12241221 if (!field_ty.hasRuntimeBitsIgnoreComptime(zcu)) continue;
12251222
1226 if (!empty) try writer.writeByte(',');
1223 if (need_comma) try writer.writeByte(',');
1224 need_comma = true;
12271225 const field_val = switch (ip.indexToKey(val.toIntern()).aggregate.storage) {
12281226 .bytes => |bytes| try ip.get(zcu.gpa, .{ .int = .{
12291227 .ty = field_ty.toIntern(),
......@@ -1233,8 +1231,6 @@ pub const DeclGen = struct {
12331231 .repeated_elem => |elem| elem,
12341232 };
12351233 try dg.renderValue(writer, Value.fromInterned(field_val), initializer_type);
1236
1237 empty = false;
12381234 }
12391235 try writer.writeByte('}');
12401236 },
......@@ -1247,8 +1243,8 @@ pub const DeclGen = struct {
12471243 var bit_offset: u64 = 0;
12481244 var eff_num_fields: usize = 0;
12491245
1250 for (0..struct_type.field_types.len) |field_index| {
1251 const field_ty = Type.fromInterned(struct_type.field_types.get(ip)[field_index]);
1246 for (0..loaded_struct.field_types.len) |field_index| {
1247 const field_ty = Type.fromInterned(loaded_struct.field_types.get(ip)[field_index]);
12521248 if (!field_ty.hasRuntimeBitsIgnoreComptime(zcu)) continue;
12531249 eff_num_fields += 1;
12541250 }
......@@ -1268,8 +1264,8 @@ pub const DeclGen = struct {
12681264
12691265 var eff_index: usize = 0;
12701266 var needs_closing_paren = false;
1271 for (0..struct_type.field_types.len) |field_index| {
1272 const field_ty = Type.fromInterned(struct_type.field_types.get(ip)[field_index]);
1267 for (0..loaded_struct.field_types.len) |field_index| {
1268 const field_ty = Type.fromInterned(loaded_struct.field_types.get(ip)[field_index]);
12731269 if (!field_ty.hasRuntimeBitsIgnoreComptime(zcu)) continue;
12741270
12751271 const field_val = switch (ip.indexToKey(val.toIntern()).aggregate.storage) {
......@@ -1304,8 +1300,8 @@ pub const DeclGen = struct {
13041300 try writer.writeByte('(');
13051301 // a << a_off | b << b_off | c << c_off
13061302 var empty = true;
1307 for (0..struct_type.field_types.len) |field_index| {
1308 const field_ty = Type.fromInterned(struct_type.field_types.get(ip)[field_index]);
1303 for (0..loaded_struct.field_types.len) |field_index| {
1304 const field_ty = Type.fromInterned(loaded_struct.field_types.get(ip)[field_index]);
13091305 if (!field_ty.hasRuntimeBitsIgnoreComptime(zcu)) continue;
13101306
13111307 if (!empty) try writer.writeAll(" | ");
......@@ -1341,10 +1337,10 @@ pub const DeclGen = struct {
13411337 else => unreachable,
13421338 },
13431339 .un => |un| {
1344 const union_obj = zcu.typeToUnion(ty).?;
1340 const loaded_union = ip.loadUnionType(ty.toIntern());
13451341 if (un.tag == .none) {
13461342 const backing_ty = try ty.unionBackingType(zcu);
1347 switch (union_obj.getLayout(ip)) {
1343 switch (loaded_union.getLayout(ip)) {
13481344 .@"packed" => {
13491345 if (!location.isInitializer()) {
13501346 try writer.writeByte('(');
......@@ -1376,10 +1372,10 @@ pub const DeclGen = struct {
13761372 try writer.writeByte(')');
13771373 }
13781374
1379 const field_index = zcu.unionTagFieldIndex(union_obj, Value.fromInterned(un.tag)).?;
1380 const field_ty = Type.fromInterned(union_obj.field_types.get(ip)[field_index]);
1381 const field_name = union_obj.loadTagType(ip).names.get(ip)[field_index];
1382 if (union_obj.getLayout(ip) == .@"packed") {
1375 const field_index = zcu.unionTagFieldIndex(loaded_union, Value.fromInterned(un.tag)).?;
1376 const field_ty = Type.fromInterned(loaded_union.field_types.get(ip)[field_index]);
1377 const field_name = loaded_union.loadTagType(ip).names.get(ip)[field_index];
1378 if (loaded_union.getLayout(ip) == .@"packed") {
13831379 if (field_ty.hasRuntimeBits(zcu)) {
13841380 if (field_ty.isPtrAtRuntime(zcu)) {
13851381 try writer.writeByte('(');
......@@ -1399,7 +1395,7 @@ pub const DeclGen = struct {
13991395
14001396 try writer.writeByte('{');
14011397 if (ty.unionTagTypeSafety(zcu)) |_| {
1402 const layout = zcu.getUnionLayout(union_obj);
1398 const layout = zcu.getUnionLayout(loaded_union);
14031399 if (layout.tag_size != 0) {
14041400 try writer.writeAll(" .tag = ");
14051401 try dg.renderValue(writer, Value.fromInterned(un.tag), initializer_type);
......@@ -1412,8 +1408,8 @@ pub const DeclGen = struct {
14121408 try writer.print(" .{ } = ", .{fmtIdent(ip.stringToSlice(field_name))});
14131409 try dg.renderValue(writer, Value.fromInterned(un.val), initializer_type);
14141410 try writer.writeByte(' ');
1415 } else for (0..union_obj.field_types.len) |this_field_index| {
1416 const this_field_ty = Type.fromInterned(union_obj.field_types.get(ip)[this_field_index]);
1411 } else for (0..loaded_union.field_types.len) |this_field_index| {
1412 const this_field_ty = Type.fromInterned(loaded_union.field_types.get(ip)[this_field_index]);
14171413 if (!this_field_ty.hasRuntimeBits(zcu)) continue;
14181414 try dg.renderUndefValue(writer, this_field_ty, initializer_type);
14191415 break;
......@@ -1445,12 +1441,14 @@ pub const DeclGen = struct {
14451441 .ReleaseFast, .ReleaseSmall => false,
14461442 };
14471443
1448 switch (ty.zigTypeTag(zcu)) {
1449 .Bool => try writer.writeAll(if (safety_on) "0xaa" else "false"),
1450 .Int, .Enum, .ErrorSet => try writer.print("{x}", .{
1451 try dg.fmtIntLiteral(try zcu.undefValue(ty), location),
1452 }),
1453 .Float => {
1444 switch (ty.toIntern()) {
1445 .c_longdouble_type,
1446 .f16_type,
1447 .f32_type,
1448 .f64_type,
1449 .f80_type,
1450 .f128_type,
1451 => {
14541452 const bits = ty.floatBits(target.*);
14551453 // All unsigned ints matching float types are pre-allocated.
14561454 const repr_ty = zcu.intType(.unsigned, bits) catch unreachable;
......@@ -1468,49 +1466,90 @@ pub const DeclGen = struct {
14681466 }
14691467 try writer.writeAll(", ");
14701468 try dg.renderUndefValue(writer, repr_ty, .FunctionArgument);
1471 try writer.writeByte(')');
1469 return writer.writeByte(')');
14721470 },
1473 .Pointer => if (ty.isSlice(zcu)) {
1474 if (!location.isInitializer()) {
1475 try writer.writeByte('(');
1471 .bool_type => try writer.writeAll(if (safety_on) "0xaa" else "false"),
1472 else => switch (ip.indexToKey(ty.toIntern())) {
1473 .simple_type,
1474 .int_type,
1475 .enum_type,
1476 .error_set_type,
1477 .inferred_error_set_type,
1478 => return writer.print("{x}", .{
1479 try dg.fmtIntLiteral(try zcu.undefValue(ty), location),
1480 }),
1481 .ptr_type => if (ty.isSlice(zcu)) {
1482 if (!location.isInitializer()) {
1483 try writer.writeByte('(');
1484 try dg.renderType(writer, ty);
1485 try writer.writeByte(')');
1486 }
1487
1488 try writer.writeAll("{(");
1489 const ptr_ty = ty.slicePtrFieldType(zcu);
1490 try dg.renderType(writer, ptr_ty);
1491 return writer.print("){x}, {0x}}}", .{
1492 try dg.fmtIntLiteral(try zcu.undefValue(Type.usize), .Other),
1493 });
1494 } else {
1495 try writer.writeAll("((");
14761496 try dg.renderType(writer, ty);
1477 try writer.writeByte(')');
1478 }
1497 return writer.print("){x})", .{
1498 try dg.fmtIntLiteral(try zcu.undefValue(Type.usize), .Other),
1499 });
1500 },
1501 .opt_type => {
1502 const payload_ty = ty.optionalChild(zcu);
14791503
1480 try writer.writeAll("{(");
1481 const ptr_ty = ty.slicePtrFieldType(zcu);
1482 try dg.renderType(writer, ptr_ty);
1483 try writer.print("){x}, {0x}}}", .{try dg.fmtIntLiteral(try zcu.undefValue(Type.usize), .Other)});
1484 } else {
1485 try writer.writeAll("((");
1486 try dg.renderType(writer, ty);
1487 try writer.print("){x})", .{try dg.fmtIntLiteral(try zcu.undefValue(Type.usize), .Other)});
1488 },
1489 .Optional => {
1490 const payload_ty = ty.optionalChild(zcu);
1504 if (!payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
1505 return dg.renderUndefValue(writer, Type.bool, location);
1506 }
14911507
1492 if (!payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
1493 return dg.renderUndefValue(writer, Type.bool, location);
1494 }
1508 if (ty.optionalReprIsPayload(zcu)) {
1509 return dg.renderUndefValue(writer, payload_ty, location);
1510 }
14951511
1496 if (ty.optionalReprIsPayload(zcu)) {
1497 return dg.renderUndefValue(writer, payload_ty, location);
1498 }
1512 if (!location.isInitializer()) {
1513 try writer.writeByte('(');
1514 try dg.renderType(writer, ty);
1515 try writer.writeByte(')');
1516 }
14991517
1500 if (!location.isInitializer()) {
1501 try writer.writeByte('(');
1502 try dg.renderType(writer, ty);
1503 try writer.writeByte(')');
1504 }
1518 try writer.writeAll("{ .payload = ");
1519 try dg.renderUndefValue(writer, payload_ty, initializer_type);
1520 try writer.writeAll(", .is_null = ");
1521 try dg.renderUndefValue(writer, Type.bool, initializer_type);
1522 return writer.writeAll(" }");
1523 },
1524 .struct_type => {
1525 const loaded_struct = ip.loadStructType(ty.toIntern());
1526 switch (loaded_struct.layout) {
1527 .auto, .@"extern" => {
1528 if (!location.isInitializer()) {
1529 try writer.writeByte('(');
1530 try dg.renderType(writer, ty);
1531 try writer.writeByte(')');
1532 }
15051533
1506 try writer.writeAll("{ .payload = ");
1507 try dg.renderUndefValue(writer, payload_ty, initializer_type);
1508 try writer.writeAll(", .is_null = ");
1509 try dg.renderUndefValue(writer, Type.bool, initializer_type);
1510 try writer.writeAll(" }");
1511 },
1512 .Struct => switch (ty.containerLayout(zcu)) {
1513 .auto, .@"extern" => {
1534 try writer.writeByte('{');
1535 var field_it = loaded_struct.iterateRuntimeOrder(ip);
1536 var need_comma = false;
1537 while (field_it.next()) |field_index| {
1538 const field_ty = Type.fromInterned(loaded_struct.field_types.get(ip)[field_index]);
1539 if (!field_ty.hasRuntimeBitsIgnoreComptime(zcu)) continue;
1540
1541 if (need_comma) try writer.writeByte(',');
1542 need_comma = true;
1543 try dg.renderUndefValue(writer, field_ty, initializer_type);
1544 }
1545 return writer.writeByte('}');
1546 },
1547 .@"packed" => return writer.print("{x}", .{
1548 try dg.fmtIntLiteral(try zcu.undefValue(ty), .Other),
1549 }),
1550 }
1551 },
1552 .anon_struct_type => |anon_struct_info| {
15141553 if (!location.isInitializer()) {
15151554 try writer.writeByte('(');
15161555 try dg.renderType(writer, ty);
......@@ -1518,116 +1557,125 @@ pub const DeclGen = struct {
15181557 }
15191558
15201559 try writer.writeByte('{');
1521 var empty = true;
1522 for (0..ty.structFieldCount(zcu)) |field_index| {
1523 if (ty.structFieldIsComptime(field_index, zcu)) continue;
1524 const field_ty = ty.structFieldType(field_index, zcu);
1525 if (!field_ty.hasRuntimeBits(zcu)) continue;
1560 var need_comma = false;
1561 for (0..anon_struct_info.types.len) |field_index| {
1562 if (anon_struct_info.values.get(ip)[field_index] != .none) continue;
1563 const field_ty = Type.fromInterned(anon_struct_info.types.get(ip)[field_index]);
1564 if (!field_ty.hasRuntimeBitsIgnoreComptime(zcu)) continue;
15261565
1527 if (!empty) try writer.writeByte(',');
1566 if (need_comma) try writer.writeByte(',');
1567 need_comma = true;
15281568 try dg.renderUndefValue(writer, field_ty, initializer_type);
1529
1530 empty = false;
15311569 }
1532
1533 try writer.writeByte('}');
1570 return writer.writeByte('}');
15341571 },
1535 .@"packed" => try writer.print("{x}", .{
1536 try dg.fmtIntLiteral(try zcu.undefValue(ty), .Other),
1537 }),
1538 },
1539 .Union => {
1540 if (!location.isInitializer()) {
1541 try writer.writeByte('(');
1542 try dg.renderType(writer, ty);
1543 try writer.writeByte(')');
1544 }
1572 .union_type => {
1573 const loaded_union = ip.loadUnionType(ty.toIntern());
1574 switch (loaded_union.getLayout(ip)) {
1575 .auto, .@"extern" => {
1576 if (!location.isInitializer()) {
1577 try writer.writeByte('(');
1578 try dg.renderType(writer, ty);
1579 try writer.writeByte(')');
1580 }
15451581
1546 try writer.writeByte('{');
1547 if (ty.unionTagTypeSafety(zcu)) |tag_ty| {
1548 const layout = ty.unionGetLayout(zcu);
1549 if (layout.tag_size != 0) {
1550 try writer.writeAll(" .tag = ");
1551 try dg.renderUndefValue(writer, tag_ty, initializer_type);
1582 try writer.writeByte('{');
1583 if (ty.unionTagTypeSafety(zcu)) |tag_ty| {
1584 const layout = ty.unionGetLayout(zcu);
1585 if (layout.tag_size != 0) {
1586 try writer.writeAll(" .tag = ");
1587 try dg.renderUndefValue(writer, tag_ty, initializer_type);
1588 }
1589 if (ty.unionHasAllZeroBitFieldTypes(zcu)) return try writer.writeByte('}');
1590 if (layout.tag_size != 0) try writer.writeByte(',');
1591 try writer.writeAll(" .payload = {");
1592 }
1593 for (0..loaded_union.field_types.len) |field_index| {
1594 const field_ty = Type.fromInterned(loaded_union.field_types.get(ip)[field_index]);
1595 if (!field_ty.hasRuntimeBits(zcu)) continue;
1596 try dg.renderUndefValue(writer, field_ty, initializer_type);
1597 break;
1598 }
1599 if (ty.unionTagTypeSafety(zcu)) |_| try writer.writeByte('}');
1600 return writer.writeByte('}');
1601 },
1602 .@"packed" => return writer.print("{x}", .{
1603 try dg.fmtIntLiteral(try zcu.undefValue(ty), .Other),
1604 }),
15521605 }
1553 if (ty.unionHasAllZeroBitFieldTypes(zcu)) return try writer.writeByte('}');
1554 if (layout.tag_size != 0) try writer.writeByte(',');
1555 try writer.writeAll(" .payload = {");
1556 }
1557 const union_obj = zcu.typeToUnion(ty).?;
1558 for (0..union_obj.field_types.len) |field_index| {
1559 const field_ty = Type.fromInterned(union_obj.field_types.get(ip)[field_index]);
1560 if (!field_ty.hasRuntimeBits(zcu)) continue;
1561 try dg.renderUndefValue(writer, field_ty, initializer_type);
1562 break;
1563 }
1564 if (ty.unionTagTypeSafety(zcu)) |_| try writer.writeByte('}');
1565 try writer.writeByte('}');
1566 },
1567 .ErrorUnion => {
1568 const payload_ty = ty.errorUnionPayload(zcu);
1569 const error_ty = ty.errorUnionSet(zcu);
1570
1571 if (!payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
1572 return dg.renderUndefValue(writer, error_ty, location);
1573 }
1606 },
1607 .error_union_type => {
1608 const payload_ty = ty.errorUnionPayload(zcu);
1609 const error_ty = ty.errorUnionSet(zcu);
15741610
1575 if (!location.isInitializer()) {
1576 try writer.writeByte('(');
1577 try dg.renderType(writer, ty);
1578 try writer.writeByte(')');
1579 }
1611 if (!payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
1612 return dg.renderUndefValue(writer, error_ty, location);
1613 }
15801614
1581 try writer.writeAll("{ .payload = ");
1582 try dg.renderUndefValue(writer, payload_ty, initializer_type);
1583 try writer.writeAll(", .error = ");
1584 try dg.renderUndefValue(writer, error_ty, initializer_type);
1585 try writer.writeAll(" }");
1586 },
1587 .Array, .Vector => {
1588 const ai = ty.arrayInfo(zcu);
1589 if (ai.elem_type.eql(Type.u8, zcu)) {
1590 const c_len = ty.arrayLenIncludingSentinel(zcu);
1591 var literal = stringLiteral(writer, c_len);
1592 try literal.start();
1593 var index: u64 = 0;
1594 while (index < c_len) : (index += 1)
1595 try literal.writeChar(0xaa);
1596 try literal.end();
1597 } else {
15981615 if (!location.isInitializer()) {
15991616 try writer.writeByte('(');
16001617 try dg.renderType(writer, ty);
16011618 try writer.writeByte(')');
16021619 }
16031620
1604 try writer.writeByte('{');
1605 const c_len = ty.arrayLenIncludingSentinel(zcu);
1606 var index: u64 = 0;
1607 while (index < c_len) : (index += 1) {
1608 if (index > 0) try writer.writeAll(", ");
1609 try dg.renderUndefValue(writer, ty.childType(zcu), initializer_type);
1621 try writer.writeAll("{ .payload = ");
1622 try dg.renderUndefValue(writer, payload_ty, initializer_type);
1623 try writer.writeAll(", .error = ");
1624 try dg.renderUndefValue(writer, error_ty, initializer_type);
1625 return writer.writeAll(" }");
1626 },
1627 .array_type, .vector_type => {
1628 const ai = ty.arrayInfo(zcu);
1629 if (ai.elem_type.eql(Type.u8, zcu)) {
1630 const c_len = ty.arrayLenIncludingSentinel(zcu);
1631 var literal = stringLiteral(writer, c_len);
1632 try literal.start();
1633 var index: u64 = 0;
1634 while (index < c_len) : (index += 1)
1635 try literal.writeChar(0xaa);
1636 return literal.end();
1637 } else {
1638 if (!location.isInitializer()) {
1639 try writer.writeByte('(');
1640 try dg.renderType(writer, ty);
1641 try writer.writeByte(')');
1642 }
1643
1644 try writer.writeByte('{');
1645 const c_len = ty.arrayLenIncludingSentinel(zcu);
1646 var index: u64 = 0;
1647 while (index < c_len) : (index += 1) {
1648 if (index > 0) try writer.writeAll(", ");
1649 try dg.renderUndefValue(writer, ty.childType(zcu), initializer_type);
1650 }
1651 return writer.writeByte('}');
16101652 }
1611 try writer.writeByte('}');
1612 }
1653 },
1654 .anyframe_type,
1655 .opaque_type,
1656 .func_type,
1657 => unreachable,
1658
1659 .undef,
1660 .simple_value,
1661 .variable,
1662 .extern_func,
1663 .func,
1664 .int,
1665 .err,
1666 .error_union,
1667 .enum_literal,
1668 .enum_tag,
1669 .empty_enum_value,
1670 .float,
1671 .ptr,
1672 .slice,
1673 .opt,
1674 .aggregate,
1675 .un,
1676 .memoized_call,
1677 => unreachable,
16131678 },
1614 .ComptimeInt,
1615 .ComptimeFloat,
1616 .Type,
1617 .EnumLiteral,
1618 .Void,
1619 .NoReturn,
1620 .Undefined,
1621 .Null,
1622 .Opaque,
1623 => unreachable,
1624
1625 .Fn,
1626 .Frame,
1627 .AnyFrame,
1628 => |tag| return dg.fail("TODO: C backend: implement value of type {s}", .{
1629 @tagName(tag),
1630 }),
16311679 }
16321680 }
16331681
......@@ -1641,13 +1689,12 @@ pub const DeclGen = struct {
16411689 ident: []const u8,
16421690 },
16431691 ) !void {
1644 const store = &dg.ctypes.set;
16451692 const zcu = dg.zcu;
16461693 const ip = &zcu.intern_pool;
16471694
16481695 const fn_decl = zcu.declPtr(fn_decl_index);
16491696 const fn_ty = fn_decl.typeOf(zcu);
1650 const fn_cty_idx = try dg.typeToIndex(fn_ty, kind);
1697 const fn_ctype = try dg.ctypeFromType(fn_ty, kind);
16511698
16521699 const fn_info = zcu.typeToFunc(fn_ty).?;
16531700 if (fn_info.cc == .Naked) {
......@@ -1661,7 +1708,7 @@ pub const DeclGen = struct {
16611708 try w.writeAll("zig_cold ");
16621709 if (fn_info.return_type == .noreturn_type) try w.writeAll("zig_noreturn ");
16631710
1664 var trailing = try renderTypePrefix(dg.pass, store.*, zcu, w, fn_cty_idx, .suffix, .{});
1711 var trailing = try renderTypePrefix(dg.pass, &dg.ctype_pool, zcu, w, fn_ctype, .suffix, .{});
16651712
16661713 if (toCallingConvention(fn_info.cc)) |call_conv| {
16671714 try w.print("{}zig_callconv({s})", .{ trailing, call_conv });
......@@ -1670,7 +1717,7 @@ pub const DeclGen = struct {
16701717
16711718 switch (kind) {
16721719 .forward => {},
1673 .complete => if (fn_decl.alignment.toByteUnitsOptional()) |a| {
1720 .complete => if (fn_decl.alignment.toByteUnits()) |a| {
16741721 try w.print("{}zig_align_fn({})", .{ trailing, a });
16751722 trailing = .maybe_space;
16761723 },
......@@ -1687,10 +1734,10 @@ pub const DeclGen = struct {
16871734
16881735 try renderTypeSuffix(
16891736 dg.pass,
1690 store.*,
1737 &dg.ctype_pool,
16911738 zcu,
16921739 w,
1693 fn_cty_idx,
1740 fn_ctype,
16941741 .suffix,
16951742 CQualifiers.init(.{ .@"const" = switch (kind) {
16961743 .forward => false,
......@@ -1701,7 +1748,7 @@ pub const DeclGen = struct {
17011748
17021749 switch (kind) {
17031750 .forward => {
1704 if (fn_decl.alignment.toByteUnitsOptional()) |a| {
1751 if (fn_decl.alignment.toByteUnits()) |a| {
17051752 try w.print(" zig_align_fn({})", .{a});
17061753 }
17071754 switch (name) {
......@@ -1748,20 +1795,13 @@ pub const DeclGen = struct {
17481795 }
17491796 }
17501797
1751 fn indexToCType(dg: *DeclGen, idx: CType.Index) CType {
1752 return dg.ctypes.indexToCType(idx);
1798 fn ctypeFromType(dg: *DeclGen, ty: Type, kind: CType.Kind) !CType {
1799 defer std.debug.assert(dg.scratch.items.len == 0);
1800 return dg.ctype_pool.fromType(dg.gpa, &dg.scratch, ty, dg.zcu, dg.mod, kind);
17531801 }
17541802
1755 fn typeToIndex(dg: *DeclGen, ty: Type, kind: CType.Kind) !CType.Index {
1756 return dg.ctypes.typeToIndex(dg.gpa, ty, dg.zcu, dg.mod, kind);
1757 }
1758
1759 fn typeToCType(dg: *DeclGen, ty: Type, kind: CType.Kind) !CType {
1760 return dg.ctypes.typeToCType(dg.gpa, ty, dg.zcu, dg.mod, kind);
1761 }
1762
1763 fn byteSize(dg: *DeclGen, cty: CType) u64 {
1764 return cty.byteSize(dg.ctypes.set, dg.mod);
1803 fn byteSize(dg: *DeclGen, ctype: CType) u64 {
1804 return ctype.byteSize(&dg.ctype_pool, dg.mod);
17651805 }
17661806
17671807 /// Renders a type as a single identifier, generating intermediate typedefs
......@@ -1776,14 +1816,12 @@ pub const DeclGen = struct {
17761816 /// | `renderType` | "uint8_t *" | "uint8_t *[10]" |
17771817 ///
17781818 fn renderType(dg: *DeclGen, w: anytype, t: Type) error{ OutOfMemory, AnalysisFail }!void {
1779 try dg.renderCType(w, try dg.typeToIndex(t, .complete));
1819 try dg.renderCType(w, try dg.ctypeFromType(t, .complete));
17801820 }
17811821
1782 fn renderCType(dg: *DeclGen, w: anytype, idx: CType.Index) error{ OutOfMemory, AnalysisFail }!void {
1783 const store = &dg.ctypes.set;
1784 const zcu = dg.zcu;
1785 _ = try renderTypePrefix(dg.pass, store.*, zcu, w, idx, .suffix, .{});
1786 try renderTypeSuffix(dg.pass, store.*, zcu, w, idx, .suffix, .{});
1822 fn renderCType(dg: *DeclGen, w: anytype, ctype: CType) error{ OutOfMemory, AnalysisFail }!void {
1823 _ = try renderTypePrefix(dg.pass, &dg.ctype_pool, dg.zcu, w, ctype, .suffix, .{});
1824 try renderTypeSuffix(dg.pass, &dg.ctype_pool, dg.zcu, w, ctype, .suffix, .{});
17871825 }
17881826
17891827 const IntCastContext = union(enum) {
......@@ -1905,32 +1943,37 @@ pub const DeclGen = struct {
19051943 alignment: Alignment,
19061944 kind: CType.Kind,
19071945 ) error{ OutOfMemory, AnalysisFail }!void {
1908 const zcu = dg.zcu;
1909 const alignas = CType.AlignAs.init(alignment, ty.abiAlignment(zcu));
1910 try dg.renderCTypeAndName(w, try dg.typeToIndex(ty, kind), name, qualifiers, alignas);
1946 try dg.renderCTypeAndName(
1947 w,
1948 try dg.ctypeFromType(ty, kind),
1949 name,
1950 qualifiers,
1951 CType.AlignAs.fromAlignment(.{
1952 .@"align" = alignment,
1953 .abi = ty.abiAlignment(dg.zcu),
1954 }),
1955 );
19111956 }
19121957
19131958 fn renderCTypeAndName(
19141959 dg: *DeclGen,
19151960 w: anytype,
1916 cty_idx: CType.Index,
1961 ctype: CType,
19171962 name: CValue,
19181963 qualifiers: CQualifiers,
19191964 alignas: CType.AlignAs,
19201965 ) error{ OutOfMemory, AnalysisFail }!void {
1921 const store = &dg.ctypes.set;
1922 const zcu = dg.zcu;
1923
19241966 switch (alignas.abiOrder()) {
19251967 .lt => try w.print("zig_under_align({}) ", .{alignas.toByteUnits()}),
19261968 .eq => {},
19271969 .gt => try w.print("zig_align({}) ", .{alignas.toByteUnits()}),
19281970 }
19291971
1930 const trailing = try renderTypePrefix(dg.pass, store.*, zcu, w, cty_idx, .suffix, qualifiers);
1931 try w.print("{}", .{trailing});
1972 try w.print("{}", .{
1973 try renderTypePrefix(dg.pass, &dg.ctype_pool, dg.zcu, w, ctype, .suffix, qualifiers),
1974 });
19321975 try dg.writeName(w, name);
1933 try renderTypeSuffix(dg.pass, store.*, zcu, w, cty_idx, .suffix, .{});
1976 try renderTypeSuffix(dg.pass, &dg.ctype_pool, dg.zcu, w, ctype, .suffix, .{});
19341977 }
19351978
19361979 fn declIsGlobal(dg: *DeclGen, val: Value) bool {
......@@ -2094,33 +2137,31 @@ pub const DeclGen = struct {
20942137 }
20952138
20962139 fn renderTypeForBuiltinFnName(dg: *DeclGen, writer: anytype, ty: Type) !void {
2097 try dg.renderCTypeForBuiltinFnName(writer, try dg.typeToCType(ty, .complete));
2140 try dg.renderCTypeForBuiltinFnName(writer, try dg.ctypeFromType(ty, .complete));
20982141 }
20992142
2100 fn renderCTypeForBuiltinFnName(dg: *DeclGen, writer: anytype, cty: CType) !void {
2101 switch (cty.tag()) {
2102 else => try writer.print("{c}{d}", .{
2103 if (cty.isBool())
2143 fn renderCTypeForBuiltinFnName(dg: *DeclGen, writer: anytype, ctype: CType) !void {
2144 switch (ctype.info(&dg.ctype_pool)) {
2145 else => |ctype_info| try writer.print("{c}{d}", .{
2146 if (ctype.isBool())
21042147 signAbbrev(.unsigned)
2105 else if (cty.isInteger())
2106 signAbbrev(cty.signedness(dg.mod))
2107 else if (cty.isFloat())
2148 else if (ctype.isInteger())
2149 signAbbrev(ctype.signedness(dg.mod))
2150 else if (ctype.isFloat())
21082151 @as(u8, 'f')
2109 else if (cty.isPointer())
2152 else if (ctype_info == .pointer)
21102153 @as(u8, 'p')
21112154 else
2112 return dg.fail("TODO: CBE: implement renderTypeForBuiltinFnName for type {}", .{
2113 cty.tag(),
2114 }),
2115 if (cty.isFloat()) cty.floatActiveBits(dg.mod) else dg.byteSize(cty) * 8,
2155 return dg.fail("TODO: CBE: implement renderTypeForBuiltinFnName for {s} type", .{@tagName(ctype_info)}),
2156 if (ctype.isFloat()) ctype.floatActiveBits(dg.mod) else dg.byteSize(ctype) * 8,
21162157 }),
21172158 .array => try writer.writeAll("big"),
21182159 }
21192160 }
21202161
21212162 fn renderBuiltinInfo(dg: *DeclGen, writer: anytype, ty: Type, info: BuiltinInfo) !void {
2122 const cty = try dg.typeToCType(ty, .complete);
2123 const is_big = cty.tag() == .array;
2163 const ctype = try dg.ctypeFromType(ty, .complete);
2164 const is_big = ctype.info(&dg.ctype_pool) == .array;
21242165 switch (info) {
21252166 .none => if (!is_big) return,
21262167 .bits => {},
......@@ -2155,7 +2196,7 @@ pub const DeclGen = struct {
21552196 .dg = dg,
21562197 .int_info = ty.intInfo(zcu),
21572198 .kind = kind,
2158 .cty = try dg.typeToCType(ty, kind),
2199 .ctype = try dg.ctypeFromType(ty, kind),
21592200 .val = val,
21602201 } };
21612202 }
......@@ -2184,122 +2225,74 @@ const RenderCTypeTrailing = enum {
21842225 }
21852226 }
21862227};
2187fn renderTypeName(
2228fn renderAlignedTypeName(w: anytype, ctype: CType) !void {
2229 try w.print("anon__aligned_{d}", .{@intFromEnum(ctype.index)});
2230}
2231fn renderFwdDeclTypeName(
21882232 zcu: *Zcu,
21892233 w: anytype,
2190 idx: CType.Index,
2191 cty: CType,
2234 ctype: CType,
2235 fwd_decl: CType.Info.FwdDecl,
21922236 attributes: []const u8,
21932237) !void {
2194 switch (cty.tag()) {
2195 else => unreachable,
2196
2197 .fwd_anon_struct,
2198 .fwd_anon_union,
2199 => |tag| try w.print("{s} {s}anon__lazy_{d}", .{
2200 @tagName(tag)["fwd_anon_".len..],
2201 attributes,
2202 idx,
2238 try w.print("{s} {s}", .{ @tagName(fwd_decl.tag), attributes });
2239 switch (fwd_decl.name) {
2240 .anon => try w.print("anon__lazy_{d}", .{@intFromEnum(ctype.index)}),
2241 .owner_decl => |owner_decl| try w.print("{}__{d}", .{
2242 fmtIdent(zcu.intern_pool.stringToSlice(zcu.declPtr(owner_decl).name)),
2243 @intFromEnum(owner_decl),
22032244 }),
2204
2205 .fwd_struct,
2206 .fwd_union,
2207 => |tag| {
2208 const owner_decl = cty.cast(CType.Payload.FwdDecl).?.data;
2209 try w.print("{s} {s}{}__{d}", .{
2210 @tagName(tag)["fwd_".len..],
2211 attributes,
2212 fmtIdent(zcu.intern_pool.stringToSlice(zcu.declPtr(owner_decl).name)),
2213 @intFromEnum(owner_decl),
2214 });
2215 },
22162245 }
22172246}
22182247fn renderTypePrefix(
22192248 pass: DeclGen.Pass,
2220 store: CType.Store.Set,
2249 ctype_pool: *const CType.Pool,
22212250 zcu: *Zcu,
22222251 w: anytype,
2223 idx: CType.Index,
2252 ctype: CType,
22242253 parent_fix: CTypeFix,
22252254 qualifiers: CQualifiers,
22262255) @TypeOf(w).Error!RenderCTypeTrailing {
22272256 var trailing = RenderCTypeTrailing.maybe_space;
2257 switch (ctype.info(ctype_pool)) {
2258 .basic => |basic_info| try w.writeAll(@tagName(basic_info)),
22282259
2229 const cty = store.indexToCType(idx);
2230 switch (cty.tag()) {
2231 .void,
2232 .char,
2233 .@"signed char",
2234 .short,
2235 .int,
2236 .long,
2237 .@"long long",
2238 ._Bool,
2239 .@"unsigned char",
2240 .@"unsigned short",
2241 .@"unsigned int",
2242 .@"unsigned long",
2243 .@"unsigned long long",
2244 .float,
2245 .double,
2246 .@"long double",
2247 .bool,
2248 .size_t,
2249 .ptrdiff_t,
2250 .uint8_t,
2251 .int8_t,
2252 .uint16_t,
2253 .int16_t,
2254 .uint32_t,
2255 .int32_t,
2256 .uint64_t,
2257 .int64_t,
2258 .uintptr_t,
2259 .intptr_t,
2260 .zig_u128,
2261 .zig_i128,
2262 .zig_f16,
2263 .zig_f32,
2264 .zig_f64,
2265 .zig_f80,
2266 .zig_f128,
2267 .zig_c_longdouble,
2268 => |tag| try w.writeAll(@tagName(tag)),
2269
2270 .pointer,
2271 .pointer_const,
2272 .pointer_volatile,
2273 .pointer_const_volatile,
2274 => |tag| {
2275 const child_idx = cty.cast(CType.Payload.Child).?.data;
2276 const child_trailing = try renderTypePrefix(
2260 .pointer => |pointer_info| {
2261 try w.print("{}*", .{try renderTypePrefix(
22772262 pass,
2278 store,
2263 ctype_pool,
22792264 zcu,
22802265 w,
2281 child_idx,
2266 pointer_info.elem_ctype,
22822267 .prefix,
2283 CQualifiers.init(.{ .@"const" = switch (tag) {
2284 .pointer, .pointer_volatile => false,
2285 .pointer_const, .pointer_const_volatile => true,
2286 else => unreachable,
2287 }, .@"volatile" = switch (tag) {
2288 .pointer, .pointer_const => false,
2289 .pointer_volatile, .pointer_const_volatile => true,
2290 else => unreachable,
2291 } }),
2292 );
2293 try w.print("{}*", .{child_trailing});
2268 CQualifiers.init(.{
2269 .@"const" = pointer_info.@"const",
2270 .@"volatile" = pointer_info.@"volatile",
2271 }),
2272 )});
22942273 trailing = .no_space;
22952274 },
22962275
2297 .array,
2298 .vector,
2299 => {
2300 const child_idx = cty.cast(CType.Payload.Sequence).?.data.elem_type;
2301 const child_trailing =
2302 try renderTypePrefix(pass, store, zcu, w, child_idx, .suffix, qualifiers);
2276 .aligned => switch (pass) {
2277 .decl => |decl_index| try w.print("decl__{d}_{d}", .{
2278 @intFromEnum(decl_index), @intFromEnum(ctype.index),
2279 }),
2280 .anon => |anon_decl| try w.print("anon__{d}_{d}", .{
2281 @intFromEnum(anon_decl), @intFromEnum(ctype.index),
2282 }),
2283 .flush => try renderAlignedTypeName(w, ctype),
2284 },
2285
2286 .array, .vector => |sequence_info| {
2287 const child_trailing = try renderTypePrefix(
2288 pass,
2289 ctype_pool,
2290 zcu,
2291 w,
2292 sequence_info.elem_ctype,
2293 .suffix,
2294 qualifiers,
2295 );
23032296 switch (parent_fix) {
23042297 .prefix => {
23052298 try w.print("{}(", .{child_trailing});
......@@ -2309,56 +2302,46 @@ fn renderTypePrefix(
23092302 }
23102303 },
23112304
2312 .fwd_anon_struct,
2313 .fwd_anon_union,
2314 => switch (pass) {
2315 .decl => |decl_index| try w.print("decl__{d}_{d}", .{ @intFromEnum(decl_index), idx }),
2316 .anon => |anon_decl| try w.print("anon__{d}_{d}", .{ @intFromEnum(anon_decl), idx }),
2317 .flush => try renderTypeName(zcu, w, idx, cty, ""),
2305 .fwd_decl => |fwd_decl_info| switch (fwd_decl_info.name) {
2306 .anon => switch (pass) {
2307 .decl => |decl_index| try w.print("decl__{d}_{d}", .{
2308 @intFromEnum(decl_index), @intFromEnum(ctype.index),
2309 }),
2310 .anon => |anon_decl| try w.print("anon__{d}_{d}", .{
2311 @intFromEnum(anon_decl), @intFromEnum(ctype.index),
2312 }),
2313 .flush => try renderFwdDeclTypeName(zcu, w, ctype, fwd_decl_info, ""),
2314 },
2315 .owner_decl => try renderFwdDeclTypeName(zcu, w, ctype, fwd_decl_info, ""),
23182316 },
23192317
2320 .fwd_struct,
2321 .fwd_union,
2322 => try renderTypeName(zcu, w, idx, cty, ""),
2323
2324 .unnamed_struct,
2325 .unnamed_union,
2326 .packed_unnamed_struct,
2327 .packed_unnamed_union,
2328 => |tag| {
2329 try w.print("{s} {s}", .{
2330 @tagName(tag)["unnamed_".len..],
2331 if (cty.isPacked()) "zig_packed(" else "",
2332 });
2333 try renderAggregateFields(zcu, w, store, cty, 1);
2334 if (cty.isPacked()) try w.writeByte(')');
2318 .aggregate => |aggregate_info| switch (aggregate_info.name) {
2319 .anon => {
2320 try w.print("{s} {s}", .{
2321 @tagName(aggregate_info.tag),
2322 if (aggregate_info.@"packed") "zig_packed(" else "",
2323 });
2324 try renderFields(zcu, w, ctype_pool, aggregate_info, 1);
2325 if (aggregate_info.@"packed") try w.writeByte(')');
2326 },
2327 .fwd_decl => |fwd_decl| return renderTypePrefix(
2328 pass,
2329 ctype_pool,
2330 zcu,
2331 w,
2332 fwd_decl,
2333 parent_fix,
2334 qualifiers,
2335 ),
23352336 },
23362337
2337 .anon_struct,
2338 .anon_union,
2339 .@"struct",
2340 .@"union",
2341 .packed_struct,
2342 .packed_union,
2343 => return renderTypePrefix(
2344 pass,
2345 store,
2346 zcu,
2347 w,
2348 cty.cast(CType.Payload.Aggregate).?.data.fwd_decl,
2349 parent_fix,
2350 qualifiers,
2351 ),
2352
2353 .function,
2354 .varargs_function,
2355 => {
2338 .function => |function_info| {
23562339 const child_trailing = try renderTypePrefix(
23572340 pass,
2358 store,
2341 ctype_pool,
23592342 zcu,
23602343 w,
2361 cty.cast(CType.Payload.Function).?.data.return_type,
2344 function_info.return_ctype,
23622345 .suffix,
23632346 .{},
23642347 );
......@@ -2371,170 +2354,107 @@ fn renderTypePrefix(
23712354 }
23722355 },
23732356 }
2374
23752357 var qualifier_it = qualifiers.iterator();
23762358 while (qualifier_it.next()) |qualifier| {
23772359 try w.print("{}{s}", .{ trailing, @tagName(qualifier) });
23782360 trailing = .maybe_space;
23792361 }
2380
23812362 return trailing;
23822363}
23832364fn renderTypeSuffix(
23842365 pass: DeclGen.Pass,
2385 store: CType.Store.Set,
2366 ctype_pool: *const CType.Pool,
23862367 zcu: *Zcu,
23872368 w: anytype,
2388 idx: CType.Index,
2369 ctype: CType,
23892370 parent_fix: CTypeFix,
23902371 qualifiers: CQualifiers,
23912372) @TypeOf(w).Error!void {
2392 const cty = store.indexToCType(idx);
2393 switch (cty.tag()) {
2394 .void,
2395 .char,
2396 .@"signed char",
2397 .short,
2398 .int,
2399 .long,
2400 .@"long long",
2401 ._Bool,
2402 .@"unsigned char",
2403 .@"unsigned short",
2404 .@"unsigned int",
2405 .@"unsigned long",
2406 .@"unsigned long long",
2407 .float,
2408 .double,
2409 .@"long double",
2410 .bool,
2411 .size_t,
2412 .ptrdiff_t,
2413 .uint8_t,
2414 .int8_t,
2415 .uint16_t,
2416 .int16_t,
2417 .uint32_t,
2418 .int32_t,
2419 .uint64_t,
2420 .int64_t,
2421 .uintptr_t,
2422 .intptr_t,
2423 .zig_u128,
2424 .zig_i128,
2425 .zig_f16,
2426 .zig_f32,
2427 .zig_f64,
2428 .zig_f80,
2429 .zig_f128,
2430 .zig_c_longdouble,
2431 => {},
2432
2433 .pointer,
2434 .pointer_const,
2435 .pointer_volatile,
2436 .pointer_const_volatile,
2437 => try renderTypeSuffix(
2373 switch (ctype.info(ctype_pool)) {
2374 .basic, .aligned, .fwd_decl, .aggregate => {},
2375 .pointer => |pointer_info| try renderTypeSuffix(
24382376 pass,
2439 store,
2377 ctype_pool,
24402378 zcu,
24412379 w,
2442 cty.cast(CType.Payload.Child).?.data,
2380 pointer_info.elem_ctype,
24432381 .prefix,
24442382 .{},
24452383 ),
2446
2447 .array,
2448 .vector,
2449 => {
2384 .array, .vector => |sequence_info| {
24502385 switch (parent_fix) {
24512386 .prefix => try w.writeByte(')'),
24522387 .suffix => {},
24532388 }
24542389
2455 try w.print("[{}]", .{cty.cast(CType.Payload.Sequence).?.data.len});
2456 try renderTypeSuffix(
2457 pass,
2458 store,
2459 zcu,
2460 w,
2461 cty.cast(CType.Payload.Sequence).?.data.elem_type,
2462 .suffix,
2463 .{},
2464 );
2390 try w.print("[{}]", .{sequence_info.len});
2391 try renderTypeSuffix(pass, ctype_pool, zcu, w, sequence_info.elem_ctype, .suffix, .{});
24652392 },
2466
2467 .fwd_anon_struct,
2468 .fwd_anon_union,
2469 .fwd_struct,
2470 .fwd_union,
2471 .unnamed_struct,
2472 .unnamed_union,
2473 .packed_unnamed_struct,
2474 .packed_unnamed_union,
2475 .anon_struct,
2476 .anon_union,
2477 .@"struct",
2478 .@"union",
2479 .packed_struct,
2480 .packed_union,
2481 => {},
2482
2483 .function,
2484 .varargs_function,
2485 => |tag| {
2393 .function => |function_info| {
24862394 switch (parent_fix) {
24872395 .prefix => try w.writeByte(')'),
24882396 .suffix => {},
24892397 }
24902398
2491 const data = cty.cast(CType.Payload.Function).?.data;
2492
24932399 try w.writeByte('(');
24942400 var need_comma = false;
2495 for (data.param_types, 0..) |param_type, param_i| {
2401 for (0..function_info.param_ctypes.len) |param_index| {
2402 const param_type = function_info.param_ctypes.at(param_index, ctype_pool);
24962403 if (need_comma) try w.writeAll(", ");
24972404 need_comma = true;
24982405 const trailing =
2499 try renderTypePrefix(pass, store, zcu, w, param_type, .suffix, qualifiers);
2500 if (qualifiers.contains(.@"const")) try w.print("{}a{d}", .{ trailing, param_i });
2501 try renderTypeSuffix(pass, store, zcu, w, param_type, .suffix, .{});
2406 try renderTypePrefix(pass, ctype_pool, zcu, w, param_type, .suffix, qualifiers);
2407 if (qualifiers.contains(.@"const")) try w.print("{}a{d}", .{ trailing, param_index });
2408 try renderTypeSuffix(pass, ctype_pool, zcu, w, param_type, .suffix, .{});
25022409 }
2503 switch (tag) {
2504 .function => {},
2505 .varargs_function => {
2506 if (need_comma) try w.writeAll(", ");
2507 need_comma = true;
2508 try w.writeAll("...");
2509 },
2510 else => unreachable,
2410 if (function_info.varargs) {
2411 if (need_comma) try w.writeAll(", ");
2412 need_comma = true;
2413 try w.writeAll("...");
25112414 }
25122415 if (!need_comma) try w.writeAll("void");
25132416 try w.writeByte(')');
25142417
2515 try renderTypeSuffix(pass, store, zcu, w, data.return_type, .suffix, .{});
2418 try renderTypeSuffix(pass, ctype_pool, zcu, w, function_info.return_ctype, .suffix, .{});
25162419 },
25172420 }
25182421}
2519fn renderAggregateFields(
2422fn renderFields(
25202423 zcu: *Zcu,
25212424 writer: anytype,
2522 store: CType.Store.Set,
2523 cty: CType,
2425 ctype_pool: *const CType.Pool,
2426 aggregate_info: CType.Info.Aggregate,
25242427 indent: usize,
25252428) !void {
25262429 try writer.writeAll("{\n");
2527 const fields = cty.fields();
2528 for (fields) |field| {
2430 for (0..aggregate_info.fields.len) |field_index| {
2431 const field_info = aggregate_info.fields.at(field_index, ctype_pool);
25292432 try writer.writeByteNTimes(' ', indent + 1);
2530 switch (field.alignas.abiOrder()) {
2531 .lt => try writer.print("zig_under_align({}) ", .{field.alignas.toByteUnits()}),
2532 .eq => {},
2533 .gt => try writer.print("zig_align({}) ", .{field.alignas.toByteUnits()}),
2433 switch (field_info.alignas.abiOrder()) {
2434 .lt => {
2435 std.debug.assert(aggregate_info.@"packed");
2436 if (field_info.alignas.@"align" != .@"1") try writer.print("zig_under_align({}) ", .{
2437 field_info.alignas.toByteUnits(),
2438 });
2439 },
2440 .eq => if (aggregate_info.@"packed" and field_info.alignas.@"align" != .@"1")
2441 try writer.print("zig_align({}) ", .{field_info.alignas.toByteUnits()}),
2442 .gt => {
2443 std.debug.assert(field_info.alignas.@"align" != .@"1");
2444 try writer.print("zig_align({}) ", .{field_info.alignas.toByteUnits()});
2445 },
25342446 }
2535 const trailing = try renderTypePrefix(.flush, store, zcu, writer, field.type, .suffix, .{});
2536 try writer.print("{}{ }", .{ trailing, fmtIdent(mem.span(field.name)) });
2537 try renderTypeSuffix(.flush, store, zcu, writer, field.type, .suffix, .{});
2447 const trailing = try renderTypePrefix(
2448 .flush,
2449 ctype_pool,
2450 zcu,
2451 writer,
2452 field_info.ctype,
2453 .suffix,
2454 .{},
2455 );
2456 try writer.print("{}{ }", .{ trailing, fmtIdent(field_info.name.slice(ctype_pool)) });
2457 try renderTypeSuffix(.flush, ctype_pool, zcu, writer, field_info.ctype, .suffix, .{});
25382458 try writer.writeAll(";\n");
25392459 }
25402460 try writer.writeByteNTimes(' ', indent);
......@@ -2544,77 +2464,77 @@ fn renderAggregateFields(
25442464pub fn genTypeDecl(
25452465 zcu: *Zcu,
25462466 writer: anytype,
2547 global_store: CType.Store.Set,
2548 global_idx: CType.Index,
2467 global_ctype_pool: *const CType.Pool,
2468 global_ctype: CType,
25492469 pass: DeclGen.Pass,
2550 decl_store: CType.Store.Set,
2551 decl_idx: CType.Index,
2470 decl_ctype_pool: *const CType.Pool,
2471 decl_ctype: CType,
25522472 found_existing: bool,
25532473) !void {
2554 const global_cty = global_store.indexToCType(global_idx);
2555 switch (global_cty.tag()) {
2556 .fwd_anon_struct => if (pass != .flush) {
2557 try writer.writeAll("typedef ");
2558 _ = try renderTypePrefix(.flush, global_store, zcu, writer, global_idx, .suffix, .{});
2559 try writer.writeByte(' ');
2560 _ = try renderTypePrefix(pass, decl_store, zcu, writer, decl_idx, .suffix, .{});
2561 try writer.writeAll(";\n");
2562 },
2563
2564 .fwd_struct,
2565 .fwd_union,
2566 .anon_struct,
2567 .anon_union,
2568 .@"struct",
2569 .@"union",
2570 .packed_struct,
2571 .packed_union,
2572 => |tag| if (!found_existing) {
2573 switch (tag) {
2574 .fwd_struct,
2575 .fwd_union,
2576 => {
2577 const owner_decl = global_cty.cast(CType.Payload.FwdDecl).?.data;
2578 _ = try renderTypePrefix(
2579 .flush,
2580 global_store,
2581 zcu,
2582 writer,
2583 global_idx,
2584 .suffix,
2585 .{},
2586 );
2587 try writer.writeAll("; /* ");
2588 try zcu.declPtr(owner_decl).renderFullyQualifiedName(zcu, writer);
2589 try writer.writeAll(" */\n");
2590 },
2591
2592 .anon_struct,
2593 .anon_union,
2594 .@"struct",
2595 .@"union",
2596 .packed_struct,
2597 .packed_union,
2598 => {
2599 const fwd_idx = global_cty.cast(CType.Payload.Aggregate).?.data.fwd_decl;
2600 try renderTypeName(
2601 zcu,
2602 writer,
2603 fwd_idx,
2604 global_store.indexToCType(fwd_idx),
2605 if (global_cty.isPacked()) "zig_packed(" else "",
2606 );
2474 switch (global_ctype.info(global_ctype_pool)) {
2475 .basic, .pointer, .array, .vector, .function => {},
2476 .aligned => |aligned_info| {
2477 if (!found_existing) {
2478 try writer.writeAll("typedef ");
2479 try writer.print("{}", .{
2480 try renderTypePrefix(pass, global_ctype_pool, zcu, writer, aligned_info.ctype, .suffix, .{}),
2481 });
2482 try renderAlignedTypeName(writer, global_ctype);
2483 try renderTypeSuffix(pass, global_ctype_pool, zcu, writer, aligned_info.ctype, .suffix, .{});
2484 std.debug.assert(aligned_info.alignas.abiOrder().compare(.lt));
2485 try writer.print(" zig_under_align({d});\n", .{aligned_info.alignas.toByteUnits()});
2486 }
2487 switch (pass) {
2488 .decl, .anon => {
2489 try writer.writeAll("typedef ");
2490 _ = try renderTypePrefix(.flush, global_ctype_pool, zcu, writer, global_ctype, .suffix, .{});
26072491 try writer.writeByte(' ');
2608 try renderAggregateFields(zcu, writer, global_store, global_cty, 0);
2609 if (global_cty.isPacked()) try writer.writeByte(')');
2492 _ = try renderTypePrefix(pass, decl_ctype_pool, zcu, writer, decl_ctype, .suffix, .{});
26102493 try writer.writeAll(";\n");
26112494 },
2612
2613 else => unreachable,
2495 .flush => {},
26142496 }
26152497 },
2616
2617 else => {},
2498 .fwd_decl => |fwd_decl_info| switch (fwd_decl_info.name) {
2499 .anon => switch (pass) {
2500 .decl, .anon => {
2501 try writer.writeAll("typedef ");
2502 _ = try renderTypePrefix(.flush, global_ctype_pool, zcu, writer, global_ctype, .suffix, .{});
2503 try writer.writeByte(' ');
2504 _ = try renderTypePrefix(pass, decl_ctype_pool, zcu, writer, decl_ctype, .suffix, .{});
2505 try writer.writeAll(";\n");
2506 },
2507 .flush => {},
2508 },
2509 .owner_decl => |owner_decl_index| if (!found_existing) {
2510 _ = try renderTypePrefix(.flush, global_ctype_pool, zcu, writer, global_ctype, .suffix, .{});
2511 try writer.writeByte(';');
2512 const owner_decl = zcu.declPtr(owner_decl_index);
2513 const owner_mod = zcu.namespacePtr(owner_decl.src_namespace).file_scope.mod;
2514 if (!owner_mod.strip) {
2515 try writer.writeAll(" /* ");
2516 try owner_decl.renderFullyQualifiedName(zcu, writer);
2517 try writer.writeAll(" */");
2518 }
2519 try writer.writeByte('\n');
2520 },
2521 },
2522 .aggregate => |aggregate_info| switch (aggregate_info.name) {
2523 .anon => {},
2524 .fwd_decl => |fwd_decl| if (!found_existing) {
2525 try renderFwdDeclTypeName(
2526 zcu,
2527 writer,
2528 fwd_decl,
2529 fwd_decl.info(global_ctype_pool).fwd_decl,
2530 if (aggregate_info.@"packed") "zig_packed(" else "",
2531 );
2532 try writer.writeByte(' ');
2533 try renderFields(zcu, writer, global_ctype_pool, aggregate_info, 0);
2534 if (aggregate_info.@"packed") try writer.writeByte(')');
2535 try writer.writeAll(";\n");
2536 },
2537 },
26182538 }
26192539}
26202540
......@@ -2771,13 +2691,13 @@ fn genExports(o: *Object) !void {
27712691 }
27722692}
27732693
2774pub fn genLazyFn(o: *Object, lazy_fn: LazyFnMap.Entry) !void {
2694pub fn genLazyFn(o: *Object, lazy_ctype_pool: *const CType.Pool, lazy_fn: LazyFnMap.Entry) !void {
27752695 const zcu = o.dg.zcu;
27762696 const ip = &zcu.intern_pool;
2697 const ctype_pool = &o.dg.ctype_pool;
27772698 const w = o.writer();
27782699 const key = lazy_fn.key_ptr.*;
27792700 const val = lazy_fn.value_ptr;
2780 const fn_name = val.fn_name;
27812701 switch (key) {
27822702 .tag_name => {
27832703 const enum_ty = val.data.tag_name;
......@@ -2787,7 +2707,7 @@ pub fn genLazyFn(o: *Object, lazy_fn: LazyFnMap.Entry) !void {
27872707 try w.writeAll("static ");
27882708 try o.dg.renderType(w, name_slice_ty);
27892709 try w.writeByte(' ');
2790 try w.writeAll(fn_name);
2710 try w.writeAll(val.fn_name.slice(lazy_ctype_pool));
27912711 try w.writeByte('(');
27922712 try o.dg.renderTypeAndName(w, enum_ty, .{ .identifier = "tag" }, Const, .none, .complete);
27932713 try w.writeAll(") {\n switch (tag) {\n");
......@@ -2829,8 +2749,9 @@ pub fn genLazyFn(o: *Object, lazy_fn: LazyFnMap.Entry) !void {
28292749 },
28302750 .never_tail, .never_inline => |fn_decl_index| {
28312751 const fn_decl = zcu.declPtr(fn_decl_index);
2832 const fn_cty = try o.dg.typeToCType(fn_decl.typeOf(zcu), .complete);
2833 const fn_info = fn_cty.cast(CType.Payload.Function).?.data;
2752 const fn_ctype = try o.dg.ctypeFromType(fn_decl.typeOf(zcu), .complete);
2753 const fn_info = fn_ctype.info(ctype_pool).function;
2754 const fn_name = val.fn_name.slice(lazy_ctype_pool);
28342755
28352756 const fwd_decl_writer = o.dg.fwdDeclWriter();
28362757 try fwd_decl_writer.print("static zig_{s} ", .{@tagName(key)});
......@@ -2843,11 +2764,13 @@ pub fn genLazyFn(o: *Object, lazy_fn: LazyFnMap.Entry) !void {
28432764 try fwd_decl_writer.writeAll(";\n");
28442765
28452766 try w.print("static zig_{s} ", .{@tagName(key)});
2846 try o.dg.renderFunctionSignature(w, fn_decl_index, .complete, .{ .ident = fn_name });
2767 try o.dg.renderFunctionSignature(w, fn_decl_index, .complete, .{
2768 .ident = fn_name,
2769 });
28472770 try w.writeAll(" {\n return ");
28482771 try o.dg.renderDeclName(w, fn_decl_index, 0);
28492772 try w.writeByte('(');
2850 for (0..fn_info.param_types.len) |arg| {
2773 for (0..fn_info.param_ctypes.len) |arg| {
28512774 if (arg > 0) try w.writeAll(", ");
28522775 try o.dg.writeCValue(w, .{ .arg = arg });
28532776 }
......@@ -2931,7 +2854,7 @@ pub fn genFunc(f: *Function) !void {
29312854 for (free_locals.values()) |list| {
29322855 for (list.keys()) |local_index| {
29332856 const local = f.locals.items[local_index];
2934 try o.dg.renderCTypeAndName(w, local.cty_idx, .{ .local = local_index }, .{}, local.flags.alignas);
2857 try o.dg.renderCTypeAndName(w, local.ctype, .{ .local = local_index }, .{}, local.flags.alignas);
29352858 try w.writeAll(";\n ");
29362859 }
29372860 }
......@@ -3451,11 +3374,7 @@ fn airPtrElemPtr(f: *Function, inst: Air.Inst.Index) !CValue {
34513374
34523375 const inst_ty = f.typeOfIndex(inst);
34533376 const ptr_ty = f.typeOf(bin_op.lhs);
3454 const ptr_align = ptr_ty.ptrAlignment(zcu);
3455 const elem_ty = ptr_ty.elemType2(zcu);
3456 const elem_align = elem_ty.abiAlignment(zcu);
3457 const is_under_aligned = ptr_align.compareStrict(.lt, elem_align);
3458 const elem_has_bits = elem_ty.hasRuntimeBitsIgnoreComptime(zcu);
3377 const elem_has_bits = ptr_ty.elemType2(zcu).hasRuntimeBitsIgnoreComptime(zcu);
34593378
34603379 const ptr = try f.resolveInst(bin_op.lhs);
34613380 const index = try f.resolveInst(bin_op.rhs);
......@@ -3470,22 +3389,13 @@ fn airPtrElemPtr(f: *Function, inst: Air.Inst.Index) !CValue {
34703389 try f.renderType(writer, inst_ty);
34713390 try writer.writeByte(')');
34723391 if (elem_has_bits) try writer.writeByte('&');
3473 if (elem_has_bits and ptr_ty.ptrSize(zcu) == .One and !is_under_aligned) {
3392 if (elem_has_bits and ptr_ty.ptrSize(zcu) == .One) {
34743393 // It's a pointer to an array, so we need to de-reference.
34753394 try f.writeCValueDeref(writer, ptr);
34763395 } else try f.writeCValue(writer, ptr, .Other);
34773396 if (elem_has_bits) {
34783397 try writer.writeByte('[');
34793398 try f.writeCValue(writer, index, .Other);
3480 if (is_under_aligned) {
3481 const factor = @divExact(elem_align.toByteUnitsOptional().?, @min(
3482 ptr_align.toByteUnitsOptional().?,
3483 f.object.dg.mod.resolved_target.result.maxIntAlignment(),
3484 ));
3485 try writer.print(" * {}", .{
3486 try f.fmtIntLiteral(try zcu.intValue(Type.usize, factor)),
3487 });
3488 }
34893399 try writer.writeByte(']');
34903400 }
34913401 try a.end(f, writer);
......@@ -3577,13 +3487,16 @@ fn airArrayElemVal(f: *Function, inst: Air.Inst.Index) !CValue {
35773487fn airAlloc(f: *Function, inst: Air.Inst.Index) !CValue {
35783488 const zcu = f.object.dg.zcu;
35793489 const inst_ty = f.typeOfIndex(inst);
3580 const elem_type = inst_ty.childType(zcu);
3581 if (!elem_type.isFnOrHasRuntimeBitsIgnoreComptime(zcu)) return .{ .undef = inst_ty };
3490 const elem_ty = inst_ty.childType(zcu);
3491 if (!elem_ty.isFnOrHasRuntimeBitsIgnoreComptime(zcu)) return .{ .undef = inst_ty };
35823492
3583 const local = try f.allocLocalValue(
3584 elem_type,
3585 inst_ty.ptrAlignment(zcu),
3586 );
3493 const local = try f.allocLocalValue(.{
3494 .ctype = try f.ctypeFromType(elem_ty, .complete),
3495 .alignas = CType.AlignAs.fromAlignment(.{
3496 .@"align" = inst_ty.ptrInfo(zcu).flags.alignment,
3497 .abi = elem_ty.abiAlignment(zcu),
3498 }),
3499 });
35873500 log.debug("%{d}: allocated unfreeable t{d}", .{ inst, local.new_local });
35883501 const gpa = f.object.dg.zcu.gpa;
35893502 try f.allocs.put(gpa, local.new_local, true);
......@@ -3596,10 +3509,13 @@ fn airRetPtr(f: *Function, inst: Air.Inst.Index) !CValue {
35963509 const elem_ty = inst_ty.childType(zcu);
35973510 if (!elem_ty.isFnOrHasRuntimeBitsIgnoreComptime(zcu)) return .{ .undef = inst_ty };
35983511
3599 const local = try f.allocLocalValue(
3600 elem_ty,
3601 inst_ty.ptrAlignment(zcu),
3602 );
3512 const local = try f.allocLocalValue(.{
3513 .ctype = try f.ctypeFromType(elem_ty, .complete),
3514 .alignas = CType.AlignAs.fromAlignment(.{
3515 .@"align" = inst_ty.ptrInfo(zcu).flags.alignment,
3516 .abi = elem_ty.abiAlignment(zcu),
3517 }),
3518 });
36033519 log.debug("%{d}: allocated unfreeable t{d}", .{ inst, local.new_local });
36043520 const gpa = f.object.dg.zcu.gpa;
36053521 try f.allocs.put(gpa, local.new_local, true);
......@@ -3608,14 +3524,14 @@ fn airRetPtr(f: *Function, inst: Air.Inst.Index) !CValue {
36083524
36093525fn airArg(f: *Function, inst: Air.Inst.Index) !CValue {
36103526 const inst_ty = f.typeOfIndex(inst);
3611 const inst_cty = try f.typeToIndex(inst_ty, .parameter);
3527 const inst_ctype = try f.ctypeFromType(inst_ty, .parameter);
36123528
36133529 const i = f.next_arg_index;
36143530 f.next_arg_index += 1;
3615 const result: CValue = if (inst_cty != try f.typeToIndex(inst_ty, .complete))
3616 .{ .arg_array = i }
3531 const result: CValue = if (inst_ctype.eql(try f.ctypeFromType(inst_ty, .complete)))
3532 .{ .arg = i }
36173533 else
3618 .{ .arg = i };
3534 .{ .arg_array = i };
36193535
36203536 if (f.liveness.isUnused(inst)) {
36213537 const writer = f.object.writer();
......@@ -3649,7 +3565,7 @@ fn airLoad(f: *Function, inst: Air.Inst.Index) !CValue {
36493565 try reap(f, inst, &.{ty_op.operand});
36503566
36513567 const is_aligned = if (ptr_info.flags.alignment != .none)
3652 ptr_info.flags.alignment.compare(.gte, src_ty.abiAlignment(zcu))
3568 ptr_info.flags.alignment.order(src_ty.abiAlignment(zcu)).compare(.gte)
36533569 else
36543570 true;
36553571 const is_array = lowersToArray(src_ty, zcu);
......@@ -3724,18 +3640,21 @@ fn airRet(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !CValue {
37243640 const op_inst = un_op.toIndex();
37253641 const op_ty = f.typeOf(un_op);
37263642 const ret_ty = if (is_ptr) op_ty.childType(zcu) else op_ty;
3727 const lowered_ret_ty = try lowerFnRetTy(ret_ty, zcu);
3643 const ret_ctype = try f.ctypeFromType(ret_ty, .parameter);
37283644
37293645 if (op_inst != null and f.air.instructions.items(.tag)[@intFromEnum(op_inst.?)] == .call_always_tail) {
37303646 try reap(f, inst, &.{un_op});
37313647 _ = try airCall(f, op_inst.?, .always_tail);
3732 } else if (lowered_ret_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
3648 } else if (ret_ctype.index != .void) {
37333649 const operand = try f.resolveInst(un_op);
37343650 try reap(f, inst, &.{un_op});
37353651 var deref = is_ptr;
37363652 const is_array = lowersToArray(ret_ty, zcu);
37373653 const ret_val = if (is_array) ret_val: {
3738 const array_local = try f.allocLocal(inst, lowered_ret_ty);
3654 const array_local = try f.allocAlignedLocal(inst, .{
3655 .ctype = ret_ctype,
3656 .alignas = CType.AlignAs.fromAbiAlignment(ret_ty.abiAlignment(f.object.dg.zcu)),
3657 });
37393658 try writer.writeAll("memcpy(");
37403659 try f.writeCValueMember(writer, array_local, .{ .identifier = "array" });
37413660 try writer.writeAll(", ");
......@@ -3921,7 +3840,7 @@ fn airStore(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue {
39213840 }
39223841
39233842 const is_aligned = if (ptr_info.flags.alignment != .none)
3924 ptr_info.flags.alignment.compare(.gte, src_ty.abiAlignment(zcu))
3843 ptr_info.flags.alignment.order(src_ty.abiAlignment(zcu)).compare(.gte)
39253844 else
39263845 true;
39273846 const is_array = lowersToArray(Type.fromInterned(ptr_info.child), zcu);
......@@ -4397,22 +4316,23 @@ fn airCall(
43974316 defer gpa.free(resolved_args);
43984317 for (resolved_args, args) |*resolved_arg, arg| {
43994318 const arg_ty = f.typeOf(arg);
4400 const arg_cty = try f.typeToIndex(arg_ty, .parameter);
4401 if (f.indexToCType(arg_cty).tag() == .void) {
4319 const arg_ctype = try f.ctypeFromType(arg_ty, .parameter);
4320 if (arg_ctype.index == .void) {
44024321 resolved_arg.* = .none;
44034322 continue;
44044323 }
44054324 resolved_arg.* = try f.resolveInst(arg);
4406 if (arg_cty != try f.typeToIndex(arg_ty, .complete)) {
4407 const lowered_arg_ty = try lowerFnRetTy(arg_ty, zcu);
4408
4409 const array_local = try f.allocLocal(inst, lowered_arg_ty);
4325 if (!arg_ctype.eql(try f.ctypeFromType(arg_ty, .complete))) {
4326 const array_local = try f.allocAlignedLocal(inst, .{
4327 .ctype = arg_ctype,
4328 .alignas = CType.AlignAs.fromAbiAlignment(arg_ty.abiAlignment(zcu)),
4329 });
44104330 try writer.writeAll("memcpy(");
44114331 try f.writeCValueMember(writer, array_local, .{ .identifier = "array" });
44124332 try writer.writeAll(", ");
44134333 try f.writeCValue(writer, resolved_arg.*, .FunctionArgument);
44144334 try writer.writeAll(", sizeof(");
4415 try f.renderType(writer, lowered_arg_ty);
4335 try f.renderCType(writer, arg_ctype);
44164336 try writer.writeAll("));\n");
44174337 resolved_arg.* = array_local;
44184338 }
......@@ -4433,21 +4353,27 @@ fn airCall(
44334353 else => unreachable,
44344354 }).?;
44354355 const ret_ty = Type.fromInterned(fn_info.return_type);
4436 const lowered_ret_ty = try lowerFnRetTy(ret_ty, zcu);
4356 const ret_ctype: CType = if (ret_ty.isNoReturn(zcu))
4357 .{ .index = .void }
4358 else
4359 try f.ctypeFromType(ret_ty, .parameter);
44374360
44384361 const result_local = result: {
44394362 if (modifier == .always_tail) {
44404363 try writer.writeAll("zig_always_tail return ");
44414364 break :result .none;
4442 } else if (!lowered_ret_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
4365 } else if (ret_ctype.index == .void) {
44434366 break :result .none;
44444367 } else if (f.liveness.isUnused(inst)) {
44454368 try writer.writeByte('(');
4446 try f.renderType(writer, Type.void);
4369 try f.renderCType(writer, .{ .index = .void });
44474370 try writer.writeByte(')');
44484371 break :result .none;
44494372 } else {
4450 const local = try f.allocLocal(inst, lowered_ret_ty);
4373 const local = try f.allocAlignedLocal(inst, .{
4374 .ctype = ret_ctype,
4375 .alignas = CType.AlignAs.fromAbiAlignment(ret_ty.abiAlignment(zcu)),
4376 });
44514377 try f.writeCValue(writer, local, .Other);
44524378 try writer.writeAll(" = ");
44534379 break :result local;
......@@ -4767,6 +4693,7 @@ const LocalResult = struct {
47674693fn bitcast(f: *Function, dest_ty: Type, operand: CValue, operand_ty: Type) !LocalResult {
47684694 const zcu = f.object.dg.zcu;
47694695 const target = &f.object.dg.mod.resolved_target.result;
4696 const ctype_pool = &f.object.dg.ctype_pool;
47704697 const writer = f.object.writer();
47714698
47724699 if (operand_ty.isAbiInt(zcu) and dest_ty.isAbiInt(zcu)) {
......@@ -4825,49 +4752,54 @@ fn bitcast(f: *Function, dest_ty: Type, operand: CValue, operand_ty: Type) !Loca
48254752
48264753 // Ensure padding bits have the expected value.
48274754 if (dest_ty.isAbiInt(zcu)) {
4828 const dest_cty = try f.typeToCType(dest_ty, .complete);
4755 const dest_ctype = try f.ctypeFromType(dest_ty, .complete);
48294756 const dest_info = dest_ty.intInfo(zcu);
48304757 var bits: u16 = dest_info.bits;
4831 var wrap_cty: ?CType = null;
4758 var wrap_ctype: ?CType = null;
48324759 var need_bitcasts = false;
48334760
48344761 try f.writeCValue(writer, local, .Other);
4835 if (dest_cty.castTag(.array)) |pl| {
4836 try writer.print("[{d}]", .{switch (target.cpu.arch.endian()) {
4837 .little => pl.data.len - 1,
4838 .big => 0,
4839 }});
4840 const elem_cty = f.indexToCType(pl.data.elem_type);
4841 wrap_cty = elem_cty.toSignedness(dest_info.signedness);
4842 need_bitcasts = wrap_cty.?.tag() == .zig_i128;
4843 bits -= 1;
4844 bits %= @as(u16, @intCast(f.byteSize(elem_cty) * 8));
4845 bits += 1;
4762 switch (dest_ctype.info(ctype_pool)) {
4763 else => {},
4764 .array => |array_info| {
4765 try writer.print("[{d}]", .{switch (target.cpu.arch.endian()) {
4766 .little => array_info.len - 1,
4767 .big => 0,
4768 }});
4769 wrap_ctype = array_info.elem_ctype.toSignedness(dest_info.signedness);
4770 need_bitcasts = wrap_ctype.?.index == .zig_i128;
4771 bits -= 1;
4772 bits %= @as(u16, @intCast(f.byteSize(array_info.elem_ctype) * 8));
4773 bits += 1;
4774 },
48464775 }
48474776 try writer.writeAll(" = ");
48484777 if (need_bitcasts) {
48494778 try writer.writeAll("zig_bitCast_");
4850 try f.object.dg.renderCTypeForBuiltinFnName(writer, wrap_cty.?.toUnsigned());
4779 try f.object.dg.renderCTypeForBuiltinFnName(writer, wrap_ctype.?.toUnsigned());
48514780 try writer.writeByte('(');
48524781 }
48534782 try writer.writeAll("zig_wrap_");
48544783 const info_ty = try zcu.intType(dest_info.signedness, bits);
4855 if (wrap_cty) |cty|
4856 try f.object.dg.renderCTypeForBuiltinFnName(writer, cty)
4784 if (wrap_ctype) |ctype|
4785 try f.object.dg.renderCTypeForBuiltinFnName(writer, ctype)
48574786 else
48584787 try f.object.dg.renderTypeForBuiltinFnName(writer, info_ty);
48594788 try writer.writeByte('(');
48604789 if (need_bitcasts) {
48614790 try writer.writeAll("zig_bitCast_");
4862 try f.object.dg.renderCTypeForBuiltinFnName(writer, wrap_cty.?);
4791 try f.object.dg.renderCTypeForBuiltinFnName(writer, wrap_ctype.?);
48634792 try writer.writeByte('(');
48644793 }
48654794 try f.writeCValue(writer, local, .Other);
4866 if (dest_cty.castTag(.array)) |pl| {
4867 try writer.print("[{d}]", .{switch (target.cpu.arch.endian()) {
4868 .little => pl.data.len - 1,
4869 .big => 0,
4870 }});
4795 switch (dest_ctype.info(ctype_pool)) {
4796 else => {},
4797 .array => |array_info| try writer.print("[{d}]", .{
4798 switch (target.cpu.arch.endian()) {
4799 .little => array_info.len - 1,
4800 .big => 0,
4801 },
4802 }),
48714803 }
48724804 if (need_bitcasts) try writer.writeByte(')');
48734805 try f.object.dg.renderBuiltinInfo(writer, info_ty, .bits);
......@@ -5131,10 +5063,9 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
51315063 if (is_reg) {
51325064 const output_ty = if (output == .none) inst_ty else f.typeOf(output).childType(zcu);
51335065 try writer.writeAll("register ");
5134 const alignment: Alignment = .none;
5135 const local_value = try f.allocLocalValue(output_ty, alignment);
5066 const local_value = try f.allocLocal(inst, output_ty);
51365067 try f.allocs.put(gpa, local_value.new_local, false);
5137 try f.object.dg.renderTypeAndName(writer, output_ty, local_value, .{}, alignment, .complete);
5068 try f.object.dg.renderTypeAndName(writer, output_ty, local_value, .{}, .none, .complete);
51385069 try writer.writeAll(" __asm(\"");
51395070 try writer.writeAll(constraint["={".len .. constraint.len - "}".len]);
51405071 try writer.writeAll("\")");
......@@ -5164,10 +5095,9 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
51645095 if (asmInputNeedsLocal(f, constraint, input_val)) {
51655096 const input_ty = f.typeOf(input);
51665097 if (is_reg) try writer.writeAll("register ");
5167 const alignment: Alignment = .none;
5168 const local_value = try f.allocLocalValue(input_ty, alignment);
5098 const local_value = try f.allocLocal(inst, input_ty);
51695099 try f.allocs.put(gpa, local_value.new_local, false);
5170 try f.object.dg.renderTypeAndName(writer, input_ty, local_value, Const, alignment, .complete);
5100 try f.object.dg.renderTypeAndName(writer, input_ty, local_value, Const, .none, .complete);
51715101 if (is_reg) {
51725102 try writer.writeAll(" __asm(\"");
51735103 try writer.writeAll(constraint["{".len .. constraint.len - "}".len]);
......@@ -5512,59 +5442,74 @@ fn fieldLocation(
55125442 end: void,
55135443} {
55145444 const ip = &zcu.intern_pool;
5515 const container_ty = container_ptr_ty.childType(zcu);
5516 return switch (container_ty.zigTypeTag(zcu)) {
5517 .Struct => blk: {
5518 if (zcu.typeToPackedStruct(container_ty)) |struct_type| {
5519 if (field_ptr_ty.ptrInfo(zcu).packed_offset.host_size == 0)
5520 break :blk .{ .byte_offset = @divExact(zcu.structPackedFieldBitOffset(struct_type, field_index) + container_ptr_ty.ptrInfo(zcu).packed_offset.bit_offset, 8) }
5445 const container_ty = Type.fromInterned(ip.indexToKey(container_ptr_ty.toIntern()).ptr_type.child);
5446 switch (ip.indexToKey(container_ty.toIntern())) {
5447 .struct_type => {
5448 const loaded_struct = ip.loadStructType(container_ty.toIntern());
5449 switch (loaded_struct.layout) {
5450 .auto, .@"extern" => {
5451 var field_it = loaded_struct.iterateRuntimeOrder(ip);
5452 var before = true;
5453 while (field_it.next()) |next_field_index| {
5454 if (next_field_index == field_index) before = false;
5455 if (before) continue;
5456 const field_type = Type.fromInterned(loaded_struct.field_types.get(ip)[next_field_index]);
5457 if (!field_type.hasRuntimeBitsIgnoreComptime(zcu)) continue;
5458 return .{ .field = if (loaded_struct.fieldName(ip, next_field_index).unwrap()) |field_name|
5459 .{ .identifier = ip.stringToSlice(field_name) }
5460 else
5461 .{ .field = next_field_index } };
5462 }
5463 return if (container_ty.hasRuntimeBitsIgnoreComptime(zcu)) .end else .begin;
5464 },
5465 .@"packed" => return if (field_ptr_ty.ptrInfo(zcu).packed_offset.host_size == 0)
5466 .{ .byte_offset = @divExact(zcu.structPackedFieldBitOffset(loaded_struct, field_index) +
5467 container_ptr_ty.ptrInfo(zcu).packed_offset.bit_offset, 8) }
55215468 else
5522 break :blk .begin;
5469 .begin,
55235470 }
5524
5525 for (field_index..container_ty.structFieldCount(zcu)) |next_field_index_usize| {
5526 const next_field_index: u32 = @intCast(next_field_index_usize);
5527 if (container_ty.structFieldIsComptime(next_field_index, zcu)) continue;
5528 const field_ty = container_ty.structFieldType(next_field_index, zcu);
5529 if (!field_ty.hasRuntimeBitsIgnoreComptime(zcu)) continue;
5530
5531 break :blk .{ .field = if (container_ty.isSimpleTuple(zcu))
5532 .{ .field = next_field_index }
5471 },
5472 .anon_struct_type => |anon_struct_info| {
5473 for (field_index..anon_struct_info.types.len) |next_field_index| {
5474 if (anon_struct_info.values.get(ip)[next_field_index] != .none) continue;
5475 const field_type = Type.fromInterned(anon_struct_info.types.get(ip)[next_field_index]);
5476 if (!field_type.hasRuntimeBitsIgnoreComptime(zcu)) continue;
5477 return .{ .field = if (anon_struct_info.fieldName(ip, next_field_index).unwrap()) |field_name|
5478 .{ .identifier = ip.stringToSlice(field_name) }
55335479 else
5534 .{ .identifier = ip.stringToSlice(container_ty.legacyStructFieldName(next_field_index, zcu)) } };
5480 .{ .field = next_field_index } };
55355481 }
5536 break :blk if (container_ty.hasRuntimeBitsIgnoreComptime(zcu)) .end else .begin;
5482 return if (container_ty.hasRuntimeBitsIgnoreComptime(zcu)) .end else .begin;
55375483 },
5538 .Union => {
5539 const union_obj = zcu.typeToUnion(container_ty).?;
5540 return switch (union_obj.getLayout(ip)) {
5484 .union_type => {
5485 const loaded_union = ip.loadUnionType(container_ty.toIntern());
5486 switch (loaded_union.getLayout(ip)) {
55415487 .auto, .@"extern" => {
5542 const field_ty = Type.fromInterned(union_obj.field_types.get(ip)[field_index]);
5488 const field_ty = Type.fromInterned(loaded_union.field_types.get(ip)[field_index]);
55435489 if (!field_ty.hasRuntimeBitsIgnoreComptime(zcu))
5544 return if (container_ty.unionTagTypeSafety(zcu) != null and
5545 !container_ty.unionHasAllZeroBitFieldTypes(zcu))
5490 return if (loaded_union.hasTag(ip) and !container_ty.unionHasAllZeroBitFieldTypes(zcu))
55465491 .{ .field = .{ .identifier = "payload" } }
55475492 else
55485493 .begin;
5549 const field_name = union_obj.loadTagType(ip).names.get(ip)[field_index];
5550 return .{ .field = if (container_ty.unionTagTypeSafety(zcu)) |_|
5494 const field_name = loaded_union.loadTagType(ip).names.get(ip)[field_index];
5495 return .{ .field = if (loaded_union.hasTag(ip))
55515496 .{ .payload_identifier = ip.stringToSlice(field_name) }
55525497 else
55535498 .{ .identifier = ip.stringToSlice(field_name) } };
55545499 },
5555 .@"packed" => .begin,
5556 };
5500 .@"packed" => return .begin,
5501 }
55575502 },
5558 .Pointer => switch (container_ty.ptrSize(zcu)) {
5503 .ptr_type => |ptr_info| switch (ptr_info.flags.size) {
5504 .One, .Many, .C => unreachable,
55595505 .Slice => switch (field_index) {
5560 0 => .{ .field = .{ .identifier = "ptr" } },
5561 1 => .{ .field = .{ .identifier = "len" } },
5506 0 => return .{ .field = .{ .identifier = "ptr" } },
5507 1 => return .{ .field = .{ .identifier = "len" } },
55625508 else => unreachable,
55635509 },
5564 .One, .Many, .C => unreachable,
55655510 },
55665511 else => unreachable,
5567 };
5512 }
55685513}
55695514
55705515fn airStructFieldPtr(f: *Function, inst: Air.Inst.Index) !CValue {
......@@ -5653,7 +5598,7 @@ fn fieldPtr(
56535598 const field_ptr_ty = f.typeOfIndex(inst);
56545599
56555600 // Ensure complete type definition is visible before accessing fields.
5656 _ = try f.typeToIndex(container_ty, .complete);
5601 _ = try f.ctypeFromType(container_ty, .complete);
56575602
56585603 const writer = f.object.writer();
56595604 const local = try f.allocLocal(inst, field_ptr_ty);
......@@ -5708,109 +5653,109 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {
57085653 const writer = f.object.writer();
57095654
57105655 // Ensure complete type definition is visible before accessing fields.
5711 _ = try f.typeToIndex(struct_ty, .complete);
5656 _ = try f.ctypeFromType(struct_ty, .complete);
5657
5658 const field_name: CValue = switch (ip.indexToKey(struct_ty.toIntern())) {
5659 .struct_type => field_name: {
5660 const loaded_struct = ip.loadStructType(struct_ty.toIntern());
5661 switch (loaded_struct.layout) {
5662 .auto, .@"extern" => break :field_name if (loaded_struct.fieldName(ip, extra.field_index).unwrap()) |field_name|
5663 .{ .identifier = ip.stringToSlice(field_name) }
5664 else
5665 .{ .field = extra.field_index },
5666 .@"packed" => {
5667 const int_info = struct_ty.intInfo(zcu);
57125668
5713 const field_name: CValue = switch (zcu.intern_pool.indexToKey(struct_ty.toIntern())) {
5714 .struct_type => switch (struct_ty.containerLayout(zcu)) {
5715 .auto, .@"extern" => if (struct_ty.isSimpleTuple(zcu))
5716 .{ .field = extra.field_index }
5717 else
5718 .{ .identifier = ip.stringToSlice(struct_ty.legacyStructFieldName(extra.field_index, zcu)) },
5719 .@"packed" => {
5720 const struct_type = zcu.typeToStruct(struct_ty).?;
5721 const int_info = struct_ty.intInfo(zcu);
5669 const bit_offset_ty = try zcu.intType(.unsigned, Type.smallestUnsignedBits(int_info.bits - 1));
57225670
5723 const bit_offset_ty = try zcu.intType(.unsigned, Type.smallestUnsignedBits(int_info.bits - 1));
5671 const bit_offset = zcu.structPackedFieldBitOffset(loaded_struct, extra.field_index);
57245672
5725 const bit_offset = zcu.structPackedFieldBitOffset(struct_type, extra.field_index);
5673 const field_int_signedness = if (inst_ty.isAbiInt(zcu))
5674 inst_ty.intInfo(zcu).signedness
5675 else
5676 .unsigned;
5677 const field_int_ty = try zcu.intType(field_int_signedness, @as(u16, @intCast(inst_ty.bitSize(zcu))));
57265678
5727 const field_int_signedness = if (inst_ty.isAbiInt(zcu))
5728 inst_ty.intInfo(zcu).signedness
5729 else
5730 .unsigned;
5731 const field_int_ty = try zcu.intType(field_int_signedness, @as(u16, @intCast(inst_ty.bitSize(zcu))));
5732
5733 const temp_local = try f.allocLocal(inst, field_int_ty);
5734 try f.writeCValue(writer, temp_local, .Other);
5735 try writer.writeAll(" = zig_wrap_");
5736 try f.object.dg.renderTypeForBuiltinFnName(writer, field_int_ty);
5737 try writer.writeAll("((");
5738 try f.renderType(writer, field_int_ty);
5739 try writer.writeByte(')');
5740 const cant_cast = int_info.bits > 64;
5741 if (cant_cast) {
5742 if (field_int_ty.bitSize(zcu) > 64) return f.fail("TODO: C backend: implement casting between types > 64 bits", .{});
5743 try writer.writeAll("zig_lo_");
5744 try f.object.dg.renderTypeForBuiltinFnName(writer, struct_ty);
5745 try writer.writeByte('(');
5746 }
5747 if (bit_offset > 0) {
5748 try writer.writeAll("zig_shr_");
5749 try f.object.dg.renderTypeForBuiltinFnName(writer, struct_ty);
5750 try writer.writeByte('(');
5751 }
5752 try f.writeCValue(writer, struct_byval, .Other);
5753 if (bit_offset > 0) {
5754 try writer.writeAll(", ");
5755 try f.object.dg.renderValue(writer, try zcu.intValue(bit_offset_ty, bit_offset), .FunctionArgument);
5679 const temp_local = try f.allocLocal(inst, field_int_ty);
5680 try f.writeCValue(writer, temp_local, .Other);
5681 try writer.writeAll(" = zig_wrap_");
5682 try f.object.dg.renderTypeForBuiltinFnName(writer, field_int_ty);
5683 try writer.writeAll("((");
5684 try f.renderType(writer, field_int_ty);
57565685 try writer.writeByte(')');
5757 }
5758 if (cant_cast) try writer.writeByte(')');
5759 try f.object.dg.renderBuiltinInfo(writer, field_int_ty, .bits);
5760 try writer.writeAll(");\n");
5761 if (inst_ty.eql(field_int_ty, f.object.dg.zcu)) return temp_local;
5686 const cant_cast = int_info.bits > 64;
5687 if (cant_cast) {
5688 if (field_int_ty.bitSize(zcu) > 64) return f.fail("TODO: C backend: implement casting between types > 64 bits", .{});
5689 try writer.writeAll("zig_lo_");
5690 try f.object.dg.renderTypeForBuiltinFnName(writer, struct_ty);
5691 try writer.writeByte('(');
5692 }
5693 if (bit_offset > 0) {
5694 try writer.writeAll("zig_shr_");
5695 try f.object.dg.renderTypeForBuiltinFnName(writer, struct_ty);
5696 try writer.writeByte('(');
5697 }
5698 try f.writeCValue(writer, struct_byval, .Other);
5699 if (bit_offset > 0) try writer.print(", {})", .{
5700 try f.fmtIntLiteral(try zcu.intValue(bit_offset_ty, bit_offset)),
5701 });
5702 if (cant_cast) try writer.writeByte(')');
5703 try f.object.dg.renderBuiltinInfo(writer, field_int_ty, .bits);
5704 try writer.writeAll(");\n");
5705 if (inst_ty.eql(field_int_ty, f.object.dg.zcu)) return temp_local;
57625706
5763 const local = try f.allocLocal(inst, inst_ty);
5764 try writer.writeAll("memcpy(");
5765 try f.writeCValue(writer, .{ .local_ref = local.new_local }, .FunctionArgument);
5766 try writer.writeAll(", ");
5767 try f.writeCValue(writer, .{ .local_ref = temp_local.new_local }, .FunctionArgument);
5768 try writer.writeAll(", sizeof(");
5769 try f.renderType(writer, inst_ty);
5770 try writer.writeAll("));\n");
5771 try freeLocal(f, inst, temp_local.new_local, null);
5772 return local;
5773 },
5707 const local = try f.allocLocal(inst, inst_ty);
5708 try writer.writeAll("memcpy(");
5709 try f.writeCValue(writer, .{ .local_ref = local.new_local }, .FunctionArgument);
5710 try writer.writeAll(", ");
5711 try f.writeCValue(writer, .{ .local_ref = temp_local.new_local }, .FunctionArgument);
5712 try writer.writeAll(", sizeof(");
5713 try f.renderType(writer, inst_ty);
5714 try writer.writeAll("));\n");
5715 try freeLocal(f, inst, temp_local.new_local, null);
5716 return local;
5717 },
5718 }
57745719 },
5775
5776 .anon_struct_type => |anon_struct_type| if (anon_struct_type.names.len == 0)
5777 .{ .field = extra.field_index }
5720 .anon_struct_type => |anon_struct_info| if (anon_struct_info.fieldName(ip, extra.field_index).unwrap()) |field_name|
5721 .{ .identifier = ip.stringToSlice(field_name) }
57785722 else
5779 .{ .identifier = ip.stringToSlice(struct_ty.legacyStructFieldName(extra.field_index, zcu)) },
5780
5723 .{ .field = extra.field_index },
57815724 .union_type => field_name: {
5782 const union_obj = ip.loadUnionType(struct_ty.toIntern());
5783 if (union_obj.flagsPtr(ip).layout == .@"packed") {
5784 const operand_lval = if (struct_byval == .constant) blk: {
5785 const operand_local = try f.allocLocal(inst, struct_ty);
5786 try f.writeCValue(writer, operand_local, .Other);
5787 try writer.writeAll(" = ");
5788 try f.writeCValue(writer, struct_byval, .Initializer);
5789 try writer.writeAll(";\n");
5790 break :blk operand_local;
5791 } else struct_byval;
5792
5793 const local = try f.allocLocal(inst, inst_ty);
5794 try writer.writeAll("memcpy(&");
5795 try f.writeCValue(writer, local, .Other);
5796 try writer.writeAll(", &");
5797 try f.writeCValue(writer, operand_lval, .Other);
5798 try writer.writeAll(", sizeof(");
5799 try f.renderType(writer, inst_ty);
5800 try writer.writeAll("));\n");
5801
5802 if (struct_byval == .constant) {
5803 try freeLocal(f, inst, operand_lval.new_local, null);
5804 }
5725 const loaded_union = ip.loadUnionType(struct_ty.toIntern());
5726 switch (loaded_union.getLayout(ip)) {
5727 .auto, .@"extern" => {
5728 const name = loaded_union.loadTagType(ip).names.get(ip)[extra.field_index];
5729 break :field_name if (loaded_union.hasTag(ip))
5730 .{ .payload_identifier = ip.stringToSlice(name) }
5731 else
5732 .{ .identifier = ip.stringToSlice(name) };
5733 },
5734 .@"packed" => {
5735 const operand_lval = if (struct_byval == .constant) blk: {
5736 const operand_local = try f.allocLocal(inst, struct_ty);
5737 try f.writeCValue(writer, operand_local, .Other);
5738 try writer.writeAll(" = ");
5739 try f.writeCValue(writer, struct_byval, .Initializer);
5740 try writer.writeAll(";\n");
5741 break :blk operand_local;
5742 } else struct_byval;
5743
5744 const local = try f.allocLocal(inst, inst_ty);
5745 try writer.writeAll("memcpy(&");
5746 try f.writeCValue(writer, local, .Other);
5747 try writer.writeAll(", &");
5748 try f.writeCValue(writer, operand_lval, .Other);
5749 try writer.writeAll(", sizeof(");
5750 try f.renderType(writer, inst_ty);
5751 try writer.writeAll("));\n");
5752
5753 if (struct_byval == .constant) {
5754 try freeLocal(f, inst, operand_lval.new_local, null);
5755 }
58055756
5806 return local;
5807 } else {
5808 const name = union_obj.loadTagType(ip).names.get(ip)[extra.field_index];
5809 break :field_name if (union_obj.hasTag(ip)) .{
5810 .payload_identifier = ip.stringToSlice(name),
5811 } else .{
5812 .identifier = ip.stringToSlice(name),
5813 };
5757 return local;
5758 },
58145759 }
58155760 },
58165761 else => unreachable,
......@@ -6089,6 +6034,7 @@ fn airIsErr(f: *Function, inst: Air.Inst.Index, is_ptr: bool, operator: []const
60896034
60906035fn airArrayToSlice(f: *Function, inst: Air.Inst.Index) !CValue {
60916036 const zcu = f.object.dg.zcu;
6037 const ctype_pool = &f.object.dg.ctype_pool;
60926038 const ty_op = f.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
60936039
60946040 const operand = try f.resolveInst(ty_op.operand);
......@@ -6107,18 +6053,18 @@ fn airArrayToSlice(f: *Function, inst: Air.Inst.Index) !CValue {
61076053 if (operand == .undef) {
61086054 try f.writeCValue(writer, .{ .undef = inst_ty.slicePtrFieldType(zcu) }, .Initializer);
61096055 } else {
6110 const ptr_cty = try f.typeToIndex(ptr_ty, .complete);
6111 const ptr_child_cty = f.indexToCType(ptr_cty).cast(CType.Payload.Child).?.data;
6056 const ptr_ctype = try f.ctypeFromType(ptr_ty, .complete);
6057 const ptr_child_ctype = ptr_ctype.info(ctype_pool).pointer.elem_ctype;
61126058 const elem_ty = array_ty.childType(zcu);
6113 const elem_cty = try f.typeToIndex(elem_ty, .complete);
6114 if (ptr_child_cty != elem_cty) {
6059 const elem_ctype = try f.ctypeFromType(elem_ty, .complete);
6060 if (!ptr_child_ctype.eql(elem_ctype)) {
61156061 try writer.writeByte('(');
6116 try f.renderCType(writer, ptr_cty);
6062 try f.renderCType(writer, ptr_ctype);
61176063 try writer.writeByte(')');
61186064 }
6119 const operand_cty = try f.typeToCType(operand_ty, .complete);
6120 const operand_child_cty = operand_cty.cast(CType.Payload.Child).?.data;
6121 if (f.indexToCType(operand_child_cty).tag() == .array) {
6065 const operand_ctype = try f.ctypeFromType(operand_ty, .complete);
6066 const operand_child_ctype = operand_ctype.info(ctype_pool).pointer.elem_ctype;
6067 if (operand_child_ctype.info(ctype_pool) == .array) {
61226068 try writer.writeByte('&');
61236069 try f.writeCValueDeref(writer, operand);
61246070 try writer.print("[{}]", .{try f.fmtIntLiteral(try zcu.intValue(Type.usize, 0))});
......@@ -6229,8 +6175,8 @@ fn airUnBuiltinCall(
62296175 const operand_ty = f.typeOf(ty_op.operand);
62306176 const scalar_ty = operand_ty.scalarType(zcu);
62316177
6232 const inst_scalar_cty = try f.typeToCType(inst_scalar_ty, .complete);
6233 const ref_ret = inst_scalar_cty.tag() == .array;
6178 const inst_scalar_ctype = try f.ctypeFromType(inst_scalar_ty, .complete);
6179 const ref_ret = inst_scalar_ctype.info(&f.object.dg.ctype_pool) == .array;
62346180
62356181 const writer = f.object.writer();
62366182 const local = try f.allocLocal(inst, inst_ty);
......@@ -6267,8 +6213,8 @@ fn airBinBuiltinCall(
62676213 const bin_op = f.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
62686214
62696215 const operand_ty = f.typeOf(bin_op.lhs);
6270 const operand_cty = try f.typeToCType(operand_ty, .complete);
6271 const is_big = operand_cty.tag() == .array;
6216 const operand_ctype = try f.ctypeFromType(operand_ty, .complete);
6217 const is_big = operand_ctype.info(&f.object.dg.ctype_pool) == .array;
62726218
62736219 const lhs = try f.resolveInst(bin_op.lhs);
62746220 const rhs = try f.resolveInst(bin_op.rhs);
......@@ -6278,8 +6224,8 @@ fn airBinBuiltinCall(
62786224 const inst_scalar_ty = inst_ty.scalarType(zcu);
62796225 const scalar_ty = operand_ty.scalarType(zcu);
62806226
6281 const inst_scalar_cty = try f.typeToCType(inst_scalar_ty, .complete);
6282 const ref_ret = inst_scalar_cty.tag() == .array;
6227 const inst_scalar_ctype = try f.ctypeFromType(inst_scalar_ty, .complete);
6228 const ref_ret = inst_scalar_ctype.info(&f.object.dg.ctype_pool) == .array;
62836229
62846230 const writer = f.object.writer();
62856231 const local = try f.allocLocal(inst, inst_ty);
......@@ -6328,8 +6274,8 @@ fn airCmpBuiltinCall(
63286274 const operand_ty = f.typeOf(data.lhs);
63296275 const scalar_ty = operand_ty.scalarType(zcu);
63306276
6331 const inst_scalar_cty = try f.typeToCType(inst_scalar_ty, .complete);
6332 const ref_ret = inst_scalar_cty.tag() == .array;
6277 const inst_scalar_ctype = try f.ctypeFromType(inst_scalar_ty, .complete);
6278 const ref_ret = inst_scalar_ctype.info(&f.object.dg.ctype_pool) == .array;
63336279
63346280 const writer = f.object.writer();
63356281 const local = try f.allocLocal(inst, inst_ty);
......@@ -7112,9 +7058,9 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {
71127058
71137059 const writer = f.object.writer();
71147060 const local = try f.allocLocal(inst, inst_ty);
7115 switch (inst_ty.zigTypeTag(zcu)) {
7116 .Array, .Vector => {
7117 const a = try Assignment.init(f, inst_ty.childType(zcu));
7061 switch (ip.indexToKey(inst_ty.toIntern())) {
7062 inline .array_type, .vector_type => |info, tag| {
7063 const a = try Assignment.init(f, Type.fromInterned(info.child));
71187064 for (resolved_elements, 0..) |element, i| {
71197065 try a.restart(f, writer);
71207066 try f.writeCValue(writer, local, .Other);
......@@ -7123,94 +7069,112 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {
71237069 try f.writeCValue(writer, element, .Other);
71247070 try a.end(f, writer);
71257071 }
7126 if (inst_ty.sentinel(zcu)) |sentinel| {
7072 if (tag == .array_type and info.sentinel != .none) {
71277073 try a.restart(f, writer);
71287074 try f.writeCValue(writer, local, .Other);
7129 try writer.print("[{d}]", .{resolved_elements.len});
7075 try writer.print("[{d}]", .{info.len});
71307076 try a.assign(f, writer);
7131 try f.object.dg.renderValue(writer, sentinel, .Other);
7077 try f.object.dg.renderValue(writer, Value.fromInterned(info.sentinel), .Other);
71327078 try a.end(f, writer);
71337079 }
71347080 },
7135 .Struct => switch (inst_ty.containerLayout(zcu)) {
7136 .auto, .@"extern" => for (resolved_elements, 0..) |element, field_index| {
7137 if (inst_ty.structFieldIsComptime(field_index, zcu)) continue;
7138 const field_ty = inst_ty.structFieldType(field_index, zcu);
7139 if (!field_ty.hasRuntimeBitsIgnoreComptime(zcu)) continue;
7140
7141 const a = try Assignment.start(f, writer, field_ty);
7142 try f.writeCValueMember(writer, local, if (inst_ty.isSimpleTuple(zcu))
7143 .{ .field = field_index }
7144 else
7145 .{ .identifier = ip.stringToSlice(inst_ty.legacyStructFieldName(@intCast(field_index), zcu)) });
7146 try a.assign(f, writer);
7147 try f.writeCValue(writer, element, .Other);
7148 try a.end(f, writer);
7149 },
7150 .@"packed" => {
7151 try f.writeCValue(writer, local, .Other);
7152 try writer.writeAll(" = ");
7153 const int_info = inst_ty.intInfo(zcu);
7081 .struct_type => {
7082 const loaded_struct = ip.loadStructType(inst_ty.toIntern());
7083 switch (loaded_struct.layout) {
7084 .auto, .@"extern" => {
7085 var field_it = loaded_struct.iterateRuntimeOrder(ip);
7086 while (field_it.next()) |field_index| {
7087 const field_ty = Type.fromInterned(loaded_struct.field_types.get(ip)[field_index]);
7088 if (!field_ty.hasRuntimeBitsIgnoreComptime(zcu)) continue;
71547089
7155 const bit_offset_ty = try zcu.intType(.unsigned, Type.smallestUnsignedBits(int_info.bits - 1));
7090 const a = try Assignment.start(f, writer, field_ty);
7091 try f.writeCValueMember(writer, local, if (loaded_struct.fieldName(ip, field_index).unwrap()) |field_name|
7092 .{ .identifier = ip.stringToSlice(field_name) }
7093 else
7094 .{ .field = field_index });
7095 try a.assign(f, writer);
7096 try f.writeCValue(writer, resolved_elements[field_index], .Other);
7097 try a.end(f, writer);
7098 }
7099 },
7100 .@"packed" => {
7101 try f.writeCValue(writer, local, .Other);
7102 try writer.writeAll(" = ");
7103 const int_info = inst_ty.intInfo(zcu);
71567104
7157 var bit_offset: u64 = 0;
7105 const bit_offset_ty = try zcu.intType(.unsigned, Type.smallestUnsignedBits(int_info.bits - 1));
71587106
7159 var empty = true;
7160 for (0..elements.len) |field_index| {
7161 if (inst_ty.structFieldIsComptime(field_index, zcu)) continue;
7162 const field_ty = inst_ty.structFieldType(field_index, zcu);
7163 if (!field_ty.hasRuntimeBitsIgnoreComptime(zcu)) continue;
7107 var bit_offset: u64 = 0;
71647108
7165 if (!empty) {
7166 try writer.writeAll("zig_or_");
7167 try f.object.dg.renderTypeForBuiltinFnName(writer, inst_ty);
7168 try writer.writeByte('(');
7109 var empty = true;
7110 for (0..elements.len) |field_index| {
7111 if (inst_ty.structFieldIsComptime(field_index, zcu)) continue;
7112 const field_ty = inst_ty.structFieldType(field_index, zcu);
7113 if (!field_ty.hasRuntimeBitsIgnoreComptime(zcu)) continue;
7114
7115 if (!empty) {
7116 try writer.writeAll("zig_or_");
7117 try f.object.dg.renderTypeForBuiltinFnName(writer, inst_ty);
7118 try writer.writeByte('(');
7119 }
7120 empty = false;
71697121 }
7170 empty = false;
7171 }
7172 empty = true;
7173 for (resolved_elements, 0..) |element, field_index| {
7174 if (inst_ty.structFieldIsComptime(field_index, zcu)) continue;
7175 const field_ty = inst_ty.structFieldType(field_index, zcu);
7176 if (!field_ty.hasRuntimeBitsIgnoreComptime(zcu)) continue;
7177
7178 if (!empty) try writer.writeAll(", ");
7179 // TODO: Skip this entire shift if val is 0?
7180 try writer.writeAll("zig_shlw_");
7181 try f.object.dg.renderTypeForBuiltinFnName(writer, inst_ty);
7182 try writer.writeByte('(');
7122 empty = true;
7123 for (resolved_elements, 0..) |element, field_index| {
7124 if (inst_ty.structFieldIsComptime(field_index, zcu)) continue;
7125 const field_ty = inst_ty.structFieldType(field_index, zcu);
7126 if (!field_ty.hasRuntimeBitsIgnoreComptime(zcu)) continue;
71837127
7184 if (inst_ty.isAbiInt(zcu) and (field_ty.isAbiInt(zcu) or field_ty.isPtrAtRuntime(zcu))) {
7185 try f.renderIntCast(writer, inst_ty, element, .{}, field_ty, .FunctionArgument);
7186 } else {
7128 if (!empty) try writer.writeAll(", ");
7129 // TODO: Skip this entire shift if val is 0?
7130 try writer.writeAll("zig_shlw_");
7131 try f.object.dg.renderTypeForBuiltinFnName(writer, inst_ty);
71877132 try writer.writeByte('(');
7188 try f.renderType(writer, inst_ty);
7189 try writer.writeByte(')');
7190 if (field_ty.isPtrAtRuntime(zcu)) {
7133
7134 if (inst_ty.isAbiInt(zcu) and (field_ty.isAbiInt(zcu) or field_ty.isPtrAtRuntime(zcu))) {
7135 try f.renderIntCast(writer, inst_ty, element, .{}, field_ty, .FunctionArgument);
7136 } else {
71917137 try writer.writeByte('(');
7192 try f.renderType(writer, switch (int_info.signedness) {
7193 .unsigned => Type.usize,
7194 .signed => Type.isize,
7195 });
7138 try f.renderType(writer, inst_ty);
71967139 try writer.writeByte(')');
7140 if (field_ty.isPtrAtRuntime(zcu)) {
7141 try writer.writeByte('(');
7142 try f.renderType(writer, switch (int_info.signedness) {
7143 .unsigned => Type.usize,
7144 .signed => Type.isize,
7145 });
7146 try writer.writeByte(')');
7147 }
7148 try f.writeCValue(writer, element, .Other);
71977149 }
7198 try f.writeCValue(writer, element, .Other);
7199 }
7200
7201 try writer.print(", {}", .{
7202 try f.fmtIntLiteral(try zcu.intValue(bit_offset_ty, bit_offset)),
7203 });
7204 try f.object.dg.renderBuiltinInfo(writer, inst_ty, .bits);
7205 try writer.writeByte(')');
7206 if (!empty) try writer.writeByte(')');
72077150
7208 bit_offset += field_ty.bitSize(zcu);
7209 empty = false;
7210 }
7151 try writer.print(", {}", .{
7152 try f.fmtIntLiteral(try zcu.intValue(bit_offset_ty, bit_offset)),
7153 });
7154 try f.object.dg.renderBuiltinInfo(writer, inst_ty, .bits);
7155 try writer.writeByte(')');
7156 if (!empty) try writer.writeByte(')');
72117157
7212 try writer.writeAll(";\n");
7213 },
7158 bit_offset += field_ty.bitSize(zcu);
7159 empty = false;
7160 }
7161 try writer.writeAll(";\n");
7162 },
7163 }
7164 },
7165 .anon_struct_type => |anon_struct_info| for (0..anon_struct_info.types.len) |field_index| {
7166 if (anon_struct_info.values.get(ip)[field_index] != .none) continue;
7167 const field_ty = Type.fromInterned(anon_struct_info.types.get(ip)[field_index]);
7168 if (!field_ty.hasRuntimeBitsIgnoreComptime(zcu)) continue;
7169
7170 const a = try Assignment.start(f, writer, field_ty);
7171 try f.writeCValueMember(writer, local, if (anon_struct_info.fieldName(ip, field_index).unwrap()) |field_name|
7172 .{ .identifier = ip.stringToSlice(field_name) }
7173 else
7174 .{ .field = field_index });
7175 try a.assign(f, writer);
7176 try f.writeCValue(writer, resolved_elements[field_index], .Other);
7177 try a.end(f, writer);
72147178 },
72157179 else => unreachable,
72167180 }
......@@ -7225,15 +7189,15 @@ fn airUnionInit(f: *Function, inst: Air.Inst.Index) !CValue {
72257189 const extra = f.air.extraData(Air.UnionInit, ty_pl.payload).data;
72267190
72277191 const union_ty = f.typeOfIndex(inst);
7228 const union_obj = zcu.typeToUnion(union_ty).?;
7229 const field_name = union_obj.loadTagType(ip).names.get(ip)[extra.field_index];
7192 const loaded_union = ip.loadUnionType(union_ty.toIntern());
7193 const field_name = loaded_union.loadTagType(ip).names.get(ip)[extra.field_index];
72307194 const payload_ty = f.typeOf(extra.init);
72317195 const payload = try f.resolveInst(extra.init);
72327196 try reap(f, inst, &.{extra.init});
72337197
72347198 const writer = f.object.writer();
72357199 const local = try f.allocLocal(inst, union_ty);
7236 if (union_obj.getLayout(ip) == .@"packed") {
7200 if (loaded_union.getLayout(ip) == .@"packed") {
72377201 try f.writeCValue(writer, local, .Other);
72387202 try writer.writeAll(" = ");
72397203 try f.writeCValue(writer, payload, .Initializer);
......@@ -7465,16 +7429,16 @@ fn airCVaStart(f: *Function, inst: Air.Inst.Index) !CValue {
74657429 const inst_ty = f.typeOfIndex(inst);
74667430 const decl_index = f.object.dg.pass.decl;
74677431 const decl = zcu.declPtr(decl_index);
7468 const fn_cty = try f.typeToCType(decl.typeOf(zcu), .complete);
7469 const param_len = fn_cty.castTag(.varargs_function).?.data.param_types.len;
7432 const function_ctype = try f.ctypeFromType(decl.typeOf(zcu), .complete);
7433 const params_len = function_ctype.info(&f.object.dg.ctype_pool).function.param_ctypes.len;
74707434
74717435 const writer = f.object.writer();
74727436 const local = try f.allocLocal(inst, inst_ty);
74737437 try writer.writeAll("va_start(*(va_list *)&");
74747438 try f.writeCValue(writer, local, .Other);
7475 if (param_len > 0) {
7439 if (params_len > 0) {
74767440 try writer.writeAll(", ");
7477 try f.writeCValue(writer, .{ .arg = param_len - 1 }, .FunctionArgument);
7441 try f.writeCValue(writer, .{ .arg = params_len - 1 }, .FunctionArgument);
74787442 }
74797443 try writer.writeAll(");\n");
74807444 return local;
......@@ -7823,7 +7787,7 @@ const FormatIntLiteralContext = struct {
78237787 dg: *DeclGen,
78247788 int_info: InternPool.Key.IntType,
78257789 kind: CType.Kind,
7826 cty: CType,
7790 ctype: CType,
78277791 val: Value,
78287792};
78297793fn formatIntLiteral(
......@@ -7834,6 +7798,7 @@ fn formatIntLiteral(
78347798) @TypeOf(writer).Error!void {
78357799 const zcu = data.dg.zcu;
78367800 const target = &data.dg.mod.resolved_target.result;
7801 const ctype_pool = &data.dg.ctype_pool;
78377802
78387803 const ExpectedContents = struct {
78397804 const base = 10;
......@@ -7867,7 +7832,7 @@ fn formatIntLiteral(
78677832 } else data.val.toBigInt(&int_buf, zcu);
78687833 assert(int.fitsInTwosComp(data.int_info.signedness, data.int_info.bits));
78697834
7870 const c_bits: usize = @intCast(data.cty.byteSize(data.dg.ctypes.set, data.dg.mod) * 8);
7835 const c_bits: usize = @intCast(data.ctype.byteSize(ctype_pool, data.dg.mod) * 8);
78717836 var one_limbs: [BigInt.calcLimbLen(1)]BigIntLimb = undefined;
78727837 const one = BigInt.Mutable.init(&one_limbs, 1).toConst();
78737838
......@@ -7879,45 +7844,45 @@ fn formatIntLiteral(
78797844 defer allocator.free(wrap.limbs);
78807845
78817846 const c_limb_info: struct {
7882 cty: CType,
7847 ctype: CType,
78837848 count: usize,
78847849 endian: std.builtin.Endian,
78857850 homogeneous: bool,
7886 } = switch (data.cty.tag()) {
7887 else => .{
7888 .cty = CType.initTag(.void),
7889 .count = 1,
7890 .endian = .little,
7891 .homogeneous = true,
7892 },
7893 .zig_u128, .zig_i128 => .{
7894 .cty = CType.initTag(.uint64_t),
7895 .count = 2,
7896 .endian = .big,
7897 .homogeneous = false,
7898 },
7899 .array => info: {
7900 const array_data = data.cty.castTag(.array).?.data;
7901 break :info .{
7902 .cty = data.dg.indexToCType(array_data.elem_type),
7903 .count = @as(usize, @intCast(array_data.len)),
7904 .endian = target.cpu.arch.endian(),
7851 } = switch (data.ctype.info(ctype_pool)) {
7852 .basic => |basic_info| switch (basic_info) {
7853 else => .{
7854 .ctype = .{ .index = .void },
7855 .count = 1,
7856 .endian = .little,
79057857 .homogeneous = true,
7906 };
7858 },
7859 .zig_u128, .zig_i128 => .{
7860 .ctype = .{ .index = .uint64_t },
7861 .count = 2,
7862 .endian = .big,
7863 .homogeneous = false,
7864 },
7865 },
7866 .array => |array_info| .{
7867 .ctype = array_info.elem_ctype,
7868 .count = @intCast(array_info.len),
7869 .endian = target.cpu.arch.endian(),
7870 .homogeneous = true,
79077871 },
7872 else => unreachable,
79087873 };
79097874 if (c_limb_info.count == 1) {
79107875 if (wrap.addWrap(int, one, data.int_info.signedness, c_bits) or
79117876 data.int_info.signedness == .signed and wrap.subWrap(int, one, data.int_info.signedness, c_bits))
79127877 return writer.print("{s}_{s}", .{
7913 data.cty.getStandardDefineAbbrev() orelse return writer.print("zig_{s}Int_{c}{d}", .{
7878 data.ctype.getStandardDefineAbbrev() orelse return writer.print("zig_{s}Int_{c}{d}", .{
79147879 if (int.positive) "max" else "min", signAbbrev(data.int_info.signedness), c_bits,
79157880 }),
79167881 if (int.positive) "MAX" else "MIN",
79177882 });
79187883
79197884 if (!int.positive) try writer.writeByte('-');
7920 try data.cty.renderLiteralPrefix(writer, data.kind);
7885 try data.ctype.renderLiteralPrefix(writer, data.kind, ctype_pool);
79217886
79227887 const style: struct { base: u8, case: std.fmt.Case = undefined } = switch (fmt.len) {
79237888 0 => .{ .base = 10 },
......@@ -7948,7 +7913,7 @@ fn formatIntLiteral(
79487913 defer allocator.free(string);
79497914 try writer.writeAll(string);
79507915 } else {
7951 try data.cty.renderLiteralPrefix(writer, data.kind);
7916 try data.ctype.renderLiteralPrefix(writer, data.kind, ctype_pool);
79527917 wrap.convertToTwosComplement(int, data.int_info.signedness, c_bits);
79537918 @memset(wrap.limbs[wrap.len..], 0);
79547919 wrap.len = wrap.limbs.len;
......@@ -7958,7 +7923,7 @@ fn formatIntLiteral(
79587923 .signedness = undefined,
79597924 .bits = @as(u16, @intCast(@divExact(c_bits, c_limb_info.count))),
79607925 };
7961 var c_limb_cty: CType = undefined;
7926 var c_limb_ctype: CType = undefined;
79627927
79637928 var limb_offset: usize = 0;
79647929 const most_significant_limb_i = wrap.len - limbs_per_c_limb;
......@@ -7979,7 +7944,7 @@ fn formatIntLiteral(
79797944 {
79807945 // most significant limb is actually signed
79817946 c_limb_int_info.signedness = .signed;
7982 c_limb_cty = c_limb_info.cty.toSigned();
7947 c_limb_ctype = c_limb_info.ctype.toSigned();
79837948
79847949 c_limb_mut.positive = wrap.positive;
79857950 c_limb_mut.truncate(
......@@ -7989,7 +7954,7 @@ fn formatIntLiteral(
79897954 );
79907955 } else {
79917956 c_limb_int_info.signedness = .unsigned;
7992 c_limb_cty = c_limb_info.cty;
7957 c_limb_ctype = c_limb_info.ctype;
79937958 }
79947959
79957960 if (limb_offset > 0) try writer.writeAll(", ");
......@@ -7997,12 +7962,12 @@ fn formatIntLiteral(
79977962 .dg = data.dg,
79987963 .int_info = c_limb_int_info,
79997964 .kind = data.kind,
8000 .cty = c_limb_cty,
7965 .ctype = c_limb_ctype,
80017966 .val = try zcu.intValue_big(Type.comptime_int, c_limb_mut.toConst()),
80027967 }, fmt, options, writer);
80037968 }
80047969 }
8005 try data.cty.renderLiteralSuffix(writer);
7970 try data.ctype.renderLiteralSuffix(writer, ctype_pool);
80067971}
80077972
80087973const Materialize = struct {
......@@ -8045,10 +8010,10 @@ const Materialize = struct {
80458010};
80468011
80478012const Assignment = struct {
8048 cty: CType.Index,
8013 ctype: CType,
80498014
80508015 pub fn init(f: *Function, ty: Type) !Assignment {
8051 return .{ .cty = try f.typeToIndex(ty, .complete) };
8016 return .{ .ctype = try f.ctypeFromType(ty, .complete) };
80528017 }
80538018
80548019 pub fn start(f: *Function, writer: anytype, ty: Type) !Assignment {
......@@ -8076,7 +8041,7 @@ const Assignment = struct {
80768041 .assign => {},
80778042 .memcpy => {
80788043 try writer.writeAll(", sizeof(");
8079 try f.renderCType(writer, self.cty);
8044 try f.renderCType(writer, self.ctype);
80808045 try writer.writeAll("))");
80818046 },
80828047 }
......@@ -8084,7 +8049,7 @@ const Assignment = struct {
80848049 }
80858050
80868051 fn strategy(self: Assignment, f: *Function) enum { assign, memcpy } {
8087 return switch (f.indexToCType(self.cty).tag()) {
8052 return switch (self.ctype.info(&f.object.dg.ctype_pool)) {
80888053 else => .assign,
80898054 .array, .vector => .memcpy,
80908055 };
......@@ -8129,28 +8094,6 @@ const Vectorize = struct {
81298094 }
81308095};
81318096
8132fn lowerFnRetTy(ret_ty: Type, zcu: *Zcu) !Type {
8133 if (ret_ty.toIntern() == .noreturn_type) return Type.noreturn;
8134
8135 if (lowersToArray(ret_ty, zcu)) {
8136 const gpa = zcu.gpa;
8137 const ip = &zcu.intern_pool;
8138 const names = [1]InternPool.NullTerminatedString{
8139 try ip.getOrPutString(gpa, "array"),
8140 };
8141 const types = [1]InternPool.Index{ret_ty.toIntern()};
8142 const values = [1]InternPool.Index{.none};
8143 const interned = try ip.getAnonStructType(gpa, .{
8144 .names = &names,
8145 .types = &types,
8146 .values = &values,
8147 });
8148 return Type.fromInterned(interned);
8149 }
8150
8151 return if (ret_ty.hasRuntimeBitsIgnoreComptime(zcu)) ret_ty else Type.void;
8152}
8153
81548097fn lowersToArray(ty: Type, zcu: *Zcu) bool {
81558098 return switch (ty.zigTypeTag(zcu)) {
81568099 .Array, .Vector => return true,
src/codegen/c/Type.zig created+2472
......@@ -0,0 +1,2472 @@
1index: CType.Index,
2
3pub fn fromPoolIndex(pool_index: usize) CType {
4 return .{ .index = @enumFromInt(CType.Index.first_pool_index + pool_index) };
5}
6
7pub fn toPoolIndex(ctype: CType) ?u32 {
8 const pool_index, const is_basic =
9 @subWithOverflow(@intFromEnum(ctype.index), CType.Index.first_pool_index);
10 return switch (is_basic) {
11 0 => pool_index,
12 1 => null,
13 };
14}
15
16pub fn eql(lhs: CType, rhs: CType) bool {
17 return lhs.index == rhs.index;
18}
19
20pub fn isBool(ctype: CType) bool {
21 return switch (ctype.index) {
22 ._Bool, .bool => true,
23 else => false,
24 };
25}
26
27pub fn isInteger(ctype: CType) bool {
28 return switch (ctype.index) {
29 .char,
30 .@"signed char",
31 .short,
32 .int,
33 .long,
34 .@"long long",
35 .@"unsigned char",
36 .@"unsigned short",
37 .@"unsigned int",
38 .@"unsigned long",
39 .@"unsigned long long",
40 .size_t,
41 .ptrdiff_t,
42 .uint8_t,
43 .int8_t,
44 .uint16_t,
45 .int16_t,
46 .uint32_t,
47 .int32_t,
48 .uint64_t,
49 .int64_t,
50 .uintptr_t,
51 .intptr_t,
52 .zig_u128,
53 .zig_i128,
54 => true,
55 else => false,
56 };
57}
58
59pub fn signedness(ctype: CType, mod: *Module) std.builtin.Signedness {
60 return switch (ctype.index) {
61 .char => mod.resolved_target.result.charSignedness(),
62 .@"signed char",
63 .short,
64 .int,
65 .long,
66 .@"long long",
67 .ptrdiff_t,
68 .int8_t,
69 .int16_t,
70 .int32_t,
71 .int64_t,
72 .intptr_t,
73 .zig_i128,
74 => .signed,
75 .@"unsigned char",
76 .@"unsigned short",
77 .@"unsigned int",
78 .@"unsigned long",
79 .@"unsigned long long",
80 .size_t,
81 .uint8_t,
82 .uint16_t,
83 .uint32_t,
84 .uint64_t,
85 .uintptr_t,
86 .zig_u128,
87 => .unsigned,
88 else => unreachable,
89 };
90}
91
92pub fn isFloat(ctype: CType) bool {
93 return switch (ctype.index) {
94 .float,
95 .double,
96 .@"long double",
97 .zig_f16,
98 .zig_f32,
99 .zig_f64,
100 .zig_f80,
101 .zig_f128,
102 .zig_c_longdouble,
103 => true,
104 else => false,
105 };
106}
107
108pub fn toSigned(ctype: CType) CType {
109 return switch (ctype.index) {
110 .char, .@"signed char", .@"unsigned char" => .{ .index = .@"signed char" },
111 .short, .@"unsigned short" => .{ .index = .short },
112 .int, .@"unsigned int" => .{ .index = .int },
113 .long, .@"unsigned long" => .{ .index = .long },
114 .@"long long", .@"unsigned long long" => .{ .index = .@"long long" },
115 .size_t, .ptrdiff_t => .{ .index = .ptrdiff_t },
116 .uint8_t, .int8_t => .{ .index = .int8_t },
117 .uint16_t, .int16_t => .{ .index = .int16_t },
118 .uint32_t, .int32_t => .{ .index = .int32_t },
119 .uint64_t, .int64_t => .{ .index = .int64_t },
120 .uintptr_t, .intptr_t => .{ .index = .intptr_t },
121 .zig_u128, .zig_i128 => .{ .index = .zig_i128 },
122 .float,
123 .double,
124 .@"long double",
125 .zig_f16,
126 .zig_f32,
127 .zig_f80,
128 .zig_f128,
129 .zig_c_longdouble,
130 => ctype,
131 else => unreachable,
132 };
133}
134
135pub fn toUnsigned(ctype: CType) CType {
136 return switch (ctype.index) {
137 .char, .@"signed char", .@"unsigned char" => .{ .index = .@"unsigned char" },
138 .short, .@"unsigned short" => .{ .index = .@"unsigned short" },
139 .int, .@"unsigned int" => .{ .index = .@"unsigned int" },
140 .long, .@"unsigned long" => .{ .index = .@"unsigned long" },
141 .@"long long", .@"unsigned long long" => .{ .index = .@"unsigned long long" },
142 .size_t, .ptrdiff_t => .{ .index = .size_t },
143 .uint8_t, .int8_t => .{ .index = .uint8_t },
144 .uint16_t, .int16_t => .{ .index = .uint16_t },
145 .uint32_t, .int32_t => .{ .index = .uint32_t },
146 .uint64_t, .int64_t => .{ .index = .uint64_t },
147 .uintptr_t, .intptr_t => .{ .index = .uintptr_t },
148 .zig_u128, .zig_i128 => .{ .index = .zig_u128 },
149 else => unreachable,
150 };
151}
152
153pub fn toSignedness(ctype: CType, s: std.builtin.Signedness) CType {
154 return switch (s) {
155 .unsigned => ctype.toUnsigned(),
156 .signed => ctype.toSigned(),
157 };
158}
159
160pub fn getStandardDefineAbbrev(ctype: CType) ?[]const u8 {
161 return switch (ctype.index) {
162 .char => "CHAR",
163 .@"signed char" => "SCHAR",
164 .short => "SHRT",
165 .int => "INT",
166 .long => "LONG",
167 .@"long long" => "LLONG",
168 .@"unsigned char" => "UCHAR",
169 .@"unsigned short" => "USHRT",
170 .@"unsigned int" => "UINT",
171 .@"unsigned long" => "ULONG",
172 .@"unsigned long long" => "ULLONG",
173 .float => "FLT",
174 .double => "DBL",
175 .@"long double" => "LDBL",
176 .size_t => "SIZE",
177 .ptrdiff_t => "PTRDIFF",
178 .uint8_t => "UINT8",
179 .int8_t => "INT8",
180 .uint16_t => "UINT16",
181 .int16_t => "INT16",
182 .uint32_t => "UINT32",
183 .int32_t => "INT32",
184 .uint64_t => "UINT64",
185 .int64_t => "INT64",
186 .uintptr_t => "UINTPTR",
187 .intptr_t => "INTPTR",
188 else => null,
189 };
190}
191
192pub fn renderLiteralPrefix(ctype: CType, writer: anytype, kind: Kind, pool: *const Pool) @TypeOf(writer).Error!void {
193 switch (ctype.info(pool)) {
194 .basic => |basic_info| switch (basic_info) {
195 .void => unreachable,
196 ._Bool,
197 .char,
198 .@"signed char",
199 .short,
200 .@"unsigned short",
201 .bool,
202 .size_t,
203 .ptrdiff_t,
204 .uintptr_t,
205 .intptr_t,
206 => switch (kind) {
207 else => try writer.print("({s})", .{@tagName(basic_info)}),
208 .global => {},
209 },
210 .int,
211 .long,
212 .@"long long",
213 .@"unsigned char",
214 .@"unsigned int",
215 .@"unsigned long",
216 .@"unsigned long long",
217 .float,
218 .double,
219 .@"long double",
220 => {},
221 .uint8_t,
222 .int8_t,
223 .uint16_t,
224 .int16_t,
225 .uint32_t,
226 .int32_t,
227 .uint64_t,
228 .int64_t,
229 => try writer.print("{s}_C(", .{ctype.getStandardDefineAbbrev().?}),
230 .zig_u128,
231 .zig_i128,
232 .zig_f16,
233 .zig_f32,
234 .zig_f64,
235 .zig_f80,
236 .zig_f128,
237 .zig_c_longdouble,
238 => try writer.print("zig_{s}_{s}(", .{
239 switch (kind) {
240 else => "make",
241 .global => "init",
242 },
243 @tagName(basic_info)["zig_".len..],
244 }),
245 .va_list => unreachable,
246 _ => unreachable,
247 },
248 .array, .vector => try writer.writeByte('{'),
249 else => unreachable,
250 }
251}
252
253pub fn renderLiteralSuffix(ctype: CType, writer: anytype, pool: *const Pool) @TypeOf(writer).Error!void {
254 switch (ctype.info(pool)) {
255 .basic => |basic_info| switch (basic_info) {
256 .void => unreachable,
257 ._Bool => {},
258 .char,
259 .@"signed char",
260 .short,
261 .int,
262 => {},
263 .long => try writer.writeByte('l'),
264 .@"long long" => try writer.writeAll("ll"),
265 .@"unsigned char",
266 .@"unsigned short",
267 .@"unsigned int",
268 => try writer.writeByte('u'),
269 .@"unsigned long",
270 .size_t,
271 .uintptr_t,
272 => try writer.writeAll("ul"),
273 .@"unsigned long long" => try writer.writeAll("ull"),
274 .float => try writer.writeByte('f'),
275 .double => {},
276 .@"long double" => try writer.writeByte('l'),
277 .bool,
278 .ptrdiff_t,
279 .intptr_t,
280 => {},
281 .uint8_t,
282 .int8_t,
283 .uint16_t,
284 .int16_t,
285 .uint32_t,
286 .int32_t,
287 .uint64_t,
288 .int64_t,
289 .zig_u128,
290 .zig_i128,
291 .zig_f16,
292 .zig_f32,
293 .zig_f64,
294 .zig_f80,
295 .zig_f128,
296 .zig_c_longdouble,
297 => try writer.writeByte(')'),
298 .va_list => unreachable,
299 _ => unreachable,
300 },
301 .array, .vector => try writer.writeByte('}'),
302 else => unreachable,
303 }
304}
305
306pub fn floatActiveBits(ctype: CType, mod: *Module) u16 {
307 const target = &mod.resolved_target.result;
308 return switch (ctype.index) {
309 .float => target.c_type_bit_size(.float),
310 .double => target.c_type_bit_size(.double),
311 .@"long double", .zig_c_longdouble => target.c_type_bit_size(.longdouble),
312 .zig_f16 => 16,
313 .zig_f32 => 32,
314 .zig_f64 => 64,
315 .zig_f80 => 80,
316 .zig_f128 => 128,
317 else => unreachable,
318 };
319}
320
321pub fn byteSize(ctype: CType, pool: *const Pool, mod: *Module) u64 {
322 const target = &mod.resolved_target.result;
323 return switch (ctype.info(pool)) {
324 .basic => |basic_info| switch (basic_info) {
325 .void => 0,
326 .char, .@"signed char", ._Bool, .@"unsigned char", .bool, .uint8_t, .int8_t => 1,
327 .short => target.c_type_byte_size(.short),
328 .int => target.c_type_byte_size(.int),
329 .long => target.c_type_byte_size(.long),
330 .@"long long" => target.c_type_byte_size(.longlong),
331 .@"unsigned short" => target.c_type_byte_size(.ushort),
332 .@"unsigned int" => target.c_type_byte_size(.uint),
333 .@"unsigned long" => target.c_type_byte_size(.ulong),
334 .@"unsigned long long" => target.c_type_byte_size(.ulonglong),
335 .float => target.c_type_byte_size(.float),
336 .double => target.c_type_byte_size(.double),
337 .@"long double" => target.c_type_byte_size(.longdouble),
338 .size_t,
339 .ptrdiff_t,
340 .uintptr_t,
341 .intptr_t,
342 => @divExact(target.ptrBitWidth(), 8),
343 .uint16_t, .int16_t, .zig_f16 => 2,
344 .uint32_t, .int32_t, .zig_f32 => 4,
345 .uint64_t, .int64_t, .zig_f64 => 8,
346 .zig_u128, .zig_i128, .zig_f128 => 16,
347 .zig_f80 => if (target.c_type_bit_size(.longdouble) == 80)
348 target.c_type_byte_size(.longdouble)
349 else
350 16,
351 .zig_c_longdouble => target.c_type_byte_size(.longdouble),
352 .va_list => unreachable,
353 _ => unreachable,
354 },
355 .pointer => @divExact(target.ptrBitWidth(), 8),
356 .array, .vector => |sequence_info| sequence_info.elem_ctype.byteSize(pool, mod) * sequence_info.len,
357 else => unreachable,
358 };
359}
360
361pub fn info(ctype: CType, pool: *const Pool) Info {
362 const pool_index = ctype.toPoolIndex() orelse return .{ .basic = ctype.index };
363 const item = pool.items.get(pool_index);
364 switch (item.tag) {
365 .basic => unreachable,
366 .pointer => return .{ .pointer = .{
367 .elem_ctype = .{ .index = @enumFromInt(item.data) },
368 } },
369 .pointer_const => return .{ .pointer = .{
370 .elem_ctype = .{ .index = @enumFromInt(item.data) },
371 .@"const" = true,
372 } },
373 .pointer_volatile => return .{ .pointer = .{
374 .elem_ctype = .{ .index = @enumFromInt(item.data) },
375 .@"volatile" = true,
376 } },
377 .pointer_const_volatile => return .{ .pointer = .{
378 .elem_ctype = .{ .index = @enumFromInt(item.data) },
379 .@"const" = true,
380 .@"volatile" = true,
381 } },
382 .aligned => {
383 const extra = pool.getExtra(Pool.Aligned, item.data);
384 return .{ .aligned = .{
385 .ctype = .{ .index = extra.ctype },
386 .alignas = extra.flags.alignas,
387 } };
388 },
389 .array_small => {
390 const extra = pool.getExtra(Pool.SequenceSmall, item.data);
391 return .{ .array = .{
392 .elem_ctype = .{ .index = extra.elem_ctype },
393 .len = extra.len,
394 } };
395 },
396 .array_large => {
397 const extra = pool.getExtra(Pool.SequenceLarge, item.data);
398 return .{ .array = .{
399 .elem_ctype = .{ .index = extra.elem_ctype },
400 .len = extra.len(),
401 } };
402 },
403 .vector => {
404 const extra = pool.getExtra(Pool.SequenceSmall, item.data);
405 return .{ .vector = .{
406 .elem_ctype = .{ .index = extra.elem_ctype },
407 .len = extra.len,
408 } };
409 },
410 .fwd_decl_struct_anon => {
411 const extra_trail = pool.getExtraTrail(Pool.FwdDeclAnon, item.data);
412 return .{ .fwd_decl = .{
413 .tag = .@"struct",
414 .name = .{ .anon = .{
415 .extra_index = extra_trail.trail.extra_index,
416 .len = extra_trail.extra.fields_len,
417 } },
418 } };
419 },
420 .fwd_decl_union_anon => {
421 const extra_trail = pool.getExtraTrail(Pool.FwdDeclAnon, item.data);
422 return .{ .fwd_decl = .{
423 .tag = .@"union",
424 .name = .{ .anon = .{
425 .extra_index = extra_trail.trail.extra_index,
426 .len = extra_trail.extra.fields_len,
427 } },
428 } };
429 },
430 .fwd_decl_struct => return .{ .fwd_decl = .{
431 .tag = .@"struct",
432 .name = .{ .owner_decl = @enumFromInt(item.data) },
433 } },
434 .fwd_decl_union => return .{ .fwd_decl = .{
435 .tag = .@"union",
436 .name = .{ .owner_decl = @enumFromInt(item.data) },
437 } },
438 .aggregate_struct_anon => {
439 const extra_trail = pool.getExtraTrail(Pool.AggregateAnon, item.data);
440 return .{ .aggregate = .{
441 .tag = .@"struct",
442 .name = .{ .anon = .{
443 .owner_decl = extra_trail.extra.owner_decl,
444 .id = extra_trail.extra.id,
445 } },
446 .fields = .{
447 .extra_index = extra_trail.trail.extra_index,
448 .len = extra_trail.extra.fields_len,
449 },
450 } };
451 },
452 .aggregate_union_anon => {
453 const extra_trail = pool.getExtraTrail(Pool.AggregateAnon, item.data);
454 return .{ .aggregate = .{
455 .tag = .@"union",
456 .name = .{ .anon = .{
457 .owner_decl = extra_trail.extra.owner_decl,
458 .id = extra_trail.extra.id,
459 } },
460 .fields = .{
461 .extra_index = extra_trail.trail.extra_index,
462 .len = extra_trail.extra.fields_len,
463 },
464 } };
465 },
466 .aggregate_struct_packed_anon => {
467 const extra_trail = pool.getExtraTrail(Pool.AggregateAnon, item.data);
468 return .{ .aggregate = .{
469 .tag = .@"struct",
470 .@"packed" = true,
471 .name = .{ .anon = .{
472 .owner_decl = extra_trail.extra.owner_decl,
473 .id = extra_trail.extra.id,
474 } },
475 .fields = .{
476 .extra_index = extra_trail.trail.extra_index,
477 .len = extra_trail.extra.fields_len,
478 },
479 } };
480 },
481 .aggregate_union_packed_anon => {
482 const extra_trail = pool.getExtraTrail(Pool.AggregateAnon, item.data);
483 return .{ .aggregate = .{
484 .tag = .@"union",
485 .@"packed" = true,
486 .name = .{ .anon = .{
487 .owner_decl = extra_trail.extra.owner_decl,
488 .id = extra_trail.extra.id,
489 } },
490 .fields = .{
491 .extra_index = extra_trail.trail.extra_index,
492 .len = extra_trail.extra.fields_len,
493 },
494 } };
495 },
496 .aggregate_struct => {
497 const extra_trail = pool.getExtraTrail(Pool.Aggregate, item.data);
498 return .{ .aggregate = .{
499 .tag = .@"struct",
500 .name = .{ .fwd_decl = .{ .index = extra_trail.extra.fwd_decl } },
501 .fields = .{
502 .extra_index = extra_trail.trail.extra_index,
503 .len = extra_trail.extra.fields_len,
504 },
505 } };
506 },
507 .aggregate_union => {
508 const extra_trail = pool.getExtraTrail(Pool.Aggregate, item.data);
509 return .{ .aggregate = .{
510 .tag = .@"union",
511 .name = .{ .fwd_decl = .{ .index = extra_trail.extra.fwd_decl } },
512 .fields = .{
513 .extra_index = extra_trail.trail.extra_index,
514 .len = extra_trail.extra.fields_len,
515 },
516 } };
517 },
518 .aggregate_struct_packed => {
519 const extra_trail = pool.getExtraTrail(Pool.Aggregate, item.data);
520 return .{ .aggregate = .{
521 .tag = .@"struct",
522 .@"packed" = true,
523 .name = .{ .fwd_decl = .{ .index = extra_trail.extra.fwd_decl } },
524 .fields = .{
525 .extra_index = extra_trail.trail.extra_index,
526 .len = extra_trail.extra.fields_len,
527 },
528 } };
529 },
530 .aggregate_union_packed => {
531 const extra_trail = pool.getExtraTrail(Pool.Aggregate, item.data);
532 return .{ .aggregate = .{
533 .tag = .@"union",
534 .@"packed" = true,
535 .name = .{ .fwd_decl = .{ .index = extra_trail.extra.fwd_decl } },
536 .fields = .{
537 .extra_index = extra_trail.trail.extra_index,
538 .len = extra_trail.extra.fields_len,
539 },
540 } };
541 },
542 .function => {
543 const extra_trail = pool.getExtraTrail(Pool.Function, item.data);
544 return .{ .function = .{
545 .return_ctype = .{ .index = extra_trail.extra.return_ctype },
546 .param_ctypes = .{
547 .extra_index = extra_trail.trail.extra_index,
548 .len = extra_trail.extra.param_ctypes_len,
549 },
550 .varargs = false,
551 } };
552 },
553 .function_varargs => {
554 const extra_trail = pool.getExtraTrail(Pool.Function, item.data);
555 return .{ .function = .{
556 .return_ctype = .{ .index = extra_trail.extra.return_ctype },
557 .param_ctypes = .{
558 .extra_index = extra_trail.trail.extra_index,
559 .len = extra_trail.extra.param_ctypes_len,
560 },
561 .varargs = true,
562 } };
563 },
564 }
565}
566
567pub fn hash(ctype: CType, pool: *const Pool) Pool.Map.Hash {
568 return if (ctype.toPoolIndex()) |pool_index|
569 pool.map.entries.items(.hash)[pool_index]
570 else
571 CType.Index.basic_hashes[@intFromEnum(ctype.index)];
572}
573
574fn toForward(ctype: CType, pool: *Pool, allocator: std.mem.Allocator) !CType {
575 return switch (ctype.info(pool)) {
576 .basic, .pointer, .fwd_decl => ctype,
577 .aligned => |aligned_info| pool.getAligned(allocator, .{
578 .ctype = try aligned_info.ctype.toForward(pool, allocator),
579 .alignas = aligned_info.alignas,
580 }),
581 .array => |array_info| pool.getArray(allocator, .{
582 .elem_ctype = try array_info.elem_ctype.toForward(pool, allocator),
583 .len = array_info.len,
584 }),
585 .vector => |vector_info| pool.getVector(allocator, .{
586 .elem_ctype = try vector_info.elem_ctype.toForward(pool, allocator),
587 .len = vector_info.len,
588 }),
589 .aggregate => |aggregate_info| switch (aggregate_info.name) {
590 .anon => ctype,
591 .fwd_decl => |fwd_decl| fwd_decl,
592 },
593 .function => unreachable,
594 };
595}
596
597const Index = enum(u32) {
598 void,
599
600 // C basic types
601 char,
602
603 @"signed char",
604 short,
605 int,
606 long,
607 @"long long",
608
609 _Bool,
610 @"unsigned char",
611 @"unsigned short",
612 @"unsigned int",
613 @"unsigned long",
614 @"unsigned long long",
615
616 float,
617 double,
618 @"long double",
619
620 // C header types
621 // - stdbool.h
622 bool,
623 // - stddef.h
624 size_t,
625 ptrdiff_t,
626 // - stdint.h
627 uint8_t,
628 int8_t,
629 uint16_t,
630 int16_t,
631 uint32_t,
632 int32_t,
633 uint64_t,
634 int64_t,
635 uintptr_t,
636 intptr_t,
637 // - stdarg.h
638 va_list,
639
640 // zig.h types
641 zig_u128,
642 zig_i128,
643 zig_f16,
644 zig_f32,
645 zig_f64,
646 zig_f80,
647 zig_f128,
648 zig_c_longdouble,
649
650 _,
651
652 const first_pool_index: u32 = @typeInfo(CType.Index).Enum.fields.len;
653 const basic_hashes = init: {
654 @setEvalBranchQuota(1_600);
655 var basic_hashes_init: [first_pool_index]Pool.Map.Hash = undefined;
656 for (&basic_hashes_init, 0..) |*basic_hash, index| {
657 const ctype_index: CType.Index = @enumFromInt(index);
658 var hasher = Pool.Hasher.init;
659 hasher.update(@intFromEnum(ctype_index));
660 basic_hash.* = hasher.final(.basic);
661 }
662 break :init basic_hashes_init;
663 };
664};
665
666const Slice = struct {
667 extra_index: Pool.ExtraIndex,
668 len: u32,
669
670 pub fn at(slice: CType.Slice, index: usize, pool: *const Pool) CType {
671 var extra: Pool.ExtraTrail = .{ .extra_index = slice.extra_index };
672 return .{ .index = extra.next(slice.len, CType.Index, pool)[index] };
673 }
674};
675
676pub const Kind = enum {
677 forward,
678 forward_parameter,
679 complete,
680 global,
681 parameter,
682
683 pub fn isForward(kind: Kind) bool {
684 return switch (kind) {
685 .forward, .forward_parameter => true,
686 .complete, .global, .parameter => false,
687 };
688 }
689
690 pub fn isParameter(kind: Kind) bool {
691 return switch (kind) {
692 .forward_parameter, .parameter => true,
693 .forward, .complete, .global => false,
694 };
695 }
696
697 pub fn asParameter(kind: Kind) Kind {
698 return switch (kind) {
699 .forward, .forward_parameter => .forward_parameter,
700 .complete, .parameter, .global => .parameter,
701 };
702 }
703
704 pub fn noParameter(kind: Kind) Kind {
705 return switch (kind) {
706 .forward, .forward_parameter => .forward,
707 .complete, .parameter => .complete,
708 .global => .global,
709 };
710 }
711};
712
713pub const String = struct {
714 index: String.Index,
715
716 const Index = enum(u32) {
717 _,
718 };
719
720 pub fn slice(string: String, pool: *const Pool) []const u8 {
721 const start = pool.string_indices.items[@intFromEnum(string.index)];
722 const end = pool.string_indices.items[@intFromEnum(string.index) + 1];
723 return pool.string_bytes.items[start..end];
724 }
725};
726
727pub const Info = union(enum) {
728 basic: CType.Index,
729 pointer: Pointer,
730 aligned: Aligned,
731 array: Sequence,
732 vector: Sequence,
733 fwd_decl: FwdDecl,
734 aggregate: Aggregate,
735 function: Function,
736
737 pub const Pointer = struct {
738 elem_ctype: CType,
739 @"const": bool = false,
740 @"volatile": bool = false,
741
742 fn tag(pointer_info: Pointer) Pool.Tag {
743 return @enumFromInt(@intFromEnum(Pool.Tag.pointer) +
744 @as(u2, @bitCast(packed struct(u2) {
745 @"const": bool,
746 @"volatile": bool,
747 }{
748 .@"const" = pointer_info.@"const",
749 .@"volatile" = pointer_info.@"volatile",
750 })));
751 }
752 };
753
754 pub const Aligned = struct {
755 ctype: CType,
756 alignas: AlignAs,
757 };
758
759 pub const Sequence = struct {
760 elem_ctype: CType,
761 len: u64,
762 };
763
764 pub const Tag = enum { @"enum", @"struct", @"union" };
765
766 pub const Field = struct {
767 name: String,
768 ctype: CType,
769 alignas: AlignAs,
770
771 pub const Slice = struct {
772 extra_index: Pool.ExtraIndex,
773 len: u32,
774
775 pub fn at(slice: Field.Slice, index: usize, pool: *const Pool) Field {
776 assert(index < slice.len);
777 const extra = pool.getExtra(Pool.Field, @intCast(slice.extra_index +
778 index * @typeInfo(Pool.Field).Struct.fields.len));
779 return .{
780 .name = .{ .index = extra.name },
781 .ctype = .{ .index = extra.ctype },
782 .alignas = extra.flags.alignas,
783 };
784 }
785
786 fn eqlAdapted(
787 lhs_slice: Field.Slice,
788 lhs_pool: *const Pool,
789 rhs_slice: Field.Slice,
790 rhs_pool: *const Pool,
791 pool_adapter: anytype,
792 ) bool {
793 if (lhs_slice.len != rhs_slice.len) return false;
794 for (0..lhs_slice.len) |index| {
795 if (!lhs_slice.at(index, lhs_pool).eqlAdapted(
796 lhs_pool,
797 rhs_slice.at(index, rhs_pool),
798 rhs_pool,
799 pool_adapter,
800 )) return false;
801 }
802 return true;
803 }
804 };
805
806 fn eqlAdapted(
807 lhs_field: Field,
808 lhs_pool: *const Pool,
809 rhs_field: Field,
810 rhs_pool: *const Pool,
811 pool_adapter: anytype,
812 ) bool {
813 return std.meta.eql(lhs_field.alignas, rhs_field.alignas) and
814 pool_adapter.eql(lhs_field.ctype, rhs_field.ctype) and std.mem.eql(
815 u8,
816 lhs_field.name.slice(lhs_pool),
817 rhs_field.name.slice(rhs_pool),
818 );
819 }
820 };
821
822 pub const FwdDecl = struct {
823 tag: Tag,
824 name: union(enum) {
825 anon: Field.Slice,
826 owner_decl: DeclIndex,
827 },
828 };
829
830 pub const Aggregate = struct {
831 tag: Tag,
832 @"packed": bool = false,
833 name: union(enum) {
834 anon: struct {
835 owner_decl: DeclIndex,
836 id: u32,
837 },
838 fwd_decl: CType,
839 },
840 fields: Field.Slice,
841 };
842
843 pub const Function = struct {
844 return_ctype: CType,
845 param_ctypes: CType.Slice,
846 varargs: bool = false,
847 };
848
849 pub fn eqlAdapted(
850 lhs_info: Info,
851 lhs_pool: *const Pool,
852 rhs_ctype: CType,
853 rhs_pool: *const Pool,
854 pool_adapter: anytype,
855 ) bool {
856 const InfoTag = @typeInfo(Info).Union.tag_type.?;
857 const rhs_info = rhs_ctype.info(rhs_pool);
858 if (@as(InfoTag, lhs_info) != @as(InfoTag, rhs_info)) return false;
859 return switch (lhs_info) {
860 .basic => |lhs_basic_info| lhs_basic_info == rhs_info.basic,
861 .pointer => |lhs_pointer_info| lhs_pointer_info.@"const" == rhs_info.pointer.@"const" and
862 lhs_pointer_info.@"volatile" == rhs_info.pointer.@"volatile" and
863 pool_adapter.eql(lhs_pointer_info.elem_ctype, rhs_info.pointer.elem_ctype),
864 .aligned => |lhs_aligned_info| std.meta.eql(lhs_aligned_info.alignas, rhs_info.aligned.alignas) and
865 pool_adapter.eql(lhs_aligned_info.ctype, rhs_info.aligned.ctype),
866 .array => |lhs_array_info| lhs_array_info.len == rhs_info.array.len and
867 pool_adapter.eql(lhs_array_info.elem_ctype, rhs_info.array.elem_ctype),
868 .vector => |lhs_vector_info| lhs_vector_info.len == rhs_info.vector.len and
869 pool_adapter.eql(lhs_vector_info.elem_ctype, rhs_info.vector.elem_ctype),
870 .fwd_decl => |lhs_fwd_decl_info| lhs_fwd_decl_info.tag == rhs_info.fwd_decl.tag and
871 switch (lhs_fwd_decl_info.name) {
872 .anon => |lhs_anon| rhs_info.fwd_decl.name == .anon and lhs_anon.eqlAdapted(
873 lhs_pool,
874 rhs_info.fwd_decl.name.anon,
875 rhs_pool,
876 pool_adapter,
877 ),
878 .owner_decl => |lhs_owner_decl| rhs_info.fwd_decl.name == .owner_decl and
879 lhs_owner_decl == rhs_info.fwd_decl.name.owner_decl,
880 },
881 .aggregate => |lhs_aggregate_info| lhs_aggregate_info.tag == rhs_info.aggregate.tag and
882 lhs_aggregate_info.@"packed" == rhs_info.aggregate.@"packed" and
883 switch (lhs_aggregate_info.name) {
884 .anon => |lhs_anon| rhs_info.aggregate.name == .anon and
885 lhs_anon.owner_decl == rhs_info.aggregate.name.anon.owner_decl and
886 lhs_anon.id == rhs_info.aggregate.name.anon.id,
887 .fwd_decl => |lhs_fwd_decl| rhs_info.aggregate.name == .fwd_decl and
888 pool_adapter.eql(lhs_fwd_decl, rhs_info.aggregate.name.fwd_decl),
889 } and lhs_aggregate_info.fields.eqlAdapted(
890 lhs_pool,
891 rhs_info.aggregate.fields,
892 rhs_pool,
893 pool_adapter,
894 ),
895 .function => |lhs_function_info| lhs_function_info.param_ctypes.len ==
896 rhs_info.function.param_ctypes.len and
897 pool_adapter.eql(lhs_function_info.return_ctype, rhs_info.function.return_ctype) and
898 for (0..lhs_function_info.param_ctypes.len) |param_index|
899 {
900 if (!pool_adapter.eql(
901 lhs_function_info.param_ctypes.at(param_index, lhs_pool),
902 rhs_info.function.param_ctypes.at(param_index, rhs_pool),
903 )) break false;
904 } else true,
905 };
906 }
907};
908
909pub const Pool = struct {
910 map: Map,
911 items: std.MultiArrayList(Item),
912 extra: std.ArrayListUnmanaged(u32),
913
914 string_map: Map,
915 string_indices: std.ArrayListUnmanaged(u32),
916 string_bytes: std.ArrayListUnmanaged(u8),
917
918 const Map = std.AutoArrayHashMapUnmanaged(void, void);
919
920 pub const empty: Pool = .{
921 .map = .{},
922 .items = .{},
923 .extra = .{},
924
925 .string_map = .{},
926 .string_indices = .{},
927 .string_bytes = .{},
928 };
929
930 pub fn init(pool: *Pool, allocator: std.mem.Allocator) !void {
931 if (pool.string_indices.items.len == 0)
932 try pool.string_indices.append(allocator, 0);
933 }
934
935 pub fn deinit(pool: *Pool, allocator: std.mem.Allocator) void {
936 pool.map.deinit(allocator);
937 pool.items.deinit(allocator);
938 pool.extra.deinit(allocator);
939
940 pool.string_map.deinit(allocator);
941 pool.string_indices.deinit(allocator);
942 pool.string_bytes.deinit(allocator);
943
944 pool.* = undefined;
945 }
946
947 pub fn move(pool: *Pool) Pool {
948 defer pool.* = empty;
949 return pool.*;
950 }
951
952 pub fn clearRetainingCapacity(pool: *Pool) void {
953 pool.map.clearRetainingCapacity();
954 pool.items.shrinkRetainingCapacity(0);
955 pool.extra.clearRetainingCapacity();
956
957 pool.string_map.clearRetainingCapacity();
958 pool.string_indices.shrinkRetainingCapacity(1);
959 pool.string_bytes.clearRetainingCapacity();
960 }
961
962 pub fn freeUnusedCapacity(pool: *Pool, allocator: std.mem.Allocator) void {
963 pool.map.shrinkAndFree(allocator, pool.map.count());
964 pool.items.shrinkAndFree(allocator, pool.items.len);
965 pool.extra.shrinkAndFree(allocator, pool.extra.items.len);
966
967 pool.string_map.shrinkAndFree(allocator, pool.string_map.count());
968 pool.string_indices.shrinkAndFree(allocator, pool.string_indices.items.len);
969 pool.string_bytes.shrinkAndFree(allocator, pool.string_bytes.items.len);
970 }
971
972 pub fn getPointer(pool: *Pool, allocator: std.mem.Allocator, pointer_info: Info.Pointer) !CType {
973 var hasher = Hasher.init;
974 hasher.update(pointer_info.elem_ctype.hash(pool));
975 return pool.tagData(
976 allocator,
977 hasher,
978 pointer_info.tag(),
979 @intFromEnum(pointer_info.elem_ctype.index),
980 );
981 }
982
983 pub fn getAligned(pool: *Pool, allocator: std.mem.Allocator, aligned_info: Info.Aligned) !CType {
984 return pool.tagExtra(allocator, .aligned, Aligned, .{
985 .ctype = aligned_info.ctype.index,
986 .flags = .{ .alignas = aligned_info.alignas },
987 });
988 }
989
990 pub fn getArray(pool: *Pool, allocator: std.mem.Allocator, array_info: Info.Sequence) !CType {
991 return if (std.math.cast(u32, array_info.len)) |small_len|
992 pool.tagExtra(allocator, .array_small, SequenceSmall, .{
993 .elem_ctype = array_info.elem_ctype.index,
994 .len = small_len,
995 })
996 else
997 pool.tagExtra(allocator, .array_large, SequenceLarge, .{
998 .elem_ctype = array_info.elem_ctype.index,
999 .len_lo = @truncate(array_info.len >> 0),
1000 .len_hi = @truncate(array_info.len >> 32),
1001 });
1002 }
1003
1004 pub fn getVector(pool: *Pool, allocator: std.mem.Allocator, vector_info: Info.Sequence) !CType {
1005 return pool.tagExtra(allocator, .vector, SequenceSmall, .{
1006 .elem_ctype = vector_info.elem_ctype.index,
1007 .len = @intCast(vector_info.len),
1008 });
1009 }
1010
1011 pub fn getFwdDecl(
1012 pool: *Pool,
1013 allocator: std.mem.Allocator,
1014 fwd_decl_info: struct {
1015 tag: Info.Tag,
1016 name: union(enum) {
1017 anon: []const Info.Field,
1018 owner_decl: DeclIndex,
1019 },
1020 },
1021 ) !CType {
1022 var hasher = Hasher.init;
1023 switch (fwd_decl_info.name) {
1024 .anon => |fields| {
1025 const ExpectedContents = [32]CType;
1026 var stack align(@max(
1027 @alignOf(std.heap.StackFallbackAllocator(0)),
1028 @alignOf(ExpectedContents),
1029 )) = std.heap.stackFallback(@sizeOf(ExpectedContents), allocator);
1030 const stack_allocator = stack.get();
1031 const field_ctypes = try stack_allocator.alloc(CType, fields.len);
1032 defer stack_allocator.free(field_ctypes);
1033 for (field_ctypes, fields) |*field_ctype, field|
1034 field_ctype.* = try field.ctype.toForward(pool, allocator);
1035 const extra: FwdDeclAnon = .{ .fields_len = @intCast(fields.len) };
1036 const extra_index = try pool.addExtra(
1037 allocator,
1038 FwdDeclAnon,
1039 extra,
1040 fields.len * @typeInfo(Field).Struct.fields.len,
1041 );
1042 for (fields, field_ctypes) |field, field_ctype| pool.addHashedExtraAssumeCapacity(
1043 &hasher,
1044 Field,
1045 .{
1046 .name = field.name.index,
1047 .ctype = field_ctype.index,
1048 .flags = .{ .alignas = field.alignas },
1049 },
1050 );
1051 hasher.updateExtra(FwdDeclAnon, extra, pool);
1052 return pool.tagTrailingExtra(allocator, hasher, switch (fwd_decl_info.tag) {
1053 .@"struct" => .fwd_decl_struct_anon,
1054 .@"union" => .fwd_decl_union_anon,
1055 .@"enum" => unreachable,
1056 }, extra_index);
1057 },
1058 .owner_decl => |owner_decl| {
1059 hasher.update(owner_decl);
1060 return pool.tagData(allocator, hasher, switch (fwd_decl_info.tag) {
1061 .@"struct" => .fwd_decl_struct,
1062 .@"union" => .fwd_decl_union,
1063 .@"enum" => unreachable,
1064 }, @intFromEnum(owner_decl));
1065 },
1066 }
1067 }
1068
1069 pub fn getAggregate(
1070 pool: *Pool,
1071 allocator: std.mem.Allocator,
1072 aggregate_info: struct {
1073 tag: Info.Tag,
1074 @"packed": bool = false,
1075 name: union(enum) {
1076 anon: struct {
1077 owner_decl: DeclIndex,
1078 id: u32,
1079 },
1080 fwd_decl: CType,
1081 },
1082 fields: []const Info.Field,
1083 },
1084 ) !CType {
1085 var hasher = Hasher.init;
1086 switch (aggregate_info.name) {
1087 .anon => |anon| {
1088 const extra: AggregateAnon = .{
1089 .owner_decl = anon.owner_decl,
1090 .id = anon.id,
1091 .fields_len = @intCast(aggregate_info.fields.len),
1092 };
1093 const extra_index = try pool.addExtra(
1094 allocator,
1095 AggregateAnon,
1096 extra,
1097 aggregate_info.fields.len * @typeInfo(Field).Struct.fields.len,
1098 );
1099 for (aggregate_info.fields) |field| pool.addHashedExtraAssumeCapacity(&hasher, Field, .{
1100 .name = field.name.index,
1101 .ctype = field.ctype.index,
1102 .flags = .{ .alignas = field.alignas },
1103 });
1104 hasher.updateExtra(AggregateAnon, extra, pool);
1105 return pool.tagTrailingExtra(allocator, hasher, switch (aggregate_info.tag) {
1106 .@"struct" => switch (aggregate_info.@"packed") {
1107 false => .aggregate_struct_anon,
1108 true => .aggregate_struct_packed_anon,
1109 },
1110 .@"union" => switch (aggregate_info.@"packed") {
1111 false => .aggregate_union_anon,
1112 true => .aggregate_union_packed_anon,
1113 },
1114 .@"enum" => unreachable,
1115 }, extra_index);
1116 },
1117 .fwd_decl => |fwd_decl| {
1118 const extra: Aggregate = .{
1119 .fwd_decl = fwd_decl.index,
1120 .fields_len = @intCast(aggregate_info.fields.len),
1121 };
1122 const extra_index = try pool.addExtra(
1123 allocator,
1124 Aggregate,
1125 extra,
1126 aggregate_info.fields.len * @typeInfo(Field).Struct.fields.len,
1127 );
1128 for (aggregate_info.fields) |field| pool.addHashedExtraAssumeCapacity(&hasher, Field, .{
1129 .name = field.name.index,
1130 .ctype = field.ctype.index,
1131 .flags = .{ .alignas = field.alignas },
1132 });
1133 hasher.updateExtra(Aggregate, extra, pool);
1134 return pool.tagTrailingExtra(allocator, hasher, switch (aggregate_info.tag) {
1135 .@"struct" => switch (aggregate_info.@"packed") {
1136 false => .aggregate_struct,
1137 true => .aggregate_struct_packed,
1138 },
1139 .@"union" => switch (aggregate_info.@"packed") {
1140 false => .aggregate_union,
1141 true => .aggregate_union_packed,
1142 },
1143 .@"enum" => unreachable,
1144 }, extra_index);
1145 },
1146 }
1147 }
1148
1149 pub fn getFunction(
1150 pool: *Pool,
1151 allocator: std.mem.Allocator,
1152 function_info: struct {
1153 return_ctype: CType,
1154 param_ctypes: []const CType,
1155 varargs: bool = false,
1156 },
1157 ) !CType {
1158 var hasher = Hasher.init;
1159 const extra: Function = .{
1160 .return_ctype = function_info.return_ctype.index,
1161 .param_ctypes_len = @intCast(function_info.param_ctypes.len),
1162 };
1163 const extra_index = try pool.addExtra(allocator, Function, extra, function_info.param_ctypes.len);
1164 for (function_info.param_ctypes) |param_ctype| {
1165 hasher.update(param_ctype.hash(pool));
1166 pool.extra.appendAssumeCapacity(@intFromEnum(param_ctype.index));
1167 }
1168 hasher.updateExtra(Function, extra, pool);
1169 return pool.tagTrailingExtra(allocator, hasher, switch (function_info.varargs) {
1170 false => .function,
1171 true => .function_varargs,
1172 }, extra_index);
1173 }
1174
1175 pub fn fromFields(
1176 pool: *Pool,
1177 allocator: std.mem.Allocator,
1178 tag: Info.Tag,
1179 fields: []Info.Field,
1180 kind: Kind,
1181 ) !CType {
1182 sortFields(fields);
1183 const fwd_decl = try pool.getFwdDecl(allocator, .{
1184 .tag = tag,
1185 .name = .{ .anon = fields },
1186 });
1187 return if (kind.isForward()) fwd_decl else pool.getAggregate(allocator, .{
1188 .tag = tag,
1189 .name = .{ .fwd_decl = fwd_decl },
1190 .fields = fields,
1191 });
1192 }
1193
1194 pub fn fromIntInfo(
1195 pool: *Pool,
1196 allocator: std.mem.Allocator,
1197 int_info: std.builtin.Type.Int,
1198 mod: *Module,
1199 kind: Kind,
1200 ) !CType {
1201 switch (int_info.bits) {
1202 0 => return .{ .index = .void },
1203 1...8 => switch (int_info.signedness) {
1204 .unsigned => return .{ .index = .uint8_t },
1205 .signed => return .{ .index = .int8_t },
1206 },
1207 9...16 => switch (int_info.signedness) {
1208 .unsigned => return .{ .index = .uint16_t },
1209 .signed => return .{ .index = .int16_t },
1210 },
1211 17...32 => switch (int_info.signedness) {
1212 .unsigned => return .{ .index = .uint32_t },
1213 .signed => return .{ .index = .int32_t },
1214 },
1215 33...64 => switch (int_info.signedness) {
1216 .unsigned => return .{ .index = .uint64_t },
1217 .signed => return .{ .index = .int64_t },
1218 },
1219 65...128 => switch (int_info.signedness) {
1220 .unsigned => return .{ .index = .zig_u128 },
1221 .signed => return .{ .index = .zig_i128 },
1222 },
1223 else => {
1224 const target = &mod.resolved_target.result;
1225 const abi_align = Type.intAbiAlignment(int_info.bits, target.*);
1226 const abi_align_bytes = abi_align.toByteUnits().?;
1227 const array_ctype = try pool.getArray(allocator, .{
1228 .len = @divExact(Type.intAbiSize(int_info.bits, target.*), abi_align_bytes),
1229 .elem_ctype = try pool.fromIntInfo(allocator, .{
1230 .signedness = .unsigned,
1231 .bits = @intCast(abi_align_bytes * 8),
1232 }, mod, kind.noParameter()),
1233 });
1234 if (!kind.isParameter()) return array_ctype;
1235 var fields = [_]Info.Field{
1236 .{
1237 .name = try pool.string(allocator, "array"),
1238 .ctype = array_ctype,
1239 .alignas = AlignAs.fromAbiAlignment(abi_align),
1240 },
1241 };
1242 return pool.fromFields(allocator, .@"struct", &fields, kind);
1243 },
1244 }
1245 }
1246
1247 pub fn fromType(
1248 pool: *Pool,
1249 allocator: std.mem.Allocator,
1250 scratch: *std.ArrayListUnmanaged(u32),
1251 ty: Type,
1252 zcu: *Zcu,
1253 mod: *Module,
1254 kind: Kind,
1255 ) !CType {
1256 const ip = &zcu.intern_pool;
1257 switch (ty.toIntern()) {
1258 .u0_type,
1259 .i0_type,
1260 .anyopaque_type,
1261 .void_type,
1262 .empty_struct_type,
1263 .type_type,
1264 .comptime_int_type,
1265 .comptime_float_type,
1266 .null_type,
1267 .undefined_type,
1268 .enum_literal_type,
1269 => return .{ .index = .void },
1270 .u1_type, .u8_type => return .{ .index = .uint8_t },
1271 .i8_type => return .{ .index = .int8_t },
1272 .u16_type => return .{ .index = .uint16_t },
1273 .i16_type => return .{ .index = .int16_t },
1274 .u29_type, .u32_type => return .{ .index = .uint32_t },
1275 .i32_type => return .{ .index = .int32_t },
1276 .u64_type => return .{ .index = .uint64_t },
1277 .i64_type => return .{ .index = .int64_t },
1278 .u80_type, .u128_type => return .{ .index = .zig_u128 },
1279 .i128_type => return .{ .index = .zig_i128 },
1280 .usize_type => return .{ .index = .uintptr_t },
1281 .isize_type => return .{ .index = .intptr_t },
1282 .c_char_type => return .{ .index = .char },
1283 .c_short_type => return .{ .index = .short },
1284 .c_ushort_type => return .{ .index = .@"unsigned short" },
1285 .c_int_type => return .{ .index = .int },
1286 .c_uint_type => return .{ .index = .@"unsigned int" },
1287 .c_long_type => return .{ .index = .long },
1288 .c_ulong_type => return .{ .index = .@"unsigned long" },
1289 .c_longlong_type => return .{ .index = .@"long long" },
1290 .c_ulonglong_type => return .{ .index = .@"unsigned long long" },
1291 .c_longdouble_type => return .{ .index = .@"long double" },
1292 .f16_type => return .{ .index = .zig_f16 },
1293 .f32_type => return .{ .index = .zig_f32 },
1294 .f64_type => return .{ .index = .zig_f64 },
1295 .f80_type => return .{ .index = .zig_f80 },
1296 .f128_type => return .{ .index = .zig_f128 },
1297 .bool_type, .optional_noreturn_type => return .{ .index = .bool },
1298 .noreturn_type,
1299 .anyframe_type,
1300 .generic_poison_type,
1301 => unreachable,
1302 .atomic_order_type,
1303 .atomic_rmw_op_type,
1304 .calling_convention_type,
1305 .address_space_type,
1306 .float_mode_type,
1307 .reduce_op_type,
1308 .call_modifier_type,
1309 => |ip_index| return pool.fromType(
1310 allocator,
1311 scratch,
1312 Type.fromInterned(ip.loadEnumType(ip_index).tag_ty),
1313 zcu,
1314 mod,
1315 kind,
1316 ),
1317 .anyerror_type,
1318 .anyerror_void_error_union_type,
1319 .adhoc_inferred_error_set_type,
1320 => return pool.fromIntInfo(allocator, .{
1321 .signedness = .unsigned,
1322 .bits = zcu.errorSetBits(),
1323 }, mod, kind),
1324 .manyptr_u8_type,
1325 => return pool.getPointer(allocator, .{
1326 .elem_ctype = .{ .index = .uint8_t },
1327 }),
1328 .manyptr_const_u8_type,
1329 .manyptr_const_u8_sentinel_0_type,
1330 => return pool.getPointer(allocator, .{
1331 .elem_ctype = .{ .index = .uint8_t },
1332 .@"const" = true,
1333 }),
1334 .single_const_pointer_to_comptime_int_type,
1335 => return pool.getPointer(allocator, .{
1336 .elem_ctype = .{ .index = .void },
1337 .@"const" = true,
1338 }),
1339 .slice_const_u8_type,
1340 .slice_const_u8_sentinel_0_type,
1341 => {
1342 const target = &mod.resolved_target.result;
1343 var fields = [_]Info.Field{
1344 .{
1345 .name = try pool.string(allocator, "ptr"),
1346 .ctype = try pool.getPointer(allocator, .{
1347 .elem_ctype = .{ .index = .uint8_t },
1348 .@"const" = true,
1349 }),
1350 .alignas = AlignAs.fromAbiAlignment(Type.ptrAbiAlignment(target.*)),
1351 },
1352 .{
1353 .name = try pool.string(allocator, "len"),
1354 .ctype = .{ .index = .uintptr_t },
1355 .alignas = AlignAs.fromAbiAlignment(
1356 Type.intAbiAlignment(target.ptrBitWidth(), target.*),
1357 ),
1358 },
1359 };
1360 return pool.fromFields(allocator, .@"struct", &fields, kind);
1361 },
1362
1363 .undef,
1364 .zero,
1365 .zero_usize,
1366 .zero_u8,
1367 .one,
1368 .one_usize,
1369 .one_u8,
1370 .four_u8,
1371 .negative_one,
1372 .calling_convention_c,
1373 .calling_convention_inline,
1374 .void_value,
1375 .unreachable_value,
1376 .null_value,
1377 .bool_true,
1378 .bool_false,
1379 .empty_struct,
1380 .generic_poison,
1381 .var_args_param_type,
1382 .none,
1383 => unreachable,
1384
1385 //.prefetch_options_type,
1386 //.export_options_type,
1387 //.extern_options_type,
1388 //.type_info_type,
1389 //_,
1390 else => |ip_index| switch (ip.indexToKey(ip_index)) {
1391 .int_type => |int_info| return pool.fromIntInfo(allocator, int_info, mod, kind),
1392 .ptr_type => |ptr_info| switch (ptr_info.flags.size) {
1393 .One, .Many, .C => return pool.getPointer(allocator, .{
1394 .elem_ctype = elem_ctype: {
1395 if (ptr_info.packed_offset.host_size > 0 and
1396 ptr_info.flags.vector_index == .none)
1397 break :elem_ctype try pool.fromIntInfo(allocator, .{
1398 .signedness = .unsigned,
1399 .bits = ptr_info.packed_offset.host_size * 8,
1400 }, mod, .forward);
1401 const elem: Info.Aligned = .{
1402 .ctype = try pool.fromType(
1403 allocator,
1404 scratch,
1405 Type.fromInterned(ptr_info.child),
1406 zcu,
1407 mod,
1408 .forward,
1409 ),
1410 .alignas = AlignAs.fromAlignment(.{
1411 .@"align" = ptr_info.flags.alignment,
1412 .abi = Type.fromInterned(ptr_info.child).abiAlignment(zcu),
1413 }),
1414 };
1415 if (elem.alignas.abiOrder().compare(.gte))
1416 break :elem_ctype elem.ctype;
1417 break :elem_ctype try pool.getAligned(allocator, elem);
1418 },
1419 .@"const" = ptr_info.flags.is_const,
1420 .@"volatile" = ptr_info.flags.is_volatile,
1421 }),
1422 .Slice => {
1423 const target = &mod.resolved_target.result;
1424 var fields = [_]Info.Field{
1425 .{
1426 .name = try pool.string(allocator, "ptr"),
1427 .ctype = try pool.fromType(
1428 allocator,
1429 scratch,
1430 Type.fromInterned(ip.slicePtrType(ip_index)),
1431 zcu,
1432 mod,
1433 kind,
1434 ),
1435 .alignas = AlignAs.fromAbiAlignment(Type.ptrAbiAlignment(target.*)),
1436 },
1437 .{
1438 .name = try pool.string(allocator, "len"),
1439 .ctype = .{ .index = .uintptr_t },
1440 .alignas = AlignAs.fromAbiAlignment(
1441 Type.intAbiAlignment(target.ptrBitWidth(), target.*),
1442 ),
1443 },
1444 };
1445 return pool.fromFields(allocator, .@"struct", &fields, kind);
1446 },
1447 },
1448 .array_type => |array_info| {
1449 const len = array_info.len + @intFromBool(array_info.sentinel != .none);
1450 if (len == 0) return .{ .index = .void };
1451 const elem_type = Type.fromInterned(array_info.child);
1452 const elem_ctype = try pool.fromType(
1453 allocator,
1454 scratch,
1455 elem_type,
1456 zcu,
1457 mod,
1458 kind.noParameter(),
1459 );
1460 if (elem_ctype.index == .void) return .{ .index = .void };
1461 const array_ctype = try pool.getArray(allocator, .{
1462 .elem_ctype = elem_ctype,
1463 .len = array_info.len + @intFromBool(array_info.sentinel != .none),
1464 });
1465 if (!kind.isParameter()) return array_ctype;
1466 var fields = [_]Info.Field{
1467 .{
1468 .name = try pool.string(allocator, "array"),
1469 .ctype = array_ctype,
1470 .alignas = AlignAs.fromAbiAlignment(elem_type.abiAlignment(zcu)),
1471 },
1472 };
1473 return pool.fromFields(allocator, .@"struct", &fields, kind);
1474 },
1475 .vector_type => |vector_info| {
1476 if (vector_info.len == 0) return .{ .index = .void };
1477 const elem_type = Type.fromInterned(vector_info.child);
1478 const elem_ctype = try pool.fromType(
1479 allocator,
1480 scratch,
1481 elem_type,
1482 zcu,
1483 mod,
1484 kind.noParameter(),
1485 );
1486 if (elem_ctype.index == .void) return .{ .index = .void };
1487 const vector_ctype = try pool.getVector(allocator, .{
1488 .elem_ctype = elem_ctype,
1489 .len = vector_info.len,
1490 });
1491 if (!kind.isParameter()) return vector_ctype;
1492 var fields = [_]Info.Field{
1493 .{
1494 .name = try pool.string(allocator, "array"),
1495 .ctype = vector_ctype,
1496 .alignas = AlignAs.fromAbiAlignment(elem_type.abiAlignment(zcu)),
1497 },
1498 };
1499 return pool.fromFields(allocator, .@"struct", &fields, kind);
1500 },
1501 .opt_type => |payload_type| {
1502 if (ip.isNoReturn(payload_type)) return .{ .index = .void };
1503 const payload_ctype = try pool.fromType(
1504 allocator,
1505 scratch,
1506 Type.fromInterned(payload_type),
1507 zcu,
1508 mod,
1509 kind.noParameter(),
1510 );
1511 if (payload_ctype.index == .void) return .{ .index = .bool };
1512 switch (payload_type) {
1513 .anyerror_type => return payload_ctype,
1514 else => switch (ip.indexToKey(payload_type)) {
1515 .ptr_type => |payload_ptr_info| if (payload_ptr_info.flags.size != .C and
1516 !payload_ptr_info.flags.is_allowzero) return payload_ctype,
1517 .error_set_type, .inferred_error_set_type => return payload_ctype,
1518 else => {},
1519 },
1520 }
1521 var fields = [_]Info.Field{
1522 .{
1523 .name = try pool.string(allocator, "is_null"),
1524 .ctype = .{ .index = .bool },
1525 .alignas = AlignAs.fromAbiAlignment(.@"1"),
1526 },
1527 .{
1528 .name = try pool.string(allocator, "payload"),
1529 .ctype = payload_ctype,
1530 .alignas = AlignAs.fromAbiAlignment(
1531 Type.fromInterned(payload_type).abiAlignment(zcu),
1532 ),
1533 },
1534 };
1535 return pool.fromFields(allocator, .@"struct", &fields, kind);
1536 },
1537 .anyframe_type => unreachable,
1538 .error_union_type => |error_union_info| {
1539 const error_set_bits = zcu.errorSetBits();
1540 const error_set_ctype = try pool.fromIntInfo(allocator, .{
1541 .signedness = .unsigned,
1542 .bits = error_set_bits,
1543 }, mod, kind);
1544 if (ip.isNoReturn(error_union_info.payload_type)) return error_set_ctype;
1545 const payload_type = Type.fromInterned(error_union_info.payload_type);
1546 const payload_ctype = try pool.fromType(
1547 allocator,
1548 scratch,
1549 payload_type,
1550 zcu,
1551 mod,
1552 kind.noParameter(),
1553 );
1554 if (payload_ctype.index == .void) return error_set_ctype;
1555 const target = &mod.resolved_target.result;
1556 var fields = [_]Info.Field{
1557 .{
1558 .name = try pool.string(allocator, "error"),
1559 .ctype = error_set_ctype,
1560 .alignas = AlignAs.fromAbiAlignment(
1561 Type.intAbiAlignment(error_set_bits, target.*),
1562 ),
1563 },
1564 .{
1565 .name = try pool.string(allocator, "payload"),
1566 .ctype = payload_ctype,
1567 .alignas = AlignAs.fromAbiAlignment(payload_type.abiAlignment(zcu)),
1568 },
1569 };
1570 return pool.fromFields(allocator, .@"struct", &fields, kind);
1571 },
1572 .simple_type => unreachable,
1573 .struct_type => {
1574 const loaded_struct = ip.loadStructType(ip_index);
1575 switch (loaded_struct.layout) {
1576 .auto, .@"extern" => {
1577 const fwd_decl = try pool.getFwdDecl(allocator, .{
1578 .tag = .@"struct",
1579 .name = .{ .owner_decl = loaded_struct.decl.unwrap().? },
1580 });
1581 if (kind.isForward()) return if (ty.hasRuntimeBitsIgnoreComptime(zcu))
1582 fwd_decl
1583 else
1584 .{ .index = .void };
1585 const scratch_top = scratch.items.len;
1586 defer scratch.shrinkRetainingCapacity(scratch_top);
1587 try scratch.ensureUnusedCapacity(
1588 allocator,
1589 loaded_struct.field_types.len * @typeInfo(Field).Struct.fields.len,
1590 );
1591 var hasher = Hasher.init;
1592 var tag: Tag = .aggregate_struct;
1593 var field_it = loaded_struct.iterateRuntimeOrder(ip);
1594 while (field_it.next()) |field_index| {
1595 const field_type = Type.fromInterned(
1596 loaded_struct.field_types.get(ip)[field_index],
1597 );
1598 const field_ctype = try pool.fromType(
1599 allocator,
1600 scratch,
1601 field_type,
1602 zcu,
1603 mod,
1604 kind.noParameter(),
1605 );
1606 if (field_ctype.index == .void) continue;
1607 const field_name = if (loaded_struct.fieldName(ip, field_index)
1608 .unwrap()) |field_name|
1609 try pool.string(allocator, ip.stringToSlice(field_name))
1610 else
1611 try pool.fmt(allocator, "f{d}", .{field_index});
1612 const field_alignas = AlignAs.fromAlignment(.{
1613 .@"align" = loaded_struct.fieldAlign(ip, field_index),
1614 .abi = field_type.abiAlignment(zcu),
1615 });
1616 pool.addHashedExtraAssumeCapacityTo(scratch, &hasher, Field, .{
1617 .name = field_name.index,
1618 .ctype = field_ctype.index,
1619 .flags = .{ .alignas = field_alignas },
1620 });
1621 if (field_alignas.abiOrder().compare(.lt))
1622 tag = .aggregate_struct_packed;
1623 }
1624 const fields_len: u32 = @intCast(@divExact(
1625 scratch.items.len - scratch_top,
1626 @typeInfo(Field).Struct.fields.len,
1627 ));
1628 if (fields_len == 0) return .{ .index = .void };
1629 try pool.ensureUnusedCapacity(allocator, 1);
1630 const extra_index = try pool.addHashedExtra(allocator, &hasher, Aggregate, .{
1631 .fwd_decl = fwd_decl.index,
1632 .fields_len = fields_len,
1633 }, fields_len * @typeInfo(Field).Struct.fields.len);
1634 pool.extra.appendSliceAssumeCapacity(scratch.items[scratch_top..]);
1635 return pool.tagTrailingExtraAssumeCapacity(hasher, tag, extra_index);
1636 },
1637 .@"packed" => return pool.fromType(
1638 allocator,
1639 scratch,
1640 Type.fromInterned(loaded_struct.backingIntType(ip).*),
1641 zcu,
1642 mod,
1643 kind,
1644 ),
1645 }
1646 },
1647 .anon_struct_type => |anon_struct_info| {
1648 const scratch_top = scratch.items.len;
1649 defer scratch.shrinkRetainingCapacity(scratch_top);
1650 try scratch.ensureUnusedCapacity(allocator, anon_struct_info.types.len *
1651 @typeInfo(Field).Struct.fields.len);
1652 var hasher = Hasher.init;
1653 for (0..anon_struct_info.types.len) |field_index| {
1654 if (anon_struct_info.values.get(ip)[field_index] != .none) continue;
1655 const field_type = Type.fromInterned(
1656 anon_struct_info.types.get(ip)[field_index],
1657 );
1658 const field_ctype = try pool.fromType(
1659 allocator,
1660 scratch,
1661 field_type,
1662 zcu,
1663 mod,
1664 kind.noParameter(),
1665 );
1666 if (field_ctype.index == .void) continue;
1667 const field_name = if (anon_struct_info.fieldName(ip, @intCast(field_index))
1668 .unwrap()) |field_name|
1669 try pool.string(allocator, ip.stringToSlice(field_name))
1670 else
1671 try pool.fmt(allocator, "f{d}", .{field_index});
1672 pool.addHashedExtraAssumeCapacityTo(scratch, &hasher, Field, .{
1673 .name = field_name.index,
1674 .ctype = field_ctype.index,
1675 .flags = .{ .alignas = AlignAs.fromAbiAlignment(
1676 field_type.abiAlignment(zcu),
1677 ) },
1678 });
1679 }
1680 const fields_len: u32 = @intCast(@divExact(
1681 scratch.items.len - scratch_top,
1682 @typeInfo(Field).Struct.fields.len,
1683 ));
1684 if (fields_len == 0) return .{ .index = .void };
1685 if (kind.isForward()) {
1686 try pool.ensureUnusedCapacity(allocator, 1);
1687 const extra_index = try pool.addHashedExtra(
1688 allocator,
1689 &hasher,
1690 FwdDeclAnon,
1691 .{ .fields_len = fields_len },
1692 fields_len * @typeInfo(Field).Struct.fields.len,
1693 );
1694 pool.extra.appendSliceAssumeCapacity(scratch.items[scratch_top..]);
1695 return pool.tagTrailingExtra(
1696 allocator,
1697 hasher,
1698 .fwd_decl_struct_anon,
1699 extra_index,
1700 );
1701 }
1702 const fwd_decl = try pool.fromType(allocator, scratch, ty, zcu, mod, .forward);
1703 try pool.ensureUnusedCapacity(allocator, 1);
1704 const extra_index = try pool.addHashedExtra(allocator, &hasher, Aggregate, .{
1705 .fwd_decl = fwd_decl.index,
1706 .fields_len = fields_len,
1707 }, fields_len * @typeInfo(Field).Struct.fields.len);
1708 pool.extra.appendSliceAssumeCapacity(scratch.items[scratch_top..]);
1709 return pool.tagTrailingExtraAssumeCapacity(hasher, .aggregate_struct, extra_index);
1710 },
1711 .union_type => {
1712 const loaded_union = ip.loadUnionType(ip_index);
1713 switch (loaded_union.getLayout(ip)) {
1714 .auto, .@"extern" => {
1715 const has_tag = loaded_union.hasTag(ip);
1716 const fwd_decl = try pool.getFwdDecl(allocator, .{
1717 .tag = if (has_tag) .@"struct" else .@"union",
1718 .name = .{ .owner_decl = loaded_union.decl },
1719 });
1720 if (kind.isForward()) return if (ty.hasRuntimeBitsIgnoreComptime(zcu))
1721 fwd_decl
1722 else
1723 .{ .index = .void };
1724 const loaded_tag = loaded_union.loadTagType(ip);
1725 const scratch_top = scratch.items.len;
1726 defer scratch.shrinkRetainingCapacity(scratch_top);
1727 try scratch.ensureUnusedCapacity(
1728 allocator,
1729 loaded_union.field_types.len * @typeInfo(Field).Struct.fields.len,
1730 );
1731 var hasher = Hasher.init;
1732 var tag: Tag = .aggregate_union;
1733 var payload_align: Alignment = .@"1";
1734 for (0..loaded_union.field_types.len) |field_index| {
1735 const field_type = Type.fromInterned(
1736 loaded_union.field_types.get(ip)[field_index],
1737 );
1738 if (ip.isNoReturn(field_type.toIntern())) continue;
1739 const field_ctype = try pool.fromType(
1740 allocator,
1741 scratch,
1742 field_type,
1743 zcu,
1744 mod,
1745 kind.noParameter(),
1746 );
1747 if (field_ctype.index == .void) continue;
1748 const field_name = try pool.string(
1749 allocator,
1750 ip.stringToSlice(loaded_tag.names.get(ip)[field_index]),
1751 );
1752 const field_alignas = AlignAs.fromAlignment(.{
1753 .@"align" = loaded_union.fieldAlign(ip, @intCast(field_index)),
1754 .abi = field_type.abiAlignment(zcu),
1755 });
1756 pool.addHashedExtraAssumeCapacityTo(scratch, &hasher, Field, .{
1757 .name = field_name.index,
1758 .ctype = field_ctype.index,
1759 .flags = .{ .alignas = field_alignas },
1760 });
1761 if (field_alignas.abiOrder().compare(.lt))
1762 tag = .aggregate_union_packed;
1763 payload_align = payload_align.maxStrict(field_alignas.@"align");
1764 }
1765 const fields_len: u32 = @intCast(@divExact(
1766 scratch.items.len - scratch_top,
1767 @typeInfo(Field).Struct.fields.len,
1768 ));
1769 if (!has_tag) {
1770 if (fields_len == 0) return .{ .index = .void };
1771 try pool.ensureUnusedCapacity(allocator, 1);
1772 const extra_index = try pool.addHashedExtra(
1773 allocator,
1774 &hasher,
1775 Aggregate,
1776 .{ .fwd_decl = fwd_decl.index, .fields_len = fields_len },
1777 fields_len * @typeInfo(Field).Struct.fields.len,
1778 );
1779 pool.extra.appendSliceAssumeCapacity(scratch.items[scratch_top..]);
1780 return pool.tagTrailingExtraAssumeCapacity(hasher, tag, extra_index);
1781 }
1782 try pool.ensureUnusedCapacity(allocator, 2);
1783 var struct_fields: [2]Info.Field = undefined;
1784 var struct_fields_len: usize = 0;
1785 if (loaded_tag.tag_ty != .comptime_int_type) {
1786 const tag_type = Type.fromInterned(loaded_tag.tag_ty);
1787 const tag_ctype: CType = try pool.fromType(
1788 allocator,
1789 scratch,
1790 tag_type,
1791 zcu,
1792 mod,
1793 kind.noParameter(),
1794 );
1795 if (tag_ctype.index != .void) {
1796 struct_fields[struct_fields_len] = .{
1797 .name = try pool.string(allocator, "tag"),
1798 .ctype = tag_ctype,
1799 .alignas = AlignAs.fromAbiAlignment(tag_type.abiAlignment(zcu)),
1800 };
1801 struct_fields_len += 1;
1802 }
1803 }
1804 if (fields_len > 0) {
1805 const payload_ctype = payload_ctype: {
1806 const extra_index = try pool.addHashedExtra(
1807 allocator,
1808 &hasher,
1809 AggregateAnon,
1810 .{
1811 .owner_decl = loaded_union.decl,
1812 .id = 0,
1813 .fields_len = fields_len,
1814 },
1815 fields_len * @typeInfo(Field).Struct.fields.len,
1816 );
1817 pool.extra.appendSliceAssumeCapacity(scratch.items[scratch_top..]);
1818 break :payload_ctype pool.tagTrailingExtraAssumeCapacity(
1819 hasher,
1820 switch (tag) {
1821 .aggregate_union => .aggregate_union_anon,
1822 .aggregate_union_packed => .aggregate_union_packed_anon,
1823 else => unreachable,
1824 },
1825 extra_index,
1826 );
1827 };
1828 if (payload_ctype.index != .void) {
1829 struct_fields[struct_fields_len] = .{
1830 .name = try pool.string(allocator, "payload"),
1831 .ctype = payload_ctype,
1832 .alignas = AlignAs.fromAbiAlignment(payload_align),
1833 };
1834 struct_fields_len += 1;
1835 }
1836 }
1837 if (struct_fields_len == 0) return .{ .index = .void };
1838 sortFields(struct_fields[0..struct_fields_len]);
1839 return pool.getAggregate(allocator, .{
1840 .tag = .@"struct",
1841 .name = .{ .fwd_decl = fwd_decl },
1842 .fields = struct_fields[0..struct_fields_len],
1843 });
1844 },
1845 .@"packed" => return pool.fromIntInfo(allocator, .{
1846 .signedness = .unsigned,
1847 .bits = @intCast(ty.bitSize(zcu)),
1848 }, mod, kind),
1849 }
1850 },
1851 .opaque_type => return .{ .index = .void },
1852 .enum_type => return pool.fromType(
1853 allocator,
1854 scratch,
1855 Type.fromInterned(ip.loadEnumType(ip_index).tag_ty),
1856 zcu,
1857 mod,
1858 kind,
1859 ),
1860 .func_type => |func_info| if (func_info.is_generic) return .{ .index = .void } else {
1861 const scratch_top = scratch.items.len;
1862 defer scratch.shrinkRetainingCapacity(scratch_top);
1863 try scratch.ensureUnusedCapacity(allocator, func_info.param_types.len);
1864 var hasher = Hasher.init;
1865 const return_type = Type.fromInterned(func_info.return_type);
1866 const return_ctype: CType =
1867 if (!ip.isNoReturn(func_info.return_type)) try pool.fromType(
1868 allocator,
1869 scratch,
1870 return_type,
1871 zcu,
1872 mod,
1873 kind.asParameter(),
1874 ) else .{ .index = .void };
1875 for (0..func_info.param_types.len) |param_index| {
1876 const param_type = Type.fromInterned(
1877 func_info.param_types.get(ip)[param_index],
1878 );
1879 const param_ctype = try pool.fromType(
1880 allocator,
1881 scratch,
1882 param_type,
1883 zcu,
1884 mod,
1885 kind.asParameter(),
1886 );
1887 if (param_ctype.index == .void) continue;
1888 hasher.update(param_ctype.hash(pool));
1889 scratch.appendAssumeCapacity(@intFromEnum(param_ctype.index));
1890 }
1891 const param_ctypes_len: u32 = @intCast(scratch.items.len - scratch_top);
1892 try pool.ensureUnusedCapacity(allocator, 1);
1893 const extra_index = try pool.addHashedExtra(allocator, &hasher, Function, .{
1894 .return_ctype = return_ctype.index,
1895 .param_ctypes_len = param_ctypes_len,
1896 }, param_ctypes_len);
1897 pool.extra.appendSliceAssumeCapacity(scratch.items[scratch_top..]);
1898 return pool.tagTrailingExtraAssumeCapacity(hasher, switch (func_info.is_var_args) {
1899 false => .function,
1900 true => .function_varargs,
1901 }, extra_index);
1902 },
1903 .error_set_type,
1904 .inferred_error_set_type,
1905 => return pool.fromIntInfo(allocator, .{
1906 .signedness = .unsigned,
1907 .bits = zcu.errorSetBits(),
1908 }, mod, kind),
1909
1910 .undef,
1911 .simple_value,
1912 .variable,
1913 .extern_func,
1914 .func,
1915 .int,
1916 .err,
1917 .error_union,
1918 .enum_literal,
1919 .enum_tag,
1920 .empty_enum_value,
1921 .float,
1922 .ptr,
1923 .slice,
1924 .opt,
1925 .aggregate,
1926 .un,
1927 .memoized_call,
1928 => unreachable,
1929 },
1930 }
1931 }
1932
1933 pub fn getOrPutAdapted(
1934 pool: *Pool,
1935 allocator: std.mem.Allocator,
1936 source_pool: *const Pool,
1937 source_ctype: CType,
1938 pool_adapter: anytype,
1939 ) !struct { CType, bool } {
1940 const tag = source_pool.items.items(.tag)[
1941 source_ctype.toPoolIndex() orelse return .{ source_ctype, true }
1942 ];
1943 try pool.ensureUnusedCapacity(allocator, 1);
1944 const CTypeAdapter = struct {
1945 pool: *const Pool,
1946 source_pool: *const Pool,
1947 source_info: Info,
1948 pool_adapter: @TypeOf(pool_adapter),
1949 pub fn hash(map_adapter: @This(), key_ctype: CType) Map.Hash {
1950 return key_ctype.hash(map_adapter.source_pool);
1951 }
1952 pub fn eql(map_adapter: @This(), _: CType, _: void, pool_index: usize) bool {
1953 return map_adapter.source_info.eqlAdapted(
1954 map_adapter.source_pool,
1955 CType.fromPoolIndex(pool_index),
1956 map_adapter.pool,
1957 map_adapter.pool_adapter,
1958 );
1959 }
1960 };
1961 const source_info = source_ctype.info(source_pool);
1962 const gop = pool.map.getOrPutAssumeCapacityAdapted(source_ctype, CTypeAdapter{
1963 .pool = pool,
1964 .source_pool = source_pool,
1965 .source_info = source_info,
1966 .pool_adapter = pool_adapter,
1967 });
1968 errdefer _ = pool.map.pop();
1969 const ctype = CType.fromPoolIndex(gop.index);
1970 if (!gop.found_existing) switch (source_info) {
1971 .basic => unreachable,
1972 .pointer => |pointer_info| pool.items.appendAssumeCapacity(.{
1973 .tag = tag,
1974 .data = @intFromEnum(pool_adapter.copy(pointer_info.elem_ctype).index),
1975 }),
1976 .aligned => |aligned_info| pool.items.appendAssumeCapacity(.{
1977 .tag = tag,
1978 .data = try pool.addExtra(allocator, Aligned, .{
1979 .ctype = pool_adapter.copy(aligned_info.ctype).index,
1980 .flags = .{ .alignas = aligned_info.alignas },
1981 }, 0),
1982 }),
1983 .array, .vector => |sequence_info| pool.items.appendAssumeCapacity(.{
1984 .tag = tag,
1985 .data = switch (tag) {
1986 .array_small, .vector => try pool.addExtra(allocator, SequenceSmall, .{
1987 .elem_ctype = pool_adapter.copy(sequence_info.elem_ctype).index,
1988 .len = @intCast(sequence_info.len),
1989 }, 0),
1990 .array_large => try pool.addExtra(allocator, SequenceLarge, .{
1991 .elem_ctype = pool_adapter.copy(sequence_info.elem_ctype).index,
1992 .len_lo = @truncate(sequence_info.len >> 0),
1993 .len_hi = @truncate(sequence_info.len >> 32),
1994 }, 0),
1995 else => unreachable,
1996 },
1997 }),
1998 .fwd_decl => |fwd_decl_info| switch (fwd_decl_info.name) {
1999 .anon => |fields| {
2000 pool.items.appendAssumeCapacity(.{
2001 .tag = tag,
2002 .data = try pool.addExtra(allocator, FwdDeclAnon, .{
2003 .fields_len = fields.len,
2004 }, fields.len * @typeInfo(Field).Struct.fields.len),
2005 });
2006 for (0..fields.len) |field_index| {
2007 const field = fields.at(field_index, source_pool);
2008 const field_name = try pool.string(allocator, field.name.slice(source_pool));
2009 pool.addExtraAssumeCapacity(Field, .{
2010 .name = field_name.index,
2011 .ctype = pool_adapter.copy(field.ctype).index,
2012 .flags = .{ .alignas = field.alignas },
2013 });
2014 }
2015 },
2016 .owner_decl => |owner_decl| pool.items.appendAssumeCapacity(.{
2017 .tag = tag,
2018 .data = @intFromEnum(owner_decl),
2019 }),
2020 },
2021 .aggregate => |aggregate_info| {
2022 pool.items.appendAssumeCapacity(.{
2023 .tag = tag,
2024 .data = switch (aggregate_info.name) {
2025 .anon => |anon| try pool.addExtra(allocator, AggregateAnon, .{
2026 .owner_decl = anon.owner_decl,
2027 .id = anon.id,
2028 .fields_len = aggregate_info.fields.len,
2029 }, aggregate_info.fields.len * @typeInfo(Field).Struct.fields.len),
2030 .fwd_decl => |fwd_decl| try pool.addExtra(allocator, Aggregate, .{
2031 .fwd_decl = pool_adapter.copy(fwd_decl).index,
2032 .fields_len = aggregate_info.fields.len,
2033 }, aggregate_info.fields.len * @typeInfo(Field).Struct.fields.len),
2034 },
2035 });
2036 for (0..aggregate_info.fields.len) |field_index| {
2037 const field = aggregate_info.fields.at(field_index, source_pool);
2038 const field_name = try pool.string(allocator, field.name.slice(source_pool));
2039 pool.addExtraAssumeCapacity(Field, .{
2040 .name = field_name.index,
2041 .ctype = pool_adapter.copy(field.ctype).index,
2042 .flags = .{ .alignas = field.alignas },
2043 });
2044 }
2045 },
2046 .function => |function_info| {
2047 pool.items.appendAssumeCapacity(.{
2048 .tag = tag,
2049 .data = try pool.addExtra(allocator, Function, .{
2050 .return_ctype = pool_adapter.copy(function_info.return_ctype).index,
2051 .param_ctypes_len = function_info.param_ctypes.len,
2052 }, function_info.param_ctypes.len),
2053 });
2054 for (0..function_info.param_ctypes.len) |param_index| pool.extra.appendAssumeCapacity(
2055 @intFromEnum(pool_adapter.copy(
2056 function_info.param_ctypes.at(param_index, source_pool),
2057 ).index),
2058 );
2059 },
2060 };
2061 assert(source_info.eqlAdapted(source_pool, ctype, pool, pool_adapter));
2062 assert(source_ctype.hash(source_pool) == ctype.hash(pool));
2063 return .{ ctype, gop.found_existing };
2064 }
2065
2066 pub fn string(pool: *Pool, allocator: std.mem.Allocator, str: []const u8) !String {
2067 try pool.string_bytes.appendSlice(allocator, str);
2068 return pool.trailingString(allocator);
2069 }
2070
2071 pub fn fmt(
2072 pool: *Pool,
2073 allocator: std.mem.Allocator,
2074 comptime fmt_str: []const u8,
2075 fmt_args: anytype,
2076 ) !String {
2077 try pool.string_bytes.writer(allocator).print(fmt_str, fmt_args);
2078 return pool.trailingString(allocator);
2079 }
2080
2081 fn ensureUnusedCapacity(pool: *Pool, allocator: std.mem.Allocator, len: u32) !void {
2082 try pool.map.ensureUnusedCapacity(allocator, len);
2083 try pool.items.ensureUnusedCapacity(allocator, len);
2084 }
2085
2086 const Hasher = struct {
2087 const Impl = std.hash.Wyhash;
2088 impl: Impl,
2089
2090 const init: Hasher = .{ .impl = Impl.init(0) };
2091
2092 fn updateExtra(hasher: *Hasher, comptime Extra: type, extra: Extra, pool: *const Pool) void {
2093 inline for (@typeInfo(Extra).Struct.fields) |field| {
2094 const value = @field(extra, field.name);
2095 hasher.update(switch (field.type) {
2096 Tag, String, CType => unreachable,
2097 CType.Index => (CType{ .index = value }).hash(pool),
2098 String.Index => (String{ .index = value }).slice(pool),
2099 else => value,
2100 });
2101 }
2102 }
2103 fn update(hasher: *Hasher, data: anytype) void {
2104 switch (@TypeOf(data)) {
2105 Tag => @compileError("pass tag to final"),
2106 CType, CType.Index => @compileError("hash ctype.hash(pool) instead"),
2107 String, String.Index => @compileError("hash string.slice(pool) instead"),
2108 u32, DeclIndex, Aligned.Flags => hasher.impl.update(std.mem.asBytes(&data)),
2109 []const u8 => hasher.impl.update(data),
2110 else => @compileError("unhandled type: " ++ @typeName(@TypeOf(data))),
2111 }
2112 }
2113
2114 fn final(hasher: Hasher, tag: Tag) Map.Hash {
2115 var impl = hasher.impl;
2116 impl.update(std.mem.asBytes(&tag));
2117 return @truncate(impl.final());
2118 }
2119 };
2120
2121 fn tagData(
2122 pool: *Pool,
2123 allocator: std.mem.Allocator,
2124 hasher: Hasher,
2125 tag: Tag,
2126 data: u32,
2127 ) !CType {
2128 try pool.ensureUnusedCapacity(allocator, 1);
2129 const Key = struct { hash: Map.Hash, tag: Tag, data: u32 };
2130 const CTypeAdapter = struct {
2131 pool: *const Pool,
2132 pub fn hash(_: @This(), key: Key) Map.Hash {
2133 return key.hash;
2134 }
2135 pub fn eql(ctype_adapter: @This(), lhs_key: Key, _: void, rhs_index: usize) bool {
2136 const rhs_item = ctype_adapter.pool.items.get(rhs_index);
2137 return lhs_key.tag == rhs_item.tag and lhs_key.data == rhs_item.data;
2138 }
2139 };
2140 const gop = pool.map.getOrPutAssumeCapacityAdapted(
2141 Key{ .hash = hasher.final(tag), .tag = tag, .data = data },
2142 CTypeAdapter{ .pool = pool },
2143 );
2144 if (!gop.found_existing) pool.items.appendAssumeCapacity(.{ .tag = tag, .data = data });
2145 return CType.fromPoolIndex(gop.index);
2146 }
2147
2148 fn tagExtra(
2149 pool: *Pool,
2150 allocator: std.mem.Allocator,
2151 tag: Tag,
2152 comptime Extra: type,
2153 extra: Extra,
2154 ) !CType {
2155 var hasher = Hasher.init;
2156 hasher.updateExtra(Extra, extra, pool);
2157 return pool.tagTrailingExtra(
2158 allocator,
2159 hasher,
2160 tag,
2161 try pool.addExtra(allocator, Extra, extra, 0),
2162 );
2163 }
2164
2165 fn tagTrailingExtra(
2166 pool: *Pool,
2167 allocator: std.mem.Allocator,
2168 hasher: Hasher,
2169 tag: Tag,
2170 extra_index: ExtraIndex,
2171 ) !CType {
2172 try pool.ensureUnusedCapacity(allocator, 1);
2173 return pool.tagTrailingExtraAssumeCapacity(hasher, tag, extra_index);
2174 }
2175
2176 fn tagTrailingExtraAssumeCapacity(
2177 pool: *Pool,
2178 hasher: Hasher,
2179 tag: Tag,
2180 extra_index: ExtraIndex,
2181 ) CType {
2182 const Key = struct { hash: Map.Hash, tag: Tag, extra: []const u32 };
2183 const CTypeAdapter = struct {
2184 pool: *const Pool,
2185 pub fn hash(_: @This(), key: Key) Map.Hash {
2186 return key.hash;
2187 }
2188 pub fn eql(ctype_adapter: @This(), lhs_key: Key, _: void, rhs_index: usize) bool {
2189 const rhs_item = ctype_adapter.pool.items.get(rhs_index);
2190 if (lhs_key.tag != rhs_item.tag) return false;
2191 const rhs_extra = ctype_adapter.pool.extra.items[rhs_item.data..];
2192 return std.mem.startsWith(u32, rhs_extra, lhs_key.extra);
2193 }
2194 };
2195 const gop = pool.map.getOrPutAssumeCapacityAdapted(
2196 Key{ .hash = hasher.final(tag), .tag = tag, .extra = pool.extra.items[extra_index..] },
2197 CTypeAdapter{ .pool = pool },
2198 );
2199 if (gop.found_existing)
2200 pool.extra.shrinkRetainingCapacity(extra_index)
2201 else
2202 pool.items.appendAssumeCapacity(.{ .tag = tag, .data = extra_index });
2203 return CType.fromPoolIndex(gop.index);
2204 }
2205
2206 fn sortFields(fields: []Info.Field) void {
2207 std.mem.sort(Info.Field, fields, {}, struct {
2208 fn before(_: void, lhs_field: Info.Field, rhs_field: Info.Field) bool {
2209 return lhs_field.alignas.order(rhs_field.alignas).compare(.gt);
2210 }
2211 }.before);
2212 }
2213
2214 fn trailingString(pool: *Pool, allocator: std.mem.Allocator) !String {
2215 const StringAdapter = struct {
2216 pool: *const Pool,
2217 pub fn hash(_: @This(), slice: []const u8) Map.Hash {
2218 return @truncate(Hasher.Impl.hash(1, slice));
2219 }
2220 pub fn eql(string_adapter: @This(), lhs_slice: []const u8, _: void, rhs_index: usize) bool {
2221 const rhs_string: String = .{ .index = @enumFromInt(rhs_index) };
2222 const rhs_slice = rhs_string.slice(string_adapter.pool);
2223 return std.mem.eql(u8, lhs_slice, rhs_slice);
2224 }
2225 };
2226 try pool.string_map.ensureUnusedCapacity(allocator, 1);
2227 try pool.string_indices.ensureUnusedCapacity(allocator, 1);
2228
2229 const start = pool.string_indices.getLast();
2230 const gop = pool.string_map.getOrPutAssumeCapacityAdapted(
2231 @as([]const u8, pool.string_bytes.items[start..]),
2232 StringAdapter{ .pool = pool },
2233 );
2234 if (gop.found_existing)
2235 pool.string_bytes.shrinkRetainingCapacity(start)
2236 else
2237 pool.string_indices.appendAssumeCapacity(@intCast(pool.string_bytes.items.len));
2238 return .{ .index = @enumFromInt(gop.index) };
2239 }
2240
2241 const Item = struct {
2242 tag: Tag,
2243 data: u32,
2244 };
2245
2246 const ExtraIndex = u32;
2247
2248 const Tag = enum(u8) {
2249 basic,
2250 pointer,
2251 pointer_const,
2252 pointer_volatile,
2253 pointer_const_volatile,
2254 aligned,
2255 array_small,
2256 array_large,
2257 vector,
2258 fwd_decl_struct_anon,
2259 fwd_decl_union_anon,
2260 fwd_decl_struct,
2261 fwd_decl_union,
2262 aggregate_struct_anon,
2263 aggregate_struct_packed_anon,
2264 aggregate_union_anon,
2265 aggregate_union_packed_anon,
2266 aggregate_struct,
2267 aggregate_struct_packed,
2268 aggregate_union,
2269 aggregate_union_packed,
2270 function,
2271 function_varargs,
2272 };
2273
2274 const Aligned = struct {
2275 ctype: CType.Index,
2276 flags: Flags,
2277
2278 const Flags = packed struct(u32) {
2279 alignas: AlignAs,
2280 _: u20 = 0,
2281 };
2282 };
2283
2284 const SequenceSmall = struct {
2285 elem_ctype: CType.Index,
2286 len: u32,
2287 };
2288
2289 const SequenceLarge = struct {
2290 elem_ctype: CType.Index,
2291 len_lo: u32,
2292 len_hi: u32,
2293
2294 fn len(extra: SequenceLarge) u64 {
2295 return @as(u64, extra.len_lo) << 0 |
2296 @as(u64, extra.len_hi) << 32;
2297 }
2298 };
2299
2300 const Field = struct {
2301 name: String.Index,
2302 ctype: CType.Index,
2303 flags: Flags,
2304
2305 const Flags = Aligned.Flags;
2306 };
2307
2308 const FwdDeclAnon = struct {
2309 fields_len: u32,
2310 };
2311
2312 const AggregateAnon = struct {
2313 owner_decl: DeclIndex,
2314 id: u32,
2315 fields_len: u32,
2316 };
2317
2318 const Aggregate = struct {
2319 fwd_decl: CType.Index,
2320 fields_len: u32,
2321 };
2322
2323 const Function = struct {
2324 return_ctype: CType.Index,
2325 param_ctypes_len: u32,
2326 };
2327
2328 fn addExtra(
2329 pool: *Pool,
2330 allocator: std.mem.Allocator,
2331 comptime Extra: type,
2332 extra: Extra,
2333 trailing_len: usize,
2334 ) !ExtraIndex {
2335 try pool.extra.ensureUnusedCapacity(
2336 allocator,
2337 @typeInfo(Extra).Struct.fields.len + trailing_len,
2338 );
2339 defer pool.addExtraAssumeCapacity(Extra, extra);
2340 return @intCast(pool.extra.items.len);
2341 }
2342 fn addExtraAssumeCapacity(pool: *Pool, comptime Extra: type, extra: Extra) void {
2343 addExtraAssumeCapacityTo(&pool.extra, Extra, extra);
2344 }
2345 fn addExtraAssumeCapacityTo(
2346 array: *std.ArrayListUnmanaged(u32),
2347 comptime Extra: type,
2348 extra: Extra,
2349 ) void {
2350 inline for (@typeInfo(Extra).Struct.fields) |field| {
2351 const value = @field(extra, field.name);
2352 array.appendAssumeCapacity(switch (field.type) {
2353 u32 => value,
2354 CType.Index, String.Index, DeclIndex => @intFromEnum(value),
2355 Aligned.Flags => @bitCast(value),
2356 else => @compileError("bad field type: " ++ field.name ++ ": " ++
2357 @typeName(field.type)),
2358 });
2359 }
2360 }
2361
2362 fn addHashedExtra(
2363 pool: *Pool,
2364 allocator: std.mem.Allocator,
2365 hasher: *Hasher,
2366 comptime Extra: type,
2367 extra: Extra,
2368 trailing_len: usize,
2369 ) !ExtraIndex {
2370 hasher.updateExtra(Extra, extra, pool);
2371 return pool.addExtra(allocator, Extra, extra, trailing_len);
2372 }
2373 fn addHashedExtraAssumeCapacity(
2374 pool: *Pool,
2375 hasher: *Hasher,
2376 comptime Extra: type,
2377 extra: Extra,
2378 ) void {
2379 hasher.updateExtra(Extra, extra, pool);
2380 pool.addExtraAssumeCapacity(Extra, extra);
2381 }
2382 fn addHashedExtraAssumeCapacityTo(
2383 pool: *Pool,
2384 array: *std.ArrayListUnmanaged(u32),
2385 hasher: *Hasher,
2386 comptime Extra: type,
2387 extra: Extra,
2388 ) void {
2389 hasher.updateExtra(Extra, extra, pool);
2390 addExtraAssumeCapacityTo(array, Extra, extra);
2391 }
2392
2393 const ExtraTrail = struct {
2394 extra_index: ExtraIndex,
2395
2396 fn next(
2397 extra_trail: *ExtraTrail,
2398 len: u32,
2399 comptime Extra: type,
2400 pool: *const Pool,
2401 ) []const Extra {
2402 defer extra_trail.extra_index += @intCast(len);
2403 return @ptrCast(pool.extra.items[extra_trail.extra_index..][0..len]);
2404 }
2405 };
2406
2407 fn getExtraTrail(
2408 pool: *const Pool,
2409 comptime Extra: type,
2410 extra_index: ExtraIndex,
2411 ) struct { extra: Extra, trail: ExtraTrail } {
2412 var extra: Extra = undefined;
2413 const fields = @typeInfo(Extra).Struct.fields;
2414 inline for (fields, pool.extra.items[extra_index..][0..fields.len]) |field, value|
2415 @field(extra, field.name) = switch (field.type) {
2416 u32 => value,
2417 CType.Index, String.Index, DeclIndex => @enumFromInt(value),
2418 Aligned.Flags => @bitCast(value),
2419 else => @compileError("bad field type: " ++ field.name ++ ": " ++ @typeName(field.type)),
2420 };
2421 return .{
2422 .extra = extra,
2423 .trail = .{ .extra_index = extra_index + @as(ExtraIndex, @intCast(fields.len)) },
2424 };
2425 }
2426
2427 fn getExtra(pool: *const Pool, comptime Extra: type, extra_index: ExtraIndex) Extra {
2428 return pool.getExtraTrail(Extra, extra_index).extra;
2429 }
2430};
2431
2432pub const AlignAs = packed struct {
2433 @"align": Alignment,
2434 abi: Alignment,
2435
2436 pub fn fromAlignment(alignas: AlignAs) AlignAs {
2437 assert(alignas.abi != .none);
2438 return .{
2439 .@"align" = if (alignas.@"align" != .none) alignas.@"align" else alignas.abi,
2440 .abi = alignas.abi,
2441 };
2442 }
2443 pub fn fromAbiAlignment(abi: Alignment) AlignAs {
2444 assert(abi != .none);
2445 return .{ .@"align" = abi, .abi = abi };
2446 }
2447 pub fn fromByteUnits(@"align": u64, abi: u64) AlignAs {
2448 return fromAlignment(.{
2449 .@"align" = Alignment.fromByteUnits(@"align"),
2450 .abi = Alignment.fromNonzeroByteUnits(abi),
2451 });
2452 }
2453
2454 pub fn order(lhs: AlignAs, rhs: AlignAs) std.math.Order {
2455 return lhs.@"align".order(rhs.@"align");
2456 }
2457 pub fn abiOrder(alignas: AlignAs) std.math.Order {
2458 return alignas.@"align".order(alignas.abi);
2459 }
2460 pub fn toByteUnits(alignas: AlignAs) u64 {
2461 return alignas.@"align".toByteUnits().?;
2462 }
2463};
2464
2465const Alignment = @import("../../InternPool.zig").Alignment;
2466const assert = std.debug.assert;
2467const CType = @This();
2468const DeclIndex = std.zig.DeclIndex;
2469const Module = @import("../../Package/Module.zig");
2470const std = @import("std");
2471const Type = @import("../../type.zig").Type;
2472const Zcu = @import("../../Module.zig");
src/codegen/c/type.zig deleted-2332
......@@ -1,2332 +0,0 @@
1const std = @import("std");
2const mem = std.mem;
3const Allocator = mem.Allocator;
4const assert = std.debug.assert;
5const autoHash = std.hash.autoHash;
6
7const Alignment = @import("../../InternPool.zig").Alignment;
8const Zcu = @import("../../Module.zig");
9const Module = @import("../../Package/Module.zig");
10const InternPool = @import("../../InternPool.zig");
11const Type = @import("../../type.zig").Type;
12
13pub const CType = extern union {
14 /// If the tag value is less than Tag.no_payload_count, then no pointer
15 /// dereference is needed.
16 tag_if_small_enough: Tag,
17 ptr_otherwise: *const Payload,
18
19 pub fn initTag(small_tag: Tag) CType {
20 assert(!small_tag.hasPayload());
21 return .{ .tag_if_small_enough = small_tag };
22 }
23
24 pub fn initPayload(pl: anytype) CType {
25 const T = @typeInfo(@TypeOf(pl)).Pointer.child;
26 return switch (pl.base.tag) {
27 inline else => |t| if (comptime t.hasPayload() and t.Type() == T) .{
28 .ptr_otherwise = &pl.base,
29 } else unreachable,
30 };
31 }
32
33 pub fn hasPayload(self: CType) bool {
34 return self.tag_if_small_enough.hasPayload();
35 }
36
37 pub fn tag(self: CType) Tag {
38 return if (self.hasPayload()) self.ptr_otherwise.tag else self.tag_if_small_enough;
39 }
40
41 pub fn cast(self: CType, comptime T: type) ?*const T {
42 if (!self.hasPayload()) return null;
43 const pl = self.ptr_otherwise;
44 return switch (pl.tag) {
45 inline else => |t| if (comptime t.hasPayload() and t.Type() == T)
46 @fieldParentPtr(T, "base", pl)
47 else
48 null,
49 };
50 }
51
52 pub fn castTag(self: CType, comptime t: Tag) ?*const t.Type() {
53 return if (self.tag() == t) @fieldParentPtr(t.Type(), "base", self.ptr_otherwise) else null;
54 }
55
56 pub const Tag = enum(usize) {
57 // The first section of this enum are tags that require no payload.
58 void,
59
60 // C basic types
61 char,
62
63 @"signed char",
64 short,
65 int,
66 long,
67 @"long long",
68
69 _Bool,
70 @"unsigned char",
71 @"unsigned short",
72 @"unsigned int",
73 @"unsigned long",
74 @"unsigned long long",
75
76 float,
77 double,
78 @"long double",
79
80 // C header types
81 // - stdbool.h
82 bool,
83 // - stddef.h
84 size_t,
85 ptrdiff_t,
86 // - stdint.h
87 uint8_t,
88 int8_t,
89 uint16_t,
90 int16_t,
91 uint32_t,
92 int32_t,
93 uint64_t,
94 int64_t,
95 uintptr_t,
96 intptr_t,
97
98 // zig.h types
99 zig_u128,
100 zig_i128,
101 zig_f16,
102 zig_f32,
103 zig_f64,
104 zig_f80,
105 zig_f128,
106 zig_c_longdouble, // Keep last_no_payload_tag updated!
107
108 // After this, the tag requires a payload.
109 pointer,
110 pointer_const,
111 pointer_volatile,
112 pointer_const_volatile,
113 array,
114 vector,
115 fwd_anon_struct,
116 fwd_anon_union,
117 fwd_struct,
118 fwd_union,
119 unnamed_struct,
120 unnamed_union,
121 packed_unnamed_struct,
122 packed_unnamed_union,
123 anon_struct,
124 anon_union,
125 @"struct",
126 @"union",
127 packed_struct,
128 packed_union,
129 function,
130 varargs_function,
131
132 pub const last_no_payload_tag = Tag.zig_c_longdouble;
133 pub const no_payload_count = @intFromEnum(last_no_payload_tag) + 1;
134
135 pub fn hasPayload(self: Tag) bool {
136 return @intFromEnum(self) >= no_payload_count;
137 }
138
139 pub fn toIndex(self: Tag) Index {
140 assert(!self.hasPayload());
141 return @as(Index, @intCast(@intFromEnum(self)));
142 }
143
144 pub fn Type(comptime self: Tag) type {
145 return switch (self) {
146 .void,
147 .char,
148 .@"signed char",
149 .short,
150 .int,
151 .long,
152 .@"long long",
153 ._Bool,
154 .@"unsigned char",
155 .@"unsigned short",
156 .@"unsigned int",
157 .@"unsigned long",
158 .@"unsigned long long",
159 .float,
160 .double,
161 .@"long double",
162 .bool,
163 .size_t,
164 .ptrdiff_t,
165 .uint8_t,
166 .int8_t,
167 .uint16_t,
168 .int16_t,
169 .uint32_t,
170 .int32_t,
171 .uint64_t,
172 .int64_t,
173 .uintptr_t,
174 .intptr_t,
175 .zig_u128,
176 .zig_i128,
177 .zig_f16,
178 .zig_f32,
179 .zig_f64,
180 .zig_f80,
181 .zig_f128,
182 .zig_c_longdouble,
183 => @compileError("Type Tag " ++ @tagName(self) ++ " has no payload"),
184
185 .pointer,
186 .pointer_const,
187 .pointer_volatile,
188 .pointer_const_volatile,
189 => Payload.Child,
190
191 .array,
192 .vector,
193 => Payload.Sequence,
194
195 .fwd_anon_struct,
196 .fwd_anon_union,
197 => Payload.Fields,
198
199 .fwd_struct,
200 .fwd_union,
201 => Payload.FwdDecl,
202
203 .unnamed_struct,
204 .unnamed_union,
205 .packed_unnamed_struct,
206 .packed_unnamed_union,
207 => Payload.Unnamed,
208
209 .anon_struct,
210 .anon_union,
211 .@"struct",
212 .@"union",
213 .packed_struct,
214 .packed_union,
215 => Payload.Aggregate,
216
217 .function,
218 .varargs_function,
219 => Payload.Function,
220 };
221 }
222 };
223
224 pub const Payload = struct {
225 tag: Tag,
226
227 pub const Child = struct {
228 base: Payload,
229 data: Index,
230 };
231
232 pub const Sequence = struct {
233 base: Payload,
234 data: struct {
235 len: u64,
236 elem_type: Index,
237 },
238 };
239
240 pub const FwdDecl = struct {
241 base: Payload,
242 data: InternPool.DeclIndex,
243 };
244
245 pub const Fields = struct {
246 base: Payload,
247 data: Data,
248
249 pub const Data = []const Field;
250 pub const Field = struct {
251 name: [*:0]const u8,
252 type: Index,
253 alignas: AlignAs,
254 };
255 };
256
257 pub const Unnamed = struct {
258 base: Payload,
259 data: struct {
260 fields: Fields.Data,
261 owner_decl: InternPool.DeclIndex,
262 id: u32,
263 },
264 };
265
266 pub const Aggregate = struct {
267 base: Payload,
268 data: struct {
269 fields: Fields.Data,
270 fwd_decl: Index,
271 },
272 };
273
274 pub const Function = struct {
275 base: Payload,
276 data: struct {
277 return_type: Index,
278 param_types: []const Index,
279 },
280 };
281 };
282
283 pub const AlignAs = packed struct {
284 @"align": Alignment,
285 abi: Alignment,
286
287 pub fn init(@"align": Alignment, abi_align: Alignment) AlignAs {
288 assert(abi_align != .none);
289 return .{
290 .@"align" = if (@"align" != .none) @"align" else abi_align,
291 .abi = abi_align,
292 };
293 }
294
295 pub fn initByteUnits(alignment: u64, abi_alignment: u32) AlignAs {
296 return init(
297 Alignment.fromByteUnits(alignment),
298 Alignment.fromNonzeroByteUnits(abi_alignment),
299 );
300 }
301 pub fn abiAlign(ty: Type, zcu: *Zcu) AlignAs {
302 const abi_align = ty.abiAlignment(zcu);
303 return init(abi_align, abi_align);
304 }
305 pub fn fieldAlign(struct_ty: Type, field_i: usize, zcu: *Zcu) AlignAs {
306 return init(
307 struct_ty.structFieldAlign(field_i, zcu),
308 struct_ty.structFieldType(field_i, zcu).abiAlignment(zcu),
309 );
310 }
311 pub fn unionPayloadAlign(union_ty: Type, zcu: *Zcu) AlignAs {
312 const union_obj = zcu.typeToUnion(union_ty).?;
313 const union_payload_align = zcu.unionAbiAlignment(union_obj);
314 return init(union_payload_align, union_payload_align);
315 }
316
317 pub fn order(lhs: AlignAs, rhs: AlignAs) std.math.Order {
318 return lhs.@"align".order(rhs.@"align");
319 }
320 pub fn abiOrder(self: AlignAs) std.math.Order {
321 return self.@"align".order(self.abi);
322 }
323 pub fn toByteUnits(self: AlignAs) u64 {
324 return self.@"align".toByteUnitsOptional().?;
325 }
326 };
327
328 pub const Index = u32;
329 pub const Store = struct {
330 arena: std.heap.ArenaAllocator.State = .{},
331 set: Set = .{},
332
333 pub const Set = struct {
334 pub const Map = std.ArrayHashMapUnmanaged(CType, void, HashContext, true);
335 const HashContext = struct {
336 store: *const Set,
337
338 pub fn hash(self: @This(), cty: CType) Map.Hash {
339 return @as(Map.Hash, @truncate(cty.hash(self.store.*)));
340 }
341 pub fn eql(_: @This(), lhs: CType, rhs: CType, _: usize) bool {
342 return lhs.eql(rhs);
343 }
344 };
345
346 map: Map = .{},
347
348 pub fn indexToCType(self: Set, index: Index) CType {
349 if (index < Tag.no_payload_count) return initTag(@as(Tag, @enumFromInt(index)));
350 return self.map.keys()[index - Tag.no_payload_count];
351 }
352
353 pub fn indexToHash(self: Set, index: Index) Map.Hash {
354 if (index < Tag.no_payload_count)
355 return (HashContext{ .store = &self }).hash(self.indexToCType(index));
356 return self.map.entries.items(.hash)[index - Tag.no_payload_count];
357 }
358
359 pub fn typeToIndex(self: Set, ty: Type, zcu: *Zcu, mod: *Module, kind: Kind) ?Index {
360 const lookup = Convert.Lookup{ .imm = .{ .set = &self, .zcu = zcu, .mod = mod } };
361
362 var convert: Convert = undefined;
363 convert.initType(ty, kind, lookup) catch unreachable;
364
365 const t = convert.tag();
366 if (!t.hasPayload()) return t.toIndex();
367
368 return if (self.map.getIndexAdapted(
369 ty,
370 TypeAdapter32{ .kind = kind, .lookup = lookup, .convert = &convert },
371 )) |idx| @as(Index, @intCast(Tag.no_payload_count + idx)) else null;
372 }
373 };
374
375 pub const Promoted = struct {
376 arena: std.heap.ArenaAllocator,
377 set: Set,
378
379 pub fn gpa(self: *Promoted) Allocator {
380 return self.arena.child_allocator;
381 }
382
383 pub fn cTypeToIndex(self: *Promoted, cty: CType) Allocator.Error!Index {
384 const t = cty.tag();
385 if (@intFromEnum(t) < Tag.no_payload_count) return @as(Index, @intCast(@intFromEnum(t)));
386
387 const gop = try self.set.map.getOrPutContext(self.gpa(), cty, .{ .store = &self.set });
388 if (!gop.found_existing) gop.key_ptr.* = cty;
389 if (std.debug.runtime_safety) {
390 const key = &self.set.map.entries.items(.key)[gop.index];
391 assert(key == gop.key_ptr);
392 assert(cty.eql(key.*));
393 assert(cty.hash(self.set) == key.hash(self.set));
394 }
395 return @as(Index, @intCast(Tag.no_payload_count + gop.index));
396 }
397
398 pub fn typeToIndex(
399 self: *Promoted,
400 ty: Type,
401 zcu: *Zcu,
402 mod: *Module,
403 kind: Kind,
404 ) Allocator.Error!Index {
405 const lookup = Convert.Lookup{ .mut = .{ .promoted = self, .zcu = zcu, .mod = mod } };
406
407 var convert: Convert = undefined;
408 try convert.initType(ty, kind, lookup);
409
410 const t = convert.tag();
411 if (!t.hasPayload()) return t.toIndex();
412
413 const gop = try self.set.map.getOrPutContextAdapted(
414 self.gpa(),
415 ty,
416 TypeAdapter32{ .kind = kind, .lookup = lookup.freeze(), .convert = &convert },
417 .{ .store = &self.set },
418 );
419 if (!gop.found_existing) {
420 errdefer _ = self.set.map.pop();
421 gop.key_ptr.* = try createFromConvert(self, ty, zcu, mod, kind, convert);
422 }
423 if (std.debug.runtime_safety) {
424 const adapter = TypeAdapter64{
425 .kind = kind,
426 .lookup = lookup.freeze(),
427 .convert = &convert,
428 };
429 const cty = &self.set.map.entries.items(.key)[gop.index];
430 assert(cty == gop.key_ptr);
431 assert(adapter.eql(ty, cty.*));
432 assert(adapter.hash(ty) == cty.hash(self.set));
433 }
434 return @as(Index, @intCast(Tag.no_payload_count + gop.index));
435 }
436 };
437
438 pub fn promote(self: Store, gpa: Allocator) Promoted {
439 return .{ .arena = self.arena.promote(gpa), .set = self.set };
440 }
441
442 pub fn demote(self: *Store, promoted: Promoted) void {
443 self.arena = promoted.arena.state;
444 self.set = promoted.set;
445 }
446
447 pub fn indexToCType(self: Store, index: Index) CType {
448 return self.set.indexToCType(index);
449 }
450
451 pub fn indexToHash(self: Store, index: Index) Set.Map.Hash {
452 return self.set.indexToHash(index);
453 }
454
455 pub fn cTypeToIndex(self: *Store, gpa: Allocator, cty: CType) !Index {
456 var promoted = self.promote(gpa);
457 defer self.demote(promoted);
458 return promoted.cTypeToIndex(cty);
459 }
460
461 pub fn typeToCType(self: *Store, gpa: Allocator, ty: Type, zcu: *Zcu, mod: *Module, kind: Kind) !CType {
462 const idx = try self.typeToIndex(gpa, ty, zcu, mod, kind);
463 return self.indexToCType(idx);
464 }
465
466 pub fn typeToIndex(self: *Store, gpa: Allocator, ty: Type, zcu: *Zcu, mod: *Module, kind: Kind) !Index {
467 var promoted = self.promote(gpa);
468 defer self.demote(promoted);
469 return promoted.typeToIndex(ty, zcu, mod, kind);
470 }
471
472 pub fn clearRetainingCapacity(self: *Store, gpa: Allocator) void {
473 var promoted = self.promote(gpa);
474 defer self.demote(promoted);
475 promoted.set.map.clearRetainingCapacity();
476 _ = promoted.arena.reset(.retain_capacity);
477 }
478
479 pub fn clearAndFree(self: *Store, gpa: Allocator) void {
480 var promoted = self.promote(gpa);
481 defer self.demote(promoted);
482 promoted.set.map.clearAndFree(gpa);
483 _ = promoted.arena.reset(.free_all);
484 }
485
486 pub fn shrinkRetainingCapacity(self: *Store, gpa: Allocator, new_len: usize) void {
487 self.set.map.shrinkRetainingCapacity(gpa, new_len);
488 }
489
490 pub fn shrinkAndFree(self: *Store, gpa: Allocator, new_len: usize) void {
491 self.set.map.shrinkAndFree(gpa, new_len);
492 }
493
494 pub fn count(self: Store) usize {
495 return self.set.map.count();
496 }
497
498 pub fn move(self: *Store) Store {
499 const moved = self.*;
500 self.* = .{};
501 return moved;
502 }
503
504 pub fn deinit(self: *Store, gpa: Allocator) void {
505 var promoted = self.promote(gpa);
506 promoted.set.map.deinit(gpa);
507 _ = promoted.arena.deinit();
508 self.* = undefined;
509 }
510 };
511
512 pub fn isBool(self: CType) bool {
513 return switch (self.tag()) {
514 ._Bool,
515 .bool,
516 => true,
517 else => false,
518 };
519 }
520
521 pub fn isInteger(self: CType) bool {
522 return switch (self.tag()) {
523 .char,
524 .@"signed char",
525 .short,
526 .int,
527 .long,
528 .@"long long",
529 .@"unsigned char",
530 .@"unsigned short",
531 .@"unsigned int",
532 .@"unsigned long",
533 .@"unsigned long long",
534 .size_t,
535 .ptrdiff_t,
536 .uint8_t,
537 .int8_t,
538 .uint16_t,
539 .int16_t,
540 .uint32_t,
541 .int32_t,
542 .uint64_t,
543 .int64_t,
544 .uintptr_t,
545 .intptr_t,
546 .zig_u128,
547 .zig_i128,
548 => true,
549 else => false,
550 };
551 }
552
553 pub fn signedness(self: CType, mod: *Module) std.builtin.Signedness {
554 return switch (self.tag()) {
555 .char => mod.resolved_target.result.charSignedness(),
556 .@"signed char",
557 .short,
558 .int,
559 .long,
560 .@"long long",
561 .ptrdiff_t,
562 .int8_t,
563 .int16_t,
564 .int32_t,
565 .int64_t,
566 .intptr_t,
567 .zig_i128,
568 => .signed,
569 .@"unsigned char",
570 .@"unsigned short",
571 .@"unsigned int",
572 .@"unsigned long",
573 .@"unsigned long long",
574 .size_t,
575 .uint8_t,
576 .uint16_t,
577 .uint32_t,
578 .uint64_t,
579 .uintptr_t,
580 .zig_u128,
581 => .unsigned,
582 else => unreachable,
583 };
584 }
585
586 pub fn isFloat(self: CType) bool {
587 return switch (self.tag()) {
588 .float,
589 .double,
590 .@"long double",
591 .zig_f16,
592 .zig_f32,
593 .zig_f64,
594 .zig_f80,
595 .zig_f128,
596 .zig_c_longdouble,
597 => true,
598 else => false,
599 };
600 }
601
602 pub fn isPointer(self: CType) bool {
603 return switch (self.tag()) {
604 .pointer,
605 .pointer_const,
606 .pointer_volatile,
607 .pointer_const_volatile,
608 => true,
609 else => false,
610 };
611 }
612
613 pub fn isFunction(self: CType) bool {
614 return switch (self.tag()) {
615 .function,
616 .varargs_function,
617 => true,
618 else => false,
619 };
620 }
621
622 pub fn toSigned(self: CType) CType {
623 return CType.initTag(switch (self.tag()) {
624 .char, .@"signed char", .@"unsigned char" => .@"signed char",
625 .short, .@"unsigned short" => .short,
626 .int, .@"unsigned int" => .int,
627 .long, .@"unsigned long" => .long,
628 .@"long long", .@"unsigned long long" => .@"long long",
629 .size_t, .ptrdiff_t => .ptrdiff_t,
630 .uint8_t, .int8_t => .int8_t,
631 .uint16_t, .int16_t => .int16_t,
632 .uint32_t, .int32_t => .int32_t,
633 .uint64_t, .int64_t => .int64_t,
634 .uintptr_t, .intptr_t => .intptr_t,
635 .zig_u128, .zig_i128 => .zig_i128,
636 .float,
637 .double,
638 .@"long double",
639 .zig_f16,
640 .zig_f32,
641 .zig_f80,
642 .zig_f128,
643 .zig_c_longdouble,
644 => |t| t,
645 else => unreachable,
646 });
647 }
648
649 pub fn toUnsigned(self: CType) CType {
650 return CType.initTag(switch (self.tag()) {
651 .char, .@"signed char", .@"unsigned char" => .@"unsigned char",
652 .short, .@"unsigned short" => .@"unsigned short",
653 .int, .@"unsigned int" => .@"unsigned int",
654 .long, .@"unsigned long" => .@"unsigned long",
655 .@"long long", .@"unsigned long long" => .@"unsigned long long",
656 .size_t, .ptrdiff_t => .size_t,
657 .uint8_t, .int8_t => .uint8_t,
658 .uint16_t, .int16_t => .uint16_t,
659 .uint32_t, .int32_t => .uint32_t,
660 .uint64_t, .int64_t => .uint64_t,
661 .uintptr_t, .intptr_t => .uintptr_t,
662 .zig_u128, .zig_i128 => .zig_u128,
663 else => unreachable,
664 });
665 }
666
667 pub fn toSignedness(self: CType, s: std.builtin.Signedness) CType {
668 return switch (s) {
669 .unsigned => self.toUnsigned(),
670 .signed => self.toSigned(),
671 };
672 }
673
674 pub fn getStandardDefineAbbrev(self: CType) ?[]const u8 {
675 return switch (self.tag()) {
676 .char => "CHAR",
677 .@"signed char" => "SCHAR",
678 .short => "SHRT",
679 .int => "INT",
680 .long => "LONG",
681 .@"long long" => "LLONG",
682 .@"unsigned char" => "UCHAR",
683 .@"unsigned short" => "USHRT",
684 .@"unsigned int" => "UINT",
685 .@"unsigned long" => "ULONG",
686 .@"unsigned long long" => "ULLONG",
687 .float => "FLT",
688 .double => "DBL",
689 .@"long double" => "LDBL",
690 .size_t => "SIZE",
691 .ptrdiff_t => "PTRDIFF",
692 .uint8_t => "UINT8",
693 .int8_t => "INT8",
694 .uint16_t => "UINT16",
695 .int16_t => "INT16",
696 .uint32_t => "UINT32",
697 .int32_t => "INT32",
698 .uint64_t => "UINT64",
699 .int64_t => "INT64",
700 .uintptr_t => "UINTPTR",
701 .intptr_t => "INTPTR",
702 else => null,
703 };
704 }
705
706 pub fn renderLiteralPrefix(self: CType, writer: anytype, kind: Kind) @TypeOf(writer).Error!void {
707 switch (self.tag()) {
708 .void => unreachable,
709 ._Bool,
710 .char,
711 .@"signed char",
712 .short,
713 .@"unsigned short",
714 .bool,
715 .size_t,
716 .ptrdiff_t,
717 .uintptr_t,
718 .intptr_t,
719 => |t| switch (kind) {
720 else => try writer.print("({s})", .{@tagName(t)}),
721 .global => {},
722 },
723 .int,
724 .long,
725 .@"long long",
726 .@"unsigned char",
727 .@"unsigned int",
728 .@"unsigned long",
729 .@"unsigned long long",
730 .float,
731 .double,
732 .@"long double",
733 => {},
734 .uint8_t,
735 .int8_t,
736 .uint16_t,
737 .int16_t,
738 .uint32_t,
739 .int32_t,
740 .uint64_t,
741 .int64_t,
742 => try writer.print("{s}_C(", .{self.getStandardDefineAbbrev().?}),
743 .zig_u128,
744 .zig_i128,
745 .zig_f16,
746 .zig_f32,
747 .zig_f64,
748 .zig_f80,
749 .zig_f128,
750 .zig_c_longdouble,
751 => |t| try writer.print("zig_{s}_{s}(", .{
752 switch (kind) {
753 else => "make",
754 .global => "init",
755 },
756 @tagName(t)["zig_".len..],
757 }),
758 .pointer,
759 .pointer_const,
760 .pointer_volatile,
761 .pointer_const_volatile,
762 => unreachable,
763 .array,
764 .vector,
765 => try writer.writeByte('{'),
766 .fwd_anon_struct,
767 .fwd_anon_union,
768 .fwd_struct,
769 .fwd_union,
770 .unnamed_struct,
771 .unnamed_union,
772 .packed_unnamed_struct,
773 .packed_unnamed_union,
774 .anon_struct,
775 .anon_union,
776 .@"struct",
777 .@"union",
778 .packed_struct,
779 .packed_union,
780 .function,
781 .varargs_function,
782 => unreachable,
783 }
784 }
785
786 pub fn renderLiteralSuffix(self: CType, writer: anytype) @TypeOf(writer).Error!void {
787 switch (self.tag()) {
788 .void => unreachable,
789 ._Bool => {},
790 .char,
791 .@"signed char",
792 .short,
793 .int,
794 => {},
795 .long => try writer.writeByte('l'),
796 .@"long long" => try writer.writeAll("ll"),
797 .@"unsigned char",
798 .@"unsigned short",
799 .@"unsigned int",
800 => try writer.writeByte('u'),
801 .@"unsigned long",
802 .size_t,
803 .uintptr_t,
804 => try writer.writeAll("ul"),
805 .@"unsigned long long" => try writer.writeAll("ull"),
806 .float => try writer.writeByte('f'),
807 .double => {},
808 .@"long double" => try writer.writeByte('l'),
809 .bool,
810 .ptrdiff_t,
811 .intptr_t,
812 => {},
813 .uint8_t,
814 .int8_t,
815 .uint16_t,
816 .int16_t,
817 .uint32_t,
818 .int32_t,
819 .uint64_t,
820 .int64_t,
821 .zig_u128,
822 .zig_i128,
823 .zig_f16,
824 .zig_f32,
825 .zig_f64,
826 .zig_f80,
827 .zig_f128,
828 .zig_c_longdouble,
829 => try writer.writeByte(')'),
830 .pointer,
831 .pointer_const,
832 .pointer_volatile,
833 .pointer_const_volatile,
834 => unreachable,
835 .array,
836 .vector,
837 => try writer.writeByte('}'),
838 .fwd_anon_struct,
839 .fwd_anon_union,
840 .fwd_struct,
841 .fwd_union,
842 .unnamed_struct,
843 .unnamed_union,
844 .packed_unnamed_struct,
845 .packed_unnamed_union,
846 .anon_struct,
847 .anon_union,
848 .@"struct",
849 .@"union",
850 .packed_struct,
851 .packed_union,
852 .function,
853 .varargs_function,
854 => unreachable,
855 }
856 }
857
858 pub fn floatActiveBits(self: CType, mod: *Module) u16 {
859 const target = &mod.resolved_target.result;
860 return switch (self.tag()) {
861 .float => target.c_type_bit_size(.float),
862 .double => target.c_type_bit_size(.double),
863 .@"long double", .zig_c_longdouble => target.c_type_bit_size(.longdouble),
864 .zig_f16 => 16,
865 .zig_f32 => 32,
866 .zig_f64 => 64,
867 .zig_f80 => 80,
868 .zig_f128 => 128,
869 else => unreachable,
870 };
871 }
872
873 pub fn byteSize(self: CType, store: Store.Set, mod: *Module) u64 {
874 const target = &mod.resolved_target.result;
875 return switch (self.tag()) {
876 .void => 0,
877 .char, .@"signed char", ._Bool, .@"unsigned char", .bool, .uint8_t, .int8_t => 1,
878 .short => target.c_type_byte_size(.short),
879 .int => target.c_type_byte_size(.int),
880 .long => target.c_type_byte_size(.long),
881 .@"long long" => target.c_type_byte_size(.longlong),
882 .@"unsigned short" => target.c_type_byte_size(.ushort),
883 .@"unsigned int" => target.c_type_byte_size(.uint),
884 .@"unsigned long" => target.c_type_byte_size(.ulong),
885 .@"unsigned long long" => target.c_type_byte_size(.ulonglong),
886 .float => target.c_type_byte_size(.float),
887 .double => target.c_type_byte_size(.double),
888 .@"long double" => target.c_type_byte_size(.longdouble),
889 .size_t,
890 .ptrdiff_t,
891 .uintptr_t,
892 .intptr_t,
893 .pointer,
894 .pointer_const,
895 .pointer_volatile,
896 .pointer_const_volatile,
897 => @divExact(target.ptrBitWidth(), 8),
898 .uint16_t, .int16_t, .zig_f16 => 2,
899 .uint32_t, .int32_t, .zig_f32 => 4,
900 .uint64_t, .int64_t, .zig_f64 => 8,
901 .zig_u128, .zig_i128, .zig_f128 => 16,
902 .zig_f80 => if (target.c_type_bit_size(.longdouble) == 80)
903 target.c_type_byte_size(.longdouble)
904 else
905 16,
906 .zig_c_longdouble => target.c_type_byte_size(.longdouble),
907
908 .array,
909 .vector,
910 => {
911 const data = self.cast(Payload.Sequence).?.data;
912 return data.len * store.indexToCType(data.elem_type).byteSize(store, mod);
913 },
914
915 .fwd_anon_struct,
916 .fwd_anon_union,
917 .fwd_struct,
918 .fwd_union,
919 .unnamed_struct,
920 .unnamed_union,
921 .packed_unnamed_struct,
922 .packed_unnamed_union,
923 .anon_struct,
924 .anon_union,
925 .@"struct",
926 .@"union",
927 .packed_struct,
928 .packed_union,
929 .function,
930 .varargs_function,
931 => unreachable,
932 };
933 }
934
935 pub fn isPacked(self: CType) bool {
936 return switch (self.tag()) {
937 else => false,
938 .packed_unnamed_struct,
939 .packed_unnamed_union,
940 .packed_struct,
941 .packed_union,
942 => true,
943 };
944 }
945
946 pub fn fields(self: CType) Payload.Fields.Data {
947 return if (self.cast(Payload.Aggregate)) |pl|
948 pl.data.fields
949 else if (self.cast(Payload.Unnamed)) |pl|
950 pl.data.fields
951 else if (self.cast(Payload.Fields)) |pl|
952 pl.data
953 else
954 unreachable;
955 }
956
957 pub fn eql(lhs: CType, rhs: CType) bool {
958 return lhs.eqlContext(rhs, struct {
959 pub fn eqlIndex(_: @This(), lhs_idx: Index, rhs_idx: Index) bool {
960 return lhs_idx == rhs_idx;
961 }
962 }{});
963 }
964
965 pub fn eqlContext(lhs: CType, rhs: CType, ctx: anytype) bool {
966 // As a shortcut, if the small tags / addresses match, we're done.
967 if (lhs.tag_if_small_enough == rhs.tag_if_small_enough) return true;
968
969 const lhs_tag = lhs.tag();
970 const rhs_tag = rhs.tag();
971 if (lhs_tag != rhs_tag) return false;
972
973 return switch (lhs_tag) {
974 .void,
975 .char,
976 .@"signed char",
977 .short,
978 .int,
979 .long,
980 .@"long long",
981 ._Bool,
982 .@"unsigned char",
983 .@"unsigned short",
984 .@"unsigned int",
985 .@"unsigned long",
986 .@"unsigned long long",
987 .float,
988 .double,
989 .@"long double",
990 .bool,
991 .size_t,
992 .ptrdiff_t,
993 .uint8_t,
994 .int8_t,
995 .uint16_t,
996 .int16_t,
997 .uint32_t,
998 .int32_t,
999 .uint64_t,
1000 .int64_t,
1001 .uintptr_t,
1002 .intptr_t,
1003 .zig_u128,
1004 .zig_i128,
1005 .zig_f16,
1006 .zig_f32,
1007 .zig_f64,
1008 .zig_f80,
1009 .zig_f128,
1010 .zig_c_longdouble,
1011 => false,
1012
1013 .pointer,
1014 .pointer_const,
1015 .pointer_volatile,
1016 .pointer_const_volatile,
1017 => ctx.eqlIndex(lhs.cast(Payload.Child).?.data, rhs.cast(Payload.Child).?.data),
1018
1019 .array,
1020 .vector,
1021 => {
1022 const lhs_data = lhs.cast(Payload.Sequence).?.data;
1023 const rhs_data = rhs.cast(Payload.Sequence).?.data;
1024 return lhs_data.len == rhs_data.len and
1025 ctx.eqlIndex(lhs_data.elem_type, rhs_data.elem_type);
1026 },
1027
1028 .fwd_anon_struct,
1029 .fwd_anon_union,
1030 => {
1031 const lhs_data = lhs.cast(Payload.Fields).?.data;
1032 const rhs_data = rhs.cast(Payload.Fields).?.data;
1033 if (lhs_data.len != rhs_data.len) return false;
1034 for (lhs_data, rhs_data) |lhs_field, rhs_field| {
1035 if (!ctx.eqlIndex(lhs_field.type, rhs_field.type)) return false;
1036 if (lhs_field.alignas.@"align" != rhs_field.alignas.@"align") return false;
1037 if (std.mem.orderZ(u8, lhs_field.name, rhs_field.name) != .eq) return false;
1038 }
1039 return true;
1040 },
1041
1042 .fwd_struct,
1043 .fwd_union,
1044 => lhs.cast(Payload.FwdDecl).?.data == rhs.cast(Payload.FwdDecl).?.data,
1045
1046 .unnamed_struct,
1047 .unnamed_union,
1048 .packed_unnamed_struct,
1049 .packed_unnamed_union,
1050 => {
1051 const lhs_data = lhs.cast(Payload.Unnamed).?.data;
1052 const rhs_data = rhs.cast(Payload.Unnamed).?.data;
1053 return lhs_data.owner_decl == rhs_data.owner_decl and lhs_data.id == rhs_data.id;
1054 },
1055
1056 .anon_struct,
1057 .anon_union,
1058 .@"struct",
1059 .@"union",
1060 .packed_struct,
1061 .packed_union,
1062 => ctx.eqlIndex(
1063 lhs.cast(Payload.Aggregate).?.data.fwd_decl,
1064 rhs.cast(Payload.Aggregate).?.data.fwd_decl,
1065 ),
1066
1067 .function,
1068 .varargs_function,
1069 => {
1070 const lhs_data = lhs.cast(Payload.Function).?.data;
1071 const rhs_data = rhs.cast(Payload.Function).?.data;
1072 if (lhs_data.param_types.len != rhs_data.param_types.len) return false;
1073 if (!ctx.eqlIndex(lhs_data.return_type, rhs_data.return_type)) return false;
1074 for (lhs_data.param_types, rhs_data.param_types) |lhs_param_idx, rhs_param_idx| {
1075 if (!ctx.eqlIndex(lhs_param_idx, rhs_param_idx)) return false;
1076 }
1077 return true;
1078 },
1079 };
1080 }
1081
1082 pub fn hash(self: CType, store: Store.Set) u64 {
1083 var hasher = std.hash.Wyhash.init(0);
1084 self.updateHasher(&hasher, store);
1085 return hasher.final();
1086 }
1087
1088 pub fn updateHasher(self: CType, hasher: anytype, store: Store.Set) void {
1089 const t = self.tag();
1090 autoHash(hasher, t);
1091 switch (t) {
1092 .void,
1093 .char,
1094 .@"signed char",
1095 .short,
1096 .int,
1097 .long,
1098 .@"long long",
1099 ._Bool,
1100 .@"unsigned char",
1101 .@"unsigned short",
1102 .@"unsigned int",
1103 .@"unsigned long",
1104 .@"unsigned long long",
1105 .float,
1106 .double,
1107 .@"long double",
1108 .bool,
1109 .size_t,
1110 .ptrdiff_t,
1111 .uint8_t,
1112 .int8_t,
1113 .uint16_t,
1114 .int16_t,
1115 .uint32_t,
1116 .int32_t,
1117 .uint64_t,
1118 .int64_t,
1119 .uintptr_t,
1120 .intptr_t,
1121 .zig_u128,
1122 .zig_i128,
1123 .zig_f16,
1124 .zig_f32,
1125 .zig_f64,
1126 .zig_f80,
1127 .zig_f128,
1128 .zig_c_longdouble,
1129 => {},
1130
1131 .pointer,
1132 .pointer_const,
1133 .pointer_volatile,
1134 .pointer_const_volatile,
1135 => store.indexToCType(self.cast(Payload.Child).?.data).updateHasher(hasher, store),
1136
1137 .array,
1138 .vector,
1139 => {
1140 const data = self.cast(Payload.Sequence).?.data;
1141 autoHash(hasher, data.len);
1142 store.indexToCType(data.elem_type).updateHasher(hasher, store);
1143 },
1144
1145 .fwd_anon_struct,
1146 .fwd_anon_union,
1147 => for (self.cast(Payload.Fields).?.data) |field| {
1148 store.indexToCType(field.type).updateHasher(hasher, store);
1149 hasher.update(mem.span(field.name));
1150 autoHash(hasher, field.alignas.@"align");
1151 },
1152
1153 .fwd_struct,
1154 .fwd_union,
1155 => autoHash(hasher, self.cast(Payload.FwdDecl).?.data),
1156
1157 .unnamed_struct,
1158 .unnamed_union,
1159 .packed_unnamed_struct,
1160 .packed_unnamed_union,
1161 => {
1162 const data = self.cast(Payload.Unnamed).?.data;
1163 autoHash(hasher, data.owner_decl);
1164 autoHash(hasher, data.id);
1165 },
1166
1167 .anon_struct,
1168 .anon_union,
1169 .@"struct",
1170 .@"union",
1171 .packed_struct,
1172 .packed_union,
1173 => store.indexToCType(self.cast(Payload.Aggregate).?.data.fwd_decl)
1174 .updateHasher(hasher, store),
1175
1176 .function,
1177 .varargs_function,
1178 => {
1179 const data = self.cast(Payload.Function).?.data;
1180 store.indexToCType(data.return_type).updateHasher(hasher, store);
1181 for (data.param_types) |param_ty| {
1182 store.indexToCType(param_ty).updateHasher(hasher, store);
1183 }
1184 },
1185 }
1186 }
1187
1188 pub const Kind = enum { forward, forward_parameter, complete, global, parameter, payload };
1189
1190 const Convert = struct {
1191 storage: union {
1192 none: void,
1193 child: Payload.Child,
1194 seq: Payload.Sequence,
1195 fwd: Payload.FwdDecl,
1196 anon: struct {
1197 fields: [2]Payload.Fields.Field,
1198 pl: union {
1199 forward: Payload.Fields,
1200 complete: Payload.Aggregate,
1201 },
1202 },
1203 },
1204 value: union(enum) {
1205 tag: Tag,
1206 cty: CType,
1207 },
1208
1209 pub fn init(self: *@This(), t: Tag) void {
1210 self.* = if (t.hasPayload()) .{
1211 .storage = .{ .none = {} },
1212 .value = .{ .tag = t },
1213 } else .{
1214 .storage = .{ .none = {} },
1215 .value = .{ .cty = initTag(t) },
1216 };
1217 }
1218
1219 pub fn tag(self: @This()) Tag {
1220 return switch (self.value) {
1221 .tag => |t| t,
1222 .cty => |c| c.tag(),
1223 };
1224 }
1225
1226 fn tagFromIntInfo(int_info: std.builtin.Type.Int) Tag {
1227 return switch (int_info.bits) {
1228 0 => .void,
1229 1...8 => switch (int_info.signedness) {
1230 .unsigned => .uint8_t,
1231 .signed => .int8_t,
1232 },
1233 9...16 => switch (int_info.signedness) {
1234 .unsigned => .uint16_t,
1235 .signed => .int16_t,
1236 },
1237 17...32 => switch (int_info.signedness) {
1238 .unsigned => .uint32_t,
1239 .signed => .int32_t,
1240 },
1241 33...64 => switch (int_info.signedness) {
1242 .unsigned => .uint64_t,
1243 .signed => .int64_t,
1244 },
1245 65...128 => switch (int_info.signedness) {
1246 .unsigned => .zig_u128,
1247 .signed => .zig_i128,
1248 },
1249 else => .array,
1250 };
1251 }
1252
1253 pub const Lookup = union(enum) {
1254 fail: struct {
1255 zcu: *Zcu,
1256 mod: *Module,
1257 },
1258 imm: struct {
1259 set: *const Store.Set,
1260 zcu: *Zcu,
1261 mod: *Module,
1262 },
1263 mut: struct {
1264 promoted: *Store.Promoted,
1265 zcu: *Zcu,
1266 mod: *Module,
1267 },
1268
1269 pub fn isMutable(self: @This()) bool {
1270 return switch (self) {
1271 .fail, .imm => false,
1272 .mut => true,
1273 };
1274 }
1275
1276 pub fn getZcu(self: @This()) *Zcu {
1277 return switch (self) {
1278 inline else => |pl| pl.zcu,
1279 };
1280 }
1281
1282 pub fn getModule(self: @This()) *Module {
1283 return switch (self) {
1284 inline else => |pl| pl.mod,
1285 };
1286 }
1287
1288 pub fn getSet(self: @This()) ?*const Store.Set {
1289 return switch (self) {
1290 .fail => null,
1291 .imm => |imm| imm.set,
1292 .mut => |mut| &mut.promoted.set,
1293 };
1294 }
1295
1296 pub fn typeToIndex(self: @This(), ty: Type, kind: Kind) !?Index {
1297 return switch (self) {
1298 .fail => null,
1299 .imm => |imm| imm.set.typeToIndex(ty, imm.zcu, imm.mod, kind),
1300 .mut => |mut| try mut.promoted.typeToIndex(ty, mut.zcu, mut.mod, kind),
1301 };
1302 }
1303
1304 pub fn indexToCType(self: @This(), index: Index) ?CType {
1305 return if (self.getSet()) |set| set.indexToCType(index) else null;
1306 }
1307
1308 pub fn freeze(self: @This()) @This() {
1309 return switch (self) {
1310 .fail, .imm => self,
1311 .mut => |mut| .{ .imm = .{ .set = &mut.promoted.set, .zcu = mut.zcu, .mod = mut.mod } },
1312 };
1313 }
1314 };
1315
1316 fn sortFields(self: *@This(), fields_len: usize) []Payload.Fields.Field {
1317 const Field = Payload.Fields.Field;
1318 const slice = self.storage.anon.fields[0..fields_len];
1319 mem.sort(Field, slice, {}, struct {
1320 fn before(_: void, lhs: Field, rhs: Field) bool {
1321 return lhs.alignas.order(rhs.alignas).compare(.gt);
1322 }
1323 }.before);
1324 return slice;
1325 }
1326
1327 fn initAnon(self: *@This(), kind: Kind, fwd_idx: Index, fields_len: usize) void {
1328 switch (kind) {
1329 .forward, .forward_parameter => {
1330 self.storage.anon.pl = .{ .forward = .{
1331 .base = .{ .tag = .fwd_anon_struct },
1332 .data = self.sortFields(fields_len),
1333 } };
1334 self.value = .{ .cty = initPayload(&self.storage.anon.pl.forward) };
1335 },
1336 .complete, .parameter, .global => {
1337 self.storage.anon.pl = .{ .complete = .{
1338 .base = .{ .tag = .anon_struct },
1339 .data = .{
1340 .fields = self.sortFields(fields_len),
1341 .fwd_decl = fwd_idx,
1342 },
1343 } };
1344 self.value = .{ .cty = initPayload(&self.storage.anon.pl.complete) };
1345 },
1346 .payload => unreachable,
1347 }
1348 }
1349
1350 fn initArrayParameter(self: *@This(), ty: Type, kind: Kind, lookup: Lookup) !void {
1351 if (switch (kind) {
1352 .forward_parameter => @as(Index, undefined),
1353 .parameter => try lookup.typeToIndex(ty, .forward_parameter),
1354 .forward, .complete, .global, .payload => unreachable,
1355 }) |fwd_idx| {
1356 if (try lookup.typeToIndex(ty, switch (kind) {
1357 .forward_parameter => .forward,
1358 .parameter => .complete,
1359 .forward, .complete, .global, .payload => unreachable,
1360 })) |array_idx| {
1361 self.storage = .{ .anon = undefined };
1362 self.storage.anon.fields[0] = .{
1363 .name = "array",
1364 .type = array_idx,
1365 .alignas = AlignAs.abiAlign(ty, lookup.getZcu()),
1366 };
1367 self.initAnon(kind, fwd_idx, 1);
1368 } else self.init(switch (kind) {
1369 .forward_parameter => .fwd_anon_struct,
1370 .parameter => .anon_struct,
1371 .forward, .complete, .global, .payload => unreachable,
1372 });
1373 } else self.init(.anon_struct);
1374 }
1375
1376 pub fn initType(self: *@This(), ty: Type, kind: Kind, lookup: Lookup) !void {
1377 const zcu = lookup.getZcu();
1378 const ip = &zcu.intern_pool;
1379
1380 self.* = undefined;
1381 if (!ty.isFnOrHasRuntimeBitsIgnoreComptime(zcu))
1382 self.init(.void)
1383 else if (ty.isAbiInt(zcu)) switch (ty.ip_index) {
1384 .usize_type => self.init(.uintptr_t),
1385 .isize_type => self.init(.intptr_t),
1386 .c_char_type => self.init(.char),
1387 .c_short_type => self.init(.short),
1388 .c_ushort_type => self.init(.@"unsigned short"),
1389 .c_int_type => self.init(.int),
1390 .c_uint_type => self.init(.@"unsigned int"),
1391 .c_long_type => self.init(.long),
1392 .c_ulong_type => self.init(.@"unsigned long"),
1393 .c_longlong_type => self.init(.@"long long"),
1394 .c_ulonglong_type => self.init(.@"unsigned long long"),
1395 else => switch (tagFromIntInfo(ty.intInfo(zcu))) {
1396 .void => unreachable,
1397 else => |t| self.init(t),
1398 .array => switch (kind) {
1399 .forward, .complete, .global => {
1400 const abi_size = ty.abiSize(zcu);
1401 const abi_align = ty.abiAlignment(zcu).toByteUnits(0);
1402 self.storage = .{ .seq = .{ .base = .{ .tag = .array }, .data = .{
1403 .len = @divExact(abi_size, abi_align),
1404 .elem_type = tagFromIntInfo(.{
1405 .signedness = .unsigned,
1406 .bits = @intCast(abi_align * 8),
1407 }).toIndex(),
1408 } } };
1409 self.value = .{ .cty = initPayload(&self.storage.seq) };
1410 },
1411 .forward_parameter,
1412 .parameter,
1413 => try self.initArrayParameter(ty, kind, lookup),
1414 .payload => unreachable,
1415 },
1416 },
1417 } else switch (ty.zigTypeTag(zcu)) {
1418 .Frame => unreachable,
1419 .AnyFrame => unreachable,
1420
1421 .Int,
1422 .Enum,
1423 .ErrorSet,
1424 .Type,
1425 .Void,
1426 .NoReturn,
1427 .ComptimeFloat,
1428 .ComptimeInt,
1429 .Undefined,
1430 .Null,
1431 .EnumLiteral,
1432 => unreachable,
1433
1434 .Bool => self.init(.bool),
1435
1436 .Float => self.init(switch (ty.ip_index) {
1437 .f16_type => .zig_f16,
1438 .f32_type => .zig_f32,
1439 .f64_type => .zig_f64,
1440 .f80_type => .zig_f80,
1441 .f128_type => .zig_f128,
1442 .c_longdouble_type => .zig_c_longdouble,
1443 else => unreachable,
1444 }),
1445
1446 .Pointer => {
1447 const info = ty.ptrInfo(zcu);
1448 switch (info.flags.size) {
1449 .Slice => {
1450 if (switch (kind) {
1451 .forward, .forward_parameter => @as(Index, undefined),
1452 .complete, .parameter, .global => try lookup.typeToIndex(ty, .forward),
1453 .payload => unreachable,
1454 }) |fwd_idx| {
1455 const ptr_ty = ty.slicePtrFieldType(zcu);
1456 if (try lookup.typeToIndex(ptr_ty, kind)) |ptr_idx| {
1457 self.storage = .{ .anon = undefined };
1458 self.storage.anon.fields[0] = .{
1459 .name = "ptr",
1460 .type = ptr_idx,
1461 .alignas = AlignAs.abiAlign(ptr_ty, zcu),
1462 };
1463 self.storage.anon.fields[1] = .{
1464 .name = "len",
1465 .type = Tag.uintptr_t.toIndex(),
1466 .alignas = AlignAs.abiAlign(Type.usize, zcu),
1467 };
1468 self.initAnon(kind, fwd_idx, 2);
1469 } else self.init(switch (kind) {
1470 .forward, .forward_parameter => .fwd_anon_struct,
1471 .complete, .parameter, .global => .anon_struct,
1472 .payload => unreachable,
1473 });
1474 } else self.init(.anon_struct);
1475 },
1476
1477 .One, .Many, .C => {
1478 const t: Tag = switch (info.flags.is_volatile) {
1479 false => switch (info.flags.is_const) {
1480 false => .pointer,
1481 true => .pointer_const,
1482 },
1483 true => switch (info.flags.is_const) {
1484 false => .pointer_volatile,
1485 true => .pointer_const_volatile,
1486 },
1487 };
1488
1489 const pointee_ty = if (info.packed_offset.host_size > 0 and info.flags.vector_index == .none)
1490 try zcu.intType(.unsigned, info.packed_offset.host_size * 8)
1491 else if (info.flags.alignment == .none or
1492 info.flags.alignment.compareStrict(.gte, Type.fromInterned(info.child).abiAlignment(zcu)))
1493 Type.fromInterned(info.child)
1494 else
1495 try zcu.intType(.unsigned, @min(
1496 info.flags.alignment.toByteUnitsOptional().?,
1497 lookup.getModule().resolved_target.result.maxIntAlignment(),
1498 ) * 8);
1499
1500 if (try lookup.typeToIndex(pointee_ty, .forward)) |child_idx| {
1501 self.storage = .{ .child = .{
1502 .base = .{ .tag = t },
1503 .data = child_idx,
1504 } };
1505 self.value = .{ .cty = initPayload(&self.storage.child) };
1506 } else self.init(t);
1507 },
1508 }
1509 },
1510
1511 .Struct, .Union => |zig_ty_tag| if (ty.containerLayout(zcu) == .@"packed") {
1512 if (zcu.typeToPackedStruct(ty)) |packed_struct| {
1513 try self.initType(Type.fromInterned(packed_struct.backingIntType(ip).*), kind, lookup);
1514 } else {
1515 const bits: u16 = @intCast(ty.bitSize(zcu));
1516 const int_ty = try zcu.intType(.unsigned, bits);
1517 try self.initType(int_ty, kind, lookup);
1518 }
1519 } else if (ty.isTupleOrAnonStruct(zcu)) {
1520 if (lookup.isMutable()) {
1521 for (0..switch (zig_ty_tag) {
1522 .Struct => ty.structFieldCount(zcu),
1523 .Union => zcu.typeToUnion(ty).?.field_types.len,
1524 else => unreachable,
1525 }) |field_i| {
1526 const field_ty = ty.structFieldType(field_i, zcu);
1527 if ((zig_ty_tag == .Struct and ty.structFieldIsComptime(field_i, zcu)) or
1528 !field_ty.hasRuntimeBitsIgnoreComptime(zcu)) continue;
1529 _ = try lookup.typeToIndex(field_ty, switch (kind) {
1530 .forward, .forward_parameter => .forward,
1531 .complete, .parameter => .complete,
1532 .global => .global,
1533 .payload => unreachable,
1534 });
1535 }
1536 switch (kind) {
1537 .forward, .forward_parameter => {},
1538 .complete, .parameter, .global => _ = try lookup.typeToIndex(ty, .forward),
1539 .payload => unreachable,
1540 }
1541 }
1542 self.init(switch (kind) {
1543 .forward, .forward_parameter => switch (zig_ty_tag) {
1544 .Struct => .fwd_anon_struct,
1545 .Union => .fwd_anon_union,
1546 else => unreachable,
1547 },
1548 .complete, .parameter, .global => switch (zig_ty_tag) {
1549 .Struct => .anon_struct,
1550 .Union => .anon_union,
1551 else => unreachable,
1552 },
1553 .payload => unreachable,
1554 });
1555 } else {
1556 const tag_ty = ty.unionTagTypeSafety(zcu);
1557 const is_tagged_union_wrapper = kind != .payload and tag_ty != null;
1558 const is_struct = zig_ty_tag == .Struct or is_tagged_union_wrapper;
1559 switch (kind) {
1560 .forward, .forward_parameter => {
1561 self.storage = .{ .fwd = .{
1562 .base = .{ .tag = if (is_struct) .fwd_struct else .fwd_union },
1563 .data = ty.getOwnerDecl(zcu),
1564 } };
1565 self.value = .{ .cty = initPayload(&self.storage.fwd) };
1566 },
1567 .complete, .parameter, .global, .payload => if (is_tagged_union_wrapper) {
1568 const fwd_idx = try lookup.typeToIndex(ty, .forward);
1569 const payload_idx = try lookup.typeToIndex(ty, .payload);
1570 const tag_idx = try lookup.typeToIndex(tag_ty.?, kind);
1571 if (fwd_idx != null and payload_idx != null and tag_idx != null) {
1572 self.storage = .{ .anon = undefined };
1573 var field_count: usize = 0;
1574 if (payload_idx != Tag.void.toIndex()) {
1575 self.storage.anon.fields[field_count] = .{
1576 .name = "payload",
1577 .type = payload_idx.?,
1578 .alignas = AlignAs.unionPayloadAlign(ty, zcu),
1579 };
1580 field_count += 1;
1581 }
1582 if (tag_idx != Tag.void.toIndex()) {
1583 self.storage.anon.fields[field_count] = .{
1584 .name = "tag",
1585 .type = tag_idx.?,
1586 .alignas = AlignAs.abiAlign(tag_ty.?, zcu),
1587 };
1588 field_count += 1;
1589 }
1590 self.storage.anon.pl = .{ .complete = .{
1591 .base = .{ .tag = .@"struct" },
1592 .data = .{
1593 .fields = self.sortFields(field_count),
1594 .fwd_decl = fwd_idx.?,
1595 },
1596 } };
1597 self.value = .{ .cty = initPayload(&self.storage.anon.pl.complete) };
1598 } else self.init(.@"struct");
1599 } else if (kind == .payload and ty.unionHasAllZeroBitFieldTypes(zcu)) {
1600 self.init(.void);
1601 } else {
1602 var is_packed = false;
1603 for (0..switch (zig_ty_tag) {
1604 .Struct => ty.structFieldCount(zcu),
1605 .Union => zcu.typeToUnion(ty).?.field_types.len,
1606 else => unreachable,
1607 }) |field_i| {
1608 const field_ty = ty.structFieldType(field_i, zcu);
1609 if (!field_ty.hasRuntimeBitsIgnoreComptime(zcu)) continue;
1610
1611 const field_align = AlignAs.fieldAlign(ty, field_i, zcu);
1612 if (field_align.abiOrder().compare(.lt)) {
1613 is_packed = true;
1614 if (!lookup.isMutable()) break;
1615 }
1616
1617 if (lookup.isMutable()) {
1618 _ = try lookup.typeToIndex(field_ty, switch (kind) {
1619 .forward, .forward_parameter => unreachable,
1620 .complete, .parameter, .payload => .complete,
1621 .global => .global,
1622 });
1623 }
1624 }
1625 switch (kind) {
1626 .forward, .forward_parameter => unreachable,
1627 .complete, .parameter, .global => {
1628 _ = try lookup.typeToIndex(ty, .forward);
1629 self.init(if (is_struct)
1630 if (is_packed) .packed_struct else .@"struct"
1631 else if (is_packed) .packed_union else .@"union");
1632 },
1633 .payload => self.init(if (is_packed)
1634 .packed_unnamed_union
1635 else
1636 .unnamed_union),
1637 }
1638 },
1639 }
1640 },
1641
1642 .Array, .Vector => |zig_ty_tag| {
1643 switch (kind) {
1644 .forward, .complete, .global => {
1645 const t: Tag = switch (zig_ty_tag) {
1646 .Array => .array,
1647 .Vector => .vector,
1648 else => unreachable,
1649 };
1650 if (try lookup.typeToIndex(ty.childType(zcu), kind)) |child_idx| {
1651 self.storage = .{ .seq = .{ .base = .{ .tag = t }, .data = .{
1652 .len = ty.arrayLenIncludingSentinel(zcu),
1653 .elem_type = child_idx,
1654 } } };
1655 self.value = .{ .cty = initPayload(&self.storage.seq) };
1656 } else self.init(t);
1657 },
1658 .forward_parameter, .parameter => try self.initArrayParameter(ty, kind, lookup),
1659 .payload => unreachable,
1660 }
1661 },
1662
1663 .Optional => {
1664 const payload_ty = ty.optionalChild(zcu);
1665 if (payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
1666 if (ty.optionalReprIsPayload(zcu)) {
1667 try self.initType(payload_ty, kind, lookup);
1668 } else if (switch (kind) {
1669 .forward, .forward_parameter => @as(Index, undefined),
1670 .complete, .parameter, .global => try lookup.typeToIndex(ty, .forward),
1671 .payload => unreachable,
1672 }) |fwd_idx| {
1673 if (try lookup.typeToIndex(payload_ty, switch (kind) {
1674 .forward, .forward_parameter => .forward,
1675 .complete, .parameter => .complete,
1676 .global => .global,
1677 .payload => unreachable,
1678 })) |payload_idx| {
1679 self.storage = .{ .anon = undefined };
1680 self.storage.anon.fields[0] = .{
1681 .name = "payload",
1682 .type = payload_idx,
1683 .alignas = AlignAs.abiAlign(payload_ty, zcu),
1684 };
1685 self.storage.anon.fields[1] = .{
1686 .name = "is_null",
1687 .type = Tag.bool.toIndex(),
1688 .alignas = AlignAs.abiAlign(Type.bool, zcu),
1689 };
1690 self.initAnon(kind, fwd_idx, 2);
1691 } else self.init(switch (kind) {
1692 .forward, .forward_parameter => .fwd_anon_struct,
1693 .complete, .parameter, .global => .anon_struct,
1694 .payload => unreachable,
1695 });
1696 } else self.init(.anon_struct);
1697 } else self.init(.bool);
1698 },
1699
1700 .ErrorUnion => {
1701 if (switch (kind) {
1702 .forward, .forward_parameter => @as(Index, undefined),
1703 .complete, .parameter, .global => try lookup.typeToIndex(ty, .forward),
1704 .payload => unreachable,
1705 }) |fwd_idx| {
1706 const payload_ty = ty.errorUnionPayload(zcu);
1707 if (try lookup.typeToIndex(payload_ty, switch (kind) {
1708 .forward, .forward_parameter => .forward,
1709 .complete, .parameter => .complete,
1710 .global => .global,
1711 .payload => unreachable,
1712 })) |payload_idx| {
1713 const error_ty = ty.errorUnionSet(zcu);
1714 if (payload_idx == Tag.void.toIndex()) {
1715 try self.initType(error_ty, kind, lookup);
1716 } else if (try lookup.typeToIndex(error_ty, kind)) |error_idx| {
1717 self.storage = .{ .anon = undefined };
1718 self.storage.anon.fields[0] = .{
1719 .name = "payload",
1720 .type = payload_idx,
1721 .alignas = AlignAs.abiAlign(payload_ty, zcu),
1722 };
1723 self.storage.anon.fields[1] = .{
1724 .name = "error",
1725 .type = error_idx,
1726 .alignas = AlignAs.abiAlign(error_ty, zcu),
1727 };
1728 self.initAnon(kind, fwd_idx, 2);
1729 } else self.init(switch (kind) {
1730 .forward, .forward_parameter => .fwd_anon_struct,
1731 .complete, .parameter, .global => .anon_struct,
1732 .payload => unreachable,
1733 });
1734 } else self.init(switch (kind) {
1735 .forward, .forward_parameter => .fwd_anon_struct,
1736 .complete, .parameter, .global => .anon_struct,
1737 .payload => unreachable,
1738 });
1739 } else self.init(.anon_struct);
1740 },
1741
1742 .Opaque => self.init(.void),
1743
1744 .Fn => {
1745 const info = zcu.typeToFunc(ty).?;
1746 if (!info.is_generic) {
1747 if (lookup.isMutable()) {
1748 const param_kind: Kind = switch (kind) {
1749 .forward, .forward_parameter => .forward_parameter,
1750 .complete, .parameter, .global => .parameter,
1751 .payload => unreachable,
1752 };
1753 _ = try lookup.typeToIndex(Type.fromInterned(info.return_type), param_kind);
1754 for (info.param_types.get(ip)) |param_type| {
1755 if (!Type.fromInterned(param_type).hasRuntimeBitsIgnoreComptime(zcu)) continue;
1756 _ = try lookup.typeToIndex(Type.fromInterned(param_type), param_kind);
1757 }
1758 }
1759 self.init(if (info.is_var_args) .varargs_function else .function);
1760 } else self.init(.void);
1761 },
1762 }
1763 }
1764 };
1765
1766 pub fn copy(self: CType, arena: Allocator) !CType {
1767 return self.copyContext(struct {
1768 arena: Allocator,
1769 pub fn copyIndex(_: @This(), idx: Index) Index {
1770 return idx;
1771 }
1772 }{ .arena = arena });
1773 }
1774
1775 fn copyFields(ctx: anytype, old_fields: Payload.Fields.Data) !Payload.Fields.Data {
1776 const new_fields = try ctx.arena.alloc(Payload.Fields.Field, old_fields.len);
1777 for (new_fields, old_fields) |*new_field, old_field| {
1778 new_field.name = try ctx.arena.dupeZ(u8, mem.span(old_field.name));
1779 new_field.type = ctx.copyIndex(old_field.type);
1780 new_field.alignas = old_field.alignas;
1781 }
1782 return new_fields;
1783 }
1784
1785 fn copyParams(ctx: anytype, old_param_types: []const Index) ![]const Index {
1786 const new_param_types = try ctx.arena.alloc(Index, old_param_types.len);
1787 for (new_param_types, old_param_types) |*new_param_type, old_param_type|
1788 new_param_type.* = ctx.copyIndex(old_param_type);
1789 return new_param_types;
1790 }
1791
1792 pub fn copyContext(self: CType, ctx: anytype) !CType {
1793 switch (self.tag()) {
1794 .void,
1795 .char,
1796 .@"signed char",
1797 .short,
1798 .int,
1799 .long,
1800 .@"long long",
1801 ._Bool,
1802 .@"unsigned char",
1803 .@"unsigned short",
1804 .@"unsigned int",
1805 .@"unsigned long",
1806 .@"unsigned long long",
1807 .float,
1808 .double,
1809 .@"long double",
1810 .bool,
1811 .size_t,
1812 .ptrdiff_t,
1813 .uint8_t,
1814 .int8_t,
1815 .uint16_t,
1816 .int16_t,
1817 .uint32_t,
1818 .int32_t,
1819 .uint64_t,
1820 .int64_t,
1821 .uintptr_t,
1822 .intptr_t,
1823 .zig_u128,
1824 .zig_i128,
1825 .zig_f16,
1826 .zig_f32,
1827 .zig_f64,
1828 .zig_f80,
1829 .zig_f128,
1830 .zig_c_longdouble,
1831 => return self,
1832
1833 .pointer,
1834 .pointer_const,
1835 .pointer_volatile,
1836 .pointer_const_volatile,
1837 => {
1838 const pl = self.cast(Payload.Child).?;
1839 const new_pl = try ctx.arena.create(Payload.Child);
1840 new_pl.* = .{ .base = .{ .tag = pl.base.tag }, .data = ctx.copyIndex(pl.data) };
1841 return initPayload(new_pl);
1842 },
1843
1844 .array,
1845 .vector,
1846 => {
1847 const pl = self.cast(Payload.Sequence).?;
1848 const new_pl = try ctx.arena.create(Payload.Sequence);
1849 new_pl.* = .{
1850 .base = .{ .tag = pl.base.tag },
1851 .data = .{ .len = pl.data.len, .elem_type = ctx.copyIndex(pl.data.elem_type) },
1852 };
1853 return initPayload(new_pl);
1854 },
1855
1856 .fwd_anon_struct,
1857 .fwd_anon_union,
1858 => {
1859 const pl = self.cast(Payload.Fields).?;
1860 const new_pl = try ctx.arena.create(Payload.Fields);
1861 new_pl.* = .{
1862 .base = .{ .tag = pl.base.tag },
1863 .data = try copyFields(ctx, pl.data),
1864 };
1865 return initPayload(new_pl);
1866 },
1867
1868 .fwd_struct,
1869 .fwd_union,
1870 => {
1871 const pl = self.cast(Payload.FwdDecl).?;
1872 const new_pl = try ctx.arena.create(Payload.FwdDecl);
1873 new_pl.* = .{ .base = .{ .tag = pl.base.tag }, .data = pl.data };
1874 return initPayload(new_pl);
1875 },
1876
1877 .unnamed_struct,
1878 .unnamed_union,
1879 .packed_unnamed_struct,
1880 .packed_unnamed_union,
1881 => {
1882 const pl = self.cast(Payload.Unnamed).?;
1883 const new_pl = try ctx.arena.create(Payload.Unnamed);
1884 new_pl.* = .{ .base = .{ .tag = pl.base.tag }, .data = .{
1885 .fields = try copyFields(ctx, pl.data.fields),
1886 .owner_decl = pl.data.owner_decl,
1887 .id = pl.data.id,
1888 } };
1889 return initPayload(new_pl);
1890 },
1891
1892 .anon_struct,
1893 .anon_union,
1894 .@"struct",
1895 .@"union",
1896 .packed_struct,
1897 .packed_union,
1898 => {
1899 const pl = self.cast(Payload.Aggregate).?;
1900 const new_pl = try ctx.arena.create(Payload.Aggregate);
1901 new_pl.* = .{ .base = .{ .tag = pl.base.tag }, .data = .{
1902 .fields = try copyFields(ctx, pl.data.fields),
1903 .fwd_decl = ctx.copyIndex(pl.data.fwd_decl),
1904 } };
1905 return initPayload(new_pl);
1906 },
1907
1908 .function,
1909 .varargs_function,
1910 => {
1911 const pl = self.cast(Payload.Function).?;
1912 const new_pl = try ctx.arena.create(Payload.Function);
1913 new_pl.* = .{ .base = .{ .tag = pl.base.tag }, .data = .{
1914 .return_type = ctx.copyIndex(pl.data.return_type),
1915 .param_types = try copyParams(ctx, pl.data.param_types),
1916 } };
1917 return initPayload(new_pl);
1918 },
1919 }
1920 }
1921
1922 fn createFromType(store: *Store.Promoted, ty: Type, zcu: *Zcu, mod: *Module, kind: Kind) !CType {
1923 var convert: Convert = undefined;
1924 try convert.initType(ty, kind, .{ .imm = .{ .set = &store.set, .zcu = zcu } });
1925 return createFromConvert(store, ty, zcu, mod, kind, &convert);
1926 }
1927
1928 fn createFromConvert(
1929 store: *Store.Promoted,
1930 ty: Type,
1931 zcu: *Zcu,
1932 mod: *Module,
1933 kind: Kind,
1934 convert: Convert,
1935 ) !CType {
1936 const ip = &zcu.intern_pool;
1937 const arena = store.arena.allocator();
1938 switch (convert.value) {
1939 .cty => |c| return c.copy(arena),
1940 .tag => |t| switch (t) {
1941 .fwd_anon_struct,
1942 .fwd_anon_union,
1943 .unnamed_struct,
1944 .unnamed_union,
1945 .packed_unnamed_struct,
1946 .packed_unnamed_union,
1947 .anon_struct,
1948 .anon_union,
1949 .@"struct",
1950 .@"union",
1951 .packed_struct,
1952 .packed_union,
1953 => {
1954 const zig_ty_tag = ty.zigTypeTag(zcu);
1955 const fields_len = switch (zig_ty_tag) {
1956 .Struct => ty.structFieldCount(zcu),
1957 .Union => zcu.typeToUnion(ty).?.field_types.len,
1958 else => unreachable,
1959 };
1960
1961 var c_fields_len: usize = 0;
1962 for (0..fields_len) |field_i| {
1963 const field_ty = ty.structFieldType(field_i, zcu);
1964 if ((zig_ty_tag == .Struct and ty.structFieldIsComptime(field_i, zcu)) or
1965 !field_ty.hasRuntimeBitsIgnoreComptime(zcu)) continue;
1966 c_fields_len += 1;
1967 }
1968
1969 const fields_pl = try arena.alloc(Payload.Fields.Field, c_fields_len);
1970 var c_field_i: usize = 0;
1971 for (0..fields_len) |field_i_usize| {
1972 const field_i: u32 = @intCast(field_i_usize);
1973 const field_ty = ty.structFieldType(field_i, zcu);
1974 if ((zig_ty_tag == .Struct and ty.structFieldIsComptime(field_i, zcu)) or
1975 !field_ty.hasRuntimeBitsIgnoreComptime(zcu)) continue;
1976
1977 defer c_field_i += 1;
1978 fields_pl[c_field_i] = .{
1979 .name = try if (ty.isSimpleTuple(zcu))
1980 std.fmt.allocPrintZ(arena, "f{}", .{field_i})
1981 else
1982 arena.dupeZ(u8, ip.stringToSlice(switch (zig_ty_tag) {
1983 .Struct => ty.legacyStructFieldName(field_i, zcu),
1984 .Union => ip.loadUnionType(ty.toIntern()).loadTagType(ip).names.get(ip)[field_i],
1985 else => unreachable,
1986 })),
1987 .type = store.set.typeToIndex(field_ty, zcu, mod, switch (kind) {
1988 .forward, .forward_parameter => .forward,
1989 .complete, .parameter, .payload => .complete,
1990 .global => .global,
1991 }).?,
1992 .alignas = AlignAs.fieldAlign(ty, field_i, zcu),
1993 };
1994 }
1995
1996 switch (t) {
1997 .fwd_anon_struct,
1998 .fwd_anon_union,
1999 => {
2000 const anon_pl = try arena.create(Payload.Fields);
2001 anon_pl.* = .{ .base = .{ .tag = t }, .data = fields_pl };
2002 return initPayload(anon_pl);
2003 },
2004
2005 .unnamed_struct,
2006 .unnamed_union,
2007 .packed_unnamed_struct,
2008 .packed_unnamed_union,
2009 => {
2010 const unnamed_pl = try arena.create(Payload.Unnamed);
2011 unnamed_pl.* = .{ .base = .{ .tag = t }, .data = .{
2012 .fields = fields_pl,
2013 .owner_decl = ty.getOwnerDecl(zcu),
2014 .id = if (ty.unionTagTypeSafety(zcu)) |_| 0 else unreachable,
2015 } };
2016 return initPayload(unnamed_pl);
2017 },
2018
2019 .anon_struct,
2020 .anon_union,
2021 .@"struct",
2022 .@"union",
2023 .packed_struct,
2024 .packed_union,
2025 => {
2026 const struct_pl = try arena.create(Payload.Aggregate);
2027 struct_pl.* = .{ .base = .{ .tag = t }, .data = .{
2028 .fields = fields_pl,
2029 .fwd_decl = store.set.typeToIndex(ty, zcu, mod, .forward).?,
2030 } };
2031 return initPayload(struct_pl);
2032 },
2033
2034 else => unreachable,
2035 }
2036 },
2037
2038 .function,
2039 .varargs_function,
2040 => {
2041 const info = zcu.typeToFunc(ty).?;
2042 assert(!info.is_generic);
2043 const param_kind: Kind = switch (kind) {
2044 .forward, .forward_parameter => .forward_parameter,
2045 .complete, .parameter, .global => .parameter,
2046 .payload => unreachable,
2047 };
2048
2049 var c_params_len: usize = 0;
2050 for (info.param_types.get(ip)) |param_type| {
2051 if (!Type.fromInterned(param_type).hasRuntimeBitsIgnoreComptime(zcu)) continue;
2052 c_params_len += 1;
2053 }
2054
2055 const params_pl = try arena.alloc(Index, c_params_len);
2056 var c_param_i: usize = 0;
2057 for (info.param_types.get(ip)) |param_type| {
2058 if (!Type.fromInterned(param_type).hasRuntimeBitsIgnoreComptime(zcu)) continue;
2059 params_pl[c_param_i] = store.set.typeToIndex(Type.fromInterned(param_type), zcu, mod, param_kind).?;
2060 c_param_i += 1;
2061 }
2062
2063 const fn_pl = try arena.create(Payload.Function);
2064 fn_pl.* = .{ .base = .{ .tag = t }, .data = .{
2065 .return_type = store.set.typeToIndex(Type.fromInterned(info.return_type), zcu, mod, param_kind).?,
2066 .param_types = params_pl,
2067 } };
2068 return initPayload(fn_pl);
2069 },
2070
2071 else => unreachable,
2072 },
2073 }
2074 }
2075
2076 pub const TypeAdapter64 = struct {
2077 kind: Kind,
2078 lookup: Convert.Lookup,
2079 convert: *const Convert,
2080
2081 fn eqlRecurse(self: @This(), ty: Type, cty: Index, kind: Kind) bool {
2082 assert(!self.lookup.isMutable());
2083
2084 var convert: Convert = undefined;
2085 convert.initType(ty, kind, self.lookup) catch unreachable;
2086
2087 const self_recurse = @This(){ .kind = kind, .lookup = self.lookup, .convert = &convert };
2088 return self_recurse.eql(ty, self.lookup.indexToCType(cty).?);
2089 }
2090
2091 pub fn eql(self: @This(), ty: Type, cty: CType) bool {
2092 const zcu = self.lookup.getZcu();
2093 const ip = &zcu.intern_pool;
2094 switch (self.convert.value) {
2095 .cty => |c| return c.eql(cty),
2096 .tag => |t| {
2097 if (t != cty.tag()) return false;
2098
2099 switch (t) {
2100 .fwd_anon_struct,
2101 .fwd_anon_union,
2102 => {
2103 if (!ty.isTupleOrAnonStruct(zcu)) return false;
2104
2105 var name_buf: [
2106 std.fmt.count("f{}", .{std.math.maxInt(usize)})
2107 ]u8 = undefined;
2108 const c_fields = cty.cast(Payload.Fields).?.data;
2109
2110 const zig_ty_tag = ty.zigTypeTag(zcu);
2111 var c_field_i: usize = 0;
2112 for (0..switch (zig_ty_tag) {
2113 .Struct => ty.structFieldCount(zcu),
2114 .Union => zcu.typeToUnion(ty).?.field_types.len,
2115 else => unreachable,
2116 }) |field_i_usize| {
2117 const field_i: u32 = @intCast(field_i_usize);
2118 const field_ty = ty.structFieldType(field_i, zcu);
2119 if ((zig_ty_tag == .Struct and ty.structFieldIsComptime(field_i, zcu)) or
2120 !field_ty.hasRuntimeBitsIgnoreComptime(zcu)) continue;
2121
2122 defer c_field_i += 1;
2123 const c_field = &c_fields[c_field_i];
2124
2125 if (!self.eqlRecurse(field_ty, c_field.type, switch (self.kind) {
2126 .forward, .forward_parameter => .forward,
2127 .complete, .parameter => .complete,
2128 .global => .global,
2129 .payload => unreachable,
2130 }) or !mem.eql(
2131 u8,
2132 if (ty.isSimpleTuple(zcu))
2133 std.fmt.bufPrintZ(&name_buf, "f{}", .{field_i}) catch unreachable
2134 else
2135 ip.stringToSlice(switch (zig_ty_tag) {
2136 .Struct => ty.legacyStructFieldName(field_i, zcu),
2137 .Union => ip.loadUnionType(ty.toIntern()).loadTagType(ip).names.get(ip)[field_i],
2138 else => unreachable,
2139 }),
2140 mem.span(c_field.name),
2141 ) or AlignAs.fieldAlign(ty, field_i, zcu).@"align" !=
2142 c_field.alignas.@"align") return false;
2143 }
2144 return true;
2145 },
2146
2147 .unnamed_struct,
2148 .unnamed_union,
2149 .packed_unnamed_struct,
2150 .packed_unnamed_union,
2151 => switch (self.kind) {
2152 .forward, .forward_parameter, .complete, .parameter, .global => unreachable,
2153 .payload => if (ty.unionTagTypeSafety(zcu)) |_| {
2154 const data = cty.cast(Payload.Unnamed).?.data;
2155 return ty.getOwnerDecl(zcu) == data.owner_decl and data.id == 0;
2156 } else unreachable,
2157 },
2158
2159 .anon_struct,
2160 .anon_union,
2161 .@"struct",
2162 .@"union",
2163 .packed_struct,
2164 .packed_union,
2165 => return self.eqlRecurse(
2166 ty,
2167 cty.cast(Payload.Aggregate).?.data.fwd_decl,
2168 .forward,
2169 ),
2170
2171 .function,
2172 .varargs_function,
2173 => {
2174 if (ty.zigTypeTag(zcu) != .Fn) return false;
2175
2176 const info = zcu.typeToFunc(ty).?;
2177 assert(!info.is_generic);
2178 const data = cty.cast(Payload.Function).?.data;
2179 const param_kind: Kind = switch (self.kind) {
2180 .forward, .forward_parameter => .forward_parameter,
2181 .complete, .parameter, .global => .parameter,
2182 .payload => unreachable,
2183 };
2184
2185 if (!self.eqlRecurse(Type.fromInterned(info.return_type), data.return_type, param_kind))
2186 return false;
2187
2188 var c_param_i: usize = 0;
2189 for (info.param_types.get(ip)) |param_type| {
2190 if (!Type.fromInterned(param_type).hasRuntimeBitsIgnoreComptime(zcu)) continue;
2191
2192 if (c_param_i >= data.param_types.len) return false;
2193 const param_cty = data.param_types[c_param_i];
2194 c_param_i += 1;
2195
2196 if (!self.eqlRecurse(Type.fromInterned(param_type), param_cty, param_kind))
2197 return false;
2198 }
2199 return c_param_i == data.param_types.len;
2200 },
2201
2202 else => unreachable,
2203 }
2204 },
2205 }
2206 }
2207
2208 pub fn hash(self: @This(), ty: Type) u64 {
2209 var hasher = std.hash.Wyhash.init(0);
2210 self.updateHasher(&hasher, ty);
2211 return hasher.final();
2212 }
2213
2214 fn updateHasherRecurse(self: @This(), hasher: anytype, ty: Type, kind: Kind) void {
2215 assert(!self.lookup.isMutable());
2216
2217 var convert: Convert = undefined;
2218 convert.initType(ty, kind, self.lookup) catch unreachable;
2219
2220 const self_recurse = @This(){ .kind = kind, .lookup = self.lookup, .convert = &convert };
2221 self_recurse.updateHasher(hasher, ty);
2222 }
2223
2224 pub fn updateHasher(self: @This(), hasher: anytype, ty: Type) void {
2225 switch (self.convert.value) {
2226 .cty => |c| return c.updateHasher(hasher, self.lookup.getSet().?.*),
2227 .tag => |t| {
2228 autoHash(hasher, t);
2229
2230 const zcu = self.lookup.getZcu();
2231 const ip = &zcu.intern_pool;
2232 switch (t) {
2233 .fwd_anon_struct,
2234 .fwd_anon_union,
2235 => {
2236 var name_buf: [
2237 std.fmt.count("f{}", .{std.math.maxInt(usize)})
2238 ]u8 = undefined;
2239
2240 const zig_ty_tag = ty.zigTypeTag(zcu);
2241 for (0..switch (ty.zigTypeTag(zcu)) {
2242 .Struct => ty.structFieldCount(zcu),
2243 .Union => zcu.typeToUnion(ty).?.field_types.len,
2244 else => unreachable,
2245 }) |field_i_usize| {
2246 const field_i: u32 = @intCast(field_i_usize);
2247 const field_ty = ty.structFieldType(field_i, zcu);
2248 if ((zig_ty_tag == .Struct and ty.structFieldIsComptime(field_i, zcu)) or
2249 !field_ty.hasRuntimeBitsIgnoreComptime(zcu)) continue;
2250
2251 self.updateHasherRecurse(hasher, field_ty, switch (self.kind) {
2252 .forward, .forward_parameter => .forward,
2253 .complete, .parameter => .complete,
2254 .global => .global,
2255 .payload => unreachable,
2256 });
2257 hasher.update(if (ty.isSimpleTuple(zcu))
2258 std.fmt.bufPrint(&name_buf, "f{}", .{field_i}) catch unreachable
2259 else
2260 zcu.intern_pool.stringToSlice(switch (zig_ty_tag) {
2261 .Struct => ty.legacyStructFieldName(field_i, zcu),
2262 .Union => ip.loadUnionType(ty.toIntern()).loadTagType(ip).names.get(ip)[field_i],
2263 else => unreachable,
2264 }));
2265 autoHash(hasher, AlignAs.fieldAlign(ty, field_i, zcu).@"align");
2266 }
2267 },
2268
2269 .unnamed_struct,
2270 .unnamed_union,
2271 .packed_unnamed_struct,
2272 .packed_unnamed_union,
2273 => switch (self.kind) {
2274 .forward, .forward_parameter, .complete, .parameter, .global => unreachable,
2275 .payload => if (ty.unionTagTypeSafety(zcu)) |_| {
2276 autoHash(hasher, ty.getOwnerDecl(zcu));
2277 autoHash(hasher, @as(u32, 0));
2278 } else unreachable,
2279 },
2280
2281 .anon_struct,
2282 .anon_union,
2283 .@"struct",
2284 .@"union",
2285 .packed_struct,
2286 .packed_union,
2287 => self.updateHasherRecurse(hasher, ty, .forward),
2288
2289 .function,
2290 .varargs_function,
2291 => {
2292 const info = zcu.typeToFunc(ty).?;
2293 assert(!info.is_generic);
2294 const param_kind: Kind = switch (self.kind) {
2295 .forward, .forward_parameter => .forward_parameter,
2296 .complete, .parameter, .global => .parameter,
2297 .payload => unreachable,
2298 };
2299
2300 self.updateHasherRecurse(hasher, Type.fromInterned(info.return_type), param_kind);
2301 for (info.param_types.get(ip)) |param_type| {
2302 if (!Type.fromInterned(param_type).hasRuntimeBitsIgnoreComptime(zcu)) continue;
2303 self.updateHasherRecurse(hasher, Type.fromInterned(param_type), param_kind);
2304 }
2305 },
2306
2307 else => unreachable,
2308 }
2309 },
2310 }
2311 }
2312 };
2313
2314 pub const TypeAdapter32 = struct {
2315 kind: Kind,
2316 lookup: Convert.Lookup,
2317 convert: *const Convert,
2318
2319 fn to64(self: @This()) TypeAdapter64 {
2320 return .{ .kind = self.kind, .lookup = self.lookup, .convert = self.convert };
2321 }
2322
2323 pub fn eql(self: @This(), ty: Type, cty: CType, cty_index: usize) bool {
2324 _ = cty_index;
2325 return self.to64().eql(ty, cty);
2326 }
2327
2328 pub fn hash(self: @This(), ty: Type) u32 {
2329 return @as(u32, @truncate(self.to64().hash(ty)));
2330 }
2331 };
2332};
src/codegen/llvm.zig+24-24
......@@ -2033,7 +2033,7 @@ pub const Object = struct {
20332033 owner_decl.src_node + 1, // Line
20342034 try o.lowerDebugType(int_ty),
20352035 ty.abiSize(mod) * 8,
2036 ty.abiAlignment(mod).toByteUnits(0) * 8,
2036 (ty.abiAlignment(mod).toByteUnits() orelse 0) * 8,
20372037 try o.builder.debugTuple(enumerators),
20382038 );
20392039
......@@ -2120,7 +2120,7 @@ pub const Object = struct {
21202120 0, // Line
21212121 try o.lowerDebugType(ptr_ty),
21222122 ptr_size * 8,
2123 ptr_align.toByteUnits(0) * 8,
2123 (ptr_align.toByteUnits() orelse 0) * 8,
21242124 0, // Offset
21252125 );
21262126
......@@ -2131,7 +2131,7 @@ pub const Object = struct {
21312131 0, // Line
21322132 try o.lowerDebugType(len_ty),
21332133 len_size * 8,
2134 len_align.toByteUnits(0) * 8,
2134 (len_align.toByteUnits() orelse 0) * 8,
21352135 len_offset * 8,
21362136 );
21372137
......@@ -2142,7 +2142,7 @@ pub const Object = struct {
21422142 line,
21432143 .none, // Underlying type
21442144 ty.abiSize(mod) * 8,
2145 ty.abiAlignment(mod).toByteUnits(0) * 8,
2145 (ty.abiAlignment(mod).toByteUnits() orelse 0) * 8,
21462146 try o.builder.debugTuple(&.{
21472147 debug_ptr_type,
21482148 debug_len_type,
......@@ -2170,7 +2170,7 @@ pub const Object = struct {
21702170 0, // Line
21712171 debug_elem_ty,
21722172 target.ptrBitWidth(),
2173 ty.ptrAlignment(mod).toByteUnits(0) * 8,
2173 (ty.ptrAlignment(mod).toByteUnits() orelse 0) * 8,
21742174 0, // Offset
21752175 );
21762176
......@@ -2217,7 +2217,7 @@ pub const Object = struct {
22172217 0, // Line
22182218 try o.lowerDebugType(ty.childType(mod)),
22192219 ty.abiSize(mod) * 8,
2220 ty.abiAlignment(mod).toByteUnits(0) * 8,
2220 (ty.abiAlignment(mod).toByteUnits() orelse 0) * 8,
22212221 try o.builder.debugTuple(&.{
22222222 try o.builder.debugSubrange(
22232223 try o.builder.debugConstant(try o.builder.intConst(.i64, 0)),
......@@ -2260,7 +2260,7 @@ pub const Object = struct {
22602260 0, // Line
22612261 debug_elem_type,
22622262 ty.abiSize(mod) * 8,
2263 ty.abiAlignment(mod).toByteUnits(0) * 8,
2263 (ty.abiAlignment(mod).toByteUnits() orelse 0) * 8,
22642264 try o.builder.debugTuple(&.{
22652265 try o.builder.debugSubrange(
22662266 try o.builder.debugConstant(try o.builder.intConst(.i64, 0)),
......@@ -2316,7 +2316,7 @@ pub const Object = struct {
23162316 0, // Line
23172317 try o.lowerDebugType(child_ty),
23182318 payload_size * 8,
2319 payload_align.toByteUnits(0) * 8,
2319 (payload_align.toByteUnits() orelse 0) * 8,
23202320 0, // Offset
23212321 );
23222322
......@@ -2327,7 +2327,7 @@ pub const Object = struct {
23272327 0,
23282328 try o.lowerDebugType(non_null_ty),
23292329 non_null_size * 8,
2330 non_null_align.toByteUnits(0) * 8,
2330 (non_null_align.toByteUnits() orelse 0) * 8,
23312331 non_null_offset * 8,
23322332 );
23332333
......@@ -2338,7 +2338,7 @@ pub const Object = struct {
23382338 0, // Line
23392339 .none, // Underlying type
23402340 ty.abiSize(mod) * 8,
2341 ty.abiAlignment(mod).toByteUnits(0) * 8,
2341 (ty.abiAlignment(mod).toByteUnits() orelse 0) * 8,
23422342 try o.builder.debugTuple(&.{
23432343 debug_data_type,
23442344 debug_some_type,
......@@ -2396,7 +2396,7 @@ pub const Object = struct {
23962396 0, // Line
23972397 try o.lowerDebugType(Type.anyerror),
23982398 error_size * 8,
2399 error_align.toByteUnits(0) * 8,
2399 (error_align.toByteUnits() orelse 0) * 8,
24002400 error_offset * 8,
24012401 );
24022402 fields[payload_index] = try o.builder.debugMemberType(
......@@ -2406,7 +2406,7 @@ pub const Object = struct {
24062406 0, // Line
24072407 try o.lowerDebugType(payload_ty),
24082408 payload_size * 8,
2409 payload_align.toByteUnits(0) * 8,
2409 (payload_align.toByteUnits() orelse 0) * 8,
24102410 payload_offset * 8,
24112411 );
24122412
......@@ -2417,7 +2417,7 @@ pub const Object = struct {
24172417 0, // Line
24182418 .none, // Underlying type
24192419 ty.abiSize(mod) * 8,
2420 ty.abiAlignment(mod).toByteUnits(0) * 8,
2420 (ty.abiAlignment(mod).toByteUnits() orelse 0) * 8,
24212421 try o.builder.debugTuple(&fields),
24222422 );
24232423
......@@ -2485,7 +2485,7 @@ pub const Object = struct {
24852485 0,
24862486 try o.lowerDebugType(Type.fromInterned(field_ty)),
24872487 field_size * 8,
2488 field_align.toByteUnits(0) * 8,
2488 (field_align.toByteUnits() orelse 0) * 8,
24892489 field_offset * 8,
24902490 ));
24912491 }
......@@ -2497,7 +2497,7 @@ pub const Object = struct {
24972497 0, // Line
24982498 .none, // Underlying type
24992499 ty.abiSize(mod) * 8,
2500 ty.abiAlignment(mod).toByteUnits(0) * 8,
2500 (ty.abiAlignment(mod).toByteUnits() orelse 0) * 8,
25012501 try o.builder.debugTuple(fields.items),
25022502 );
25032503
......@@ -2566,7 +2566,7 @@ pub const Object = struct {
25662566 0, // Line
25672567 try o.lowerDebugType(field_ty),
25682568 field_size * 8,
2569 field_align.toByteUnits(0) * 8,
2569 (field_align.toByteUnits() orelse 0) * 8,
25702570 field_offset * 8,
25712571 ));
25722572 }
......@@ -2578,7 +2578,7 @@ pub const Object = struct {
25782578 0, // Line
25792579 .none, // Underlying type
25802580 ty.abiSize(mod) * 8,
2581 ty.abiAlignment(mod).toByteUnits(0) * 8,
2581 (ty.abiAlignment(mod).toByteUnits() orelse 0) * 8,
25822582 try o.builder.debugTuple(fields.items),
25832583 );
25842584
......@@ -2621,7 +2621,7 @@ pub const Object = struct {
26212621 0, // Line
26222622 .none, // Underlying type
26232623 ty.abiSize(mod) * 8,
2624 ty.abiAlignment(mod).toByteUnits(0) * 8,
2624 (ty.abiAlignment(mod).toByteUnits() orelse 0) * 8,
26252625 try o.builder.debugTuple(
26262626 &.{try o.lowerDebugType(Type.fromInterned(union_type.enum_tag_ty))},
26272627 ),
......@@ -2661,7 +2661,7 @@ pub const Object = struct {
26612661 0, // Line
26622662 try o.lowerDebugType(Type.fromInterned(field_ty)),
26632663 field_size * 8,
2664 field_align.toByteUnits(0) * 8,
2664 (field_align.toByteUnits() orelse 0) * 8,
26652665 0, // Offset
26662666 ));
26672667 }
......@@ -2680,7 +2680,7 @@ pub const Object = struct {
26802680 0, // Line
26812681 .none, // Underlying type
26822682 ty.abiSize(mod) * 8,
2683 ty.abiAlignment(mod).toByteUnits(0) * 8,
2683 (ty.abiAlignment(mod).toByteUnits() orelse 0) * 8,
26842684 try o.builder.debugTuple(fields.items),
26852685 );
26862686
......@@ -2711,7 +2711,7 @@ pub const Object = struct {
27112711 0, // Line
27122712 try o.lowerDebugType(Type.fromInterned(union_type.enum_tag_ty)),
27132713 layout.tag_size * 8,
2714 layout.tag_align.toByteUnits(0) * 8,
2714 (layout.tag_align.toByteUnits() orelse 0) * 8,
27152715 tag_offset * 8,
27162716 );
27172717
......@@ -2722,7 +2722,7 @@ pub const Object = struct {
27222722 0, // Line
27232723 debug_union_type,
27242724 layout.payload_size * 8,
2725 layout.payload_align.toByteUnits(0) * 8,
2725 (layout.payload_align.toByteUnits() orelse 0) * 8,
27262726 payload_offset * 8,
27272727 );
27282728
......@@ -2739,7 +2739,7 @@ pub const Object = struct {
27392739 0, // Line
27402740 .none, // Underlying type
27412741 ty.abiSize(mod) * 8,
2742 ty.abiAlignment(mod).toByteUnits(0) * 8,
2742 (ty.abiAlignment(mod).toByteUnits() orelse 0) * 8,
27432743 try o.builder.debugTuple(&full_fields),
27442744 );
27452745
......@@ -4473,7 +4473,7 @@ pub const Object = struct {
44734473 // The value cannot be undefined, because we use the `nonnull` annotation
44744474 // for non-optional pointers. We also need to respect the alignment, even though
44754475 // the address will never be dereferenced.
4476 const int: u64 = ptr_ty.ptrInfo(mod).flags.alignment.toByteUnitsOptional() orelse
4476 const int: u64 = ptr_ty.ptrInfo(mod).flags.alignment.toByteUnits() orelse
44774477 // Note that these 0xaa values are appropriate even in release-optimized builds
44784478 // because we need a well-defined value that is not null, and LLVM does not
44794479 // have an "undef_but_not_null" attribute. As an example, if this `alloc` AIR
src/crash_report.zig+1-1
......@@ -172,7 +172,7 @@ pub fn attachSegfaultHandler() void {
172172 };
173173}
174174
175fn handleSegfaultPosix(sig: i32, info: *const posix.siginfo_t, ctx_ptr: ?*const anyopaque) callconv(.C) noreturn {
175fn handleSegfaultPosix(sig: i32, info: *const posix.siginfo_t, ctx_ptr: ?*anyopaque) callconv(.C) noreturn {
176176 // TODO: use alarm() here to prevent infinite loops
177177 PanicSwitch.preDispatch();
178178
src/link/C.zig+98-123
......@@ -69,13 +69,13 @@ pub const DeclBlock = struct {
6969 fwd_decl: String = String.empty,
7070 /// Each `Decl` stores a set of used `CType`s. In `flush()`, we iterate
7171 /// over each `Decl` and generate the definition for each used `CType` once.
72 ctypes: codegen.CType.Store = .{},
73 /// Key and Value storage use the ctype arena.
72 ctype_pool: codegen.CType.Pool = codegen.CType.Pool.empty,
73 /// May contain string references to ctype_pool
7474 lazy_fns: codegen.LazyFnMap = .{},
7575
7676 fn deinit(db: *DeclBlock, gpa: Allocator) void {
7777 db.lazy_fns.deinit(gpa);
78 db.ctypes.deinit(gpa);
78 db.ctype_pool.deinit(gpa);
7979 db.* = undefined;
8080 }
8181};
......@@ -190,11 +190,12 @@ pub fn updateFunc(
190190 const decl = zcu.declPtr(decl_index);
191191 const gop = try self.decl_table.getOrPut(gpa, decl_index);
192192 if (!gop.found_existing) gop.value_ptr.* = .{};
193 const ctypes = &gop.value_ptr.ctypes;
193 const ctype_pool = &gop.value_ptr.ctype_pool;
194194 const lazy_fns = &gop.value_ptr.lazy_fns;
195195 const fwd_decl = &self.fwd_decl_buf;
196196 const code = &self.code_buf;
197 ctypes.clearRetainingCapacity(gpa);
197 try ctype_pool.init(gpa);
198 ctype_pool.clearRetainingCapacity();
198199 lazy_fns.clearRetainingCapacity();
199200 fwd_decl.clearRetainingCapacity();
200201 code.clearRetainingCapacity();
......@@ -213,7 +214,8 @@ pub fn updateFunc(
213214 .pass = .{ .decl = decl_index },
214215 .is_naked_fn = decl.typeOf(zcu).fnCallingConvention(zcu) == .Naked,
215216 .fwd_decl = fwd_decl.toManaged(gpa),
216 .ctypes = ctypes.*,
217 .ctype_pool = ctype_pool.*,
218 .scratch = .{},
217219 .anon_decl_deps = self.anon_decls,
218220 .aligned_anon_decls = self.aligned_anon_decls,
219221 },
......@@ -222,12 +224,16 @@ pub fn updateFunc(
222224 },
223225 .lazy_fns = lazy_fns.*,
224226 };
225
226227 function.object.indent_writer = .{ .underlying_writer = function.object.code.writer() };
227228 defer {
228229 self.anon_decls = function.object.dg.anon_decl_deps;
229230 self.aligned_anon_decls = function.object.dg.aligned_anon_decls;
230231 fwd_decl.* = function.object.dg.fwd_decl.moveToUnmanaged();
232 ctype_pool.* = function.object.dg.ctype_pool.move();
233 ctype_pool.freeUnusedCapacity(gpa);
234 function.object.dg.scratch.deinit(gpa);
235 lazy_fns.* = function.lazy_fns.move();
236 lazy_fns.shrinkAndFree(gpa, lazy_fns.count());
231237 code.* = function.object.code.moveToUnmanaged();
232238 function.deinit();
233239 }
......@@ -239,16 +245,8 @@ pub fn updateFunc(
239245 },
240246 else => |e| return e,
241247 };
242
243 ctypes.* = function.object.dg.ctypes.move();
244 lazy_fns.* = function.lazy_fns.move();
245
246 // Free excess allocated memory for this Decl.
247 ctypes.shrinkAndFree(gpa, ctypes.count());
248 lazy_fns.shrinkAndFree(gpa, lazy_fns.count());
249
250 gop.value_ptr.code = try self.addString(function.object.code.items);
251248 gop.value_ptr.fwd_decl = try self.addString(function.object.dg.fwd_decl.items);
249 gop.value_ptr.code = try self.addString(function.object.code.items);
252250}
253251
254252fn updateAnonDecl(self: *C, zcu: *Zcu, i: usize) !void {
......@@ -269,7 +267,8 @@ fn updateAnonDecl(self: *C, zcu: *Zcu, i: usize) !void {
269267 .pass = .{ .anon = anon_decl },
270268 .is_naked_fn = false,
271269 .fwd_decl = fwd_decl.toManaged(gpa),
272 .ctypes = .{},
270 .ctype_pool = codegen.CType.Pool.empty,
271 .scratch = .{},
273272 .anon_decl_deps = self.anon_decls,
274273 .aligned_anon_decls = self.aligned_anon_decls,
275274 },
......@@ -277,14 +276,15 @@ fn updateAnonDecl(self: *C, zcu: *Zcu, i: usize) !void {
277276 .indent_writer = undefined, // set later so we can get a pointer to object.code
278277 };
279278 object.indent_writer = .{ .underlying_writer = object.code.writer() };
280
281279 defer {
282280 self.anon_decls = object.dg.anon_decl_deps;
283281 self.aligned_anon_decls = object.dg.aligned_anon_decls;
284 object.dg.ctypes.deinit(object.dg.gpa);
285282 fwd_decl.* = object.dg.fwd_decl.moveToUnmanaged();
283 object.dg.ctype_pool.deinit(object.dg.gpa);
284 object.dg.scratch.deinit(gpa);
286285 code.* = object.code.moveToUnmanaged();
287286 }
287 try object.dg.ctype_pool.init(gpa);
288288
289289 const c_value: codegen.CValue = .{ .constant = Value.fromInterned(anon_decl) };
290290 const alignment: Alignment = self.aligned_anon_decls.get(anon_decl) orelse .none;
......@@ -297,13 +297,11 @@ fn updateAnonDecl(self: *C, zcu: *Zcu, i: usize) !void {
297297 else => |e| return e,
298298 };
299299
300 // Free excess allocated memory for this Decl.
301 object.dg.ctypes.shrinkAndFree(gpa, object.dg.ctypes.count());
302
300 object.dg.ctype_pool.freeUnusedCapacity(gpa);
303301 object.dg.anon_decl_deps.values()[i] = .{
304302 .code = try self.addString(object.code.items),
305303 .fwd_decl = try self.addString(object.dg.fwd_decl.items),
306 .ctypes = object.dg.ctypes.move(),
304 .ctype_pool = object.dg.ctype_pool.move(),
307305 };
308306}
309307
......@@ -315,13 +313,13 @@ pub fn updateDecl(self: *C, zcu: *Zcu, decl_index: InternPool.DeclIndex) !void {
315313
316314 const decl = zcu.declPtr(decl_index);
317315 const gop = try self.decl_table.getOrPut(gpa, decl_index);
318 if (!gop.found_existing) {
319 gop.value_ptr.* = .{};
320 }
321 const ctypes = &gop.value_ptr.ctypes;
316 errdefer _ = self.decl_table.pop();
317 if (!gop.found_existing) gop.value_ptr.* = .{};
318 const ctype_pool = &gop.value_ptr.ctype_pool;
322319 const fwd_decl = &self.fwd_decl_buf;
323320 const code = &self.code_buf;
324 ctypes.clearRetainingCapacity(gpa);
321 try ctype_pool.init(gpa);
322 ctype_pool.clearRetainingCapacity();
325323 fwd_decl.clearRetainingCapacity();
326324 code.clearRetainingCapacity();
327325
......@@ -334,7 +332,8 @@ pub fn updateDecl(self: *C, zcu: *Zcu, decl_index: InternPool.DeclIndex) !void {
334332 .pass = .{ .decl = decl_index },
335333 .is_naked_fn = false,
336334 .fwd_decl = fwd_decl.toManaged(gpa),
337 .ctypes = ctypes.*,
335 .ctype_pool = ctype_pool.*,
336 .scratch = .{},
338337 .anon_decl_deps = self.anon_decls,
339338 .aligned_anon_decls = self.aligned_anon_decls,
340339 },
......@@ -345,8 +344,10 @@ pub fn updateDecl(self: *C, zcu: *Zcu, decl_index: InternPool.DeclIndex) !void {
345344 defer {
346345 self.anon_decls = object.dg.anon_decl_deps;
347346 self.aligned_anon_decls = object.dg.aligned_anon_decls;
348 object.dg.ctypes.deinit(object.dg.gpa);
349347 fwd_decl.* = object.dg.fwd_decl.moveToUnmanaged();
348 ctype_pool.* = object.dg.ctype_pool.move();
349 ctype_pool.freeUnusedCapacity(gpa);
350 object.dg.scratch.deinit(gpa);
350351 code.* = object.code.moveToUnmanaged();
351352 }
352353
......@@ -357,12 +358,6 @@ pub fn updateDecl(self: *C, zcu: *Zcu, decl_index: InternPool.DeclIndex) !void {
357358 },
358359 else => |e| return e,
359360 };
360
361 ctypes.* = object.dg.ctypes.move();
362
363 // Free excess allocated memory for this Decl.
364 ctypes.shrinkAndFree(gpa, ctypes.count());
365
366361 gop.value_ptr.code = try self.addString(object.code.items);
367362 gop.value_ptr.fwd_decl = try self.addString(object.dg.fwd_decl.items);
368363}
......@@ -416,7 +411,10 @@ pub fn flushModule(self: *C, arena: Allocator, prog_node: *std.Progress.Node) !v
416411 // This code path happens exclusively with -ofmt=c. The flush logic for
417412 // emit-h is in `flushEmitH` below.
418413
419 var f: Flush = .{};
414 var f: Flush = .{
415 .ctype_pool = codegen.CType.Pool.empty,
416 .lazy_ctype_pool = codegen.CType.Pool.empty,
417 };
420418 defer f.deinit(gpa);
421419
422420 const abi_defines = try self.abiDefines(zcu.getTarget());
......@@ -443,7 +441,8 @@ pub fn flushModule(self: *C, arena: Allocator, prog_node: *std.Progress.Node) !v
443441
444442 self.lazy_fwd_decl_buf.clearRetainingCapacity();
445443 self.lazy_code_buf.clearRetainingCapacity();
446 try self.flushErrDecls(zcu, &f.lazy_ctypes);
444 try f.lazy_ctype_pool.init(gpa);
445 try self.flushErrDecls(zcu, &f.lazy_ctype_pool);
447446
448447 // Unlike other backends, the .c code we are emitting has order-dependent decls.
449448 // `CType`s, forward decls, and non-functions first.
......@@ -471,15 +470,15 @@ pub fn flushModule(self: *C, arena: Allocator, prog_node: *std.Progress.Node) !v
471470 {
472471 // We need to flush lazy ctypes after flushing all decls but before flushing any decl ctypes.
473472 // This ensures that every lazy CType.Index exactly matches the global CType.Index.
474 assert(f.ctypes.count() == 0);
475 try self.flushCTypes(zcu, &f, .flush, f.lazy_ctypes);
473 try f.ctype_pool.init(gpa);
474 try self.flushCTypes(zcu, &f, .flush, &f.lazy_ctype_pool);
476475
477476 for (self.anon_decls.keys(), self.anon_decls.values()) |anon_decl, decl_block| {
478 try self.flushCTypes(zcu, &f, .{ .anon = anon_decl }, decl_block.ctypes);
477 try self.flushCTypes(zcu, &f, .{ .anon = anon_decl }, &decl_block.ctype_pool);
479478 }
480479
481480 for (self.decl_table.keys(), self.decl_table.values()) |decl_index, decl_block| {
482 try self.flushCTypes(zcu, &f, .{ .decl = decl_index }, decl_block.ctypes);
481 try self.flushCTypes(zcu, &f, .{ .decl = decl_index }, &decl_block.ctype_pool);
483482 }
484483 }
485484
......@@ -510,11 +509,11 @@ pub fn flushModule(self: *C, arena: Allocator, prog_node: *std.Progress.Node) !v
510509}
511510
512511const Flush = struct {
513 ctypes: codegen.CType.Store = .{},
514 ctypes_map: std.ArrayListUnmanaged(codegen.CType.Index) = .{},
512 ctype_pool: codegen.CType.Pool,
513 ctype_global_from_decl_map: std.ArrayListUnmanaged(codegen.CType) = .{},
515514 ctypes_buf: std.ArrayListUnmanaged(u8) = .{},
516515
517 lazy_ctypes: codegen.CType.Store = .{},
516 lazy_ctype_pool: codegen.CType.Pool,
518517 lazy_fns: LazyFns = .{},
519518
520519 asm_buf: std.ArrayListUnmanaged(u8) = .{},
......@@ -536,10 +535,11 @@ const Flush = struct {
536535 f.all_buffers.deinit(gpa);
537536 f.asm_buf.deinit(gpa);
538537 f.lazy_fns.deinit(gpa);
539 f.lazy_ctypes.deinit(gpa);
538 f.lazy_ctype_pool.deinit(gpa);
540539 f.ctypes_buf.deinit(gpa);
541 f.ctypes_map.deinit(gpa);
542 f.ctypes.deinit(gpa);
540 assert(f.ctype_global_from_decl_map.items.len == 0);
541 f.ctype_global_from_decl_map.deinit(gpa);
542 f.ctype_pool.deinit(gpa);
543543 }
544544};
545545
......@@ -552,88 +552,59 @@ fn flushCTypes(
552552 zcu: *Zcu,
553553 f: *Flush,
554554 pass: codegen.DeclGen.Pass,
555 decl_ctypes: codegen.CType.Store,
555 decl_ctype_pool: *const codegen.CType.Pool,
556556) FlushDeclError!void {
557557 const gpa = self.base.comp.gpa;
558 const global_ctype_pool = &f.ctype_pool;
558559
559 const decl_ctypes_len = decl_ctypes.count();
560 f.ctypes_map.clearRetainingCapacity();
561 try f.ctypes_map.ensureTotalCapacity(gpa, decl_ctypes_len);
562
563 var global_ctypes = f.ctypes.promote(gpa);
564 defer f.ctypes.demote(global_ctypes);
560 const global_from_decl_map = &f.ctype_global_from_decl_map;
561 assert(global_from_decl_map.items.len == 0);
562 try global_from_decl_map.ensureTotalCapacity(gpa, decl_ctype_pool.items.len);
563 defer global_from_decl_map.clearRetainingCapacity();
565564
566565 var ctypes_buf = f.ctypes_buf.toManaged(gpa);
567566 defer f.ctypes_buf = ctypes_buf.moveToUnmanaged();
568567 const writer = ctypes_buf.writer();
569568
570 const slice = decl_ctypes.set.map.entries.slice();
571 for (slice.items(.key), 0..) |decl_cty, decl_i| {
572 const Context = struct {
573 arena: Allocator,
574 ctypes_map: []codegen.CType.Index,
575 cached_hash: codegen.CType.Store.Set.Map.Hash,
576 idx: codegen.CType.Index,
577
578 pub fn hash(ctx: @This(), _: codegen.CType) codegen.CType.Store.Set.Map.Hash {
579 return ctx.cached_hash;
569 for (0..decl_ctype_pool.items.len) |decl_ctype_pool_index| {
570 const PoolAdapter = struct {
571 global_from_decl_map: []const codegen.CType,
572 pub fn eql(pool_adapter: @This(), decl_ctype: codegen.CType, global_ctype: codegen.CType) bool {
573 return if (decl_ctype.toPoolIndex()) |decl_pool_index|
574 decl_pool_index < pool_adapter.global_from_decl_map.len and
575 pool_adapter.global_from_decl_map[decl_pool_index].eql(global_ctype)
576 else
577 decl_ctype.index == global_ctype.index;
580578 }
581 pub fn eql(ctx: @This(), lhs: codegen.CType, rhs: codegen.CType, _: usize) bool {
582 return lhs.eqlContext(rhs, ctx);
579 pub fn copy(pool_adapter: @This(), decl_ctype: codegen.CType) codegen.CType {
580 return if (decl_ctype.toPoolIndex()) |decl_pool_index|
581 pool_adapter.global_from_decl_map[decl_pool_index]
582 else
583 decl_ctype;
583584 }
584 pub fn eqlIndex(
585 ctx: @This(),
586 lhs_idx: codegen.CType.Index,
587 rhs_idx: codegen.CType.Index,
588 ) bool {
589 if (lhs_idx < codegen.CType.Tag.no_payload_count or
590 rhs_idx < codegen.CType.Tag.no_payload_count) return lhs_idx == rhs_idx;
591 const lhs_i = lhs_idx - codegen.CType.Tag.no_payload_count;
592 if (lhs_i >= ctx.ctypes_map.len) return false;
593 return ctx.ctypes_map[lhs_i] == rhs_idx;
594 }
595 pub fn copyIndex(ctx: @This(), idx: codegen.CType.Index) codegen.CType.Index {
596 if (idx < codegen.CType.Tag.no_payload_count) return idx;
597 return ctx.ctypes_map[idx - codegen.CType.Tag.no_payload_count];
598 }
599 };
600 const decl_idx = @as(codegen.CType.Index, @intCast(codegen.CType.Tag.no_payload_count + decl_i));
601 const ctx = Context{
602 .arena = global_ctypes.arena.allocator(),
603 .ctypes_map = f.ctypes_map.items,
604 .cached_hash = decl_ctypes.indexToHash(decl_idx),
605 .idx = decl_idx,
606585 };
607 const gop = try global_ctypes.set.map.getOrPutContextAdapted(gpa, decl_cty, ctx, .{
608 .store = &global_ctypes.set,
609 });
610 const global_idx =
611 @as(codegen.CType.Index, @intCast(codegen.CType.Tag.no_payload_count + gop.index));
612 f.ctypes_map.appendAssumeCapacity(global_idx);
613 if (!gop.found_existing) {
614 errdefer _ = global_ctypes.set.map.pop();
615 gop.key_ptr.* = try decl_cty.copyContext(ctx);
616 }
617 if (std.debug.runtime_safety) {
618 const global_cty = &global_ctypes.set.map.entries.items(.key)[gop.index];
619 assert(global_cty == gop.key_ptr);
620 assert(decl_cty.eqlContext(global_cty.*, ctx));
621 assert(decl_cty.hash(decl_ctypes.set) == global_cty.hash(global_ctypes.set));
622 }
586 const decl_ctype = codegen.CType.fromPoolIndex(decl_ctype_pool_index);
587 const global_ctype, const found_existing = try global_ctype_pool.getOrPutAdapted(
588 gpa,
589 decl_ctype_pool,
590 decl_ctype,
591 PoolAdapter{ .global_from_decl_map = global_from_decl_map.items },
592 );
593 global_from_decl_map.appendAssumeCapacity(global_ctype);
623594 try codegen.genTypeDecl(
624595 zcu,
625596 writer,
626 global_ctypes.set,
627 global_idx,
597 global_ctype_pool,
598 global_ctype,
628599 pass,
629 decl_ctypes.set,
630 decl_idx,
631 gop.found_existing,
600 decl_ctype_pool,
601 decl_ctype,
602 found_existing,
632603 );
633604 }
634605}
635606
636fn flushErrDecls(self: *C, zcu: *Zcu, ctypes: *codegen.CType.Store) FlushDeclError!void {
607fn flushErrDecls(self: *C, zcu: *Zcu, ctype_pool: *codegen.CType.Pool) FlushDeclError!void {
637608 const gpa = self.base.comp.gpa;
638609
639610 const fwd_decl = &self.lazy_fwd_decl_buf;
......@@ -648,7 +619,8 @@ fn flushErrDecls(self: *C, zcu: *Zcu, ctypes: *codegen.CType.Store) FlushDeclErr
648619 .pass = .flush,
649620 .is_naked_fn = false,
650621 .fwd_decl = fwd_decl.toManaged(gpa),
651 .ctypes = ctypes.*,
622 .ctype_pool = ctype_pool.*,
623 .scratch = .{},
652624 .anon_decl_deps = self.anon_decls,
653625 .aligned_anon_decls = self.aligned_anon_decls,
654626 },
......@@ -659,8 +631,10 @@ fn flushErrDecls(self: *C, zcu: *Zcu, ctypes: *codegen.CType.Store) FlushDeclErr
659631 defer {
660632 self.anon_decls = object.dg.anon_decl_deps;
661633 self.aligned_anon_decls = object.dg.aligned_anon_decls;
662 object.dg.ctypes.deinit(gpa);
663634 fwd_decl.* = object.dg.fwd_decl.moveToUnmanaged();
635 ctype_pool.* = object.dg.ctype_pool.move();
636 ctype_pool.freeUnusedCapacity(gpa);
637 object.dg.scratch.deinit(gpa);
664638 code.* = object.code.moveToUnmanaged();
665639 }
666640
......@@ -668,15 +642,14 @@ fn flushErrDecls(self: *C, zcu: *Zcu, ctypes: *codegen.CType.Store) FlushDeclErr
668642 error.AnalysisFail => unreachable,
669643 else => |e| return e,
670644 };
671
672 ctypes.* = object.dg.ctypes.move();
673645}
674646
675647fn flushLazyFn(
676648 self: *C,
677649 zcu: *Zcu,
678650 mod: *Module,
679 ctypes: *codegen.CType.Store,
651 ctype_pool: *codegen.CType.Pool,
652 lazy_ctype_pool: *const codegen.CType.Pool,
680653 lazy_fn: codegen.LazyFnMap.Entry,
681654) FlushDeclError!void {
682655 const gpa = self.base.comp.gpa;
......@@ -693,7 +666,8 @@ fn flushLazyFn(
693666 .pass = .flush,
694667 .is_naked_fn = false,
695668 .fwd_decl = fwd_decl.toManaged(gpa),
696 .ctypes = ctypes.*,
669 .ctype_pool = ctype_pool.*,
670 .scratch = .{},
697671 .anon_decl_deps = .{},
698672 .aligned_anon_decls = .{},
699673 },
......@@ -706,17 +680,17 @@ fn flushLazyFn(
706680 // `updateFunc()` does.
707681 assert(object.dg.anon_decl_deps.count() == 0);
708682 assert(object.dg.aligned_anon_decls.count() == 0);
709 object.dg.ctypes.deinit(gpa);
710683 fwd_decl.* = object.dg.fwd_decl.moveToUnmanaged();
684 ctype_pool.* = object.dg.ctype_pool.move();
685 ctype_pool.freeUnusedCapacity(gpa);
686 object.dg.scratch.deinit(gpa);
711687 code.* = object.code.moveToUnmanaged();
712688 }
713689
714 codegen.genLazyFn(&object, lazy_fn) catch |err| switch (err) {
690 codegen.genLazyFn(&object, lazy_ctype_pool, lazy_fn) catch |err| switch (err) {
715691 error.AnalysisFail => unreachable,
716692 else => |e| return e,
717693 };
718
719 ctypes.* = object.dg.ctypes.move();
720694}
721695
722696fn flushLazyFns(
......@@ -724,6 +698,7 @@ fn flushLazyFns(
724698 zcu: *Zcu,
725699 mod: *Module,
726700 f: *Flush,
701 lazy_ctype_pool: *const codegen.CType.Pool,
727702 lazy_fns: codegen.LazyFnMap,
728703) FlushDeclError!void {
729704 const gpa = self.base.comp.gpa;
......@@ -734,7 +709,7 @@ fn flushLazyFns(
734709 const gop = f.lazy_fns.getOrPutAssumeCapacity(entry.key_ptr.*);
735710 if (gop.found_existing) continue;
736711 gop.value_ptr.* = {};
737 try self.flushLazyFn(zcu, mod, &f.lazy_ctypes, entry);
712 try self.flushLazyFn(zcu, mod, &f.lazy_ctype_pool, lazy_ctype_pool, entry);
738713 }
739714}
740715
......@@ -748,7 +723,7 @@ fn flushDeclBlock(
748723 extern_symbol_name: InternPool.OptionalNullTerminatedString,
749724) FlushDeclError!void {
750725 const gpa = self.base.comp.gpa;
751 try self.flushLazyFns(zcu, mod, f, decl_block.lazy_fns);
726 try self.flushLazyFns(zcu, mod, f, &decl_block.ctype_pool, decl_block.lazy_fns);
752727 try f.all_buffers.ensureUnusedCapacity(gpa, 1);
753728 fwd_decl: {
754729 if (extern_symbol_name.unwrap()) |name| {
src/link/Coff.zig+3-3
......@@ -1223,7 +1223,7 @@ fn lowerConst(self: *Coff, name: []const u8, val: Value, required_alignment: Int
12231223 atom.getSymbolPtr(self).value = try self.allocateAtom(
12241224 atom_index,
12251225 atom.size,
1226 @intCast(required_alignment.toByteUnitsOptional().?),
1226 @intCast(required_alignment.toByteUnits().?),
12271227 );
12281228 errdefer self.freeAtom(atom_index);
12291229
......@@ -1344,7 +1344,7 @@ fn updateLazySymbolAtom(
13441344 symbol.section_number = @as(coff.SectionNumber, @enumFromInt(section_index + 1));
13451345 symbol.type = .{ .complex_type = .NULL, .base_type = .NULL };
13461346
1347 const vaddr = try self.allocateAtom(atom_index, code_len, @intCast(required_alignment.toByteUnits(0)));
1347 const vaddr = try self.allocateAtom(atom_index, code_len, @intCast(required_alignment.toByteUnits() orelse 0));
13481348 errdefer self.freeAtom(atom_index);
13491349
13501350 log.debug("allocated atom for {s} at 0x{x}", .{ name, vaddr });
......@@ -1428,7 +1428,7 @@ fn updateDeclCode(self: *Coff, decl_index: InternPool.DeclIndex, code: []u8, com
14281428 const decl_name = mod.intern_pool.stringToSlice(try decl.fullyQualifiedName(mod));
14291429
14301430 log.debug("updateDeclCode {s}{*}", .{ decl_name, decl });
1431 const required_alignment: u32 = @intCast(decl.getAlignment(mod).toByteUnits(0));
1431 const required_alignment: u32 = @intCast(decl.getAlignment(mod).toByteUnits() orelse 0);
14321432
14331433 const decl_metadata = self.decls.get(decl_index).?;
14341434 const atom_index = decl_metadata.atom;
src/link/Elf.zig+1-1
......@@ -4051,7 +4051,7 @@ fn updateSectionSizes(self: *Elf) !void {
40514051 const padding = offset - shdr.sh_size;
40524052 atom_ptr.value = offset;
40534053 shdr.sh_size += padding + atom_ptr.size;
4054 shdr.sh_addralign = @max(shdr.sh_addralign, atom_ptr.alignment.toByteUnits(1));
4054 shdr.sh_addralign = @max(shdr.sh_addralign, atom_ptr.alignment.toByteUnits() orelse 1);
40554055 }
40564056 }
40574057
src/link/Elf/Atom.zig+1-1
......@@ -208,7 +208,7 @@ pub fn allocate(self: *Atom, elf_file: *Elf) !void {
208208 zig_object.debug_aranges_section_dirty = true;
209209 }
210210 }
211 shdr.sh_addralign = @max(shdr.sh_addralign, self.alignment.toByteUnitsOptional().?);
211 shdr.sh_addralign = @max(shdr.sh_addralign, self.alignment.toByteUnits().?);
212212
213213 // This function can also reallocate an atom.
214214 // In this case we need to "unplug" it from its previous location before
src/link/Elf/ZigObject.zig+1-1
......@@ -313,7 +313,7 @@ pub fn inputShdr(self: ZigObject, atom_index: Atom.Index, elf_file: *Elf) elf.El
313313 shdr.sh_addr = 0;
314314 shdr.sh_offset = 0;
315315 shdr.sh_size = atom.size;
316 shdr.sh_addralign = atom.alignment.toByteUnits(1);
316 shdr.sh_addralign = atom.alignment.toByteUnits() orelse 1;
317317 return shdr;
318318}
319319
src/link/Elf/relocatable.zig+1-1
......@@ -330,7 +330,7 @@ fn updateSectionSizes(elf_file: *Elf) !void {
330330 const padding = offset - shdr.sh_size;
331331 atom_ptr.value = offset;
332332 shdr.sh_size += padding + atom_ptr.size;
333 shdr.sh_addralign = @max(shdr.sh_addralign, atom_ptr.alignment.toByteUnits(1));
333 shdr.sh_addralign = @max(shdr.sh_addralign, atom_ptr.alignment.toByteUnits() orelse 1);
334334 }
335335 }
336336
src/link/Elf/thunks.zig+1-1
......@@ -63,7 +63,7 @@ fn advance(shdr: *elf.Elf64_Shdr, size: u64, alignment: Atom.Alignment) !u64 {
6363 const offset = alignment.forward(shdr.sh_size);
6464 const padding = offset - shdr.sh_size;
6565 shdr.sh_size += padding + size;
66 shdr.sh_addralign = @max(shdr.sh_addralign, alignment.toByteUnits(1));
66 shdr.sh_addralign = @max(shdr.sh_addralign, alignment.toByteUnits() orelse 1);
6767 return offset;
6868}
6969
src/link/MachO.zig+1-1
......@@ -2060,7 +2060,7 @@ fn calcSectionSizes(self: *MachO) !void {
20602060
20612061 for (atoms.items) |atom_index| {
20622062 const atom = self.getAtom(atom_index).?;
2063 const atom_alignment = atom.alignment.toByteUnits(1);
2063 const atom_alignment = atom.alignment.toByteUnits() orelse 1;
20642064 const offset = mem.alignForward(u64, header.size, atom_alignment);
20652065 const padding = offset - header.size;
20662066 atom.value = offset;
src/link/MachO/relocatable.zig+1-1
......@@ -380,7 +380,7 @@ fn calcSectionSizes(macho_file: *MachO) !void {
380380 if (atoms.items.len == 0) continue;
381381 for (atoms.items) |atom_index| {
382382 const atom = macho_file.getAtom(atom_index).?;
383 const atom_alignment = atom.alignment.toByteUnits(1);
383 const atom_alignment = atom.alignment.toByteUnits() orelse 1;
384384 const offset = mem.alignForward(u64, header.size, atom_alignment);
385385 const padding = offset - header.size;
386386 atom.value = offset;
src/link/Wasm.zig+1-1
......@@ -2263,7 +2263,7 @@ fn setupMemory(wasm: *Wasm) !void {
22632263 }
22642264 if (wasm.findGlobalSymbol("__tls_align")) |loc| {
22652265 const sym = loc.getSymbol(wasm);
2266 wasm.wasm_globals.items[sym.index - wasm.imported_globals_count].init.i32_const = @intCast(segment.alignment.toByteUnitsOptional().?);
2266 wasm.wasm_globals.items[sym.index - wasm.imported_globals_count].init.i32_const = @intCast(segment.alignment.toByteUnits().?);
22672267 }
22682268 if (wasm.findGlobalSymbol("__tls_base")) |loc| {
22692269 const sym = loc.getSymbol(wasm);
src/main.zig+1-5
......@@ -3544,11 +3544,7 @@ fn createModule(
35443544 // If the target is not overridden, use the parent's target. Of course,
35453545 // if this is the root module then we need to proceed to resolve the
35463546 // target.
3547 if (cli_mod.target_arch_os_abi == null and
3548 cli_mod.target_mcpu == null and
3549 create_module.dynamic_linker == null and
3550 create_module.object_format == null)
3551 {
3547 if (cli_mod.target_arch_os_abi == null and cli_mod.target_mcpu == null) {
35523548 if (parent) |p| break :t p.resolved_target;
35533549 }
35543550
src/print_value.zig+1-1
......@@ -80,7 +80,7 @@ pub fn print(
8080 inline .u64, .i64, .big_int => |x| try writer.print("{}", .{x}),
8181 .lazy_align => |ty| if (opt_sema) |sema| {
8282 const a = (try Type.fromInterned(ty).abiAlignmentAdvanced(mod, .{ .sema = sema })).scalar;
83 try writer.print("{}", .{a.toByteUnits(0)});
83 try writer.print("{}", .{a.toByteUnits() orelse 0});
8484 } else try writer.print("@alignOf({})", .{Type.fromInterned(ty).fmt(mod)}),
8585 .lazy_size => |ty| if (opt_sema) |sema| {
8686 const s = (try Type.fromInterned(ty).abiSizeAdvanced(mod, .{ .sema = sema })).scalar;
src/target.zig+1-1
......@@ -525,7 +525,7 @@ pub fn backendSupportsFeature(
525525 .error_return_trace => use_llvm,
526526 .is_named_enum_value => use_llvm,
527527 .error_set_has_value => use_llvm or cpu_arch.isWasm(),
528 .field_reordering => use_llvm,
528 .field_reordering => ofmt == .c or use_llvm,
529529 .safety_checked_instructions => use_llvm,
530530 };
531531}
src/type.zig+25-27
......@@ -203,7 +203,7 @@ pub const Type = struct {
203203 info.flags.alignment
204204 else
205205 Type.fromInterned(info.child).abiAlignment(mod);
206 try writer.print("align({d}", .{alignment.toByteUnits(0)});
206 try writer.print("align({d}", .{alignment.toByteUnits() orelse 0});
207207
208208 if (info.packed_offset.bit_offset != 0 or info.packed_offset.host_size != 0) {
209209 try writer.print(":{d}:{d}", .{
......@@ -863,7 +863,7 @@ pub const Type = struct {
863863 pub fn lazyAbiAlignment(ty: Type, mod: *Module) !Value {
864864 switch (try ty.abiAlignmentAdvanced(mod, .lazy)) {
865865 .val => |val| return val,
866 .scalar => |x| return mod.intValue(Type.comptime_int, x.toByteUnits(0)),
866 .scalar => |x| return mod.intValue(Type.comptime_int, x.toByteUnits() orelse 0),
867867 }
868868 }
869869
......@@ -905,7 +905,7 @@ pub const Type = struct {
905905 return .{ .scalar = intAbiAlignment(int_type.bits, target) };
906906 },
907907 .ptr_type, .anyframe_type => {
908 return .{ .scalar = Alignment.fromByteUnits(@divExact(target.ptrBitWidth(), 8)) };
908 return .{ .scalar = ptrAbiAlignment(target) };
909909 },
910910 .array_type => |array_type| {
911911 return Type.fromInterned(array_type.child).abiAlignmentAdvanced(mod, strat);
......@@ -920,6 +920,9 @@ pub const Type = struct {
920920 const alignment = std.math.ceilPowerOfTwoAssert(u32, bytes);
921921 return .{ .scalar = Alignment.fromByteUnits(alignment) };
922922 },
923 .stage2_c => {
924 return Type.fromInterned(vector_type.child).abiAlignmentAdvanced(mod, strat);
925 },
923926 .stage2_x86_64 => {
924927 if (vector_type.child == .bool_type) {
925928 if (vector_type.len > 256 and std.Target.x86.featureSetHas(target.cpu.features, .avx512f)) return .{ .scalar = .@"64" };
......@@ -966,12 +969,12 @@ pub const Type = struct {
966969
967970 .usize,
968971 .isize,
972 => return .{ .scalar = intAbiAlignment(target.ptrBitWidth(), target) },
973
969974 .export_options,
970975 .extern_options,
971976 .type_info,
972 => return .{
973 .scalar = Alignment.fromByteUnits(@divExact(target.ptrBitWidth(), 8)),
974 },
977 => return .{ .scalar = ptrAbiAlignment(target) },
975978
976979 .c_char => return .{ .scalar = cTypeAlign(target, .char) },
977980 .c_short => return .{ .scalar = cTypeAlign(target, .short) },
......@@ -1160,9 +1163,7 @@ pub const Type = struct {
11601163 const child_type = ty.optionalChild(mod);
11611164
11621165 switch (child_type.zigTypeTag(mod)) {
1163 .Pointer => return .{
1164 .scalar = Alignment.fromByteUnits(@divExact(target.ptrBitWidth(), 8)),
1165 },
1166 .Pointer => return .{ .scalar = ptrAbiAlignment(target) },
11661167 .ErrorSet => return abiAlignmentAdvanced(Type.anyerror, mod, strat),
11671168 .NoReturn => return .{ .scalar = .@"1" },
11681169 else => {},
......@@ -1274,6 +1275,10 @@ pub const Type = struct {
12741275 const total_bits = elem_bits * vector_type.len;
12751276 break :total_bytes (total_bits + 7) / 8;
12761277 },
1278 .stage2_c => total_bytes: {
1279 const elem_bytes: u32 = @intCast((try Type.fromInterned(vector_type.child).abiSizeAdvanced(mod, strat)).scalar);
1280 break :total_bytes elem_bytes * vector_type.len;
1281 },
12771282 .stage2_x86_64 => total_bytes: {
12781283 if (vector_type.child == .bool_type) break :total_bytes std.math.divCeil(u32, vector_type.len, 8) catch unreachable;
12791284 const elem_bytes: u32 = @intCast((try Type.fromInterned(vector_type.child).abiSizeAdvanced(mod, strat)).scalar);
......@@ -1527,15 +1532,19 @@ pub const Type = struct {
15271532 // guaranteed to be >= that of bool's (1 byte) the added size is exactly equal
15281533 // to the child type's ABI alignment.
15291534 return AbiSizeAdvanced{
1530 .scalar = child_ty.abiAlignment(mod).toByteUnits(0) + payload_size,
1535 .scalar = (child_ty.abiAlignment(mod).toByteUnits() orelse 0) + payload_size,
15311536 };
15321537 }
15331538
1534 fn intAbiSize(bits: u16, target: Target) u64 {
1539 pub fn ptrAbiAlignment(target: Target) Alignment {
1540 return Alignment.fromNonzeroByteUnits(@divExact(target.ptrBitWidth(), 8));
1541 }
1542
1543 pub fn intAbiSize(bits: u16, target: Target) u64 {
15351544 return intAbiAlignment(bits, target).forward(@as(u16, @intCast((@as(u17, bits) + 7) / 8)));
15361545 }
15371546
1538 fn intAbiAlignment(bits: u16, target: Target) Alignment {
1547 pub fn intAbiAlignment(bits: u16, target: Target) Alignment {
15391548 return Alignment.fromByteUnits(@min(
15401549 std.math.ceilPowerOfTwoPromote(u16, @as(u16, @intCast((@as(u17, bits) + 7) / 8))),
15411550 target.maxIntAlignment(),
......@@ -1572,7 +1581,7 @@ pub const Type = struct {
15721581 if (len == 0) return 0;
15731582 const elem_ty = Type.fromInterned(array_type.child);
15741583 const elem_size = @max(
1575 (try elem_ty.abiAlignmentAdvanced(mod, strat)).scalar.toByteUnits(0),
1584 (try elem_ty.abiAlignmentAdvanced(mod, strat)).scalar.toByteUnits() orelse 0,
15761585 (try elem_ty.abiSizeAdvanced(mod, strat)).scalar,
15771586 );
15781587 if (elem_size == 0) return 0;
......@@ -3016,26 +3025,15 @@ pub const Type = struct {
30163025 }
30173026
30183027 /// Returns none in the case of a tuple which uses the integer index as the field name.
3019 pub fn structFieldName(ty: Type, field_index: u32, mod: *Module) InternPool.OptionalNullTerminatedString {
3028 pub fn structFieldName(ty: Type, index: usize, mod: *Module) InternPool.OptionalNullTerminatedString {
30203029 const ip = &mod.intern_pool;
30213030 return switch (ip.indexToKey(ty.toIntern())) {
3022 .struct_type => ip.loadStructType(ty.toIntern()).fieldName(ip, field_index),
3023 .anon_struct_type => |anon_struct| anon_struct.fieldName(ip, field_index),
3031 .struct_type => ip.loadStructType(ty.toIntern()).fieldName(ip, index),
3032 .anon_struct_type => |anon_struct| anon_struct.fieldName(ip, index),
30243033 else => unreachable,
30253034 };
30263035 }
30273036
3028 /// When struct types have no field names, the names are implicitly understood to be
3029 /// strings corresponding to the field indexes in declaration order. It used to be the
3030 /// case that a NullTerminatedString would be stored for each field in this case, however,
3031 /// now, callers must handle the possibility that there are no names stored at all.
3032 /// Here we fake the previous behavior. Probably something better could be done by examining
3033 /// all the callsites of this function.
3034 pub fn legacyStructFieldName(ty: Type, i: u32, mod: *Module) InternPool.NullTerminatedString {
3035 return ty.structFieldName(i, mod).unwrap() orelse
3036 mod.intern_pool.getOrPutStringFmt(mod.gpa, "{d}", .{i}) catch @panic("OOM");
3037 }
3038
30393037 pub fn structFieldCount(ty: Type, mod: *Module) u32 {
30403038 const ip = &mod.intern_pool;
30413039 return switch (ip.indexToKey(ty.toIntern())) {
test/behavior/align.zig-1
......@@ -624,7 +624,6 @@ test "sub-aligned pointer field access" {
624624 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
625625 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
626626 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
627 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
628627
629628 // Originally reported at https://github.com/ziglang/zig/issues/14904
630629
test/behavior/vector.zig+4
......@@ -1176,18 +1176,22 @@ test "@shlWithOverflow" {
11761176test "alignment of vectors" {
11771177 try expect(@alignOf(@Vector(2, u8)) == switch (builtin.zig_backend) {
11781178 else => 2,
1179 .stage2_c => @alignOf(u8),
11791180 .stage2_x86_64 => 16,
11801181 });
11811182 try expect(@alignOf(@Vector(2, u1)) == switch (builtin.zig_backend) {
11821183 else => 1,
1184 .stage2_c => @alignOf(u1),
11831185 .stage2_x86_64 => 16,
11841186 });
11851187 try expect(@alignOf(@Vector(1, u1)) == switch (builtin.zig_backend) {
11861188 else => 1,
1189 .stage2_c => @alignOf(u1),
11871190 .stage2_x86_64 => 16,
11881191 });
11891192 try expect(@alignOf(@Vector(2, u16)) == switch (builtin.zig_backend) {
11901193 else => 4,
1194 .stage2_c => @alignOf(u16),
11911195 .stage2_x86_64 => 16,
11921196 });
11931197}
test/tests.zig+12-5
......@@ -1164,19 +1164,26 @@ pub fn addModuleTests(b: *std.Build, options: ModuleTestOptions) *Step {
11641164 compile_c.addCSourceFile(.{
11651165 .file = these_tests.getEmittedBin(),
11661166 .flags = &.{
1167 // TODO output -std=c89 compatible C code
1167 // Tracking issue for making the C backend generate C89 compatible code:
1168 // https://github.com/ziglang/zig/issues/19468
11681169 "-std=c99",
11691170 "-pedantic",
11701171 "-Werror",
1171 // TODO stop violating these pedantic errors. spotted everywhere
1172
1173 // Tracking issue for making the C backend generate code
1174 // that does not trigger warnings:
1175 // https://github.com/ziglang/zig/issues/19467
1176
1177 // spotted everywhere
11721178 "-Wno-builtin-requires-header",
1173 // TODO stop violating these pedantic errors. spotted on linux
1174 "-Wno-address-of-packed-member",
1179
1180 // spotted on linux
11751181 "-Wno-gnu-folding-constant",
11761182 "-Wno-incompatible-function-pointer-types",
11771183 "-Wno-incompatible-pointer-types",
11781184 "-Wno-overlength-strings",
1179 // TODO stop violating these pedantic errors. spotted on darwin
1185
1186 // spotted on darwin
11801187 "-Wno-dollar-in-identifier-extension",
11811188 "-Wno-absolute-value",
11821189 },
tools/lldb_pretty_printers.py+4-4
......@@ -354,7 +354,7 @@ def InstRef_SummaryProvider(value, _=None):
354354def InstIndex_SummaryProvider(value, _=None):
355355 return 'instructions[%d]' % value.unsigned
356356
357class Module_Decl__Module_Decl_Index_SynthProvider:
357class zig_DeclIndex_SynthProvider:
358358 def __init__(self, value, _=None): self.value = value
359359 def update(self):
360360 try:
......@@ -425,7 +425,7 @@ def InternPool_Find(thread):
425425 for frame in thread:
426426 ip = frame.FindVariable('ip') or frame.FindVariable('intern_pool')
427427 if ip: return ip
428 mod = frame.FindVariable('mod') or frame.FindVariable('module')
428 mod = frame.FindVariable('zcu') or frame.FindVariable('mod') or frame.FindVariable('module')
429429 if mod:
430430 ip = mod.GetChildMemberWithName('intern_pool')
431431 if ip: return ip
......@@ -617,7 +617,7 @@ type_tag_handlers = {
617617
618618def value_Value_str_lit(payload):
619619 for frame in payload.thread:
620 mod = frame.FindVariable('mod') or frame.FindVariable('module')
620 mod = frame.FindVariable('zcu') or frame.FindVariable('mod') or frame.FindVariable('module')
621621 if mod: break
622622 else: return
623623 return '"%s"' % zig_String_decode(mod.GetChildMemberWithName('string_literal_bytes').GetChildMemberWithName('items'), payload.GetChildMemberWithName('index').unsigned, payload.GetChildMemberWithName('len').unsigned)
......@@ -714,7 +714,7 @@ def __lldb_init_module(debugger, _=None):
714714 add(debugger, category='zig.stage2', type='Air.Inst::Air.Inst.Index', identifier='InstIndex', summary=True)
715715 add(debugger, category='zig.stage2', regex=True, type=MultiArrayList_Entry('Air\\.Inst'), identifier='TagAndPayload', synth=True, inline_children=True, summary=True)
716716 add(debugger, category='zig.stage2', regex=True, type='^Air\\.Inst\\.Data\\.Data__struct_[1-9][0-9]*$', inline_children=True, summary=True)
717 add(debugger, category='zig.stage2', type='Module.Decl::Module.Decl.Index', synth=True)
717 add(debugger, category='zig.stage2', type='zig.DeclIndex', synth=True)
718718 add(debugger, category='zig.stage2', type='Module.Namespace::Module.Namespace.Index', synth=True)
719719 add(debugger, category='zig.stage2', type='Module.LazySrcLoc', identifier='zig_TaggedUnion', synth=True)
720720 add(debugger, category='zig.stage2', type='InternPool.Index', synth=True)