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...@@ -564,7 +564,7 @@ set(ZIG_STAGE2_SOURCES
564 "${CMAKE_SOURCE_DIR}/src/clang_options_data.zig"564 "${CMAKE_SOURCE_DIR}/src/clang_options_data.zig"
565 "${CMAKE_SOURCE_DIR}/src/codegen.zig"565 "${CMAKE_SOURCE_DIR}/src/codegen.zig"
566 "${CMAKE_SOURCE_DIR}/src/codegen/c.zig"566 "${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"
568 "${CMAKE_SOURCE_DIR}/src/codegen/llvm.zig"568 "${CMAKE_SOURCE_DIR}/src/codegen/llvm.zig"
569 "${CMAKE_SOURCE_DIR}/src/codegen/llvm/bindings.zig"569 "${CMAKE_SOURCE_DIR}/src/codegen/llvm/bindings.zig"
570 "${CMAKE_SOURCE_DIR}/src/glibc.zig"570 "${CMAKE_SOURCE_DIR}/src/glibc.zig"
build.zig+1-3
...@@ -16,9 +16,7 @@ pub fn build(b: *std.Build) !void {...@@ -16,9 +16,7 @@ pub fn build(b: *std.Build) !void {
16 const only_c = b.option(bool, "only-c", "Translate the Zig compiler to C code, with only the C backend enabled") orelse false;16 const only_c = b.option(bool, "only-c", "Translate the Zig compiler to C code, with only the C backend enabled") orelse false;
17 const target = t: {17 const target = t: {
18 var default_target: std.zig.CrossTarget = .{};18 var default_target: std.zig.CrossTarget = .{};
19 if (only_c) {19 default_target.ofmt = b.option(std.Target.ObjectFormat, "ofmt", "Object format to target") orelse if (only_c) .c else null;
20 default_target.ofmt = .c;
21 }
22 break :t b.standardTargetOptions(.{ .default_target = default_target });20 break :t b.standardTargetOptions(.{ .default_target = default_target });
23 };21 };
2422
lib/std/c/darwin.zig+2-2
...@@ -1150,8 +1150,8 @@ pub const siginfo_t = extern struct {...@@ -1150,8 +1150,8 @@ pub const siginfo_t = extern struct {
11501150
1151/// Renamed from `sigaction` to `Sigaction` to avoid conflict with function name.1151/// Renamed from `sigaction` to `Sigaction` to avoid conflict with function name.
1152pub const Sigaction = extern struct {1152pub const Sigaction = extern struct {
1153 pub const handler_fn = *align(1) const fn (c_int) callconv(.C) void;1153 pub const handler_fn = *align(1) const fn (i32) callconv(.C) void;
1154 pub const sigaction_fn = *const fn (c_int, *const siginfo_t, ?*anyopaque) callconv(.C) void;1154 pub const sigaction_fn = *const fn (i32, *const siginfo_t, ?*anyopaque) callconv(.C) void;
11551155
1156 handler: extern union {1156 handler: extern union {
1157 handler: ?handler_fn,1157 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 };...@@ -690,8 +690,8 @@ pub const empty_sigset = sigset_t{ .__bits = [_]c_uint{0} ** _SIG_WORDS };
690pub const sig_atomic_t = c_int;690pub const sig_atomic_t = c_int;
691691
692pub const Sigaction = extern struct {692pub const Sigaction = extern struct {
693 pub const handler_fn = *align(1) const fn (c_int) callconv(.C) void;693 pub const handler_fn = *align(1) const fn (i32) callconv(.C) void;
694 pub const sigaction_fn = *const fn (c_int, *const siginfo_t, ?*anyopaque) callconv(.C) void;694 pub const sigaction_fn = *const fn (i32, *const siginfo_t, ?*anyopaque) callconv(.C) void;
695695
696 /// signal handler696 /// signal handler
697 handler: extern union {697 handler: extern union {
...@@ -702,7 +702,7 @@ pub const Sigaction = extern struct {...@@ -702,7 +702,7 @@ pub const Sigaction = extern struct {
702 mask: sigset_t,702 mask: sigset_t,
703};703};
704704
705pub const sig_t = *const fn (c_int) callconv(.C) void;705pub const sig_t = *const fn (i32) callconv(.C) void;
706706
707pub const SOCK = struct {707pub const SOCK = struct {
708 pub const STREAM = 1;708 pub const STREAM = 1;
lib/std/c/freebsd.zig+2-2
...@@ -1171,8 +1171,8 @@ const NSIG = 32;...@@ -1171,8 +1171,8 @@ const NSIG = 32;
11711171
1172/// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall.1172/// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall.
1173pub const Sigaction = extern struct {1173pub const Sigaction = extern struct {
1174 pub const handler_fn = *align(1) const fn (c_int) callconv(.C) void;1174 pub const handler_fn = *align(1) const fn (i32) callconv(.C) void;
1175 pub const sigaction_fn = *const fn (c_int, *const siginfo_t, ?*anyopaque) callconv(.C) void;1175 pub const sigaction_fn = *const fn (i32, *const siginfo_t, ?*anyopaque) callconv(.C) void;
11761176
1177 /// signal handler1177 /// signal handler
1178 handler: extern union {1178 handler: extern union {
lib/std/c/haiku.zig+1-1
...@@ -501,7 +501,7 @@ pub const siginfo_t = extern struct {...@@ -501,7 +501,7 @@ pub const siginfo_t = extern struct {
501/// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall.501/// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall.
502pub const Sigaction = extern struct {502pub const Sigaction = extern struct {
503 pub const handler_fn = *align(1) const fn (i32) callconv(.C) void;503 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
506 /// signal handler506 /// signal handler
507 handler: extern union {507 handler: extern union {
lib/std/c/netbsd.zig+2-2
...@@ -864,8 +864,8 @@ pub const SIG = struct {...@@ -864,8 +864,8 @@ pub const SIG = struct {
864864
865/// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall.865/// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall.
866pub const Sigaction = extern struct {866pub const Sigaction = extern struct {
867 pub const handler_fn = *align(1) const fn (c_int) callconv(.C) void;867 pub const handler_fn = *align(1) const fn (i32) callconv(.C) void;
868 pub const sigaction_fn = *const fn (c_int, *const siginfo_t, ?*anyopaque) callconv(.C) void;868 pub const sigaction_fn = *const fn (i32, *const siginfo_t, ?*anyopaque) callconv(.C) void;
869869
870 /// signal handler870 /// signal handler
871 handler: extern union {871 handler: extern union {
lib/std/c/openbsd.zig+2-2
...@@ -842,8 +842,8 @@ pub const SIG = struct {...@@ -842,8 +842,8 @@ pub const SIG = struct {
842842
843/// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall.843/// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall.
844pub const Sigaction = extern struct {844pub const Sigaction = extern struct {
845 pub const handler_fn = *align(1) const fn (c_int) callconv(.C) void;845 pub const handler_fn = *align(1) const fn (i32) callconv(.C) void;
846 pub const sigaction_fn = *const fn (c_int, *const siginfo_t, ?*anyopaque) callconv(.C) void;846 pub const sigaction_fn = *const fn (i32, *const siginfo_t, ?*anyopaque) callconv(.C) void;
847847
848 /// signal handler848 /// signal handler
849 handler: extern union {849 handler: extern union {
lib/std/c/solaris.zig+2-2
...@@ -874,8 +874,8 @@ pub const SIG = struct {...@@ -874,8 +874,8 @@ pub const SIG = struct {
874874
875/// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall.875/// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall.
876pub const Sigaction = extern struct {876pub const Sigaction = extern struct {
877 pub const handler_fn = *align(1) const fn (c_int) callconv(.C) void;877 pub const handler_fn = *align(1) const fn (i32) callconv(.C) void;
878 pub const sigaction_fn = *const fn (c_int, *const siginfo_t, ?*anyopaque) callconv(.C) void;878 pub const sigaction_fn = *const fn (i32, *const siginfo_t, ?*anyopaque) callconv(.C) void;
879879
880 /// signal options880 /// signal options
881 flags: c_uint,881 flags: c_uint,
lib/std/debug.zig+1-1
...@@ -2570,7 +2570,7 @@ fn resetSegfaultHandler() void {...@@ -2570,7 +2570,7 @@ fn resetSegfaultHandler() void {
2570 updateSegfaultHandler(&act) catch {};2570 updateSegfaultHandler(&act) catch {};
2571}2571}
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 {
2574 // Reset to the default handler so that if a segfault happens in this handler it will crash2574 // Reset to the default handler so that if a segfault happens in this handler it will crash
2575 // the process. Also when this handler returns, the original instruction will be repeated2575 // the process. Also when this handler returns, the original instruction will be repeated
2576 // and the resulting segfault will crash the process rather than continually dump stack traces.2576 // 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 {...@@ -695,8 +695,8 @@ pub const SIG = struct {
695};695};
696696
697pub const Sigaction = extern struct {697pub const Sigaction = extern struct {
698 pub const handler_fn = *align(1) const fn (c_int) callconv(.C) void;698 pub const handler_fn = *align(1) const fn (i32) callconv(.C) void;
699 pub const sigaction_fn = *const fn (c_int, *const siginfo_t, ?*anyopaque) callconv(.C) void;699 pub const sigaction_fn = *const fn (i32, *const siginfo_t, ?*anyopaque) callconv(.C) void;
700700
701 handler: extern union {701 handler: extern union {
702 handler: ?handler_fn,702 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...@@ -4301,7 +4301,7 @@ pub const all_mask: sigset_t = [_]u32{0xffffffff} ** @typeInfo(sigset_t).Array.l
4301pub const app_mask: sigset_t = [2]u32{ 0xfffffffc, 0x7fffffff } ++ [_]u32{0xffffffff} ** 30;4301pub const app_mask: sigset_t = [2]u32{ 0xfffffffc, 0x7fffffff } ++ [_]u32{0xffffffff} ** 30;
43024302
4303const k_sigaction_funcs = struct {4303const 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;
4305 const restorer = *const fn () callconv(.C) void;4305 const restorer = *const fn () callconv(.C) void;
4306};4306};
43074307
...@@ -4328,8 +4328,8 @@ pub const k_sigaction = switch (native_arch) {...@@ -4328,8 +4328,8 @@ pub const k_sigaction = switch (native_arch) {
43284328
4329/// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall.4329/// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall.
4330pub const Sigaction = extern struct {4330pub const Sigaction = extern struct {
4331 pub const handler_fn = *align(1) const fn (c_int) callconv(.C) void;4331 pub const handler_fn = *align(1) const fn (i32) callconv(.C) void;
4332 pub const sigaction_fn = *const fn (c_int, *const siginfo_t, ?*anyopaque) callconv(.C) void;4332 pub const sigaction_fn = *const fn (i32, *const siginfo_t, ?*anyopaque) callconv(.C) void;
43334333
4334 handler: extern union {4334 handler: extern union {
4335 handler: ?handler_fn,4335 handler: ?handler_fn,
lib/std/os/plan9.zig+2-2
...@@ -186,8 +186,8 @@ pub const empty_sigset = 0;...@@ -186,8 +186,8 @@ pub const empty_sigset = 0;
186pub const siginfo_t = c_long;186pub const siginfo_t = c_long;
187// TODO plan9 doesn't have sigaction_fn. Sigaction is not a union, but we incude it here to be compatible.187// TODO plan9 doesn't have sigaction_fn. Sigaction is not a union, but we incude it here to be compatible.
188pub const Sigaction = extern struct {188pub const Sigaction = extern struct {
189 pub const handler_fn = *const fn (c_int) callconv(.C) void;189 pub const handler_fn = *const fn (i32) callconv(.C) void;
190 pub const sigaction_fn = *const fn (c_int, *const siginfo_t, ?*anyopaque) callconv(.C) void;190 pub const sigaction_fn = *const fn (i32, *const siginfo_t, ?*anyopaque) callconv(.C) void;
191191
192 handler: extern union {192 handler: extern union {
193 handler: ?handler_fn,193 handler: ?handler_fn,
lib/std/start.zig+1-1
...@@ -597,4 +597,4 @@ fn maybeIgnoreSigpipe() void {...@@ -597,4 +597,4 @@ fn maybeIgnoreSigpipe() void {
597 }597 }
598}598}
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...@@ -3457,14 +3457,18 @@ fn processOneJob(comp: *Compilation, job: Job, prog_node: *std.Progress.Node) !v
3457 .pass = .{ .decl = decl_index },3457 .pass = .{ .decl = decl_index },
3458 .is_naked_fn = false,3458 .is_naked_fn = false,
3459 .fwd_decl = fwd_decl.toManaged(gpa),3459 .fwd_decl = fwd_decl.toManaged(gpa),
3460 .ctypes = .{},3460 .ctype_pool = c_codegen.CType.Pool.empty,
3461 .scratch = .{},
3461 .anon_decl_deps = .{},3462 .anon_decl_deps = .{},
3462 .aligned_anon_decls = .{},3463 .aligned_anon_decls = .{},
3463 };3464 };
3464 defer {3465 defer {
3465 dg.ctypes.deinit(gpa);3466 fwd_decl.* = dg.fwd_decl.moveToUnmanaged();
3466 dg.fwd_decl.deinit();3467 fwd_decl.shrinkAndFree(gpa, fwd_decl.items.len);
3468 dg.ctype_pool.deinit(gpa);
3469 dg.scratch.deinit(gpa);
3467 }3470 }
3471 try dg.ctype_pool.init(gpa);
34683472
3469 c_codegen.genHeader(&dg) catch |err| switch (err) {3473 c_codegen.genHeader(&dg) catch |err| switch (err) {
3470 error.AnalysisFail => {3474 error.AnalysisFail => {
...@@ -3473,9 +3477,6 @@ fn processOneJob(comp: *Compilation, job: Job, prog_node: *std.Progress.Node) !v...@@ -3473,9 +3477,6 @@ fn processOneJob(comp: *Compilation, job: Job, prog_node: *std.Progress.Node) !v
3473 },3477 },
3474 else => |e| return e,3478 else => |e| return e,
3475 };3479 };
3476
3477 fwd_decl.* = dg.fwd_decl.moveToUnmanaged();
3478 fwd_decl.shrinkAndFree(gpa, fwd_decl.items.len);
3479 },3480 },
3480 }3481 }
3481 },3482 },
src/InternPool.zig+2-9
...@@ -712,7 +712,7 @@ pub const Key = union(enum) {...@@ -712,7 +712,7 @@ pub const Key = union(enum) {
712 pub fn fieldName(712 pub fn fieldName(
713 self: AnonStructType,713 self: AnonStructType,
714 ip: *const InternPool,714 ip: *const InternPool,
715 index: u32,715 index: usize,
716 ) OptionalNullTerminatedString {716 ) OptionalNullTerminatedString {
717 if (self.names.len == 0)717 if (self.names.len == 0)
718 return .none;718 return .none;
...@@ -3879,20 +3879,13 @@ pub const Alignment = enum(u6) {...@@ -3879,20 +3879,13 @@ pub const Alignment = enum(u6) {
3879 none = std.math.maxInt(u6),3879 none = std.math.maxInt(u6),
3880 _,3880 _,
38813881
3882 pub fn toByteUnitsOptional(a: Alignment) ?u64 {3882 pub fn toByteUnits(a: Alignment) ?u64 {
3883 return switch (a) {3883 return switch (a) {
3884 .none => null,3884 .none => null,
3885 else => @as(u64, 1) << @intFromEnum(a),3885 else => @as(u64, 1) << @intFromEnum(a),
3886 };3886 };
3887 }3887 }
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
3896 pub fn fromByteUnits(n: u64) Alignment {3889 pub fn fromByteUnits(n: u64) Alignment {
3897 if (n == 0) return .none;3890 if (n == 0) return .none;
3898 assert(std.math.isPowerOfTwo(n));3891 assert(std.math.isPowerOfTwo(n));
src/Module.zig+1-1
...@@ -5846,7 +5846,7 @@ pub fn intBitsForValue(mod: *Module, val: Value, sign: bool) u16 {...@@ -5846,7 +5846,7 @@ pub fn intBitsForValue(mod: *Module, val: Value, sign: bool) u16 {
5846 return @as(u16, @intCast(big.bitCountTwosComp()));5846 return @as(u16, @intCast(big.bitCountTwosComp()));
5847 },5847 },
5848 .lazy_align => |lazy_ty| {5848 .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);
5850 },5850 },
5851 .lazy_size => |lazy_ty| {5851 .lazy_size => |lazy_ty| {
5852 return Type.smallestUnsignedBits(Type.fromInterned(lazy_ty).abiSize(mod)) + @intFromBool(sign);5852 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...@@ -6508,7 +6508,7 @@ fn zirSetAlignStack(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.Inst
6508 const alignment = try sema.resolveAlign(block, operand_src, extra.operand);6508 const alignment = try sema.resolveAlign(block, operand_src, extra.operand);
6509 if (alignment.order(Alignment.fromNonzeroByteUnits(256)).compare(.gt)) {6509 if (alignment.order(Alignment.fromNonzeroByteUnits(256)).compare(.gt)) {
6510 return sema.fail(block, src, "attempt to @setAlignStack({d}); maximum is 256", .{6510 return sema.fail(block, src, "attempt to @setAlignStack({d}); maximum is 256", .{
6511 alignment.toByteUnitsOptional().?,6511 alignment.toByteUnits().?,
6512 });6512 });
6513 }6513 }
65146514
...@@ -17804,7 +17804,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -17804,7 +17804,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
17804 },17804 },
17805 .Pointer => {17805 .Pointer => {
17806 const info = ty.ptrInfo(mod);17806 const info = ty.ptrInfo(mod);
17807 const alignment = if (info.flags.alignment.toByteUnitsOptional()) |alignment|17807 const alignment = if (info.flags.alignment.toByteUnits()) |alignment|
17808 try mod.intValue(Type.comptime_int, alignment)17808 try mod.intValue(Type.comptime_int, alignment)
17809 else17809 else
17810 try Type.fromInterned(info.child).lazyAbiAlignment(mod);17810 try Type.fromInterned(info.child).lazyAbiAlignment(mod);
...@@ -18279,7 +18279,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -18279,7 +18279,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
18279 // type: type,18279 // type: type,
18280 field_ty,18280 field_ty,
18281 // alignment: comptime_int,18281 // 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(),
18283 };18283 };
18284 field_val.* = try mod.intern(.{ .aggregate = .{18284 field_val.* = try mod.intern(.{ .aggregate = .{
18285 .ty = union_field_ty.toIntern(),18285 .ty = union_field_ty.toIntern(),
...@@ -18436,7 +18436,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -18436,7 +18436,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
18436 // is_comptime: bool,18436 // is_comptime: bool,
18437 Value.makeBool(is_comptime).toIntern(),18437 Value.makeBool(is_comptime).toIntern(),
18438 // alignment: comptime_int,18438 // 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(),
18440 };18440 };
18441 struct_field_val.* = try mod.intern(.{ .aggregate = .{18441 struct_field_val.* = try mod.intern(.{ .aggregate = .{
18442 .ty = struct_field_ty.toIntern(),18442 .ty = struct_field_ty.toIntern(),
...@@ -18505,7 +18505,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -18505,7 +18505,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
18505 // is_comptime: bool,18505 // is_comptime: bool,
18506 Value.makeBool(field_is_comptime).toIntern(),18506 Value.makeBool(field_is_comptime).toIntern(),
18507 // alignment: comptime_int,18507 // 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(),
18509 };18509 };
18510 field_val.* = try mod.intern(.{ .aggregate = .{18510 field_val.* = try mod.intern(.{ .aggregate = .{
18511 .ty = struct_field_ty.toIntern(),18511 .ty = struct_field_ty.toIntern(),
...@@ -22552,7 +22552,7 @@ fn zirPtrFromInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!...@@ -22552,7 +22552,7 @@ fn zirPtrFromInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!
22552 try sema.addSafetyCheck(block, src, is_non_zero, .cast_to_null);22552 try sema.addSafetyCheck(block, src, is_non_zero, .cast_to_null);
22553 }22553 }
22554 if (ptr_align.compare(.gt, .@"1")) {22554 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;
22556 const align_minus_1 = Air.internedToRef((try mod.intValue(Type.usize, align_bytes_minus_1)).toIntern());22556 const align_minus_1 = Air.internedToRef((try mod.intValue(Type.usize, align_bytes_minus_1)).toIntern());
22557 const remainder = try block.addBinOp(.bit_and, operand_coerced, align_minus_1);22557 const remainder = try block.addBinOp(.bit_and, operand_coerced, align_minus_1);
22558 const is_aligned = try block.addBinOp(.cmp_eq, remainder, .zero_usize);22558 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!...@@ -22572,7 +22572,7 @@ fn zirPtrFromInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!
22572 try sema.addSafetyCheck(block, src, is_non_zero, .cast_to_null);22572 try sema.addSafetyCheck(block, src, is_non_zero, .cast_to_null);
22573 }22573 }
22574 if (ptr_align.compare(.gt, .@"1")) {22574 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;
22576 const align_minus_1 = Air.internedToRef((try mod.intValue(Type.usize, align_bytes_minus_1)).toIntern());22576 const align_minus_1 = Air.internedToRef((try mod.intValue(Type.usize, align_bytes_minus_1)).toIntern());
22577 const remainder = try block.addBinOp(.bit_and, elem_coerced, align_minus_1);22577 const remainder = try block.addBinOp(.bit_and, elem_coerced, align_minus_1);
22578 const is_aligned = try block.addBinOp(.cmp_eq, remainder, .zero_usize);22578 const is_aligned = try block.addBinOp(.cmp_eq, remainder, .zero_usize);
...@@ -22970,10 +22970,10 @@ fn ptrCastFull(...@@ -22970,10 +22970,10 @@ fn ptrCastFull(
22970 const msg = try sema.errMsg(block, src, "cast increases pointer alignment", .{});22970 const msg = try sema.errMsg(block, src, "cast increases pointer alignment", .{});
22971 errdefer msg.destroy(sema.gpa);22971 errdefer msg.destroy(sema.gpa);
22972 try sema.errNote(block, operand_src, msg, "'{}' has alignment '{d}'", .{22972 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,
22974 });22974 });
22975 try sema.errNote(block, src, msg, "'{}' has alignment '{d}'", .{22975 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,
22977 });22977 });
22978 try sema.errNote(block, src, msg, "use @alignCast to assert pointer alignment", .{});22978 try sema.errNote(block, src, msg, "use @alignCast to assert pointer alignment", .{});
22979 break :msg msg;22979 break :msg msg;
...@@ -23067,7 +23067,7 @@ fn ptrCastFull(...@@ -23067,7 +23067,7 @@ fn ptrCastFull(
23067 if (!dest_align.check(addr)) {23067 if (!dest_align.check(addr)) {
23068 return sema.fail(block, operand_src, "pointer address 0x{X} is not aligned to {d} bytes", .{23068 return sema.fail(block, operand_src, "pointer address 0x{X} is not aligned to {d} bytes", .{
23069 addr,23069 addr,
23070 dest_align.toByteUnitsOptional().?,23070 dest_align.toByteUnits().?,
23071 });23071 });
23072 }23072 }
23073 }23073 }
...@@ -23110,7 +23110,7 @@ fn ptrCastFull(...@@ -23110,7 +23110,7 @@ fn ptrCastFull(
23110 dest_align.compare(.gt, src_align) and23110 dest_align.compare(.gt, src_align) and
23111 try sema.typeHasRuntimeBits(Type.fromInterned(dest_info.child)))23111 try sema.typeHasRuntimeBits(Type.fromInterned(dest_info.child)))
23112 {23112 {
23113 const align_bytes_minus_1 = dest_align.toByteUnitsOptional().? - 1;23113 const align_bytes_minus_1 = dest_align.toByteUnits().? - 1;
23114 const align_minus_1 = Air.internedToRef((try mod.intValue(Type.usize, align_bytes_minus_1)).toIntern());23114 const align_minus_1 = Air.internedToRef((try mod.intValue(Type.usize, align_bytes_minus_1)).toIntern());
23115 const ptr_int = try block.addUnOp(.int_from_ptr, ptr);23115 const ptr_int = try block.addUnOp(.int_from_ptr, ptr);
23116 const remainder = try block.addBinOp(.bit_and, ptr_int, align_minus_1);23116 const remainder = try block.addBinOp(.bit_and, ptr_int, align_minus_1);
...@@ -27837,7 +27837,7 @@ fn structFieldPtrByIndex(...@@ -27837,7 +27837,7 @@ fn structFieldPtrByIndex(
27837 const elem_size_bits = Type.fromInterned(ptr_ty_data.child).bitSize(mod);27837 const elem_size_bits = Type.fromInterned(ptr_ty_data.child).bitSize(mod);
27838 if (elem_size_bytes * 8 == elem_size_bits) {27838 if (elem_size_bytes * 8 == elem_size_bits) {
27839 const byte_offset = ptr_ty_data.packed_offset.bit_offset / 8;27839 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().?));
27841 assert(new_align != .none);27841 assert(new_align != .none);
27842 ptr_ty_data.flags.alignment = new_align;27842 ptr_ty_data.flags.alignment = new_align;
27843 ptr_ty_data.packed_offset = .{ .host_size = 0, .bit_offset = 0 };27843 ptr_ty_data.packed_offset = .{ .host_size = 0, .bit_offset = 0 };
...@@ -29132,7 +29132,7 @@ fn coerceExtra(...@@ -29132,7 +29132,7 @@ fn coerceExtra(
29132 .addr = .{ .int = if (dest_info.flags.alignment != .none)29132 .addr = .{ .int = if (dest_info.flags.alignment != .none)
29133 (try mod.intValue(29133 (try mod.intValue(
29134 Type.usize,29134 Type.usize,
29135 dest_info.flags.alignment.toByteUnitsOptional().?,29135 dest_info.flags.alignment.toByteUnits().?,
29136 )).toIntern()29136 )).toIntern()
29137 else29137 else
29138 try mod.intern_pool.getCoercedInts(29138 try mod.intern_pool.getCoercedInts(
...@@ -29800,7 +29800,7 @@ const InMemoryCoercionResult = union(enum) {...@@ -29800,7 +29800,7 @@ const InMemoryCoercionResult = union(enum) {
29800 },29800 },
29801 .ptr_alignment => |pair| {29801 .ptr_alignment => |pair| {
29802 try sema.errNote(block, src, msg, "pointer alignment '{d}' cannot cast into pointer alignment '{d}'", .{29802 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,
29804 });29804 });
29805 break;29805 break;
29806 },29806 },
src/Value.zig+8-8
...@@ -176,7 +176,7 @@ pub fn toBigIntAdvanced(...@@ -176,7 +176,7 @@ pub fn toBigIntAdvanced(
176 if (opt_sema) |sema| try sema.resolveTypeLayout(Type.fromInterned(ty));176 if (opt_sema) |sema| try sema.resolveTypeLayout(Type.fromInterned(ty));
177 const x = switch (int.storage) {177 const x = switch (int.storage) {
178 else => unreachable,178 else => unreachable,
179 .lazy_align => Type.fromInterned(ty).abiAlignment(mod).toByteUnits(0),179 .lazy_align => Type.fromInterned(ty).abiAlignment(mod).toByteUnits() orelse 0,
180 .lazy_size => Type.fromInterned(ty).abiSize(mod),180 .lazy_size => Type.fromInterned(ty).abiSize(mod),
181 };181 };
182 return BigIntMutable.init(&space.limbs, x).toConst();182 return BigIntMutable.init(&space.limbs, x).toConst();
...@@ -237,9 +237,9 @@ pub fn getUnsignedIntAdvanced(val: Value, mod: *Module, opt_sema: ?*Sema) !?u64...@@ -237,9 +237,9 @@ pub fn getUnsignedIntAdvanced(val: Value, mod: *Module, opt_sema: ?*Sema) !?u64
237 .u64 => |x| x,237 .u64 => |x| x,
238 .i64 => |x| std.math.cast(u64, x),238 .i64 => |x| std.math.cast(u64, x),
239 .lazy_align => |ty| if (opt_sema) |sema|239 .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
241 else241 else
242 Type.fromInterned(ty).abiAlignment(mod).toByteUnits(0),242 Type.fromInterned(ty).abiAlignment(mod).toByteUnits() orelse 0,
243 .lazy_size => |ty| if (opt_sema) |sema|243 .lazy_size => |ty| if (opt_sema) |sema|
244 (try Type.fromInterned(ty).abiSizeAdvanced(mod, .{ .sema = sema })).scalar244 (try Type.fromInterned(ty).abiSizeAdvanced(mod, .{ .sema = sema })).scalar
245 else245 else
...@@ -289,7 +289,7 @@ pub fn toSignedInt(val: Value, mod: *Module) i64 {...@@ -289,7 +289,7 @@ pub fn toSignedInt(val: Value, mod: *Module) i64 {
289 .big_int => |big_int| big_int.to(i64) catch unreachable,289 .big_int => |big_int| big_int.to(i64) catch unreachable,
290 .i64 => |x| x,290 .i64 => |x| x,
291 .u64 => |x| @intCast(x),291 .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),
293 .lazy_size => |ty| @intCast(Type.fromInterned(ty).abiSize(mod)),293 .lazy_size => |ty| @intCast(Type.fromInterned(ty).abiSize(mod)),
294 },294 },
295 else => unreachable,295 else => unreachable,
...@@ -497,7 +497,7 @@ pub fn writeToPackedMemory(...@@ -497,7 +497,7 @@ pub fn writeToPackedMemory(
497 inline .u64, .i64 => |int| std.mem.writeVarPackedInt(buffer, bit_offset, bits, int, endian),497 inline .u64, .i64 => |int| std.mem.writeVarPackedInt(buffer, bit_offset, bits, int, endian),
498 .big_int => |bigint| bigint.writePackedTwosComplement(buffer, bit_offset, bits, endian),498 .big_int => |bigint| bigint.writePackedTwosComplement(buffer, bit_offset, bits, endian),
499 .lazy_align => |lazy_align| {499 .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;
501 std.mem.writeVarPackedInt(buffer, bit_offset, bits, num, endian);501 std.mem.writeVarPackedInt(buffer, bit_offset, bits, num, endian);
502 },502 },
503 .lazy_size => |lazy_size| {503 .lazy_size => |lazy_size| {
...@@ -890,7 +890,7 @@ pub fn toFloat(val: Value, comptime T: type, mod: *Module) T {...@@ -890,7 +890,7 @@ pub fn toFloat(val: Value, comptime T: type, mod: *Module) T {
890 }890 }
891 return @floatFromInt(x);891 return @floatFromInt(x);
892 },892 },
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),
894 .lazy_size => |ty| @floatFromInt(Type.fromInterned(ty).abiSize(mod)),894 .lazy_size => |ty| @floatFromInt(Type.fromInterned(ty).abiSize(mod)),
895 },895 },
896 .float => |float| switch (float.storage) {896 .float => |float| switch (float.storage) {
...@@ -1529,9 +1529,9 @@ pub fn floatFromIntScalar(val: Value, float_ty: Type, mod: *Module, opt_sema: ?*...@@ -1529,9 +1529,9 @@ pub fn floatFromIntScalar(val: Value, float_ty: Type, mod: *Module, opt_sema: ?*
1529 },1529 },
1530 inline .u64, .i64 => |x| floatFromIntInner(x, float_ty, mod),1530 inline .u64, .i64 => |x| floatFromIntInner(x, float_ty, mod),
1531 .lazy_align => |ty| if (opt_sema) |sema| {1531 .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);
1533 } else {1533 } 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);
1535 },1535 },
1536 .lazy_size => |ty| if (opt_sema) |sema| {1536 .lazy_size => |ty| if (opt_sema) |sema| {
1537 return floatFromIntInner((try Type.fromInterned(ty).abiSizeAdvanced(mod, .{ .sema = sema })).scalar, float_ty, mod);1537 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 {...@@ -1296,7 +1296,7 @@ fn genFunc(func: *CodeGen) InnerError!void {
1296 // subtract it from the current stack pointer1296 // subtract it from the current stack pointer
1297 try prologue.append(.{ .tag = .i32_sub, .data = .{ .tag = {} } });1297 try prologue.append(.{ .tag = .i32_sub, .data = .{ .tag = {} } });
1298 // Get negative stack aligment1298 // 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 } });
1300 // Bitwise-and the value to get the new stack pointer to ensure the pointers are aligned with the abi alignment1300 // Bitwise-and the value to get the new stack pointer to ensure the pointers are aligned with the abi alignment
1301 try prologue.append(.{ .tag = .i32_and, .data = .{ .tag = {} } });1301 try prologue.append(.{ .tag = .i32_and, .data = .{ .tag = {} } });
1302 // store the current stack pointer as the bottom, which will be used to calculate all stack pointer offsets1302 // 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 {...@@ -2107,7 +2107,7 @@ fn airRet(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
2107 });2107 });
2108 try func.addMemArg(Mir.Inst.Tag.fromOpcode(opcode), .{2108 try func.addMemArg(Mir.Inst.Tag.fromOpcode(opcode), .{
2109 .offset = operand.offset(),2109 .offset = operand.offset(),
2110 .alignment = @intCast(scalar_type.abiAlignment(mod).toByteUnitsOptional().?),2110 .alignment = @intCast(scalar_type.abiAlignment(mod).toByteUnits().?),
2111 });2111 });
2112 },2112 },
2113 else => try func.emitWValue(operand),2113 else => try func.emitWValue(operand),
...@@ -2384,7 +2384,7 @@ fn store(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerE...@@ -2384,7 +2384,7 @@ fn store(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerE
2384 try func.mir_extra.appendSlice(func.gpa, &[_]u32{2384 try func.mir_extra.appendSlice(func.gpa, &[_]u32{
2385 std.wasm.simdOpcode(.v128_store),2385 std.wasm.simdOpcode(.v128_store),
2386 offset + lhs.offset(),2386 offset + lhs.offset(),
2387 @intCast(ty.abiAlignment(mod).toByteUnits(0)),2387 @intCast(ty.abiAlignment(mod).toByteUnits() orelse 0),
2388 });2388 });
2389 return func.addInst(.{ .tag = .simd_prefix, .data = .{ .payload = extra_index } });2389 return func.addInst(.{ .tag = .simd_prefix, .data = .{ .payload = extra_index } });
2390 },2390 },
...@@ -2440,7 +2440,7 @@ fn store(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerE...@@ -2440,7 +2440,7 @@ fn store(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerE
2440 Mir.Inst.Tag.fromOpcode(opcode),2440 Mir.Inst.Tag.fromOpcode(opcode),
2441 .{2441 .{
2442 .offset = offset + lhs.offset(),2442 .offset = offset + lhs.offset(),
2443 .alignment = @intCast(ty.abiAlignment(mod).toByteUnitsOptional().?),2443 .alignment = @intCast(ty.abiAlignment(mod).toByteUnits().?),
2444 },2444 },
2445 );2445 );
2446}2446}
...@@ -2500,7 +2500,7 @@ fn load(func: *CodeGen, operand: WValue, ty: Type, offset: u32) InnerError!WValu...@@ -2500,7 +2500,7 @@ fn load(func: *CodeGen, operand: WValue, ty: Type, offset: u32) InnerError!WValu
2500 try func.mir_extra.appendSlice(func.gpa, &[_]u32{2500 try func.mir_extra.appendSlice(func.gpa, &[_]u32{
2501 std.wasm.simdOpcode(.v128_load),2501 std.wasm.simdOpcode(.v128_load),
2502 offset + operand.offset(),2502 offset + operand.offset(),
2503 @intCast(ty.abiAlignment(mod).toByteUnitsOptional().?),2503 @intCast(ty.abiAlignment(mod).toByteUnits().?),
2504 });2504 });
2505 try func.addInst(.{ .tag = .simd_prefix, .data = .{ .payload = extra_index } });2505 try func.addInst(.{ .tag = .simd_prefix, .data = .{ .payload = extra_index } });
2506 return WValue{ .stack = {} };2506 return WValue{ .stack = {} };
...@@ -2518,7 +2518,7 @@ fn load(func: *CodeGen, operand: WValue, ty: Type, offset: u32) InnerError!WValu...@@ -2518,7 +2518,7 @@ fn load(func: *CodeGen, operand: WValue, ty: Type, offset: u32) InnerError!WValu
2518 Mir.Inst.Tag.fromOpcode(opcode),2518 Mir.Inst.Tag.fromOpcode(opcode),
2519 .{2519 .{
2520 .offset = offset + operand.offset(),2520 .offset = offset + operand.offset(),
2521 .alignment = @intCast(ty.abiAlignment(mod).toByteUnitsOptional().?),2521 .alignment = @intCast(ty.abiAlignment(mod).toByteUnits().?),
2522 },2522 },
2523 );2523 );
25242524
...@@ -3456,7 +3456,7 @@ fn intStorageAsI32(storage: InternPool.Key.Int.Storage, mod: *Module) i32 {...@@ -3456,7 +3456,7 @@ fn intStorageAsI32(storage: InternPool.Key.Int.Storage, mod: *Module) i32 {
3456 .i64 => |x| @as(i32, @intCast(x)),3456 .i64 => |x| @as(i32, @intCast(x)),
3457 .u64 => |x| @as(i32, @bitCast(@as(u32, @intCast(x)))),3457 .u64 => |x| @as(i32, @bitCast(@as(u32, @intCast(x)))),
3458 .big_int => unreachable,3458 .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)))),
3460 .lazy_size => |ty| @as(i32, @bitCast(@as(u32, @intCast(Type.fromInterned(ty).abiSize(mod))))),3460 .lazy_size => |ty| @as(i32, @bitCast(@as(u32, @intCast(Type.fromInterned(ty).abiSize(mod))))),
3461 };3461 };
3462}3462}
...@@ -4204,7 +4204,7 @@ fn airIsErr(func: *CodeGen, inst: Air.Inst.Index, opcode: wasm.Opcode) InnerErro...@@ -4204,7 +4204,7 @@ fn airIsErr(func: *CodeGen, inst: Air.Inst.Index, opcode: wasm.Opcode) InnerErro
4204 if (pl_ty.hasRuntimeBitsIgnoreComptime(mod)) {4204 if (pl_ty.hasRuntimeBitsIgnoreComptime(mod)) {
4205 try func.addMemArg(.i32_load16_u, .{4205 try func.addMemArg(.i32_load16_u, .{
4206 .offset = operand.offset() + @as(u32, @intCast(errUnionErrorOffset(pl_ty, mod))),4206 .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().?),
4208 });4208 });
4209 }4209 }
42104210
...@@ -5141,7 +5141,7 @@ fn airSplat(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -5141,7 +5141,7 @@ fn airSplat(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
5141 try func.mir_extra.appendSlice(func.gpa, &[_]u32{5141 try func.mir_extra.appendSlice(func.gpa, &[_]u32{
5142 opcode,5142 opcode,
5143 operand.offset(),5143 operand.offset(),
5144 @intCast(elem_ty.abiAlignment(mod).toByteUnitsOptional().?),5144 @intCast(elem_ty.abiAlignment(mod).toByteUnits().?),
5145 });5145 });
5146 try func.addInst(.{ .tag = .simd_prefix, .data = .{ .payload = extra_index } });5146 try func.addInst(.{ .tag = .simd_prefix, .data = .{ .payload = extra_index } });
5147 try func.addLabel(.local_set, result.local.value);5147 try func.addLabel(.local_set, result.local.value);
...@@ -6552,7 +6552,7 @@ fn lowerTry(...@@ -6552,7 +6552,7 @@ fn lowerTry(
6552 const err_offset = @as(u32, @intCast(errUnionErrorOffset(pl_ty, mod)));6552 const err_offset = @as(u32, @intCast(errUnionErrorOffset(pl_ty, mod)));
6553 try func.addMemArg(.i32_load16_u, .{6553 try func.addMemArg(.i32_load16_u, .{
6554 .offset = err_union.offset() + err_offset,6554 .offset = err_union.offset() + err_offset,
6555 .alignment = @intCast(Type.anyerror.abiAlignment(mod).toByteUnitsOptional().?),6555 .alignment = @intCast(Type.anyerror.abiAlignment(mod).toByteUnits().?),
6556 });6556 });
6557 }6557 }
6558 try func.addTag(.i32_eqz);6558 try func.addTag(.i32_eqz);
...@@ -7499,7 +7499,7 @@ fn airCmpxchg(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -7499,7 +7499,7 @@ fn airCmpxchg(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
7499 else => |size| return func.fail("TODO: implement `@cmpxchg` for types with abi size '{d}'", .{size}),7499 else => |size| return func.fail("TODO: implement `@cmpxchg` for types with abi size '{d}'", .{size}),
7500 }, .{7500 }, .{
7501 .offset = ptr_operand.offset(),7501 .offset = ptr_operand.offset(),
7502 .alignment = @intCast(ty.abiAlignment(mod).toByteUnitsOptional().?),7502 .alignment = @intCast(ty.abiAlignment(mod).toByteUnits().?),
7503 });7503 });
7504 try func.addLabel(.local_tee, val_local.local.value);7504 try func.addLabel(.local_tee, val_local.local.value);
7505 _ = try func.cmp(.stack, expected_val, ty, .eq);7505 _ = try func.cmp(.stack, expected_val, ty, .eq);
...@@ -7561,7 +7561,7 @@ fn airAtomicLoad(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -7561,7 +7561,7 @@ fn airAtomicLoad(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
7561 try func.emitWValue(ptr);7561 try func.emitWValue(ptr);
7562 try func.addAtomicMemArg(tag, .{7562 try func.addAtomicMemArg(tag, .{
7563 .offset = ptr.offset(),7563 .offset = ptr.offset(),
7564 .alignment = @intCast(ty.abiAlignment(mod).toByteUnitsOptional().?),7564 .alignment = @intCast(ty.abiAlignment(mod).toByteUnits().?),
7565 });7565 });
7566 } else {7566 } else {
7567 _ = try func.load(ptr, ty, 0);7567 _ = try func.load(ptr, ty, 0);
...@@ -7622,7 +7622,7 @@ fn airAtomicRmw(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -7622,7 +7622,7 @@ fn airAtomicRmw(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
7622 },7622 },
7623 .{7623 .{
7624 .offset = ptr.offset(),7624 .offset = ptr.offset(),
7625 .alignment = @intCast(ty.abiAlignment(mod).toByteUnitsOptional().?),7625 .alignment = @intCast(ty.abiAlignment(mod).toByteUnits().?),
7626 },7626 },
7627 );7627 );
7628 const select_res = try func.allocLocal(ty);7628 const select_res = try func.allocLocal(ty);
...@@ -7682,7 +7682,7 @@ fn airAtomicRmw(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -7682,7 +7682,7 @@ fn airAtomicRmw(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
7682 };7682 };
7683 try func.addAtomicMemArg(tag, .{7683 try func.addAtomicMemArg(tag, .{
7684 .offset = ptr.offset(),7684 .offset = ptr.offset(),
7685 .alignment = @intCast(ty.abiAlignment(mod).toByteUnitsOptional().?),7685 .alignment = @intCast(ty.abiAlignment(mod).toByteUnits().?),
7686 });7686 });
7687 const result = try WValue.toLocal(.stack, func, ty);7687 const result = try WValue.toLocal(.stack, func, ty);
7688 return func.finishAir(inst, result, &.{ pl_op.operand, extra.operand });7688 return func.finishAir(inst, result, &.{ pl_op.operand, extra.operand });
...@@ -7781,7 +7781,7 @@ fn airAtomicStore(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -7781,7 +7781,7 @@ fn airAtomicStore(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
7781 try func.lowerToStack(operand);7781 try func.lowerToStack(operand);
7782 try func.addAtomicMemArg(tag, .{7782 try func.addAtomicMemArg(tag, .{
7783 .offset = ptr.offset(),7783 .offset = ptr.offset(),
7784 .alignment = @intCast(ty.abiAlignment(mod).toByteUnitsOptional().?),7784 .alignment = @intCast(ty.abiAlignment(mod).toByteUnits().?),
7785 });7785 });
7786 } else {7786 } else {
7787 try func.store(ptr, operand, ty, 0);7787 try func.store(ptr, operand, ty, 0);
src/arch/x86_64/CodeGen.zig+3-3
...@@ -18959,7 +18959,7 @@ fn resolveCallingConventionValues(...@@ -18959,7 +18959,7 @@ fn resolveCallingConventionValues(
1895918959
18960 const param_size: u31 = @intCast(ty.abiSize(mod));18960 const param_size: u31 = @intCast(ty.abiSize(mod));
18961 const param_align: u31 =18961 const param_align: u31 =
18962 @intCast(@max(ty.abiAlignment(mod).toByteUnitsOptional().?, 8));18962 @intCast(@max(ty.abiAlignment(mod).toByteUnits().?, 8));
18963 result.stack_byte_count =18963 result.stack_byte_count =
18964 mem.alignForward(u31, result.stack_byte_count, param_align);18964 mem.alignForward(u31, result.stack_byte_count, param_align);
18965 arg.* = .{ .load_frame = .{18965 arg.* = .{ .load_frame = .{
...@@ -19003,7 +19003,7 @@ fn resolveCallingConventionValues(...@@ -19003,7 +19003,7 @@ fn resolveCallingConventionValues(
19003 continue;19003 continue;
19004 }19004 }
19005 const param_size: u31 = @intCast(ty.abiSize(mod));19005 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().?);
19007 result.stack_byte_count =19007 result.stack_byte_count =
19008 mem.alignForward(u31, result.stack_byte_count, param_align);19008 mem.alignForward(u31, result.stack_byte_count, param_align);
19009 arg.* = .{ .load_frame = .{19009 arg.* = .{ .load_frame = .{
...@@ -19096,7 +19096,7 @@ fn splitType(self: *Self, ty: Type) ![2]Type {...@@ -19096,7 +19096,7 @@ fn splitType(self: *Self, ty: Type) ![2]Type {
19096 .integer => switch (part_i) {19096 .integer => switch (part_i) {
19097 0 => Type.u64,19097 0 => Type.u64,
19098 1 => part: {19098 1 => part: {
19099 const elem_size = ty.abiAlignment(mod).minStrict(.@"8").toByteUnitsOptional().?;19099 const elem_size = ty.abiAlignment(mod).minStrict(.@"8").toByteUnits().?;
19100 const elem_ty = try mod.intType(.unsigned, @intCast(elem_size * 8));19100 const elem_ty = try mod.intType(.unsigned, @intCast(elem_size * 8));
19101 break :part switch (@divExact(ty.abiSize(mod) - 8, elem_size)) {19101 break :part switch (@divExact(ty.abiSize(mod) - 8, elem_size)) {
19102 1 => elem_ty,19102 1 => elem_ty,
src/codegen.zig+3-3
...@@ -548,7 +548,7 @@ pub fn generateSymbol(...@@ -548,7 +548,7 @@ pub fn generateSymbol(
548 }548 }
549549
550 const size = struct_type.size(ip).*;550 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
553 const padding = math.cast(553 const padding = math.cast(
554 usize,554 usize,
...@@ -893,12 +893,12 @@ fn genDeclRef(...@@ -893,12 +893,12 @@ fn genDeclRef(
893 // TODO this feels clunky. Perhaps we should check for it in `genTypedValue`?893 // TODO this feels clunky. Perhaps we should check for it in `genTypedValue`?
894 if (ty.castPtrToFn(zcu)) |fn_ty| {894 if (ty.castPtrToFn(zcu)) |fn_ty| {
895 if (zcu.typeToFunc(fn_ty).?.is_generic) {895 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().? });
897 }897 }
898 } else if (ty.zigTypeTag(zcu) == .Pointer) {898 } else if (ty.zigTypeTag(zcu) == .Pointer) {
899 const elem_ty = ty.elemType2(zcu);899 const elem_ty = ty.elemType2(zcu);
900 if (!elem_ty.hasRuntimeBits(zcu)) {900 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().? });
902 }902 }
903 }903 }
904904
src/codegen/c.zig+926-983
...@@ -22,7 +22,7 @@ const Alignment = InternPool.Alignment;...@@ -22,7 +22,7 @@ const Alignment = InternPool.Alignment;
22const BigIntLimb = std.math.big.Limb;22const BigIntLimb = std.math.big.Limb;
23const BigInt = std.math.big.int;23const BigInt = std.math.big.int;
2424
25pub const CType = @import("c/type.zig").CType;25pub const CType = @import("c/Type.zig");
2626
27pub const CValue = union(enum) {27pub const CValue = union(enum) {
28 none: void,28 none: void,
...@@ -62,7 +62,7 @@ pub const LazyFnKey = union(enum) {...@@ -62,7 +62,7 @@ pub const LazyFnKey = union(enum) {
62 never_inline: InternPool.DeclIndex,62 never_inline: InternPool.DeclIndex,
63};63};
64pub const LazyFnValue = struct {64pub const LazyFnValue = struct {
65 fn_name: []const u8,65 fn_name: CType.String,
66 data: Data,66 data: Data,
6767
68 pub const Data = union {68 pub const Data = union {
...@@ -74,19 +74,19 @@ pub const LazyFnValue = struct {...@@ -74,19 +74,19 @@ pub const LazyFnValue = struct {
74pub const LazyFnMap = std.AutoArrayHashMapUnmanaged(LazyFnKey, LazyFnValue);74pub const LazyFnMap = std.AutoArrayHashMapUnmanaged(LazyFnKey, LazyFnValue);
7575
76const Local = struct {76const Local = struct {
77 cty_idx: CType.Index,77 ctype: CType,
78 flags: packed struct(u32) {78 flags: packed struct(u32) {
79 alignas: CType.AlignAs,79 alignas: CType.AlignAs,
80 _: u20 = undefined,80 _: u20 = undefined,
81 },81 },
8282
83 pub fn getType(local: Local) LocalType {83 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 };
85 }85 }
86};86};
8787
88const LocalIndex = u16;88const LocalIndex = u16;
89const LocalType = struct { cty_idx: CType.Index, alignas: CType.AlignAs };89const LocalType = struct { ctype: CType, alignas: CType.AlignAs };
90const LocalsList = std.AutoArrayHashMapUnmanaged(LocalIndex, void);90const LocalsList = std.AutoArrayHashMapUnmanaged(LocalIndex, void);
91const LocalsMap = std.AutoArrayHashMapUnmanaged(LocalType, LocalsList);91const LocalsMap = std.AutoArrayHashMapUnmanaged(LocalType, LocalsList);
9292
...@@ -193,6 +193,7 @@ const reserved_idents = std.ComptimeStringMap(void, .{...@@ -193,6 +193,7 @@ const reserved_idents = std.ComptimeStringMap(void, .{
193 .{ "switch", {} },193 .{ "switch", {} },
194 .{ "thread_local", {} },194 .{ "thread_local", {} },
195 .{ "typedef", {} },195 .{ "typedef", {} },
196 .{ "typeof", {} },
196 .{ "uint16_t", {} },197 .{ "uint16_t", {} },
197 .{ "uint32_t", {} },198 .{ "uint32_t", {} },
198 .{ "uint64_t", {} },199 .{ "uint64_t", {} },
...@@ -309,12 +310,14 @@ pub const Function = struct {...@@ -309,12 +310,14 @@ pub const Function = struct {
309310
310 const result: CValue = if (lowersToArray(ty, zcu)) result: {311 const result: CValue = if (lowersToArray(ty, zcu)) result: {
311 const writer = f.object.codeHeaderWriter();312 const writer = f.object.codeHeaderWriter();
312 const alignment: Alignment = .none;313 const decl_c_value = try f.allocLocalValue(.{
313 const decl_c_value = try f.allocLocalValue(ty, alignment);314 .ctype = try f.ctypeFromType(ty, .complete),
315 .alignas = CType.AlignAs.fromAbiAlignment(ty.abiAlignment(zcu)),
316 });
314 const gpa = f.object.dg.gpa;317 const gpa = f.object.dg.gpa;
315 try f.allocs.put(gpa, decl_c_value.new_local, false);318 try f.allocs.put(gpa, decl_c_value.new_local, false);
316 try writer.writeAll("static ");319 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);
318 try writer.writeAll(" = ");321 try writer.writeAll(" = ");
319 try f.object.dg.renderValue(writer, val, .StaticInitializer);322 try f.object.dg.renderValue(writer, val, .StaticInitializer);
320 try writer.writeAll(";\n ");323 try writer.writeAll(";\n ");
...@@ -335,42 +338,39 @@ pub const Function = struct {...@@ -335,42 +338,39 @@ pub const Function = struct {
335 /// Skips the reuse logic. This function should be used for any persistent allocation, i.e.338 /// Skips the reuse logic. This function should be used for any persistent allocation, i.e.
336 /// those which go into `allocs`. This function does not add the resulting local into `allocs`;339 /// those which go into `allocs`. This function does not add the resulting local into `allocs`;
337 /// that responsibility lies with the caller.340 /// that responsibility lies with the caller.
338 fn allocLocalValue(f: *Function, ty: Type, alignment: Alignment) !CValue {341 fn allocLocalValue(f: *Function, local_type: LocalType) !CValue {
339 const zcu = f.object.dg.zcu;342 try f.locals.ensureUnusedCapacity(f.object.dg.gpa, 1);
340 const gpa = f.object.dg.gpa;343 defer f.locals.appendAssumeCapacity(.{
341 try f.locals.append(gpa, .{344 .ctype = local_type.ctype,
342 .cty_idx = try f.typeToIndex(ty, .complete),345 .flags = .{ .alignas = local_type.alignas },
343 .flags = .{
344 .alignas = CType.AlignAs.init(alignment, ty.abiAlignment(zcu)),
345 },
346 });346 });
347 return .{ .new_local = @intCast(f.locals.items.len - 1) };347 return .{ .new_local = @intCast(f.locals.items.len) };
348 }348 }
349349
350 fn allocLocal(f: *Function, inst: ?Air.Inst.Index, ty: Type) !CValue {350 fn allocLocal(f: *Function, inst: ?Air.Inst.Index, ty: Type) !CValue {
351 const result = try f.allocAlignedLocal(ty, .{}, .none);351 return f.allocAlignedLocal(inst, .{
352 if (inst) |i| {352 .ctype = try f.ctypeFromType(ty, .complete),
353 log.debug("%{d}: allocating t{d}", .{ i, result.new_local });353 .alignas = CType.AlignAs.fromAbiAlignment(ty.abiAlignment(f.object.dg.zcu)),
354 } else {354 });
355 log.debug("allocating t{d}", .{result.new_local});
356 }
357 return result;
358 }355 }
359356
360 /// Only allocates the local; does not print anything. Will attempt to re-use locals, so should357 /// Only allocates the local; does not print anything. Will attempt to re-use locals, so should
361 /// not be used for persistent locals (i.e. those in `allocs`).358 /// not be used for persistent locals (i.e. those in `allocs`).
362 fn allocAlignedLocal(f: *Function, ty: Type, _: CQualifiers, alignment: Alignment) !CValue {359 fn allocAlignedLocal(f: *Function, inst: ?Air.Inst.Index, local_type: LocalType) !CValue {
363 const zcu = f.object.dg.zcu;360 const result: CValue = result: {
364 if (f.free_locals_map.getPtr(.{361 if (f.free_locals_map.getPtr(local_type)) |locals_list| {
365 .cty_idx = try f.typeToIndex(ty, .complete),362 if (locals_list.popOrNull()) |local_entry| {
366 .alignas = CType.AlignAs.init(alignment, ty.abiAlignment(zcu)),363 break :result .{ .new_local = local_entry.key };
367 })) |locals_list| {364 }
368 if (locals_list.popOrNull()) |local_entry| {
369 return .{ .new_local = local_entry.key };
370 }365 }
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});
371 }372 }
372373 return result;
373 return f.allocLocalValue(ty, alignment);
374 }374 }
375375
376 fn writeCValue(f: *Function, w: anytype, c_value: CValue, location: ValueRenderLocation) !void {376 fn writeCValue(f: *Function, w: anytype, c_value: CValue, location: ValueRenderLocation) !void {
...@@ -380,15 +380,20 @@ pub const Function = struct {...@@ -380,15 +380,20 @@ pub const Function = struct {
380 .local_ref => |i| {380 .local_ref => |i| {
381 const local = &f.locals.items[i];381 const local = &f.locals.items[i];
382 if (local.flags.alignas.abiOrder().compare(.lt)) {382 if (local.flags.alignas.abiOrder().compare(.lt)) {
383 const zcu = f.object.dg.zcu;383 const gpa = f.object.dg.gpa;
384 const pointee_ty = try zcu.intType(.unsigned, @min(384 const mod = f.object.dg.mod;
385 local.flags.alignas.@"align".toByteUnitsOptional().?,385 const ctype_pool = &f.object.dg.ctype_pool;
386 f.object.dg.mod.resolved_target.result.maxIntAlignment(),
387 ) * 8);
388 const ptr_ty = try zcu.singleMutPtrType(pointee_ty);
389386
390 try w.writeByte('(');387 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 }));
392 try w.writeByte(')');397 try w.writeByte(')');
393 }398 }
394 try w.print("&t{d}", .{i});399 try w.print("&t{d}", .{i});
...@@ -460,28 +465,20 @@ pub const Function = struct {...@@ -460,28 +465,20 @@ pub const Function = struct {
460 return f.object.dg.fail(format, args);465 return f.object.dg.fail(format, args);
461 }466 }
462467
463 fn indexToCType(f: *Function, idx: CType.Index) CType {468 fn ctypeFromType(f: *Function, ty: Type, kind: CType.Kind) !CType {
464 return f.object.dg.indexToCType(idx);469 return f.object.dg.ctypeFromType(ty, kind);
465 }
466
467 fn typeToIndex(f: *Function, ty: Type, kind: CType.Kind) !CType.Index {
468 return f.object.dg.typeToIndex(ty, kind);
469 }470 }
470471
471 fn typeToCType(f: *Function, ty: Type, kind: CType.Kind) !CType {472 fn byteSize(f: *Function, ctype: CType) u64 {
472 return f.object.dg.typeToCType(ty, kind);473 return f.object.dg.byteSize(ctype);
473 }474 }
474475
475 fn byteSize(f: *Function, cty: CType) u64 {476 fn renderType(f: *Function, w: anytype, ctype: Type) !void {
476 return f.object.dg.byteSize(cty);477 return f.object.dg.renderType(w, ctype);
477 }478 }
478479
479 fn renderType(f: *Function, w: anytype, t: Type) !void {480 fn renderCType(f: *Function, w: anytype, ctype: CType) !void {
480 return f.object.dg.renderType(w, t);481 return f.object.dg.renderCType(w, ctype);
481 }
482
483 fn renderCType(f: *Function, w: anytype, t: CType.Index) !void {
484 return f.object.dg.renderCType(w, t);
485 }482 }
486483
487 fn renderIntCast(f: *Function, w: anytype, dest_ty: Type, src: CValue, v: Vectorize, src_ty: Type, location: ValueRenderLocation) !void {484 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 {...@@ -494,21 +491,19 @@ pub const Function = struct {
494491
495 fn getLazyFnName(f: *Function, key: LazyFnKey, data: LazyFnValue.Data) ![]const u8 {492 fn getLazyFnName(f: *Function, key: LazyFnKey, data: LazyFnValue.Data) ![]const u8 {
496 const gpa = f.object.dg.gpa;493 const gpa = f.object.dg.gpa;
494 const zcu = f.object.dg.zcu;
495 const ctype_pool = &f.object.dg.ctype_pool;
496
497 const gop = try f.lazy_fns.getOrPut(gpa, key);497 const gop = try f.lazy_fns.getOrPut(gpa, key);
498 if (!gop.found_existing) {498 if (!gop.found_existing) {
499 errdefer _ = f.lazy_fns.pop();499 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
506 gop.value_ptr.* = .{501 gop.value_ptr.* = .{
507 .fn_name = switch (key) {502 .fn_name = switch (key) {
508 .tag_name,503 .tag_name,
509 .never_tail,504 .never_tail,
510 .never_inline,505 .never_inline,
511 => |owner_decl| try std.fmt.allocPrint(arena, "zig_{s}_{}__{d}", .{506 => |owner_decl| try ctype_pool.fmt(gpa, "zig_{s}_{}__{d}", .{
512 @tagName(key),507 @tagName(key),
513 fmtIdent(zcu.intern_pool.stringToSlice(zcu.declPtr(owner_decl).name)),508 fmtIdent(zcu.intern_pool.stringToSlice(zcu.declPtr(owner_decl).name)),
514 @intFromEnum(owner_decl),509 @intFromEnum(owner_decl),
...@@ -521,7 +516,7 @@ pub const Function = struct {...@@ -521,7 +516,7 @@ pub const Function = struct {
521 },516 },
522 };517 };
523 }518 }
524 return gop.value_ptr.fn_name;519 return gop.value_ptr.fn_name.slice(ctype_pool);
525 }520 }
526521
527 pub fn deinit(f: *Function) void {522 pub fn deinit(f: *Function) void {
...@@ -532,7 +527,6 @@ pub const Function = struct {...@@ -532,7 +527,6 @@ pub const Function = struct {
532 f.blocks.deinit(gpa);527 f.blocks.deinit(gpa);
533 f.value_map.deinit();528 f.value_map.deinit();
534 f.lazy_fns.deinit(gpa);529 f.lazy_fns.deinit(gpa);
535 f.object.dg.ctypes.deinit(gpa);
536 }530 }
537531
538 fn typeOf(f: *Function, inst: Air.Inst.Ref) Type {532 fn typeOf(f: *Function, inst: Air.Inst.Ref) Type {
...@@ -575,7 +569,8 @@ pub const DeclGen = struct {...@@ -575,7 +569,8 @@ pub const DeclGen = struct {
575 /// This is a borrowed reference from `link.C`.569 /// This is a borrowed reference from `link.C`.
576 fwd_decl: std.ArrayList(u8),570 fwd_decl: std.ArrayList(u8),
577 error_msg: ?*Zcu.ErrorMsg,571 error_msg: ?*Zcu.ErrorMsg,
578 ctypes: CType.Store,572 ctype_pool: CType.Pool,
573 scratch: std.ArrayListUnmanaged(u32),
579 /// Keeps track of anonymous decls that need to be rendered before this574 /// Keeps track of anonymous decls that need to be rendered before this
580 /// (named) Decl in the output C code.575 /// (named) Decl in the output C code.
581 anon_decl_deps: std.AutoArrayHashMapUnmanaged(InternPool.Index, C.DeclBlock),576 anon_decl_deps: std.AutoArrayHashMapUnmanaged(InternPool.Index, C.DeclBlock),
...@@ -610,6 +605,7 @@ pub const DeclGen = struct {...@@ -610,6 +605,7 @@ pub const DeclGen = struct {
610 ) error{ OutOfMemory, AnalysisFail }!void {605 ) error{ OutOfMemory, AnalysisFail }!void {
611 const zcu = dg.zcu;606 const zcu = dg.zcu;
612 const ip = &zcu.intern_pool;607 const ip = &zcu.intern_pool;
608 const ctype_pool = &dg.ctype_pool;
613 const decl_val = Value.fromInterned(anon_decl.val);609 const decl_val = Value.fromInterned(anon_decl.val);
614 const decl_ty = decl_val.typeOf(zcu);610 const decl_ty = decl_val.typeOf(zcu);
615611
...@@ -631,10 +627,10 @@ pub const DeclGen = struct {...@@ -631,10 +627,10 @@ pub const DeclGen = struct {
631 // them). The analysis until now should ensure that the C function627 // them). The analysis until now should ensure that the C function
632 // pointers are compatible. If they are not, then there is a bug628 // pointers are compatible. If they are not, then there is a bug
633 // somewhere and we should let the C compiler tell us about it.629 // 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;630 const elem_ctype = (try dg.ctypeFromType(ptr_ty, .complete)).info(ctype_pool).pointer.elem_ctype;
635 const decl_cty = try dg.typeToIndex(decl_ty, .complete);631 const decl_ctype = try dg.ctypeFromType(decl_ty, .complete);
636 const need_cast = child_cty != decl_cty and632 const need_cast = !elem_ctype.eql(decl_ctype) and
637 (dg.indexToCType(child_cty).tag() != .function or dg.indexToCType(decl_cty).tag() != .function);633 (elem_ctype.info(ctype_pool) != .function or decl_ctype.info(ctype_pool) != .function);
638 if (need_cast) {634 if (need_cast) {
639 try writer.writeAll("((");635 try writer.writeAll("((");
640 try dg.renderType(writer, ptr_ty);636 try dg.renderType(writer, ptr_ty);
...@@ -655,7 +651,7 @@ pub const DeclGen = struct {...@@ -655,7 +651,7 @@ pub const DeclGen = struct {
655 const explicit_alignment = ptr_type.flags.alignment;651 const explicit_alignment = ptr_type.flags.alignment;
656 if (explicit_alignment != .none) {652 if (explicit_alignment != .none) {
657 const abi_alignment = Type.fromInterned(ptr_type.child).abiAlignment(zcu);653 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)) {
659 const aligned_gop = try dg.aligned_anon_decls.getOrPut(dg.gpa, anon_decl.val);655 const aligned_gop = try dg.aligned_anon_decls.getOrPut(dg.gpa, anon_decl.val);
660 aligned_gop.value_ptr.* = if (aligned_gop.found_existing)656 aligned_gop.value_ptr.* = if (aligned_gop.found_existing)
661 aligned_gop.value_ptr.maxStrict(explicit_alignment)657 aligned_gop.value_ptr.maxStrict(explicit_alignment)
...@@ -673,6 +669,7 @@ pub const DeclGen = struct {...@@ -673,6 +669,7 @@ pub const DeclGen = struct {
673 location: ValueRenderLocation,669 location: ValueRenderLocation,
674 ) error{ OutOfMemory, AnalysisFail }!void {670 ) error{ OutOfMemory, AnalysisFail }!void {
675 const zcu = dg.zcu;671 const zcu = dg.zcu;
672 const ctype_pool = &dg.ctype_pool;
676 const decl = zcu.declPtr(decl_index);673 const decl = zcu.declPtr(decl_index);
677 assert(decl.has_tv);674 assert(decl.has_tv);
678675
...@@ -695,10 +692,10 @@ pub const DeclGen = struct {...@@ -695,10 +692,10 @@ pub const DeclGen = struct {
695 // them). The analysis until now should ensure that the C function692 // them). The analysis until now should ensure that the C function
696 // pointers are compatible. If they are not, then there is a bug693 // pointers are compatible. If they are not, then there is a bug
697 // somewhere and we should let the C compiler tell us about it.694 // 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;695 const elem_ctype = (try dg.ctypeFromType(ty, .complete)).info(ctype_pool).pointer.elem_ctype;
699 const decl_cty = try dg.typeToIndex(decl_ty, .complete);696 const decl_ctype = try dg.ctypeFromType(decl_ty, .complete);
700 const need_cast = child_cty != decl_cty and697 const need_cast = !elem_ctype.eql(decl_ctype) and
701 (dg.indexToCType(child_cty).tag() != .function or dg.indexToCType(decl_cty).tag() != .function);698 (elem_ctype.info(ctype_pool) != .function or decl_ctype.info(ctype_pool) != .function);
702 if (need_cast) {699 if (need_cast) {
703 try writer.writeAll("((");700 try writer.writeAll("((");
704 try dg.renderType(writer, ty);701 try dg.renderType(writer, ty);
...@@ -720,31 +717,31 @@ pub const DeclGen = struct {...@@ -720,31 +717,31 @@ pub const DeclGen = struct {
720 const zcu = dg.zcu;717 const zcu = dg.zcu;
721 const ip = &zcu.intern_pool;718 const ip = &zcu.intern_pool;
722 const ptr_ty = Type.fromInterned(ip.typeOf(ptr_val));719 const ptr_ty = Type.fromInterned(ip.typeOf(ptr_val));
723 const ptr_cty = try dg.typeToIndex(ptr_ty, .complete);720 const ptr_ctype = try dg.ctypeFromType(ptr_ty, .complete);
724 const ptr_child_cty = dg.indexToCType(ptr_cty).cast(CType.Payload.Child).?.data;721 const ptr_child_ctype = ptr_ctype.info(&dg.ctype_pool).pointer.elem_ctype;
725 const ptr = ip.indexToKey(ptr_val).ptr;722 const ptr = ip.indexToKey(ptr_val).ptr;
726 switch (ptr.addr) {723 switch (ptr.addr) {
727 .decl => |d| try dg.renderDeclValue(writer, Value.fromInterned(ptr_val), d, location),724 .decl => |d| try dg.renderDeclValue(writer, Value.fromInterned(ptr_val), d, location),
728 .anon_decl => |anon_decl| try dg.renderAnonDeclValue(writer, Value.fromInterned(ptr_val), anon_decl, location),725 .anon_decl => |anon_decl| try dg.renderAnonDeclValue(writer, Value.fromInterned(ptr_val), anon_decl, location),
729 .int => |int| {726 .int => |int| {
730 try writer.writeByte('(');727 try writer.writeByte('(');
731 try dg.renderCType(writer, ptr_cty);728 try dg.renderCType(writer, ptr_ctype);
732 try writer.print("){x}", .{try dg.fmtIntLiteral(Value.fromInterned(int), .Other)});729 try writer.print("){x}", .{try dg.fmtIntLiteral(Value.fromInterned(int), .Other)});
733 },730 },
734 .eu_payload, .opt_payload => |base| {731 .eu_payload, .opt_payload => |base| {
735 const ptr_base_ty = Type.fromInterned(ip.typeOf(base));732 const ptr_base_ty = Type.fromInterned(ip.typeOf(base));
736 const base_ty = ptr_base_ty.childType(zcu);733 const base_ty = ptr_base_ty.childType(zcu);
737 // Ensure complete type definition is visible before accessing fields.734 // Ensure complete type definition is visible before accessing fields.
738 _ = try dg.typeToIndex(base_ty, .complete);735 _ = try dg.ctypeFromType(base_ty, .complete);
739 const payload_ty = switch (ptr.addr) {736 const payload_ty = switch (ptr.addr) {
740 .eu_payload => base_ty.errorUnionPayload(zcu),737 .eu_payload => base_ty.errorUnionPayload(zcu),
741 .opt_payload => base_ty.optionalChild(zcu),738 .opt_payload => base_ty.optionalChild(zcu),
742 else => unreachable,739 else => unreachable,
743 };740 };
744 const payload_cty = try dg.typeToIndex(payload_ty, .forward);741 const payload_ctype = try dg.ctypeFromType(payload_ty, .forward);
745 if (ptr_child_cty != payload_cty) {742 if (!ptr_child_ctype.eql(payload_ctype)) {
746 try writer.writeByte('(');743 try writer.writeByte('(');
747 try dg.renderCType(writer, ptr_cty);744 try dg.renderCType(writer, ptr_ctype);
748 try writer.writeByte(')');745 try writer.writeByte(')');
749 }746 }
750 try writer.writeAll("&(");747 try writer.writeAll("&(");
...@@ -754,10 +751,10 @@ pub const DeclGen = struct {...@@ -754,10 +751,10 @@ pub const DeclGen = struct {
754 .elem => |elem| {751 .elem => |elem| {
755 const ptr_base_ty = Type.fromInterned(ip.typeOf(elem.base));752 const ptr_base_ty = Type.fromInterned(ip.typeOf(elem.base));
756 const elem_ty = ptr_base_ty.elemType2(zcu);753 const elem_ty = ptr_base_ty.elemType2(zcu);
757 const elem_cty = try dg.typeToIndex(elem_ty, .forward);754 const elem_ctype = try dg.ctypeFromType(elem_ty, .forward);
758 if (ptr_child_cty != elem_cty) {755 if (!ptr_child_ctype.eql(elem_ctype)) {
759 try writer.writeByte('(');756 try writer.writeByte('(');
760 try dg.renderCType(writer, ptr_cty);757 try dg.renderCType(writer, ptr_ctype);
761 try writer.writeByte(')');758 try writer.writeByte(')');
762 }759 }
763 try writer.writeAll("&(");760 try writer.writeAll("&(");
...@@ -769,14 +766,14 @@ pub const DeclGen = struct {...@@ -769,14 +766,14 @@ pub const DeclGen = struct {
769 .field => |field| {766 .field => |field| {
770 const ptr_base_ty = Type.fromInterned(ip.typeOf(field.base));767 const ptr_base_ty = Type.fromInterned(ip.typeOf(field.base));
771 const base_ty = ptr_base_ty.childType(zcu);768 const base_ty = ptr_base_ty.childType(zcu);
772 // Ensure complete type definition is visible before accessing fields.769 // Ensure complete type definition is available before accessing fields.
773 _ = try dg.typeToIndex(base_ty, .complete);770 _ = try dg.ctypeFromType(base_ty, .complete);
774 switch (fieldLocation(ptr_base_ty, ptr_ty, @as(u32, @intCast(field.index)), zcu)) {771 switch (fieldLocation(ptr_base_ty, ptr_ty, @as(u32, @intCast(field.index)), zcu)) {
775 .begin => {772 .begin => {
776 const ptr_base_cty = try dg.typeToIndex(ptr_base_ty, .complete);773 const ptr_base_ctype = try dg.ctypeFromType(ptr_base_ty, .complete);
777 if (ptr_cty != ptr_base_cty) {774 if (!ptr_ctype.eql(ptr_base_ctype)) {
778 try writer.writeByte('(');775 try writer.writeByte('(');
779 try dg.renderCType(writer, ptr_cty);776 try dg.renderCType(writer, ptr_ctype);
780 try writer.writeByte(')');777 try writer.writeByte(')');
781 }778 }
782 try dg.renderParentPtr(writer, field.base, location);779 try dg.renderParentPtr(writer, field.base, location);
...@@ -797,10 +794,10 @@ pub const DeclGen = struct {...@@ -797,10 +794,10 @@ pub const DeclGen = struct {
797 },794 },
798 else => unreachable,795 else => unreachable,
799 };796 };
800 const field_cty = try dg.typeToIndex(field_ty, .forward);797 const field_ctype = try dg.ctypeFromType(field_ty, .forward);
801 if (ptr_child_cty != field_cty) {798 if (!ptr_child_ctype.eql(field_ctype)) {
802 try writer.writeByte('(');799 try writer.writeByte('(');
803 try dg.renderCType(writer, ptr_cty);800 try dg.renderCType(writer, ptr_ctype);
804 try writer.writeByte(')');801 try writer.writeByte(')');
805 }802 }
806 try writer.writeAll("&(");803 try writer.writeAll("&(");
...@@ -810,15 +807,15 @@ pub const DeclGen = struct {...@@ -810,15 +807,15 @@ pub const DeclGen = struct {
810 },807 },
811 .byte_offset => |byte_offset| {808 .byte_offset => |byte_offset| {
812 const u8_ptr_ty = try zcu.adjustPtrTypeChild(ptr_ty, Type.u8);809 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)) {
816 try writer.writeByte('(');813 try writer.writeByte('(');
817 try dg.renderCType(writer, ptr_cty);814 try dg.renderCType(writer, ptr_ctype);
818 try writer.writeByte(')');815 try writer.writeByte(')');
819 }816 }
820 try writer.writeAll("((");817 try writer.writeAll("((");
821 try dg.renderCType(writer, u8_ptr_cty);818 try dg.renderCType(writer, u8_ptr_ctype);
822 try writer.writeByte(')');819 try writer.writeByte(')');
823 try dg.renderParentPtr(writer, field.base, location);820 try dg.renderParentPtr(writer, field.base, location);
824 try writer.print(" + {})", .{821 try writer.print(" + {})", .{
...@@ -826,10 +823,10 @@ pub const DeclGen = struct {...@@ -826,10 +823,10 @@ pub const DeclGen = struct {
826 });823 });
827 },824 },
828 .end => {825 .end => {
829 const ptr_base_cty = try dg.typeToIndex(ptr_base_ty, .complete);826 const ptr_base_ctype = try dg.ctypeFromType(ptr_base_ty, .complete);
830 if (ptr_cty != ptr_base_cty) {827 if (!ptr_ctype.eql(ptr_base_ctype)) {
831 try writer.writeByte('(');828 try writer.writeByte('(');
832 try dg.renderCType(writer, ptr_cty);829 try dg.renderCType(writer, ptr_ctype);
833 try writer.writeByte(')');830 try writer.writeByte(')');
834 }831 }
835 try writer.writeAll("((");832 try writer.writeAll("((");
...@@ -1207,8 +1204,8 @@ pub const DeclGen = struct {...@@ -1207,8 +1204,8 @@ pub const DeclGen = struct {
1207 try writer.writeByte('}');1204 try writer.writeByte('}');
1208 },1205 },
1209 .struct_type => {1206 .struct_type => {
1210 const struct_type = ip.loadStructType(ty.toIntern());1207 const loaded_struct = ip.loadStructType(ty.toIntern());
1211 switch (struct_type.layout) {1208 switch (loaded_struct.layout) {
1212 .auto, .@"extern" => {1209 .auto, .@"extern" => {
1213 if (!location.isInitializer()) {1210 if (!location.isInitializer()) {
1214 try writer.writeByte('(');1211 try writer.writeByte('(');
...@@ -1217,13 +1214,14 @@ pub const DeclGen = struct {...@@ -1217,13 +1214,14 @@ pub const DeclGen = struct {
1217 }1214 }
12181215
1219 try writer.writeByte('{');1216 try writer.writeByte('{');
1220 var empty = true;1217 var field_it = loaded_struct.iterateRuntimeOrder(ip);
1221 for (0..struct_type.field_types.len) |field_index| {1218 var need_comma = false;
1222 const field_ty = Type.fromInterned(struct_type.field_types.get(ip)[field_index]);1219 while (field_it.next()) |field_index| {
1223 if (struct_type.fieldIsComptime(ip, field_index)) continue;1220 const field_ty = Type.fromInterned(loaded_struct.field_types.get(ip)[field_index]);
1224 if (!field_ty.hasRuntimeBitsIgnoreComptime(zcu)) continue;1221 if (!field_ty.hasRuntimeBitsIgnoreComptime(zcu)) continue;
12251222
1226 if (!empty) try writer.writeByte(',');1223 if (need_comma) try writer.writeByte(',');
1224 need_comma = true;
1227 const field_val = switch (ip.indexToKey(val.toIntern()).aggregate.storage) {1225 const field_val = switch (ip.indexToKey(val.toIntern()).aggregate.storage) {
1228 .bytes => |bytes| try ip.get(zcu.gpa, .{ .int = .{1226 .bytes => |bytes| try ip.get(zcu.gpa, .{ .int = .{
1229 .ty = field_ty.toIntern(),1227 .ty = field_ty.toIntern(),
...@@ -1233,8 +1231,6 @@ pub const DeclGen = struct {...@@ -1233,8 +1231,6 @@ pub const DeclGen = struct {
1233 .repeated_elem => |elem| elem,1231 .repeated_elem => |elem| elem,
1234 };1232 };
1235 try dg.renderValue(writer, Value.fromInterned(field_val), initializer_type);1233 try dg.renderValue(writer, Value.fromInterned(field_val), initializer_type);
1236
1237 empty = false;
1238 }1234 }
1239 try writer.writeByte('}');1235 try writer.writeByte('}');
1240 },1236 },
...@@ -1247,8 +1243,8 @@ pub const DeclGen = struct {...@@ -1247,8 +1243,8 @@ pub const DeclGen = struct {
1247 var bit_offset: u64 = 0;1243 var bit_offset: u64 = 0;
1248 var eff_num_fields: usize = 0;1244 var eff_num_fields: usize = 0;
12491245
1250 for (0..struct_type.field_types.len) |field_index| {1246 for (0..loaded_struct.field_types.len) |field_index| {
1251 const field_ty = Type.fromInterned(struct_type.field_types.get(ip)[field_index]);1247 const field_ty = Type.fromInterned(loaded_struct.field_types.get(ip)[field_index]);
1252 if (!field_ty.hasRuntimeBitsIgnoreComptime(zcu)) continue;1248 if (!field_ty.hasRuntimeBitsIgnoreComptime(zcu)) continue;
1253 eff_num_fields += 1;1249 eff_num_fields += 1;
1254 }1250 }
...@@ -1268,8 +1264,8 @@ pub const DeclGen = struct {...@@ -1268,8 +1264,8 @@ pub const DeclGen = struct {
12681264
1269 var eff_index: usize = 0;1265 var eff_index: usize = 0;
1270 var needs_closing_paren = false;1266 var needs_closing_paren = false;
1271 for (0..struct_type.field_types.len) |field_index| {1267 for (0..loaded_struct.field_types.len) |field_index| {
1272 const field_ty = Type.fromInterned(struct_type.field_types.get(ip)[field_index]);1268 const field_ty = Type.fromInterned(loaded_struct.field_types.get(ip)[field_index]);
1273 if (!field_ty.hasRuntimeBitsIgnoreComptime(zcu)) continue;1269 if (!field_ty.hasRuntimeBitsIgnoreComptime(zcu)) continue;
12741270
1275 const field_val = switch (ip.indexToKey(val.toIntern()).aggregate.storage) {1271 const field_val = switch (ip.indexToKey(val.toIntern()).aggregate.storage) {
...@@ -1304,8 +1300,8 @@ pub const DeclGen = struct {...@@ -1304,8 +1300,8 @@ pub const DeclGen = struct {
1304 try writer.writeByte('(');1300 try writer.writeByte('(');
1305 // a << a_off | b << b_off | c << c_off1301 // a << a_off | b << b_off | c << c_off
1306 var empty = true;1302 var empty = true;
1307 for (0..struct_type.field_types.len) |field_index| {1303 for (0..loaded_struct.field_types.len) |field_index| {
1308 const field_ty = Type.fromInterned(struct_type.field_types.get(ip)[field_index]);1304 const field_ty = Type.fromInterned(loaded_struct.field_types.get(ip)[field_index]);
1309 if (!field_ty.hasRuntimeBitsIgnoreComptime(zcu)) continue;1305 if (!field_ty.hasRuntimeBitsIgnoreComptime(zcu)) continue;
13101306
1311 if (!empty) try writer.writeAll(" | ");1307 if (!empty) try writer.writeAll(" | ");
...@@ -1341,10 +1337,10 @@ pub const DeclGen = struct {...@@ -1341,10 +1337,10 @@ pub const DeclGen = struct {
1341 else => unreachable,1337 else => unreachable,
1342 },1338 },
1343 .un => |un| {1339 .un => |un| {
1344 const union_obj = zcu.typeToUnion(ty).?;1340 const loaded_union = ip.loadUnionType(ty.toIntern());
1345 if (un.tag == .none) {1341 if (un.tag == .none) {
1346 const backing_ty = try ty.unionBackingType(zcu);1342 const backing_ty = try ty.unionBackingType(zcu);
1347 switch (union_obj.getLayout(ip)) {1343 switch (loaded_union.getLayout(ip)) {
1348 .@"packed" => {1344 .@"packed" => {
1349 if (!location.isInitializer()) {1345 if (!location.isInitializer()) {
1350 try writer.writeByte('(');1346 try writer.writeByte('(');
...@@ -1376,10 +1372,10 @@ pub const DeclGen = struct {...@@ -1376,10 +1372,10 @@ pub const DeclGen = struct {
1376 try writer.writeByte(')');1372 try writer.writeByte(')');
1377 }1373 }
13781374
1379 const field_index = zcu.unionTagFieldIndex(union_obj, Value.fromInterned(un.tag)).?;1375 const field_index = zcu.unionTagFieldIndex(loaded_union, Value.fromInterned(un.tag)).?;
1380 const field_ty = Type.fromInterned(union_obj.field_types.get(ip)[field_index]);1376 const field_ty = Type.fromInterned(loaded_union.field_types.get(ip)[field_index]);
1381 const field_name = union_obj.loadTagType(ip).names.get(ip)[field_index];1377 const field_name = loaded_union.loadTagType(ip).names.get(ip)[field_index];
1382 if (union_obj.getLayout(ip) == .@"packed") {1378 if (loaded_union.getLayout(ip) == .@"packed") {
1383 if (field_ty.hasRuntimeBits(zcu)) {1379 if (field_ty.hasRuntimeBits(zcu)) {
1384 if (field_ty.isPtrAtRuntime(zcu)) {1380 if (field_ty.isPtrAtRuntime(zcu)) {
1385 try writer.writeByte('(');1381 try writer.writeByte('(');
...@@ -1399,7 +1395,7 @@ pub const DeclGen = struct {...@@ -1399,7 +1395,7 @@ pub const DeclGen = struct {
13991395
1400 try writer.writeByte('{');1396 try writer.writeByte('{');
1401 if (ty.unionTagTypeSafety(zcu)) |_| {1397 if (ty.unionTagTypeSafety(zcu)) |_| {
1402 const layout = zcu.getUnionLayout(union_obj);1398 const layout = zcu.getUnionLayout(loaded_union);
1403 if (layout.tag_size != 0) {1399 if (layout.tag_size != 0) {
1404 try writer.writeAll(" .tag = ");1400 try writer.writeAll(" .tag = ");
1405 try dg.renderValue(writer, Value.fromInterned(un.tag), initializer_type);1401 try dg.renderValue(writer, Value.fromInterned(un.tag), initializer_type);
...@@ -1412,8 +1408,8 @@ pub const DeclGen = struct {...@@ -1412,8 +1408,8 @@ pub const DeclGen = struct {
1412 try writer.print(" .{ } = ", .{fmtIdent(ip.stringToSlice(field_name))});1408 try writer.print(" .{ } = ", .{fmtIdent(ip.stringToSlice(field_name))});
1413 try dg.renderValue(writer, Value.fromInterned(un.val), initializer_type);1409 try dg.renderValue(writer, Value.fromInterned(un.val), initializer_type);
1414 try writer.writeByte(' ');1410 try writer.writeByte(' ');
1415 } else for (0..union_obj.field_types.len) |this_field_index| {1411 } else for (0..loaded_union.field_types.len) |this_field_index| {
1416 const this_field_ty = Type.fromInterned(union_obj.field_types.get(ip)[this_field_index]);1412 const this_field_ty = Type.fromInterned(loaded_union.field_types.get(ip)[this_field_index]);
1417 if (!this_field_ty.hasRuntimeBits(zcu)) continue;1413 if (!this_field_ty.hasRuntimeBits(zcu)) continue;
1418 try dg.renderUndefValue(writer, this_field_ty, initializer_type);1414 try dg.renderUndefValue(writer, this_field_ty, initializer_type);
1419 break;1415 break;
...@@ -1445,12 +1441,14 @@ pub const DeclGen = struct {...@@ -1445,12 +1441,14 @@ pub const DeclGen = struct {
1445 .ReleaseFast, .ReleaseSmall => false,1441 .ReleaseFast, .ReleaseSmall => false,
1446 };1442 };
14471443
1448 switch (ty.zigTypeTag(zcu)) {1444 switch (ty.toIntern()) {
1449 .Bool => try writer.writeAll(if (safety_on) "0xaa" else "false"),1445 .c_longdouble_type,
1450 .Int, .Enum, .ErrorSet => try writer.print("{x}", .{1446 .f16_type,
1451 try dg.fmtIntLiteral(try zcu.undefValue(ty), location),1447 .f32_type,
1452 }),1448 .f64_type,
1453 .Float => {1449 .f80_type,
1450 .f128_type,
1451 => {
1454 const bits = ty.floatBits(target.*);1452 const bits = ty.floatBits(target.*);
1455 // All unsigned ints matching float types are pre-allocated.1453 // All unsigned ints matching float types are pre-allocated.
1456 const repr_ty = zcu.intType(.unsigned, bits) catch unreachable;1454 const repr_ty = zcu.intType(.unsigned, bits) catch unreachable;
...@@ -1468,49 +1466,90 @@ pub const DeclGen = struct {...@@ -1468,49 +1466,90 @@ pub const DeclGen = struct {
1468 }1466 }
1469 try writer.writeAll(", ");1467 try writer.writeAll(", ");
1470 try dg.renderUndefValue(writer, repr_ty, .FunctionArgument);1468 try dg.renderUndefValue(writer, repr_ty, .FunctionArgument);
1471 try writer.writeByte(')');1469 return writer.writeByte(')');
1472 },1470 },
1473 .Pointer => if (ty.isSlice(zcu)) {1471 .bool_type => try writer.writeAll(if (safety_on) "0xaa" else "false"),
1474 if (!location.isInitializer()) {1472 else => switch (ip.indexToKey(ty.toIntern())) {
1475 try writer.writeByte('(');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("((");
1476 try dg.renderType(writer, ty);1496 try dg.renderType(writer, ty);
1477 try writer.writeByte(')');1497 return writer.print("){x})", .{
1478 }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("{(");1504 if (!payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
1481 const ptr_ty = ty.slicePtrFieldType(zcu);1505 return dg.renderUndefValue(writer, Type.bool, location);
1482 try dg.renderType(writer, ptr_ty);1506 }
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);
14911507
1492 if (!payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) {1508 if (ty.optionalReprIsPayload(zcu)) {
1493 return dg.renderUndefValue(writer, Type.bool, location);1509 return dg.renderUndefValue(writer, payload_ty, location);
1494 }1510 }
14951511
1496 if (ty.optionalReprIsPayload(zcu)) {1512 if (!location.isInitializer()) {
1497 return dg.renderUndefValue(writer, payload_ty, location);1513 try writer.writeByte('(');
1498 }1514 try dg.renderType(writer, ty);
1515 try writer.writeByte(')');
1516 }
14991517
1500 if (!location.isInitializer()) {1518 try writer.writeAll("{ .payload = ");
1501 try writer.writeByte('(');1519 try dg.renderUndefValue(writer, payload_ty, initializer_type);
1502 try dg.renderType(writer, ty);1520 try writer.writeAll(", .is_null = ");
1503 try writer.writeByte(')');1521 try dg.renderUndefValue(writer, Type.bool, initializer_type);
1504 }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 = ");1534 try writer.writeByte('{');
1507 try dg.renderUndefValue(writer, payload_ty, initializer_type);1535 var field_it = loaded_struct.iterateRuntimeOrder(ip);
1508 try writer.writeAll(", .is_null = ");1536 var need_comma = false;
1509 try dg.renderUndefValue(writer, Type.bool, initializer_type);1537 while (field_it.next()) |field_index| {
1510 try writer.writeAll(" }");1538 const field_ty = Type.fromInterned(loaded_struct.field_types.get(ip)[field_index]);
1511 },1539 if (!field_ty.hasRuntimeBitsIgnoreComptime(zcu)) continue;
1512 .Struct => switch (ty.containerLayout(zcu)) {1540
1513 .auto, .@"extern" => {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| {
1514 if (!location.isInitializer()) {1553 if (!location.isInitializer()) {
1515 try writer.writeByte('(');1554 try writer.writeByte('(');
1516 try dg.renderType(writer, ty);1555 try dg.renderType(writer, ty);
...@@ -1518,116 +1557,125 @@ pub const DeclGen = struct {...@@ -1518,116 +1557,125 @@ pub const DeclGen = struct {
1518 }1557 }
15191558
1520 try writer.writeByte('{');1559 try writer.writeByte('{');
1521 var empty = true;1560 var need_comma = false;
1522 for (0..ty.structFieldCount(zcu)) |field_index| {1561 for (0..anon_struct_info.types.len) |field_index| {
1523 if (ty.structFieldIsComptime(field_index, zcu)) continue;1562 if (anon_struct_info.values.get(ip)[field_index] != .none) continue;
1524 const field_ty = ty.structFieldType(field_index, zcu);1563 const field_ty = Type.fromInterned(anon_struct_info.types.get(ip)[field_index]);
1525 if (!field_ty.hasRuntimeBits(zcu)) continue;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;
1528 try dg.renderUndefValue(writer, field_ty, initializer_type);1568 try dg.renderUndefValue(writer, field_ty, initializer_type);
1529
1530 empty = false;
1531 }1569 }
15321570 return writer.writeByte('}');
1533 try writer.writeByte('}');
1534 },1571 },
1535 .@"packed" => try writer.print("{x}", .{1572 .union_type => {
1536 try dg.fmtIntLiteral(try zcu.undefValue(ty), .Other),1573 const loaded_union = ip.loadUnionType(ty.toIntern());
1537 }),1574 switch (loaded_union.getLayout(ip)) {
1538 },1575 .auto, .@"extern" => {
1539 .Union => {1576 if (!location.isInitializer()) {
1540 if (!location.isInitializer()) {1577 try writer.writeByte('(');
1541 try writer.writeByte('(');1578 try dg.renderType(writer, ty);
1542 try dg.renderType(writer, ty);1579 try writer.writeByte(')');
1543 try writer.writeByte(')');1580 }
1544 }
15451581
1546 try writer.writeByte('{');1582 try writer.writeByte('{');
1547 if (ty.unionTagTypeSafety(zcu)) |tag_ty| {1583 if (ty.unionTagTypeSafety(zcu)) |tag_ty| {
1548 const layout = ty.unionGetLayout(zcu);1584 const layout = ty.unionGetLayout(zcu);
1549 if (layout.tag_size != 0) {1585 if (layout.tag_size != 0) {
1550 try writer.writeAll(" .tag = ");1586 try writer.writeAll(" .tag = ");
1551 try dg.renderUndefValue(writer, tag_ty, initializer_type);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 }),
1552 }1605 }
1553 if (ty.unionHasAllZeroBitFieldTypes(zcu)) return try writer.writeByte('}');1606 },
1554 if (layout.tag_size != 0) try writer.writeByte(',');1607 .error_union_type => {
1555 try writer.writeAll(" .payload = {");1608 const payload_ty = ty.errorUnionPayload(zcu);
1556 }1609 const error_ty = ty.errorUnionSet(zcu);
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 }
15741610
1575 if (!location.isInitializer()) {1611 if (!payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
1576 try writer.writeByte('(');1612 return dg.renderUndefValue(writer, error_ty, location);
1577 try dg.renderType(writer, ty);1613 }
1578 try writer.writeByte(')');
1579 }
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 {
1598 if (!location.isInitializer()) {1615 if (!location.isInitializer()) {
1599 try writer.writeByte('(');1616 try writer.writeByte('(');
1600 try dg.renderType(writer, ty);1617 try dg.renderType(writer, ty);
1601 try writer.writeByte(')');1618 try writer.writeByte(')');
1602 }1619 }
16031620
1604 try writer.writeByte('{');1621 try writer.writeAll("{ .payload = ");
1605 const c_len = ty.arrayLenIncludingSentinel(zcu);1622 try dg.renderUndefValue(writer, payload_ty, initializer_type);
1606 var index: u64 = 0;1623 try writer.writeAll(", .error = ");
1607 while (index < c_len) : (index += 1) {1624 try dg.renderUndefValue(writer, error_ty, initializer_type);
1608 if (index > 0) try writer.writeAll(", ");1625 return writer.writeAll(" }");
1609 try dg.renderUndefValue(writer, ty.childType(zcu), initializer_type);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('}');
1610 }1652 }
1611 try writer.writeByte('}');1653 },
1612 }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,
1613 },1678 },
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 }),
1631 }1679 }
1632 }1680 }
16331681
...@@ -1641,13 +1689,12 @@ pub const DeclGen = struct {...@@ -1641,13 +1689,12 @@ pub const DeclGen = struct {
1641 ident: []const u8,1689 ident: []const u8,
1642 },1690 },
1643 ) !void {1691 ) !void {
1644 const store = &dg.ctypes.set;
1645 const zcu = dg.zcu;1692 const zcu = dg.zcu;
1646 const ip = &zcu.intern_pool;1693 const ip = &zcu.intern_pool;
16471694
1648 const fn_decl = zcu.declPtr(fn_decl_index);1695 const fn_decl = zcu.declPtr(fn_decl_index);
1649 const fn_ty = fn_decl.typeOf(zcu);1696 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
1652 const fn_info = zcu.typeToFunc(fn_ty).?;1699 const fn_info = zcu.typeToFunc(fn_ty).?;
1653 if (fn_info.cc == .Naked) {1700 if (fn_info.cc == .Naked) {
...@@ -1661,7 +1708,7 @@ pub const DeclGen = struct {...@@ -1661,7 +1708,7 @@ pub const DeclGen = struct {
1661 try w.writeAll("zig_cold ");1708 try w.writeAll("zig_cold ");
1662 if (fn_info.return_type == .noreturn_type) try w.writeAll("zig_noreturn ");1709 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
1666 if (toCallingConvention(fn_info.cc)) |call_conv| {1713 if (toCallingConvention(fn_info.cc)) |call_conv| {
1667 try w.print("{}zig_callconv({s})", .{ trailing, call_conv });1714 try w.print("{}zig_callconv({s})", .{ trailing, call_conv });
...@@ -1670,7 +1717,7 @@ pub const DeclGen = struct {...@@ -1670,7 +1717,7 @@ pub const DeclGen = struct {
16701717
1671 switch (kind) {1718 switch (kind) {
1672 .forward => {},1719 .forward => {},
1673 .complete => if (fn_decl.alignment.toByteUnitsOptional()) |a| {1720 .complete => if (fn_decl.alignment.toByteUnits()) |a| {
1674 try w.print("{}zig_align_fn({})", .{ trailing, a });1721 try w.print("{}zig_align_fn({})", .{ trailing, a });
1675 trailing = .maybe_space;1722 trailing = .maybe_space;
1676 },1723 },
...@@ -1687,10 +1734,10 @@ pub const DeclGen = struct {...@@ -1687,10 +1734,10 @@ pub const DeclGen = struct {
16871734
1688 try renderTypeSuffix(1735 try renderTypeSuffix(
1689 dg.pass,1736 dg.pass,
1690 store.*,1737 &dg.ctype_pool,
1691 zcu,1738 zcu,
1692 w,1739 w,
1693 fn_cty_idx,1740 fn_ctype,
1694 .suffix,1741 .suffix,
1695 CQualifiers.init(.{ .@"const" = switch (kind) {1742 CQualifiers.init(.{ .@"const" = switch (kind) {
1696 .forward => false,1743 .forward => false,
...@@ -1701,7 +1748,7 @@ pub const DeclGen = struct {...@@ -1701,7 +1748,7 @@ pub const DeclGen = struct {
17011748
1702 switch (kind) {1749 switch (kind) {
1703 .forward => {1750 .forward => {
1704 if (fn_decl.alignment.toByteUnitsOptional()) |a| {1751 if (fn_decl.alignment.toByteUnits()) |a| {
1705 try w.print(" zig_align_fn({})", .{a});1752 try w.print(" zig_align_fn({})", .{a});
1706 }1753 }
1707 switch (name) {1754 switch (name) {
...@@ -1748,20 +1795,13 @@ pub const DeclGen = struct {...@@ -1748,20 +1795,13 @@ pub const DeclGen = struct {
1748 }1795 }
1749 }1796 }
17501797
1751 fn indexToCType(dg: *DeclGen, idx: CType.Index) CType {1798 fn ctypeFromType(dg: *DeclGen, ty: Type, kind: CType.Kind) !CType {
1752 return dg.ctypes.indexToCType(idx);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);
1753 }1801 }
17541802
1755 fn typeToIndex(dg: *DeclGen, ty: Type, kind: CType.Kind) !CType.Index {1803 fn byteSize(dg: *DeclGen, ctype: CType) u64 {
1756 return dg.ctypes.typeToIndex(dg.gpa, ty, dg.zcu, dg.mod, kind);1804 return ctype.byteSize(&dg.ctype_pool, dg.mod);
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);
1765 }1805 }
17661806
1767 /// Renders a type as a single identifier, generating intermediate typedefs1807 /// Renders a type as a single identifier, generating intermediate typedefs
...@@ -1776,14 +1816,12 @@ pub const DeclGen = struct {...@@ -1776,14 +1816,12 @@ pub const DeclGen = struct {
1776 /// | `renderType` | "uint8_t *" | "uint8_t *[10]" |1816 /// | `renderType` | "uint8_t *" | "uint8_t *[10]" |
1777 ///1817 ///
1778 fn renderType(dg: *DeclGen, w: anytype, t: Type) error{ OutOfMemory, AnalysisFail }!void {1818 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));
1780 }1820 }
17811821
1782 fn renderCType(dg: *DeclGen, w: anytype, idx: CType.Index) error{ OutOfMemory, AnalysisFail }!void {1822 fn renderCType(dg: *DeclGen, w: anytype, ctype: CType) error{ OutOfMemory, AnalysisFail }!void {
1783 const store = &dg.ctypes.set;1823 _ = try renderTypePrefix(dg.pass, &dg.ctype_pool, dg.zcu, w, ctype, .suffix, .{});
1784 const zcu = dg.zcu;1824 try renderTypeSuffix(dg.pass, &dg.ctype_pool, dg.zcu, w, ctype, .suffix, .{});
1785 _ = try renderTypePrefix(dg.pass, store.*, zcu, w, idx, .suffix, .{});
1786 try renderTypeSuffix(dg.pass, store.*, zcu, w, idx, .suffix, .{});
1787 }1825 }
17881826
1789 const IntCastContext = union(enum) {1827 const IntCastContext = union(enum) {
...@@ -1905,32 +1943,37 @@ pub const DeclGen = struct {...@@ -1905,32 +1943,37 @@ pub const DeclGen = struct {
1905 alignment: Alignment,1943 alignment: Alignment,
1906 kind: CType.Kind,1944 kind: CType.Kind,
1907 ) error{ OutOfMemory, AnalysisFail }!void {1945 ) error{ OutOfMemory, AnalysisFail }!void {
1908 const zcu = dg.zcu;1946 try dg.renderCTypeAndName(
1909 const alignas = CType.AlignAs.init(alignment, ty.abiAlignment(zcu));1947 w,
1910 try dg.renderCTypeAndName(w, try dg.typeToIndex(ty, kind), name, qualifiers, alignas);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 );
1911 }1956 }
19121957
1913 fn renderCTypeAndName(1958 fn renderCTypeAndName(
1914 dg: *DeclGen,1959 dg: *DeclGen,
1915 w: anytype,1960 w: anytype,
1916 cty_idx: CType.Index,1961 ctype: CType,
1917 name: CValue,1962 name: CValue,
1918 qualifiers: CQualifiers,1963 qualifiers: CQualifiers,
1919 alignas: CType.AlignAs,1964 alignas: CType.AlignAs,
1920 ) error{ OutOfMemory, AnalysisFail }!void {1965 ) error{ OutOfMemory, AnalysisFail }!void {
1921 const store = &dg.ctypes.set;
1922 const zcu = dg.zcu;
1923
1924 switch (alignas.abiOrder()) {1966 switch (alignas.abiOrder()) {
1925 .lt => try w.print("zig_under_align({}) ", .{alignas.toByteUnits()}),1967 .lt => try w.print("zig_under_align({}) ", .{alignas.toByteUnits()}),
1926 .eq => {},1968 .eq => {},
1927 .gt => try w.print("zig_align({}) ", .{alignas.toByteUnits()}),1969 .gt => try w.print("zig_align({}) ", .{alignas.toByteUnits()}),
1928 }1970 }
19291971
1930 const trailing = try renderTypePrefix(dg.pass, store.*, zcu, w, cty_idx, .suffix, qualifiers);1972 try w.print("{}", .{
1931 try w.print("{}", .{trailing});1973 try renderTypePrefix(dg.pass, &dg.ctype_pool, dg.zcu, w, ctype, .suffix, qualifiers),
1974 });
1932 try dg.writeName(w, name);1975 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, .{});
1934 }1977 }
19351978
1936 fn declIsGlobal(dg: *DeclGen, val: Value) bool {1979 fn declIsGlobal(dg: *DeclGen, val: Value) bool {
...@@ -2094,33 +2137,31 @@ pub const DeclGen = struct {...@@ -2094,33 +2137,31 @@ pub const DeclGen = struct {
2094 }2137 }
20952138
2096 fn renderTypeForBuiltinFnName(dg: *DeclGen, writer: anytype, ty: Type) !void {2139 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));
2098 }2141 }
20992142
2100 fn renderCTypeForBuiltinFnName(dg: *DeclGen, writer: anytype, cty: CType) !void {2143 fn renderCTypeForBuiltinFnName(dg: *DeclGen, writer: anytype, ctype: CType) !void {
2101 switch (cty.tag()) {2144 switch (ctype.info(&dg.ctype_pool)) {
2102 else => try writer.print("{c}{d}", .{2145 else => |ctype_info| try writer.print("{c}{d}", .{
2103 if (cty.isBool())2146 if (ctype.isBool())
2104 signAbbrev(.unsigned)2147 signAbbrev(.unsigned)
2105 else if (cty.isInteger())2148 else if (ctype.isInteger())
2106 signAbbrev(cty.signedness(dg.mod))2149 signAbbrev(ctype.signedness(dg.mod))
2107 else if (cty.isFloat())2150 else if (ctype.isFloat())
2108 @as(u8, 'f')2151 @as(u8, 'f')
2109 else if (cty.isPointer())2152 else if (ctype_info == .pointer)
2110 @as(u8, 'p')2153 @as(u8, 'p')
2111 else2154 else
2112 return dg.fail("TODO: CBE: implement renderTypeForBuiltinFnName for type {}", .{2155 return dg.fail("TODO: CBE: implement renderTypeForBuiltinFnName for {s} type", .{@tagName(ctype_info)}),
2113 cty.tag(),2156 if (ctype.isFloat()) ctype.floatActiveBits(dg.mod) else dg.byteSize(ctype) * 8,
2114 }),
2115 if (cty.isFloat()) cty.floatActiveBits(dg.mod) else dg.byteSize(cty) * 8,
2116 }),2157 }),
2117 .array => try writer.writeAll("big"),2158 .array => try writer.writeAll("big"),
2118 }2159 }
2119 }2160 }
21202161
2121 fn renderBuiltinInfo(dg: *DeclGen, writer: anytype, ty: Type, info: BuiltinInfo) !void {2162 fn renderBuiltinInfo(dg: *DeclGen, writer: anytype, ty: Type, info: BuiltinInfo) !void {
2122 const cty = try dg.typeToCType(ty, .complete);2163 const ctype = try dg.ctypeFromType(ty, .complete);
2123 const is_big = cty.tag() == .array;2164 const is_big = ctype.info(&dg.ctype_pool) == .array;
2124 switch (info) {2165 switch (info) {
2125 .none => if (!is_big) return,2166 .none => if (!is_big) return,
2126 .bits => {},2167 .bits => {},
...@@ -2155,7 +2196,7 @@ pub const DeclGen = struct {...@@ -2155,7 +2196,7 @@ pub const DeclGen = struct {
2155 .dg = dg,2196 .dg = dg,
2156 .int_info = ty.intInfo(zcu),2197 .int_info = ty.intInfo(zcu),
2157 .kind = kind,2198 .kind = kind,
2158 .cty = try dg.typeToCType(ty, kind),2199 .ctype = try dg.ctypeFromType(ty, kind),
2159 .val = val,2200 .val = val,
2160 } };2201 } };
2161 }2202 }
...@@ -2184,122 +2225,74 @@ const RenderCTypeTrailing = enum {...@@ -2184,122 +2225,74 @@ const RenderCTypeTrailing = enum {
2184 }2225 }
2185 }2226 }
2186};2227};
2187fn renderTypeName(2228fn renderAlignedTypeName(w: anytype, ctype: CType) !void {
2229 try w.print("anon__aligned_{d}", .{@intFromEnum(ctype.index)});
2230}
2231fn renderFwdDeclTypeName(
2188 zcu: *Zcu,2232 zcu: *Zcu,
2189 w: anytype,2233 w: anytype,
2190 idx: CType.Index,2234 ctype: CType,
2191 cty: CType,2235 fwd_decl: CType.Info.FwdDecl,
2192 attributes: []const u8,2236 attributes: []const u8,
2193) !void {2237) !void {
2194 switch (cty.tag()) {2238 try w.print("{s} {s}", .{ @tagName(fwd_decl.tag), attributes });
2195 else => unreachable,2239 switch (fwd_decl.name) {
21962240 .anon => try w.print("anon__lazy_{d}", .{@intFromEnum(ctype.index)}),
2197 .fwd_anon_struct,2241 .owner_decl => |owner_decl| try w.print("{}__{d}", .{
2198 .fwd_anon_union,2242 fmtIdent(zcu.intern_pool.stringToSlice(zcu.declPtr(owner_decl).name)),
2199 => |tag| try w.print("{s} {s}anon__lazy_{d}", .{2243 @intFromEnum(owner_decl),
2200 @tagName(tag)["fwd_anon_".len..],
2201 attributes,
2202 idx,
2203 }),2244 }),
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 },
2216 }2245 }
2217}2246}
2218fn renderTypePrefix(2247fn renderTypePrefix(
2219 pass: DeclGen.Pass,2248 pass: DeclGen.Pass,
2220 store: CType.Store.Set,2249 ctype_pool: *const CType.Pool,
2221 zcu: *Zcu,2250 zcu: *Zcu,
2222 w: anytype,2251 w: anytype,
2223 idx: CType.Index,2252 ctype: CType,
2224 parent_fix: CTypeFix,2253 parent_fix: CTypeFix,
2225 qualifiers: CQualifiers,2254 qualifiers: CQualifiers,
2226) @TypeOf(w).Error!RenderCTypeTrailing {2255) @TypeOf(w).Error!RenderCTypeTrailing {
2227 var trailing = RenderCTypeTrailing.maybe_space;2256 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);2260 .pointer => |pointer_info| {
2230 switch (cty.tag()) {2261 try w.print("{}*", .{try renderTypePrefix(
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(
2277 pass,2262 pass,
2278 store,2263 ctype_pool,
2279 zcu,2264 zcu,
2280 w,2265 w,
2281 child_idx,2266 pointer_info.elem_ctype,
2282 .prefix,2267 .prefix,
2283 CQualifiers.init(.{ .@"const" = switch (tag) {2268 CQualifiers.init(.{
2284 .pointer, .pointer_volatile => false,2269 .@"const" = pointer_info.@"const",
2285 .pointer_const, .pointer_const_volatile => true,2270 .@"volatile" = pointer_info.@"volatile",
2286 else => unreachable,2271 }),
2287 }, .@"volatile" = switch (tag) {2272 )});
2288 .pointer, .pointer_const => false,
2289 .pointer_volatile, .pointer_const_volatile => true,
2290 else => unreachable,
2291 } }),
2292 );
2293 try w.print("{}*", .{child_trailing});
2294 trailing = .no_space;2273 trailing = .no_space;
2295 },2274 },
22962275
2297 .array,2276 .aligned => switch (pass) {
2298 .vector,2277 .decl => |decl_index| try w.print("decl__{d}_{d}", .{
2299 => {2278 @intFromEnum(decl_index), @intFromEnum(ctype.index),
2300 const child_idx = cty.cast(CType.Payload.Sequence).?.data.elem_type;2279 }),
2301 const child_trailing =2280 .anon => |anon_decl| try w.print("anon__{d}_{d}", .{
2302 try renderTypePrefix(pass, store, zcu, w, child_idx, .suffix, qualifiers);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 );
2303 switch (parent_fix) {2296 switch (parent_fix) {
2304 .prefix => {2297 .prefix => {
2305 try w.print("{}(", .{child_trailing});2298 try w.print("{}(", .{child_trailing});
...@@ -2309,56 +2302,46 @@ fn renderTypePrefix(...@@ -2309,56 +2302,46 @@ fn renderTypePrefix(
2309 }2302 }
2310 },2303 },
23112304
2312 .fwd_anon_struct,2305 .fwd_decl => |fwd_decl_info| switch (fwd_decl_info.name) {
2313 .fwd_anon_union,2306 .anon => switch (pass) {
2314 => switch (pass) {2307 .decl => |decl_index| try w.print("decl__{d}_{d}", .{
2315 .decl => |decl_index| try w.print("decl__{d}_{d}", .{ @intFromEnum(decl_index), idx }),2308 @intFromEnum(decl_index), @intFromEnum(ctype.index),
2316 .anon => |anon_decl| try w.print("anon__{d}_{d}", .{ @intFromEnum(anon_decl), idx }),2309 }),
2317 .flush => try renderTypeName(zcu, w, idx, cty, ""),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, ""),
2318 },2316 },
23192317
2320 .fwd_struct,2318 .aggregate => |aggregate_info| switch (aggregate_info.name) {
2321 .fwd_union,2319 .anon => {
2322 => try renderTypeName(zcu, w, idx, cty, ""),2320 try w.print("{s} {s}", .{
23232321 @tagName(aggregate_info.tag),
2324 .unnamed_struct,2322 if (aggregate_info.@"packed") "zig_packed(" else "",
2325 .unnamed_union,2323 });
2326 .packed_unnamed_struct,2324 try renderFields(zcu, w, ctype_pool, aggregate_info, 1);
2327 .packed_unnamed_union,2325 if (aggregate_info.@"packed") try w.writeByte(')');
2328 => |tag| {2326 },
2329 try w.print("{s} {s}", .{2327 .fwd_decl => |fwd_decl| return renderTypePrefix(
2330 @tagName(tag)["unnamed_".len..],2328 pass,
2331 if (cty.isPacked()) "zig_packed(" else "",2329 ctype_pool,
2332 });2330 zcu,
2333 try renderAggregateFields(zcu, w, store, cty, 1);2331 w,
2334 if (cty.isPacked()) try w.writeByte(')');2332 fwd_decl,
2333 parent_fix,
2334 qualifiers,
2335 ),
2335 },2336 },
23362337
2337 .anon_struct,2338 .function => |function_info| {
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 => {
2356 const child_trailing = try renderTypePrefix(2339 const child_trailing = try renderTypePrefix(
2357 pass,2340 pass,
2358 store,2341 ctype_pool,
2359 zcu,2342 zcu,
2360 w,2343 w,
2361 cty.cast(CType.Payload.Function).?.data.return_type,2344 function_info.return_ctype,
2362 .suffix,2345 .suffix,
2363 .{},2346 .{},
2364 );2347 );
...@@ -2371,170 +2354,107 @@ fn renderTypePrefix(...@@ -2371,170 +2354,107 @@ fn renderTypePrefix(
2371 }2354 }
2372 },2355 },
2373 }2356 }
2374
2375 var qualifier_it = qualifiers.iterator();2357 var qualifier_it = qualifiers.iterator();
2376 while (qualifier_it.next()) |qualifier| {2358 while (qualifier_it.next()) |qualifier| {
2377 try w.print("{}{s}", .{ trailing, @tagName(qualifier) });2359 try w.print("{}{s}", .{ trailing, @tagName(qualifier) });
2378 trailing = .maybe_space;2360 trailing = .maybe_space;
2379 }2361 }
2380
2381 return trailing;2362 return trailing;
2382}2363}
2383fn renderTypeSuffix(2364fn renderTypeSuffix(
2384 pass: DeclGen.Pass,2365 pass: DeclGen.Pass,
2385 store: CType.Store.Set,2366 ctype_pool: *const CType.Pool,
2386 zcu: *Zcu,2367 zcu: *Zcu,
2387 w: anytype,2368 w: anytype,
2388 idx: CType.Index,2369 ctype: CType,
2389 parent_fix: CTypeFix,2370 parent_fix: CTypeFix,
2390 qualifiers: CQualifiers,2371 qualifiers: CQualifiers,
2391) @TypeOf(w).Error!void {2372) @TypeOf(w).Error!void {
2392 const cty = store.indexToCType(idx);2373 switch (ctype.info(ctype_pool)) {
2393 switch (cty.tag()) {2374 .basic, .aligned, .fwd_decl, .aggregate => {},
2394 .void,2375 .pointer => |pointer_info| try renderTypeSuffix(
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(
2438 pass,2376 pass,
2439 store,2377 ctype_pool,
2440 zcu,2378 zcu,
2441 w,2379 w,
2442 cty.cast(CType.Payload.Child).?.data,2380 pointer_info.elem_ctype,
2443 .prefix,2381 .prefix,
2444 .{},2382 .{},
2445 ),2383 ),
24462384 .array, .vector => |sequence_info| {
2447 .array,
2448 .vector,
2449 => {
2450 switch (parent_fix) {2385 switch (parent_fix) {
2451 .prefix => try w.writeByte(')'),2386 .prefix => try w.writeByte(')'),
2452 .suffix => {},2387 .suffix => {},
2453 }2388 }
24542389
2455 try w.print("[{}]", .{cty.cast(CType.Payload.Sequence).?.data.len});2390 try w.print("[{}]", .{sequence_info.len});
2456 try renderTypeSuffix(2391 try renderTypeSuffix(pass, ctype_pool, zcu, w, sequence_info.elem_ctype, .suffix, .{});
2457 pass,
2458 store,
2459 zcu,
2460 w,
2461 cty.cast(CType.Payload.Sequence).?.data.elem_type,
2462 .suffix,
2463 .{},
2464 );
2465 },2392 },
24662393 .function => |function_info| {
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| {
2486 switch (parent_fix) {2394 switch (parent_fix) {
2487 .prefix => try w.writeByte(')'),2395 .prefix => try w.writeByte(')'),
2488 .suffix => {},2396 .suffix => {},
2489 }2397 }
24902398
2491 const data = cty.cast(CType.Payload.Function).?.data;
2492
2493 try w.writeByte('(');2399 try w.writeByte('(');
2494 var need_comma = false;2400 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);
2496 if (need_comma) try w.writeAll(", ");2403 if (need_comma) try w.writeAll(", ");
2497 need_comma = true;2404 need_comma = true;
2498 const trailing =2405 const trailing =
2499 try renderTypePrefix(pass, store, zcu, w, param_type, .suffix, qualifiers);2406 try renderTypePrefix(pass, ctype_pool, zcu, w, param_type, .suffix, qualifiers);
2500 if (qualifiers.contains(.@"const")) try w.print("{}a{d}", .{ trailing, param_i });2407 if (qualifiers.contains(.@"const")) try w.print("{}a{d}", .{ trailing, param_index });
2501 try renderTypeSuffix(pass, store, zcu, w, param_type, .suffix, .{});2408 try renderTypeSuffix(pass, ctype_pool, zcu, w, param_type, .suffix, .{});
2502 }2409 }
2503 switch (tag) {2410 if (function_info.varargs) {
2504 .function => {},2411 if (need_comma) try w.writeAll(", ");
2505 .varargs_function => {2412 need_comma = true;
2506 if (need_comma) try w.writeAll(", ");2413 try w.writeAll("...");
2507 need_comma = true;
2508 try w.writeAll("...");
2509 },
2510 else => unreachable,
2511 }2414 }
2512 if (!need_comma) try w.writeAll("void");2415 if (!need_comma) try w.writeAll("void");
2513 try w.writeByte(')');2416 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, .{});
2516 },2419 },
2517 }2420 }
2518}2421}
2519fn renderAggregateFields(2422fn renderFields(
2520 zcu: *Zcu,2423 zcu: *Zcu,
2521 writer: anytype,2424 writer: anytype,
2522 store: CType.Store.Set,2425 ctype_pool: *const CType.Pool,
2523 cty: CType,2426 aggregate_info: CType.Info.Aggregate,
2524 indent: usize,2427 indent: usize,
2525) !void {2428) !void {
2526 try writer.writeAll("{\n");2429 try writer.writeAll("{\n");
2527 const fields = cty.fields();2430 for (0..aggregate_info.fields.len) |field_index| {
2528 for (fields) |field| {2431 const field_info = aggregate_info.fields.at(field_index, ctype_pool);
2529 try writer.writeByteNTimes(' ', indent + 1);2432 try writer.writeByteNTimes(' ', indent + 1);
2530 switch (field.alignas.abiOrder()) {2433 switch (field_info.alignas.abiOrder()) {
2531 .lt => try writer.print("zig_under_align({}) ", .{field.alignas.toByteUnits()}),2434 .lt => {
2532 .eq => {},2435 std.debug.assert(aggregate_info.@"packed");
2533 .gt => try writer.print("zig_align({}) ", .{field.alignas.toByteUnits()}),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 },
2534 }2446 }
2535 const trailing = try renderTypePrefix(.flush, store, zcu, writer, field.type, .suffix, .{});2447 const trailing = try renderTypePrefix(
2536 try writer.print("{}{ }", .{ trailing, fmtIdent(mem.span(field.name)) });2448 .flush,
2537 try renderTypeSuffix(.flush, store, zcu, writer, field.type, .suffix, .{});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, .{});
2538 try writer.writeAll(";\n");2458 try writer.writeAll(";\n");
2539 }2459 }
2540 try writer.writeByteNTimes(' ', indent);2460 try writer.writeByteNTimes(' ', indent);
...@@ -2544,77 +2464,77 @@ fn renderAggregateFields(...@@ -2544,77 +2464,77 @@ fn renderAggregateFields(
2544pub fn genTypeDecl(2464pub fn genTypeDecl(
2545 zcu: *Zcu,2465 zcu: *Zcu,
2546 writer: anytype,2466 writer: anytype,
2547 global_store: CType.Store.Set,2467 global_ctype_pool: *const CType.Pool,
2548 global_idx: CType.Index,2468 global_ctype: CType,
2549 pass: DeclGen.Pass,2469 pass: DeclGen.Pass,
2550 decl_store: CType.Store.Set,2470 decl_ctype_pool: *const CType.Pool,
2551 decl_idx: CType.Index,2471 decl_ctype: CType,
2552 found_existing: bool,2472 found_existing: bool,
2553) !void {2473) !void {
2554 const global_cty = global_store.indexToCType(global_idx);2474 switch (global_ctype.info(global_ctype_pool)) {
2555 switch (global_cty.tag()) {2475 .basic, .pointer, .array, .vector, .function => {},
2556 .fwd_anon_struct => if (pass != .flush) {2476 .aligned => |aligned_info| {
2557 try writer.writeAll("typedef ");2477 if (!found_existing) {
2558 _ = try renderTypePrefix(.flush, global_store, zcu, writer, global_idx, .suffix, .{});2478 try writer.writeAll("typedef ");
2559 try writer.writeByte(' ');2479 try writer.print("{}", .{
2560 _ = try renderTypePrefix(pass, decl_store, zcu, writer, decl_idx, .suffix, .{});2480 try renderTypePrefix(pass, global_ctype_pool, zcu, writer, aligned_info.ctype, .suffix, .{}),
2561 try writer.writeAll(";\n");2481 });
2562 },2482 try renderAlignedTypeName(writer, global_ctype);
25632483 try renderTypeSuffix(pass, global_ctype_pool, zcu, writer, aligned_info.ctype, .suffix, .{});
2564 .fwd_struct,2484 std.debug.assert(aligned_info.alignas.abiOrder().compare(.lt));
2565 .fwd_union,2485 try writer.print(" zig_under_align({d});\n", .{aligned_info.alignas.toByteUnits()});
2566 .anon_struct,2486 }
2567 .anon_union,2487 switch (pass) {
2568 .@"struct",2488 .decl, .anon => {
2569 .@"union",2489 try writer.writeAll("typedef ");
2570 .packed_struct,2490 _ = try renderTypePrefix(.flush, global_ctype_pool, zcu, writer, global_ctype, .suffix, .{});
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 );
2607 try writer.writeByte(' ');2491 try writer.writeByte(' ');
2608 try renderAggregateFields(zcu, writer, global_store, global_cty, 0);2492 _ = try renderTypePrefix(pass, decl_ctype_pool, zcu, writer, decl_ctype, .suffix, .{});
2609 if (global_cty.isPacked()) try writer.writeByte(')');
2610 try writer.writeAll(";\n");2493 try writer.writeAll(";\n");
2611 },2494 },
26122495 .flush => {},
2613 else => unreachable,
2614 }2496 }
2615 },2497 },
26162498 .fwd_decl => |fwd_decl_info| switch (fwd_decl_info.name) {
2617 else => {},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 },
2618 }2538 }
2619}2539}
26202540
...@@ -2771,13 +2691,13 @@ fn genExports(o: *Object) !void {...@@ -2771,13 +2691,13 @@ fn genExports(o: *Object) !void {
2771 }2691 }
2772}2692}
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 {
2775 const zcu = o.dg.zcu;2695 const zcu = o.dg.zcu;
2776 const ip = &zcu.intern_pool;2696 const ip = &zcu.intern_pool;
2697 const ctype_pool = &o.dg.ctype_pool;
2777 const w = o.writer();2698 const w = o.writer();
2778 const key = lazy_fn.key_ptr.*;2699 const key = lazy_fn.key_ptr.*;
2779 const val = lazy_fn.value_ptr;2700 const val = lazy_fn.value_ptr;
2780 const fn_name = val.fn_name;
2781 switch (key) {2701 switch (key) {
2782 .tag_name => {2702 .tag_name => {
2783 const enum_ty = val.data.tag_name;2703 const enum_ty = val.data.tag_name;
...@@ -2787,7 +2707,7 @@ pub fn genLazyFn(o: *Object, lazy_fn: LazyFnMap.Entry) !void {...@@ -2787,7 +2707,7 @@ pub fn genLazyFn(o: *Object, lazy_fn: LazyFnMap.Entry) !void {
2787 try w.writeAll("static ");2707 try w.writeAll("static ");
2788 try o.dg.renderType(w, name_slice_ty);2708 try o.dg.renderType(w, name_slice_ty);
2789 try w.writeByte(' ');2709 try w.writeByte(' ');
2790 try w.writeAll(fn_name);2710 try w.writeAll(val.fn_name.slice(lazy_ctype_pool));
2791 try w.writeByte('(');2711 try w.writeByte('(');
2792 try o.dg.renderTypeAndName(w, enum_ty, .{ .identifier = "tag" }, Const, .none, .complete);2712 try o.dg.renderTypeAndName(w, enum_ty, .{ .identifier = "tag" }, Const, .none, .complete);
2793 try w.writeAll(") {\n switch (tag) {\n");2713 try w.writeAll(") {\n switch (tag) {\n");
...@@ -2829,8 +2749,9 @@ pub fn genLazyFn(o: *Object, lazy_fn: LazyFnMap.Entry) !void {...@@ -2829,8 +2749,9 @@ pub fn genLazyFn(o: *Object, lazy_fn: LazyFnMap.Entry) !void {
2829 },2749 },
2830 .never_tail, .never_inline => |fn_decl_index| {2750 .never_tail, .never_inline => |fn_decl_index| {
2831 const fn_decl = zcu.declPtr(fn_decl_index);2751 const fn_decl = zcu.declPtr(fn_decl_index);
2832 const fn_cty = try o.dg.typeToCType(fn_decl.typeOf(zcu), .complete);2752 const fn_ctype = try o.dg.ctypeFromType(fn_decl.typeOf(zcu), .complete);
2833 const fn_info = fn_cty.cast(CType.Payload.Function).?.data;2753 const fn_info = fn_ctype.info(ctype_pool).function;
2754 const fn_name = val.fn_name.slice(lazy_ctype_pool);
28342755
2835 const fwd_decl_writer = o.dg.fwdDeclWriter();2756 const fwd_decl_writer = o.dg.fwdDeclWriter();
2836 try fwd_decl_writer.print("static zig_{s} ", .{@tagName(key)});2757 try fwd_decl_writer.print("static zig_{s} ", .{@tagName(key)});
...@@ -2843,11 +2764,13 @@ pub fn genLazyFn(o: *Object, lazy_fn: LazyFnMap.Entry) !void {...@@ -2843,11 +2764,13 @@ pub fn genLazyFn(o: *Object, lazy_fn: LazyFnMap.Entry) !void {
2843 try fwd_decl_writer.writeAll(";\n");2764 try fwd_decl_writer.writeAll(";\n");
28442765
2845 try w.print("static zig_{s} ", .{@tagName(key)});2766 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 });
2847 try w.writeAll(" {\n return ");2770 try w.writeAll(" {\n return ");
2848 try o.dg.renderDeclName(w, fn_decl_index, 0);2771 try o.dg.renderDeclName(w, fn_decl_index, 0);
2849 try w.writeByte('(');2772 try w.writeByte('(');
2850 for (0..fn_info.param_types.len) |arg| {2773 for (0..fn_info.param_ctypes.len) |arg| {
2851 if (arg > 0) try w.writeAll(", ");2774 if (arg > 0) try w.writeAll(", ");
2852 try o.dg.writeCValue(w, .{ .arg = arg });2775 try o.dg.writeCValue(w, .{ .arg = arg });
2853 }2776 }
...@@ -2931,7 +2854,7 @@ pub fn genFunc(f: *Function) !void {...@@ -2931,7 +2854,7 @@ pub fn genFunc(f: *Function) !void {
2931 for (free_locals.values()) |list| {2854 for (free_locals.values()) |list| {
2932 for (list.keys()) |local_index| {2855 for (list.keys()) |local_index| {
2933 const local = f.locals.items[local_index];2856 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);
2935 try w.writeAll(";\n ");2858 try w.writeAll(";\n ");
2936 }2859 }
2937 }2860 }
...@@ -3451,11 +3374,7 @@ fn airPtrElemPtr(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3451,11 +3374,7 @@ fn airPtrElemPtr(f: *Function, inst: Air.Inst.Index) !CValue {
34513374
3452 const inst_ty = f.typeOfIndex(inst);3375 const inst_ty = f.typeOfIndex(inst);
3453 const ptr_ty = f.typeOf(bin_op.lhs);3376 const ptr_ty = f.typeOf(bin_op.lhs);
3454 const ptr_align = ptr_ty.ptrAlignment(zcu);3377 const elem_has_bits = ptr_ty.elemType2(zcu).hasRuntimeBitsIgnoreComptime(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);
34593378
3460 const ptr = try f.resolveInst(bin_op.lhs);3379 const ptr = try f.resolveInst(bin_op.lhs);
3461 const index = try f.resolveInst(bin_op.rhs);3380 const index = try f.resolveInst(bin_op.rhs);
...@@ -3470,22 +3389,13 @@ fn airPtrElemPtr(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3470,22 +3389,13 @@ fn airPtrElemPtr(f: *Function, inst: Air.Inst.Index) !CValue {
3470 try f.renderType(writer, inst_ty);3389 try f.renderType(writer, inst_ty);
3471 try writer.writeByte(')');3390 try writer.writeByte(')');
3472 if (elem_has_bits) try writer.writeByte('&');3391 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) {
3474 // It's a pointer to an array, so we need to de-reference.3393 // It's a pointer to an array, so we need to de-reference.
3475 try f.writeCValueDeref(writer, ptr);3394 try f.writeCValueDeref(writer, ptr);
3476 } else try f.writeCValue(writer, ptr, .Other);3395 } else try f.writeCValue(writer, ptr, .Other);
3477 if (elem_has_bits) {3396 if (elem_has_bits) {
3478 try writer.writeByte('[');3397 try writer.writeByte('[');
3479 try f.writeCValue(writer, index, .Other);3398 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 }
3489 try writer.writeByte(']');3399 try writer.writeByte(']');
3490 }3400 }
3491 try a.end(f, writer);3401 try a.end(f, writer);
...@@ -3577,13 +3487,16 @@ fn airArrayElemVal(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3577,13 +3487,16 @@ fn airArrayElemVal(f: *Function, inst: Air.Inst.Index) !CValue {
3577fn airAlloc(f: *Function, inst: Air.Inst.Index) !CValue {3487fn airAlloc(f: *Function, inst: Air.Inst.Index) !CValue {
3578 const zcu = f.object.dg.zcu;3488 const zcu = f.object.dg.zcu;
3579 const inst_ty = f.typeOfIndex(inst);3489 const inst_ty = f.typeOfIndex(inst);
3580 const elem_type = inst_ty.childType(zcu);3490 const elem_ty = inst_ty.childType(zcu);
3581 if (!elem_type.isFnOrHasRuntimeBitsIgnoreComptime(zcu)) return .{ .undef = inst_ty };3491 if (!elem_ty.isFnOrHasRuntimeBitsIgnoreComptime(zcu)) return .{ .undef = inst_ty };
35823492
3583 const local = try f.allocLocalValue(3493 const local = try f.allocLocalValue(.{
3584 elem_type,3494 .ctype = try f.ctypeFromType(elem_ty, .complete),
3585 inst_ty.ptrAlignment(zcu),3495 .alignas = CType.AlignAs.fromAlignment(.{
3586 );3496 .@"align" = inst_ty.ptrInfo(zcu).flags.alignment,
3497 .abi = elem_ty.abiAlignment(zcu),
3498 }),
3499 });
3587 log.debug("%{d}: allocated unfreeable t{d}", .{ inst, local.new_local });3500 log.debug("%{d}: allocated unfreeable t{d}", .{ inst, local.new_local });
3588 const gpa = f.object.dg.zcu.gpa;3501 const gpa = f.object.dg.zcu.gpa;
3589 try f.allocs.put(gpa, local.new_local, true);3502 try f.allocs.put(gpa, local.new_local, true);
...@@ -3596,10 +3509,13 @@ fn airRetPtr(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3596,10 +3509,13 @@ fn airRetPtr(f: *Function, inst: Air.Inst.Index) !CValue {
3596 const elem_ty = inst_ty.childType(zcu);3509 const elem_ty = inst_ty.childType(zcu);
3597 if (!elem_ty.isFnOrHasRuntimeBitsIgnoreComptime(zcu)) return .{ .undef = inst_ty };3510 if (!elem_ty.isFnOrHasRuntimeBitsIgnoreComptime(zcu)) return .{ .undef = inst_ty };
35983511
3599 const local = try f.allocLocalValue(3512 const local = try f.allocLocalValue(.{
3600 elem_ty,3513 .ctype = try f.ctypeFromType(elem_ty, .complete),
3601 inst_ty.ptrAlignment(zcu),3514 .alignas = CType.AlignAs.fromAlignment(.{
3602 );3515 .@"align" = inst_ty.ptrInfo(zcu).flags.alignment,
3516 .abi = elem_ty.abiAlignment(zcu),
3517 }),
3518 });
3603 log.debug("%{d}: allocated unfreeable t{d}", .{ inst, local.new_local });3519 log.debug("%{d}: allocated unfreeable t{d}", .{ inst, local.new_local });
3604 const gpa = f.object.dg.zcu.gpa;3520 const gpa = f.object.dg.zcu.gpa;
3605 try f.allocs.put(gpa, local.new_local, true);3521 try f.allocs.put(gpa, local.new_local, true);
...@@ -3608,14 +3524,14 @@ fn airRetPtr(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3608,14 +3524,14 @@ fn airRetPtr(f: *Function, inst: Air.Inst.Index) !CValue {
36083524
3609fn airArg(f: *Function, inst: Air.Inst.Index) !CValue {3525fn airArg(f: *Function, inst: Air.Inst.Index) !CValue {
3610 const inst_ty = f.typeOfIndex(inst);3526 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
3613 const i = f.next_arg_index;3529 const i = f.next_arg_index;
3614 f.next_arg_index += 1;3530 f.next_arg_index += 1;
3615 const result: CValue = if (inst_cty != try f.typeToIndex(inst_ty, .complete))3531 const result: CValue = if (inst_ctype.eql(try f.ctypeFromType(inst_ty, .complete)))
3616 .{ .arg_array = i }3532 .{ .arg = i }
3617 else3533 else
3618 .{ .arg = i };3534 .{ .arg_array = i };
36193535
3620 if (f.liveness.isUnused(inst)) {3536 if (f.liveness.isUnused(inst)) {
3621 const writer = f.object.writer();3537 const writer = f.object.writer();
...@@ -3649,7 +3565,7 @@ fn airLoad(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3649,7 +3565,7 @@ fn airLoad(f: *Function, inst: Air.Inst.Index) !CValue {
3649 try reap(f, inst, &.{ty_op.operand});3565 try reap(f, inst, &.{ty_op.operand});
36503566
3651 const is_aligned = if (ptr_info.flags.alignment != .none)3567 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)
3653 else3569 else
3654 true;3570 true;
3655 const is_array = lowersToArray(src_ty, zcu);3571 const is_array = lowersToArray(src_ty, zcu);
...@@ -3724,18 +3640,21 @@ fn airRet(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !CValue {...@@ -3724,18 +3640,21 @@ fn airRet(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !CValue {
3724 const op_inst = un_op.toIndex();3640 const op_inst = un_op.toIndex();
3725 const op_ty = f.typeOf(un_op);3641 const op_ty = f.typeOf(un_op);
3726 const ret_ty = if (is_ptr) op_ty.childType(zcu) else op_ty;3642 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
3729 if (op_inst != null and f.air.instructions.items(.tag)[@intFromEnum(op_inst.?)] == .call_always_tail) {3645 if (op_inst != null and f.air.instructions.items(.tag)[@intFromEnum(op_inst.?)] == .call_always_tail) {
3730 try reap(f, inst, &.{un_op});3646 try reap(f, inst, &.{un_op});
3731 _ = try airCall(f, op_inst.?, .always_tail);3647 _ = try airCall(f, op_inst.?, .always_tail);
3732 } else if (lowered_ret_ty.hasRuntimeBitsIgnoreComptime(zcu)) {3648 } else if (ret_ctype.index != .void) {
3733 const operand = try f.resolveInst(un_op);3649 const operand = try f.resolveInst(un_op);
3734 try reap(f, inst, &.{un_op});3650 try reap(f, inst, &.{un_op});
3735 var deref = is_ptr;3651 var deref = is_ptr;
3736 const is_array = lowersToArray(ret_ty, zcu);3652 const is_array = lowersToArray(ret_ty, zcu);
3737 const ret_val = if (is_array) ret_val: {3653 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 });
3739 try writer.writeAll("memcpy(");3658 try writer.writeAll("memcpy(");
3740 try f.writeCValueMember(writer, array_local, .{ .identifier = "array" });3659 try f.writeCValueMember(writer, array_local, .{ .identifier = "array" });
3741 try writer.writeAll(", ");3660 try writer.writeAll(", ");
...@@ -3921,7 +3840,7 @@ fn airStore(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue {...@@ -3921,7 +3840,7 @@ fn airStore(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue {
3921 }3840 }
39223841
3923 const is_aligned = if (ptr_info.flags.alignment != .none)3842 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)
3925 else3844 else
3926 true;3845 true;
3927 const is_array = lowersToArray(Type.fromInterned(ptr_info.child), zcu);3846 const is_array = lowersToArray(Type.fromInterned(ptr_info.child), zcu);
...@@ -4397,22 +4316,23 @@ fn airCall(...@@ -4397,22 +4316,23 @@ fn airCall(
4397 defer gpa.free(resolved_args);4316 defer gpa.free(resolved_args);
4398 for (resolved_args, args) |*resolved_arg, arg| {4317 for (resolved_args, args) |*resolved_arg, arg| {
4399 const arg_ty = f.typeOf(arg);4318 const arg_ty = f.typeOf(arg);
4400 const arg_cty = try f.typeToIndex(arg_ty, .parameter);4319 const arg_ctype = try f.ctypeFromType(arg_ty, .parameter);
4401 if (f.indexToCType(arg_cty).tag() == .void) {4320 if (arg_ctype.index == .void) {
4402 resolved_arg.* = .none;4321 resolved_arg.* = .none;
4403 continue;4322 continue;
4404 }4323 }
4405 resolved_arg.* = try f.resolveInst(arg);4324 resolved_arg.* = try f.resolveInst(arg);
4406 if (arg_cty != try f.typeToIndex(arg_ty, .complete)) {4325 if (!arg_ctype.eql(try f.ctypeFromType(arg_ty, .complete))) {
4407 const lowered_arg_ty = try lowerFnRetTy(arg_ty, zcu);4326 const array_local = try f.allocAlignedLocal(inst, .{
44084327 .ctype = arg_ctype,
4409 const array_local = try f.allocLocal(inst, lowered_arg_ty);4328 .alignas = CType.AlignAs.fromAbiAlignment(arg_ty.abiAlignment(zcu)),
4329 });
4410 try writer.writeAll("memcpy(");4330 try writer.writeAll("memcpy(");
4411 try f.writeCValueMember(writer, array_local, .{ .identifier = "array" });4331 try f.writeCValueMember(writer, array_local, .{ .identifier = "array" });
4412 try writer.writeAll(", ");4332 try writer.writeAll(", ");
4413 try f.writeCValue(writer, resolved_arg.*, .FunctionArgument);4333 try f.writeCValue(writer, resolved_arg.*, .FunctionArgument);
4414 try writer.writeAll(", sizeof(");4334 try writer.writeAll(", sizeof(");
4415 try f.renderType(writer, lowered_arg_ty);4335 try f.renderCType(writer, arg_ctype);
4416 try writer.writeAll("));\n");4336 try writer.writeAll("));\n");
4417 resolved_arg.* = array_local;4337 resolved_arg.* = array_local;
4418 }4338 }
...@@ -4433,21 +4353,27 @@ fn airCall(...@@ -4433,21 +4353,27 @@ fn airCall(
4433 else => unreachable,4353 else => unreachable,
4434 }).?;4354 }).?;
4435 const ret_ty = Type.fromInterned(fn_info.return_type);4355 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
4438 const result_local = result: {4361 const result_local = result: {
4439 if (modifier == .always_tail) {4362 if (modifier == .always_tail) {
4440 try writer.writeAll("zig_always_tail return ");4363 try writer.writeAll("zig_always_tail return ");
4441 break :result .none;4364 break :result .none;
4442 } else if (!lowered_ret_ty.hasRuntimeBitsIgnoreComptime(zcu)) {4365 } else if (ret_ctype.index == .void) {
4443 break :result .none;4366 break :result .none;
4444 } else if (f.liveness.isUnused(inst)) {4367 } else if (f.liveness.isUnused(inst)) {
4445 try writer.writeByte('(');4368 try writer.writeByte('(');
4446 try f.renderType(writer, Type.void);4369 try f.renderCType(writer, .{ .index = .void });
4447 try writer.writeByte(')');4370 try writer.writeByte(')');
4448 break :result .none;4371 break :result .none;
4449 } else {4372 } 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 });
4451 try f.writeCValue(writer, local, .Other);4377 try f.writeCValue(writer, local, .Other);
4452 try writer.writeAll(" = ");4378 try writer.writeAll(" = ");
4453 break :result local;4379 break :result local;
...@@ -4767,6 +4693,7 @@ const LocalResult = struct {...@@ -4767,6 +4693,7 @@ const LocalResult = struct {
4767fn bitcast(f: *Function, dest_ty: Type, operand: CValue, operand_ty: Type) !LocalResult {4693fn bitcast(f: *Function, dest_ty: Type, operand: CValue, operand_ty: Type) !LocalResult {
4768 const zcu = f.object.dg.zcu;4694 const zcu = f.object.dg.zcu;
4769 const target = &f.object.dg.mod.resolved_target.result;4695 const target = &f.object.dg.mod.resolved_target.result;
4696 const ctype_pool = &f.object.dg.ctype_pool;
4770 const writer = f.object.writer();4697 const writer = f.object.writer();
47714698
4772 if (operand_ty.isAbiInt(zcu) and dest_ty.isAbiInt(zcu)) {4699 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...@@ -4825,49 +4752,54 @@ fn bitcast(f: *Function, dest_ty: Type, operand: CValue, operand_ty: Type) !Loca
48254752
4826 // Ensure padding bits have the expected value.4753 // Ensure padding bits have the expected value.
4827 if (dest_ty.isAbiInt(zcu)) {4754 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);
4829 const dest_info = dest_ty.intInfo(zcu);4756 const dest_info = dest_ty.intInfo(zcu);
4830 var bits: u16 = dest_info.bits;4757 var bits: u16 = dest_info.bits;
4831 var wrap_cty: ?CType = null;4758 var wrap_ctype: ?CType = null;
4832 var need_bitcasts = false;4759 var need_bitcasts = false;
48334760
4834 try f.writeCValue(writer, local, .Other);4761 try f.writeCValue(writer, local, .Other);
4835 if (dest_cty.castTag(.array)) |pl| {4762 switch (dest_ctype.info(ctype_pool)) {
4836 try writer.print("[{d}]", .{switch (target.cpu.arch.endian()) {4763 else => {},
4837 .little => pl.data.len - 1,4764 .array => |array_info| {
4838 .big => 0,4765 try writer.print("[{d}]", .{switch (target.cpu.arch.endian()) {
4839 }});4766 .little => array_info.len - 1,
4840 const elem_cty = f.indexToCType(pl.data.elem_type);4767 .big => 0,
4841 wrap_cty = elem_cty.toSignedness(dest_info.signedness);4768 }});
4842 need_bitcasts = wrap_cty.?.tag() == .zig_i128;4769 wrap_ctype = array_info.elem_ctype.toSignedness(dest_info.signedness);
4843 bits -= 1;4770 need_bitcasts = wrap_ctype.?.index == .zig_i128;
4844 bits %= @as(u16, @intCast(f.byteSize(elem_cty) * 8));4771 bits -= 1;
4845 bits += 1;4772 bits %= @as(u16, @intCast(f.byteSize(array_info.elem_ctype) * 8));
4773 bits += 1;
4774 },
4846 }4775 }
4847 try writer.writeAll(" = ");4776 try writer.writeAll(" = ");
4848 if (need_bitcasts) {4777 if (need_bitcasts) {
4849 try writer.writeAll("zig_bitCast_");4778 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());
4851 try writer.writeByte('(');4780 try writer.writeByte('(');
4852 }4781 }
4853 try writer.writeAll("zig_wrap_");4782 try writer.writeAll("zig_wrap_");
4854 const info_ty = try zcu.intType(dest_info.signedness, bits);4783 const info_ty = try zcu.intType(dest_info.signedness, bits);
4855 if (wrap_cty) |cty|4784 if (wrap_ctype) |ctype|
4856 try f.object.dg.renderCTypeForBuiltinFnName(writer, cty)4785 try f.object.dg.renderCTypeForBuiltinFnName(writer, ctype)
4857 else4786 else
4858 try f.object.dg.renderTypeForBuiltinFnName(writer, info_ty);4787 try f.object.dg.renderTypeForBuiltinFnName(writer, info_ty);
4859 try writer.writeByte('(');4788 try writer.writeByte('(');
4860 if (need_bitcasts) {4789 if (need_bitcasts) {
4861 try writer.writeAll("zig_bitCast_");4790 try writer.writeAll("zig_bitCast_");
4862 try f.object.dg.renderCTypeForBuiltinFnName(writer, wrap_cty.?);4791 try f.object.dg.renderCTypeForBuiltinFnName(writer, wrap_ctype.?);
4863 try writer.writeByte('(');4792 try writer.writeByte('(');
4864 }4793 }
4865 try f.writeCValue(writer, local, .Other);4794 try f.writeCValue(writer, local, .Other);
4866 if (dest_cty.castTag(.array)) |pl| {4795 switch (dest_ctype.info(ctype_pool)) {
4867 try writer.print("[{d}]", .{switch (target.cpu.arch.endian()) {4796 else => {},
4868 .little => pl.data.len - 1,4797 .array => |array_info| try writer.print("[{d}]", .{
4869 .big => 0,4798 switch (target.cpu.arch.endian()) {
4870 }});4799 .little => array_info.len - 1,
4800 .big => 0,
4801 },
4802 }),
4871 }4803 }
4872 if (need_bitcasts) try writer.writeByte(')');4804 if (need_bitcasts) try writer.writeByte(')');
4873 try f.object.dg.renderBuiltinInfo(writer, info_ty, .bits);4805 try f.object.dg.renderBuiltinInfo(writer, info_ty, .bits);
...@@ -5131,10 +5063,9 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5131,10 +5063,9 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
5131 if (is_reg) {5063 if (is_reg) {
5132 const output_ty = if (output == .none) inst_ty else f.typeOf(output).childType(zcu);5064 const output_ty = if (output == .none) inst_ty else f.typeOf(output).childType(zcu);
5133 try writer.writeAll("register ");5065 try writer.writeAll("register ");
5134 const alignment: Alignment = .none;5066 const local_value = try f.allocLocal(inst, output_ty);
5135 const local_value = try f.allocLocalValue(output_ty, alignment);
5136 try f.allocs.put(gpa, local_value.new_local, false);5067 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);
5138 try writer.writeAll(" __asm(\"");5069 try writer.writeAll(" __asm(\"");
5139 try writer.writeAll(constraint["={".len .. constraint.len - "}".len]);5070 try writer.writeAll(constraint["={".len .. constraint.len - "}".len]);
5140 try writer.writeAll("\")");5071 try writer.writeAll("\")");
...@@ -5164,10 +5095,9 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5164,10 +5095,9 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
5164 if (asmInputNeedsLocal(f, constraint, input_val)) {5095 if (asmInputNeedsLocal(f, constraint, input_val)) {
5165 const input_ty = f.typeOf(input);5096 const input_ty = f.typeOf(input);
5166 if (is_reg) try writer.writeAll("register ");5097 if (is_reg) try writer.writeAll("register ");
5167 const alignment: Alignment = .none;5098 const local_value = try f.allocLocal(inst, input_ty);
5168 const local_value = try f.allocLocalValue(input_ty, alignment);
5169 try f.allocs.put(gpa, local_value.new_local, false);5099 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);
5171 if (is_reg) {5101 if (is_reg) {
5172 try writer.writeAll(" __asm(\"");5102 try writer.writeAll(" __asm(\"");
5173 try writer.writeAll(constraint["{".len .. constraint.len - "}".len]);5103 try writer.writeAll(constraint["{".len .. constraint.len - "}".len]);
...@@ -5512,59 +5442,74 @@ fn fieldLocation(...@@ -5512,59 +5442,74 @@ fn fieldLocation(
5512 end: void,5442 end: void,
5513} {5443} {
5514 const ip = &zcu.intern_pool;5444 const ip = &zcu.intern_pool;
5515 const container_ty = container_ptr_ty.childType(zcu);5445 const container_ty = Type.fromInterned(ip.indexToKey(container_ptr_ty.toIntern()).ptr_type.child);
5516 return switch (container_ty.zigTypeTag(zcu)) {5446 switch (ip.indexToKey(container_ty.toIntern())) {
5517 .Struct => blk: {5447 .struct_type => {
5518 if (zcu.typeToPackedStruct(container_ty)) |struct_type| {5448 const loaded_struct = ip.loadStructType(container_ty.toIntern());
5519 if (field_ptr_ty.ptrInfo(zcu).packed_offset.host_size == 0)5449 switch (loaded_struct.layout) {
5520 break :blk .{ .byte_offset = @divExact(zcu.structPackedFieldBitOffset(struct_type, field_index) + container_ptr_ty.ptrInfo(zcu).packed_offset.bit_offset, 8) }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) }
5521 else5468 else
5522 break :blk .begin;5469 .begin,
5523 }5470 }
55245471 },
5525 for (field_index..container_ty.structFieldCount(zcu)) |next_field_index_usize| {5472 .anon_struct_type => |anon_struct_info| {
5526 const next_field_index: u32 = @intCast(next_field_index_usize);5473 for (field_index..anon_struct_info.types.len) |next_field_index| {
5527 if (container_ty.structFieldIsComptime(next_field_index, zcu)) continue;5474 if (anon_struct_info.values.get(ip)[next_field_index] != .none) continue;
5528 const field_ty = container_ty.structFieldType(next_field_index, zcu);5475 const field_type = Type.fromInterned(anon_struct_info.types.get(ip)[next_field_index]);
5529 if (!field_ty.hasRuntimeBitsIgnoreComptime(zcu)) continue;5476 if (!field_type.hasRuntimeBitsIgnoreComptime(zcu)) continue;
55305477 return .{ .field = if (anon_struct_info.fieldName(ip, next_field_index).unwrap()) |field_name|
5531 break :blk .{ .field = if (container_ty.isSimpleTuple(zcu))5478 .{ .identifier = ip.stringToSlice(field_name) }
5532 .{ .field = next_field_index }
5533 else5479 else
5534 .{ .identifier = ip.stringToSlice(container_ty.legacyStructFieldName(next_field_index, zcu)) } };5480 .{ .field = next_field_index } };
5535 }5481 }
5536 break :blk if (container_ty.hasRuntimeBitsIgnoreComptime(zcu)) .end else .begin;5482 return if (container_ty.hasRuntimeBitsIgnoreComptime(zcu)) .end else .begin;
5537 },5483 },
5538 .Union => {5484 .union_type => {
5539 const union_obj = zcu.typeToUnion(container_ty).?;5485 const loaded_union = ip.loadUnionType(container_ty.toIntern());
5540 return switch (union_obj.getLayout(ip)) {5486 switch (loaded_union.getLayout(ip)) {
5541 .auto, .@"extern" => {5487 .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]);
5543 if (!field_ty.hasRuntimeBitsIgnoreComptime(zcu))5489 if (!field_ty.hasRuntimeBitsIgnoreComptime(zcu))
5544 return if (container_ty.unionTagTypeSafety(zcu) != null and5490 return if (loaded_union.hasTag(ip) and !container_ty.unionHasAllZeroBitFieldTypes(zcu))
5545 !container_ty.unionHasAllZeroBitFieldTypes(zcu))
5546 .{ .field = .{ .identifier = "payload" } }5491 .{ .field = .{ .identifier = "payload" } }
5547 else5492 else
5548 .begin;5493 .begin;
5549 const field_name = union_obj.loadTagType(ip).names.get(ip)[field_index];5494 const field_name = loaded_union.loadTagType(ip).names.get(ip)[field_index];
5550 return .{ .field = if (container_ty.unionTagTypeSafety(zcu)) |_|5495 return .{ .field = if (loaded_union.hasTag(ip))
5551 .{ .payload_identifier = ip.stringToSlice(field_name) }5496 .{ .payload_identifier = ip.stringToSlice(field_name) }
5552 else5497 else
5553 .{ .identifier = ip.stringToSlice(field_name) } };5498 .{ .identifier = ip.stringToSlice(field_name) } };
5554 },5499 },
5555 .@"packed" => .begin,5500 .@"packed" => return .begin,
5556 };5501 }
5557 },5502 },
5558 .Pointer => switch (container_ty.ptrSize(zcu)) {5503 .ptr_type => |ptr_info| switch (ptr_info.flags.size) {
5504 .One, .Many, .C => unreachable,
5559 .Slice => switch (field_index) {5505 .Slice => switch (field_index) {
5560 0 => .{ .field = .{ .identifier = "ptr" } },5506 0 => return .{ .field = .{ .identifier = "ptr" } },
5561 1 => .{ .field = .{ .identifier = "len" } },5507 1 => return .{ .field = .{ .identifier = "len" } },
5562 else => unreachable,5508 else => unreachable,
5563 },5509 },
5564 .One, .Many, .C => unreachable,
5565 },5510 },
5566 else => unreachable,5511 else => unreachable,
5567 };5512 }
5568}5513}
55695514
5570fn airStructFieldPtr(f: *Function, inst: Air.Inst.Index) !CValue {5515fn airStructFieldPtr(f: *Function, inst: Air.Inst.Index) !CValue {
...@@ -5653,7 +5598,7 @@ fn fieldPtr(...@@ -5653,7 +5598,7 @@ fn fieldPtr(
5653 const field_ptr_ty = f.typeOfIndex(inst);5598 const field_ptr_ty = f.typeOfIndex(inst);
56545599
5655 // Ensure complete type definition is visible before accessing fields.5600 // Ensure complete type definition is visible before accessing fields.
5656 _ = try f.typeToIndex(container_ty, .complete);5601 _ = try f.ctypeFromType(container_ty, .complete);
56575602
5658 const writer = f.object.writer();5603 const writer = f.object.writer();
5659 const local = try f.allocLocal(inst, field_ptr_ty);5604 const local = try f.allocLocal(inst, field_ptr_ty);
...@@ -5708,109 +5653,109 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5708,109 +5653,109 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {
5708 const writer = f.object.writer();5653 const writer = f.object.writer();
57095654
5710 // Ensure complete type definition is visible before accessing fields.5655 // 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())) {5669 const bit_offset_ty = try zcu.intType(.unsigned, Type.smallestUnsignedBits(int_info.bits - 1));
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);
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))5679 const temp_local = try f.allocLocal(inst, field_int_ty);
5728 inst_ty.intInfo(zcu).signedness5680 try f.writeCValue(writer, temp_local, .Other);
5729 else5681 try writer.writeAll(" = zig_wrap_");
5730 .unsigned;5682 try f.object.dg.renderTypeForBuiltinFnName(writer, field_int_ty);
5731 const field_int_ty = try zcu.intType(field_int_signedness, @as(u16, @intCast(inst_ty.bitSize(zcu))));5683 try writer.writeAll("((");
57325684 try f.renderType(writer, field_int_ty);
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);
5756 try writer.writeByte(')');5685 try writer.writeByte(')');
5757 }5686 const cant_cast = int_info.bits > 64;
5758 if (cant_cast) try writer.writeByte(')');5687 if (cant_cast) {
5759 try f.object.dg.renderBuiltinInfo(writer, field_int_ty, .bits);5688 if (field_int_ty.bitSize(zcu) > 64) return f.fail("TODO: C backend: implement casting between types > 64 bits", .{});
5760 try writer.writeAll(");\n");5689 try writer.writeAll("zig_lo_");
5761 if (inst_ty.eql(field_int_ty, f.object.dg.zcu)) return temp_local;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);5707 const local = try f.allocLocal(inst, inst_ty);
5764 try writer.writeAll("memcpy(");5708 try writer.writeAll("memcpy(");
5765 try f.writeCValue(writer, .{ .local_ref = local.new_local }, .FunctionArgument);5709 try f.writeCValue(writer, .{ .local_ref = local.new_local }, .FunctionArgument);
5766 try writer.writeAll(", ");5710 try writer.writeAll(", ");
5767 try f.writeCValue(writer, .{ .local_ref = temp_local.new_local }, .FunctionArgument);5711 try f.writeCValue(writer, .{ .local_ref = temp_local.new_local }, .FunctionArgument);
5768 try writer.writeAll(", sizeof(");5712 try writer.writeAll(", sizeof(");
5769 try f.renderType(writer, inst_ty);5713 try f.renderType(writer, inst_ty);
5770 try writer.writeAll("));\n");5714 try writer.writeAll("));\n");
5771 try freeLocal(f, inst, temp_local.new_local, null);5715 try freeLocal(f, inst, temp_local.new_local, null);
5772 return local;5716 return local;
5773 },5717 },
5718 }
5774 },5719 },
57755720 .anon_struct_type => |anon_struct_info| if (anon_struct_info.fieldName(ip, extra.field_index).unwrap()) |field_name|
5776 .anon_struct_type => |anon_struct_type| if (anon_struct_type.names.len == 0)5721 .{ .identifier = ip.stringToSlice(field_name) }
5777 .{ .field = extra.field_index }
5778 else5722 else
5779 .{ .identifier = ip.stringToSlice(struct_ty.legacyStructFieldName(extra.field_index, zcu)) },5723 .{ .field = extra.field_index },
5780
5781 .union_type => field_name: {5724 .union_type => field_name: {
5782 const union_obj = ip.loadUnionType(struct_ty.toIntern());5725 const loaded_union = ip.loadUnionType(struct_ty.toIntern());
5783 if (union_obj.flagsPtr(ip).layout == .@"packed") {5726 switch (loaded_union.getLayout(ip)) {
5784 const operand_lval = if (struct_byval == .constant) blk: {5727 .auto, .@"extern" => {
5785 const operand_local = try f.allocLocal(inst, struct_ty);5728 const name = loaded_union.loadTagType(ip).names.get(ip)[extra.field_index];
5786 try f.writeCValue(writer, operand_local, .Other);5729 break :field_name if (loaded_union.hasTag(ip))
5787 try writer.writeAll(" = ");5730 .{ .payload_identifier = ip.stringToSlice(name) }
5788 try f.writeCValue(writer, struct_byval, .Initializer);5731 else
5789 try writer.writeAll(";\n");5732 .{ .identifier = ip.stringToSlice(name) };
5790 break :blk operand_local;5733 },
5791 } else struct_byval;5734 .@"packed" => {
57925735 const operand_lval = if (struct_byval == .constant) blk: {
5793 const local = try f.allocLocal(inst, inst_ty);5736 const operand_local = try f.allocLocal(inst, struct_ty);
5794 try writer.writeAll("memcpy(&");5737 try f.writeCValue(writer, operand_local, .Other);
5795 try f.writeCValue(writer, local, .Other);5738 try writer.writeAll(" = ");
5796 try writer.writeAll(", &");5739 try f.writeCValue(writer, struct_byval, .Initializer);
5797 try f.writeCValue(writer, operand_lval, .Other);5740 try writer.writeAll(";\n");
5798 try writer.writeAll(", sizeof(");5741 break :blk operand_local;
5799 try f.renderType(writer, inst_ty);5742 } else struct_byval;
5800 try writer.writeAll("));\n");5743
58015744 const local = try f.allocLocal(inst, inst_ty);
5802 if (struct_byval == .constant) {5745 try writer.writeAll("memcpy(&");
5803 try freeLocal(f, inst, operand_lval.new_local, null);5746 try f.writeCValue(writer, local, .Other);
5804 }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;5757 return local;
5807 } else {5758 },
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 };
5814 }5759 }
5815 },5760 },
5816 else => unreachable,5761 else => unreachable,
...@@ -6089,6 +6034,7 @@ fn airIsErr(f: *Function, inst: Air.Inst.Index, is_ptr: bool, operator: []const...@@ -6089,6 +6034,7 @@ fn airIsErr(f: *Function, inst: Air.Inst.Index, is_ptr: bool, operator: []const
60896034
6090fn airArrayToSlice(f: *Function, inst: Air.Inst.Index) !CValue {6035fn airArrayToSlice(f: *Function, inst: Air.Inst.Index) !CValue {
6091 const zcu = f.object.dg.zcu;6036 const zcu = f.object.dg.zcu;
6037 const ctype_pool = &f.object.dg.ctype_pool;
6092 const ty_op = f.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;6038 const ty_op = f.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
60936039
6094 const operand = try f.resolveInst(ty_op.operand);6040 const operand = try f.resolveInst(ty_op.operand);
...@@ -6107,18 +6053,18 @@ fn airArrayToSlice(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -6107,18 +6053,18 @@ fn airArrayToSlice(f: *Function, inst: Air.Inst.Index) !CValue {
6107 if (operand == .undef) {6053 if (operand == .undef) {
6108 try f.writeCValue(writer, .{ .undef = inst_ty.slicePtrFieldType(zcu) }, .Initializer);6054 try f.writeCValue(writer, .{ .undef = inst_ty.slicePtrFieldType(zcu) }, .Initializer);
6109 } else {6055 } else {
6110 const ptr_cty = try f.typeToIndex(ptr_ty, .complete);6056 const ptr_ctype = try f.ctypeFromType(ptr_ty, .complete);
6111 const ptr_child_cty = f.indexToCType(ptr_cty).cast(CType.Payload.Child).?.data;6057 const ptr_child_ctype = ptr_ctype.info(ctype_pool).pointer.elem_ctype;
6112 const elem_ty = array_ty.childType(zcu);6058 const elem_ty = array_ty.childType(zcu);
6113 const elem_cty = try f.typeToIndex(elem_ty, .complete);6059 const elem_ctype = try f.ctypeFromType(elem_ty, .complete);
6114 if (ptr_child_cty != elem_cty) {6060 if (!ptr_child_ctype.eql(elem_ctype)) {
6115 try writer.writeByte('(');6061 try writer.writeByte('(');
6116 try f.renderCType(writer, ptr_cty);6062 try f.renderCType(writer, ptr_ctype);
6117 try writer.writeByte(')');6063 try writer.writeByte(')');
6118 }6064 }
6119 const operand_cty = try f.typeToCType(operand_ty, .complete);6065 const operand_ctype = try f.ctypeFromType(operand_ty, .complete);
6120 const operand_child_cty = operand_cty.cast(CType.Payload.Child).?.data;6066 const operand_child_ctype = operand_ctype.info(ctype_pool).pointer.elem_ctype;
6121 if (f.indexToCType(operand_child_cty).tag() == .array) {6067 if (operand_child_ctype.info(ctype_pool) == .array) {
6122 try writer.writeByte('&');6068 try writer.writeByte('&');
6123 try f.writeCValueDeref(writer, operand);6069 try f.writeCValueDeref(writer, operand);
6124 try writer.print("[{}]", .{try f.fmtIntLiteral(try zcu.intValue(Type.usize, 0))});6070 try writer.print("[{}]", .{try f.fmtIntLiteral(try zcu.intValue(Type.usize, 0))});
...@@ -6229,8 +6175,8 @@ fn airUnBuiltinCall(...@@ -6229,8 +6175,8 @@ fn airUnBuiltinCall(
6229 const operand_ty = f.typeOf(ty_op.operand);6175 const operand_ty = f.typeOf(ty_op.operand);
6230 const scalar_ty = operand_ty.scalarType(zcu);6176 const scalar_ty = operand_ty.scalarType(zcu);
62316177
6232 const inst_scalar_cty = try f.typeToCType(inst_scalar_ty, .complete);6178 const inst_scalar_ctype = try f.ctypeFromType(inst_scalar_ty, .complete);
6233 const ref_ret = inst_scalar_cty.tag() == .array;6179 const ref_ret = inst_scalar_ctype.info(&f.object.dg.ctype_pool) == .array;
62346180
6235 const writer = f.object.writer();6181 const writer = f.object.writer();
6236 const local = try f.allocLocal(inst, inst_ty);6182 const local = try f.allocLocal(inst, inst_ty);
...@@ -6267,8 +6213,8 @@ fn airBinBuiltinCall(...@@ -6267,8 +6213,8 @@ fn airBinBuiltinCall(
6267 const bin_op = f.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;6213 const bin_op = f.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
62686214
6269 const operand_ty = f.typeOf(bin_op.lhs);6215 const operand_ty = f.typeOf(bin_op.lhs);
6270 const operand_cty = try f.typeToCType(operand_ty, .complete);6216 const operand_ctype = try f.ctypeFromType(operand_ty, .complete);
6271 const is_big = operand_cty.tag() == .array;6217 const is_big = operand_ctype.info(&f.object.dg.ctype_pool) == .array;
62726218
6273 const lhs = try f.resolveInst(bin_op.lhs);6219 const lhs = try f.resolveInst(bin_op.lhs);
6274 const rhs = try f.resolveInst(bin_op.rhs);6220 const rhs = try f.resolveInst(bin_op.rhs);
...@@ -6278,8 +6224,8 @@ fn airBinBuiltinCall(...@@ -6278,8 +6224,8 @@ fn airBinBuiltinCall(
6278 const inst_scalar_ty = inst_ty.scalarType(zcu);6224 const inst_scalar_ty = inst_ty.scalarType(zcu);
6279 const scalar_ty = operand_ty.scalarType(zcu);6225 const scalar_ty = operand_ty.scalarType(zcu);
62806226
6281 const inst_scalar_cty = try f.typeToCType(inst_scalar_ty, .complete);6227 const inst_scalar_ctype = try f.ctypeFromType(inst_scalar_ty, .complete);
6282 const ref_ret = inst_scalar_cty.tag() == .array;6228 const ref_ret = inst_scalar_ctype.info(&f.object.dg.ctype_pool) == .array;
62836229
6284 const writer = f.object.writer();6230 const writer = f.object.writer();
6285 const local = try f.allocLocal(inst, inst_ty);6231 const local = try f.allocLocal(inst, inst_ty);
...@@ -6328,8 +6274,8 @@ fn airCmpBuiltinCall(...@@ -6328,8 +6274,8 @@ fn airCmpBuiltinCall(
6328 const operand_ty = f.typeOf(data.lhs);6274 const operand_ty = f.typeOf(data.lhs);
6329 const scalar_ty = operand_ty.scalarType(zcu);6275 const scalar_ty = operand_ty.scalarType(zcu);
63306276
6331 const inst_scalar_cty = try f.typeToCType(inst_scalar_ty, .complete);6277 const inst_scalar_ctype = try f.ctypeFromType(inst_scalar_ty, .complete);
6332 const ref_ret = inst_scalar_cty.tag() == .array;6278 const ref_ret = inst_scalar_ctype.info(&f.object.dg.ctype_pool) == .array;
63336279
6334 const writer = f.object.writer();6280 const writer = f.object.writer();
6335 const local = try f.allocLocal(inst, inst_ty);6281 const local = try f.allocLocal(inst, inst_ty);
...@@ -7112,9 +7058,9 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -7112,9 +7058,9 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {
71127058
7113 const writer = f.object.writer();7059 const writer = f.object.writer();
7114 const local = try f.allocLocal(inst, inst_ty);7060 const local = try f.allocLocal(inst, inst_ty);
7115 switch (inst_ty.zigTypeTag(zcu)) {7061 switch (ip.indexToKey(inst_ty.toIntern())) {
7116 .Array, .Vector => {7062 inline .array_type, .vector_type => |info, tag| {
7117 const a = try Assignment.init(f, inst_ty.childType(zcu));7063 const a = try Assignment.init(f, Type.fromInterned(info.child));
7118 for (resolved_elements, 0..) |element, i| {7064 for (resolved_elements, 0..) |element, i| {
7119 try a.restart(f, writer);7065 try a.restart(f, writer);
7120 try f.writeCValue(writer, local, .Other);7066 try f.writeCValue(writer, local, .Other);
...@@ -7123,94 +7069,112 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -7123,94 +7069,112 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {
7123 try f.writeCValue(writer, element, .Other);7069 try f.writeCValue(writer, element, .Other);
7124 try a.end(f, writer);7070 try a.end(f, writer);
7125 }7071 }
7126 if (inst_ty.sentinel(zcu)) |sentinel| {7072 if (tag == .array_type and info.sentinel != .none) {
7127 try a.restart(f, writer);7073 try a.restart(f, writer);
7128 try f.writeCValue(writer, local, .Other);7074 try f.writeCValue(writer, local, .Other);
7129 try writer.print("[{d}]", .{resolved_elements.len});7075 try writer.print("[{d}]", .{info.len});
7130 try a.assign(f, writer);7076 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);
7132 try a.end(f, writer);7078 try a.end(f, writer);
7133 }7079 }
7134 },7080 },
7135 .Struct => switch (inst_ty.containerLayout(zcu)) {7081 .struct_type => {
7136 .auto, .@"extern" => for (resolved_elements, 0..) |element, field_index| {7082 const loaded_struct = ip.loadStructType(inst_ty.toIntern());
7137 if (inst_ty.structFieldIsComptime(field_index, zcu)) continue;7083 switch (loaded_struct.layout) {
7138 const field_ty = inst_ty.structFieldType(field_index, zcu);7084 .auto, .@"extern" => {
7139 if (!field_ty.hasRuntimeBitsIgnoreComptime(zcu)) continue;7085 var field_it = loaded_struct.iterateRuntimeOrder(ip);
71407086 while (field_it.next()) |field_index| {
7141 const a = try Assignment.start(f, writer, field_ty);7087 const field_ty = Type.fromInterned(loaded_struct.field_types.get(ip)[field_index]);
7142 try f.writeCValueMember(writer, local, if (inst_ty.isSimpleTuple(zcu))7088 if (!field_ty.hasRuntimeBitsIgnoreComptime(zcu)) continue;
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);
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;7107 var bit_offset: u64 = 0;
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;
71647108
7165 if (!empty) {7109 var empty = true;
7166 try writer.writeAll("zig_or_");7110 for (0..elements.len) |field_index| {
7167 try f.object.dg.renderTypeForBuiltinFnName(writer, inst_ty);7111 if (inst_ty.structFieldIsComptime(field_index, zcu)) continue;
7168 try writer.writeByte('(');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;
7169 }7121 }
7170 empty = false;7122 empty = true;
7171 }7123 for (resolved_elements, 0..) |element, field_index| {
7172 empty = true;7124 if (inst_ty.structFieldIsComptime(field_index, zcu)) continue;
7173 for (resolved_elements, 0..) |element, field_index| {7125 const field_ty = inst_ty.structFieldType(field_index, zcu);
7174 if (inst_ty.structFieldIsComptime(field_index, zcu)) continue;7126 if (!field_ty.hasRuntimeBitsIgnoreComptime(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('(');
71837127
7184 if (inst_ty.isAbiInt(zcu) and (field_ty.isAbiInt(zcu) or field_ty.isPtrAtRuntime(zcu))) {7128 if (!empty) try writer.writeAll(", ");
7185 try f.renderIntCast(writer, inst_ty, element, .{}, field_ty, .FunctionArgument);7129 // TODO: Skip this entire shift if val is 0?
7186 } else {7130 try writer.writeAll("zig_shlw_");
7131 try f.object.dg.renderTypeForBuiltinFnName(writer, inst_ty);
7187 try writer.writeByte('(');7132 try writer.writeByte('(');
7188 try f.renderType(writer, inst_ty);7133
7189 try writer.writeByte(')');7134 if (inst_ty.isAbiInt(zcu) and (field_ty.isAbiInt(zcu) or field_ty.isPtrAtRuntime(zcu))) {
7190 if (field_ty.isPtrAtRuntime(zcu)) {7135 try f.renderIntCast(writer, inst_ty, element, .{}, field_ty, .FunctionArgument);
7136 } else {
7191 try writer.writeByte('(');7137 try writer.writeByte('(');
7192 try f.renderType(writer, switch (int_info.signedness) {7138 try f.renderType(writer, inst_ty);
7193 .unsigned => Type.usize,
7194 .signed => Type.isize,
7195 });
7196 try writer.writeByte(')');7139 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);
7197 }7149 }
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);7151 try writer.print(", {}", .{
7209 empty = false;7152 try f.fmtIntLiteral(try zcu.intValue(bit_offset_ty, bit_offset)),
7210 }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");7158 bit_offset += field_ty.bitSize(zcu);
7213 },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);
7214 },7178 },
7215 else => unreachable,7179 else => unreachable,
7216 }7180 }
...@@ -7225,15 +7189,15 @@ fn airUnionInit(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -7225,15 +7189,15 @@ fn airUnionInit(f: *Function, inst: Air.Inst.Index) !CValue {
7225 const extra = f.air.extraData(Air.UnionInit, ty_pl.payload).data;7189 const extra = f.air.extraData(Air.UnionInit, ty_pl.payload).data;
72267190
7227 const union_ty = f.typeOfIndex(inst);7191 const union_ty = f.typeOfIndex(inst);
7228 const union_obj = zcu.typeToUnion(union_ty).?;7192 const loaded_union = ip.loadUnionType(union_ty.toIntern());
7229 const field_name = union_obj.loadTagType(ip).names.get(ip)[extra.field_index];7193 const field_name = loaded_union.loadTagType(ip).names.get(ip)[extra.field_index];
7230 const payload_ty = f.typeOf(extra.init);7194 const payload_ty = f.typeOf(extra.init);
7231 const payload = try f.resolveInst(extra.init);7195 const payload = try f.resolveInst(extra.init);
7232 try reap(f, inst, &.{extra.init});7196 try reap(f, inst, &.{extra.init});
72337197
7234 const writer = f.object.writer();7198 const writer = f.object.writer();
7235 const local = try f.allocLocal(inst, union_ty);7199 const local = try f.allocLocal(inst, union_ty);
7236 if (union_obj.getLayout(ip) == .@"packed") {7200 if (loaded_union.getLayout(ip) == .@"packed") {
7237 try f.writeCValue(writer, local, .Other);7201 try f.writeCValue(writer, local, .Other);
7238 try writer.writeAll(" = ");7202 try writer.writeAll(" = ");
7239 try f.writeCValue(writer, payload, .Initializer);7203 try f.writeCValue(writer, payload, .Initializer);
...@@ -7465,16 +7429,16 @@ fn airCVaStart(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -7465,16 +7429,16 @@ fn airCVaStart(f: *Function, inst: Air.Inst.Index) !CValue {
7465 const inst_ty = f.typeOfIndex(inst);7429 const inst_ty = f.typeOfIndex(inst);
7466 const decl_index = f.object.dg.pass.decl;7430 const decl_index = f.object.dg.pass.decl;
7467 const decl = zcu.declPtr(decl_index);7431 const decl = zcu.declPtr(decl_index);
7468 const fn_cty = try f.typeToCType(decl.typeOf(zcu), .complete);7432 const function_ctype = try f.ctypeFromType(decl.typeOf(zcu), .complete);
7469 const param_len = fn_cty.castTag(.varargs_function).?.data.param_types.len;7433 const params_len = function_ctype.info(&f.object.dg.ctype_pool).function.param_ctypes.len;
74707434
7471 const writer = f.object.writer();7435 const writer = f.object.writer();
7472 const local = try f.allocLocal(inst, inst_ty);7436 const local = try f.allocLocal(inst, inst_ty);
7473 try writer.writeAll("va_start(*(va_list *)&");7437 try writer.writeAll("va_start(*(va_list *)&");
7474 try f.writeCValue(writer, local, .Other);7438 try f.writeCValue(writer, local, .Other);
7475 if (param_len > 0) {7439 if (params_len > 0) {
7476 try writer.writeAll(", ");7440 try writer.writeAll(", ");
7477 try f.writeCValue(writer, .{ .arg = param_len - 1 }, .FunctionArgument);7441 try f.writeCValue(writer, .{ .arg = params_len - 1 }, .FunctionArgument);
7478 }7442 }
7479 try writer.writeAll(");\n");7443 try writer.writeAll(");\n");
7480 return local;7444 return local;
...@@ -7823,7 +7787,7 @@ const FormatIntLiteralContext = struct {...@@ -7823,7 +7787,7 @@ const FormatIntLiteralContext = struct {
7823 dg: *DeclGen,7787 dg: *DeclGen,
7824 int_info: InternPool.Key.IntType,7788 int_info: InternPool.Key.IntType,
7825 kind: CType.Kind,7789 kind: CType.Kind,
7826 cty: CType,7790 ctype: CType,
7827 val: Value,7791 val: Value,
7828};7792};
7829fn formatIntLiteral(7793fn formatIntLiteral(
...@@ -7834,6 +7798,7 @@ fn formatIntLiteral(...@@ -7834,6 +7798,7 @@ fn formatIntLiteral(
7834) @TypeOf(writer).Error!void {7798) @TypeOf(writer).Error!void {
7835 const zcu = data.dg.zcu;7799 const zcu = data.dg.zcu;
7836 const target = &data.dg.mod.resolved_target.result;7800 const target = &data.dg.mod.resolved_target.result;
7801 const ctype_pool = &data.dg.ctype_pool;
78377802
7838 const ExpectedContents = struct {7803 const ExpectedContents = struct {
7839 const base = 10;7804 const base = 10;
...@@ -7867,7 +7832,7 @@ fn formatIntLiteral(...@@ -7867,7 +7832,7 @@ fn formatIntLiteral(
7867 } else data.val.toBigInt(&int_buf, zcu);7832 } else data.val.toBigInt(&int_buf, zcu);
7868 assert(int.fitsInTwosComp(data.int_info.signedness, data.int_info.bits));7833 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);
7871 var one_limbs: [BigInt.calcLimbLen(1)]BigIntLimb = undefined;7836 var one_limbs: [BigInt.calcLimbLen(1)]BigIntLimb = undefined;
7872 const one = BigInt.Mutable.init(&one_limbs, 1).toConst();7837 const one = BigInt.Mutable.init(&one_limbs, 1).toConst();
78737838
...@@ -7879,45 +7844,45 @@ fn formatIntLiteral(...@@ -7879,45 +7844,45 @@ fn formatIntLiteral(
7879 defer allocator.free(wrap.limbs);7844 defer allocator.free(wrap.limbs);
78807845
7881 const c_limb_info: struct {7846 const c_limb_info: struct {
7882 cty: CType,7847 ctype: CType,
7883 count: usize,7848 count: usize,
7884 endian: std.builtin.Endian,7849 endian: std.builtin.Endian,
7885 homogeneous: bool,7850 homogeneous: bool,
7886 } = switch (data.cty.tag()) {7851 } = switch (data.ctype.info(ctype_pool)) {
7887 else => .{7852 .basic => |basic_info| switch (basic_info) {
7888 .cty = CType.initTag(.void),7853 else => .{
7889 .count = 1,7854 .ctype = .{ .index = .void },
7890 .endian = .little,7855 .count = 1,
7891 .homogeneous = true,7856 .endian = .little,
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(),
7905 .homogeneous = true,7857 .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,
7907 },7871 },
7872 else => unreachable,
7908 };7873 };
7909 if (c_limb_info.count == 1) {7874 if (c_limb_info.count == 1) {
7910 if (wrap.addWrap(int, one, data.int_info.signedness, c_bits) or7875 if (wrap.addWrap(int, one, data.int_info.signedness, c_bits) or
7911 data.int_info.signedness == .signed and wrap.subWrap(int, one, data.int_info.signedness, c_bits))7876 data.int_info.signedness == .signed and wrap.subWrap(int, one, data.int_info.signedness, c_bits))
7912 return writer.print("{s}_{s}", .{7877 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}", .{
7914 if (int.positive) "max" else "min", signAbbrev(data.int_info.signedness), c_bits,7879 if (int.positive) "max" else "min", signAbbrev(data.int_info.signedness), c_bits,
7915 }),7880 }),
7916 if (int.positive) "MAX" else "MIN",7881 if (int.positive) "MAX" else "MIN",
7917 });7882 });
79187883
7919 if (!int.positive) try writer.writeByte('-');7884 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
7922 const style: struct { base: u8, case: std.fmt.Case = undefined } = switch (fmt.len) {7887 const style: struct { base: u8, case: std.fmt.Case = undefined } = switch (fmt.len) {
7923 0 => .{ .base = 10 },7888 0 => .{ .base = 10 },
...@@ -7948,7 +7913,7 @@ fn formatIntLiteral(...@@ -7948,7 +7913,7 @@ fn formatIntLiteral(
7948 defer allocator.free(string);7913 defer allocator.free(string);
7949 try writer.writeAll(string);7914 try writer.writeAll(string);
7950 } else {7915 } else {
7951 try data.cty.renderLiteralPrefix(writer, data.kind);7916 try data.ctype.renderLiteralPrefix(writer, data.kind, ctype_pool);
7952 wrap.convertToTwosComplement(int, data.int_info.signedness, c_bits);7917 wrap.convertToTwosComplement(int, data.int_info.signedness, c_bits);
7953 @memset(wrap.limbs[wrap.len..], 0);7918 @memset(wrap.limbs[wrap.len..], 0);
7954 wrap.len = wrap.limbs.len;7919 wrap.len = wrap.limbs.len;
...@@ -7958,7 +7923,7 @@ fn formatIntLiteral(...@@ -7958,7 +7923,7 @@ fn formatIntLiteral(
7958 .signedness = undefined,7923 .signedness = undefined,
7959 .bits = @as(u16, @intCast(@divExact(c_bits, c_limb_info.count))),7924 .bits = @as(u16, @intCast(@divExact(c_bits, c_limb_info.count))),
7960 };7925 };
7961 var c_limb_cty: CType = undefined;7926 var c_limb_ctype: CType = undefined;
79627927
7963 var limb_offset: usize = 0;7928 var limb_offset: usize = 0;
7964 const most_significant_limb_i = wrap.len - limbs_per_c_limb;7929 const most_significant_limb_i = wrap.len - limbs_per_c_limb;
...@@ -7979,7 +7944,7 @@ fn formatIntLiteral(...@@ -7979,7 +7944,7 @@ fn formatIntLiteral(
7979 {7944 {
7980 // most significant limb is actually signed7945 // most significant limb is actually signed
7981 c_limb_int_info.signedness = .signed;7946 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
7984 c_limb_mut.positive = wrap.positive;7949 c_limb_mut.positive = wrap.positive;
7985 c_limb_mut.truncate(7950 c_limb_mut.truncate(
...@@ -7989,7 +7954,7 @@ fn formatIntLiteral(...@@ -7989,7 +7954,7 @@ fn formatIntLiteral(
7989 );7954 );
7990 } else {7955 } else {
7991 c_limb_int_info.signedness = .unsigned;7956 c_limb_int_info.signedness = .unsigned;
7992 c_limb_cty = c_limb_info.cty;7957 c_limb_ctype = c_limb_info.ctype;
7993 }7958 }
79947959
7995 if (limb_offset > 0) try writer.writeAll(", ");7960 if (limb_offset > 0) try writer.writeAll(", ");
...@@ -7997,12 +7962,12 @@ fn formatIntLiteral(...@@ -7997,12 +7962,12 @@ fn formatIntLiteral(
7997 .dg = data.dg,7962 .dg = data.dg,
7998 .int_info = c_limb_int_info,7963 .int_info = c_limb_int_info,
7999 .kind = data.kind,7964 .kind = data.kind,
8000 .cty = c_limb_cty,7965 .ctype = c_limb_ctype,
8001 .val = try zcu.intValue_big(Type.comptime_int, c_limb_mut.toConst()),7966 .val = try zcu.intValue_big(Type.comptime_int, c_limb_mut.toConst()),
8002 }, fmt, options, writer);7967 }, fmt, options, writer);
8003 }7968 }
8004 }7969 }
8005 try data.cty.renderLiteralSuffix(writer);7970 try data.ctype.renderLiteralSuffix(writer, ctype_pool);
8006}7971}
80077972
8008const Materialize = struct {7973const Materialize = struct {
...@@ -8045,10 +8010,10 @@ const Materialize = struct {...@@ -8045,10 +8010,10 @@ const Materialize = struct {
8045};8010};
80468011
8047const Assignment = struct {8012const Assignment = struct {
8048 cty: CType.Index,8013 ctype: CType,
80498014
8050 pub fn init(f: *Function, ty: Type) !Assignment {8015 pub fn init(f: *Function, ty: Type) !Assignment {
8051 return .{ .cty = try f.typeToIndex(ty, .complete) };8016 return .{ .ctype = try f.ctypeFromType(ty, .complete) };
8052 }8017 }
80538018
8054 pub fn start(f: *Function, writer: anytype, ty: Type) !Assignment {8019 pub fn start(f: *Function, writer: anytype, ty: Type) !Assignment {
...@@ -8076,7 +8041,7 @@ const Assignment = struct {...@@ -8076,7 +8041,7 @@ const Assignment = struct {
8076 .assign => {},8041 .assign => {},
8077 .memcpy => {8042 .memcpy => {
8078 try writer.writeAll(", sizeof(");8043 try writer.writeAll(", sizeof(");
8079 try f.renderCType(writer, self.cty);8044 try f.renderCType(writer, self.ctype);
8080 try writer.writeAll("))");8045 try writer.writeAll("))");
8081 },8046 },
8082 }8047 }
...@@ -8084,7 +8049,7 @@ const Assignment = struct {...@@ -8084,7 +8049,7 @@ const Assignment = struct {
8084 }8049 }
80858050
8086 fn strategy(self: Assignment, f: *Function) enum { assign, memcpy } {8051 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)) {
8088 else => .assign,8053 else => .assign,
8089 .array, .vector => .memcpy,8054 .array, .vector => .memcpy,
8090 };8055 };
...@@ -8129,28 +8094,6 @@ const Vectorize = struct {...@@ -8129,28 +8094,6 @@ const Vectorize = struct {
8129 }8094 }
8130};8095};
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
8154fn lowersToArray(ty: Type, zcu: *Zcu) bool {8097fn lowersToArray(ty: Type, zcu: *Zcu) bool {
8155 return switch (ty.zigTypeTag(zcu)) {8098 return switch (ty.zigTypeTag(zcu)) {
8156 .Array, .Vector => return true,8099 .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 {...@@ -2033,7 +2033,7 @@ pub const Object = struct {
2033 owner_decl.src_node + 1, // Line2033 owner_decl.src_node + 1, // Line
2034 try o.lowerDebugType(int_ty),2034 try o.lowerDebugType(int_ty),
2035 ty.abiSize(mod) * 8,2035 ty.abiSize(mod) * 8,
2036 ty.abiAlignment(mod).toByteUnits(0) * 8,2036 (ty.abiAlignment(mod).toByteUnits() orelse 0) * 8,
2037 try o.builder.debugTuple(enumerators),2037 try o.builder.debugTuple(enumerators),
2038 );2038 );
20392039
...@@ -2120,7 +2120,7 @@ pub const Object = struct {...@@ -2120,7 +2120,7 @@ pub const Object = struct {
2120 0, // Line2120 0, // Line
2121 try o.lowerDebugType(ptr_ty),2121 try o.lowerDebugType(ptr_ty),
2122 ptr_size * 8,2122 ptr_size * 8,
2123 ptr_align.toByteUnits(0) * 8,2123 (ptr_align.toByteUnits() orelse 0) * 8,
2124 0, // Offset2124 0, // Offset
2125 );2125 );
21262126
...@@ -2131,7 +2131,7 @@ pub const Object = struct {...@@ -2131,7 +2131,7 @@ pub const Object = struct {
2131 0, // Line2131 0, // Line
2132 try o.lowerDebugType(len_ty),2132 try o.lowerDebugType(len_ty),
2133 len_size * 8,2133 len_size * 8,
2134 len_align.toByteUnits(0) * 8,2134 (len_align.toByteUnits() orelse 0) * 8,
2135 len_offset * 8,2135 len_offset * 8,
2136 );2136 );
21372137
...@@ -2142,7 +2142,7 @@ pub const Object = struct {...@@ -2142,7 +2142,7 @@ pub const Object = struct {
2142 line,2142 line,
2143 .none, // Underlying type2143 .none, // Underlying type
2144 ty.abiSize(mod) * 8,2144 ty.abiSize(mod) * 8,
2145 ty.abiAlignment(mod).toByteUnits(0) * 8,2145 (ty.abiAlignment(mod).toByteUnits() orelse 0) * 8,
2146 try o.builder.debugTuple(&.{2146 try o.builder.debugTuple(&.{
2147 debug_ptr_type,2147 debug_ptr_type,
2148 debug_len_type,2148 debug_len_type,
...@@ -2170,7 +2170,7 @@ pub const Object = struct {...@@ -2170,7 +2170,7 @@ pub const Object = struct {
2170 0, // Line2170 0, // Line
2171 debug_elem_ty,2171 debug_elem_ty,
2172 target.ptrBitWidth(),2172 target.ptrBitWidth(),
2173 ty.ptrAlignment(mod).toByteUnits(0) * 8,2173 (ty.ptrAlignment(mod).toByteUnits() orelse 0) * 8,
2174 0, // Offset2174 0, // Offset
2175 );2175 );
21762176
...@@ -2217,7 +2217,7 @@ pub const Object = struct {...@@ -2217,7 +2217,7 @@ pub const Object = struct {
2217 0, // Line2217 0, // Line
2218 try o.lowerDebugType(ty.childType(mod)),2218 try o.lowerDebugType(ty.childType(mod)),
2219 ty.abiSize(mod) * 8,2219 ty.abiSize(mod) * 8,
2220 ty.abiAlignment(mod).toByteUnits(0) * 8,2220 (ty.abiAlignment(mod).toByteUnits() orelse 0) * 8,
2221 try o.builder.debugTuple(&.{2221 try o.builder.debugTuple(&.{
2222 try o.builder.debugSubrange(2222 try o.builder.debugSubrange(
2223 try o.builder.debugConstant(try o.builder.intConst(.i64, 0)),2223 try o.builder.debugConstant(try o.builder.intConst(.i64, 0)),
...@@ -2260,7 +2260,7 @@ pub const Object = struct {...@@ -2260,7 +2260,7 @@ pub const Object = struct {
2260 0, // Line2260 0, // Line
2261 debug_elem_type,2261 debug_elem_type,
2262 ty.abiSize(mod) * 8,2262 ty.abiSize(mod) * 8,
2263 ty.abiAlignment(mod).toByteUnits(0) * 8,2263 (ty.abiAlignment(mod).toByteUnits() orelse 0) * 8,
2264 try o.builder.debugTuple(&.{2264 try o.builder.debugTuple(&.{
2265 try o.builder.debugSubrange(2265 try o.builder.debugSubrange(
2266 try o.builder.debugConstant(try o.builder.intConst(.i64, 0)),2266 try o.builder.debugConstant(try o.builder.intConst(.i64, 0)),
...@@ -2316,7 +2316,7 @@ pub const Object = struct {...@@ -2316,7 +2316,7 @@ pub const Object = struct {
2316 0, // Line2316 0, // Line
2317 try o.lowerDebugType(child_ty),2317 try o.lowerDebugType(child_ty),
2318 payload_size * 8,2318 payload_size * 8,
2319 payload_align.toByteUnits(0) * 8,2319 (payload_align.toByteUnits() orelse 0) * 8,
2320 0, // Offset2320 0, // Offset
2321 );2321 );
23222322
...@@ -2327,7 +2327,7 @@ pub const Object = struct {...@@ -2327,7 +2327,7 @@ pub const Object = struct {
2327 0,2327 0,
2328 try o.lowerDebugType(non_null_ty),2328 try o.lowerDebugType(non_null_ty),
2329 non_null_size * 8,2329 non_null_size * 8,
2330 non_null_align.toByteUnits(0) * 8,2330 (non_null_align.toByteUnits() orelse 0) * 8,
2331 non_null_offset * 8,2331 non_null_offset * 8,
2332 );2332 );
23332333
...@@ -2338,7 +2338,7 @@ pub const Object = struct {...@@ -2338,7 +2338,7 @@ pub const Object = struct {
2338 0, // Line2338 0, // Line
2339 .none, // Underlying type2339 .none, // Underlying type
2340 ty.abiSize(mod) * 8,2340 ty.abiSize(mod) * 8,
2341 ty.abiAlignment(mod).toByteUnits(0) * 8,2341 (ty.abiAlignment(mod).toByteUnits() orelse 0) * 8,
2342 try o.builder.debugTuple(&.{2342 try o.builder.debugTuple(&.{
2343 debug_data_type,2343 debug_data_type,
2344 debug_some_type,2344 debug_some_type,
...@@ -2396,7 +2396,7 @@ pub const Object = struct {...@@ -2396,7 +2396,7 @@ pub const Object = struct {
2396 0, // Line2396 0, // Line
2397 try o.lowerDebugType(Type.anyerror),2397 try o.lowerDebugType(Type.anyerror),
2398 error_size * 8,2398 error_size * 8,
2399 error_align.toByteUnits(0) * 8,2399 (error_align.toByteUnits() orelse 0) * 8,
2400 error_offset * 8,2400 error_offset * 8,
2401 );2401 );
2402 fields[payload_index] = try o.builder.debugMemberType(2402 fields[payload_index] = try o.builder.debugMemberType(
...@@ -2406,7 +2406,7 @@ pub const Object = struct {...@@ -2406,7 +2406,7 @@ pub const Object = struct {
2406 0, // Line2406 0, // Line
2407 try o.lowerDebugType(payload_ty),2407 try o.lowerDebugType(payload_ty),
2408 payload_size * 8,2408 payload_size * 8,
2409 payload_align.toByteUnits(0) * 8,2409 (payload_align.toByteUnits() orelse 0) * 8,
2410 payload_offset * 8,2410 payload_offset * 8,
2411 );2411 );
24122412
...@@ -2417,7 +2417,7 @@ pub const Object = struct {...@@ -2417,7 +2417,7 @@ pub const Object = struct {
2417 0, // Line2417 0, // Line
2418 .none, // Underlying type2418 .none, // Underlying type
2419 ty.abiSize(mod) * 8,2419 ty.abiSize(mod) * 8,
2420 ty.abiAlignment(mod).toByteUnits(0) * 8,2420 (ty.abiAlignment(mod).toByteUnits() orelse 0) * 8,
2421 try o.builder.debugTuple(&fields),2421 try o.builder.debugTuple(&fields),
2422 );2422 );
24232423
...@@ -2485,7 +2485,7 @@ pub const Object = struct {...@@ -2485,7 +2485,7 @@ pub const Object = struct {
2485 0,2485 0,
2486 try o.lowerDebugType(Type.fromInterned(field_ty)),2486 try o.lowerDebugType(Type.fromInterned(field_ty)),
2487 field_size * 8,2487 field_size * 8,
2488 field_align.toByteUnits(0) * 8,2488 (field_align.toByteUnits() orelse 0) * 8,
2489 field_offset * 8,2489 field_offset * 8,
2490 ));2490 ));
2491 }2491 }
...@@ -2497,7 +2497,7 @@ pub const Object = struct {...@@ -2497,7 +2497,7 @@ pub const Object = struct {
2497 0, // Line2497 0, // Line
2498 .none, // Underlying type2498 .none, // Underlying type
2499 ty.abiSize(mod) * 8,2499 ty.abiSize(mod) * 8,
2500 ty.abiAlignment(mod).toByteUnits(0) * 8,2500 (ty.abiAlignment(mod).toByteUnits() orelse 0) * 8,
2501 try o.builder.debugTuple(fields.items),2501 try o.builder.debugTuple(fields.items),
2502 );2502 );
25032503
...@@ -2566,7 +2566,7 @@ pub const Object = struct {...@@ -2566,7 +2566,7 @@ pub const Object = struct {
2566 0, // Line2566 0, // Line
2567 try o.lowerDebugType(field_ty),2567 try o.lowerDebugType(field_ty),
2568 field_size * 8,2568 field_size * 8,
2569 field_align.toByteUnits(0) * 8,2569 (field_align.toByteUnits() orelse 0) * 8,
2570 field_offset * 8,2570 field_offset * 8,
2571 ));2571 ));
2572 }2572 }
...@@ -2578,7 +2578,7 @@ pub const Object = struct {...@@ -2578,7 +2578,7 @@ pub const Object = struct {
2578 0, // Line2578 0, // Line
2579 .none, // Underlying type2579 .none, // Underlying type
2580 ty.abiSize(mod) * 8,2580 ty.abiSize(mod) * 8,
2581 ty.abiAlignment(mod).toByteUnits(0) * 8,2581 (ty.abiAlignment(mod).toByteUnits() orelse 0) * 8,
2582 try o.builder.debugTuple(fields.items),2582 try o.builder.debugTuple(fields.items),
2583 );2583 );
25842584
...@@ -2621,7 +2621,7 @@ pub const Object = struct {...@@ -2621,7 +2621,7 @@ pub const Object = struct {
2621 0, // Line2621 0, // Line
2622 .none, // Underlying type2622 .none, // Underlying type
2623 ty.abiSize(mod) * 8,2623 ty.abiSize(mod) * 8,
2624 ty.abiAlignment(mod).toByteUnits(0) * 8,2624 (ty.abiAlignment(mod).toByteUnits() orelse 0) * 8,
2625 try o.builder.debugTuple(2625 try o.builder.debugTuple(
2626 &.{try o.lowerDebugType(Type.fromInterned(union_type.enum_tag_ty))},2626 &.{try o.lowerDebugType(Type.fromInterned(union_type.enum_tag_ty))},
2627 ),2627 ),
...@@ -2661,7 +2661,7 @@ pub const Object = struct {...@@ -2661,7 +2661,7 @@ pub const Object = struct {
2661 0, // Line2661 0, // Line
2662 try o.lowerDebugType(Type.fromInterned(field_ty)),2662 try o.lowerDebugType(Type.fromInterned(field_ty)),
2663 field_size * 8,2663 field_size * 8,
2664 field_align.toByteUnits(0) * 8,2664 (field_align.toByteUnits() orelse 0) * 8,
2665 0, // Offset2665 0, // Offset
2666 ));2666 ));
2667 }2667 }
...@@ -2680,7 +2680,7 @@ pub const Object = struct {...@@ -2680,7 +2680,7 @@ pub const Object = struct {
2680 0, // Line2680 0, // Line
2681 .none, // Underlying type2681 .none, // Underlying type
2682 ty.abiSize(mod) * 8,2682 ty.abiSize(mod) * 8,
2683 ty.abiAlignment(mod).toByteUnits(0) * 8,2683 (ty.abiAlignment(mod).toByteUnits() orelse 0) * 8,
2684 try o.builder.debugTuple(fields.items),2684 try o.builder.debugTuple(fields.items),
2685 );2685 );
26862686
...@@ -2711,7 +2711,7 @@ pub const Object = struct {...@@ -2711,7 +2711,7 @@ pub const Object = struct {
2711 0, // Line2711 0, // Line
2712 try o.lowerDebugType(Type.fromInterned(union_type.enum_tag_ty)),2712 try o.lowerDebugType(Type.fromInterned(union_type.enum_tag_ty)),
2713 layout.tag_size * 8,2713 layout.tag_size * 8,
2714 layout.tag_align.toByteUnits(0) * 8,2714 (layout.tag_align.toByteUnits() orelse 0) * 8,
2715 tag_offset * 8,2715 tag_offset * 8,
2716 );2716 );
27172717
...@@ -2722,7 +2722,7 @@ pub const Object = struct {...@@ -2722,7 +2722,7 @@ pub const Object = struct {
2722 0, // Line2722 0, // Line
2723 debug_union_type,2723 debug_union_type,
2724 layout.payload_size * 8,2724 layout.payload_size * 8,
2725 layout.payload_align.toByteUnits(0) * 8,2725 (layout.payload_align.toByteUnits() orelse 0) * 8,
2726 payload_offset * 8,2726 payload_offset * 8,
2727 );2727 );
27282728
...@@ -2739,7 +2739,7 @@ pub const Object = struct {...@@ -2739,7 +2739,7 @@ pub const Object = struct {
2739 0, // Line2739 0, // Line
2740 .none, // Underlying type2740 .none, // Underlying type
2741 ty.abiSize(mod) * 8,2741 ty.abiSize(mod) * 8,
2742 ty.abiAlignment(mod).toByteUnits(0) * 8,2742 (ty.abiAlignment(mod).toByteUnits() orelse 0) * 8,
2743 try o.builder.debugTuple(&full_fields),2743 try o.builder.debugTuple(&full_fields),
2744 );2744 );
27452745
...@@ -4473,7 +4473,7 @@ pub const Object = struct {...@@ -4473,7 +4473,7 @@ pub const Object = struct {
4473 // The value cannot be undefined, because we use the `nonnull` annotation4473 // The value cannot be undefined, because we use the `nonnull` annotation
4474 // for non-optional pointers. We also need to respect the alignment, even though4474 // for non-optional pointers. We also need to respect the alignment, even though
4475 // the address will never be dereferenced.4475 // the address will never be dereferenced.
4476 const int: u64 = ptr_ty.ptrInfo(mod).flags.alignment.toByteUnitsOptional() orelse4476 const int: u64 = ptr_ty.ptrInfo(mod).flags.alignment.toByteUnits() orelse
4477 // Note that these 0xaa values are appropriate even in release-optimized builds4477 // Note that these 0xaa values are appropriate even in release-optimized builds
4478 // because we need a well-defined value that is not null, and LLVM does not4478 // because we need a well-defined value that is not null, and LLVM does not
4479 // have an "undef_but_not_null" attribute. As an example, if this `alloc` AIR4479 // 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 {...@@ -172,7 +172,7 @@ pub fn attachSegfaultHandler() void {
172 };172 };
173}173}
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 {
176 // TODO: use alarm() here to prevent infinite loops176 // TODO: use alarm() here to prevent infinite loops
177 PanicSwitch.preDispatch();177 PanicSwitch.preDispatch();
178178
src/link/C.zig+98-123
...@@ -69,13 +69,13 @@ pub const DeclBlock = struct {...@@ -69,13 +69,13 @@ pub const DeclBlock = struct {
69 fwd_decl: String = String.empty,69 fwd_decl: String = String.empty,
70 /// Each `Decl` stores a set of used `CType`s. In `flush()`, we iterate70 /// Each `Decl` stores a set of used `CType`s. In `flush()`, we iterate
71 /// over each `Decl` and generate the definition for each used `CType` once.71 /// over each `Decl` and generate the definition for each used `CType` once.
72 ctypes: codegen.CType.Store = .{},72 ctype_pool: codegen.CType.Pool = codegen.CType.Pool.empty,
73 /// Key and Value storage use the ctype arena.73 /// May contain string references to ctype_pool
74 lazy_fns: codegen.LazyFnMap = .{},74 lazy_fns: codegen.LazyFnMap = .{},
7575
76 fn deinit(db: *DeclBlock, gpa: Allocator) void {76 fn deinit(db: *DeclBlock, gpa: Allocator) void {
77 db.lazy_fns.deinit(gpa);77 db.lazy_fns.deinit(gpa);
78 db.ctypes.deinit(gpa);78 db.ctype_pool.deinit(gpa);
79 db.* = undefined;79 db.* = undefined;
80 }80 }
81};81};
...@@ -190,11 +190,12 @@ pub fn updateFunc(...@@ -190,11 +190,12 @@ pub fn updateFunc(
190 const decl = zcu.declPtr(decl_index);190 const decl = zcu.declPtr(decl_index);
191 const gop = try self.decl_table.getOrPut(gpa, decl_index);191 const gop = try self.decl_table.getOrPut(gpa, decl_index);
192 if (!gop.found_existing) gop.value_ptr.* = .{};192 if (!gop.found_existing) gop.value_ptr.* = .{};
193 const ctypes = &gop.value_ptr.ctypes;193 const ctype_pool = &gop.value_ptr.ctype_pool;
194 const lazy_fns = &gop.value_ptr.lazy_fns;194 const lazy_fns = &gop.value_ptr.lazy_fns;
195 const fwd_decl = &self.fwd_decl_buf;195 const fwd_decl = &self.fwd_decl_buf;
196 const code = &self.code_buf;196 const code = &self.code_buf;
197 ctypes.clearRetainingCapacity(gpa);197 try ctype_pool.init(gpa);
198 ctype_pool.clearRetainingCapacity();
198 lazy_fns.clearRetainingCapacity();199 lazy_fns.clearRetainingCapacity();
199 fwd_decl.clearRetainingCapacity();200 fwd_decl.clearRetainingCapacity();
200 code.clearRetainingCapacity();201 code.clearRetainingCapacity();
...@@ -213,7 +214,8 @@ pub fn updateFunc(...@@ -213,7 +214,8 @@ pub fn updateFunc(
213 .pass = .{ .decl = decl_index },214 .pass = .{ .decl = decl_index },
214 .is_naked_fn = decl.typeOf(zcu).fnCallingConvention(zcu) == .Naked,215 .is_naked_fn = decl.typeOf(zcu).fnCallingConvention(zcu) == .Naked,
215 .fwd_decl = fwd_decl.toManaged(gpa),216 .fwd_decl = fwd_decl.toManaged(gpa),
216 .ctypes = ctypes.*,217 .ctype_pool = ctype_pool.*,
218 .scratch = .{},
217 .anon_decl_deps = self.anon_decls,219 .anon_decl_deps = self.anon_decls,
218 .aligned_anon_decls = self.aligned_anon_decls,220 .aligned_anon_decls = self.aligned_anon_decls,
219 },221 },
...@@ -222,12 +224,16 @@ pub fn updateFunc(...@@ -222,12 +224,16 @@ pub fn updateFunc(
222 },224 },
223 .lazy_fns = lazy_fns.*,225 .lazy_fns = lazy_fns.*,
224 };226 };
225
226 function.object.indent_writer = .{ .underlying_writer = function.object.code.writer() };227 function.object.indent_writer = .{ .underlying_writer = function.object.code.writer() };
227 defer {228 defer {
228 self.anon_decls = function.object.dg.anon_decl_deps;229 self.anon_decls = function.object.dg.anon_decl_deps;
229 self.aligned_anon_decls = function.object.dg.aligned_anon_decls;230 self.aligned_anon_decls = function.object.dg.aligned_anon_decls;
230 fwd_decl.* = function.object.dg.fwd_decl.moveToUnmanaged();231 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());
231 code.* = function.object.code.moveToUnmanaged();237 code.* = function.object.code.moveToUnmanaged();
232 function.deinit();238 function.deinit();
233 }239 }
...@@ -239,16 +245,8 @@ pub fn updateFunc(...@@ -239,16 +245,8 @@ pub fn updateFunc(
239 },245 },
240 else => |e| return e,246 else => |e| return e,
241 };247 };
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);
251 gop.value_ptr.fwd_decl = try self.addString(function.object.dg.fwd_decl.items);248 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);
252}250}
253251
254fn updateAnonDecl(self: *C, zcu: *Zcu, i: usize) !void {252fn updateAnonDecl(self: *C, zcu: *Zcu, i: usize) !void {
...@@ -269,7 +267,8 @@ fn updateAnonDecl(self: *C, zcu: *Zcu, i: usize) !void {...@@ -269,7 +267,8 @@ fn updateAnonDecl(self: *C, zcu: *Zcu, i: usize) !void {
269 .pass = .{ .anon = anon_decl },267 .pass = .{ .anon = anon_decl },
270 .is_naked_fn = false,268 .is_naked_fn = false,
271 .fwd_decl = fwd_decl.toManaged(gpa),269 .fwd_decl = fwd_decl.toManaged(gpa),
272 .ctypes = .{},270 .ctype_pool = codegen.CType.Pool.empty,
271 .scratch = .{},
273 .anon_decl_deps = self.anon_decls,272 .anon_decl_deps = self.anon_decls,
274 .aligned_anon_decls = self.aligned_anon_decls,273 .aligned_anon_decls = self.aligned_anon_decls,
275 },274 },
...@@ -277,14 +276,15 @@ fn updateAnonDecl(self: *C, zcu: *Zcu, i: usize) !void {...@@ -277,14 +276,15 @@ fn updateAnonDecl(self: *C, zcu: *Zcu, i: usize) !void {
277 .indent_writer = undefined, // set later so we can get a pointer to object.code276 .indent_writer = undefined, // set later so we can get a pointer to object.code
278 };277 };
279 object.indent_writer = .{ .underlying_writer = object.code.writer() };278 object.indent_writer = .{ .underlying_writer = object.code.writer() };
280
281 defer {279 defer {
282 self.anon_decls = object.dg.anon_decl_deps;280 self.anon_decls = object.dg.anon_decl_deps;
283 self.aligned_anon_decls = object.dg.aligned_anon_decls;281 self.aligned_anon_decls = object.dg.aligned_anon_decls;
284 object.dg.ctypes.deinit(object.dg.gpa);
285 fwd_decl.* = object.dg.fwd_decl.moveToUnmanaged();282 fwd_decl.* = object.dg.fwd_decl.moveToUnmanaged();
283 object.dg.ctype_pool.deinit(object.dg.gpa);
284 object.dg.scratch.deinit(gpa);
286 code.* = object.code.moveToUnmanaged();285 code.* = object.code.moveToUnmanaged();
287 }286 }
287 try object.dg.ctype_pool.init(gpa);
288288
289 const c_value: codegen.CValue = .{ .constant = Value.fromInterned(anon_decl) };289 const c_value: codegen.CValue = .{ .constant = Value.fromInterned(anon_decl) };
290 const alignment: Alignment = self.aligned_anon_decls.get(anon_decl) orelse .none;290 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 {...@@ -297,13 +297,11 @@ fn updateAnonDecl(self: *C, zcu: *Zcu, i: usize) !void {
297 else => |e| return e,297 else => |e| return e,
298 };298 };
299299
300 // Free excess allocated memory for this Decl.300 object.dg.ctype_pool.freeUnusedCapacity(gpa);
301 object.dg.ctypes.shrinkAndFree(gpa, object.dg.ctypes.count());
302
303 object.dg.anon_decl_deps.values()[i] = .{301 object.dg.anon_decl_deps.values()[i] = .{
304 .code = try self.addString(object.code.items),302 .code = try self.addString(object.code.items),
305 .fwd_decl = try self.addString(object.dg.fwd_decl.items),303 .fwd_decl = try self.addString(object.dg.fwd_decl.items),
306 .ctypes = object.dg.ctypes.move(),304 .ctype_pool = object.dg.ctype_pool.move(),
307 };305 };
308}306}
309307
...@@ -315,13 +313,13 @@ pub fn updateDecl(self: *C, zcu: *Zcu, decl_index: InternPool.DeclIndex) !void {...@@ -315,13 +313,13 @@ pub fn updateDecl(self: *C, zcu: *Zcu, decl_index: InternPool.DeclIndex) !void {
315313
316 const decl = zcu.declPtr(decl_index);314 const decl = zcu.declPtr(decl_index);
317 const gop = try self.decl_table.getOrPut(gpa, decl_index);315 const gop = try self.decl_table.getOrPut(gpa, decl_index);
318 if (!gop.found_existing) {316 errdefer _ = self.decl_table.pop();
319 gop.value_ptr.* = .{};317 if (!gop.found_existing) gop.value_ptr.* = .{};
320 }318 const ctype_pool = &gop.value_ptr.ctype_pool;
321 const ctypes = &gop.value_ptr.ctypes;
322 const fwd_decl = &self.fwd_decl_buf;319 const fwd_decl = &self.fwd_decl_buf;
323 const code = &self.code_buf;320 const code = &self.code_buf;
324 ctypes.clearRetainingCapacity(gpa);321 try ctype_pool.init(gpa);
322 ctype_pool.clearRetainingCapacity();
325 fwd_decl.clearRetainingCapacity();323 fwd_decl.clearRetainingCapacity();
326 code.clearRetainingCapacity();324 code.clearRetainingCapacity();
327325
...@@ -334,7 +332,8 @@ pub fn updateDecl(self: *C, zcu: *Zcu, decl_index: InternPool.DeclIndex) !void {...@@ -334,7 +332,8 @@ pub fn updateDecl(self: *C, zcu: *Zcu, decl_index: InternPool.DeclIndex) !void {
334 .pass = .{ .decl = decl_index },332 .pass = .{ .decl = decl_index },
335 .is_naked_fn = false,333 .is_naked_fn = false,
336 .fwd_decl = fwd_decl.toManaged(gpa),334 .fwd_decl = fwd_decl.toManaged(gpa),
337 .ctypes = ctypes.*,335 .ctype_pool = ctype_pool.*,
336 .scratch = .{},
338 .anon_decl_deps = self.anon_decls,337 .anon_decl_deps = self.anon_decls,
339 .aligned_anon_decls = self.aligned_anon_decls,338 .aligned_anon_decls = self.aligned_anon_decls,
340 },339 },
...@@ -345,8 +344,10 @@ pub fn updateDecl(self: *C, zcu: *Zcu, decl_index: InternPool.DeclIndex) !void {...@@ -345,8 +344,10 @@ pub fn updateDecl(self: *C, zcu: *Zcu, decl_index: InternPool.DeclIndex) !void {
345 defer {344 defer {
346 self.anon_decls = object.dg.anon_decl_deps;345 self.anon_decls = object.dg.anon_decl_deps;
347 self.aligned_anon_decls = object.dg.aligned_anon_decls;346 self.aligned_anon_decls = object.dg.aligned_anon_decls;
348 object.dg.ctypes.deinit(object.dg.gpa);
349 fwd_decl.* = object.dg.fwd_decl.moveToUnmanaged();347 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);
350 code.* = object.code.moveToUnmanaged();351 code.* = object.code.moveToUnmanaged();
351 }352 }
352353
...@@ -357,12 +358,6 @@ pub fn updateDecl(self: *C, zcu: *Zcu, decl_index: InternPool.DeclIndex) !void {...@@ -357,12 +358,6 @@ pub fn updateDecl(self: *C, zcu: *Zcu, decl_index: InternPool.DeclIndex) !void {
357 },358 },
358 else => |e| return e,359 else => |e| return e,
359 };360 };
360
361 ctypes.* = object.dg.ctypes.move();
362
363 // Free excess allocated memory for this Decl.
364 ctypes.shrinkAndFree(gpa, ctypes.count());
365
366 gop.value_ptr.code = try self.addString(object.code.items);361 gop.value_ptr.code = try self.addString(object.code.items);
367 gop.value_ptr.fwd_decl = try self.addString(object.dg.fwd_decl.items);362 gop.value_ptr.fwd_decl = try self.addString(object.dg.fwd_decl.items);
368}363}
...@@ -416,7 +411,10 @@ pub fn flushModule(self: *C, arena: Allocator, prog_node: *std.Progress.Node) !v...@@ -416,7 +411,10 @@ pub fn flushModule(self: *C, arena: Allocator, prog_node: *std.Progress.Node) !v
416 // This code path happens exclusively with -ofmt=c. The flush logic for411 // This code path happens exclusively with -ofmt=c. The flush logic for
417 // emit-h is in `flushEmitH` below.412 // 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 };
420 defer f.deinit(gpa);418 defer f.deinit(gpa);
421419
422 const abi_defines = try self.abiDefines(zcu.getTarget());420 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...@@ -443,7 +441,8 @@ pub fn flushModule(self: *C, arena: Allocator, prog_node: *std.Progress.Node) !v
443441
444 self.lazy_fwd_decl_buf.clearRetainingCapacity();442 self.lazy_fwd_decl_buf.clearRetainingCapacity();
445 self.lazy_code_buf.clearRetainingCapacity();443 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
448 // Unlike other backends, the .c code we are emitting has order-dependent decls.447 // Unlike other backends, the .c code we are emitting has order-dependent decls.
449 // `CType`s, forward decls, and non-functions first.448 // `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...@@ -471,15 +470,15 @@ pub fn flushModule(self: *C, arena: Allocator, prog_node: *std.Progress.Node) !v
471 {470 {
472 // We need to flush lazy ctypes after flushing all decls but before flushing any decl ctypes.471 // We need to flush lazy ctypes after flushing all decls but before flushing any decl ctypes.
473 // This ensures that every lazy CType.Index exactly matches the global CType.Index.472 // This ensures that every lazy CType.Index exactly matches the global CType.Index.
474 assert(f.ctypes.count() == 0);473 try f.ctype_pool.init(gpa);
475 try self.flushCTypes(zcu, &f, .flush, f.lazy_ctypes);474 try self.flushCTypes(zcu, &f, .flush, &f.lazy_ctype_pool);
476475
477 for (self.anon_decls.keys(), self.anon_decls.values()) |anon_decl, decl_block| {476 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);
479 }478 }
480479
481 for (self.decl_table.keys(), self.decl_table.values()) |decl_index, decl_block| {480 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);
483 }482 }
484 }483 }
485484
...@@ -510,11 +509,11 @@ pub fn flushModule(self: *C, arena: Allocator, prog_node: *std.Progress.Node) !v...@@ -510,11 +509,11 @@ pub fn flushModule(self: *C, arena: Allocator, prog_node: *std.Progress.Node) !v
510}509}
511510
512const Flush = struct {511const Flush = struct {
513 ctypes: codegen.CType.Store = .{},512 ctype_pool: codegen.CType.Pool,
514 ctypes_map: std.ArrayListUnmanaged(codegen.CType.Index) = .{},513 ctype_global_from_decl_map: std.ArrayListUnmanaged(codegen.CType) = .{},
515 ctypes_buf: std.ArrayListUnmanaged(u8) = .{},514 ctypes_buf: std.ArrayListUnmanaged(u8) = .{},
516515
517 lazy_ctypes: codegen.CType.Store = .{},516 lazy_ctype_pool: codegen.CType.Pool,
518 lazy_fns: LazyFns = .{},517 lazy_fns: LazyFns = .{},
519518
520 asm_buf: std.ArrayListUnmanaged(u8) = .{},519 asm_buf: std.ArrayListUnmanaged(u8) = .{},
...@@ -536,10 +535,11 @@ const Flush = struct {...@@ -536,10 +535,11 @@ const Flush = struct {
536 f.all_buffers.deinit(gpa);535 f.all_buffers.deinit(gpa);
537 f.asm_buf.deinit(gpa);536 f.asm_buf.deinit(gpa);
538 f.lazy_fns.deinit(gpa);537 f.lazy_fns.deinit(gpa);
539 f.lazy_ctypes.deinit(gpa);538 f.lazy_ctype_pool.deinit(gpa);
540 f.ctypes_buf.deinit(gpa);539 f.ctypes_buf.deinit(gpa);
541 f.ctypes_map.deinit(gpa);540 assert(f.ctype_global_from_decl_map.items.len == 0);
542 f.ctypes.deinit(gpa);541 f.ctype_global_from_decl_map.deinit(gpa);
542 f.ctype_pool.deinit(gpa);
543 }543 }
544};544};
545545
...@@ -552,88 +552,59 @@ fn flushCTypes(...@@ -552,88 +552,59 @@ fn flushCTypes(
552 zcu: *Zcu,552 zcu: *Zcu,
553 f: *Flush,553 f: *Flush,
554 pass: codegen.DeclGen.Pass,554 pass: codegen.DeclGen.Pass,
555 decl_ctypes: codegen.CType.Store,555 decl_ctype_pool: *const codegen.CType.Pool,
556) FlushDeclError!void {556) FlushDeclError!void {
557 const gpa = self.base.comp.gpa;557 const gpa = self.base.comp.gpa;
558 const global_ctype_pool = &f.ctype_pool;
558559
559 const decl_ctypes_len = decl_ctypes.count();560 const global_from_decl_map = &f.ctype_global_from_decl_map;
560 f.ctypes_map.clearRetainingCapacity();561 assert(global_from_decl_map.items.len == 0);
561 try f.ctypes_map.ensureTotalCapacity(gpa, decl_ctypes_len);562 try global_from_decl_map.ensureTotalCapacity(gpa, decl_ctype_pool.items.len);
562563 defer global_from_decl_map.clearRetainingCapacity();
563 var global_ctypes = f.ctypes.promote(gpa);
564 defer f.ctypes.demote(global_ctypes);
565564
566 var ctypes_buf = f.ctypes_buf.toManaged(gpa);565 var ctypes_buf = f.ctypes_buf.toManaged(gpa);
567 defer f.ctypes_buf = ctypes_buf.moveToUnmanaged();566 defer f.ctypes_buf = ctypes_buf.moveToUnmanaged();
568 const writer = ctypes_buf.writer();567 const writer = ctypes_buf.writer();
569568
570 const slice = decl_ctypes.set.map.entries.slice();569 for (0..decl_ctype_pool.items.len) |decl_ctype_pool_index| {
571 for (slice.items(.key), 0..) |decl_cty, decl_i| {570 const PoolAdapter = struct {
572 const Context = struct {571 global_from_decl_map: []const codegen.CType,
573 arena: Allocator,572 pub fn eql(pool_adapter: @This(), decl_ctype: codegen.CType, global_ctype: codegen.CType) bool {
574 ctypes_map: []codegen.CType.Index,573 return if (decl_ctype.toPoolIndex()) |decl_pool_index|
575 cached_hash: codegen.CType.Store.Set.Map.Hash,574 decl_pool_index < pool_adapter.global_from_decl_map.len and
576 idx: codegen.CType.Index,575 pool_adapter.global_from_decl_map[decl_pool_index].eql(global_ctype)
577576 else
578 pub fn hash(ctx: @This(), _: codegen.CType) codegen.CType.Store.Set.Map.Hash {577 decl_ctype.index == global_ctype.index;
579 return ctx.cached_hash;
580 }578 }
581 pub fn eql(ctx: @This(), lhs: codegen.CType, rhs: codegen.CType, _: usize) bool {579 pub fn copy(pool_adapter: @This(), decl_ctype: codegen.CType) codegen.CType {
582 return lhs.eqlContext(rhs, ctx);580 return if (decl_ctype.toPoolIndex()) |decl_pool_index|
581 pool_adapter.global_from_decl_map[decl_pool_index]
582 else
583 decl_ctype;
583 }584 }
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,
606 };585 };
607 const gop = try global_ctypes.set.map.getOrPutContextAdapted(gpa, decl_cty, ctx, .{586 const decl_ctype = codegen.CType.fromPoolIndex(decl_ctype_pool_index);
608 .store = &global_ctypes.set,587 const global_ctype, const found_existing = try global_ctype_pool.getOrPutAdapted(
609 });588 gpa,
610 const global_idx =589 decl_ctype_pool,
611 @as(codegen.CType.Index, @intCast(codegen.CType.Tag.no_payload_count + gop.index));590 decl_ctype,
612 f.ctypes_map.appendAssumeCapacity(global_idx);591 PoolAdapter{ .global_from_decl_map = global_from_decl_map.items },
613 if (!gop.found_existing) {592 );
614 errdefer _ = global_ctypes.set.map.pop();593 global_from_decl_map.appendAssumeCapacity(global_ctype);
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 }
623 try codegen.genTypeDecl(594 try codegen.genTypeDecl(
624 zcu,595 zcu,
625 writer,596 writer,
626 global_ctypes.set,597 global_ctype_pool,
627 global_idx,598 global_ctype,
628 pass,599 pass,
629 decl_ctypes.set,600 decl_ctype_pool,
630 decl_idx,601 decl_ctype,
631 gop.found_existing,602 found_existing,
632 );603 );
633 }604 }
634}605}
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 {
637 const gpa = self.base.comp.gpa;608 const gpa = self.base.comp.gpa;
638609
639 const fwd_decl = &self.lazy_fwd_decl_buf;610 const fwd_decl = &self.lazy_fwd_decl_buf;
...@@ -648,7 +619,8 @@ fn flushErrDecls(self: *C, zcu: *Zcu, ctypes: *codegen.CType.Store) FlushDeclErr...@@ -648,7 +619,8 @@ fn flushErrDecls(self: *C, zcu: *Zcu, ctypes: *codegen.CType.Store) FlushDeclErr
648 .pass = .flush,619 .pass = .flush,
649 .is_naked_fn = false,620 .is_naked_fn = false,
650 .fwd_decl = fwd_decl.toManaged(gpa),621 .fwd_decl = fwd_decl.toManaged(gpa),
651 .ctypes = ctypes.*,622 .ctype_pool = ctype_pool.*,
623 .scratch = .{},
652 .anon_decl_deps = self.anon_decls,624 .anon_decl_deps = self.anon_decls,
653 .aligned_anon_decls = self.aligned_anon_decls,625 .aligned_anon_decls = self.aligned_anon_decls,
654 },626 },
...@@ -659,8 +631,10 @@ fn flushErrDecls(self: *C, zcu: *Zcu, ctypes: *codegen.CType.Store) FlushDeclErr...@@ -659,8 +631,10 @@ fn flushErrDecls(self: *C, zcu: *Zcu, ctypes: *codegen.CType.Store) FlushDeclErr
659 defer {631 defer {
660 self.anon_decls = object.dg.anon_decl_deps;632 self.anon_decls = object.dg.anon_decl_deps;
661 self.aligned_anon_decls = object.dg.aligned_anon_decls;633 self.aligned_anon_decls = object.dg.aligned_anon_decls;
662 object.dg.ctypes.deinit(gpa);
663 fwd_decl.* = object.dg.fwd_decl.moveToUnmanaged();634 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);
664 code.* = object.code.moveToUnmanaged();638 code.* = object.code.moveToUnmanaged();
665 }639 }
666640
...@@ -668,15 +642,14 @@ fn flushErrDecls(self: *C, zcu: *Zcu, ctypes: *codegen.CType.Store) FlushDeclErr...@@ -668,15 +642,14 @@ fn flushErrDecls(self: *C, zcu: *Zcu, ctypes: *codegen.CType.Store) FlushDeclErr
668 error.AnalysisFail => unreachable,642 error.AnalysisFail => unreachable,
669 else => |e| return e,643 else => |e| return e,
670 };644 };
671
672 ctypes.* = object.dg.ctypes.move();
673}645}
674646
675fn flushLazyFn(647fn flushLazyFn(
676 self: *C,648 self: *C,
677 zcu: *Zcu,649 zcu: *Zcu,
678 mod: *Module,650 mod: *Module,
679 ctypes: *codegen.CType.Store,651 ctype_pool: *codegen.CType.Pool,
652 lazy_ctype_pool: *const codegen.CType.Pool,
680 lazy_fn: codegen.LazyFnMap.Entry,653 lazy_fn: codegen.LazyFnMap.Entry,
681) FlushDeclError!void {654) FlushDeclError!void {
682 const gpa = self.base.comp.gpa;655 const gpa = self.base.comp.gpa;
...@@ -693,7 +666,8 @@ fn flushLazyFn(...@@ -693,7 +666,8 @@ fn flushLazyFn(
693 .pass = .flush,666 .pass = .flush,
694 .is_naked_fn = false,667 .is_naked_fn = false,
695 .fwd_decl = fwd_decl.toManaged(gpa),668 .fwd_decl = fwd_decl.toManaged(gpa),
696 .ctypes = ctypes.*,669 .ctype_pool = ctype_pool.*,
670 .scratch = .{},
697 .anon_decl_deps = .{},671 .anon_decl_deps = .{},
698 .aligned_anon_decls = .{},672 .aligned_anon_decls = .{},
699 },673 },
...@@ -706,17 +680,17 @@ fn flushLazyFn(...@@ -706,17 +680,17 @@ fn flushLazyFn(
706 // `updateFunc()` does.680 // `updateFunc()` does.
707 assert(object.dg.anon_decl_deps.count() == 0);681 assert(object.dg.anon_decl_deps.count() == 0);
708 assert(object.dg.aligned_anon_decls.count() == 0);682 assert(object.dg.aligned_anon_decls.count() == 0);
709 object.dg.ctypes.deinit(gpa);
710 fwd_decl.* = object.dg.fwd_decl.moveToUnmanaged();683 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);
711 code.* = object.code.moveToUnmanaged();687 code.* = object.code.moveToUnmanaged();
712 }688 }
713689
714 codegen.genLazyFn(&object, lazy_fn) catch |err| switch (err) {690 codegen.genLazyFn(&object, lazy_ctype_pool, lazy_fn) catch |err| switch (err) {
715 error.AnalysisFail => unreachable,691 error.AnalysisFail => unreachable,
716 else => |e| return e,692 else => |e| return e,
717 };693 };
718
719 ctypes.* = object.dg.ctypes.move();
720}694}
721695
722fn flushLazyFns(696fn flushLazyFns(
...@@ -724,6 +698,7 @@ fn flushLazyFns(...@@ -724,6 +698,7 @@ fn flushLazyFns(
724 zcu: *Zcu,698 zcu: *Zcu,
725 mod: *Module,699 mod: *Module,
726 f: *Flush,700 f: *Flush,
701 lazy_ctype_pool: *const codegen.CType.Pool,
727 lazy_fns: codegen.LazyFnMap,702 lazy_fns: codegen.LazyFnMap,
728) FlushDeclError!void {703) FlushDeclError!void {
729 const gpa = self.base.comp.gpa;704 const gpa = self.base.comp.gpa;
...@@ -734,7 +709,7 @@ fn flushLazyFns(...@@ -734,7 +709,7 @@ fn flushLazyFns(
734 const gop = f.lazy_fns.getOrPutAssumeCapacity(entry.key_ptr.*);709 const gop = f.lazy_fns.getOrPutAssumeCapacity(entry.key_ptr.*);
735 if (gop.found_existing) continue;710 if (gop.found_existing) continue;
736 gop.value_ptr.* = {};711 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);
738 }713 }
739}714}
740715
...@@ -748,7 +723,7 @@ fn flushDeclBlock(...@@ -748,7 +723,7 @@ fn flushDeclBlock(
748 extern_symbol_name: InternPool.OptionalNullTerminatedString,723 extern_symbol_name: InternPool.OptionalNullTerminatedString,
749) FlushDeclError!void {724) FlushDeclError!void {
750 const gpa = self.base.comp.gpa;725 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);
752 try f.all_buffers.ensureUnusedCapacity(gpa, 1);727 try f.all_buffers.ensureUnusedCapacity(gpa, 1);
753 fwd_decl: {728 fwd_decl: {
754 if (extern_symbol_name.unwrap()) |name| {729 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...@@ -1223,7 +1223,7 @@ fn lowerConst(self: *Coff, name: []const u8, val: Value, required_alignment: Int
1223 atom.getSymbolPtr(self).value = try self.allocateAtom(1223 atom.getSymbolPtr(self).value = try self.allocateAtom(
1224 atom_index,1224 atom_index,
1225 atom.size,1225 atom.size,
1226 @intCast(required_alignment.toByteUnitsOptional().?),1226 @intCast(required_alignment.toByteUnits().?),
1227 );1227 );
1228 errdefer self.freeAtom(atom_index);1228 errdefer self.freeAtom(atom_index);
12291229
...@@ -1344,7 +1344,7 @@ fn updateLazySymbolAtom(...@@ -1344,7 +1344,7 @@ fn updateLazySymbolAtom(
1344 symbol.section_number = @as(coff.SectionNumber, @enumFromInt(section_index + 1));1344 symbol.section_number = @as(coff.SectionNumber, @enumFromInt(section_index + 1));
1345 symbol.type = .{ .complex_type = .NULL, .base_type = .NULL };1345 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));
1348 errdefer self.freeAtom(atom_index);1348 errdefer self.freeAtom(atom_index);
13491349
1350 log.debug("allocated atom for {s} at 0x{x}", .{ name, vaddr });1350 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...@@ -1428,7 +1428,7 @@ fn updateDeclCode(self: *Coff, decl_index: InternPool.DeclIndex, code: []u8, com
1428 const decl_name = mod.intern_pool.stringToSlice(try decl.fullyQualifiedName(mod));1428 const decl_name = mod.intern_pool.stringToSlice(try decl.fullyQualifiedName(mod));
14291429
1430 log.debug("updateDeclCode {s}{*}", .{ decl_name, decl });1430 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
1433 const decl_metadata = self.decls.get(decl_index).?;1433 const decl_metadata = self.decls.get(decl_index).?;
1434 const atom_index = decl_metadata.atom;1434 const atom_index = decl_metadata.atom;
src/link/Elf.zig+1-1
...@@ -4051,7 +4051,7 @@ fn updateSectionSizes(self: *Elf) !void {...@@ -4051,7 +4051,7 @@ fn updateSectionSizes(self: *Elf) !void {
4051 const padding = offset - shdr.sh_size;4051 const padding = offset - shdr.sh_size;
4052 atom_ptr.value = offset;4052 atom_ptr.value = offset;
4053 shdr.sh_size += padding + atom_ptr.size;4053 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);
4055 }4055 }
4056 }4056 }
40574057
src/link/Elf/Atom.zig+1-1
...@@ -208,7 +208,7 @@ pub fn allocate(self: *Atom, elf_file: *Elf) !void {...@@ -208,7 +208,7 @@ pub fn allocate(self: *Atom, elf_file: *Elf) !void {
208 zig_object.debug_aranges_section_dirty = true;208 zig_object.debug_aranges_section_dirty = true;
209 }209 }
210 }210 }
211 shdr.sh_addralign = @max(shdr.sh_addralign, self.alignment.toByteUnitsOptional().?);211 shdr.sh_addralign = @max(shdr.sh_addralign, self.alignment.toByteUnits().?);
212212
213 // This function can also reallocate an atom.213 // This function can also reallocate an atom.
214 // In this case we need to "unplug" it from its previous location before214 // 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...@@ -313,7 +313,7 @@ pub fn inputShdr(self: ZigObject, atom_index: Atom.Index, elf_file: *Elf) elf.El
313 shdr.sh_addr = 0;313 shdr.sh_addr = 0;
314 shdr.sh_offset = 0;314 shdr.sh_offset = 0;
315 shdr.sh_size = atom.size;315 shdr.sh_size = atom.size;
316 shdr.sh_addralign = atom.alignment.toByteUnits(1);316 shdr.sh_addralign = atom.alignment.toByteUnits() orelse 1;
317 return shdr;317 return shdr;
318}318}
319319
src/link/Elf/relocatable.zig+1-1
...@@ -330,7 +330,7 @@ fn updateSectionSizes(elf_file: *Elf) !void {...@@ -330,7 +330,7 @@ fn updateSectionSizes(elf_file: *Elf) !void {
330 const padding = offset - shdr.sh_size;330 const padding = offset - shdr.sh_size;
331 atom_ptr.value = offset;331 atom_ptr.value = offset;
332 shdr.sh_size += padding + atom_ptr.size;332 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);
334 }334 }
335 }335 }
336336
src/link/Elf/thunks.zig+1-1
...@@ -63,7 +63,7 @@ fn advance(shdr: *elf.Elf64_Shdr, size: u64, alignment: Atom.Alignment) !u64 {...@@ -63,7 +63,7 @@ fn advance(shdr: *elf.Elf64_Shdr, size: u64, alignment: Atom.Alignment) !u64 {
63 const offset = alignment.forward(shdr.sh_size);63 const offset = alignment.forward(shdr.sh_size);
64 const padding = offset - shdr.sh_size;64 const padding = offset - shdr.sh_size;
65 shdr.sh_size += padding + size;65 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);
67 return offset;67 return offset;
68}68}
6969
src/link/MachO.zig+1-1
...@@ -2060,7 +2060,7 @@ fn calcSectionSizes(self: *MachO) !void {...@@ -2060,7 +2060,7 @@ fn calcSectionSizes(self: *MachO) !void {
20602060
2061 for (atoms.items) |atom_index| {2061 for (atoms.items) |atom_index| {
2062 const atom = self.getAtom(atom_index).?;2062 const atom = self.getAtom(atom_index).?;
2063 const atom_alignment = atom.alignment.toByteUnits(1);2063 const atom_alignment = atom.alignment.toByteUnits() orelse 1;
2064 const offset = mem.alignForward(u64, header.size, atom_alignment);2064 const offset = mem.alignForward(u64, header.size, atom_alignment);
2065 const padding = offset - header.size;2065 const padding = offset - header.size;
2066 atom.value = offset;2066 atom.value = offset;
src/link/MachO/relocatable.zig+1-1
...@@ -380,7 +380,7 @@ fn calcSectionSizes(macho_file: *MachO) !void {...@@ -380,7 +380,7 @@ fn calcSectionSizes(macho_file: *MachO) !void {
380 if (atoms.items.len == 0) continue;380 if (atoms.items.len == 0) continue;
381 for (atoms.items) |atom_index| {381 for (atoms.items) |atom_index| {
382 const atom = macho_file.getAtom(atom_index).?;382 const atom = macho_file.getAtom(atom_index).?;
383 const atom_alignment = atom.alignment.toByteUnits(1);383 const atom_alignment = atom.alignment.toByteUnits() orelse 1;
384 const offset = mem.alignForward(u64, header.size, atom_alignment);384 const offset = mem.alignForward(u64, header.size, atom_alignment);
385 const padding = offset - header.size;385 const padding = offset - header.size;
386 atom.value = offset;386 atom.value = offset;
src/link/Wasm.zig+1-1
...@@ -2263,7 +2263,7 @@ fn setupMemory(wasm: *Wasm) !void {...@@ -2263,7 +2263,7 @@ fn setupMemory(wasm: *Wasm) !void {
2263 }2263 }
2264 if (wasm.findGlobalSymbol("__tls_align")) |loc| {2264 if (wasm.findGlobalSymbol("__tls_align")) |loc| {
2265 const sym = loc.getSymbol(wasm);2265 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().?);
2267 }2267 }
2268 if (wasm.findGlobalSymbol("__tls_base")) |loc| {2268 if (wasm.findGlobalSymbol("__tls_base")) |loc| {
2269 const sym = loc.getSymbol(wasm);2269 const sym = loc.getSymbol(wasm);
src/main.zig+1-5
...@@ -3544,11 +3544,7 @@ fn createModule(...@@ -3544,11 +3544,7 @@ fn createModule(
3544 // If the target is not overridden, use the parent's target. Of course,3544 // If the target is not overridden, use the parent's target. Of course,
3545 // if this is the root module then we need to proceed to resolve the3545 // if this is the root module then we need to proceed to resolve the
3546 // target.3546 // target.
3547 if (cli_mod.target_arch_os_abi == null and3547 if (cli_mod.target_arch_os_abi == null and cli_mod.target_mcpu == null) {
3548 cli_mod.target_mcpu == null and
3549 create_module.dynamic_linker == null and
3550 create_module.object_format == null)
3551 {
3552 if (parent) |p| break :t p.resolved_target;3548 if (parent) |p| break :t p.resolved_target;
3553 }3549 }
35543550
src/print_value.zig+1-1
...@@ -80,7 +80,7 @@ pub fn print(...@@ -80,7 +80,7 @@ pub fn print(
80 inline .u64, .i64, .big_int => |x| try writer.print("{}", .{x}),80 inline .u64, .i64, .big_int => |x| try writer.print("{}", .{x}),
81 .lazy_align => |ty| if (opt_sema) |sema| {81 .lazy_align => |ty| if (opt_sema) |sema| {
82 const a = (try Type.fromInterned(ty).abiAlignmentAdvanced(mod, .{ .sema = sema })).scalar;82 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});
84 } else try writer.print("@alignOf({})", .{Type.fromInterned(ty).fmt(mod)}),84 } else try writer.print("@alignOf({})", .{Type.fromInterned(ty).fmt(mod)}),
85 .lazy_size => |ty| if (opt_sema) |sema| {85 .lazy_size => |ty| if (opt_sema) |sema| {
86 const s = (try Type.fromInterned(ty).abiSizeAdvanced(mod, .{ .sema = sema })).scalar;86 const s = (try Type.fromInterned(ty).abiSizeAdvanced(mod, .{ .sema = sema })).scalar;
src/target.zig+1-1
...@@ -525,7 +525,7 @@ pub fn backendSupportsFeature(...@@ -525,7 +525,7 @@ pub fn backendSupportsFeature(
525 .error_return_trace => use_llvm,525 .error_return_trace => use_llvm,
526 .is_named_enum_value => use_llvm,526 .is_named_enum_value => use_llvm,
527 .error_set_has_value => use_llvm or cpu_arch.isWasm(),527 .error_set_has_value => use_llvm or cpu_arch.isWasm(),
528 .field_reordering => use_llvm,528 .field_reordering => ofmt == .c or use_llvm,
529 .safety_checked_instructions => use_llvm,529 .safety_checked_instructions => use_llvm,
530 };530 };
531}531}
src/type.zig+25-27
...@@ -203,7 +203,7 @@ pub const Type = struct {...@@ -203,7 +203,7 @@ pub const Type = struct {
203 info.flags.alignment203 info.flags.alignment
204 else204 else
205 Type.fromInterned(info.child).abiAlignment(mod);205 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
208 if (info.packed_offset.bit_offset != 0 or info.packed_offset.host_size != 0) {208 if (info.packed_offset.bit_offset != 0 or info.packed_offset.host_size != 0) {
209 try writer.print(":{d}:{d}", .{209 try writer.print(":{d}:{d}", .{
...@@ -863,7 +863,7 @@ pub const Type = struct {...@@ -863,7 +863,7 @@ pub const Type = struct {
863 pub fn lazyAbiAlignment(ty: Type, mod: *Module) !Value {863 pub fn lazyAbiAlignment(ty: Type, mod: *Module) !Value {
864 switch (try ty.abiAlignmentAdvanced(mod, .lazy)) {864 switch (try ty.abiAlignmentAdvanced(mod, .lazy)) {
865 .val => |val| return val,865 .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),
867 }867 }
868 }868 }
869869
...@@ -905,7 +905,7 @@ pub const Type = struct {...@@ -905,7 +905,7 @@ pub const Type = struct {
905 return .{ .scalar = intAbiAlignment(int_type.bits, target) };905 return .{ .scalar = intAbiAlignment(int_type.bits, target) };
906 },906 },
907 .ptr_type, .anyframe_type => {907 .ptr_type, .anyframe_type => {
908 return .{ .scalar = Alignment.fromByteUnits(@divExact(target.ptrBitWidth(), 8)) };908 return .{ .scalar = ptrAbiAlignment(target) };
909 },909 },
910 .array_type => |array_type| {910 .array_type => |array_type| {
911 return Type.fromInterned(array_type.child).abiAlignmentAdvanced(mod, strat);911 return Type.fromInterned(array_type.child).abiAlignmentAdvanced(mod, strat);
...@@ -920,6 +920,9 @@ pub const Type = struct {...@@ -920,6 +920,9 @@ pub const Type = struct {
920 const alignment = std.math.ceilPowerOfTwoAssert(u32, bytes);920 const alignment = std.math.ceilPowerOfTwoAssert(u32, bytes);
921 return .{ .scalar = Alignment.fromByteUnits(alignment) };921 return .{ .scalar = Alignment.fromByteUnits(alignment) };
922 },922 },
923 .stage2_c => {
924 return Type.fromInterned(vector_type.child).abiAlignmentAdvanced(mod, strat);
925 },
923 .stage2_x86_64 => {926 .stage2_x86_64 => {
924 if (vector_type.child == .bool_type) {927 if (vector_type.child == .bool_type) {
925 if (vector_type.len > 256 and std.Target.x86.featureSetHas(target.cpu.features, .avx512f)) return .{ .scalar = .@"64" };928 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 {...@@ -966,12 +969,12 @@ pub const Type = struct {
966969
967 .usize,970 .usize,
968 .isize,971 .isize,
972 => return .{ .scalar = intAbiAlignment(target.ptrBitWidth(), target) },
973
969 .export_options,974 .export_options,
970 .extern_options,975 .extern_options,
971 .type_info,976 .type_info,
972 => return .{977 => return .{ .scalar = ptrAbiAlignment(target) },
973 .scalar = Alignment.fromByteUnits(@divExact(target.ptrBitWidth(), 8)),
974 },
975978
976 .c_char => return .{ .scalar = cTypeAlign(target, .char) },979 .c_char => return .{ .scalar = cTypeAlign(target, .char) },
977 .c_short => return .{ .scalar = cTypeAlign(target, .short) },980 .c_short => return .{ .scalar = cTypeAlign(target, .short) },
...@@ -1160,9 +1163,7 @@ pub const Type = struct {...@@ -1160,9 +1163,7 @@ pub const Type = struct {
1160 const child_type = ty.optionalChild(mod);1163 const child_type = ty.optionalChild(mod);
11611164
1162 switch (child_type.zigTypeTag(mod)) {1165 switch (child_type.zigTypeTag(mod)) {
1163 .Pointer => return .{1166 .Pointer => return .{ .scalar = ptrAbiAlignment(target) },
1164 .scalar = Alignment.fromByteUnits(@divExact(target.ptrBitWidth(), 8)),
1165 },
1166 .ErrorSet => return abiAlignmentAdvanced(Type.anyerror, mod, strat),1167 .ErrorSet => return abiAlignmentAdvanced(Type.anyerror, mod, strat),
1167 .NoReturn => return .{ .scalar = .@"1" },1168 .NoReturn => return .{ .scalar = .@"1" },
1168 else => {},1169 else => {},
...@@ -1274,6 +1275,10 @@ pub const Type = struct {...@@ -1274,6 +1275,10 @@ pub const Type = struct {
1274 const total_bits = elem_bits * vector_type.len;1275 const total_bits = elem_bits * vector_type.len;
1275 break :total_bytes (total_bits + 7) / 8;1276 break :total_bytes (total_bits + 7) / 8;
1276 },1277 },
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 },
1277 .stage2_x86_64 => total_bytes: {1282 .stage2_x86_64 => total_bytes: {
1278 if (vector_type.child == .bool_type) break :total_bytes std.math.divCeil(u32, vector_type.len, 8) catch unreachable;1283 if (vector_type.child == .bool_type) break :total_bytes std.math.divCeil(u32, vector_type.len, 8) catch unreachable;
1279 const elem_bytes: u32 = @intCast((try Type.fromInterned(vector_type.child).abiSizeAdvanced(mod, strat)).scalar);1284 const elem_bytes: u32 = @intCast((try Type.fromInterned(vector_type.child).abiSizeAdvanced(mod, strat)).scalar);
...@@ -1527,15 +1532,19 @@ pub const Type = struct {...@@ -1527,15 +1532,19 @@ pub const Type = struct {
1527 // guaranteed to be >= that of bool's (1 byte) the added size is exactly equal1532 // guaranteed to be >= that of bool's (1 byte) the added size is exactly equal
1528 // to the child type's ABI alignment.1533 // to the child type's ABI alignment.
1529 return AbiSizeAdvanced{1534 return AbiSizeAdvanced{
1530 .scalar = child_ty.abiAlignment(mod).toByteUnits(0) + payload_size,1535 .scalar = (child_ty.abiAlignment(mod).toByteUnits() orelse 0) + payload_size,
1531 };1536 };
1532 }1537 }
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 {
1535 return intAbiAlignment(bits, target).forward(@as(u16, @intCast((@as(u17, bits) + 7) / 8)));1544 return intAbiAlignment(bits, target).forward(@as(u16, @intCast((@as(u17, bits) + 7) / 8)));
1536 }1545 }
15371546
1538 fn intAbiAlignment(bits: u16, target: Target) Alignment {1547 pub fn intAbiAlignment(bits: u16, target: Target) Alignment {
1539 return Alignment.fromByteUnits(@min(1548 return Alignment.fromByteUnits(@min(
1540 std.math.ceilPowerOfTwoPromote(u16, @as(u16, @intCast((@as(u17, bits) + 7) / 8))),1549 std.math.ceilPowerOfTwoPromote(u16, @as(u16, @intCast((@as(u17, bits) + 7) / 8))),
1541 target.maxIntAlignment(),1550 target.maxIntAlignment(),
...@@ -1572,7 +1581,7 @@ pub const Type = struct {...@@ -1572,7 +1581,7 @@ pub const Type = struct {
1572 if (len == 0) return 0;1581 if (len == 0) return 0;
1573 const elem_ty = Type.fromInterned(array_type.child);1582 const elem_ty = Type.fromInterned(array_type.child);
1574 const elem_size = @max(1583 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,
1576 (try elem_ty.abiSizeAdvanced(mod, strat)).scalar,1585 (try elem_ty.abiSizeAdvanced(mod, strat)).scalar,
1577 );1586 );
1578 if (elem_size == 0) return 0;1587 if (elem_size == 0) return 0;
...@@ -3016,26 +3025,15 @@ pub const Type = struct {...@@ -3016,26 +3025,15 @@ pub const Type = struct {
3016 }3025 }
30173026
3018 /// Returns none in the case of a tuple which uses the integer index as the field name.3027 /// 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 {
3020 const ip = &mod.intern_pool;3029 const ip = &mod.intern_pool;
3021 return switch (ip.indexToKey(ty.toIntern())) {3030 return switch (ip.indexToKey(ty.toIntern())) {
3022 .struct_type => ip.loadStructType(ty.toIntern()).fieldName(ip, field_index),3031 .struct_type => ip.loadStructType(ty.toIntern()).fieldName(ip, index),
3023 .anon_struct_type => |anon_struct| anon_struct.fieldName(ip, field_index),3032 .anon_struct_type => |anon_struct| anon_struct.fieldName(ip, index),
3024 else => unreachable,3033 else => unreachable,
3025 };3034 };
3026 }3035 }
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
3039 pub fn structFieldCount(ty: Type, mod: *Module) u32 {3037 pub fn structFieldCount(ty: Type, mod: *Module) u32 {
3040 const ip = &mod.intern_pool;3038 const ip = &mod.intern_pool;
3041 return switch (ip.indexToKey(ty.toIntern())) {3039 return switch (ip.indexToKey(ty.toIntern())) {
test/behavior/align.zig-1
...@@ -624,7 +624,6 @@ test "sub-aligned pointer field access" {...@@ -624,7 +624,6 @@ test "sub-aligned pointer field access" {
624 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;624 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
625 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;625 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
626 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;626 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
627 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
628627
629 // Originally reported at https://github.com/ziglang/zig/issues/14904628 // Originally reported at https://github.com/ziglang/zig/issues/14904
630629
test/behavior/vector.zig+4
...@@ -1176,18 +1176,22 @@ test "@shlWithOverflow" {...@@ -1176,18 +1176,22 @@ test "@shlWithOverflow" {
1176test "alignment of vectors" {1176test "alignment of vectors" {
1177 try expect(@alignOf(@Vector(2, u8)) == switch (builtin.zig_backend) {1177 try expect(@alignOf(@Vector(2, u8)) == switch (builtin.zig_backend) {
1178 else => 2,1178 else => 2,
1179 .stage2_c => @alignOf(u8),
1179 .stage2_x86_64 => 16,1180 .stage2_x86_64 => 16,
1180 });1181 });
1181 try expect(@alignOf(@Vector(2, u1)) == switch (builtin.zig_backend) {1182 try expect(@alignOf(@Vector(2, u1)) == switch (builtin.zig_backend) {
1182 else => 1,1183 else => 1,
1184 .stage2_c => @alignOf(u1),
1183 .stage2_x86_64 => 16,1185 .stage2_x86_64 => 16,
1184 });1186 });
1185 try expect(@alignOf(@Vector(1, u1)) == switch (builtin.zig_backend) {1187 try expect(@alignOf(@Vector(1, u1)) == switch (builtin.zig_backend) {
1186 else => 1,1188 else => 1,
1189 .stage2_c => @alignOf(u1),
1187 .stage2_x86_64 => 16,1190 .stage2_x86_64 => 16,
1188 });1191 });
1189 try expect(@alignOf(@Vector(2, u16)) == switch (builtin.zig_backend) {1192 try expect(@alignOf(@Vector(2, u16)) == switch (builtin.zig_backend) {
1190 else => 4,1193 else => 4,
1194 .stage2_c => @alignOf(u16),
1191 .stage2_x86_64 => 16,1195 .stage2_x86_64 => 16,
1192 });1196 });
1193}1197}
test/tests.zig+12-5
...@@ -1164,19 +1164,26 @@ pub fn addModuleTests(b: *std.Build, options: ModuleTestOptions) *Step {...@@ -1164,19 +1164,26 @@ pub fn addModuleTests(b: *std.Build, options: ModuleTestOptions) *Step {
1164 compile_c.addCSourceFile(.{1164 compile_c.addCSourceFile(.{
1165 .file = these_tests.getEmittedBin(),1165 .file = these_tests.getEmittedBin(),
1166 .flags = &.{1166 .flags = &.{
1167 // TODO output -std=c89 compatible C code1167 // Tracking issue for making the C backend generate C89 compatible code:
1168 // https://github.com/ziglang/zig/issues/19468
1168 "-std=c99",1169 "-std=c99",
1169 "-pedantic",1170 "-pedantic",
1170 "-Werror",1171 "-Werror",
1171 // TODO stop violating these pedantic errors. spotted everywhere1172
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
1172 "-Wno-builtin-requires-header",1178 "-Wno-builtin-requires-header",
1173 // TODO stop violating these pedantic errors. spotted on linux1179
1174 "-Wno-address-of-packed-member",1180 // spotted on linux
1175 "-Wno-gnu-folding-constant",1181 "-Wno-gnu-folding-constant",
1176 "-Wno-incompatible-function-pointer-types",1182 "-Wno-incompatible-function-pointer-types",
1177 "-Wno-incompatible-pointer-types",1183 "-Wno-incompatible-pointer-types",
1178 "-Wno-overlength-strings",1184 "-Wno-overlength-strings",
1179 // TODO stop violating these pedantic errors. spotted on darwin1185
1186 // spotted on darwin
1180 "-Wno-dollar-in-identifier-extension",1187 "-Wno-dollar-in-identifier-extension",
1181 "-Wno-absolute-value",1188 "-Wno-absolute-value",
1182 },1189 },
tools/lldb_pretty_printers.py+4-4
...@@ -354,7 +354,7 @@ def InstRef_SummaryProvider(value, _=None):...@@ -354,7 +354,7 @@ def InstRef_SummaryProvider(value, _=None):
354def InstIndex_SummaryProvider(value, _=None):354def InstIndex_SummaryProvider(value, _=None):
355 return 'instructions[%d]' % value.unsigned355 return 'instructions[%d]' % value.unsigned
356356
357class Module_Decl__Module_Decl_Index_SynthProvider:357class zig_DeclIndex_SynthProvider:
358 def __init__(self, value, _=None): self.value = value358 def __init__(self, value, _=None): self.value = value
359 def update(self):359 def update(self):
360 try:360 try:
...@@ -425,7 +425,7 @@ def InternPool_Find(thread):...@@ -425,7 +425,7 @@ def InternPool_Find(thread):
425 for frame in thread:425 for frame in thread:
426 ip = frame.FindVariable('ip') or frame.FindVariable('intern_pool')426 ip = frame.FindVariable('ip') or frame.FindVariable('intern_pool')
427 if ip: return ip427 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')
429 if mod:429 if mod:
430 ip = mod.GetChildMemberWithName('intern_pool')430 ip = mod.GetChildMemberWithName('intern_pool')
431 if ip: return ip431 if ip: return ip
...@@ -617,7 +617,7 @@ type_tag_handlers = {...@@ -617,7 +617,7 @@ type_tag_handlers = {
617617
618def value_Value_str_lit(payload):618def value_Value_str_lit(payload):
619 for frame in payload.thread:619 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')
621 if mod: break621 if mod: break
622 else: return622 else: return
623 return '"%s"' % zig_String_decode(mod.GetChildMemberWithName('string_literal_bytes').GetChildMemberWithName('items'), payload.GetChildMemberWithName('index').unsigned, payload.GetChildMemberWithName('len').unsigned)623 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):...@@ -714,7 +714,7 @@ def __lldb_init_module(debugger, _=None):
714 add(debugger, category='zig.stage2', type='Air.Inst::Air.Inst.Index', identifier='InstIndex', summary=True)714 add(debugger, category='zig.stage2', type='Air.Inst::Air.Inst.Index', identifier='InstIndex', summary=True)
715 add(debugger, category='zig.stage2', regex=True, type=MultiArrayList_Entry('Air\\.Inst'), identifier='TagAndPayload', synth=True, inline_children=True, summary=True)715 add(debugger, category='zig.stage2', regex=True, type=MultiArrayList_Entry('Air\\.Inst'), identifier='TagAndPayload', synth=True, inline_children=True, summary=True)
716 add(debugger, category='zig.stage2', regex=True, type='^Air\\.Inst\\.Data\\.Data__struct_[1-9][0-9]*$', inline_children=True, summary=True)716 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)
718 add(debugger, category='zig.stage2', type='Module.Namespace::Module.Namespace.Index', synth=True)718 add(debugger, category='zig.stage2', type='Module.Namespace::Module.Namespace.Index', synth=True)
719 add(debugger, category='zig.stage2', type='Module.LazySrcLoc', identifier='zig_TaggedUnion', synth=True)719 add(debugger, category='zig.stage2', type='Module.LazySrcLoc', identifier='zig_TaggedUnion', synth=True)
720 add(debugger, category='zig.stage2', type='InternPool.Index', synth=True)720 add(debugger, category='zig.stage2', type='InternPool.Index', synth=True)