Commit 5a41704f7e
Changed files (45)
lib
src
arch
wasm
x86_64
link
test
behavior
lib/std/c/darwin.zig
@@ -1150,8 +1150,8 @@ pub const siginfo_t = extern struct {
/// Renamed from `sigaction` to `Sigaction` to avoid conflict with function name.
pub const Sigaction = extern struct {
- pub const handler_fn = *align(1) const fn (c_int) callconv(.C) void;
- pub const sigaction_fn = *const fn (c_int, *const siginfo_t, ?*anyopaque) callconv(.C) void;
+ pub const handler_fn = *align(1) const fn (i32) callconv(.C) void;
+ pub const sigaction_fn = *const fn (i32, *const siginfo_t, ?*anyopaque) callconv(.C) void;
handler: extern union {
handler: ?handler_fn,
lib/std/c/dragonfly.zig
@@ -690,8 +690,8 @@ pub const empty_sigset = sigset_t{ .__bits = [_]c_uint{0} ** _SIG_WORDS };
pub const sig_atomic_t = c_int;
pub const Sigaction = extern struct {
- pub const handler_fn = *align(1) const fn (c_int) callconv(.C) void;
- pub const sigaction_fn = *const fn (c_int, *const siginfo_t, ?*anyopaque) callconv(.C) void;
+ pub const handler_fn = *align(1) const fn (i32) callconv(.C) void;
+ pub const sigaction_fn = *const fn (i32, *const siginfo_t, ?*anyopaque) callconv(.C) void;
/// signal handler
handler: extern union {
@@ -702,7 +702,7 @@ pub const Sigaction = extern struct {
mask: sigset_t,
};
-pub const sig_t = *const fn (c_int) callconv(.C) void;
+pub const sig_t = *const fn (i32) callconv(.C) void;
pub const SOCK = struct {
pub const STREAM = 1;
lib/std/c/freebsd.zig
@@ -1171,8 +1171,8 @@ const NSIG = 32;
/// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall.
pub const Sigaction = extern struct {
- pub const handler_fn = *align(1) const fn (c_int) callconv(.C) void;
- pub const sigaction_fn = *const fn (c_int, *const siginfo_t, ?*anyopaque) callconv(.C) void;
+ pub const handler_fn = *align(1) const fn (i32) callconv(.C) void;
+ pub const sigaction_fn = *const fn (i32, *const siginfo_t, ?*anyopaque) callconv(.C) void;
/// signal handler
handler: extern union {
lib/std/c/haiku.zig
@@ -501,7 +501,7 @@ pub const siginfo_t = extern struct {
/// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall.
pub const Sigaction = extern struct {
pub const handler_fn = *align(1) const fn (i32) callconv(.C) void;
- pub const sigaction_fn = *const fn (c_int, *allowzero anyopaque, ?*anyopaque) callconv(.C) void;
+ pub const sigaction_fn = *const fn (i32, *const siginfo_t, ?*anyopaque) callconv(.C) void;
/// signal handler
handler: extern union {
lib/std/c/netbsd.zig
@@ -864,8 +864,8 @@ pub const SIG = struct {
/// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall.
pub const Sigaction = extern struct {
- pub const handler_fn = *align(1) const fn (c_int) callconv(.C) void;
- pub const sigaction_fn = *const fn (c_int, *const siginfo_t, ?*anyopaque) callconv(.C) void;
+ pub const handler_fn = *align(1) const fn (i32) callconv(.C) void;
+ pub const sigaction_fn = *const fn (i32, *const siginfo_t, ?*anyopaque) callconv(.C) void;
/// signal handler
handler: extern union {
lib/std/c/openbsd.zig
@@ -842,8 +842,8 @@ pub const SIG = struct {
/// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall.
pub const Sigaction = extern struct {
- pub const handler_fn = *align(1) const fn (c_int) callconv(.C) void;
- pub const sigaction_fn = *const fn (c_int, *const siginfo_t, ?*anyopaque) callconv(.C) void;
+ pub const handler_fn = *align(1) const fn (i32) callconv(.C) void;
+ pub const sigaction_fn = *const fn (i32, *const siginfo_t, ?*anyopaque) callconv(.C) void;
/// signal handler
handler: extern union {
lib/std/c/solaris.zig
@@ -874,8 +874,8 @@ pub const SIG = struct {
/// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall.
pub const Sigaction = extern struct {
- pub const handler_fn = *align(1) const fn (c_int) callconv(.C) void;
- pub const sigaction_fn = *const fn (c_int, *const siginfo_t, ?*anyopaque) callconv(.C) void;
+ pub const handler_fn = *align(1) const fn (i32) callconv(.C) void;
+ pub const sigaction_fn = *const fn (i32, *const siginfo_t, ?*anyopaque) callconv(.C) void;
/// signal options
flags: c_uint,
lib/std/os/emscripten.zig
@@ -695,8 +695,8 @@ pub const SIG = struct {
};
pub const Sigaction = extern struct {
- pub const handler_fn = *align(1) const fn (c_int) callconv(.C) void;
- pub const sigaction_fn = *const fn (c_int, *const siginfo_t, ?*anyopaque) callconv(.C) void;
+ pub const handler_fn = *align(1) const fn (i32) callconv(.C) void;
+ pub const sigaction_fn = *const fn (i32, *const siginfo_t, ?*anyopaque) callconv(.C) void;
handler: extern union {
handler: ?handler_fn,
lib/std/os/linux.zig
@@ -4301,7 +4301,7 @@ pub const all_mask: sigset_t = [_]u32{0xffffffff} ** @typeInfo(sigset_t).Array.l
pub const app_mask: sigset_t = [2]u32{ 0xfffffffc, 0x7fffffff } ++ [_]u32{0xffffffff} ** 30;
const k_sigaction_funcs = struct {
- const handler = ?*align(1) const fn (c_int) callconv(.C) void;
+ const handler = ?*align(1) const fn (i32) callconv(.C) void;
const restorer = *const fn () callconv(.C) void;
};
@@ -4328,8 +4328,8 @@ pub const k_sigaction = switch (native_arch) {
/// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall.
pub const Sigaction = extern struct {
- pub const handler_fn = *align(1) const fn (c_int) callconv(.C) void;
- pub const sigaction_fn = *const fn (c_int, *const siginfo_t, ?*anyopaque) callconv(.C) void;
+ pub const handler_fn = *align(1) const fn (i32) callconv(.C) void;
+ pub const sigaction_fn = *const fn (i32, *const siginfo_t, ?*anyopaque) callconv(.C) void;
handler: extern union {
handler: ?handler_fn,
lib/std/os/plan9.zig
@@ -186,8 +186,8 @@ pub const empty_sigset = 0;
pub const siginfo_t = c_long;
// TODO plan9 doesn't have sigaction_fn. Sigaction is not a union, but we incude it here to be compatible.
pub const Sigaction = extern struct {
- pub const handler_fn = *const fn (c_int) callconv(.C) void;
- pub const sigaction_fn = *const fn (c_int, *const siginfo_t, ?*anyopaque) callconv(.C) void;
+ pub const handler_fn = *const fn (i32) callconv(.C) void;
+ pub const sigaction_fn = *const fn (i32, *const siginfo_t, ?*anyopaque) callconv(.C) void;
handler: extern union {
handler: ?handler_fn,
lib/std/debug.zig
@@ -2570,7 +2570,7 @@ fn resetSegfaultHandler() void {
updateSegfaultHandler(&act) catch {};
}
-fn handleSegfaultPosix(sig: i32, info: *const posix.siginfo_t, ctx_ptr: ?*const anyopaque) callconv(.C) noreturn {
+fn handleSegfaultPosix(sig: i32, info: *const posix.siginfo_t, ctx_ptr: ?*anyopaque) callconv(.C) noreturn {
// Reset to the default handler so that if a segfault happens in this handler it will crash
// the process. Also when this handler returns, the original instruction will be repeated
// and the resulting segfault will crash the process rather than continually dump stack traces.
lib/std/start.zig
@@ -597,4 +597,4 @@ fn maybeIgnoreSigpipe() void {
}
}
-fn noopSigHandler(_: c_int) callconv(.C) void {}
+fn noopSigHandler(_: i32) callconv(.C) void {}
src/arch/wasm/CodeGen.zig
@@ -1296,7 +1296,7 @@ fn genFunc(func: *CodeGen) InnerError!void {
// subtract it from the current stack pointer
try prologue.append(.{ .tag = .i32_sub, .data = .{ .tag = {} } });
// Get negative stack aligment
- try prologue.append(.{ .tag = .i32_const, .data = .{ .imm32 = @as(i32, @intCast(func.stack_alignment.toByteUnitsOptional().?)) * -1 } });
+ try prologue.append(.{ .tag = .i32_const, .data = .{ .imm32 = @as(i32, @intCast(func.stack_alignment.toByteUnits().?)) * -1 } });
// Bitwise-and the value to get the new stack pointer to ensure the pointers are aligned with the abi alignment
try prologue.append(.{ .tag = .i32_and, .data = .{ .tag = {} } });
// 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 {
});
try func.addMemArg(Mir.Inst.Tag.fromOpcode(opcode), .{
.offset = operand.offset(),
- .alignment = @intCast(scalar_type.abiAlignment(mod).toByteUnitsOptional().?),
+ .alignment = @intCast(scalar_type.abiAlignment(mod).toByteUnits().?),
});
},
else => try func.emitWValue(operand),
@@ -2384,7 +2384,7 @@ fn store(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerE
try func.mir_extra.appendSlice(func.gpa, &[_]u32{
std.wasm.simdOpcode(.v128_store),
offset + lhs.offset(),
- @intCast(ty.abiAlignment(mod).toByteUnits(0)),
+ @intCast(ty.abiAlignment(mod).toByteUnits() orelse 0),
});
return func.addInst(.{ .tag = .simd_prefix, .data = .{ .payload = extra_index } });
},
@@ -2440,7 +2440,7 @@ fn store(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerE
Mir.Inst.Tag.fromOpcode(opcode),
.{
.offset = offset + lhs.offset(),
- .alignment = @intCast(ty.abiAlignment(mod).toByteUnitsOptional().?),
+ .alignment = @intCast(ty.abiAlignment(mod).toByteUnits().?),
},
);
}
@@ -2500,7 +2500,7 @@ fn load(func: *CodeGen, operand: WValue, ty: Type, offset: u32) InnerError!WValu
try func.mir_extra.appendSlice(func.gpa, &[_]u32{
std.wasm.simdOpcode(.v128_load),
offset + operand.offset(),
- @intCast(ty.abiAlignment(mod).toByteUnitsOptional().?),
+ @intCast(ty.abiAlignment(mod).toByteUnits().?),
});
try func.addInst(.{ .tag = .simd_prefix, .data = .{ .payload = extra_index } });
return WValue{ .stack = {} };
@@ -2518,7 +2518,7 @@ fn load(func: *CodeGen, operand: WValue, ty: Type, offset: u32) InnerError!WValu
Mir.Inst.Tag.fromOpcode(opcode),
.{
.offset = offset + operand.offset(),
- .alignment = @intCast(ty.abiAlignment(mod).toByteUnitsOptional().?),
+ .alignment = @intCast(ty.abiAlignment(mod).toByteUnits().?),
},
);
@@ -3456,7 +3456,7 @@ fn intStorageAsI32(storage: InternPool.Key.Int.Storage, mod: *Module) i32 {
.i64 => |x| @as(i32, @intCast(x)),
.u64 => |x| @as(i32, @bitCast(@as(u32, @intCast(x)))),
.big_int => unreachable,
- .lazy_align => |ty| @as(i32, @bitCast(@as(u32, @intCast(Type.fromInterned(ty).abiAlignment(mod).toByteUnits(0))))),
+ .lazy_align => |ty| @as(i32, @bitCast(@as(u32, @intCast(Type.fromInterned(ty).abiAlignment(mod).toByteUnits() orelse 0)))),
.lazy_size => |ty| @as(i32, @bitCast(@as(u32, @intCast(Type.fromInterned(ty).abiSize(mod))))),
};
}
@@ -4204,7 +4204,7 @@ fn airIsErr(func: *CodeGen, inst: Air.Inst.Index, opcode: wasm.Opcode) InnerErro
if (pl_ty.hasRuntimeBitsIgnoreComptime(mod)) {
try func.addMemArg(.i32_load16_u, .{
.offset = operand.offset() + @as(u32, @intCast(errUnionErrorOffset(pl_ty, mod))),
- .alignment = @intCast(Type.anyerror.abiAlignment(mod).toByteUnitsOptional().?),
+ .alignment = @intCast(Type.anyerror.abiAlignment(mod).toByteUnits().?),
});
}
@@ -5141,7 +5141,7 @@ fn airSplat(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
try func.mir_extra.appendSlice(func.gpa, &[_]u32{
opcode,
operand.offset(),
- @intCast(elem_ty.abiAlignment(mod).toByteUnitsOptional().?),
+ @intCast(elem_ty.abiAlignment(mod).toByteUnits().?),
});
try func.addInst(.{ .tag = .simd_prefix, .data = .{ .payload = extra_index } });
try func.addLabel(.local_set, result.local.value);
@@ -6552,7 +6552,7 @@ fn lowerTry(
const err_offset = @as(u32, @intCast(errUnionErrorOffset(pl_ty, mod)));
try func.addMemArg(.i32_load16_u, .{
.offset = err_union.offset() + err_offset,
- .alignment = @intCast(Type.anyerror.abiAlignment(mod).toByteUnitsOptional().?),
+ .alignment = @intCast(Type.anyerror.abiAlignment(mod).toByteUnits().?),
});
}
try func.addTag(.i32_eqz);
@@ -7499,7 +7499,7 @@ fn airCmpxchg(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
else => |size| return func.fail("TODO: implement `@cmpxchg` for types with abi size '{d}'", .{size}),
}, .{
.offset = ptr_operand.offset(),
- .alignment = @intCast(ty.abiAlignment(mod).toByteUnitsOptional().?),
+ .alignment = @intCast(ty.abiAlignment(mod).toByteUnits().?),
});
try func.addLabel(.local_tee, val_local.local.value);
_ = try func.cmp(.stack, expected_val, ty, .eq);
@@ -7561,7 +7561,7 @@ fn airAtomicLoad(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
try func.emitWValue(ptr);
try func.addAtomicMemArg(tag, .{
.offset = ptr.offset(),
- .alignment = @intCast(ty.abiAlignment(mod).toByteUnitsOptional().?),
+ .alignment = @intCast(ty.abiAlignment(mod).toByteUnits().?),
});
} else {
_ = try func.load(ptr, ty, 0);
@@ -7622,7 +7622,7 @@ fn airAtomicRmw(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
},
.{
.offset = ptr.offset(),
- .alignment = @intCast(ty.abiAlignment(mod).toByteUnitsOptional().?),
+ .alignment = @intCast(ty.abiAlignment(mod).toByteUnits().?),
},
);
const select_res = try func.allocLocal(ty);
@@ -7682,7 +7682,7 @@ fn airAtomicRmw(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
};
try func.addAtomicMemArg(tag, .{
.offset = ptr.offset(),
- .alignment = @intCast(ty.abiAlignment(mod).toByteUnitsOptional().?),
+ .alignment = @intCast(ty.abiAlignment(mod).toByteUnits().?),
});
const result = try WValue.toLocal(.stack, func, ty);
return func.finishAir(inst, result, &.{ pl_op.operand, extra.operand });
@@ -7781,7 +7781,7 @@ fn airAtomicStore(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
try func.lowerToStack(operand);
try func.addAtomicMemArg(tag, .{
.offset = ptr.offset(),
- .alignment = @intCast(ty.abiAlignment(mod).toByteUnitsOptional().?),
+ .alignment = @intCast(ty.abiAlignment(mod).toByteUnits().?),
});
} else {
try func.store(ptr, operand, ty, 0);
src/arch/x86_64/CodeGen.zig
@@ -18959,7 +18959,7 @@ fn resolveCallingConventionValues(
const param_size: u31 = @intCast(ty.abiSize(mod));
const param_align: u31 =
- @intCast(@max(ty.abiAlignment(mod).toByteUnitsOptional().?, 8));
+ @intCast(@max(ty.abiAlignment(mod).toByteUnits().?, 8));
result.stack_byte_count =
mem.alignForward(u31, result.stack_byte_count, param_align);
arg.* = .{ .load_frame = .{
@@ -19003,7 +19003,7 @@ fn resolveCallingConventionValues(
continue;
}
const param_size: u31 = @intCast(ty.abiSize(mod));
- const param_align: u31 = @intCast(ty.abiAlignment(mod).toByteUnitsOptional().?);
+ const param_align: u31 = @intCast(ty.abiAlignment(mod).toByteUnits().?);
result.stack_byte_count =
mem.alignForward(u31, result.stack_byte_count, param_align);
arg.* = .{ .load_frame = .{
@@ -19096,7 +19096,7 @@ fn splitType(self: *Self, ty: Type) ![2]Type {
.integer => switch (part_i) {
0 => Type.u64,
1 => part: {
- const elem_size = ty.abiAlignment(mod).minStrict(.@"8").toByteUnitsOptional().?;
+ const elem_size = ty.abiAlignment(mod).minStrict(.@"8").toByteUnits().?;
const elem_ty = try mod.intType(.unsigned, @intCast(elem_size * 8));
break :part switch (@divExact(ty.abiSize(mod) - 8, elem_size)) {
1 => elem_ty,
src/codegen/c/Type.zig
@@ -0,0 +1,2472 @@
+index: CType.Index,
+
+pub fn fromPoolIndex(pool_index: usize) CType {
+ return .{ .index = @enumFromInt(CType.Index.first_pool_index + pool_index) };
+}
+
+pub fn toPoolIndex(ctype: CType) ?u32 {
+ const pool_index, const is_basic =
+ @subWithOverflow(@intFromEnum(ctype.index), CType.Index.first_pool_index);
+ return switch (is_basic) {
+ 0 => pool_index,
+ 1 => null,
+ };
+}
+
+pub fn eql(lhs: CType, rhs: CType) bool {
+ return lhs.index == rhs.index;
+}
+
+pub fn isBool(ctype: CType) bool {
+ return switch (ctype.index) {
+ ._Bool, .bool => true,
+ else => false,
+ };
+}
+
+pub fn isInteger(ctype: CType) bool {
+ return switch (ctype.index) {
+ .char,
+ .@"signed char",
+ .short,
+ .int,
+ .long,
+ .@"long long",
+ .@"unsigned char",
+ .@"unsigned short",
+ .@"unsigned int",
+ .@"unsigned long",
+ .@"unsigned long long",
+ .size_t,
+ .ptrdiff_t,
+ .uint8_t,
+ .int8_t,
+ .uint16_t,
+ .int16_t,
+ .uint32_t,
+ .int32_t,
+ .uint64_t,
+ .int64_t,
+ .uintptr_t,
+ .intptr_t,
+ .zig_u128,
+ .zig_i128,
+ => true,
+ else => false,
+ };
+}
+
+pub fn signedness(ctype: CType, mod: *Module) std.builtin.Signedness {
+ return switch (ctype.index) {
+ .char => mod.resolved_target.result.charSignedness(),
+ .@"signed char",
+ .short,
+ .int,
+ .long,
+ .@"long long",
+ .ptrdiff_t,
+ .int8_t,
+ .int16_t,
+ .int32_t,
+ .int64_t,
+ .intptr_t,
+ .zig_i128,
+ => .signed,
+ .@"unsigned char",
+ .@"unsigned short",
+ .@"unsigned int",
+ .@"unsigned long",
+ .@"unsigned long long",
+ .size_t,
+ .uint8_t,
+ .uint16_t,
+ .uint32_t,
+ .uint64_t,
+ .uintptr_t,
+ .zig_u128,
+ => .unsigned,
+ else => unreachable,
+ };
+}
+
+pub fn isFloat(ctype: CType) bool {
+ return switch (ctype.index) {
+ .float,
+ .double,
+ .@"long double",
+ .zig_f16,
+ .zig_f32,
+ .zig_f64,
+ .zig_f80,
+ .zig_f128,
+ .zig_c_longdouble,
+ => true,
+ else => false,
+ };
+}
+
+pub fn toSigned(ctype: CType) CType {
+ return switch (ctype.index) {
+ .char, .@"signed char", .@"unsigned char" => .{ .index = .@"signed char" },
+ .short, .@"unsigned short" => .{ .index = .short },
+ .int, .@"unsigned int" => .{ .index = .int },
+ .long, .@"unsigned long" => .{ .index = .long },
+ .@"long long", .@"unsigned long long" => .{ .index = .@"long long" },
+ .size_t, .ptrdiff_t => .{ .index = .ptrdiff_t },
+ .uint8_t, .int8_t => .{ .index = .int8_t },
+ .uint16_t, .int16_t => .{ .index = .int16_t },
+ .uint32_t, .int32_t => .{ .index = .int32_t },
+ .uint64_t, .int64_t => .{ .index = .int64_t },
+ .uintptr_t, .intptr_t => .{ .index = .intptr_t },
+ .zig_u128, .zig_i128 => .{ .index = .zig_i128 },
+ .float,
+ .double,
+ .@"long double",
+ .zig_f16,
+ .zig_f32,
+ .zig_f80,
+ .zig_f128,
+ .zig_c_longdouble,
+ => ctype,
+ else => unreachable,
+ };
+}
+
+pub fn toUnsigned(ctype: CType) CType {
+ return switch (ctype.index) {
+ .char, .@"signed char", .@"unsigned char" => .{ .index = .@"unsigned char" },
+ .short, .@"unsigned short" => .{ .index = .@"unsigned short" },
+ .int, .@"unsigned int" => .{ .index = .@"unsigned int" },
+ .long, .@"unsigned long" => .{ .index = .@"unsigned long" },
+ .@"long long", .@"unsigned long long" => .{ .index = .@"unsigned long long" },
+ .size_t, .ptrdiff_t => .{ .index = .size_t },
+ .uint8_t, .int8_t => .{ .index = .uint8_t },
+ .uint16_t, .int16_t => .{ .index = .uint16_t },
+ .uint32_t, .int32_t => .{ .index = .uint32_t },
+ .uint64_t, .int64_t => .{ .index = .uint64_t },
+ .uintptr_t, .intptr_t => .{ .index = .uintptr_t },
+ .zig_u128, .zig_i128 => .{ .index = .zig_u128 },
+ else => unreachable,
+ };
+}
+
+pub fn toSignedness(ctype: CType, s: std.builtin.Signedness) CType {
+ return switch (s) {
+ .unsigned => ctype.toUnsigned(),
+ .signed => ctype.toSigned(),
+ };
+}
+
+pub fn getStandardDefineAbbrev(ctype: CType) ?[]const u8 {
+ return switch (ctype.index) {
+ .char => "CHAR",
+ .@"signed char" => "SCHAR",
+ .short => "SHRT",
+ .int => "INT",
+ .long => "LONG",
+ .@"long long" => "LLONG",
+ .@"unsigned char" => "UCHAR",
+ .@"unsigned short" => "USHRT",
+ .@"unsigned int" => "UINT",
+ .@"unsigned long" => "ULONG",
+ .@"unsigned long long" => "ULLONG",
+ .float => "FLT",
+ .double => "DBL",
+ .@"long double" => "LDBL",
+ .size_t => "SIZE",
+ .ptrdiff_t => "PTRDIFF",
+ .uint8_t => "UINT8",
+ .int8_t => "INT8",
+ .uint16_t => "UINT16",
+ .int16_t => "INT16",
+ .uint32_t => "UINT32",
+ .int32_t => "INT32",
+ .uint64_t => "UINT64",
+ .int64_t => "INT64",
+ .uintptr_t => "UINTPTR",
+ .intptr_t => "INTPTR",
+ else => null,
+ };
+}
+
+pub fn renderLiteralPrefix(ctype: CType, writer: anytype, kind: Kind, pool: *const Pool) @TypeOf(writer).Error!void {
+ switch (ctype.info(pool)) {
+ .basic => |basic_info| switch (basic_info) {
+ .void => unreachable,
+ ._Bool,
+ .char,
+ .@"signed char",
+ .short,
+ .@"unsigned short",
+ .bool,
+ .size_t,
+ .ptrdiff_t,
+ .uintptr_t,
+ .intptr_t,
+ => switch (kind) {
+ else => try writer.print("({s})", .{@tagName(basic_info)}),
+ .global => {},
+ },
+ .int,
+ .long,
+ .@"long long",
+ .@"unsigned char",
+ .@"unsigned int",
+ .@"unsigned long",
+ .@"unsigned long long",
+ .float,
+ .double,
+ .@"long double",
+ => {},
+ .uint8_t,
+ .int8_t,
+ .uint16_t,
+ .int16_t,
+ .uint32_t,
+ .int32_t,
+ .uint64_t,
+ .int64_t,
+ => try writer.print("{s}_C(", .{ctype.getStandardDefineAbbrev().?}),
+ .zig_u128,
+ .zig_i128,
+ .zig_f16,
+ .zig_f32,
+ .zig_f64,
+ .zig_f80,
+ .zig_f128,
+ .zig_c_longdouble,
+ => try writer.print("zig_{s}_{s}(", .{
+ switch (kind) {
+ else => "make",
+ .global => "init",
+ },
+ @tagName(basic_info)["zig_".len..],
+ }),
+ .va_list => unreachable,
+ _ => unreachable,
+ },
+ .array, .vector => try writer.writeByte('{'),
+ else => unreachable,
+ }
+}
+
+pub fn renderLiteralSuffix(ctype: CType, writer: anytype, pool: *const Pool) @TypeOf(writer).Error!void {
+ switch (ctype.info(pool)) {
+ .basic => |basic_info| switch (basic_info) {
+ .void => unreachable,
+ ._Bool => {},
+ .char,
+ .@"signed char",
+ .short,
+ .int,
+ => {},
+ .long => try writer.writeByte('l'),
+ .@"long long" => try writer.writeAll("ll"),
+ .@"unsigned char",
+ .@"unsigned short",
+ .@"unsigned int",
+ => try writer.writeByte('u'),
+ .@"unsigned long",
+ .size_t,
+ .uintptr_t,
+ => try writer.writeAll("ul"),
+ .@"unsigned long long" => try writer.writeAll("ull"),
+ .float => try writer.writeByte('f'),
+ .double => {},
+ .@"long double" => try writer.writeByte('l'),
+ .bool,
+ .ptrdiff_t,
+ .intptr_t,
+ => {},
+ .uint8_t,
+ .int8_t,
+ .uint16_t,
+ .int16_t,
+ .uint32_t,
+ .int32_t,
+ .uint64_t,
+ .int64_t,
+ .zig_u128,
+ .zig_i128,
+ .zig_f16,
+ .zig_f32,
+ .zig_f64,
+ .zig_f80,
+ .zig_f128,
+ .zig_c_longdouble,
+ => try writer.writeByte(')'),
+ .va_list => unreachable,
+ _ => unreachable,
+ },
+ .array, .vector => try writer.writeByte('}'),
+ else => unreachable,
+ }
+}
+
+pub fn floatActiveBits(ctype: CType, mod: *Module) u16 {
+ const target = &mod.resolved_target.result;
+ return switch (ctype.index) {
+ .float => target.c_type_bit_size(.float),
+ .double => target.c_type_bit_size(.double),
+ .@"long double", .zig_c_longdouble => target.c_type_bit_size(.longdouble),
+ .zig_f16 => 16,
+ .zig_f32 => 32,
+ .zig_f64 => 64,
+ .zig_f80 => 80,
+ .zig_f128 => 128,
+ else => unreachable,
+ };
+}
+
+pub fn byteSize(ctype: CType, pool: *const Pool, mod: *Module) u64 {
+ const target = &mod.resolved_target.result;
+ return switch (ctype.info(pool)) {
+ .basic => |basic_info| switch (basic_info) {
+ .void => 0,
+ .char, .@"signed char", ._Bool, .@"unsigned char", .bool, .uint8_t, .int8_t => 1,
+ .short => target.c_type_byte_size(.short),
+ .int => target.c_type_byte_size(.int),
+ .long => target.c_type_byte_size(.long),
+ .@"long long" => target.c_type_byte_size(.longlong),
+ .@"unsigned short" => target.c_type_byte_size(.ushort),
+ .@"unsigned int" => target.c_type_byte_size(.uint),
+ .@"unsigned long" => target.c_type_byte_size(.ulong),
+ .@"unsigned long long" => target.c_type_byte_size(.ulonglong),
+ .float => target.c_type_byte_size(.float),
+ .double => target.c_type_byte_size(.double),
+ .@"long double" => target.c_type_byte_size(.longdouble),
+ .size_t,
+ .ptrdiff_t,
+ .uintptr_t,
+ .intptr_t,
+ => @divExact(target.ptrBitWidth(), 8),
+ .uint16_t, .int16_t, .zig_f16 => 2,
+ .uint32_t, .int32_t, .zig_f32 => 4,
+ .uint64_t, .int64_t, .zig_f64 => 8,
+ .zig_u128, .zig_i128, .zig_f128 => 16,
+ .zig_f80 => if (target.c_type_bit_size(.longdouble) == 80)
+ target.c_type_byte_size(.longdouble)
+ else
+ 16,
+ .zig_c_longdouble => target.c_type_byte_size(.longdouble),
+ .va_list => unreachable,
+ _ => unreachable,
+ },
+ .pointer => @divExact(target.ptrBitWidth(), 8),
+ .array, .vector => |sequence_info| sequence_info.elem_ctype.byteSize(pool, mod) * sequence_info.len,
+ else => unreachable,
+ };
+}
+
+pub fn info(ctype: CType, pool: *const Pool) Info {
+ const pool_index = ctype.toPoolIndex() orelse return .{ .basic = ctype.index };
+ const item = pool.items.get(pool_index);
+ switch (item.tag) {
+ .basic => unreachable,
+ .pointer => return .{ .pointer = .{
+ .elem_ctype = .{ .index = @enumFromInt(item.data) },
+ } },
+ .pointer_const => return .{ .pointer = .{
+ .elem_ctype = .{ .index = @enumFromInt(item.data) },
+ .@"const" = true,
+ } },
+ .pointer_volatile => return .{ .pointer = .{
+ .elem_ctype = .{ .index = @enumFromInt(item.data) },
+ .@"volatile" = true,
+ } },
+ .pointer_const_volatile => return .{ .pointer = .{
+ .elem_ctype = .{ .index = @enumFromInt(item.data) },
+ .@"const" = true,
+ .@"volatile" = true,
+ } },
+ .aligned => {
+ const extra = pool.getExtra(Pool.Aligned, item.data);
+ return .{ .aligned = .{
+ .ctype = .{ .index = extra.ctype },
+ .alignas = extra.flags.alignas,
+ } };
+ },
+ .array_small => {
+ const extra = pool.getExtra(Pool.SequenceSmall, item.data);
+ return .{ .array = .{
+ .elem_ctype = .{ .index = extra.elem_ctype },
+ .len = extra.len,
+ } };
+ },
+ .array_large => {
+ const extra = pool.getExtra(Pool.SequenceLarge, item.data);
+ return .{ .array = .{
+ .elem_ctype = .{ .index = extra.elem_ctype },
+ .len = extra.len(),
+ } };
+ },
+ .vector => {
+ const extra = pool.getExtra(Pool.SequenceSmall, item.data);
+ return .{ .vector = .{
+ .elem_ctype = .{ .index = extra.elem_ctype },
+ .len = extra.len,
+ } };
+ },
+ .fwd_decl_struct_anon => {
+ const extra_trail = pool.getExtraTrail(Pool.FwdDeclAnon, item.data);
+ return .{ .fwd_decl = .{
+ .tag = .@"struct",
+ .name = .{ .anon = .{
+ .extra_index = extra_trail.trail.extra_index,
+ .len = extra_trail.extra.fields_len,
+ } },
+ } };
+ },
+ .fwd_decl_union_anon => {
+ const extra_trail = pool.getExtraTrail(Pool.FwdDeclAnon, item.data);
+ return .{ .fwd_decl = .{
+ .tag = .@"union",
+ .name = .{ .anon = .{
+ .extra_index = extra_trail.trail.extra_index,
+ .len = extra_trail.extra.fields_len,
+ } },
+ } };
+ },
+ .fwd_decl_struct => return .{ .fwd_decl = .{
+ .tag = .@"struct",
+ .name = .{ .owner_decl = @enumFromInt(item.data) },
+ } },
+ .fwd_decl_union => return .{ .fwd_decl = .{
+ .tag = .@"union",
+ .name = .{ .owner_decl = @enumFromInt(item.data) },
+ } },
+ .aggregate_struct_anon => {
+ const extra_trail = pool.getExtraTrail(Pool.AggregateAnon, item.data);
+ return .{ .aggregate = .{
+ .tag = .@"struct",
+ .name = .{ .anon = .{
+ .owner_decl = extra_trail.extra.owner_decl,
+ .id = extra_trail.extra.id,
+ } },
+ .fields = .{
+ .extra_index = extra_trail.trail.extra_index,
+ .len = extra_trail.extra.fields_len,
+ },
+ } };
+ },
+ .aggregate_union_anon => {
+ const extra_trail = pool.getExtraTrail(Pool.AggregateAnon, item.data);
+ return .{ .aggregate = .{
+ .tag = .@"union",
+ .name = .{ .anon = .{
+ .owner_decl = extra_trail.extra.owner_decl,
+ .id = extra_trail.extra.id,
+ } },
+ .fields = .{
+ .extra_index = extra_trail.trail.extra_index,
+ .len = extra_trail.extra.fields_len,
+ },
+ } };
+ },
+ .aggregate_struct_packed_anon => {
+ const extra_trail = pool.getExtraTrail(Pool.AggregateAnon, item.data);
+ return .{ .aggregate = .{
+ .tag = .@"struct",
+ .@"packed" = true,
+ .name = .{ .anon = .{
+ .owner_decl = extra_trail.extra.owner_decl,
+ .id = extra_trail.extra.id,
+ } },
+ .fields = .{
+ .extra_index = extra_trail.trail.extra_index,
+ .len = extra_trail.extra.fields_len,
+ },
+ } };
+ },
+ .aggregate_union_packed_anon => {
+ const extra_trail = pool.getExtraTrail(Pool.AggregateAnon, item.data);
+ return .{ .aggregate = .{
+ .tag = .@"union",
+ .@"packed" = true,
+ .name = .{ .anon = .{
+ .owner_decl = extra_trail.extra.owner_decl,
+ .id = extra_trail.extra.id,
+ } },
+ .fields = .{
+ .extra_index = extra_trail.trail.extra_index,
+ .len = extra_trail.extra.fields_len,
+ },
+ } };
+ },
+ .aggregate_struct => {
+ const extra_trail = pool.getExtraTrail(Pool.Aggregate, item.data);
+ return .{ .aggregate = .{
+ .tag = .@"struct",
+ .name = .{ .fwd_decl = .{ .index = extra_trail.extra.fwd_decl } },
+ .fields = .{
+ .extra_index = extra_trail.trail.extra_index,
+ .len = extra_trail.extra.fields_len,
+ },
+ } };
+ },
+ .aggregate_union => {
+ const extra_trail = pool.getExtraTrail(Pool.Aggregate, item.data);
+ return .{ .aggregate = .{
+ .tag = .@"union",
+ .name = .{ .fwd_decl = .{ .index = extra_trail.extra.fwd_decl } },
+ .fields = .{
+ .extra_index = extra_trail.trail.extra_index,
+ .len = extra_trail.extra.fields_len,
+ },
+ } };
+ },
+ .aggregate_struct_packed => {
+ const extra_trail = pool.getExtraTrail(Pool.Aggregate, item.data);
+ return .{ .aggregate = .{
+ .tag = .@"struct",
+ .@"packed" = true,
+ .name = .{ .fwd_decl = .{ .index = extra_trail.extra.fwd_decl } },
+ .fields = .{
+ .extra_index = extra_trail.trail.extra_index,
+ .len = extra_trail.extra.fields_len,
+ },
+ } };
+ },
+ .aggregate_union_packed => {
+ const extra_trail = pool.getExtraTrail(Pool.Aggregate, item.data);
+ return .{ .aggregate = .{
+ .tag = .@"union",
+ .@"packed" = true,
+ .name = .{ .fwd_decl = .{ .index = extra_trail.extra.fwd_decl } },
+ .fields = .{
+ .extra_index = extra_trail.trail.extra_index,
+ .len = extra_trail.extra.fields_len,
+ },
+ } };
+ },
+ .function => {
+ const extra_trail = pool.getExtraTrail(Pool.Function, item.data);
+ return .{ .function = .{
+ .return_ctype = .{ .index = extra_trail.extra.return_ctype },
+ .param_ctypes = .{
+ .extra_index = extra_trail.trail.extra_index,
+ .len = extra_trail.extra.param_ctypes_len,
+ },
+ .varargs = false,
+ } };
+ },
+ .function_varargs => {
+ const extra_trail = pool.getExtraTrail(Pool.Function, item.data);
+ return .{ .function = .{
+ .return_ctype = .{ .index = extra_trail.extra.return_ctype },
+ .param_ctypes = .{
+ .extra_index = extra_trail.trail.extra_index,
+ .len = extra_trail.extra.param_ctypes_len,
+ },
+ .varargs = true,
+ } };
+ },
+ }
+}
+
+pub fn hash(ctype: CType, pool: *const Pool) Pool.Map.Hash {
+ return if (ctype.toPoolIndex()) |pool_index|
+ pool.map.entries.items(.hash)[pool_index]
+ else
+ CType.Index.basic_hashes[@intFromEnum(ctype.index)];
+}
+
+fn toForward(ctype: CType, pool: *Pool, allocator: std.mem.Allocator) !CType {
+ return switch (ctype.info(pool)) {
+ .basic, .pointer, .fwd_decl => ctype,
+ .aligned => |aligned_info| pool.getAligned(allocator, .{
+ .ctype = try aligned_info.ctype.toForward(pool, allocator),
+ .alignas = aligned_info.alignas,
+ }),
+ .array => |array_info| pool.getArray(allocator, .{
+ .elem_ctype = try array_info.elem_ctype.toForward(pool, allocator),
+ .len = array_info.len,
+ }),
+ .vector => |vector_info| pool.getVector(allocator, .{
+ .elem_ctype = try vector_info.elem_ctype.toForward(pool, allocator),
+ .len = vector_info.len,
+ }),
+ .aggregate => |aggregate_info| switch (aggregate_info.name) {
+ .anon => ctype,
+ .fwd_decl => |fwd_decl| fwd_decl,
+ },
+ .function => unreachable,
+ };
+}
+
+const Index = enum(u32) {
+ void,
+
+ // C basic types
+ char,
+
+ @"signed char",
+ short,
+ int,
+ long,
+ @"long long",
+
+ _Bool,
+ @"unsigned char",
+ @"unsigned short",
+ @"unsigned int",
+ @"unsigned long",
+ @"unsigned long long",
+
+ float,
+ double,
+ @"long double",
+
+ // C header types
+ // - stdbool.h
+ bool,
+ // - stddef.h
+ size_t,
+ ptrdiff_t,
+ // - stdint.h
+ uint8_t,
+ int8_t,
+ uint16_t,
+ int16_t,
+ uint32_t,
+ int32_t,
+ uint64_t,
+ int64_t,
+ uintptr_t,
+ intptr_t,
+ // - stdarg.h
+ va_list,
+
+ // zig.h types
+ zig_u128,
+ zig_i128,
+ zig_f16,
+ zig_f32,
+ zig_f64,
+ zig_f80,
+ zig_f128,
+ zig_c_longdouble,
+
+ _,
+
+ const first_pool_index: u32 = @typeInfo(CType.Index).Enum.fields.len;
+ const basic_hashes = init: {
+ @setEvalBranchQuota(1_600);
+ var basic_hashes_init: [first_pool_index]Pool.Map.Hash = undefined;
+ for (&basic_hashes_init, 0..) |*basic_hash, index| {
+ const ctype_index: CType.Index = @enumFromInt(index);
+ var hasher = Pool.Hasher.init;
+ hasher.update(@intFromEnum(ctype_index));
+ basic_hash.* = hasher.final(.basic);
+ }
+ break :init basic_hashes_init;
+ };
+};
+
+const Slice = struct {
+ extra_index: Pool.ExtraIndex,
+ len: u32,
+
+ pub fn at(slice: CType.Slice, index: usize, pool: *const Pool) CType {
+ var extra: Pool.ExtraTrail = .{ .extra_index = slice.extra_index };
+ return .{ .index = extra.next(slice.len, CType.Index, pool)[index] };
+ }
+};
+
+pub const Kind = enum {
+ forward,
+ forward_parameter,
+ complete,
+ global,
+ parameter,
+
+ pub fn isForward(kind: Kind) bool {
+ return switch (kind) {
+ .forward, .forward_parameter => true,
+ .complete, .global, .parameter => false,
+ };
+ }
+
+ pub fn isParameter(kind: Kind) bool {
+ return switch (kind) {
+ .forward_parameter, .parameter => true,
+ .forward, .complete, .global => false,
+ };
+ }
+
+ pub fn asParameter(kind: Kind) Kind {
+ return switch (kind) {
+ .forward, .forward_parameter => .forward_parameter,
+ .complete, .parameter, .global => .parameter,
+ };
+ }
+
+ pub fn noParameter(kind: Kind) Kind {
+ return switch (kind) {
+ .forward, .forward_parameter => .forward,
+ .complete, .parameter => .complete,
+ .global => .global,
+ };
+ }
+};
+
+pub const String = struct {
+ index: String.Index,
+
+ const Index = enum(u32) {
+ _,
+ };
+
+ pub fn slice(string: String, pool: *const Pool) []const u8 {
+ const start = pool.string_indices.items[@intFromEnum(string.index)];
+ const end = pool.string_indices.items[@intFromEnum(string.index) + 1];
+ return pool.string_bytes.items[start..end];
+ }
+};
+
+pub const Info = union(enum) {
+ basic: CType.Index,
+ pointer: Pointer,
+ aligned: Aligned,
+ array: Sequence,
+ vector: Sequence,
+ fwd_decl: FwdDecl,
+ aggregate: Aggregate,
+ function: Function,
+
+ pub const Pointer = struct {
+ elem_ctype: CType,
+ @"const": bool = false,
+ @"volatile": bool = false,
+
+ fn tag(pointer_info: Pointer) Pool.Tag {
+ return @enumFromInt(@intFromEnum(Pool.Tag.pointer) +
+ @as(u2, @bitCast(packed struct(u2) {
+ @"const": bool,
+ @"volatile": bool,
+ }{
+ .@"const" = pointer_info.@"const",
+ .@"volatile" = pointer_info.@"volatile",
+ })));
+ }
+ };
+
+ pub const Aligned = struct {
+ ctype: CType,
+ alignas: AlignAs,
+ };
+
+ pub const Sequence = struct {
+ elem_ctype: CType,
+ len: u64,
+ };
+
+ pub const Tag = enum { @"enum", @"struct", @"union" };
+
+ pub const Field = struct {
+ name: String,
+ ctype: CType,
+ alignas: AlignAs,
+
+ pub const Slice = struct {
+ extra_index: Pool.ExtraIndex,
+ len: u32,
+
+ pub fn at(slice: Field.Slice, index: usize, pool: *const Pool) Field {
+ assert(index < slice.len);
+ const extra = pool.getExtra(Pool.Field, @intCast(slice.extra_index +
+ index * @typeInfo(Pool.Field).Struct.fields.len));
+ return .{
+ .name = .{ .index = extra.name },
+ .ctype = .{ .index = extra.ctype },
+ .alignas = extra.flags.alignas,
+ };
+ }
+
+ fn eqlAdapted(
+ lhs_slice: Field.Slice,
+ lhs_pool: *const Pool,
+ rhs_slice: Field.Slice,
+ rhs_pool: *const Pool,
+ pool_adapter: anytype,
+ ) bool {
+ if (lhs_slice.len != rhs_slice.len) return false;
+ for (0..lhs_slice.len) |index| {
+ if (!lhs_slice.at(index, lhs_pool).eqlAdapted(
+ lhs_pool,
+ rhs_slice.at(index, rhs_pool),
+ rhs_pool,
+ pool_adapter,
+ )) return false;
+ }
+ return true;
+ }
+ };
+
+ fn eqlAdapted(
+ lhs_field: Field,
+ lhs_pool: *const Pool,
+ rhs_field: Field,
+ rhs_pool: *const Pool,
+ pool_adapter: anytype,
+ ) bool {
+ return std.meta.eql(lhs_field.alignas, rhs_field.alignas) and
+ pool_adapter.eql(lhs_field.ctype, rhs_field.ctype) and std.mem.eql(
+ u8,
+ lhs_field.name.slice(lhs_pool),
+ rhs_field.name.slice(rhs_pool),
+ );
+ }
+ };
+
+ pub const FwdDecl = struct {
+ tag: Tag,
+ name: union(enum) {
+ anon: Field.Slice,
+ owner_decl: DeclIndex,
+ },
+ };
+
+ pub const Aggregate = struct {
+ tag: Tag,
+ @"packed": bool = false,
+ name: union(enum) {
+ anon: struct {
+ owner_decl: DeclIndex,
+ id: u32,
+ },
+ fwd_decl: CType,
+ },
+ fields: Field.Slice,
+ };
+
+ pub const Function = struct {
+ return_ctype: CType,
+ param_ctypes: CType.Slice,
+ varargs: bool = false,
+ };
+
+ pub fn eqlAdapted(
+ lhs_info: Info,
+ lhs_pool: *const Pool,
+ rhs_ctype: CType,
+ rhs_pool: *const Pool,
+ pool_adapter: anytype,
+ ) bool {
+ const InfoTag = @typeInfo(Info).Union.tag_type.?;
+ const rhs_info = rhs_ctype.info(rhs_pool);
+ if (@as(InfoTag, lhs_info) != @as(InfoTag, rhs_info)) return false;
+ return switch (lhs_info) {
+ .basic => |lhs_basic_info| lhs_basic_info == rhs_info.basic,
+ .pointer => |lhs_pointer_info| lhs_pointer_info.@"const" == rhs_info.pointer.@"const" and
+ lhs_pointer_info.@"volatile" == rhs_info.pointer.@"volatile" and
+ pool_adapter.eql(lhs_pointer_info.elem_ctype, rhs_info.pointer.elem_ctype),
+ .aligned => |lhs_aligned_info| std.meta.eql(lhs_aligned_info.alignas, rhs_info.aligned.alignas) and
+ pool_adapter.eql(lhs_aligned_info.ctype, rhs_info.aligned.ctype),
+ .array => |lhs_array_info| lhs_array_info.len == rhs_info.array.len and
+ pool_adapter.eql(lhs_array_info.elem_ctype, rhs_info.array.elem_ctype),
+ .vector => |lhs_vector_info| lhs_vector_info.len == rhs_info.vector.len and
+ pool_adapter.eql(lhs_vector_info.elem_ctype, rhs_info.vector.elem_ctype),
+ .fwd_decl => |lhs_fwd_decl_info| lhs_fwd_decl_info.tag == rhs_info.fwd_decl.tag and
+ switch (lhs_fwd_decl_info.name) {
+ .anon => |lhs_anon| rhs_info.fwd_decl.name == .anon and lhs_anon.eqlAdapted(
+ lhs_pool,
+ rhs_info.fwd_decl.name.anon,
+ rhs_pool,
+ pool_adapter,
+ ),
+ .owner_decl => |lhs_owner_decl| rhs_info.fwd_decl.name == .owner_decl and
+ lhs_owner_decl == rhs_info.fwd_decl.name.owner_decl,
+ },
+ .aggregate => |lhs_aggregate_info| lhs_aggregate_info.tag == rhs_info.aggregate.tag and
+ lhs_aggregate_info.@"packed" == rhs_info.aggregate.@"packed" and
+ switch (lhs_aggregate_info.name) {
+ .anon => |lhs_anon| rhs_info.aggregate.name == .anon and
+ lhs_anon.owner_decl == rhs_info.aggregate.name.anon.owner_decl and
+ lhs_anon.id == rhs_info.aggregate.name.anon.id,
+ .fwd_decl => |lhs_fwd_decl| rhs_info.aggregate.name == .fwd_decl and
+ pool_adapter.eql(lhs_fwd_decl, rhs_info.aggregate.name.fwd_decl),
+ } and lhs_aggregate_info.fields.eqlAdapted(
+ lhs_pool,
+ rhs_info.aggregate.fields,
+ rhs_pool,
+ pool_adapter,
+ ),
+ .function => |lhs_function_info| lhs_function_info.param_ctypes.len ==
+ rhs_info.function.param_ctypes.len and
+ pool_adapter.eql(lhs_function_info.return_ctype, rhs_info.function.return_ctype) and
+ for (0..lhs_function_info.param_ctypes.len) |param_index|
+ {
+ if (!pool_adapter.eql(
+ lhs_function_info.param_ctypes.at(param_index, lhs_pool),
+ rhs_info.function.param_ctypes.at(param_index, rhs_pool),
+ )) break false;
+ } else true,
+ };
+ }
+};
+
+pub const Pool = struct {
+ map: Map,
+ items: std.MultiArrayList(Item),
+ extra: std.ArrayListUnmanaged(u32),
+
+ string_map: Map,
+ string_indices: std.ArrayListUnmanaged(u32),
+ string_bytes: std.ArrayListUnmanaged(u8),
+
+ const Map = std.AutoArrayHashMapUnmanaged(void, void);
+
+ pub const empty: Pool = .{
+ .map = .{},
+ .items = .{},
+ .extra = .{},
+
+ .string_map = .{},
+ .string_indices = .{},
+ .string_bytes = .{},
+ };
+
+ pub fn init(pool: *Pool, allocator: std.mem.Allocator) !void {
+ if (pool.string_indices.items.len == 0)
+ try pool.string_indices.append(allocator, 0);
+ }
+
+ pub fn deinit(pool: *Pool, allocator: std.mem.Allocator) void {
+ pool.map.deinit(allocator);
+ pool.items.deinit(allocator);
+ pool.extra.deinit(allocator);
+
+ pool.string_map.deinit(allocator);
+ pool.string_indices.deinit(allocator);
+ pool.string_bytes.deinit(allocator);
+
+ pool.* = undefined;
+ }
+
+ pub fn move(pool: *Pool) Pool {
+ defer pool.* = empty;
+ return pool.*;
+ }
+
+ pub fn clearRetainingCapacity(pool: *Pool) void {
+ pool.map.clearRetainingCapacity();
+ pool.items.shrinkRetainingCapacity(0);
+ pool.extra.clearRetainingCapacity();
+
+ pool.string_map.clearRetainingCapacity();
+ pool.string_indices.shrinkRetainingCapacity(1);
+ pool.string_bytes.clearRetainingCapacity();
+ }
+
+ pub fn freeUnusedCapacity(pool: *Pool, allocator: std.mem.Allocator) void {
+ pool.map.shrinkAndFree(allocator, pool.map.count());
+ pool.items.shrinkAndFree(allocator, pool.items.len);
+ pool.extra.shrinkAndFree(allocator, pool.extra.items.len);
+
+ pool.string_map.shrinkAndFree(allocator, pool.string_map.count());
+ pool.string_indices.shrinkAndFree(allocator, pool.string_indices.items.len);
+ pool.string_bytes.shrinkAndFree(allocator, pool.string_bytes.items.len);
+ }
+
+ pub fn getPointer(pool: *Pool, allocator: std.mem.Allocator, pointer_info: Info.Pointer) !CType {
+ var hasher = Hasher.init;
+ hasher.update(pointer_info.elem_ctype.hash(pool));
+ return pool.tagData(
+ allocator,
+ hasher,
+ pointer_info.tag(),
+ @intFromEnum(pointer_info.elem_ctype.index),
+ );
+ }
+
+ pub fn getAligned(pool: *Pool, allocator: std.mem.Allocator, aligned_info: Info.Aligned) !CType {
+ return pool.tagExtra(allocator, .aligned, Aligned, .{
+ .ctype = aligned_info.ctype.index,
+ .flags = .{ .alignas = aligned_info.alignas },
+ });
+ }
+
+ pub fn getArray(pool: *Pool, allocator: std.mem.Allocator, array_info: Info.Sequence) !CType {
+ return if (std.math.cast(u32, array_info.len)) |small_len|
+ pool.tagExtra(allocator, .array_small, SequenceSmall, .{
+ .elem_ctype = array_info.elem_ctype.index,
+ .len = small_len,
+ })
+ else
+ pool.tagExtra(allocator, .array_large, SequenceLarge, .{
+ .elem_ctype = array_info.elem_ctype.index,
+ .len_lo = @truncate(array_info.len >> 0),
+ .len_hi = @truncate(array_info.len >> 32),
+ });
+ }
+
+ pub fn getVector(pool: *Pool, allocator: std.mem.Allocator, vector_info: Info.Sequence) !CType {
+ return pool.tagExtra(allocator, .vector, SequenceSmall, .{
+ .elem_ctype = vector_info.elem_ctype.index,
+ .len = @intCast(vector_info.len),
+ });
+ }
+
+ pub fn getFwdDecl(
+ pool: *Pool,
+ allocator: std.mem.Allocator,
+ fwd_decl_info: struct {
+ tag: Info.Tag,
+ name: union(enum) {
+ anon: []const Info.Field,
+ owner_decl: DeclIndex,
+ },
+ },
+ ) !CType {
+ var hasher = Hasher.init;
+ switch (fwd_decl_info.name) {
+ .anon => |fields| {
+ const ExpectedContents = [32]CType;
+ var stack align(@max(
+ @alignOf(std.heap.StackFallbackAllocator(0)),
+ @alignOf(ExpectedContents),
+ )) = std.heap.stackFallback(@sizeOf(ExpectedContents), allocator);
+ const stack_allocator = stack.get();
+ const field_ctypes = try stack_allocator.alloc(CType, fields.len);
+ defer stack_allocator.free(field_ctypes);
+ for (field_ctypes, fields) |*field_ctype, field|
+ field_ctype.* = try field.ctype.toForward(pool, allocator);
+ const extra: FwdDeclAnon = .{ .fields_len = @intCast(fields.len) };
+ const extra_index = try pool.addExtra(
+ allocator,
+ FwdDeclAnon,
+ extra,
+ fields.len * @typeInfo(Field).Struct.fields.len,
+ );
+ for (fields, field_ctypes) |field, field_ctype| pool.addHashedExtraAssumeCapacity(
+ &hasher,
+ Field,
+ .{
+ .name = field.name.index,
+ .ctype = field_ctype.index,
+ .flags = .{ .alignas = field.alignas },
+ },
+ );
+ hasher.updateExtra(FwdDeclAnon, extra, pool);
+ return pool.tagTrailingExtra(allocator, hasher, switch (fwd_decl_info.tag) {
+ .@"struct" => .fwd_decl_struct_anon,
+ .@"union" => .fwd_decl_union_anon,
+ .@"enum" => unreachable,
+ }, extra_index);
+ },
+ .owner_decl => |owner_decl| {
+ hasher.update(owner_decl);
+ return pool.tagData(allocator, hasher, switch (fwd_decl_info.tag) {
+ .@"struct" => .fwd_decl_struct,
+ .@"union" => .fwd_decl_union,
+ .@"enum" => unreachable,
+ }, @intFromEnum(owner_decl));
+ },
+ }
+ }
+
+ pub fn getAggregate(
+ pool: *Pool,
+ allocator: std.mem.Allocator,
+ aggregate_info: struct {
+ tag: Info.Tag,
+ @"packed": bool = false,
+ name: union(enum) {
+ anon: struct {
+ owner_decl: DeclIndex,
+ id: u32,
+ },
+ fwd_decl: CType,
+ },
+ fields: []const Info.Field,
+ },
+ ) !CType {
+ var hasher = Hasher.init;
+ switch (aggregate_info.name) {
+ .anon => |anon| {
+ const extra: AggregateAnon = .{
+ .owner_decl = anon.owner_decl,
+ .id = anon.id,
+ .fields_len = @intCast(aggregate_info.fields.len),
+ };
+ const extra_index = try pool.addExtra(
+ allocator,
+ AggregateAnon,
+ extra,
+ aggregate_info.fields.len * @typeInfo(Field).Struct.fields.len,
+ );
+ for (aggregate_info.fields) |field| pool.addHashedExtraAssumeCapacity(&hasher, Field, .{
+ .name = field.name.index,
+ .ctype = field.ctype.index,
+ .flags = .{ .alignas = field.alignas },
+ });
+ hasher.updateExtra(AggregateAnon, extra, pool);
+ return pool.tagTrailingExtra(allocator, hasher, switch (aggregate_info.tag) {
+ .@"struct" => switch (aggregate_info.@"packed") {
+ false => .aggregate_struct_anon,
+ true => .aggregate_struct_packed_anon,
+ },
+ .@"union" => switch (aggregate_info.@"packed") {
+ false => .aggregate_union_anon,
+ true => .aggregate_union_packed_anon,
+ },
+ .@"enum" => unreachable,
+ }, extra_index);
+ },
+ .fwd_decl => |fwd_decl| {
+ const extra: Aggregate = .{
+ .fwd_decl = fwd_decl.index,
+ .fields_len = @intCast(aggregate_info.fields.len),
+ };
+ const extra_index = try pool.addExtra(
+ allocator,
+ Aggregate,
+ extra,
+ aggregate_info.fields.len * @typeInfo(Field).Struct.fields.len,
+ );
+ for (aggregate_info.fields) |field| pool.addHashedExtraAssumeCapacity(&hasher, Field, .{
+ .name = field.name.index,
+ .ctype = field.ctype.index,
+ .flags = .{ .alignas = field.alignas },
+ });
+ hasher.updateExtra(Aggregate, extra, pool);
+ return pool.tagTrailingExtra(allocator, hasher, switch (aggregate_info.tag) {
+ .@"struct" => switch (aggregate_info.@"packed") {
+ false => .aggregate_struct,
+ true => .aggregate_struct_packed,
+ },
+ .@"union" => switch (aggregate_info.@"packed") {
+ false => .aggregate_union,
+ true => .aggregate_union_packed,
+ },
+ .@"enum" => unreachable,
+ }, extra_index);
+ },
+ }
+ }
+
+ pub fn getFunction(
+ pool: *Pool,
+ allocator: std.mem.Allocator,
+ function_info: struct {
+ return_ctype: CType,
+ param_ctypes: []const CType,
+ varargs: bool = false,
+ },
+ ) !CType {
+ var hasher = Hasher.init;
+ const extra: Function = .{
+ .return_ctype = function_info.return_ctype.index,
+ .param_ctypes_len = @intCast(function_info.param_ctypes.len),
+ };
+ const extra_index = try pool.addExtra(allocator, Function, extra, function_info.param_ctypes.len);
+ for (function_info.param_ctypes) |param_ctype| {
+ hasher.update(param_ctype.hash(pool));
+ pool.extra.appendAssumeCapacity(@intFromEnum(param_ctype.index));
+ }
+ hasher.updateExtra(Function, extra, pool);
+ return pool.tagTrailingExtra(allocator, hasher, switch (function_info.varargs) {
+ false => .function,
+ true => .function_varargs,
+ }, extra_index);
+ }
+
+ pub fn fromFields(
+ pool: *Pool,
+ allocator: std.mem.Allocator,
+ tag: Info.Tag,
+ fields: []Info.Field,
+ kind: Kind,
+ ) !CType {
+ sortFields(fields);
+ const fwd_decl = try pool.getFwdDecl(allocator, .{
+ .tag = tag,
+ .name = .{ .anon = fields },
+ });
+ return if (kind.isForward()) fwd_decl else pool.getAggregate(allocator, .{
+ .tag = tag,
+ .name = .{ .fwd_decl = fwd_decl },
+ .fields = fields,
+ });
+ }
+
+ pub fn fromIntInfo(
+ pool: *Pool,
+ allocator: std.mem.Allocator,
+ int_info: std.builtin.Type.Int,
+ mod: *Module,
+ kind: Kind,
+ ) !CType {
+ switch (int_info.bits) {
+ 0 => return .{ .index = .void },
+ 1...8 => switch (int_info.signedness) {
+ .unsigned => return .{ .index = .uint8_t },
+ .signed => return .{ .index = .int8_t },
+ },
+ 9...16 => switch (int_info.signedness) {
+ .unsigned => return .{ .index = .uint16_t },
+ .signed => return .{ .index = .int16_t },
+ },
+ 17...32 => switch (int_info.signedness) {
+ .unsigned => return .{ .index = .uint32_t },
+ .signed => return .{ .index = .int32_t },
+ },
+ 33...64 => switch (int_info.signedness) {
+ .unsigned => return .{ .index = .uint64_t },
+ .signed => return .{ .index = .int64_t },
+ },
+ 65...128 => switch (int_info.signedness) {
+ .unsigned => return .{ .index = .zig_u128 },
+ .signed => return .{ .index = .zig_i128 },
+ },
+ else => {
+ const target = &mod.resolved_target.result;
+ const abi_align = Type.intAbiAlignment(int_info.bits, target.*);
+ const abi_align_bytes = abi_align.toByteUnits().?;
+ const array_ctype = try pool.getArray(allocator, .{
+ .len = @divExact(Type.intAbiSize(int_info.bits, target.*), abi_align_bytes),
+ .elem_ctype = try pool.fromIntInfo(allocator, .{
+ .signedness = .unsigned,
+ .bits = @intCast(abi_align_bytes * 8),
+ }, mod, kind.noParameter()),
+ });
+ if (!kind.isParameter()) return array_ctype;
+ var fields = [_]Info.Field{
+ .{
+ .name = try pool.string(allocator, "array"),
+ .ctype = array_ctype,
+ .alignas = AlignAs.fromAbiAlignment(abi_align),
+ },
+ };
+ return pool.fromFields(allocator, .@"struct", &fields, kind);
+ },
+ }
+ }
+
+ pub fn fromType(
+ pool: *Pool,
+ allocator: std.mem.Allocator,
+ scratch: *std.ArrayListUnmanaged(u32),
+ ty: Type,
+ zcu: *Zcu,
+ mod: *Module,
+ kind: Kind,
+ ) !CType {
+ const ip = &zcu.intern_pool;
+ switch (ty.toIntern()) {
+ .u0_type,
+ .i0_type,
+ .anyopaque_type,
+ .void_type,
+ .empty_struct_type,
+ .type_type,
+ .comptime_int_type,
+ .comptime_float_type,
+ .null_type,
+ .undefined_type,
+ .enum_literal_type,
+ => return .{ .index = .void },
+ .u1_type, .u8_type => return .{ .index = .uint8_t },
+ .i8_type => return .{ .index = .int8_t },
+ .u16_type => return .{ .index = .uint16_t },
+ .i16_type => return .{ .index = .int16_t },
+ .u29_type, .u32_type => return .{ .index = .uint32_t },
+ .i32_type => return .{ .index = .int32_t },
+ .u64_type => return .{ .index = .uint64_t },
+ .i64_type => return .{ .index = .int64_t },
+ .u80_type, .u128_type => return .{ .index = .zig_u128 },
+ .i128_type => return .{ .index = .zig_i128 },
+ .usize_type => return .{ .index = .uintptr_t },
+ .isize_type => return .{ .index = .intptr_t },
+ .c_char_type => return .{ .index = .char },
+ .c_short_type => return .{ .index = .short },
+ .c_ushort_type => return .{ .index = .@"unsigned short" },
+ .c_int_type => return .{ .index = .int },
+ .c_uint_type => return .{ .index = .@"unsigned int" },
+ .c_long_type => return .{ .index = .long },
+ .c_ulong_type => return .{ .index = .@"unsigned long" },
+ .c_longlong_type => return .{ .index = .@"long long" },
+ .c_ulonglong_type => return .{ .index = .@"unsigned long long" },
+ .c_longdouble_type => return .{ .index = .@"long double" },
+ .f16_type => return .{ .index = .zig_f16 },
+ .f32_type => return .{ .index = .zig_f32 },
+ .f64_type => return .{ .index = .zig_f64 },
+ .f80_type => return .{ .index = .zig_f80 },
+ .f128_type => return .{ .index = .zig_f128 },
+ .bool_type, .optional_noreturn_type => return .{ .index = .bool },
+ .noreturn_type,
+ .anyframe_type,
+ .generic_poison_type,
+ => unreachable,
+ .atomic_order_type,
+ .atomic_rmw_op_type,
+ .calling_convention_type,
+ .address_space_type,
+ .float_mode_type,
+ .reduce_op_type,
+ .call_modifier_type,
+ => |ip_index| return pool.fromType(
+ allocator,
+ scratch,
+ Type.fromInterned(ip.loadEnumType(ip_index).tag_ty),
+ zcu,
+ mod,
+ kind,
+ ),
+ .anyerror_type,
+ .anyerror_void_error_union_type,
+ .adhoc_inferred_error_set_type,
+ => return pool.fromIntInfo(allocator, .{
+ .signedness = .unsigned,
+ .bits = zcu.errorSetBits(),
+ }, mod, kind),
+ .manyptr_u8_type,
+ => return pool.getPointer(allocator, .{
+ .elem_ctype = .{ .index = .uint8_t },
+ }),
+ .manyptr_const_u8_type,
+ .manyptr_const_u8_sentinel_0_type,
+ => return pool.getPointer(allocator, .{
+ .elem_ctype = .{ .index = .uint8_t },
+ .@"const" = true,
+ }),
+ .single_const_pointer_to_comptime_int_type,
+ => return pool.getPointer(allocator, .{
+ .elem_ctype = .{ .index = .void },
+ .@"const" = true,
+ }),
+ .slice_const_u8_type,
+ .slice_const_u8_sentinel_0_type,
+ => {
+ const target = &mod.resolved_target.result;
+ var fields = [_]Info.Field{
+ .{
+ .name = try pool.string(allocator, "ptr"),
+ .ctype = try pool.getPointer(allocator, .{
+ .elem_ctype = .{ .index = .uint8_t },
+ .@"const" = true,
+ }),
+ .alignas = AlignAs.fromAbiAlignment(Type.ptrAbiAlignment(target.*)),
+ },
+ .{
+ .name = try pool.string(allocator, "len"),
+ .ctype = .{ .index = .uintptr_t },
+ .alignas = AlignAs.fromAbiAlignment(
+ Type.intAbiAlignment(target.ptrBitWidth(), target.*),
+ ),
+ },
+ };
+ return pool.fromFields(allocator, .@"struct", &fields, kind);
+ },
+
+ .undef,
+ .zero,
+ .zero_usize,
+ .zero_u8,
+ .one,
+ .one_usize,
+ .one_u8,
+ .four_u8,
+ .negative_one,
+ .calling_convention_c,
+ .calling_convention_inline,
+ .void_value,
+ .unreachable_value,
+ .null_value,
+ .bool_true,
+ .bool_false,
+ .empty_struct,
+ .generic_poison,
+ .var_args_param_type,
+ .none,
+ => unreachable,
+
+ //.prefetch_options_type,
+ //.export_options_type,
+ //.extern_options_type,
+ //.type_info_type,
+ //_,
+ else => |ip_index| switch (ip.indexToKey(ip_index)) {
+ .int_type => |int_info| return pool.fromIntInfo(allocator, int_info, mod, kind),
+ .ptr_type => |ptr_info| switch (ptr_info.flags.size) {
+ .One, .Many, .C => return pool.getPointer(allocator, .{
+ .elem_ctype = elem_ctype: {
+ if (ptr_info.packed_offset.host_size > 0 and
+ ptr_info.flags.vector_index == .none)
+ break :elem_ctype try pool.fromIntInfo(allocator, .{
+ .signedness = .unsigned,
+ .bits = ptr_info.packed_offset.host_size * 8,
+ }, mod, .forward);
+ const elem: Info.Aligned = .{
+ .ctype = try pool.fromType(
+ allocator,
+ scratch,
+ Type.fromInterned(ptr_info.child),
+ zcu,
+ mod,
+ .forward,
+ ),
+ .alignas = AlignAs.fromAlignment(.{
+ .@"align" = ptr_info.flags.alignment,
+ .abi = Type.fromInterned(ptr_info.child).abiAlignment(zcu),
+ }),
+ };
+ if (elem.alignas.abiOrder().compare(.gte))
+ break :elem_ctype elem.ctype;
+ break :elem_ctype try pool.getAligned(allocator, elem);
+ },
+ .@"const" = ptr_info.flags.is_const,
+ .@"volatile" = ptr_info.flags.is_volatile,
+ }),
+ .Slice => {
+ const target = &mod.resolved_target.result;
+ var fields = [_]Info.Field{
+ .{
+ .name = try pool.string(allocator, "ptr"),
+ .ctype = try pool.fromType(
+ allocator,
+ scratch,
+ Type.fromInterned(ip.slicePtrType(ip_index)),
+ zcu,
+ mod,
+ kind,
+ ),
+ .alignas = AlignAs.fromAbiAlignment(Type.ptrAbiAlignment(target.*)),
+ },
+ .{
+ .name = try pool.string(allocator, "len"),
+ .ctype = .{ .index = .uintptr_t },
+ .alignas = AlignAs.fromAbiAlignment(
+ Type.intAbiAlignment(target.ptrBitWidth(), target.*),
+ ),
+ },
+ };
+ return pool.fromFields(allocator, .@"struct", &fields, kind);
+ },
+ },
+ .array_type => |array_info| {
+ const len = array_info.len + @intFromBool(array_info.sentinel != .none);
+ if (len == 0) return .{ .index = .void };
+ const elem_type = Type.fromInterned(array_info.child);
+ const elem_ctype = try pool.fromType(
+ allocator,
+ scratch,
+ elem_type,
+ zcu,
+ mod,
+ kind.noParameter(),
+ );
+ if (elem_ctype.index == .void) return .{ .index = .void };
+ const array_ctype = try pool.getArray(allocator, .{
+ .elem_ctype = elem_ctype,
+ .len = array_info.len + @intFromBool(array_info.sentinel != .none),
+ });
+ if (!kind.isParameter()) return array_ctype;
+ var fields = [_]Info.Field{
+ .{
+ .name = try pool.string(allocator, "array"),
+ .ctype = array_ctype,
+ .alignas = AlignAs.fromAbiAlignment(elem_type.abiAlignment(zcu)),
+ },
+ };
+ return pool.fromFields(allocator, .@"struct", &fields, kind);
+ },
+ .vector_type => |vector_info| {
+ if (vector_info.len == 0) return .{ .index = .void };
+ const elem_type = Type.fromInterned(vector_info.child);
+ const elem_ctype = try pool.fromType(
+ allocator,
+ scratch,
+ elem_type,
+ zcu,
+ mod,
+ kind.noParameter(),
+ );
+ if (elem_ctype.index == .void) return .{ .index = .void };
+ const vector_ctype = try pool.getVector(allocator, .{
+ .elem_ctype = elem_ctype,
+ .len = vector_info.len,
+ });
+ if (!kind.isParameter()) return vector_ctype;
+ var fields = [_]Info.Field{
+ .{
+ .name = try pool.string(allocator, "array"),
+ .ctype = vector_ctype,
+ .alignas = AlignAs.fromAbiAlignment(elem_type.abiAlignment(zcu)),
+ },
+ };
+ return pool.fromFields(allocator, .@"struct", &fields, kind);
+ },
+ .opt_type => |payload_type| {
+ if (ip.isNoReturn(payload_type)) return .{ .index = .void };
+ const payload_ctype = try pool.fromType(
+ allocator,
+ scratch,
+ Type.fromInterned(payload_type),
+ zcu,
+ mod,
+ kind.noParameter(),
+ );
+ if (payload_ctype.index == .void) return .{ .index = .bool };
+ switch (payload_type) {
+ .anyerror_type => return payload_ctype,
+ else => switch (ip.indexToKey(payload_type)) {
+ .ptr_type => |payload_ptr_info| if (payload_ptr_info.flags.size != .C and
+ !payload_ptr_info.flags.is_allowzero) return payload_ctype,
+ .error_set_type, .inferred_error_set_type => return payload_ctype,
+ else => {},
+ },
+ }
+ var fields = [_]Info.Field{
+ .{
+ .name = try pool.string(allocator, "is_null"),
+ .ctype = .{ .index = .bool },
+ .alignas = AlignAs.fromAbiAlignment(.@"1"),
+ },
+ .{
+ .name = try pool.string(allocator, "payload"),
+ .ctype = payload_ctype,
+ .alignas = AlignAs.fromAbiAlignment(
+ Type.fromInterned(payload_type).abiAlignment(zcu),
+ ),
+ },
+ };
+ return pool.fromFields(allocator, .@"struct", &fields, kind);
+ },
+ .anyframe_type => unreachable,
+ .error_union_type => |error_union_info| {
+ const error_set_bits = zcu.errorSetBits();
+ const error_set_ctype = try pool.fromIntInfo(allocator, .{
+ .signedness = .unsigned,
+ .bits = error_set_bits,
+ }, mod, kind);
+ if (ip.isNoReturn(error_union_info.payload_type)) return error_set_ctype;
+ const payload_type = Type.fromInterned(error_union_info.payload_type);
+ const payload_ctype = try pool.fromType(
+ allocator,
+ scratch,
+ payload_type,
+ zcu,
+ mod,
+ kind.noParameter(),
+ );
+ if (payload_ctype.index == .void) return error_set_ctype;
+ const target = &mod.resolved_target.result;
+ var fields = [_]Info.Field{
+ .{
+ .name = try pool.string(allocator, "error"),
+ .ctype = error_set_ctype,
+ .alignas = AlignAs.fromAbiAlignment(
+ Type.intAbiAlignment(error_set_bits, target.*),
+ ),
+ },
+ .{
+ .name = try pool.string(allocator, "payload"),
+ .ctype = payload_ctype,
+ .alignas = AlignAs.fromAbiAlignment(payload_type.abiAlignment(zcu)),
+ },
+ };
+ return pool.fromFields(allocator, .@"struct", &fields, kind);
+ },
+ .simple_type => unreachable,
+ .struct_type => {
+ const loaded_struct = ip.loadStructType(ip_index);
+ switch (loaded_struct.layout) {
+ .auto, .@"extern" => {
+ const fwd_decl = try pool.getFwdDecl(allocator, .{
+ .tag = .@"struct",
+ .name = .{ .owner_decl = loaded_struct.decl.unwrap().? },
+ });
+ if (kind.isForward()) return if (ty.hasRuntimeBitsIgnoreComptime(zcu))
+ fwd_decl
+ else
+ .{ .index = .void };
+ const scratch_top = scratch.items.len;
+ defer scratch.shrinkRetainingCapacity(scratch_top);
+ try scratch.ensureUnusedCapacity(
+ allocator,
+ loaded_struct.field_types.len * @typeInfo(Field).Struct.fields.len,
+ );
+ var hasher = Hasher.init;
+ var tag: Tag = .aggregate_struct;
+ var field_it = loaded_struct.iterateRuntimeOrder(ip);
+ while (field_it.next()) |field_index| {
+ const field_type = Type.fromInterned(
+ loaded_struct.field_types.get(ip)[field_index],
+ );
+ const field_ctype = try pool.fromType(
+ allocator,
+ scratch,
+ field_type,
+ zcu,
+ mod,
+ kind.noParameter(),
+ );
+ if (field_ctype.index == .void) continue;
+ const field_name = if (loaded_struct.fieldName(ip, field_index)
+ .unwrap()) |field_name|
+ try pool.string(allocator, ip.stringToSlice(field_name))
+ else
+ try pool.fmt(allocator, "f{d}", .{field_index});
+ const field_alignas = AlignAs.fromAlignment(.{
+ .@"align" = loaded_struct.fieldAlign(ip, field_index),
+ .abi = field_type.abiAlignment(zcu),
+ });
+ pool.addHashedExtraAssumeCapacityTo(scratch, &hasher, Field, .{
+ .name = field_name.index,
+ .ctype = field_ctype.index,
+ .flags = .{ .alignas = field_alignas },
+ });
+ if (field_alignas.abiOrder().compare(.lt))
+ tag = .aggregate_struct_packed;
+ }
+ const fields_len: u32 = @intCast(@divExact(
+ scratch.items.len - scratch_top,
+ @typeInfo(Field).Struct.fields.len,
+ ));
+ if (fields_len == 0) return .{ .index = .void };
+ try pool.ensureUnusedCapacity(allocator, 1);
+ const extra_index = try pool.addHashedExtra(allocator, &hasher, Aggregate, .{
+ .fwd_decl = fwd_decl.index,
+ .fields_len = fields_len,
+ }, fields_len * @typeInfo(Field).Struct.fields.len);
+ pool.extra.appendSliceAssumeCapacity(scratch.items[scratch_top..]);
+ return pool.tagTrailingExtraAssumeCapacity(hasher, tag, extra_index);
+ },
+ .@"packed" => return pool.fromType(
+ allocator,
+ scratch,
+ Type.fromInterned(loaded_struct.backingIntType(ip).*),
+ zcu,
+ mod,
+ kind,
+ ),
+ }
+ },
+ .anon_struct_type => |anon_struct_info| {
+ const scratch_top = scratch.items.len;
+ defer scratch.shrinkRetainingCapacity(scratch_top);
+ try scratch.ensureUnusedCapacity(allocator, anon_struct_info.types.len *
+ @typeInfo(Field).Struct.fields.len);
+ var hasher = Hasher.init;
+ for (0..anon_struct_info.types.len) |field_index| {
+ if (anon_struct_info.values.get(ip)[field_index] != .none) continue;
+ const field_type = Type.fromInterned(
+ anon_struct_info.types.get(ip)[field_index],
+ );
+ const field_ctype = try pool.fromType(
+ allocator,
+ scratch,
+ field_type,
+ zcu,
+ mod,
+ kind.noParameter(),
+ );
+ if (field_ctype.index == .void) continue;
+ const field_name = if (anon_struct_info.fieldName(ip, @intCast(field_index))
+ .unwrap()) |field_name|
+ try pool.string(allocator, ip.stringToSlice(field_name))
+ else
+ try pool.fmt(allocator, "f{d}", .{field_index});
+ pool.addHashedExtraAssumeCapacityTo(scratch, &hasher, Field, .{
+ .name = field_name.index,
+ .ctype = field_ctype.index,
+ .flags = .{ .alignas = AlignAs.fromAbiAlignment(
+ field_type.abiAlignment(zcu),
+ ) },
+ });
+ }
+ const fields_len: u32 = @intCast(@divExact(
+ scratch.items.len - scratch_top,
+ @typeInfo(Field).Struct.fields.len,
+ ));
+ if (fields_len == 0) return .{ .index = .void };
+ if (kind.isForward()) {
+ try pool.ensureUnusedCapacity(allocator, 1);
+ const extra_index = try pool.addHashedExtra(
+ allocator,
+ &hasher,
+ FwdDeclAnon,
+ .{ .fields_len = fields_len },
+ fields_len * @typeInfo(Field).Struct.fields.len,
+ );
+ pool.extra.appendSliceAssumeCapacity(scratch.items[scratch_top..]);
+ return pool.tagTrailingExtra(
+ allocator,
+ hasher,
+ .fwd_decl_struct_anon,
+ extra_index,
+ );
+ }
+ const fwd_decl = try pool.fromType(allocator, scratch, ty, zcu, mod, .forward);
+ try pool.ensureUnusedCapacity(allocator, 1);
+ const extra_index = try pool.addHashedExtra(allocator, &hasher, Aggregate, .{
+ .fwd_decl = fwd_decl.index,
+ .fields_len = fields_len,
+ }, fields_len * @typeInfo(Field).Struct.fields.len);
+ pool.extra.appendSliceAssumeCapacity(scratch.items[scratch_top..]);
+ return pool.tagTrailingExtraAssumeCapacity(hasher, .aggregate_struct, extra_index);
+ },
+ .union_type => {
+ const loaded_union = ip.loadUnionType(ip_index);
+ switch (loaded_union.getLayout(ip)) {
+ .auto, .@"extern" => {
+ const has_tag = loaded_union.hasTag(ip);
+ const fwd_decl = try pool.getFwdDecl(allocator, .{
+ .tag = if (has_tag) .@"struct" else .@"union",
+ .name = .{ .owner_decl = loaded_union.decl },
+ });
+ if (kind.isForward()) return if (ty.hasRuntimeBitsIgnoreComptime(zcu))
+ fwd_decl
+ else
+ .{ .index = .void };
+ const loaded_tag = loaded_union.loadTagType(ip);
+ const scratch_top = scratch.items.len;
+ defer scratch.shrinkRetainingCapacity(scratch_top);
+ try scratch.ensureUnusedCapacity(
+ allocator,
+ loaded_union.field_types.len * @typeInfo(Field).Struct.fields.len,
+ );
+ var hasher = Hasher.init;
+ var tag: Tag = .aggregate_union;
+ var payload_align: Alignment = .@"1";
+ for (0..loaded_union.field_types.len) |field_index| {
+ const field_type = Type.fromInterned(
+ loaded_union.field_types.get(ip)[field_index],
+ );
+ if (ip.isNoReturn(field_type.toIntern())) continue;
+ const field_ctype = try pool.fromType(
+ allocator,
+ scratch,
+ field_type,
+ zcu,
+ mod,
+ kind.noParameter(),
+ );
+ if (field_ctype.index == .void) continue;
+ const field_name = try pool.string(
+ allocator,
+ ip.stringToSlice(loaded_tag.names.get(ip)[field_index]),
+ );
+ const field_alignas = AlignAs.fromAlignment(.{
+ .@"align" = loaded_union.fieldAlign(ip, @intCast(field_index)),
+ .abi = field_type.abiAlignment(zcu),
+ });
+ pool.addHashedExtraAssumeCapacityTo(scratch, &hasher, Field, .{
+ .name = field_name.index,
+ .ctype = field_ctype.index,
+ .flags = .{ .alignas = field_alignas },
+ });
+ if (field_alignas.abiOrder().compare(.lt))
+ tag = .aggregate_union_packed;
+ payload_align = payload_align.maxStrict(field_alignas.@"align");
+ }
+ const fields_len: u32 = @intCast(@divExact(
+ scratch.items.len - scratch_top,
+ @typeInfo(Field).Struct.fields.len,
+ ));
+ if (!has_tag) {
+ if (fields_len == 0) return .{ .index = .void };
+ try pool.ensureUnusedCapacity(allocator, 1);
+ const extra_index = try pool.addHashedExtra(
+ allocator,
+ &hasher,
+ Aggregate,
+ .{ .fwd_decl = fwd_decl.index, .fields_len = fields_len },
+ fields_len * @typeInfo(Field).Struct.fields.len,
+ );
+ pool.extra.appendSliceAssumeCapacity(scratch.items[scratch_top..]);
+ return pool.tagTrailingExtraAssumeCapacity(hasher, tag, extra_index);
+ }
+ try pool.ensureUnusedCapacity(allocator, 2);
+ var struct_fields: [2]Info.Field = undefined;
+ var struct_fields_len: usize = 0;
+ if (loaded_tag.tag_ty != .comptime_int_type) {
+ const tag_type = Type.fromInterned(loaded_tag.tag_ty);
+ const tag_ctype: CType = try pool.fromType(
+ allocator,
+ scratch,
+ tag_type,
+ zcu,
+ mod,
+ kind.noParameter(),
+ );
+ if (tag_ctype.index != .void) {
+ struct_fields[struct_fields_len] = .{
+ .name = try pool.string(allocator, "tag"),
+ .ctype = tag_ctype,
+ .alignas = AlignAs.fromAbiAlignment(tag_type.abiAlignment(zcu)),
+ };
+ struct_fields_len += 1;
+ }
+ }
+ if (fields_len > 0) {
+ const payload_ctype = payload_ctype: {
+ const extra_index = try pool.addHashedExtra(
+ allocator,
+ &hasher,
+ AggregateAnon,
+ .{
+ .owner_decl = loaded_union.decl,
+ .id = 0,
+ .fields_len = fields_len,
+ },
+ fields_len * @typeInfo(Field).Struct.fields.len,
+ );
+ pool.extra.appendSliceAssumeCapacity(scratch.items[scratch_top..]);
+ break :payload_ctype pool.tagTrailingExtraAssumeCapacity(
+ hasher,
+ switch (tag) {
+ .aggregate_union => .aggregate_union_anon,
+ .aggregate_union_packed => .aggregate_union_packed_anon,
+ else => unreachable,
+ },
+ extra_index,
+ );
+ };
+ if (payload_ctype.index != .void) {
+ struct_fields[struct_fields_len] = .{
+ .name = try pool.string(allocator, "payload"),
+ .ctype = payload_ctype,
+ .alignas = AlignAs.fromAbiAlignment(payload_align),
+ };
+ struct_fields_len += 1;
+ }
+ }
+ if (struct_fields_len == 0) return .{ .index = .void };
+ sortFields(struct_fields[0..struct_fields_len]);
+ return pool.getAggregate(allocator, .{
+ .tag = .@"struct",
+ .name = .{ .fwd_decl = fwd_decl },
+ .fields = struct_fields[0..struct_fields_len],
+ });
+ },
+ .@"packed" => return pool.fromIntInfo(allocator, .{
+ .signedness = .unsigned,
+ .bits = @intCast(ty.bitSize(zcu)),
+ }, mod, kind),
+ }
+ },
+ .opaque_type => return .{ .index = .void },
+ .enum_type => return pool.fromType(
+ allocator,
+ scratch,
+ Type.fromInterned(ip.loadEnumType(ip_index).tag_ty),
+ zcu,
+ mod,
+ kind,
+ ),
+ .func_type => |func_info| if (func_info.is_generic) return .{ .index = .void } else {
+ const scratch_top = scratch.items.len;
+ defer scratch.shrinkRetainingCapacity(scratch_top);
+ try scratch.ensureUnusedCapacity(allocator, func_info.param_types.len);
+ var hasher = Hasher.init;
+ const return_type = Type.fromInterned(func_info.return_type);
+ const return_ctype: CType =
+ if (!ip.isNoReturn(func_info.return_type)) try pool.fromType(
+ allocator,
+ scratch,
+ return_type,
+ zcu,
+ mod,
+ kind.asParameter(),
+ ) else .{ .index = .void };
+ for (0..func_info.param_types.len) |param_index| {
+ const param_type = Type.fromInterned(
+ func_info.param_types.get(ip)[param_index],
+ );
+ const param_ctype = try pool.fromType(
+ allocator,
+ scratch,
+ param_type,
+ zcu,
+ mod,
+ kind.asParameter(),
+ );
+ if (param_ctype.index == .void) continue;
+ hasher.update(param_ctype.hash(pool));
+ scratch.appendAssumeCapacity(@intFromEnum(param_ctype.index));
+ }
+ const param_ctypes_len: u32 = @intCast(scratch.items.len - scratch_top);
+ try pool.ensureUnusedCapacity(allocator, 1);
+ const extra_index = try pool.addHashedExtra(allocator, &hasher, Function, .{
+ .return_ctype = return_ctype.index,
+ .param_ctypes_len = param_ctypes_len,
+ }, param_ctypes_len);
+ pool.extra.appendSliceAssumeCapacity(scratch.items[scratch_top..]);
+ return pool.tagTrailingExtraAssumeCapacity(hasher, switch (func_info.is_var_args) {
+ false => .function,
+ true => .function_varargs,
+ }, extra_index);
+ },
+ .error_set_type,
+ .inferred_error_set_type,
+ => return pool.fromIntInfo(allocator, .{
+ .signedness = .unsigned,
+ .bits = zcu.errorSetBits(),
+ }, mod, kind),
+
+ .undef,
+ .simple_value,
+ .variable,
+ .extern_func,
+ .func,
+ .int,
+ .err,
+ .error_union,
+ .enum_literal,
+ .enum_tag,
+ .empty_enum_value,
+ .float,
+ .ptr,
+ .slice,
+ .opt,
+ .aggregate,
+ .un,
+ .memoized_call,
+ => unreachable,
+ },
+ }
+ }
+
+ pub fn getOrPutAdapted(
+ pool: *Pool,
+ allocator: std.mem.Allocator,
+ source_pool: *const Pool,
+ source_ctype: CType,
+ pool_adapter: anytype,
+ ) !struct { CType, bool } {
+ const tag = source_pool.items.items(.tag)[
+ source_ctype.toPoolIndex() orelse return .{ source_ctype, true }
+ ];
+ try pool.ensureUnusedCapacity(allocator, 1);
+ const CTypeAdapter = struct {
+ pool: *const Pool,
+ source_pool: *const Pool,
+ source_info: Info,
+ pool_adapter: @TypeOf(pool_adapter),
+ pub fn hash(map_adapter: @This(), key_ctype: CType) Map.Hash {
+ return key_ctype.hash(map_adapter.source_pool);
+ }
+ pub fn eql(map_adapter: @This(), _: CType, _: void, pool_index: usize) bool {
+ return map_adapter.source_info.eqlAdapted(
+ map_adapter.source_pool,
+ CType.fromPoolIndex(pool_index),
+ map_adapter.pool,
+ map_adapter.pool_adapter,
+ );
+ }
+ };
+ const source_info = source_ctype.info(source_pool);
+ const gop = pool.map.getOrPutAssumeCapacityAdapted(source_ctype, CTypeAdapter{
+ .pool = pool,
+ .source_pool = source_pool,
+ .source_info = source_info,
+ .pool_adapter = pool_adapter,
+ });
+ errdefer _ = pool.map.pop();
+ const ctype = CType.fromPoolIndex(gop.index);
+ if (!gop.found_existing) switch (source_info) {
+ .basic => unreachable,
+ .pointer => |pointer_info| pool.items.appendAssumeCapacity(.{
+ .tag = tag,
+ .data = @intFromEnum(pool_adapter.copy(pointer_info.elem_ctype).index),
+ }),
+ .aligned => |aligned_info| pool.items.appendAssumeCapacity(.{
+ .tag = tag,
+ .data = try pool.addExtra(allocator, Aligned, .{
+ .ctype = pool_adapter.copy(aligned_info.ctype).index,
+ .flags = .{ .alignas = aligned_info.alignas },
+ }, 0),
+ }),
+ .array, .vector => |sequence_info| pool.items.appendAssumeCapacity(.{
+ .tag = tag,
+ .data = switch (tag) {
+ .array_small, .vector => try pool.addExtra(allocator, SequenceSmall, .{
+ .elem_ctype = pool_adapter.copy(sequence_info.elem_ctype).index,
+ .len = @intCast(sequence_info.len),
+ }, 0),
+ .array_large => try pool.addExtra(allocator, SequenceLarge, .{
+ .elem_ctype = pool_adapter.copy(sequence_info.elem_ctype).index,
+ .len_lo = @truncate(sequence_info.len >> 0),
+ .len_hi = @truncate(sequence_info.len >> 32),
+ }, 0),
+ else => unreachable,
+ },
+ }),
+ .fwd_decl => |fwd_decl_info| switch (fwd_decl_info.name) {
+ .anon => |fields| {
+ pool.items.appendAssumeCapacity(.{
+ .tag = tag,
+ .data = try pool.addExtra(allocator, FwdDeclAnon, .{
+ .fields_len = fields.len,
+ }, fields.len * @typeInfo(Field).Struct.fields.len),
+ });
+ for (0..fields.len) |field_index| {
+ const field = fields.at(field_index, source_pool);
+ const field_name = try pool.string(allocator, field.name.slice(source_pool));
+ pool.addExtraAssumeCapacity(Field, .{
+ .name = field_name.index,
+ .ctype = pool_adapter.copy(field.ctype).index,
+ .flags = .{ .alignas = field.alignas },
+ });
+ }
+ },
+ .owner_decl => |owner_decl| pool.items.appendAssumeCapacity(.{
+ .tag = tag,
+ .data = @intFromEnum(owner_decl),
+ }),
+ },
+ .aggregate => |aggregate_info| {
+ pool.items.appendAssumeCapacity(.{
+ .tag = tag,
+ .data = switch (aggregate_info.name) {
+ .anon => |anon| try pool.addExtra(allocator, AggregateAnon, .{
+ .owner_decl = anon.owner_decl,
+ .id = anon.id,
+ .fields_len = aggregate_info.fields.len,
+ }, aggregate_info.fields.len * @typeInfo(Field).Struct.fields.len),
+ .fwd_decl => |fwd_decl| try pool.addExtra(allocator, Aggregate, .{
+ .fwd_decl = pool_adapter.copy(fwd_decl).index,
+ .fields_len = aggregate_info.fields.len,
+ }, aggregate_info.fields.len * @typeInfo(Field).Struct.fields.len),
+ },
+ });
+ for (0..aggregate_info.fields.len) |field_index| {
+ const field = aggregate_info.fields.at(field_index, source_pool);
+ const field_name = try pool.string(allocator, field.name.slice(source_pool));
+ pool.addExtraAssumeCapacity(Field, .{
+ .name = field_name.index,
+ .ctype = pool_adapter.copy(field.ctype).index,
+ .flags = .{ .alignas = field.alignas },
+ });
+ }
+ },
+ .function => |function_info| {
+ pool.items.appendAssumeCapacity(.{
+ .tag = tag,
+ .data = try pool.addExtra(allocator, Function, .{
+ .return_ctype = pool_adapter.copy(function_info.return_ctype).index,
+ .param_ctypes_len = function_info.param_ctypes.len,
+ }, function_info.param_ctypes.len),
+ });
+ for (0..function_info.param_ctypes.len) |param_index| pool.extra.appendAssumeCapacity(
+ @intFromEnum(pool_adapter.copy(
+ function_info.param_ctypes.at(param_index, source_pool),
+ ).index),
+ );
+ },
+ };
+ assert(source_info.eqlAdapted(source_pool, ctype, pool, pool_adapter));
+ assert(source_ctype.hash(source_pool) == ctype.hash(pool));
+ return .{ ctype, gop.found_existing };
+ }
+
+ pub fn string(pool: *Pool, allocator: std.mem.Allocator, str: []const u8) !String {
+ try pool.string_bytes.appendSlice(allocator, str);
+ return pool.trailingString(allocator);
+ }
+
+ pub fn fmt(
+ pool: *Pool,
+ allocator: std.mem.Allocator,
+ comptime fmt_str: []const u8,
+ fmt_args: anytype,
+ ) !String {
+ try pool.string_bytes.writer(allocator).print(fmt_str, fmt_args);
+ return pool.trailingString(allocator);
+ }
+
+ fn ensureUnusedCapacity(pool: *Pool, allocator: std.mem.Allocator, len: u32) !void {
+ try pool.map.ensureUnusedCapacity(allocator, len);
+ try pool.items.ensureUnusedCapacity(allocator, len);
+ }
+
+ const Hasher = struct {
+ const Impl = std.hash.Wyhash;
+ impl: Impl,
+
+ const init: Hasher = .{ .impl = Impl.init(0) };
+
+ fn updateExtra(hasher: *Hasher, comptime Extra: type, extra: Extra, pool: *const Pool) void {
+ inline for (@typeInfo(Extra).Struct.fields) |field| {
+ const value = @field(extra, field.name);
+ hasher.update(switch (field.type) {
+ Tag, String, CType => unreachable,
+ CType.Index => (CType{ .index = value }).hash(pool),
+ String.Index => (String{ .index = value }).slice(pool),
+ else => value,
+ });
+ }
+ }
+ fn update(hasher: *Hasher, data: anytype) void {
+ switch (@TypeOf(data)) {
+ Tag => @compileError("pass tag to final"),
+ CType, CType.Index => @compileError("hash ctype.hash(pool) instead"),
+ String, String.Index => @compileError("hash string.slice(pool) instead"),
+ u32, DeclIndex, Aligned.Flags => hasher.impl.update(std.mem.asBytes(&data)),
+ []const u8 => hasher.impl.update(data),
+ else => @compileError("unhandled type: " ++ @typeName(@TypeOf(data))),
+ }
+ }
+
+ fn final(hasher: Hasher, tag: Tag) Map.Hash {
+ var impl = hasher.impl;
+ impl.update(std.mem.asBytes(&tag));
+ return @truncate(impl.final());
+ }
+ };
+
+ fn tagData(
+ pool: *Pool,
+ allocator: std.mem.Allocator,
+ hasher: Hasher,
+ tag: Tag,
+ data: u32,
+ ) !CType {
+ try pool.ensureUnusedCapacity(allocator, 1);
+ const Key = struct { hash: Map.Hash, tag: Tag, data: u32 };
+ const CTypeAdapter = struct {
+ pool: *const Pool,
+ pub fn hash(_: @This(), key: Key) Map.Hash {
+ return key.hash;
+ }
+ pub fn eql(ctype_adapter: @This(), lhs_key: Key, _: void, rhs_index: usize) bool {
+ const rhs_item = ctype_adapter.pool.items.get(rhs_index);
+ return lhs_key.tag == rhs_item.tag and lhs_key.data == rhs_item.data;
+ }
+ };
+ const gop = pool.map.getOrPutAssumeCapacityAdapted(
+ Key{ .hash = hasher.final(tag), .tag = tag, .data = data },
+ CTypeAdapter{ .pool = pool },
+ );
+ if (!gop.found_existing) pool.items.appendAssumeCapacity(.{ .tag = tag, .data = data });
+ return CType.fromPoolIndex(gop.index);
+ }
+
+ fn tagExtra(
+ pool: *Pool,
+ allocator: std.mem.Allocator,
+ tag: Tag,
+ comptime Extra: type,
+ extra: Extra,
+ ) !CType {
+ var hasher = Hasher.init;
+ hasher.updateExtra(Extra, extra, pool);
+ return pool.tagTrailingExtra(
+ allocator,
+ hasher,
+ tag,
+ try pool.addExtra(allocator, Extra, extra, 0),
+ );
+ }
+
+ fn tagTrailingExtra(
+ pool: *Pool,
+ allocator: std.mem.Allocator,
+ hasher: Hasher,
+ tag: Tag,
+ extra_index: ExtraIndex,
+ ) !CType {
+ try pool.ensureUnusedCapacity(allocator, 1);
+ return pool.tagTrailingExtraAssumeCapacity(hasher, tag, extra_index);
+ }
+
+ fn tagTrailingExtraAssumeCapacity(
+ pool: *Pool,
+ hasher: Hasher,
+ tag: Tag,
+ extra_index: ExtraIndex,
+ ) CType {
+ const Key = struct { hash: Map.Hash, tag: Tag, extra: []const u32 };
+ const CTypeAdapter = struct {
+ pool: *const Pool,
+ pub fn hash(_: @This(), key: Key) Map.Hash {
+ return key.hash;
+ }
+ pub fn eql(ctype_adapter: @This(), lhs_key: Key, _: void, rhs_index: usize) bool {
+ const rhs_item = ctype_adapter.pool.items.get(rhs_index);
+ if (lhs_key.tag != rhs_item.tag) return false;
+ const rhs_extra = ctype_adapter.pool.extra.items[rhs_item.data..];
+ return std.mem.startsWith(u32, rhs_extra, lhs_key.extra);
+ }
+ };
+ const gop = pool.map.getOrPutAssumeCapacityAdapted(
+ Key{ .hash = hasher.final(tag), .tag = tag, .extra = pool.extra.items[extra_index..] },
+ CTypeAdapter{ .pool = pool },
+ );
+ if (gop.found_existing)
+ pool.extra.shrinkRetainingCapacity(extra_index)
+ else
+ pool.items.appendAssumeCapacity(.{ .tag = tag, .data = extra_index });
+ return CType.fromPoolIndex(gop.index);
+ }
+
+ fn sortFields(fields: []Info.Field) void {
+ std.mem.sort(Info.Field, fields, {}, struct {
+ fn before(_: void, lhs_field: Info.Field, rhs_field: Info.Field) bool {
+ return lhs_field.alignas.order(rhs_field.alignas).compare(.gt);
+ }
+ }.before);
+ }
+
+ fn trailingString(pool: *Pool, allocator: std.mem.Allocator) !String {
+ const StringAdapter = struct {
+ pool: *const Pool,
+ pub fn hash(_: @This(), slice: []const u8) Map.Hash {
+ return @truncate(Hasher.Impl.hash(1, slice));
+ }
+ pub fn eql(string_adapter: @This(), lhs_slice: []const u8, _: void, rhs_index: usize) bool {
+ const rhs_string: String = .{ .index = @enumFromInt(rhs_index) };
+ const rhs_slice = rhs_string.slice(string_adapter.pool);
+ return std.mem.eql(u8, lhs_slice, rhs_slice);
+ }
+ };
+ try pool.string_map.ensureUnusedCapacity(allocator, 1);
+ try pool.string_indices.ensureUnusedCapacity(allocator, 1);
+
+ const start = pool.string_indices.getLast();
+ const gop = pool.string_map.getOrPutAssumeCapacityAdapted(
+ @as([]const u8, pool.string_bytes.items[start..]),
+ StringAdapter{ .pool = pool },
+ );
+ if (gop.found_existing)
+ pool.string_bytes.shrinkRetainingCapacity(start)
+ else
+ pool.string_indices.appendAssumeCapacity(@intCast(pool.string_bytes.items.len));
+ return .{ .index = @enumFromInt(gop.index) };
+ }
+
+ const Item = struct {
+ tag: Tag,
+ data: u32,
+ };
+
+ const ExtraIndex = u32;
+
+ const Tag = enum(u8) {
+ basic,
+ pointer,
+ pointer_const,
+ pointer_volatile,
+ pointer_const_volatile,
+ aligned,
+ array_small,
+ array_large,
+ vector,
+ fwd_decl_struct_anon,
+ fwd_decl_union_anon,
+ fwd_decl_struct,
+ fwd_decl_union,
+ aggregate_struct_anon,
+ aggregate_struct_packed_anon,
+ aggregate_union_anon,
+ aggregate_union_packed_anon,
+ aggregate_struct,
+ aggregate_struct_packed,
+ aggregate_union,
+ aggregate_union_packed,
+ function,
+ function_varargs,
+ };
+
+ const Aligned = struct {
+ ctype: CType.Index,
+ flags: Flags,
+
+ const Flags = packed struct(u32) {
+ alignas: AlignAs,
+ _: u20 = 0,
+ };
+ };
+
+ const SequenceSmall = struct {
+ elem_ctype: CType.Index,
+ len: u32,
+ };
+
+ const SequenceLarge = struct {
+ elem_ctype: CType.Index,
+ len_lo: u32,
+ len_hi: u32,
+
+ fn len(extra: SequenceLarge) u64 {
+ return @as(u64, extra.len_lo) << 0 |
+ @as(u64, extra.len_hi) << 32;
+ }
+ };
+
+ const Field = struct {
+ name: String.Index,
+ ctype: CType.Index,
+ flags: Flags,
+
+ const Flags = Aligned.Flags;
+ };
+
+ const FwdDeclAnon = struct {
+ fields_len: u32,
+ };
+
+ const AggregateAnon = struct {
+ owner_decl: DeclIndex,
+ id: u32,
+ fields_len: u32,
+ };
+
+ const Aggregate = struct {
+ fwd_decl: CType.Index,
+ fields_len: u32,
+ };
+
+ const Function = struct {
+ return_ctype: CType.Index,
+ param_ctypes_len: u32,
+ };
+
+ fn addExtra(
+ pool: *Pool,
+ allocator: std.mem.Allocator,
+ comptime Extra: type,
+ extra: Extra,
+ trailing_len: usize,
+ ) !ExtraIndex {
+ try pool.extra.ensureUnusedCapacity(
+ allocator,
+ @typeInfo(Extra).Struct.fields.len + trailing_len,
+ );
+ defer pool.addExtraAssumeCapacity(Extra, extra);
+ return @intCast(pool.extra.items.len);
+ }
+ fn addExtraAssumeCapacity(pool: *Pool, comptime Extra: type, extra: Extra) void {
+ addExtraAssumeCapacityTo(&pool.extra, Extra, extra);
+ }
+ fn addExtraAssumeCapacityTo(
+ array: *std.ArrayListUnmanaged(u32),
+ comptime Extra: type,
+ extra: Extra,
+ ) void {
+ inline for (@typeInfo(Extra).Struct.fields) |field| {
+ const value = @field(extra, field.name);
+ array.appendAssumeCapacity(switch (field.type) {
+ u32 => value,
+ CType.Index, String.Index, DeclIndex => @intFromEnum(value),
+ Aligned.Flags => @bitCast(value),
+ else => @compileError("bad field type: " ++ field.name ++ ": " ++
+ @typeName(field.type)),
+ });
+ }
+ }
+
+ fn addHashedExtra(
+ pool: *Pool,
+ allocator: std.mem.Allocator,
+ hasher: *Hasher,
+ comptime Extra: type,
+ extra: Extra,
+ trailing_len: usize,
+ ) !ExtraIndex {
+ hasher.updateExtra(Extra, extra, pool);
+ return pool.addExtra(allocator, Extra, extra, trailing_len);
+ }
+ fn addHashedExtraAssumeCapacity(
+ pool: *Pool,
+ hasher: *Hasher,
+ comptime Extra: type,
+ extra: Extra,
+ ) void {
+ hasher.updateExtra(Extra, extra, pool);
+ pool.addExtraAssumeCapacity(Extra, extra);
+ }
+ fn addHashedExtraAssumeCapacityTo(
+ pool: *Pool,
+ array: *std.ArrayListUnmanaged(u32),
+ hasher: *Hasher,
+ comptime Extra: type,
+ extra: Extra,
+ ) void {
+ hasher.updateExtra(Extra, extra, pool);
+ addExtraAssumeCapacityTo(array, Extra, extra);
+ }
+
+ const ExtraTrail = struct {
+ extra_index: ExtraIndex,
+
+ fn next(
+ extra_trail: *ExtraTrail,
+ len: u32,
+ comptime Extra: type,
+ pool: *const Pool,
+ ) []const Extra {
+ defer extra_trail.extra_index += @intCast(len);
+ return @ptrCast(pool.extra.items[extra_trail.extra_index..][0..len]);
+ }
+ };
+
+ fn getExtraTrail(
+ pool: *const Pool,
+ comptime Extra: type,
+ extra_index: ExtraIndex,
+ ) struct { extra: Extra, trail: ExtraTrail } {
+ var extra: Extra = undefined;
+ const fields = @typeInfo(Extra).Struct.fields;
+ inline for (fields, pool.extra.items[extra_index..][0..fields.len]) |field, value|
+ @field(extra, field.name) = switch (field.type) {
+ u32 => value,
+ CType.Index, String.Index, DeclIndex => @enumFromInt(value),
+ Aligned.Flags => @bitCast(value),
+ else => @compileError("bad field type: " ++ field.name ++ ": " ++ @typeName(field.type)),
+ };
+ return .{
+ .extra = extra,
+ .trail = .{ .extra_index = extra_index + @as(ExtraIndex, @intCast(fields.len)) },
+ };
+ }
+
+ fn getExtra(pool: *const Pool, comptime Extra: type, extra_index: ExtraIndex) Extra {
+ return pool.getExtraTrail(Extra, extra_index).extra;
+ }
+};
+
+pub const AlignAs = packed struct {
+ @"align": Alignment,
+ abi: Alignment,
+
+ pub fn fromAlignment(alignas: AlignAs) AlignAs {
+ assert(alignas.abi != .none);
+ return .{
+ .@"align" = if (alignas.@"align" != .none) alignas.@"align" else alignas.abi,
+ .abi = alignas.abi,
+ };
+ }
+ pub fn fromAbiAlignment(abi: Alignment) AlignAs {
+ assert(abi != .none);
+ return .{ .@"align" = abi, .abi = abi };
+ }
+ pub fn fromByteUnits(@"align": u64, abi: u64) AlignAs {
+ return fromAlignment(.{
+ .@"align" = Alignment.fromByteUnits(@"align"),
+ .abi = Alignment.fromNonzeroByteUnits(abi),
+ });
+ }
+
+ pub fn order(lhs: AlignAs, rhs: AlignAs) std.math.Order {
+ return lhs.@"align".order(rhs.@"align");
+ }
+ pub fn abiOrder(alignas: AlignAs) std.math.Order {
+ return alignas.@"align".order(alignas.abi);
+ }
+ pub fn toByteUnits(alignas: AlignAs) u64 {
+ return alignas.@"align".toByteUnits().?;
+ }
+};
+
+const Alignment = @import("../../InternPool.zig").Alignment;
+const assert = std.debug.assert;
+const CType = @This();
+const DeclIndex = std.zig.DeclIndex;
+const Module = @import("../../Package/Module.zig");
+const std = @import("std");
+const Type = @import("../../type.zig").Type;
+const Zcu = @import("../../Module.zig");
src/codegen/c/type.zig
@@ -1,2332 +0,0 @@
-const std = @import("std");
-const mem = std.mem;
-const Allocator = mem.Allocator;
-const assert = std.debug.assert;
-const autoHash = std.hash.autoHash;
-
-const Alignment = @import("../../InternPool.zig").Alignment;
-const Zcu = @import("../../Module.zig");
-const Module = @import("../../Package/Module.zig");
-const InternPool = @import("../../InternPool.zig");
-const Type = @import("../../type.zig").Type;
-
-pub const CType = extern union {
- /// If the tag value is less than Tag.no_payload_count, then no pointer
- /// dereference is needed.
- tag_if_small_enough: Tag,
- ptr_otherwise: *const Payload,
-
- pub fn initTag(small_tag: Tag) CType {
- assert(!small_tag.hasPayload());
- return .{ .tag_if_small_enough = small_tag };
- }
-
- pub fn initPayload(pl: anytype) CType {
- const T = @typeInfo(@TypeOf(pl)).Pointer.child;
- return switch (pl.base.tag) {
- inline else => |t| if (comptime t.hasPayload() and t.Type() == T) .{
- .ptr_otherwise = &pl.base,
- } else unreachable,
- };
- }
-
- pub fn hasPayload(self: CType) bool {
- return self.tag_if_small_enough.hasPayload();
- }
-
- pub fn tag(self: CType) Tag {
- return if (self.hasPayload()) self.ptr_otherwise.tag else self.tag_if_small_enough;
- }
-
- pub fn cast(self: CType, comptime T: type) ?*const T {
- if (!self.hasPayload()) return null;
- const pl = self.ptr_otherwise;
- return switch (pl.tag) {
- inline else => |t| if (comptime t.hasPayload() and t.Type() == T)
- @fieldParentPtr(T, "base", pl)
- else
- null,
- };
- }
-
- pub fn castTag(self: CType, comptime t: Tag) ?*const t.Type() {
- return if (self.tag() == t) @fieldParentPtr(t.Type(), "base", self.ptr_otherwise) else null;
- }
-
- pub const Tag = enum(usize) {
- // The first section of this enum are tags that require no payload.
- void,
-
- // C basic types
- char,
-
- @"signed char",
- short,
- int,
- long,
- @"long long",
-
- _Bool,
- @"unsigned char",
- @"unsigned short",
- @"unsigned int",
- @"unsigned long",
- @"unsigned long long",
-
- float,
- double,
- @"long double",
-
- // C header types
- // - stdbool.h
- bool,
- // - stddef.h
- size_t,
- ptrdiff_t,
- // - stdint.h
- uint8_t,
- int8_t,
- uint16_t,
- int16_t,
- uint32_t,
- int32_t,
- uint64_t,
- int64_t,
- uintptr_t,
- intptr_t,
-
- // zig.h types
- zig_u128,
- zig_i128,
- zig_f16,
- zig_f32,
- zig_f64,
- zig_f80,
- zig_f128,
- zig_c_longdouble, // Keep last_no_payload_tag updated!
-
- // After this, the tag requires a payload.
- pointer,
- pointer_const,
- pointer_volatile,
- pointer_const_volatile,
- array,
- vector,
- fwd_anon_struct,
- fwd_anon_union,
- fwd_struct,
- fwd_union,
- unnamed_struct,
- unnamed_union,
- packed_unnamed_struct,
- packed_unnamed_union,
- anon_struct,
- anon_union,
- @"struct",
- @"union",
- packed_struct,
- packed_union,
- function,
- varargs_function,
-
- pub const last_no_payload_tag = Tag.zig_c_longdouble;
- pub const no_payload_count = @intFromEnum(last_no_payload_tag) + 1;
-
- pub fn hasPayload(self: Tag) bool {
- return @intFromEnum(self) >= no_payload_count;
- }
-
- pub fn toIndex(self: Tag) Index {
- assert(!self.hasPayload());
- return @as(Index, @intCast(@intFromEnum(self)));
- }
-
- pub fn Type(comptime self: Tag) type {
- return switch (self) {
- .void,
- .char,
- .@"signed char",
- .short,
- .int,
- .long,
- .@"long long",
- ._Bool,
- .@"unsigned char",
- .@"unsigned short",
- .@"unsigned int",
- .@"unsigned long",
- .@"unsigned long long",
- .float,
- .double,
- .@"long double",
- .bool,
- .size_t,
- .ptrdiff_t,
- .uint8_t,
- .int8_t,
- .uint16_t,
- .int16_t,
- .uint32_t,
- .int32_t,
- .uint64_t,
- .int64_t,
- .uintptr_t,
- .intptr_t,
- .zig_u128,
- .zig_i128,
- .zig_f16,
- .zig_f32,
- .zig_f64,
- .zig_f80,
- .zig_f128,
- .zig_c_longdouble,
- => @compileError("Type Tag " ++ @tagName(self) ++ " has no payload"),
-
- .pointer,
- .pointer_const,
- .pointer_volatile,
- .pointer_const_volatile,
- => Payload.Child,
-
- .array,
- .vector,
- => Payload.Sequence,
-
- .fwd_anon_struct,
- .fwd_anon_union,
- => Payload.Fields,
-
- .fwd_struct,
- .fwd_union,
- => Payload.FwdDecl,
-
- .unnamed_struct,
- .unnamed_union,
- .packed_unnamed_struct,
- .packed_unnamed_union,
- => Payload.Unnamed,
-
- .anon_struct,
- .anon_union,
- .@"struct",
- .@"union",
- .packed_struct,
- .packed_union,
- => Payload.Aggregate,
-
- .function,
- .varargs_function,
- => Payload.Function,
- };
- }
- };
-
- pub const Payload = struct {
- tag: Tag,
-
- pub const Child = struct {
- base: Payload,
- data: Index,
- };
-
- pub const Sequence = struct {
- base: Payload,
- data: struct {
- len: u64,
- elem_type: Index,
- },
- };
-
- pub const FwdDecl = struct {
- base: Payload,
- data: InternPool.DeclIndex,
- };
-
- pub const Fields = struct {
- base: Payload,
- data: Data,
-
- pub const Data = []const Field;
- pub const Field = struct {
- name: [*:0]const u8,
- type: Index,
- alignas: AlignAs,
- };
- };
-
- pub const Unnamed = struct {
- base: Payload,
- data: struct {
- fields: Fields.Data,
- owner_decl: InternPool.DeclIndex,
- id: u32,
- },
- };
-
- pub const Aggregate = struct {
- base: Payload,
- data: struct {
- fields: Fields.Data,
- fwd_decl: Index,
- },
- };
-
- pub const Function = struct {
- base: Payload,
- data: struct {
- return_type: Index,
- param_types: []const Index,
- },
- };
- };
-
- pub const AlignAs = packed struct {
- @"align": Alignment,
- abi: Alignment,
-
- pub fn init(@"align": Alignment, abi_align: Alignment) AlignAs {
- assert(abi_align != .none);
- return .{
- .@"align" = if (@"align" != .none) @"align" else abi_align,
- .abi = abi_align,
- };
- }
-
- pub fn initByteUnits(alignment: u64, abi_alignment: u32) AlignAs {
- return init(
- Alignment.fromByteUnits(alignment),
- Alignment.fromNonzeroByteUnits(abi_alignment),
- );
- }
- pub fn abiAlign(ty: Type, zcu: *Zcu) AlignAs {
- const abi_align = ty.abiAlignment(zcu);
- return init(abi_align, abi_align);
- }
- pub fn fieldAlign(struct_ty: Type, field_i: usize, zcu: *Zcu) AlignAs {
- return init(
- struct_ty.structFieldAlign(field_i, zcu),
- struct_ty.structFieldType(field_i, zcu).abiAlignment(zcu),
- );
- }
- pub fn unionPayloadAlign(union_ty: Type, zcu: *Zcu) AlignAs {
- const union_obj = zcu.typeToUnion(union_ty).?;
- const union_payload_align = zcu.unionAbiAlignment(union_obj);
- return init(union_payload_align, union_payload_align);
- }
-
- pub fn order(lhs: AlignAs, rhs: AlignAs) std.math.Order {
- return lhs.@"align".order(rhs.@"align");
- }
- pub fn abiOrder(self: AlignAs) std.math.Order {
- return self.@"align".order(self.abi);
- }
- pub fn toByteUnits(self: AlignAs) u64 {
- return self.@"align".toByteUnitsOptional().?;
- }
- };
-
- pub const Index = u32;
- pub const Store = struct {
- arena: std.heap.ArenaAllocator.State = .{},
- set: Set = .{},
-
- pub const Set = struct {
- pub const Map = std.ArrayHashMapUnmanaged(CType, void, HashContext, true);
- const HashContext = struct {
- store: *const Set,
-
- pub fn hash(self: @This(), cty: CType) Map.Hash {
- return @as(Map.Hash, @truncate(cty.hash(self.store.*)));
- }
- pub fn eql(_: @This(), lhs: CType, rhs: CType, _: usize) bool {
- return lhs.eql(rhs);
- }
- };
-
- map: Map = .{},
-
- pub fn indexToCType(self: Set, index: Index) CType {
- if (index < Tag.no_payload_count) return initTag(@as(Tag, @enumFromInt(index)));
- return self.map.keys()[index - Tag.no_payload_count];
- }
-
- pub fn indexToHash(self: Set, index: Index) Map.Hash {
- if (index < Tag.no_payload_count)
- return (HashContext{ .store = &self }).hash(self.indexToCType(index));
- return self.map.entries.items(.hash)[index - Tag.no_payload_count];
- }
-
- pub fn typeToIndex(self: Set, ty: Type, zcu: *Zcu, mod: *Module, kind: Kind) ?Index {
- const lookup = Convert.Lookup{ .imm = .{ .set = &self, .zcu = zcu, .mod = mod } };
-
- var convert: Convert = undefined;
- convert.initType(ty, kind, lookup) catch unreachable;
-
- const t = convert.tag();
- if (!t.hasPayload()) return t.toIndex();
-
- return if (self.map.getIndexAdapted(
- ty,
- TypeAdapter32{ .kind = kind, .lookup = lookup, .convert = &convert },
- )) |idx| @as(Index, @intCast(Tag.no_payload_count + idx)) else null;
- }
- };
-
- pub const Promoted = struct {
- arena: std.heap.ArenaAllocator,
- set: Set,
-
- pub fn gpa(self: *Promoted) Allocator {
- return self.arena.child_allocator;
- }
-
- pub fn cTypeToIndex(self: *Promoted, cty: CType) Allocator.Error!Index {
- const t = cty.tag();
- if (@intFromEnum(t) < Tag.no_payload_count) return @as(Index, @intCast(@intFromEnum(t)));
-
- const gop = try self.set.map.getOrPutContext(self.gpa(), cty, .{ .store = &self.set });
- if (!gop.found_existing) gop.key_ptr.* = cty;
- if (std.debug.runtime_safety) {
- const key = &self.set.map.entries.items(.key)[gop.index];
- assert(key == gop.key_ptr);
- assert(cty.eql(key.*));
- assert(cty.hash(self.set) == key.hash(self.set));
- }
- return @as(Index, @intCast(Tag.no_payload_count + gop.index));
- }
-
- pub fn typeToIndex(
- self: *Promoted,
- ty: Type,
- zcu: *Zcu,
- mod: *Module,
- kind: Kind,
- ) Allocator.Error!Index {
- const lookup = Convert.Lookup{ .mut = .{ .promoted = self, .zcu = zcu, .mod = mod } };
-
- var convert: Convert = undefined;
- try convert.initType(ty, kind, lookup);
-
- const t = convert.tag();
- if (!t.hasPayload()) return t.toIndex();
-
- const gop = try self.set.map.getOrPutContextAdapted(
- self.gpa(),
- ty,
- TypeAdapter32{ .kind = kind, .lookup = lookup.freeze(), .convert = &convert },
- .{ .store = &self.set },
- );
- if (!gop.found_existing) {
- errdefer _ = self.set.map.pop();
- gop.key_ptr.* = try createFromConvert(self, ty, zcu, mod, kind, convert);
- }
- if (std.debug.runtime_safety) {
- const adapter = TypeAdapter64{
- .kind = kind,
- .lookup = lookup.freeze(),
- .convert = &convert,
- };
- const cty = &self.set.map.entries.items(.key)[gop.index];
- assert(cty == gop.key_ptr);
- assert(adapter.eql(ty, cty.*));
- assert(adapter.hash(ty) == cty.hash(self.set));
- }
- return @as(Index, @intCast(Tag.no_payload_count + gop.index));
- }
- };
-
- pub fn promote(self: Store, gpa: Allocator) Promoted {
- return .{ .arena = self.arena.promote(gpa), .set = self.set };
- }
-
- pub fn demote(self: *Store, promoted: Promoted) void {
- self.arena = promoted.arena.state;
- self.set = promoted.set;
- }
-
- pub fn indexToCType(self: Store, index: Index) CType {
- return self.set.indexToCType(index);
- }
-
- pub fn indexToHash(self: Store, index: Index) Set.Map.Hash {
- return self.set.indexToHash(index);
- }
-
- pub fn cTypeToIndex(self: *Store, gpa: Allocator, cty: CType) !Index {
- var promoted = self.promote(gpa);
- defer self.demote(promoted);
- return promoted.cTypeToIndex(cty);
- }
-
- pub fn typeToCType(self: *Store, gpa: Allocator, ty: Type, zcu: *Zcu, mod: *Module, kind: Kind) !CType {
- const idx = try self.typeToIndex(gpa, ty, zcu, mod, kind);
- return self.indexToCType(idx);
- }
-
- pub fn typeToIndex(self: *Store, gpa: Allocator, ty: Type, zcu: *Zcu, mod: *Module, kind: Kind) !Index {
- var promoted = self.promote(gpa);
- defer self.demote(promoted);
- return promoted.typeToIndex(ty, zcu, mod, kind);
- }
-
- pub fn clearRetainingCapacity(self: *Store, gpa: Allocator) void {
- var promoted = self.promote(gpa);
- defer self.demote(promoted);
- promoted.set.map.clearRetainingCapacity();
- _ = promoted.arena.reset(.retain_capacity);
- }
-
- pub fn clearAndFree(self: *Store, gpa: Allocator) void {
- var promoted = self.promote(gpa);
- defer self.demote(promoted);
- promoted.set.map.clearAndFree(gpa);
- _ = promoted.arena.reset(.free_all);
- }
-
- pub fn shrinkRetainingCapacity(self: *Store, gpa: Allocator, new_len: usize) void {
- self.set.map.shrinkRetainingCapacity(gpa, new_len);
- }
-
- pub fn shrinkAndFree(self: *Store, gpa: Allocator, new_len: usize) void {
- self.set.map.shrinkAndFree(gpa, new_len);
- }
-
- pub fn count(self: Store) usize {
- return self.set.map.count();
- }
-
- pub fn move(self: *Store) Store {
- const moved = self.*;
- self.* = .{};
- return moved;
- }
-
- pub fn deinit(self: *Store, gpa: Allocator) void {
- var promoted = self.promote(gpa);
- promoted.set.map.deinit(gpa);
- _ = promoted.arena.deinit();
- self.* = undefined;
- }
- };
-
- pub fn isBool(self: CType) bool {
- return switch (self.tag()) {
- ._Bool,
- .bool,
- => true,
- else => false,
- };
- }
-
- pub fn isInteger(self: CType) bool {
- return switch (self.tag()) {
- .char,
- .@"signed char",
- .short,
- .int,
- .long,
- .@"long long",
- .@"unsigned char",
- .@"unsigned short",
- .@"unsigned int",
- .@"unsigned long",
- .@"unsigned long long",
- .size_t,
- .ptrdiff_t,
- .uint8_t,
- .int8_t,
- .uint16_t,
- .int16_t,
- .uint32_t,
- .int32_t,
- .uint64_t,
- .int64_t,
- .uintptr_t,
- .intptr_t,
- .zig_u128,
- .zig_i128,
- => true,
- else => false,
- };
- }
-
- pub fn signedness(self: CType, mod: *Module) std.builtin.Signedness {
- return switch (self.tag()) {
- .char => mod.resolved_target.result.charSignedness(),
- .@"signed char",
- .short,
- .int,
- .long,
- .@"long long",
- .ptrdiff_t,
- .int8_t,
- .int16_t,
- .int32_t,
- .int64_t,
- .intptr_t,
- .zig_i128,
- => .signed,
- .@"unsigned char",
- .@"unsigned short",
- .@"unsigned int",
- .@"unsigned long",
- .@"unsigned long long",
- .size_t,
- .uint8_t,
- .uint16_t,
- .uint32_t,
- .uint64_t,
- .uintptr_t,
- .zig_u128,
- => .unsigned,
- else => unreachable,
- };
- }
-
- pub fn isFloat(self: CType) bool {
- return switch (self.tag()) {
- .float,
- .double,
- .@"long double",
- .zig_f16,
- .zig_f32,
- .zig_f64,
- .zig_f80,
- .zig_f128,
- .zig_c_longdouble,
- => true,
- else => false,
- };
- }
-
- pub fn isPointer(self: CType) bool {
- return switch (self.tag()) {
- .pointer,
- .pointer_const,
- .pointer_volatile,
- .pointer_const_volatile,
- => true,
- else => false,
- };
- }
-
- pub fn isFunction(self: CType) bool {
- return switch (self.tag()) {
- .function,
- .varargs_function,
- => true,
- else => false,
- };
- }
-
- pub fn toSigned(self: CType) CType {
- return CType.initTag(switch (self.tag()) {
- .char, .@"signed char", .@"unsigned char" => .@"signed char",
- .short, .@"unsigned short" => .short,
- .int, .@"unsigned int" => .int,
- .long, .@"unsigned long" => .long,
- .@"long long", .@"unsigned long long" => .@"long long",
- .size_t, .ptrdiff_t => .ptrdiff_t,
- .uint8_t, .int8_t => .int8_t,
- .uint16_t, .int16_t => .int16_t,
- .uint32_t, .int32_t => .int32_t,
- .uint64_t, .int64_t => .int64_t,
- .uintptr_t, .intptr_t => .intptr_t,
- .zig_u128, .zig_i128 => .zig_i128,
- .float,
- .double,
- .@"long double",
- .zig_f16,
- .zig_f32,
- .zig_f80,
- .zig_f128,
- .zig_c_longdouble,
- => |t| t,
- else => unreachable,
- });
- }
-
- pub fn toUnsigned(self: CType) CType {
- return CType.initTag(switch (self.tag()) {
- .char, .@"signed char", .@"unsigned char" => .@"unsigned char",
- .short, .@"unsigned short" => .@"unsigned short",
- .int, .@"unsigned int" => .@"unsigned int",
- .long, .@"unsigned long" => .@"unsigned long",
- .@"long long", .@"unsigned long long" => .@"unsigned long long",
- .size_t, .ptrdiff_t => .size_t,
- .uint8_t, .int8_t => .uint8_t,
- .uint16_t, .int16_t => .uint16_t,
- .uint32_t, .int32_t => .uint32_t,
- .uint64_t, .int64_t => .uint64_t,
- .uintptr_t, .intptr_t => .uintptr_t,
- .zig_u128, .zig_i128 => .zig_u128,
- else => unreachable,
- });
- }
-
- pub fn toSignedness(self: CType, s: std.builtin.Signedness) CType {
- return switch (s) {
- .unsigned => self.toUnsigned(),
- .signed => self.toSigned(),
- };
- }
-
- pub fn getStandardDefineAbbrev(self: CType) ?[]const u8 {
- return switch (self.tag()) {
- .char => "CHAR",
- .@"signed char" => "SCHAR",
- .short => "SHRT",
- .int => "INT",
- .long => "LONG",
- .@"long long" => "LLONG",
- .@"unsigned char" => "UCHAR",
- .@"unsigned short" => "USHRT",
- .@"unsigned int" => "UINT",
- .@"unsigned long" => "ULONG",
- .@"unsigned long long" => "ULLONG",
- .float => "FLT",
- .double => "DBL",
- .@"long double" => "LDBL",
- .size_t => "SIZE",
- .ptrdiff_t => "PTRDIFF",
- .uint8_t => "UINT8",
- .int8_t => "INT8",
- .uint16_t => "UINT16",
- .int16_t => "INT16",
- .uint32_t => "UINT32",
- .int32_t => "INT32",
- .uint64_t => "UINT64",
- .int64_t => "INT64",
- .uintptr_t => "UINTPTR",
- .intptr_t => "INTPTR",
- else => null,
- };
- }
-
- pub fn renderLiteralPrefix(self: CType, writer: anytype, kind: Kind) @TypeOf(writer).Error!void {
- switch (self.tag()) {
- .void => unreachable,
- ._Bool,
- .char,
- .@"signed char",
- .short,
- .@"unsigned short",
- .bool,
- .size_t,
- .ptrdiff_t,
- .uintptr_t,
- .intptr_t,
- => |t| switch (kind) {
- else => try writer.print("({s})", .{@tagName(t)}),
- .global => {},
- },
- .int,
- .long,
- .@"long long",
- .@"unsigned char",
- .@"unsigned int",
- .@"unsigned long",
- .@"unsigned long long",
- .float,
- .double,
- .@"long double",
- => {},
- .uint8_t,
- .int8_t,
- .uint16_t,
- .int16_t,
- .uint32_t,
- .int32_t,
- .uint64_t,
- .int64_t,
- => try writer.print("{s}_C(", .{self.getStandardDefineAbbrev().?}),
- .zig_u128,
- .zig_i128,
- .zig_f16,
- .zig_f32,
- .zig_f64,
- .zig_f80,
- .zig_f128,
- .zig_c_longdouble,
- => |t| try writer.print("zig_{s}_{s}(", .{
- switch (kind) {
- else => "make",
- .global => "init",
- },
- @tagName(t)["zig_".len..],
- }),
- .pointer,
- .pointer_const,
- .pointer_volatile,
- .pointer_const_volatile,
- => unreachable,
- .array,
- .vector,
- => try writer.writeByte('{'),
- .fwd_anon_struct,
- .fwd_anon_union,
- .fwd_struct,
- .fwd_union,
- .unnamed_struct,
- .unnamed_union,
- .packed_unnamed_struct,
- .packed_unnamed_union,
- .anon_struct,
- .anon_union,
- .@"struct",
- .@"union",
- .packed_struct,
- .packed_union,
- .function,
- .varargs_function,
- => unreachable,
- }
- }
-
- pub fn renderLiteralSuffix(self: CType, writer: anytype) @TypeOf(writer).Error!void {
- switch (self.tag()) {
- .void => unreachable,
- ._Bool => {},
- .char,
- .@"signed char",
- .short,
- .int,
- => {},
- .long => try writer.writeByte('l'),
- .@"long long" => try writer.writeAll("ll"),
- .@"unsigned char",
- .@"unsigned short",
- .@"unsigned int",
- => try writer.writeByte('u'),
- .@"unsigned long",
- .size_t,
- .uintptr_t,
- => try writer.writeAll("ul"),
- .@"unsigned long long" => try writer.writeAll("ull"),
- .float => try writer.writeByte('f'),
- .double => {},
- .@"long double" => try writer.writeByte('l'),
- .bool,
- .ptrdiff_t,
- .intptr_t,
- => {},
- .uint8_t,
- .int8_t,
- .uint16_t,
- .int16_t,
- .uint32_t,
- .int32_t,
- .uint64_t,
- .int64_t,
- .zig_u128,
- .zig_i128,
- .zig_f16,
- .zig_f32,
- .zig_f64,
- .zig_f80,
- .zig_f128,
- .zig_c_longdouble,
- => try writer.writeByte(')'),
- .pointer,
- .pointer_const,
- .pointer_volatile,
- .pointer_const_volatile,
- => unreachable,
- .array,
- .vector,
- => try writer.writeByte('}'),
- .fwd_anon_struct,
- .fwd_anon_union,
- .fwd_struct,
- .fwd_union,
- .unnamed_struct,
- .unnamed_union,
- .packed_unnamed_struct,
- .packed_unnamed_union,
- .anon_struct,
- .anon_union,
- .@"struct",
- .@"union",
- .packed_struct,
- .packed_union,
- .function,
- .varargs_function,
- => unreachable,
- }
- }
-
- pub fn floatActiveBits(self: CType, mod: *Module) u16 {
- const target = &mod.resolved_target.result;
- return switch (self.tag()) {
- .float => target.c_type_bit_size(.float),
- .double => target.c_type_bit_size(.double),
- .@"long double", .zig_c_longdouble => target.c_type_bit_size(.longdouble),
- .zig_f16 => 16,
- .zig_f32 => 32,
- .zig_f64 => 64,
- .zig_f80 => 80,
- .zig_f128 => 128,
- else => unreachable,
- };
- }
-
- pub fn byteSize(self: CType, store: Store.Set, mod: *Module) u64 {
- const target = &mod.resolved_target.result;
- return switch (self.tag()) {
- .void => 0,
- .char, .@"signed char", ._Bool, .@"unsigned char", .bool, .uint8_t, .int8_t => 1,
- .short => target.c_type_byte_size(.short),
- .int => target.c_type_byte_size(.int),
- .long => target.c_type_byte_size(.long),
- .@"long long" => target.c_type_byte_size(.longlong),
- .@"unsigned short" => target.c_type_byte_size(.ushort),
- .@"unsigned int" => target.c_type_byte_size(.uint),
- .@"unsigned long" => target.c_type_byte_size(.ulong),
- .@"unsigned long long" => target.c_type_byte_size(.ulonglong),
- .float => target.c_type_byte_size(.float),
- .double => target.c_type_byte_size(.double),
- .@"long double" => target.c_type_byte_size(.longdouble),
- .size_t,
- .ptrdiff_t,
- .uintptr_t,
- .intptr_t,
- .pointer,
- .pointer_const,
- .pointer_volatile,
- .pointer_const_volatile,
- => @divExact(target.ptrBitWidth(), 8),
- .uint16_t, .int16_t, .zig_f16 => 2,
- .uint32_t, .int32_t, .zig_f32 => 4,
- .uint64_t, .int64_t, .zig_f64 => 8,
- .zig_u128, .zig_i128, .zig_f128 => 16,
- .zig_f80 => if (target.c_type_bit_size(.longdouble) == 80)
- target.c_type_byte_size(.longdouble)
- else
- 16,
- .zig_c_longdouble => target.c_type_byte_size(.longdouble),
-
- .array,
- .vector,
- => {
- const data = self.cast(Payload.Sequence).?.data;
- return data.len * store.indexToCType(data.elem_type).byteSize(store, mod);
- },
-
- .fwd_anon_struct,
- .fwd_anon_union,
- .fwd_struct,
- .fwd_union,
- .unnamed_struct,
- .unnamed_union,
- .packed_unnamed_struct,
- .packed_unnamed_union,
- .anon_struct,
- .anon_union,
- .@"struct",
- .@"union",
- .packed_struct,
- .packed_union,
- .function,
- .varargs_function,
- => unreachable,
- };
- }
-
- pub fn isPacked(self: CType) bool {
- return switch (self.tag()) {
- else => false,
- .packed_unnamed_struct,
- .packed_unnamed_union,
- .packed_struct,
- .packed_union,
- => true,
- };
- }
-
- pub fn fields(self: CType) Payload.Fields.Data {
- return if (self.cast(Payload.Aggregate)) |pl|
- pl.data.fields
- else if (self.cast(Payload.Unnamed)) |pl|
- pl.data.fields
- else if (self.cast(Payload.Fields)) |pl|
- pl.data
- else
- unreachable;
- }
-
- pub fn eql(lhs: CType, rhs: CType) bool {
- return lhs.eqlContext(rhs, struct {
- pub fn eqlIndex(_: @This(), lhs_idx: Index, rhs_idx: Index) bool {
- return lhs_idx == rhs_idx;
- }
- }{});
- }
-
- pub fn eqlContext(lhs: CType, rhs: CType, ctx: anytype) bool {
- // As a shortcut, if the small tags / addresses match, we're done.
- if (lhs.tag_if_small_enough == rhs.tag_if_small_enough) return true;
-
- const lhs_tag = lhs.tag();
- const rhs_tag = rhs.tag();
- if (lhs_tag != rhs_tag) return false;
-
- return switch (lhs_tag) {
- .void,
- .char,
- .@"signed char",
- .short,
- .int,
- .long,
- .@"long long",
- ._Bool,
- .@"unsigned char",
- .@"unsigned short",
- .@"unsigned int",
- .@"unsigned long",
- .@"unsigned long long",
- .float,
- .double,
- .@"long double",
- .bool,
- .size_t,
- .ptrdiff_t,
- .uint8_t,
- .int8_t,
- .uint16_t,
- .int16_t,
- .uint32_t,
- .int32_t,
- .uint64_t,
- .int64_t,
- .uintptr_t,
- .intptr_t,
- .zig_u128,
- .zig_i128,
- .zig_f16,
- .zig_f32,
- .zig_f64,
- .zig_f80,
- .zig_f128,
- .zig_c_longdouble,
- => false,
-
- .pointer,
- .pointer_const,
- .pointer_volatile,
- .pointer_const_volatile,
- => ctx.eqlIndex(lhs.cast(Payload.Child).?.data, rhs.cast(Payload.Child).?.data),
-
- .array,
- .vector,
- => {
- const lhs_data = lhs.cast(Payload.Sequence).?.data;
- const rhs_data = rhs.cast(Payload.Sequence).?.data;
- return lhs_data.len == rhs_data.len and
- ctx.eqlIndex(lhs_data.elem_type, rhs_data.elem_type);
- },
-
- .fwd_anon_struct,
- .fwd_anon_union,
- => {
- const lhs_data = lhs.cast(Payload.Fields).?.data;
- const rhs_data = rhs.cast(Payload.Fields).?.data;
- if (lhs_data.len != rhs_data.len) return false;
- for (lhs_data, rhs_data) |lhs_field, rhs_field| {
- if (!ctx.eqlIndex(lhs_field.type, rhs_field.type)) return false;
- if (lhs_field.alignas.@"align" != rhs_field.alignas.@"align") return false;
- if (std.mem.orderZ(u8, lhs_field.name, rhs_field.name) != .eq) return false;
- }
- return true;
- },
-
- .fwd_struct,
- .fwd_union,
- => lhs.cast(Payload.FwdDecl).?.data == rhs.cast(Payload.FwdDecl).?.data,
-
- .unnamed_struct,
- .unnamed_union,
- .packed_unnamed_struct,
- .packed_unnamed_union,
- => {
- const lhs_data = lhs.cast(Payload.Unnamed).?.data;
- const rhs_data = rhs.cast(Payload.Unnamed).?.data;
- return lhs_data.owner_decl == rhs_data.owner_decl and lhs_data.id == rhs_data.id;
- },
-
- .anon_struct,
- .anon_union,
- .@"struct",
- .@"union",
- .packed_struct,
- .packed_union,
- => ctx.eqlIndex(
- lhs.cast(Payload.Aggregate).?.data.fwd_decl,
- rhs.cast(Payload.Aggregate).?.data.fwd_decl,
- ),
-
- .function,
- .varargs_function,
- => {
- const lhs_data = lhs.cast(Payload.Function).?.data;
- const rhs_data = rhs.cast(Payload.Function).?.data;
- if (lhs_data.param_types.len != rhs_data.param_types.len) return false;
- if (!ctx.eqlIndex(lhs_data.return_type, rhs_data.return_type)) return false;
- for (lhs_data.param_types, rhs_data.param_types) |lhs_param_idx, rhs_param_idx| {
- if (!ctx.eqlIndex(lhs_param_idx, rhs_param_idx)) return false;
- }
- return true;
- },
- };
- }
-
- pub fn hash(self: CType, store: Store.Set) u64 {
- var hasher = std.hash.Wyhash.init(0);
- self.updateHasher(&hasher, store);
- return hasher.final();
- }
-
- pub fn updateHasher(self: CType, hasher: anytype, store: Store.Set) void {
- const t = self.tag();
- autoHash(hasher, t);
- switch (t) {
- .void,
- .char,
- .@"signed char",
- .short,
- .int,
- .long,
- .@"long long",
- ._Bool,
- .@"unsigned char",
- .@"unsigned short",
- .@"unsigned int",
- .@"unsigned long",
- .@"unsigned long long",
- .float,
- .double,
- .@"long double",
- .bool,
- .size_t,
- .ptrdiff_t,
- .uint8_t,
- .int8_t,
- .uint16_t,
- .int16_t,
- .uint32_t,
- .int32_t,
- .uint64_t,
- .int64_t,
- .uintptr_t,
- .intptr_t,
- .zig_u128,
- .zig_i128,
- .zig_f16,
- .zig_f32,
- .zig_f64,
- .zig_f80,
- .zig_f128,
- .zig_c_longdouble,
- => {},
-
- .pointer,
- .pointer_const,
- .pointer_volatile,
- .pointer_const_volatile,
- => store.indexToCType(self.cast(Payload.Child).?.data).updateHasher(hasher, store),
-
- .array,
- .vector,
- => {
- const data = self.cast(Payload.Sequence).?.data;
- autoHash(hasher, data.len);
- store.indexToCType(data.elem_type).updateHasher(hasher, store);
- },
-
- .fwd_anon_struct,
- .fwd_anon_union,
- => for (self.cast(Payload.Fields).?.data) |field| {
- store.indexToCType(field.type).updateHasher(hasher, store);
- hasher.update(mem.span(field.name));
- autoHash(hasher, field.alignas.@"align");
- },
-
- .fwd_struct,
- .fwd_union,
- => autoHash(hasher, self.cast(Payload.FwdDecl).?.data),
-
- .unnamed_struct,
- .unnamed_union,
- .packed_unnamed_struct,
- .packed_unnamed_union,
- => {
- const data = self.cast(Payload.Unnamed).?.data;
- autoHash(hasher, data.owner_decl);
- autoHash(hasher, data.id);
- },
-
- .anon_struct,
- .anon_union,
- .@"struct",
- .@"union",
- .packed_struct,
- .packed_union,
- => store.indexToCType(self.cast(Payload.Aggregate).?.data.fwd_decl)
- .updateHasher(hasher, store),
-
- .function,
- .varargs_function,
- => {
- const data = self.cast(Payload.Function).?.data;
- store.indexToCType(data.return_type).updateHasher(hasher, store);
- for (data.param_types) |param_ty| {
- store.indexToCType(param_ty).updateHasher(hasher, store);
- }
- },
- }
- }
-
- pub const Kind = enum { forward, forward_parameter, complete, global, parameter, payload };
-
- const Convert = struct {
- storage: union {
- none: void,
- child: Payload.Child,
- seq: Payload.Sequence,
- fwd: Payload.FwdDecl,
- anon: struct {
- fields: [2]Payload.Fields.Field,
- pl: union {
- forward: Payload.Fields,
- complete: Payload.Aggregate,
- },
- },
- },
- value: union(enum) {
- tag: Tag,
- cty: CType,
- },
-
- pub fn init(self: *@This(), t: Tag) void {
- self.* = if (t.hasPayload()) .{
- .storage = .{ .none = {} },
- .value = .{ .tag = t },
- } else .{
- .storage = .{ .none = {} },
- .value = .{ .cty = initTag(t) },
- };
- }
-
- pub fn tag(self: @This()) Tag {
- return switch (self.value) {
- .tag => |t| t,
- .cty => |c| c.tag(),
- };
- }
-
- fn tagFromIntInfo(int_info: std.builtin.Type.Int) Tag {
- return switch (int_info.bits) {
- 0 => .void,
- 1...8 => switch (int_info.signedness) {
- .unsigned => .uint8_t,
- .signed => .int8_t,
- },
- 9...16 => switch (int_info.signedness) {
- .unsigned => .uint16_t,
- .signed => .int16_t,
- },
- 17...32 => switch (int_info.signedness) {
- .unsigned => .uint32_t,
- .signed => .int32_t,
- },
- 33...64 => switch (int_info.signedness) {
- .unsigned => .uint64_t,
- .signed => .int64_t,
- },
- 65...128 => switch (int_info.signedness) {
- .unsigned => .zig_u128,
- .signed => .zig_i128,
- },
- else => .array,
- };
- }
-
- pub const Lookup = union(enum) {
- fail: struct {
- zcu: *Zcu,
- mod: *Module,
- },
- imm: struct {
- set: *const Store.Set,
- zcu: *Zcu,
- mod: *Module,
- },
- mut: struct {
- promoted: *Store.Promoted,
- zcu: *Zcu,
- mod: *Module,
- },
-
- pub fn isMutable(self: @This()) bool {
- return switch (self) {
- .fail, .imm => false,
- .mut => true,
- };
- }
-
- pub fn getZcu(self: @This()) *Zcu {
- return switch (self) {
- inline else => |pl| pl.zcu,
- };
- }
-
- pub fn getModule(self: @This()) *Module {
- return switch (self) {
- inline else => |pl| pl.mod,
- };
- }
-
- pub fn getSet(self: @This()) ?*const Store.Set {
- return switch (self) {
- .fail => null,
- .imm => |imm| imm.set,
- .mut => |mut| &mut.promoted.set,
- };
- }
-
- pub fn typeToIndex(self: @This(), ty: Type, kind: Kind) !?Index {
- return switch (self) {
- .fail => null,
- .imm => |imm| imm.set.typeToIndex(ty, imm.zcu, imm.mod, kind),
- .mut => |mut| try mut.promoted.typeToIndex(ty, mut.zcu, mut.mod, kind),
- };
- }
-
- pub fn indexToCType(self: @This(), index: Index) ?CType {
- return if (self.getSet()) |set| set.indexToCType(index) else null;
- }
-
- pub fn freeze(self: @This()) @This() {
- return switch (self) {
- .fail, .imm => self,
- .mut => |mut| .{ .imm = .{ .set = &mut.promoted.set, .zcu = mut.zcu, .mod = mut.mod } },
- };
- }
- };
-
- fn sortFields(self: *@This(), fields_len: usize) []Payload.Fields.Field {
- const Field = Payload.Fields.Field;
- const slice = self.storage.anon.fields[0..fields_len];
- mem.sort(Field, slice, {}, struct {
- fn before(_: void, lhs: Field, rhs: Field) bool {
- return lhs.alignas.order(rhs.alignas).compare(.gt);
- }
- }.before);
- return slice;
- }
-
- fn initAnon(self: *@This(), kind: Kind, fwd_idx: Index, fields_len: usize) void {
- switch (kind) {
- .forward, .forward_parameter => {
- self.storage.anon.pl = .{ .forward = .{
- .base = .{ .tag = .fwd_anon_struct },
- .data = self.sortFields(fields_len),
- } };
- self.value = .{ .cty = initPayload(&self.storage.anon.pl.forward) };
- },
- .complete, .parameter, .global => {
- self.storage.anon.pl = .{ .complete = .{
- .base = .{ .tag = .anon_struct },
- .data = .{
- .fields = self.sortFields(fields_len),
- .fwd_decl = fwd_idx,
- },
- } };
- self.value = .{ .cty = initPayload(&self.storage.anon.pl.complete) };
- },
- .payload => unreachable,
- }
- }
-
- fn initArrayParameter(self: *@This(), ty: Type, kind: Kind, lookup: Lookup) !void {
- if (switch (kind) {
- .forward_parameter => @as(Index, undefined),
- .parameter => try lookup.typeToIndex(ty, .forward_parameter),
- .forward, .complete, .global, .payload => unreachable,
- }) |fwd_idx| {
- if (try lookup.typeToIndex(ty, switch (kind) {
- .forward_parameter => .forward,
- .parameter => .complete,
- .forward, .complete, .global, .payload => unreachable,
- })) |array_idx| {
- self.storage = .{ .anon = undefined };
- self.storage.anon.fields[0] = .{
- .name = "array",
- .type = array_idx,
- .alignas = AlignAs.abiAlign(ty, lookup.getZcu()),
- };
- self.initAnon(kind, fwd_idx, 1);
- } else self.init(switch (kind) {
- .forward_parameter => .fwd_anon_struct,
- .parameter => .anon_struct,
- .forward, .complete, .global, .payload => unreachable,
- });
- } else self.init(.anon_struct);
- }
-
- pub fn initType(self: *@This(), ty: Type, kind: Kind, lookup: Lookup) !void {
- const zcu = lookup.getZcu();
- const ip = &zcu.intern_pool;
-
- self.* = undefined;
- if (!ty.isFnOrHasRuntimeBitsIgnoreComptime(zcu))
- self.init(.void)
- else if (ty.isAbiInt(zcu)) switch (ty.ip_index) {
- .usize_type => self.init(.uintptr_t),
- .isize_type => self.init(.intptr_t),
- .c_char_type => self.init(.char),
- .c_short_type => self.init(.short),
- .c_ushort_type => self.init(.@"unsigned short"),
- .c_int_type => self.init(.int),
- .c_uint_type => self.init(.@"unsigned int"),
- .c_long_type => self.init(.long),
- .c_ulong_type => self.init(.@"unsigned long"),
- .c_longlong_type => self.init(.@"long long"),
- .c_ulonglong_type => self.init(.@"unsigned long long"),
- else => switch (tagFromIntInfo(ty.intInfo(zcu))) {
- .void => unreachable,
- else => |t| self.init(t),
- .array => switch (kind) {
- .forward, .complete, .global => {
- const abi_size = ty.abiSize(zcu);
- const abi_align = ty.abiAlignment(zcu).toByteUnits(0);
- self.storage = .{ .seq = .{ .base = .{ .tag = .array }, .data = .{
- .len = @divExact(abi_size, abi_align),
- .elem_type = tagFromIntInfo(.{
- .signedness = .unsigned,
- .bits = @intCast(abi_align * 8),
- }).toIndex(),
- } } };
- self.value = .{ .cty = initPayload(&self.storage.seq) };
- },
- .forward_parameter,
- .parameter,
- => try self.initArrayParameter(ty, kind, lookup),
- .payload => unreachable,
- },
- },
- } else switch (ty.zigTypeTag(zcu)) {
- .Frame => unreachable,
- .AnyFrame => unreachable,
-
- .Int,
- .Enum,
- .ErrorSet,
- .Type,
- .Void,
- .NoReturn,
- .ComptimeFloat,
- .ComptimeInt,
- .Undefined,
- .Null,
- .EnumLiteral,
- => unreachable,
-
- .Bool => self.init(.bool),
-
- .Float => self.init(switch (ty.ip_index) {
- .f16_type => .zig_f16,
- .f32_type => .zig_f32,
- .f64_type => .zig_f64,
- .f80_type => .zig_f80,
- .f128_type => .zig_f128,
- .c_longdouble_type => .zig_c_longdouble,
- else => unreachable,
- }),
-
- .Pointer => {
- const info = ty.ptrInfo(zcu);
- switch (info.flags.size) {
- .Slice => {
- if (switch (kind) {
- .forward, .forward_parameter => @as(Index, undefined),
- .complete, .parameter, .global => try lookup.typeToIndex(ty, .forward),
- .payload => unreachable,
- }) |fwd_idx| {
- const ptr_ty = ty.slicePtrFieldType(zcu);
- if (try lookup.typeToIndex(ptr_ty, kind)) |ptr_idx| {
- self.storage = .{ .anon = undefined };
- self.storage.anon.fields[0] = .{
- .name = "ptr",
- .type = ptr_idx,
- .alignas = AlignAs.abiAlign(ptr_ty, zcu),
- };
- self.storage.anon.fields[1] = .{
- .name = "len",
- .type = Tag.uintptr_t.toIndex(),
- .alignas = AlignAs.abiAlign(Type.usize, zcu),
- };
- self.initAnon(kind, fwd_idx, 2);
- } else self.init(switch (kind) {
- .forward, .forward_parameter => .fwd_anon_struct,
- .complete, .parameter, .global => .anon_struct,
- .payload => unreachable,
- });
- } else self.init(.anon_struct);
- },
-
- .One, .Many, .C => {
- const t: Tag = switch (info.flags.is_volatile) {
- false => switch (info.flags.is_const) {
- false => .pointer,
- true => .pointer_const,
- },
- true => switch (info.flags.is_const) {
- false => .pointer_volatile,
- true => .pointer_const_volatile,
- },
- };
-
- const pointee_ty = if (info.packed_offset.host_size > 0 and info.flags.vector_index == .none)
- try zcu.intType(.unsigned, info.packed_offset.host_size * 8)
- else if (info.flags.alignment == .none or
- info.flags.alignment.compareStrict(.gte, Type.fromInterned(info.child).abiAlignment(zcu)))
- Type.fromInterned(info.child)
- else
- try zcu.intType(.unsigned, @min(
- info.flags.alignment.toByteUnitsOptional().?,
- lookup.getModule().resolved_target.result.maxIntAlignment(),
- ) * 8);
-
- if (try lookup.typeToIndex(pointee_ty, .forward)) |child_idx| {
- self.storage = .{ .child = .{
- .base = .{ .tag = t },
- .data = child_idx,
- } };
- self.value = .{ .cty = initPayload(&self.storage.child) };
- } else self.init(t);
- },
- }
- },
-
- .Struct, .Union => |zig_ty_tag| if (ty.containerLayout(zcu) == .@"packed") {
- if (zcu.typeToPackedStruct(ty)) |packed_struct| {
- try self.initType(Type.fromInterned(packed_struct.backingIntType(ip).*), kind, lookup);
- } else {
- const bits: u16 = @intCast(ty.bitSize(zcu));
- const int_ty = try zcu.intType(.unsigned, bits);
- try self.initType(int_ty, kind, lookup);
- }
- } else if (ty.isTupleOrAnonStruct(zcu)) {
- if (lookup.isMutable()) {
- for (0..switch (zig_ty_tag) {
- .Struct => ty.structFieldCount(zcu),
- .Union => zcu.typeToUnion(ty).?.field_types.len,
- else => unreachable,
- }) |field_i| {
- const field_ty = ty.structFieldType(field_i, zcu);
- if ((zig_ty_tag == .Struct and ty.structFieldIsComptime(field_i, zcu)) or
- !field_ty.hasRuntimeBitsIgnoreComptime(zcu)) continue;
- _ = try lookup.typeToIndex(field_ty, switch (kind) {
- .forward, .forward_parameter => .forward,
- .complete, .parameter => .complete,
- .global => .global,
- .payload => unreachable,
- });
- }
- switch (kind) {
- .forward, .forward_parameter => {},
- .complete, .parameter, .global => _ = try lookup.typeToIndex(ty, .forward),
- .payload => unreachable,
- }
- }
- self.init(switch (kind) {
- .forward, .forward_parameter => switch (zig_ty_tag) {
- .Struct => .fwd_anon_struct,
- .Union => .fwd_anon_union,
- else => unreachable,
- },
- .complete, .parameter, .global => switch (zig_ty_tag) {
- .Struct => .anon_struct,
- .Union => .anon_union,
- else => unreachable,
- },
- .payload => unreachable,
- });
- } else {
- const tag_ty = ty.unionTagTypeSafety(zcu);
- const is_tagged_union_wrapper = kind != .payload and tag_ty != null;
- const is_struct = zig_ty_tag == .Struct or is_tagged_union_wrapper;
- switch (kind) {
- .forward, .forward_parameter => {
- self.storage = .{ .fwd = .{
- .base = .{ .tag = if (is_struct) .fwd_struct else .fwd_union },
- .data = ty.getOwnerDecl(zcu),
- } };
- self.value = .{ .cty = initPayload(&self.storage.fwd) };
- },
- .complete, .parameter, .global, .payload => if (is_tagged_union_wrapper) {
- const fwd_idx = try lookup.typeToIndex(ty, .forward);
- const payload_idx = try lookup.typeToIndex(ty, .payload);
- const tag_idx = try lookup.typeToIndex(tag_ty.?, kind);
- if (fwd_idx != null and payload_idx != null and tag_idx != null) {
- self.storage = .{ .anon = undefined };
- var field_count: usize = 0;
- if (payload_idx != Tag.void.toIndex()) {
- self.storage.anon.fields[field_count] = .{
- .name = "payload",
- .type = payload_idx.?,
- .alignas = AlignAs.unionPayloadAlign(ty, zcu),
- };
- field_count += 1;
- }
- if (tag_idx != Tag.void.toIndex()) {
- self.storage.anon.fields[field_count] = .{
- .name = "tag",
- .type = tag_idx.?,
- .alignas = AlignAs.abiAlign(tag_ty.?, zcu),
- };
- field_count += 1;
- }
- self.storage.anon.pl = .{ .complete = .{
- .base = .{ .tag = .@"struct" },
- .data = .{
- .fields = self.sortFields(field_count),
- .fwd_decl = fwd_idx.?,
- },
- } };
- self.value = .{ .cty = initPayload(&self.storage.anon.pl.complete) };
- } else self.init(.@"struct");
- } else if (kind == .payload and ty.unionHasAllZeroBitFieldTypes(zcu)) {
- self.init(.void);
- } else {
- var is_packed = false;
- for (0..switch (zig_ty_tag) {
- .Struct => ty.structFieldCount(zcu),
- .Union => zcu.typeToUnion(ty).?.field_types.len,
- else => unreachable,
- }) |field_i| {
- const field_ty = ty.structFieldType(field_i, zcu);
- if (!field_ty.hasRuntimeBitsIgnoreComptime(zcu)) continue;
-
- const field_align = AlignAs.fieldAlign(ty, field_i, zcu);
- if (field_align.abiOrder().compare(.lt)) {
- is_packed = true;
- if (!lookup.isMutable()) break;
- }
-
- if (lookup.isMutable()) {
- _ = try lookup.typeToIndex(field_ty, switch (kind) {
- .forward, .forward_parameter => unreachable,
- .complete, .parameter, .payload => .complete,
- .global => .global,
- });
- }
- }
- switch (kind) {
- .forward, .forward_parameter => unreachable,
- .complete, .parameter, .global => {
- _ = try lookup.typeToIndex(ty, .forward);
- self.init(if (is_struct)
- if (is_packed) .packed_struct else .@"struct"
- else if (is_packed) .packed_union else .@"union");
- },
- .payload => self.init(if (is_packed)
- .packed_unnamed_union
- else
- .unnamed_union),
- }
- },
- }
- },
-
- .Array, .Vector => |zig_ty_tag| {
- switch (kind) {
- .forward, .complete, .global => {
- const t: Tag = switch (zig_ty_tag) {
- .Array => .array,
- .Vector => .vector,
- else => unreachable,
- };
- if (try lookup.typeToIndex(ty.childType(zcu), kind)) |child_idx| {
- self.storage = .{ .seq = .{ .base = .{ .tag = t }, .data = .{
- .len = ty.arrayLenIncludingSentinel(zcu),
- .elem_type = child_idx,
- } } };
- self.value = .{ .cty = initPayload(&self.storage.seq) };
- } else self.init(t);
- },
- .forward_parameter, .parameter => try self.initArrayParameter(ty, kind, lookup),
- .payload => unreachable,
- }
- },
-
- .Optional => {
- const payload_ty = ty.optionalChild(zcu);
- if (payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
- if (ty.optionalReprIsPayload(zcu)) {
- try self.initType(payload_ty, kind, lookup);
- } else if (switch (kind) {
- .forward, .forward_parameter => @as(Index, undefined),
- .complete, .parameter, .global => try lookup.typeToIndex(ty, .forward),
- .payload => unreachable,
- }) |fwd_idx| {
- if (try lookup.typeToIndex(payload_ty, switch (kind) {
- .forward, .forward_parameter => .forward,
- .complete, .parameter => .complete,
- .global => .global,
- .payload => unreachable,
- })) |payload_idx| {
- self.storage = .{ .anon = undefined };
- self.storage.anon.fields[0] = .{
- .name = "payload",
- .type = payload_idx,
- .alignas = AlignAs.abiAlign(payload_ty, zcu),
- };
- self.storage.anon.fields[1] = .{
- .name = "is_null",
- .type = Tag.bool.toIndex(),
- .alignas = AlignAs.abiAlign(Type.bool, zcu),
- };
- self.initAnon(kind, fwd_idx, 2);
- } else self.init(switch (kind) {
- .forward, .forward_parameter => .fwd_anon_struct,
- .complete, .parameter, .global => .anon_struct,
- .payload => unreachable,
- });
- } else self.init(.anon_struct);
- } else self.init(.bool);
- },
-
- .ErrorUnion => {
- if (switch (kind) {
- .forward, .forward_parameter => @as(Index, undefined),
- .complete, .parameter, .global => try lookup.typeToIndex(ty, .forward),
- .payload => unreachable,
- }) |fwd_idx| {
- const payload_ty = ty.errorUnionPayload(zcu);
- if (try lookup.typeToIndex(payload_ty, switch (kind) {
- .forward, .forward_parameter => .forward,
- .complete, .parameter => .complete,
- .global => .global,
- .payload => unreachable,
- })) |payload_idx| {
- const error_ty = ty.errorUnionSet(zcu);
- if (payload_idx == Tag.void.toIndex()) {
- try self.initType(error_ty, kind, lookup);
- } else if (try lookup.typeToIndex(error_ty, kind)) |error_idx| {
- self.storage = .{ .anon = undefined };
- self.storage.anon.fields[0] = .{
- .name = "payload",
- .type = payload_idx,
- .alignas = AlignAs.abiAlign(payload_ty, zcu),
- };
- self.storage.anon.fields[1] = .{
- .name = "error",
- .type = error_idx,
- .alignas = AlignAs.abiAlign(error_ty, zcu),
- };
- self.initAnon(kind, fwd_idx, 2);
- } else self.init(switch (kind) {
- .forward, .forward_parameter => .fwd_anon_struct,
- .complete, .parameter, .global => .anon_struct,
- .payload => unreachable,
- });
- } else self.init(switch (kind) {
- .forward, .forward_parameter => .fwd_anon_struct,
- .complete, .parameter, .global => .anon_struct,
- .payload => unreachable,
- });
- } else self.init(.anon_struct);
- },
-
- .Opaque => self.init(.void),
-
- .Fn => {
- const info = zcu.typeToFunc(ty).?;
- if (!info.is_generic) {
- if (lookup.isMutable()) {
- const param_kind: Kind = switch (kind) {
- .forward, .forward_parameter => .forward_parameter,
- .complete, .parameter, .global => .parameter,
- .payload => unreachable,
- };
- _ = try lookup.typeToIndex(Type.fromInterned(info.return_type), param_kind);
- for (info.param_types.get(ip)) |param_type| {
- if (!Type.fromInterned(param_type).hasRuntimeBitsIgnoreComptime(zcu)) continue;
- _ = try lookup.typeToIndex(Type.fromInterned(param_type), param_kind);
- }
- }
- self.init(if (info.is_var_args) .varargs_function else .function);
- } else self.init(.void);
- },
- }
- }
- };
-
- pub fn copy(self: CType, arena: Allocator) !CType {
- return self.copyContext(struct {
- arena: Allocator,
- pub fn copyIndex(_: @This(), idx: Index) Index {
- return idx;
- }
- }{ .arena = arena });
- }
-
- fn copyFields(ctx: anytype, old_fields: Payload.Fields.Data) !Payload.Fields.Data {
- const new_fields = try ctx.arena.alloc(Payload.Fields.Field, old_fields.len);
- for (new_fields, old_fields) |*new_field, old_field| {
- new_field.name = try ctx.arena.dupeZ(u8, mem.span(old_field.name));
- new_field.type = ctx.copyIndex(old_field.type);
- new_field.alignas = old_field.alignas;
- }
- return new_fields;
- }
-
- fn copyParams(ctx: anytype, old_param_types: []const Index) ![]const Index {
- const new_param_types = try ctx.arena.alloc(Index, old_param_types.len);
- for (new_param_types, old_param_types) |*new_param_type, old_param_type|
- new_param_type.* = ctx.copyIndex(old_param_type);
- return new_param_types;
- }
-
- pub fn copyContext(self: CType, ctx: anytype) !CType {
- switch (self.tag()) {
- .void,
- .char,
- .@"signed char",
- .short,
- .int,
- .long,
- .@"long long",
- ._Bool,
- .@"unsigned char",
- .@"unsigned short",
- .@"unsigned int",
- .@"unsigned long",
- .@"unsigned long long",
- .float,
- .double,
- .@"long double",
- .bool,
- .size_t,
- .ptrdiff_t,
- .uint8_t,
- .int8_t,
- .uint16_t,
- .int16_t,
- .uint32_t,
- .int32_t,
- .uint64_t,
- .int64_t,
- .uintptr_t,
- .intptr_t,
- .zig_u128,
- .zig_i128,
- .zig_f16,
- .zig_f32,
- .zig_f64,
- .zig_f80,
- .zig_f128,
- .zig_c_longdouble,
- => return self,
-
- .pointer,
- .pointer_const,
- .pointer_volatile,
- .pointer_const_volatile,
- => {
- const pl = self.cast(Payload.Child).?;
- const new_pl = try ctx.arena.create(Payload.Child);
- new_pl.* = .{ .base = .{ .tag = pl.base.tag }, .data = ctx.copyIndex(pl.data) };
- return initPayload(new_pl);
- },
-
- .array,
- .vector,
- => {
- const pl = self.cast(Payload.Sequence).?;
- const new_pl = try ctx.arena.create(Payload.Sequence);
- new_pl.* = .{
- .base = .{ .tag = pl.base.tag },
- .data = .{ .len = pl.data.len, .elem_type = ctx.copyIndex(pl.data.elem_type) },
- };
- return initPayload(new_pl);
- },
-
- .fwd_anon_struct,
- .fwd_anon_union,
- => {
- const pl = self.cast(Payload.Fields).?;
- const new_pl = try ctx.arena.create(Payload.Fields);
- new_pl.* = .{
- .base = .{ .tag = pl.base.tag },
- .data = try copyFields(ctx, pl.data),
- };
- return initPayload(new_pl);
- },
-
- .fwd_struct,
- .fwd_union,
- => {
- const pl = self.cast(Payload.FwdDecl).?;
- const new_pl = try ctx.arena.create(Payload.FwdDecl);
- new_pl.* = .{ .base = .{ .tag = pl.base.tag }, .data = pl.data };
- return initPayload(new_pl);
- },
-
- .unnamed_struct,
- .unnamed_union,
- .packed_unnamed_struct,
- .packed_unnamed_union,
- => {
- const pl = self.cast(Payload.Unnamed).?;
- const new_pl = try ctx.arena.create(Payload.Unnamed);
- new_pl.* = .{ .base = .{ .tag = pl.base.tag }, .data = .{
- .fields = try copyFields(ctx, pl.data.fields),
- .owner_decl = pl.data.owner_decl,
- .id = pl.data.id,
- } };
- return initPayload(new_pl);
- },
-
- .anon_struct,
- .anon_union,
- .@"struct",
- .@"union",
- .packed_struct,
- .packed_union,
- => {
- const pl = self.cast(Payload.Aggregate).?;
- const new_pl = try ctx.arena.create(Payload.Aggregate);
- new_pl.* = .{ .base = .{ .tag = pl.base.tag }, .data = .{
- .fields = try copyFields(ctx, pl.data.fields),
- .fwd_decl = ctx.copyIndex(pl.data.fwd_decl),
- } };
- return initPayload(new_pl);
- },
-
- .function,
- .varargs_function,
- => {
- const pl = self.cast(Payload.Function).?;
- const new_pl = try ctx.arena.create(Payload.Function);
- new_pl.* = .{ .base = .{ .tag = pl.base.tag }, .data = .{
- .return_type = ctx.copyIndex(pl.data.return_type),
- .param_types = try copyParams(ctx, pl.data.param_types),
- } };
- return initPayload(new_pl);
- },
- }
- }
-
- fn createFromType(store: *Store.Promoted, ty: Type, zcu: *Zcu, mod: *Module, kind: Kind) !CType {
- var convert: Convert = undefined;
- try convert.initType(ty, kind, .{ .imm = .{ .set = &store.set, .zcu = zcu } });
- return createFromConvert(store, ty, zcu, mod, kind, &convert);
- }
-
- fn createFromConvert(
- store: *Store.Promoted,
- ty: Type,
- zcu: *Zcu,
- mod: *Module,
- kind: Kind,
- convert: Convert,
- ) !CType {
- const ip = &zcu.intern_pool;
- const arena = store.arena.allocator();
- switch (convert.value) {
- .cty => |c| return c.copy(arena),
- .tag => |t| switch (t) {
- .fwd_anon_struct,
- .fwd_anon_union,
- .unnamed_struct,
- .unnamed_union,
- .packed_unnamed_struct,
- .packed_unnamed_union,
- .anon_struct,
- .anon_union,
- .@"struct",
- .@"union",
- .packed_struct,
- .packed_union,
- => {
- const zig_ty_tag = ty.zigTypeTag(zcu);
- const fields_len = switch (zig_ty_tag) {
- .Struct => ty.structFieldCount(zcu),
- .Union => zcu.typeToUnion(ty).?.field_types.len,
- else => unreachable,
- };
-
- var c_fields_len: usize = 0;
- for (0..fields_len) |field_i| {
- const field_ty = ty.structFieldType(field_i, zcu);
- if ((zig_ty_tag == .Struct and ty.structFieldIsComptime(field_i, zcu)) or
- !field_ty.hasRuntimeBitsIgnoreComptime(zcu)) continue;
- c_fields_len += 1;
- }
-
- const fields_pl = try arena.alloc(Payload.Fields.Field, c_fields_len);
- var c_field_i: usize = 0;
- for (0..fields_len) |field_i_usize| {
- const field_i: u32 = @intCast(field_i_usize);
- const field_ty = ty.structFieldType(field_i, zcu);
- if ((zig_ty_tag == .Struct and ty.structFieldIsComptime(field_i, zcu)) or
- !field_ty.hasRuntimeBitsIgnoreComptime(zcu)) continue;
-
- defer c_field_i += 1;
- fields_pl[c_field_i] = .{
- .name = try if (ty.isSimpleTuple(zcu))
- std.fmt.allocPrintZ(arena, "f{}", .{field_i})
- else
- arena.dupeZ(u8, ip.stringToSlice(switch (zig_ty_tag) {
- .Struct => ty.legacyStructFieldName(field_i, zcu),
- .Union => ip.loadUnionType(ty.toIntern()).loadTagType(ip).names.get(ip)[field_i],
- else => unreachable,
- })),
- .type = store.set.typeToIndex(field_ty, zcu, mod, switch (kind) {
- .forward, .forward_parameter => .forward,
- .complete, .parameter, .payload => .complete,
- .global => .global,
- }).?,
- .alignas = AlignAs.fieldAlign(ty, field_i, zcu),
- };
- }
-
- switch (t) {
- .fwd_anon_struct,
- .fwd_anon_union,
- => {
- const anon_pl = try arena.create(Payload.Fields);
- anon_pl.* = .{ .base = .{ .tag = t }, .data = fields_pl };
- return initPayload(anon_pl);
- },
-
- .unnamed_struct,
- .unnamed_union,
- .packed_unnamed_struct,
- .packed_unnamed_union,
- => {
- const unnamed_pl = try arena.create(Payload.Unnamed);
- unnamed_pl.* = .{ .base = .{ .tag = t }, .data = .{
- .fields = fields_pl,
- .owner_decl = ty.getOwnerDecl(zcu),
- .id = if (ty.unionTagTypeSafety(zcu)) |_| 0 else unreachable,
- } };
- return initPayload(unnamed_pl);
- },
-
- .anon_struct,
- .anon_union,
- .@"struct",
- .@"union",
- .packed_struct,
- .packed_union,
- => {
- const struct_pl = try arena.create(Payload.Aggregate);
- struct_pl.* = .{ .base = .{ .tag = t }, .data = .{
- .fields = fields_pl,
- .fwd_decl = store.set.typeToIndex(ty, zcu, mod, .forward).?,
- } };
- return initPayload(struct_pl);
- },
-
- else => unreachable,
- }
- },
-
- .function,
- .varargs_function,
- => {
- const info = zcu.typeToFunc(ty).?;
- assert(!info.is_generic);
- const param_kind: Kind = switch (kind) {
- .forward, .forward_parameter => .forward_parameter,
- .complete, .parameter, .global => .parameter,
- .payload => unreachable,
- };
-
- var c_params_len: usize = 0;
- for (info.param_types.get(ip)) |param_type| {
- if (!Type.fromInterned(param_type).hasRuntimeBitsIgnoreComptime(zcu)) continue;
- c_params_len += 1;
- }
-
- const params_pl = try arena.alloc(Index, c_params_len);
- var c_param_i: usize = 0;
- for (info.param_types.get(ip)) |param_type| {
- if (!Type.fromInterned(param_type).hasRuntimeBitsIgnoreComptime(zcu)) continue;
- params_pl[c_param_i] = store.set.typeToIndex(Type.fromInterned(param_type), zcu, mod, param_kind).?;
- c_param_i += 1;
- }
-
- const fn_pl = try arena.create(Payload.Function);
- fn_pl.* = .{ .base = .{ .tag = t }, .data = .{
- .return_type = store.set.typeToIndex(Type.fromInterned(info.return_type), zcu, mod, param_kind).?,
- .param_types = params_pl,
- } };
- return initPayload(fn_pl);
- },
-
- else => unreachable,
- },
- }
- }
-
- pub const TypeAdapter64 = struct {
- kind: Kind,
- lookup: Convert.Lookup,
- convert: *const Convert,
-
- fn eqlRecurse(self: @This(), ty: Type, cty: Index, kind: Kind) bool {
- assert(!self.lookup.isMutable());
-
- var convert: Convert = undefined;
- convert.initType(ty, kind, self.lookup) catch unreachable;
-
- const self_recurse = @This(){ .kind = kind, .lookup = self.lookup, .convert = &convert };
- return self_recurse.eql(ty, self.lookup.indexToCType(cty).?);
- }
-
- pub fn eql(self: @This(), ty: Type, cty: CType) bool {
- const zcu = self.lookup.getZcu();
- const ip = &zcu.intern_pool;
- switch (self.convert.value) {
- .cty => |c| return c.eql(cty),
- .tag => |t| {
- if (t != cty.tag()) return false;
-
- switch (t) {
- .fwd_anon_struct,
- .fwd_anon_union,
- => {
- if (!ty.isTupleOrAnonStruct(zcu)) return false;
-
- var name_buf: [
- std.fmt.count("f{}", .{std.math.maxInt(usize)})
- ]u8 = undefined;
- const c_fields = cty.cast(Payload.Fields).?.data;
-
- const zig_ty_tag = ty.zigTypeTag(zcu);
- var c_field_i: usize = 0;
- for (0..switch (zig_ty_tag) {
- .Struct => ty.structFieldCount(zcu),
- .Union => zcu.typeToUnion(ty).?.field_types.len,
- else => unreachable,
- }) |field_i_usize| {
- const field_i: u32 = @intCast(field_i_usize);
- const field_ty = ty.structFieldType(field_i, zcu);
- if ((zig_ty_tag == .Struct and ty.structFieldIsComptime(field_i, zcu)) or
- !field_ty.hasRuntimeBitsIgnoreComptime(zcu)) continue;
-
- defer c_field_i += 1;
- const c_field = &c_fields[c_field_i];
-
- if (!self.eqlRecurse(field_ty, c_field.type, switch (self.kind) {
- .forward, .forward_parameter => .forward,
- .complete, .parameter => .complete,
- .global => .global,
- .payload => unreachable,
- }) or !mem.eql(
- u8,
- if (ty.isSimpleTuple(zcu))
- std.fmt.bufPrintZ(&name_buf, "f{}", .{field_i}) catch unreachable
- else
- ip.stringToSlice(switch (zig_ty_tag) {
- .Struct => ty.legacyStructFieldName(field_i, zcu),
- .Union => ip.loadUnionType(ty.toIntern()).loadTagType(ip).names.get(ip)[field_i],
- else => unreachable,
- }),
- mem.span(c_field.name),
- ) or AlignAs.fieldAlign(ty, field_i, zcu).@"align" !=
- c_field.alignas.@"align") return false;
- }
- return true;
- },
-
- .unnamed_struct,
- .unnamed_union,
- .packed_unnamed_struct,
- .packed_unnamed_union,
- => switch (self.kind) {
- .forward, .forward_parameter, .complete, .parameter, .global => unreachable,
- .payload => if (ty.unionTagTypeSafety(zcu)) |_| {
- const data = cty.cast(Payload.Unnamed).?.data;
- return ty.getOwnerDecl(zcu) == data.owner_decl and data.id == 0;
- } else unreachable,
- },
-
- .anon_struct,
- .anon_union,
- .@"struct",
- .@"union",
- .packed_struct,
- .packed_union,
- => return self.eqlRecurse(
- ty,
- cty.cast(Payload.Aggregate).?.data.fwd_decl,
- .forward,
- ),
-
- .function,
- .varargs_function,
- => {
- if (ty.zigTypeTag(zcu) != .Fn) return false;
-
- const info = zcu.typeToFunc(ty).?;
- assert(!info.is_generic);
- const data = cty.cast(Payload.Function).?.data;
- const param_kind: Kind = switch (self.kind) {
- .forward, .forward_parameter => .forward_parameter,
- .complete, .parameter, .global => .parameter,
- .payload => unreachable,
- };
-
- if (!self.eqlRecurse(Type.fromInterned(info.return_type), data.return_type, param_kind))
- return false;
-
- var c_param_i: usize = 0;
- for (info.param_types.get(ip)) |param_type| {
- if (!Type.fromInterned(param_type).hasRuntimeBitsIgnoreComptime(zcu)) continue;
-
- if (c_param_i >= data.param_types.len) return false;
- const param_cty = data.param_types[c_param_i];
- c_param_i += 1;
-
- if (!self.eqlRecurse(Type.fromInterned(param_type), param_cty, param_kind))
- return false;
- }
- return c_param_i == data.param_types.len;
- },
-
- else => unreachable,
- }
- },
- }
- }
-
- pub fn hash(self: @This(), ty: Type) u64 {
- var hasher = std.hash.Wyhash.init(0);
- self.updateHasher(&hasher, ty);
- return hasher.final();
- }
-
- fn updateHasherRecurse(self: @This(), hasher: anytype, ty: Type, kind: Kind) void {
- assert(!self.lookup.isMutable());
-
- var convert: Convert = undefined;
- convert.initType(ty, kind, self.lookup) catch unreachable;
-
- const self_recurse = @This(){ .kind = kind, .lookup = self.lookup, .convert = &convert };
- self_recurse.updateHasher(hasher, ty);
- }
-
- pub fn updateHasher(self: @This(), hasher: anytype, ty: Type) void {
- switch (self.convert.value) {
- .cty => |c| return c.updateHasher(hasher, self.lookup.getSet().?.*),
- .tag => |t| {
- autoHash(hasher, t);
-
- const zcu = self.lookup.getZcu();
- const ip = &zcu.intern_pool;
- switch (t) {
- .fwd_anon_struct,
- .fwd_anon_union,
- => {
- var name_buf: [
- std.fmt.count("f{}", .{std.math.maxInt(usize)})
- ]u8 = undefined;
-
- const zig_ty_tag = ty.zigTypeTag(zcu);
- for (0..switch (ty.zigTypeTag(zcu)) {
- .Struct => ty.structFieldCount(zcu),
- .Union => zcu.typeToUnion(ty).?.field_types.len,
- else => unreachable,
- }) |field_i_usize| {
- const field_i: u32 = @intCast(field_i_usize);
- const field_ty = ty.structFieldType(field_i, zcu);
- if ((zig_ty_tag == .Struct and ty.structFieldIsComptime(field_i, zcu)) or
- !field_ty.hasRuntimeBitsIgnoreComptime(zcu)) continue;
-
- self.updateHasherRecurse(hasher, field_ty, switch (self.kind) {
- .forward, .forward_parameter => .forward,
- .complete, .parameter => .complete,
- .global => .global,
- .payload => unreachable,
- });
- hasher.update(if (ty.isSimpleTuple(zcu))
- std.fmt.bufPrint(&name_buf, "f{}", .{field_i}) catch unreachable
- else
- zcu.intern_pool.stringToSlice(switch (zig_ty_tag) {
- .Struct => ty.legacyStructFieldName(field_i, zcu),
- .Union => ip.loadUnionType(ty.toIntern()).loadTagType(ip).names.get(ip)[field_i],
- else => unreachable,
- }));
- autoHash(hasher, AlignAs.fieldAlign(ty, field_i, zcu).@"align");
- }
- },
-
- .unnamed_struct,
- .unnamed_union,
- .packed_unnamed_struct,
- .packed_unnamed_union,
- => switch (self.kind) {
- .forward, .forward_parameter, .complete, .parameter, .global => unreachable,
- .payload => if (ty.unionTagTypeSafety(zcu)) |_| {
- autoHash(hasher, ty.getOwnerDecl(zcu));
- autoHash(hasher, @as(u32, 0));
- } else unreachable,
- },
-
- .anon_struct,
- .anon_union,
- .@"struct",
- .@"union",
- .packed_struct,
- .packed_union,
- => self.updateHasherRecurse(hasher, ty, .forward),
-
- .function,
- .varargs_function,
- => {
- const info = zcu.typeToFunc(ty).?;
- assert(!info.is_generic);
- const param_kind: Kind = switch (self.kind) {
- .forward, .forward_parameter => .forward_parameter,
- .complete, .parameter, .global => .parameter,
- .payload => unreachable,
- };
-
- self.updateHasherRecurse(hasher, Type.fromInterned(info.return_type), param_kind);
- for (info.param_types.get(ip)) |param_type| {
- if (!Type.fromInterned(param_type).hasRuntimeBitsIgnoreComptime(zcu)) continue;
- self.updateHasherRecurse(hasher, Type.fromInterned(param_type), param_kind);
- }
- },
-
- else => unreachable,
- }
- },
- }
- }
- };
-
- pub const TypeAdapter32 = struct {
- kind: Kind,
- lookup: Convert.Lookup,
- convert: *const Convert,
-
- fn to64(self: @This()) TypeAdapter64 {
- return .{ .kind = self.kind, .lookup = self.lookup, .convert = self.convert };
- }
-
- pub fn eql(self: @This(), ty: Type, cty: CType, cty_index: usize) bool {
- _ = cty_index;
- return self.to64().eql(ty, cty);
- }
-
- pub fn hash(self: @This(), ty: Type) u32 {
- return @as(u32, @truncate(self.to64().hash(ty)));
- }
- };
-};
src/codegen/c.zig
@@ -22,7 +22,7 @@ const Alignment = InternPool.Alignment;
const BigIntLimb = std.math.big.Limb;
const BigInt = std.math.big.int;
-pub const CType = @import("c/type.zig").CType;
+pub const CType = @import("c/Type.zig");
pub const CValue = union(enum) {
none: void,
@@ -62,7 +62,7 @@ pub const LazyFnKey = union(enum) {
never_inline: InternPool.DeclIndex,
};
pub const LazyFnValue = struct {
- fn_name: []const u8,
+ fn_name: CType.String,
data: Data,
pub const Data = union {
@@ -74,19 +74,19 @@ pub const LazyFnValue = struct {
pub const LazyFnMap = std.AutoArrayHashMapUnmanaged(LazyFnKey, LazyFnValue);
const Local = struct {
- cty_idx: CType.Index,
+ ctype: CType,
flags: packed struct(u32) {
alignas: CType.AlignAs,
_: u20 = undefined,
},
pub fn getType(local: Local) LocalType {
- return .{ .cty_idx = local.cty_idx, .alignas = local.flags.alignas };
+ return .{ .ctype = local.ctype, .alignas = local.flags.alignas };
}
};
const LocalIndex = u16;
-const LocalType = struct { cty_idx: CType.Index, alignas: CType.AlignAs };
+const LocalType = struct { ctype: CType, alignas: CType.AlignAs };
const LocalsList = std.AutoArrayHashMapUnmanaged(LocalIndex, void);
const LocalsMap = std.AutoArrayHashMapUnmanaged(LocalType, LocalsList);
@@ -193,6 +193,7 @@ const reserved_idents = std.ComptimeStringMap(void, .{
.{ "switch", {} },
.{ "thread_local", {} },
.{ "typedef", {} },
+ .{ "typeof", {} },
.{ "uint16_t", {} },
.{ "uint32_t", {} },
.{ "uint64_t", {} },
@@ -309,12 +310,14 @@ pub const Function = struct {
const result: CValue = if (lowersToArray(ty, zcu)) result: {
const writer = f.object.codeHeaderWriter();
- const alignment: Alignment = .none;
- const decl_c_value = try f.allocLocalValue(ty, alignment);
+ const decl_c_value = try f.allocLocalValue(.{
+ .ctype = try f.ctypeFromType(ty, .complete),
+ .alignas = CType.AlignAs.fromAbiAlignment(ty.abiAlignment(zcu)),
+ });
const gpa = f.object.dg.gpa;
try f.allocs.put(gpa, decl_c_value.new_local, false);
try writer.writeAll("static ");
- try f.object.dg.renderTypeAndName(writer, ty, decl_c_value, Const, alignment, .complete);
+ try f.object.dg.renderTypeAndName(writer, ty, decl_c_value, Const, .none, .complete);
try writer.writeAll(" = ");
try f.object.dg.renderValue(writer, val, .StaticInitializer);
try writer.writeAll(";\n ");
@@ -335,42 +338,39 @@ pub const Function = struct {
/// Skips the reuse logic. This function should be used for any persistent allocation, i.e.
/// those which go into `allocs`. This function does not add the resulting local into `allocs`;
/// that responsibility lies with the caller.
- fn allocLocalValue(f: *Function, ty: Type, alignment: Alignment) !CValue {
- const zcu = f.object.dg.zcu;
- const gpa = f.object.dg.gpa;
- try f.locals.append(gpa, .{
- .cty_idx = try f.typeToIndex(ty, .complete),
- .flags = .{
- .alignas = CType.AlignAs.init(alignment, ty.abiAlignment(zcu)),
- },
+ fn allocLocalValue(f: *Function, local_type: LocalType) !CValue {
+ try f.locals.ensureUnusedCapacity(f.object.dg.gpa, 1);
+ defer f.locals.appendAssumeCapacity(.{
+ .ctype = local_type.ctype,
+ .flags = .{ .alignas = local_type.alignas },
});
- return .{ .new_local = @intCast(f.locals.items.len - 1) };
+ return .{ .new_local = @intCast(f.locals.items.len) };
}
fn allocLocal(f: *Function, inst: ?Air.Inst.Index, ty: Type) !CValue {
- const result = try f.allocAlignedLocal(ty, .{}, .none);
- if (inst) |i| {
- log.debug("%{d}: allocating t{d}", .{ i, result.new_local });
- } else {
- log.debug("allocating t{d}", .{result.new_local});
- }
- return result;
+ return f.allocAlignedLocal(inst, .{
+ .ctype = try f.ctypeFromType(ty, .complete),
+ .alignas = CType.AlignAs.fromAbiAlignment(ty.abiAlignment(f.object.dg.zcu)),
+ });
}
/// Only allocates the local; does not print anything. Will attempt to re-use locals, so should
/// not be used for persistent locals (i.e. those in `allocs`).
- fn allocAlignedLocal(f: *Function, ty: Type, _: CQualifiers, alignment: Alignment) !CValue {
- const zcu = f.object.dg.zcu;
- if (f.free_locals_map.getPtr(.{
- .cty_idx = try f.typeToIndex(ty, .complete),
- .alignas = CType.AlignAs.init(alignment, ty.abiAlignment(zcu)),
- })) |locals_list| {
- if (locals_list.popOrNull()) |local_entry| {
- return .{ .new_local = local_entry.key };
+ fn allocAlignedLocal(f: *Function, inst: ?Air.Inst.Index, local_type: LocalType) !CValue {
+ const result: CValue = result: {
+ if (f.free_locals_map.getPtr(local_type)) |locals_list| {
+ if (locals_list.popOrNull()) |local_entry| {
+ break :result .{ .new_local = local_entry.key };
+ }
}
+ break :result try f.allocLocalValue(local_type);
+ };
+ if (inst) |i| {
+ log.debug("%{d}: allocating t{d}", .{ i, result.new_local });
+ } else {
+ log.debug("allocating t{d}", .{result.new_local});
}
-
- return f.allocLocalValue(ty, alignment);
+ return result;
}
fn writeCValue(f: *Function, w: anytype, c_value: CValue, location: ValueRenderLocation) !void {
@@ -380,15 +380,20 @@ pub const Function = struct {
.local_ref => |i| {
const local = &f.locals.items[i];
if (local.flags.alignas.abiOrder().compare(.lt)) {
- const zcu = f.object.dg.zcu;
- const pointee_ty = try zcu.intType(.unsigned, @min(
- local.flags.alignas.@"align".toByteUnitsOptional().?,
- f.object.dg.mod.resolved_target.result.maxIntAlignment(),
- ) * 8);
- const ptr_ty = try zcu.singleMutPtrType(pointee_ty);
+ const gpa = f.object.dg.gpa;
+ const mod = f.object.dg.mod;
+ const ctype_pool = &f.object.dg.ctype_pool;
try w.writeByte('(');
- try f.renderType(w, ptr_ty);
+ try f.renderCType(w, try ctype_pool.getPointer(gpa, .{
+ .elem_ctype = try ctype_pool.fromIntInfo(gpa, .{
+ .signedness = .unsigned,
+ .bits = @min(
+ local.flags.alignas.toByteUnits(),
+ mod.resolved_target.result.maxIntAlignment(),
+ ) * 8,
+ }, mod, .forward),
+ }));
try w.writeByte(')');
}
try w.print("&t{d}", .{i});
@@ -460,28 +465,20 @@ pub const Function = struct {
return f.object.dg.fail(format, args);
}
- fn indexToCType(f: *Function, idx: CType.Index) CType {
- return f.object.dg.indexToCType(idx);
- }
-
- fn typeToIndex(f: *Function, ty: Type, kind: CType.Kind) !CType.Index {
- return f.object.dg.typeToIndex(ty, kind);
+ fn ctypeFromType(f: *Function, ty: Type, kind: CType.Kind) !CType {
+ return f.object.dg.ctypeFromType(ty, kind);
}
- fn typeToCType(f: *Function, ty: Type, kind: CType.Kind) !CType {
- return f.object.dg.typeToCType(ty, kind);
+ fn byteSize(f: *Function, ctype: CType) u64 {
+ return f.object.dg.byteSize(ctype);
}
- fn byteSize(f: *Function, cty: CType) u64 {
- return f.object.dg.byteSize(cty);
+ fn renderType(f: *Function, w: anytype, ctype: Type) !void {
+ return f.object.dg.renderType(w, ctype);
}
- fn renderType(f: *Function, w: anytype, t: Type) !void {
- return f.object.dg.renderType(w, t);
- }
-
- fn renderCType(f: *Function, w: anytype, t: CType.Index) !void {
- return f.object.dg.renderCType(w, t);
+ fn renderCType(f: *Function, w: anytype, ctype: CType) !void {
+ return f.object.dg.renderCType(w, ctype);
}
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 {
fn getLazyFnName(f: *Function, key: LazyFnKey, data: LazyFnValue.Data) ![]const u8 {
const gpa = f.object.dg.gpa;
+ const zcu = f.object.dg.zcu;
+ const ctype_pool = &f.object.dg.ctype_pool;
+
const gop = try f.lazy_fns.getOrPut(gpa, key);
if (!gop.found_existing) {
errdefer _ = f.lazy_fns.pop();
- var promoted = f.object.dg.ctypes.promote(gpa);
- defer f.object.dg.ctypes.demote(promoted);
- const arena = promoted.arena.allocator();
- const zcu = f.object.dg.zcu;
-
gop.value_ptr.* = .{
.fn_name = switch (key) {
.tag_name,
.never_tail,
.never_inline,
- => |owner_decl| try std.fmt.allocPrint(arena, "zig_{s}_{}__{d}", .{
+ => |owner_decl| try ctype_pool.fmt(gpa, "zig_{s}_{}__{d}", .{
@tagName(key),
fmtIdent(zcu.intern_pool.stringToSlice(zcu.declPtr(owner_decl).name)),
@intFromEnum(owner_decl),
@@ -521,7 +516,7 @@ pub const Function = struct {
},
};
}
- return gop.value_ptr.fn_name;
+ return gop.value_ptr.fn_name.slice(ctype_pool);
}
pub fn deinit(f: *Function) void {
@@ -532,7 +527,6 @@ pub const Function = struct {
f.blocks.deinit(gpa);
f.value_map.deinit();
f.lazy_fns.deinit(gpa);
- f.object.dg.ctypes.deinit(gpa);
}
fn typeOf(f: *Function, inst: Air.Inst.Ref) Type {
@@ -575,7 +569,8 @@ pub const DeclGen = struct {
/// This is a borrowed reference from `link.C`.
fwd_decl: std.ArrayList(u8),
error_msg: ?*Zcu.ErrorMsg,
- ctypes: CType.Store,
+ ctype_pool: CType.Pool,
+ scratch: std.ArrayListUnmanaged(u32),
/// Keeps track of anonymous decls that need to be rendered before this
/// (named) Decl in the output C code.
anon_decl_deps: std.AutoArrayHashMapUnmanaged(InternPool.Index, C.DeclBlock),
@@ -610,6 +605,7 @@ pub const DeclGen = struct {
) error{ OutOfMemory, AnalysisFail }!void {
const zcu = dg.zcu;
const ip = &zcu.intern_pool;
+ const ctype_pool = &dg.ctype_pool;
const decl_val = Value.fromInterned(anon_decl.val);
const decl_ty = decl_val.typeOf(zcu);
@@ -631,10 +627,10 @@ pub const DeclGen = struct {
// them). The analysis until now should ensure that the C function
// pointers are compatible. If they are not, then there is a bug
// somewhere and we should let the C compiler tell us about it.
- const child_cty = (try dg.typeToCType(ptr_ty, .complete)).cast(CType.Payload.Child).?.data;
- const decl_cty = try dg.typeToIndex(decl_ty, .complete);
- const need_cast = child_cty != decl_cty and
- (dg.indexToCType(child_cty).tag() != .function or dg.indexToCType(decl_cty).tag() != .function);
+ const elem_ctype = (try dg.ctypeFromType(ptr_ty, .complete)).info(ctype_pool).pointer.elem_ctype;
+ const decl_ctype = try dg.ctypeFromType(decl_ty, .complete);
+ const need_cast = !elem_ctype.eql(decl_ctype) and
+ (elem_ctype.info(ctype_pool) != .function or decl_ctype.info(ctype_pool) != .function);
if (need_cast) {
try writer.writeAll("((");
try dg.renderType(writer, ptr_ty);
@@ -655,7 +651,7 @@ pub const DeclGen = struct {
const explicit_alignment = ptr_type.flags.alignment;
if (explicit_alignment != .none) {
const abi_alignment = Type.fromInterned(ptr_type.child).abiAlignment(zcu);
- if (explicit_alignment.compareStrict(.gt, abi_alignment)) {
+ if (explicit_alignment.order(abi_alignment).compare(.gt)) {
const aligned_gop = try dg.aligned_anon_decls.getOrPut(dg.gpa, anon_decl.val);
aligned_gop.value_ptr.* = if (aligned_gop.found_existing)
aligned_gop.value_ptr.maxStrict(explicit_alignment)
@@ -673,6 +669,7 @@ pub const DeclGen = struct {
location: ValueRenderLocation,
) error{ OutOfMemory, AnalysisFail }!void {
const zcu = dg.zcu;
+ const ctype_pool = &dg.ctype_pool;
const decl = zcu.declPtr(decl_index);
assert(decl.has_tv);
@@ -695,10 +692,10 @@ pub const DeclGen = struct {
// them). The analysis until now should ensure that the C function
// pointers are compatible. If they are not, then there is a bug
// somewhere and we should let the C compiler tell us about it.
- const child_cty = (try dg.typeToCType(ty, .complete)).cast(CType.Payload.Child).?.data;
- const decl_cty = try dg.typeToIndex(decl_ty, .complete);
- const need_cast = child_cty != decl_cty and
- (dg.indexToCType(child_cty).tag() != .function or dg.indexToCType(decl_cty).tag() != .function);
+ const elem_ctype = (try dg.ctypeFromType(ty, .complete)).info(ctype_pool).pointer.elem_ctype;
+ const decl_ctype = try dg.ctypeFromType(decl_ty, .complete);
+ const need_cast = !elem_ctype.eql(decl_ctype) and
+ (elem_ctype.info(ctype_pool) != .function or decl_ctype.info(ctype_pool) != .function);
if (need_cast) {
try writer.writeAll("((");
try dg.renderType(writer, ty);
@@ -720,31 +717,31 @@ pub const DeclGen = struct {
const zcu = dg.zcu;
const ip = &zcu.intern_pool;
const ptr_ty = Type.fromInterned(ip.typeOf(ptr_val));
- const ptr_cty = try dg.typeToIndex(ptr_ty, .complete);
- const ptr_child_cty = dg.indexToCType(ptr_cty).cast(CType.Payload.Child).?.data;
+ const ptr_ctype = try dg.ctypeFromType(ptr_ty, .complete);
+ const ptr_child_ctype = ptr_ctype.info(&dg.ctype_pool).pointer.elem_ctype;
const ptr = ip.indexToKey(ptr_val).ptr;
switch (ptr.addr) {
.decl => |d| try dg.renderDeclValue(writer, Value.fromInterned(ptr_val), d, location),
.anon_decl => |anon_decl| try dg.renderAnonDeclValue(writer, Value.fromInterned(ptr_val), anon_decl, location),
.int => |int| {
try writer.writeByte('(');
- try dg.renderCType(writer, ptr_cty);
+ try dg.renderCType(writer, ptr_ctype);
try writer.print("){x}", .{try dg.fmtIntLiteral(Value.fromInterned(int), .Other)});
},
.eu_payload, .opt_payload => |base| {
const ptr_base_ty = Type.fromInterned(ip.typeOf(base));
const base_ty = ptr_base_ty.childType(zcu);
// Ensure complete type definition is visible before accessing fields.
- _ = try dg.typeToIndex(base_ty, .complete);
+ _ = try dg.ctypeFromType(base_ty, .complete);
const payload_ty = switch (ptr.addr) {
.eu_payload => base_ty.errorUnionPayload(zcu),
.opt_payload => base_ty.optionalChild(zcu),
else => unreachable,
};
- const payload_cty = try dg.typeToIndex(payload_ty, .forward);
- if (ptr_child_cty != payload_cty) {
+ const payload_ctype = try dg.ctypeFromType(payload_ty, .forward);
+ if (!ptr_child_ctype.eql(payload_ctype)) {
try writer.writeByte('(');
- try dg.renderCType(writer, ptr_cty);
+ try dg.renderCType(writer, ptr_ctype);
try writer.writeByte(')');
}
try writer.writeAll("&(");
@@ -754,10 +751,10 @@ pub const DeclGen = struct {
.elem => |elem| {
const ptr_base_ty = Type.fromInterned(ip.typeOf(elem.base));
const elem_ty = ptr_base_ty.elemType2(zcu);
- const elem_cty = try dg.typeToIndex(elem_ty, .forward);
- if (ptr_child_cty != elem_cty) {
+ const elem_ctype = try dg.ctypeFromType(elem_ty, .forward);
+ if (!ptr_child_ctype.eql(elem_ctype)) {
try writer.writeByte('(');
- try dg.renderCType(writer, ptr_cty);
+ try dg.renderCType(writer, ptr_ctype);
try writer.writeByte(')');
}
try writer.writeAll("&(");
@@ -769,14 +766,14 @@ pub const DeclGen = struct {
.field => |field| {
const ptr_base_ty = Type.fromInterned(ip.typeOf(field.base));
const base_ty = ptr_base_ty.childType(zcu);
- // Ensure complete type definition is visible before accessing fields.
- _ = try dg.typeToIndex(base_ty, .complete);
+ // Ensure complete type definition is available before accessing fields.
+ _ = try dg.ctypeFromType(base_ty, .complete);
switch (fieldLocation(ptr_base_ty, ptr_ty, @as(u32, @intCast(field.index)), zcu)) {
.begin => {
- const ptr_base_cty = try dg.typeToIndex(ptr_base_ty, .complete);
- if (ptr_cty != ptr_base_cty) {
+ const ptr_base_ctype = try dg.ctypeFromType(ptr_base_ty, .complete);
+ if (!ptr_ctype.eql(ptr_base_ctype)) {
try writer.writeByte('(');
- try dg.renderCType(writer, ptr_cty);
+ try dg.renderCType(writer, ptr_ctype);
try writer.writeByte(')');
}
try dg.renderParentPtr(writer, field.base, location);
@@ -797,10 +794,10 @@ pub const DeclGen = struct {
},
else => unreachable,
};
- const field_cty = try dg.typeToIndex(field_ty, .forward);
- if (ptr_child_cty != field_cty) {
+ const field_ctype = try dg.ctypeFromType(field_ty, .forward);
+ if (!ptr_child_ctype.eql(field_ctype)) {
try writer.writeByte('(');
- try dg.renderCType(writer, ptr_cty);
+ try dg.renderCType(writer, ptr_ctype);
try writer.writeByte(')');
}
try writer.writeAll("&(");
@@ -810,15 +807,15 @@ pub const DeclGen = struct {
},
.byte_offset => |byte_offset| {
const u8_ptr_ty = try zcu.adjustPtrTypeChild(ptr_ty, Type.u8);
- const u8_ptr_cty = try dg.typeToIndex(u8_ptr_ty, .complete);
+ const u8_ptr_ctype = try dg.ctypeFromType(u8_ptr_ty, .complete);
- if (ptr_cty != u8_ptr_cty) {
+ if (!ptr_ctype.eql(u8_ptr_ctype)) {
try writer.writeByte('(');
- try dg.renderCType(writer, ptr_cty);
+ try dg.renderCType(writer, ptr_ctype);
try writer.writeByte(')');
}
try writer.writeAll("((");
- try dg.renderCType(writer, u8_ptr_cty);
+ try dg.renderCType(writer, u8_ptr_ctype);
try writer.writeByte(')');
try dg.renderParentPtr(writer, field.base, location);
try writer.print(" + {})", .{
@@ -826,10 +823,10 @@ pub const DeclGen = struct {
});
},
.end => {
- const ptr_base_cty = try dg.typeToIndex(ptr_base_ty, .complete);
- if (ptr_cty != ptr_base_cty) {
+ const ptr_base_ctype = try dg.ctypeFromType(ptr_base_ty, .complete);
+ if (!ptr_ctype.eql(ptr_base_ctype)) {
try writer.writeByte('(');
- try dg.renderCType(writer, ptr_cty);
+ try dg.renderCType(writer, ptr_ctype);
try writer.writeByte(')');
}
try writer.writeAll("((");
@@ -1207,8 +1204,8 @@ pub const DeclGen = struct {
try writer.writeByte('}');
},
.struct_type => {
- const struct_type = ip.loadStructType(ty.toIntern());
- switch (struct_type.layout) {
+ const loaded_struct = ip.loadStructType(ty.toIntern());
+ switch (loaded_struct.layout) {
.auto, .@"extern" => {
if (!location.isInitializer()) {
try writer.writeByte('(');
@@ -1217,13 +1214,14 @@ pub const DeclGen = struct {
}
try writer.writeByte('{');
- var empty = true;
- for (0..struct_type.field_types.len) |field_index| {
- const field_ty = Type.fromInterned(struct_type.field_types.get(ip)[field_index]);
- if (struct_type.fieldIsComptime(ip, field_index)) continue;
+ var field_it = loaded_struct.iterateRuntimeOrder(ip);
+ var need_comma = false;
+ while (field_it.next()) |field_index| {
+ const field_ty = Type.fromInterned(loaded_struct.field_types.get(ip)[field_index]);
if (!field_ty.hasRuntimeBitsIgnoreComptime(zcu)) continue;
- if (!empty) try writer.writeByte(',');
+ if (need_comma) try writer.writeByte(',');
+ need_comma = true;
const field_val = switch (ip.indexToKey(val.toIntern()).aggregate.storage) {
.bytes => |bytes| try ip.get(zcu.gpa, .{ .int = .{
.ty = field_ty.toIntern(),
@@ -1233,8 +1231,6 @@ pub const DeclGen = struct {
.repeated_elem => |elem| elem,
};
try dg.renderValue(writer, Value.fromInterned(field_val), initializer_type);
-
- empty = false;
}
try writer.writeByte('}');
},
@@ -1247,8 +1243,8 @@ pub const DeclGen = struct {
var bit_offset: u64 = 0;
var eff_num_fields: usize = 0;
- for (0..struct_type.field_types.len) |field_index| {
- const field_ty = Type.fromInterned(struct_type.field_types.get(ip)[field_index]);
+ for (0..loaded_struct.field_types.len) |field_index| {
+ const field_ty = Type.fromInterned(loaded_struct.field_types.get(ip)[field_index]);
if (!field_ty.hasRuntimeBitsIgnoreComptime(zcu)) continue;
eff_num_fields += 1;
}
@@ -1268,8 +1264,8 @@ pub const DeclGen = struct {
var eff_index: usize = 0;
var needs_closing_paren = false;
- for (0..struct_type.field_types.len) |field_index| {
- const field_ty = Type.fromInterned(struct_type.field_types.get(ip)[field_index]);
+ for (0..loaded_struct.field_types.len) |field_index| {
+ const field_ty = Type.fromInterned(loaded_struct.field_types.get(ip)[field_index]);
if (!field_ty.hasRuntimeBitsIgnoreComptime(zcu)) continue;
const field_val = switch (ip.indexToKey(val.toIntern()).aggregate.storage) {
@@ -1304,8 +1300,8 @@ pub const DeclGen = struct {
try writer.writeByte('(');
// a << a_off | b << b_off | c << c_off
var empty = true;
- for (0..struct_type.field_types.len) |field_index| {
- const field_ty = Type.fromInterned(struct_type.field_types.get(ip)[field_index]);
+ for (0..loaded_struct.field_types.len) |field_index| {
+ const field_ty = Type.fromInterned(loaded_struct.field_types.get(ip)[field_index]);
if (!field_ty.hasRuntimeBitsIgnoreComptime(zcu)) continue;
if (!empty) try writer.writeAll(" | ");
@@ -1341,10 +1337,10 @@ pub const DeclGen = struct {
else => unreachable,
},
.un => |un| {
- const union_obj = zcu.typeToUnion(ty).?;
+ const loaded_union = ip.loadUnionType(ty.toIntern());
if (un.tag == .none) {
const backing_ty = try ty.unionBackingType(zcu);
- switch (union_obj.getLayout(ip)) {
+ switch (loaded_union.getLayout(ip)) {
.@"packed" => {
if (!location.isInitializer()) {
try writer.writeByte('(');
@@ -1376,10 +1372,10 @@ pub const DeclGen = struct {
try writer.writeByte(')');
}
- const field_index = zcu.unionTagFieldIndex(union_obj, Value.fromInterned(un.tag)).?;
- const field_ty = Type.fromInterned(union_obj.field_types.get(ip)[field_index]);
- const field_name = union_obj.loadTagType(ip).names.get(ip)[field_index];
- if (union_obj.getLayout(ip) == .@"packed") {
+ const field_index = zcu.unionTagFieldIndex(loaded_union, Value.fromInterned(un.tag)).?;
+ const field_ty = Type.fromInterned(loaded_union.field_types.get(ip)[field_index]);
+ const field_name = loaded_union.loadTagType(ip).names.get(ip)[field_index];
+ if (loaded_union.getLayout(ip) == .@"packed") {
if (field_ty.hasRuntimeBits(zcu)) {
if (field_ty.isPtrAtRuntime(zcu)) {
try writer.writeByte('(');
@@ -1399,7 +1395,7 @@ pub const DeclGen = struct {
try writer.writeByte('{');
if (ty.unionTagTypeSafety(zcu)) |_| {
- const layout = zcu.getUnionLayout(union_obj);
+ const layout = zcu.getUnionLayout(loaded_union);
if (layout.tag_size != 0) {
try writer.writeAll(" .tag = ");
try dg.renderValue(writer, Value.fromInterned(un.tag), initializer_type);
@@ -1412,8 +1408,8 @@ pub const DeclGen = struct {
try writer.print(" .{ } = ", .{fmtIdent(ip.stringToSlice(field_name))});
try dg.renderValue(writer, Value.fromInterned(un.val), initializer_type);
try writer.writeByte(' ');
- } else for (0..union_obj.field_types.len) |this_field_index| {
- const this_field_ty = Type.fromInterned(union_obj.field_types.get(ip)[this_field_index]);
+ } else for (0..loaded_union.field_types.len) |this_field_index| {
+ const this_field_ty = Type.fromInterned(loaded_union.field_types.get(ip)[this_field_index]);
if (!this_field_ty.hasRuntimeBits(zcu)) continue;
try dg.renderUndefValue(writer, this_field_ty, initializer_type);
break;
@@ -1445,12 +1441,14 @@ pub const DeclGen = struct {
.ReleaseFast, .ReleaseSmall => false,
};
- switch (ty.zigTypeTag(zcu)) {
- .Bool => try writer.writeAll(if (safety_on) "0xaa" else "false"),
- .Int, .Enum, .ErrorSet => try writer.print("{x}", .{
- try dg.fmtIntLiteral(try zcu.undefValue(ty), location),
- }),
- .Float => {
+ switch (ty.toIntern()) {
+ .c_longdouble_type,
+ .f16_type,
+ .f32_type,
+ .f64_type,
+ .f80_type,
+ .f128_type,
+ => {
const bits = ty.floatBits(target.*);
// All unsigned ints matching float types are pre-allocated.
const repr_ty = zcu.intType(.unsigned, bits) catch unreachable;
@@ -1468,49 +1466,90 @@ pub const DeclGen = struct {
}
try writer.writeAll(", ");
try dg.renderUndefValue(writer, repr_ty, .FunctionArgument);
- try writer.writeByte(')');
+ return writer.writeByte(')');
},
- .Pointer => if (ty.isSlice(zcu)) {
- if (!location.isInitializer()) {
- try writer.writeByte('(');
+ .bool_type => try writer.writeAll(if (safety_on) "0xaa" else "false"),
+ else => switch (ip.indexToKey(ty.toIntern())) {
+ .simple_type,
+ .int_type,
+ .enum_type,
+ .error_set_type,
+ .inferred_error_set_type,
+ => return writer.print("{x}", .{
+ try dg.fmtIntLiteral(try zcu.undefValue(ty), location),
+ }),
+ .ptr_type => if (ty.isSlice(zcu)) {
+ if (!location.isInitializer()) {
+ try writer.writeByte('(');
+ try dg.renderType(writer, ty);
+ try writer.writeByte(')');
+ }
+
+ try writer.writeAll("{(");
+ const ptr_ty = ty.slicePtrFieldType(zcu);
+ try dg.renderType(writer, ptr_ty);
+ return writer.print("){x}, {0x}}}", .{
+ try dg.fmtIntLiteral(try zcu.undefValue(Type.usize), .Other),
+ });
+ } else {
+ try writer.writeAll("((");
try dg.renderType(writer, ty);
- try writer.writeByte(')');
- }
+ return writer.print("){x})", .{
+ try dg.fmtIntLiteral(try zcu.undefValue(Type.usize), .Other),
+ });
+ },
+ .opt_type => {
+ const payload_ty = ty.optionalChild(zcu);
- try writer.writeAll("{(");
- const ptr_ty = ty.slicePtrFieldType(zcu);
- try dg.renderType(writer, ptr_ty);
- try writer.print("){x}, {0x}}}", .{try dg.fmtIntLiteral(try zcu.undefValue(Type.usize), .Other)});
- } else {
- try writer.writeAll("((");
- try dg.renderType(writer, ty);
- try writer.print("){x})", .{try dg.fmtIntLiteral(try zcu.undefValue(Type.usize), .Other)});
- },
- .Optional => {
- const payload_ty = ty.optionalChild(zcu);
+ if (!payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
+ return dg.renderUndefValue(writer, Type.bool, location);
+ }
- if (!payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
- return dg.renderUndefValue(writer, Type.bool, location);
- }
+ if (ty.optionalReprIsPayload(zcu)) {
+ return dg.renderUndefValue(writer, payload_ty, location);
+ }
- if (ty.optionalReprIsPayload(zcu)) {
- return dg.renderUndefValue(writer, payload_ty, location);
- }
+ if (!location.isInitializer()) {
+ try writer.writeByte('(');
+ try dg.renderType(writer, ty);
+ try writer.writeByte(')');
+ }
- if (!location.isInitializer()) {
- try writer.writeByte('(');
- try dg.renderType(writer, ty);
- try writer.writeByte(')');
- }
+ try writer.writeAll("{ .payload = ");
+ try dg.renderUndefValue(writer, payload_ty, initializer_type);
+ try writer.writeAll(", .is_null = ");
+ try dg.renderUndefValue(writer, Type.bool, initializer_type);
+ return writer.writeAll(" }");
+ },
+ .struct_type => {
+ const loaded_struct = ip.loadStructType(ty.toIntern());
+ switch (loaded_struct.layout) {
+ .auto, .@"extern" => {
+ if (!location.isInitializer()) {
+ try writer.writeByte('(');
+ try dg.renderType(writer, ty);
+ try writer.writeByte(')');
+ }
- try writer.writeAll("{ .payload = ");
- try dg.renderUndefValue(writer, payload_ty, initializer_type);
- try writer.writeAll(", .is_null = ");
- try dg.renderUndefValue(writer, Type.bool, initializer_type);
- try writer.writeAll(" }");
- },
- .Struct => switch (ty.containerLayout(zcu)) {
- .auto, .@"extern" => {
+ try writer.writeByte('{');
+ var field_it = loaded_struct.iterateRuntimeOrder(ip);
+ var need_comma = false;
+ while (field_it.next()) |field_index| {
+ const field_ty = Type.fromInterned(loaded_struct.field_types.get(ip)[field_index]);
+ if (!field_ty.hasRuntimeBitsIgnoreComptime(zcu)) continue;
+
+ if (need_comma) try writer.writeByte(',');
+ need_comma = true;
+ try dg.renderUndefValue(writer, field_ty, initializer_type);
+ }
+ return writer.writeByte('}');
+ },
+ .@"packed" => return writer.print("{x}", .{
+ try dg.fmtIntLiteral(try zcu.undefValue(ty), .Other),
+ }),
+ }
+ },
+ .anon_struct_type => |anon_struct_info| {
if (!location.isInitializer()) {
try writer.writeByte('(');
try dg.renderType(writer, ty);
@@ -1518,116 +1557,125 @@ pub const DeclGen = struct {
}
try writer.writeByte('{');
- var empty = true;
- for (0..ty.structFieldCount(zcu)) |field_index| {
- if (ty.structFieldIsComptime(field_index, zcu)) continue;
- const field_ty = ty.structFieldType(field_index, zcu);
- if (!field_ty.hasRuntimeBits(zcu)) continue;
+ var need_comma = false;
+ for (0..anon_struct_info.types.len) |field_index| {
+ if (anon_struct_info.values.get(ip)[field_index] != .none) continue;
+ const field_ty = Type.fromInterned(anon_struct_info.types.get(ip)[field_index]);
+ if (!field_ty.hasRuntimeBitsIgnoreComptime(zcu)) continue;
- if (!empty) try writer.writeByte(',');
+ if (need_comma) try writer.writeByte(',');
+ need_comma = true;
try dg.renderUndefValue(writer, field_ty, initializer_type);
-
- empty = false;
}
-
- try writer.writeByte('}');
+ return writer.writeByte('}');
},
- .@"packed" => try writer.print("{x}", .{
- try dg.fmtIntLiteral(try zcu.undefValue(ty), .Other),
- }),
- },
- .Union => {
- if (!location.isInitializer()) {
- try writer.writeByte('(');
- try dg.renderType(writer, ty);
- try writer.writeByte(')');
- }
+ .union_type => {
+ const loaded_union = ip.loadUnionType(ty.toIntern());
+ switch (loaded_union.getLayout(ip)) {
+ .auto, .@"extern" => {
+ if (!location.isInitializer()) {
+ try writer.writeByte('(');
+ try dg.renderType(writer, ty);
+ try writer.writeByte(')');
+ }
- try writer.writeByte('{');
- if (ty.unionTagTypeSafety(zcu)) |tag_ty| {
- const layout = ty.unionGetLayout(zcu);
- if (layout.tag_size != 0) {
- try writer.writeAll(" .tag = ");
- try dg.renderUndefValue(writer, tag_ty, initializer_type);
+ try writer.writeByte('{');
+ if (ty.unionTagTypeSafety(zcu)) |tag_ty| {
+ const layout = ty.unionGetLayout(zcu);
+ if (layout.tag_size != 0) {
+ try writer.writeAll(" .tag = ");
+ try dg.renderUndefValue(writer, tag_ty, initializer_type);
+ }
+ if (ty.unionHasAllZeroBitFieldTypes(zcu)) return try writer.writeByte('}');
+ if (layout.tag_size != 0) try writer.writeByte(',');
+ try writer.writeAll(" .payload = {");
+ }
+ for (0..loaded_union.field_types.len) |field_index| {
+ const field_ty = Type.fromInterned(loaded_union.field_types.get(ip)[field_index]);
+ if (!field_ty.hasRuntimeBits(zcu)) continue;
+ try dg.renderUndefValue(writer, field_ty, initializer_type);
+ break;
+ }
+ if (ty.unionTagTypeSafety(zcu)) |_| try writer.writeByte('}');
+ return writer.writeByte('}');
+ },
+ .@"packed" => return writer.print("{x}", .{
+ try dg.fmtIntLiteral(try zcu.undefValue(ty), .Other),
+ }),
}
- if (ty.unionHasAllZeroBitFieldTypes(zcu)) return try writer.writeByte('}');
- if (layout.tag_size != 0) try writer.writeByte(',');
- try writer.writeAll(" .payload = {");
- }
- const union_obj = zcu.typeToUnion(ty).?;
- for (0..union_obj.field_types.len) |field_index| {
- const field_ty = Type.fromInterned(union_obj.field_types.get(ip)[field_index]);
- if (!field_ty.hasRuntimeBits(zcu)) continue;
- try dg.renderUndefValue(writer, field_ty, initializer_type);
- break;
- }
- if (ty.unionTagTypeSafety(zcu)) |_| try writer.writeByte('}');
- try writer.writeByte('}');
- },
- .ErrorUnion => {
- const payload_ty = ty.errorUnionPayload(zcu);
- const error_ty = ty.errorUnionSet(zcu);
-
- if (!payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
- return dg.renderUndefValue(writer, error_ty, location);
- }
+ },
+ .error_union_type => {
+ const payload_ty = ty.errorUnionPayload(zcu);
+ const error_ty = ty.errorUnionSet(zcu);
- if (!location.isInitializer()) {
- try writer.writeByte('(');
- try dg.renderType(writer, ty);
- try writer.writeByte(')');
- }
+ if (!payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
+ return dg.renderUndefValue(writer, error_ty, location);
+ }
- try writer.writeAll("{ .payload = ");
- try dg.renderUndefValue(writer, payload_ty, initializer_type);
- try writer.writeAll(", .error = ");
- try dg.renderUndefValue(writer, error_ty, initializer_type);
- try writer.writeAll(" }");
- },
- .Array, .Vector => {
- const ai = ty.arrayInfo(zcu);
- if (ai.elem_type.eql(Type.u8, zcu)) {
- const c_len = ty.arrayLenIncludingSentinel(zcu);
- var literal = stringLiteral(writer, c_len);
- try literal.start();
- var index: u64 = 0;
- while (index < c_len) : (index += 1)
- try literal.writeChar(0xaa);
- try literal.end();
- } else {
if (!location.isInitializer()) {
try writer.writeByte('(');
try dg.renderType(writer, ty);
try writer.writeByte(')');
}
- try writer.writeByte('{');
- const c_len = ty.arrayLenIncludingSentinel(zcu);
- var index: u64 = 0;
- while (index < c_len) : (index += 1) {
- if (index > 0) try writer.writeAll(", ");
- try dg.renderUndefValue(writer, ty.childType(zcu), initializer_type);
+ try writer.writeAll("{ .payload = ");
+ try dg.renderUndefValue(writer, payload_ty, initializer_type);
+ try writer.writeAll(", .error = ");
+ try dg.renderUndefValue(writer, error_ty, initializer_type);
+ return writer.writeAll(" }");
+ },
+ .array_type, .vector_type => {
+ const ai = ty.arrayInfo(zcu);
+ if (ai.elem_type.eql(Type.u8, zcu)) {
+ const c_len = ty.arrayLenIncludingSentinel(zcu);
+ var literal = stringLiteral(writer, c_len);
+ try literal.start();
+ var index: u64 = 0;
+ while (index < c_len) : (index += 1)
+ try literal.writeChar(0xaa);
+ return literal.end();
+ } else {
+ if (!location.isInitializer()) {
+ try writer.writeByte('(');
+ try dg.renderType(writer, ty);
+ try writer.writeByte(')');
+ }
+
+ try writer.writeByte('{');
+ const c_len = ty.arrayLenIncludingSentinel(zcu);
+ var index: u64 = 0;
+ while (index < c_len) : (index += 1) {
+ if (index > 0) try writer.writeAll(", ");
+ try dg.renderUndefValue(writer, ty.childType(zcu), initializer_type);
+ }
+ return writer.writeByte('}');
}
- try writer.writeByte('}');
- }
+ },
+ .anyframe_type,
+ .opaque_type,
+ .func_type,
+ => unreachable,
+
+ .undef,
+ .simple_value,
+ .variable,
+ .extern_func,
+ .func,
+ .int,
+ .err,
+ .error_union,
+ .enum_literal,
+ .enum_tag,
+ .empty_enum_value,
+ .float,
+ .ptr,
+ .slice,
+ .opt,
+ .aggregate,
+ .un,
+ .memoized_call,
+ => unreachable,
},
- .ComptimeInt,
- .ComptimeFloat,
- .Type,
- .EnumLiteral,
- .Void,
- .NoReturn,
- .Undefined,
- .Null,
- .Opaque,
- => unreachable,
-
- .Fn,
- .Frame,
- .AnyFrame,
- => |tag| return dg.fail("TODO: C backend: implement value of type {s}", .{
- @tagName(tag),
- }),
}
}
@@ -1641,13 +1689,12 @@ pub const DeclGen = struct {
ident: []const u8,
},
) !void {
- const store = &dg.ctypes.set;
const zcu = dg.zcu;
const ip = &zcu.intern_pool;
const fn_decl = zcu.declPtr(fn_decl_index);
const fn_ty = fn_decl.typeOf(zcu);
- const fn_cty_idx = try dg.typeToIndex(fn_ty, kind);
+ const fn_ctype = try dg.ctypeFromType(fn_ty, kind);
const fn_info = zcu.typeToFunc(fn_ty).?;
if (fn_info.cc == .Naked) {
@@ -1661,7 +1708,7 @@ pub const DeclGen = struct {
try w.writeAll("zig_cold ");
if (fn_info.return_type == .noreturn_type) try w.writeAll("zig_noreturn ");
- var trailing = try renderTypePrefix(dg.pass, store.*, zcu, w, fn_cty_idx, .suffix, .{});
+ var trailing = try renderTypePrefix(dg.pass, &dg.ctype_pool, zcu, w, fn_ctype, .suffix, .{});
if (toCallingConvention(fn_info.cc)) |call_conv| {
try w.print("{}zig_callconv({s})", .{ trailing, call_conv });
@@ -1670,7 +1717,7 @@ pub const DeclGen = struct {
switch (kind) {
.forward => {},
- .complete => if (fn_decl.alignment.toByteUnitsOptional()) |a| {
+ .complete => if (fn_decl.alignment.toByteUnits()) |a| {
try w.print("{}zig_align_fn({})", .{ trailing, a });
trailing = .maybe_space;
},
@@ -1687,10 +1734,10 @@ pub const DeclGen = struct {
try renderTypeSuffix(
dg.pass,
- store.*,
+ &dg.ctype_pool,
zcu,
w,
- fn_cty_idx,
+ fn_ctype,
.suffix,
CQualifiers.init(.{ .@"const" = switch (kind) {
.forward => false,
@@ -1701,7 +1748,7 @@ pub const DeclGen = struct {
switch (kind) {
.forward => {
- if (fn_decl.alignment.toByteUnitsOptional()) |a| {
+ if (fn_decl.alignment.toByteUnits()) |a| {
try w.print(" zig_align_fn({})", .{a});
}
switch (name) {
@@ -1748,20 +1795,13 @@ pub const DeclGen = struct {
}
}
- fn indexToCType(dg: *DeclGen, idx: CType.Index) CType {
- return dg.ctypes.indexToCType(idx);
+ fn ctypeFromType(dg: *DeclGen, ty: Type, kind: CType.Kind) !CType {
+ defer std.debug.assert(dg.scratch.items.len == 0);
+ return dg.ctype_pool.fromType(dg.gpa, &dg.scratch, ty, dg.zcu, dg.mod, kind);
}
- fn typeToIndex(dg: *DeclGen, ty: Type, kind: CType.Kind) !CType.Index {
- return dg.ctypes.typeToIndex(dg.gpa, ty, dg.zcu, dg.mod, kind);
- }
-
- fn typeToCType(dg: *DeclGen, ty: Type, kind: CType.Kind) !CType {
- return dg.ctypes.typeToCType(dg.gpa, ty, dg.zcu, dg.mod, kind);
- }
-
- fn byteSize(dg: *DeclGen, cty: CType) u64 {
- return cty.byteSize(dg.ctypes.set, dg.mod);
+ fn byteSize(dg: *DeclGen, ctype: CType) u64 {
+ return ctype.byteSize(&dg.ctype_pool, dg.mod);
}
/// Renders a type as a single identifier, generating intermediate typedefs
@@ -1776,14 +1816,12 @@ pub const DeclGen = struct {
/// | `renderType` | "uint8_t *" | "uint8_t *[10]" |
///
fn renderType(dg: *DeclGen, w: anytype, t: Type) error{ OutOfMemory, AnalysisFail }!void {
- try dg.renderCType(w, try dg.typeToIndex(t, .complete));
+ try dg.renderCType(w, try dg.ctypeFromType(t, .complete));
}
- fn renderCType(dg: *DeclGen, w: anytype, idx: CType.Index) error{ OutOfMemory, AnalysisFail }!void {
- const store = &dg.ctypes.set;
- const zcu = dg.zcu;
- _ = try renderTypePrefix(dg.pass, store.*, zcu, w, idx, .suffix, .{});
- try renderTypeSuffix(dg.pass, store.*, zcu, w, idx, .suffix, .{});
+ fn renderCType(dg: *DeclGen, w: anytype, ctype: CType) error{ OutOfMemory, AnalysisFail }!void {
+ _ = try renderTypePrefix(dg.pass, &dg.ctype_pool, dg.zcu, w, ctype, .suffix, .{});
+ try renderTypeSuffix(dg.pass, &dg.ctype_pool, dg.zcu, w, ctype, .suffix, .{});
}
const IntCastContext = union(enum) {
@@ -1905,32 +1943,37 @@ pub const DeclGen = struct {
alignment: Alignment,
kind: CType.Kind,
) error{ OutOfMemory, AnalysisFail }!void {
- const zcu = dg.zcu;
- const alignas = CType.AlignAs.init(alignment, ty.abiAlignment(zcu));
- try dg.renderCTypeAndName(w, try dg.typeToIndex(ty, kind), name, qualifiers, alignas);
+ try dg.renderCTypeAndName(
+ w,
+ try dg.ctypeFromType(ty, kind),
+ name,
+ qualifiers,
+ CType.AlignAs.fromAlignment(.{
+ .@"align" = alignment,
+ .abi = ty.abiAlignment(dg.zcu),
+ }),
+ );
}
fn renderCTypeAndName(
dg: *DeclGen,
w: anytype,
- cty_idx: CType.Index,
+ ctype: CType,
name: CValue,
qualifiers: CQualifiers,
alignas: CType.AlignAs,
) error{ OutOfMemory, AnalysisFail }!void {
- const store = &dg.ctypes.set;
- const zcu = dg.zcu;
-
switch (alignas.abiOrder()) {
.lt => try w.print("zig_under_align({}) ", .{alignas.toByteUnits()}),
.eq => {},
.gt => try w.print("zig_align({}) ", .{alignas.toByteUnits()}),
}
- const trailing = try renderTypePrefix(dg.pass, store.*, zcu, w, cty_idx, .suffix, qualifiers);
- try w.print("{}", .{trailing});
+ try w.print("{}", .{
+ try renderTypePrefix(dg.pass, &dg.ctype_pool, dg.zcu, w, ctype, .suffix, qualifiers),
+ });
try dg.writeName(w, name);
- try renderTypeSuffix(dg.pass, store.*, zcu, w, cty_idx, .suffix, .{});
+ try renderTypeSuffix(dg.pass, &dg.ctype_pool, dg.zcu, w, ctype, .suffix, .{});
}
fn declIsGlobal(dg: *DeclGen, val: Value) bool {
@@ -2094,33 +2137,31 @@ pub const DeclGen = struct {
}
fn renderTypeForBuiltinFnName(dg: *DeclGen, writer: anytype, ty: Type) !void {
- try dg.renderCTypeForBuiltinFnName(writer, try dg.typeToCType(ty, .complete));
+ try dg.renderCTypeForBuiltinFnName(writer, try dg.ctypeFromType(ty, .complete));
}
- fn renderCTypeForBuiltinFnName(dg: *DeclGen, writer: anytype, cty: CType) !void {
- switch (cty.tag()) {
- else => try writer.print("{c}{d}", .{
- if (cty.isBool())
+ fn renderCTypeForBuiltinFnName(dg: *DeclGen, writer: anytype, ctype: CType) !void {
+ switch (ctype.info(&dg.ctype_pool)) {
+ else => |ctype_info| try writer.print("{c}{d}", .{
+ if (ctype.isBool())
signAbbrev(.unsigned)
- else if (cty.isInteger())
- signAbbrev(cty.signedness(dg.mod))
- else if (cty.isFloat())
+ else if (ctype.isInteger())
+ signAbbrev(ctype.signedness(dg.mod))
+ else if (ctype.isFloat())
@as(u8, 'f')
- else if (cty.isPointer())
+ else if (ctype_info == .pointer)
@as(u8, 'p')
else
- return dg.fail("TODO: CBE: implement renderTypeForBuiltinFnName for type {}", .{
- cty.tag(),
- }),
- if (cty.isFloat()) cty.floatActiveBits(dg.mod) else dg.byteSize(cty) * 8,
+ return dg.fail("TODO: CBE: implement renderTypeForBuiltinFnName for {s} type", .{@tagName(ctype_info)}),
+ if (ctype.isFloat()) ctype.floatActiveBits(dg.mod) else dg.byteSize(ctype) * 8,
}),
.array => try writer.writeAll("big"),
}
}
fn renderBuiltinInfo(dg: *DeclGen, writer: anytype, ty: Type, info: BuiltinInfo) !void {
- const cty = try dg.typeToCType(ty, .complete);
- const is_big = cty.tag() == .array;
+ const ctype = try dg.ctypeFromType(ty, .complete);
+ const is_big = ctype.info(&dg.ctype_pool) == .array;
switch (info) {
.none => if (!is_big) return,
.bits => {},
@@ -2155,7 +2196,7 @@ pub const DeclGen = struct {
.dg = dg,
.int_info = ty.intInfo(zcu),
.kind = kind,
- .cty = try dg.typeToCType(ty, kind),
+ .ctype = try dg.ctypeFromType(ty, kind),
.val = val,
} };
}
@@ -2184,122 +2225,74 @@ const RenderCTypeTrailing = enum {
}
}
};
-fn renderTypeName(
+fn renderAlignedTypeName(w: anytype, ctype: CType) !void {
+ try w.print("anon__aligned_{d}", .{@intFromEnum(ctype.index)});
+}
+fn renderFwdDeclTypeName(
zcu: *Zcu,
w: anytype,
- idx: CType.Index,
- cty: CType,
+ ctype: CType,
+ fwd_decl: CType.Info.FwdDecl,
attributes: []const u8,
) !void {
- switch (cty.tag()) {
- else => unreachable,
-
- .fwd_anon_struct,
- .fwd_anon_union,
- => |tag| try w.print("{s} {s}anon__lazy_{d}", .{
- @tagName(tag)["fwd_anon_".len..],
- attributes,
- idx,
+ try w.print("{s} {s}", .{ @tagName(fwd_decl.tag), attributes });
+ switch (fwd_decl.name) {
+ .anon => try w.print("anon__lazy_{d}", .{@intFromEnum(ctype.index)}),
+ .owner_decl => |owner_decl| try w.print("{}__{d}", .{
+ fmtIdent(zcu.intern_pool.stringToSlice(zcu.declPtr(owner_decl).name)),
+ @intFromEnum(owner_decl),
}),
-
- .fwd_struct,
- .fwd_union,
- => |tag| {
- const owner_decl = cty.cast(CType.Payload.FwdDecl).?.data;
- try w.print("{s} {s}{}__{d}", .{
- @tagName(tag)["fwd_".len..],
- attributes,
- fmtIdent(zcu.intern_pool.stringToSlice(zcu.declPtr(owner_decl).name)),
- @intFromEnum(owner_decl),
- });
- },
}
}
fn renderTypePrefix(
pass: DeclGen.Pass,
- store: CType.Store.Set,
+ ctype_pool: *const CType.Pool,
zcu: *Zcu,
w: anytype,
- idx: CType.Index,
+ ctype: CType,
parent_fix: CTypeFix,
qualifiers: CQualifiers,
) @TypeOf(w).Error!RenderCTypeTrailing {
var trailing = RenderCTypeTrailing.maybe_space;
+ switch (ctype.info(ctype_pool)) {
+ .basic => |basic_info| try w.writeAll(@tagName(basic_info)),
- const cty = store.indexToCType(idx);
- switch (cty.tag()) {
- .void,
- .char,
- .@"signed char",
- .short,
- .int,
- .long,
- .@"long long",
- ._Bool,
- .@"unsigned char",
- .@"unsigned short",
- .@"unsigned int",
- .@"unsigned long",
- .@"unsigned long long",
- .float,
- .double,
- .@"long double",
- .bool,
- .size_t,
- .ptrdiff_t,
- .uint8_t,
- .int8_t,
- .uint16_t,
- .int16_t,
- .uint32_t,
- .int32_t,
- .uint64_t,
- .int64_t,
- .uintptr_t,
- .intptr_t,
- .zig_u128,
- .zig_i128,
- .zig_f16,
- .zig_f32,
- .zig_f64,
- .zig_f80,
- .zig_f128,
- .zig_c_longdouble,
- => |tag| try w.writeAll(@tagName(tag)),
-
- .pointer,
- .pointer_const,
- .pointer_volatile,
- .pointer_const_volatile,
- => |tag| {
- const child_idx = cty.cast(CType.Payload.Child).?.data;
- const child_trailing = try renderTypePrefix(
+ .pointer => |pointer_info| {
+ try w.print("{}*", .{try renderTypePrefix(
pass,
- store,
+ ctype_pool,
zcu,
w,
- child_idx,
+ pointer_info.elem_ctype,
.prefix,
- CQualifiers.init(.{ .@"const" = switch (tag) {
- .pointer, .pointer_volatile => false,
- .pointer_const, .pointer_const_volatile => true,
- else => unreachable,
- }, .@"volatile" = switch (tag) {
- .pointer, .pointer_const => false,
- .pointer_volatile, .pointer_const_volatile => true,
- else => unreachable,
- } }),
- );
- try w.print("{}*", .{child_trailing});
+ CQualifiers.init(.{
+ .@"const" = pointer_info.@"const",
+ .@"volatile" = pointer_info.@"volatile",
+ }),
+ )});
trailing = .no_space;
},
- .array,
- .vector,
- => {
- const child_idx = cty.cast(CType.Payload.Sequence).?.data.elem_type;
- const child_trailing =
- try renderTypePrefix(pass, store, zcu, w, child_idx, .suffix, qualifiers);
+ .aligned => switch (pass) {
+ .decl => |decl_index| try w.print("decl__{d}_{d}", .{
+ @intFromEnum(decl_index), @intFromEnum(ctype.index),
+ }),
+ .anon => |anon_decl| try w.print("anon__{d}_{d}", .{
+ @intFromEnum(anon_decl), @intFromEnum(ctype.index),
+ }),
+ .flush => try renderAlignedTypeName(w, ctype),
+ },
+
+ .array, .vector => |sequence_info| {
+ const child_trailing = try renderTypePrefix(
+ pass,
+ ctype_pool,
+ zcu,
+ w,
+ sequence_info.elem_ctype,
+ .suffix,
+ qualifiers,
+ );
switch (parent_fix) {
.prefix => {
try w.print("{}(", .{child_trailing});
@@ -2309,56 +2302,46 @@ fn renderTypePrefix(
}
},
- .fwd_anon_struct,
- .fwd_anon_union,
- => switch (pass) {
- .decl => |decl_index| try w.print("decl__{d}_{d}", .{ @intFromEnum(decl_index), idx }),
- .anon => |anon_decl| try w.print("anon__{d}_{d}", .{ @intFromEnum(anon_decl), idx }),
- .flush => try renderTypeName(zcu, w, idx, cty, ""),
+ .fwd_decl => |fwd_decl_info| switch (fwd_decl_info.name) {
+ .anon => switch (pass) {
+ .decl => |decl_index| try w.print("decl__{d}_{d}", .{
+ @intFromEnum(decl_index), @intFromEnum(ctype.index),
+ }),
+ .anon => |anon_decl| try w.print("anon__{d}_{d}", .{
+ @intFromEnum(anon_decl), @intFromEnum(ctype.index),
+ }),
+ .flush => try renderFwdDeclTypeName(zcu, w, ctype, fwd_decl_info, ""),
+ },
+ .owner_decl => try renderFwdDeclTypeName(zcu, w, ctype, fwd_decl_info, ""),
},
- .fwd_struct,
- .fwd_union,
- => try renderTypeName(zcu, w, idx, cty, ""),
-
- .unnamed_struct,
- .unnamed_union,
- .packed_unnamed_struct,
- .packed_unnamed_union,
- => |tag| {
- try w.print("{s} {s}", .{
- @tagName(tag)["unnamed_".len..],
- if (cty.isPacked()) "zig_packed(" else "",
- });
- try renderAggregateFields(zcu, w, store, cty, 1);
- if (cty.isPacked()) try w.writeByte(')');
+ .aggregate => |aggregate_info| switch (aggregate_info.name) {
+ .anon => {
+ try w.print("{s} {s}", .{
+ @tagName(aggregate_info.tag),
+ if (aggregate_info.@"packed") "zig_packed(" else "",
+ });
+ try renderFields(zcu, w, ctype_pool, aggregate_info, 1);
+ if (aggregate_info.@"packed") try w.writeByte(')');
+ },
+ .fwd_decl => |fwd_decl| return renderTypePrefix(
+ pass,
+ ctype_pool,
+ zcu,
+ w,
+ fwd_decl,
+ parent_fix,
+ qualifiers,
+ ),
},
- .anon_struct,
- .anon_union,
- .@"struct",
- .@"union",
- .packed_struct,
- .packed_union,
- => return renderTypePrefix(
- pass,
- store,
- zcu,
- w,
- cty.cast(CType.Payload.Aggregate).?.data.fwd_decl,
- parent_fix,
- qualifiers,
- ),
-
- .function,
- .varargs_function,
- => {
+ .function => |function_info| {
const child_trailing = try renderTypePrefix(
pass,
- store,
+ ctype_pool,
zcu,
w,
- cty.cast(CType.Payload.Function).?.data.return_type,
+ function_info.return_ctype,
.suffix,
.{},
);
@@ -2371,170 +2354,107 @@ fn renderTypePrefix(
}
},
}
-
var qualifier_it = qualifiers.iterator();
while (qualifier_it.next()) |qualifier| {
try w.print("{}{s}", .{ trailing, @tagName(qualifier) });
trailing = .maybe_space;
}
-
return trailing;
}
fn renderTypeSuffix(
pass: DeclGen.Pass,
- store: CType.Store.Set,
+ ctype_pool: *const CType.Pool,
zcu: *Zcu,
w: anytype,
- idx: CType.Index,
+ ctype: CType,
parent_fix: CTypeFix,
qualifiers: CQualifiers,
) @TypeOf(w).Error!void {
- const cty = store.indexToCType(idx);
- switch (cty.tag()) {
- .void,
- .char,
- .@"signed char",
- .short,
- .int,
- .long,
- .@"long long",
- ._Bool,
- .@"unsigned char",
- .@"unsigned short",
- .@"unsigned int",
- .@"unsigned long",
- .@"unsigned long long",
- .float,
- .double,
- .@"long double",
- .bool,
- .size_t,
- .ptrdiff_t,
- .uint8_t,
- .int8_t,
- .uint16_t,
- .int16_t,
- .uint32_t,
- .int32_t,
- .uint64_t,
- .int64_t,
- .uintptr_t,
- .intptr_t,
- .zig_u128,
- .zig_i128,
- .zig_f16,
- .zig_f32,
- .zig_f64,
- .zig_f80,
- .zig_f128,
- .zig_c_longdouble,
- => {},
-
- .pointer,
- .pointer_const,
- .pointer_volatile,
- .pointer_const_volatile,
- => try renderTypeSuffix(
+ switch (ctype.info(ctype_pool)) {
+ .basic, .aligned, .fwd_decl, .aggregate => {},
+ .pointer => |pointer_info| try renderTypeSuffix(
pass,
- store,
+ ctype_pool,
zcu,
w,
- cty.cast(CType.Payload.Child).?.data,
+ pointer_info.elem_ctype,
.prefix,
.{},
),
-
- .array,
- .vector,
- => {
+ .array, .vector => |sequence_info| {
switch (parent_fix) {
.prefix => try w.writeByte(')'),
.suffix => {},
}
- try w.print("[{}]", .{cty.cast(CType.Payload.Sequence).?.data.len});
- try renderTypeSuffix(
- pass,
- store,
- zcu,
- w,
- cty.cast(CType.Payload.Sequence).?.data.elem_type,
- .suffix,
- .{},
- );
+ try w.print("[{}]", .{sequence_info.len});
+ try renderTypeSuffix(pass, ctype_pool, zcu, w, sequence_info.elem_ctype, .suffix, .{});
},
-
- .fwd_anon_struct,
- .fwd_anon_union,
- .fwd_struct,
- .fwd_union,
- .unnamed_struct,
- .unnamed_union,
- .packed_unnamed_struct,
- .packed_unnamed_union,
- .anon_struct,
- .anon_union,
- .@"struct",
- .@"union",
- .packed_struct,
- .packed_union,
- => {},
-
- .function,
- .varargs_function,
- => |tag| {
+ .function => |function_info| {
switch (parent_fix) {
.prefix => try w.writeByte(')'),
.suffix => {},
}
- const data = cty.cast(CType.Payload.Function).?.data;
-
try w.writeByte('(');
var need_comma = false;
- for (data.param_types, 0..) |param_type, param_i| {
+ for (0..function_info.param_ctypes.len) |param_index| {
+ const param_type = function_info.param_ctypes.at(param_index, ctype_pool);
if (need_comma) try w.writeAll(", ");
need_comma = true;
const trailing =
- try renderTypePrefix(pass, store, zcu, w, param_type, .suffix, qualifiers);
- if (qualifiers.contains(.@"const")) try w.print("{}a{d}", .{ trailing, param_i });
- try renderTypeSuffix(pass, store, zcu, w, param_type, .suffix, .{});
+ try renderTypePrefix(pass, ctype_pool, zcu, w, param_type, .suffix, qualifiers);
+ if (qualifiers.contains(.@"const")) try w.print("{}a{d}", .{ trailing, param_index });
+ try renderTypeSuffix(pass, ctype_pool, zcu, w, param_type, .suffix, .{});
}
- switch (tag) {
- .function => {},
- .varargs_function => {
- if (need_comma) try w.writeAll(", ");
- need_comma = true;
- try w.writeAll("...");
- },
- else => unreachable,
+ if (function_info.varargs) {
+ if (need_comma) try w.writeAll(", ");
+ need_comma = true;
+ try w.writeAll("...");
}
if (!need_comma) try w.writeAll("void");
try w.writeByte(')');
- try renderTypeSuffix(pass, store, zcu, w, data.return_type, .suffix, .{});
+ try renderTypeSuffix(pass, ctype_pool, zcu, w, function_info.return_ctype, .suffix, .{});
},
}
}
-fn renderAggregateFields(
+fn renderFields(
zcu: *Zcu,
writer: anytype,
- store: CType.Store.Set,
- cty: CType,
+ ctype_pool: *const CType.Pool,
+ aggregate_info: CType.Info.Aggregate,
indent: usize,
) !void {
try writer.writeAll("{\n");
- const fields = cty.fields();
- for (fields) |field| {
+ for (0..aggregate_info.fields.len) |field_index| {
+ const field_info = aggregate_info.fields.at(field_index, ctype_pool);
try writer.writeByteNTimes(' ', indent + 1);
- switch (field.alignas.abiOrder()) {
- .lt => try writer.print("zig_under_align({}) ", .{field.alignas.toByteUnits()}),
- .eq => {},
- .gt => try writer.print("zig_align({}) ", .{field.alignas.toByteUnits()}),
+ switch (field_info.alignas.abiOrder()) {
+ .lt => {
+ std.debug.assert(aggregate_info.@"packed");
+ if (field_info.alignas.@"align" != .@"1") try writer.print("zig_under_align({}) ", .{
+ field_info.alignas.toByteUnits(),
+ });
+ },
+ .eq => if (aggregate_info.@"packed" and field_info.alignas.@"align" != .@"1")
+ try writer.print("zig_align({}) ", .{field_info.alignas.toByteUnits()}),
+ .gt => {
+ std.debug.assert(field_info.alignas.@"align" != .@"1");
+ try writer.print("zig_align({}) ", .{field_info.alignas.toByteUnits()});
+ },
}
- const trailing = try renderTypePrefix(.flush, store, zcu, writer, field.type, .suffix, .{});
- try writer.print("{}{ }", .{ trailing, fmtIdent(mem.span(field.name)) });
- try renderTypeSuffix(.flush, store, zcu, writer, field.type, .suffix, .{});
+ const trailing = try renderTypePrefix(
+ .flush,
+ ctype_pool,
+ zcu,
+ writer,
+ field_info.ctype,
+ .suffix,
+ .{},
+ );
+ try writer.print("{}{ }", .{ trailing, fmtIdent(field_info.name.slice(ctype_pool)) });
+ try renderTypeSuffix(.flush, ctype_pool, zcu, writer, field_info.ctype, .suffix, .{});
try writer.writeAll(";\n");
}
try writer.writeByteNTimes(' ', indent);
@@ -2544,77 +2464,77 @@ fn renderAggregateFields(
pub fn genTypeDecl(
zcu: *Zcu,
writer: anytype,
- global_store: CType.Store.Set,
- global_idx: CType.Index,
+ global_ctype_pool: *const CType.Pool,
+ global_ctype: CType,
pass: DeclGen.Pass,
- decl_store: CType.Store.Set,
- decl_idx: CType.Index,
+ decl_ctype_pool: *const CType.Pool,
+ decl_ctype: CType,
found_existing: bool,
) !void {
- const global_cty = global_store.indexToCType(global_idx);
- switch (global_cty.tag()) {
- .fwd_anon_struct => if (pass != .flush) {
- try writer.writeAll("typedef ");
- _ = try renderTypePrefix(.flush, global_store, zcu, writer, global_idx, .suffix, .{});
- try writer.writeByte(' ');
- _ = try renderTypePrefix(pass, decl_store, zcu, writer, decl_idx, .suffix, .{});
- try writer.writeAll(";\n");
- },
-
- .fwd_struct,
- .fwd_union,
- .anon_struct,
- .anon_union,
- .@"struct",
- .@"union",
- .packed_struct,
- .packed_union,
- => |tag| if (!found_existing) {
- switch (tag) {
- .fwd_struct,
- .fwd_union,
- => {
- const owner_decl = global_cty.cast(CType.Payload.FwdDecl).?.data;
- _ = try renderTypePrefix(
- .flush,
- global_store,
- zcu,
- writer,
- global_idx,
- .suffix,
- .{},
- );
- try writer.writeAll("; /* ");
- try zcu.declPtr(owner_decl).renderFullyQualifiedName(zcu, writer);
- try writer.writeAll(" */\n");
- },
-
- .anon_struct,
- .anon_union,
- .@"struct",
- .@"union",
- .packed_struct,
- .packed_union,
- => {
- const fwd_idx = global_cty.cast(CType.Payload.Aggregate).?.data.fwd_decl;
- try renderTypeName(
- zcu,
- writer,
- fwd_idx,
- global_store.indexToCType(fwd_idx),
- if (global_cty.isPacked()) "zig_packed(" else "",
- );
+ switch (global_ctype.info(global_ctype_pool)) {
+ .basic, .pointer, .array, .vector, .function => {},
+ .aligned => |aligned_info| {
+ if (!found_existing) {
+ try writer.writeAll("typedef ");
+ try writer.print("{}", .{
+ try renderTypePrefix(pass, global_ctype_pool, zcu, writer, aligned_info.ctype, .suffix, .{}),
+ });
+ try renderAlignedTypeName(writer, global_ctype);
+ try renderTypeSuffix(pass, global_ctype_pool, zcu, writer, aligned_info.ctype, .suffix, .{});
+ std.debug.assert(aligned_info.alignas.abiOrder().compare(.lt));
+ try writer.print(" zig_under_align({d});\n", .{aligned_info.alignas.toByteUnits()});
+ }
+ switch (pass) {
+ .decl, .anon => {
+ try writer.writeAll("typedef ");
+ _ = try renderTypePrefix(.flush, global_ctype_pool, zcu, writer, global_ctype, .suffix, .{});
try writer.writeByte(' ');
- try renderAggregateFields(zcu, writer, global_store, global_cty, 0);
- if (global_cty.isPacked()) try writer.writeByte(')');
+ _ = try renderTypePrefix(pass, decl_ctype_pool, zcu, writer, decl_ctype, .suffix, .{});
try writer.writeAll(";\n");
},
-
- else => unreachable,
+ .flush => {},
}
},
-
- else => {},
+ .fwd_decl => |fwd_decl_info| switch (fwd_decl_info.name) {
+ .anon => switch (pass) {
+ .decl, .anon => {
+ try writer.writeAll("typedef ");
+ _ = try renderTypePrefix(.flush, global_ctype_pool, zcu, writer, global_ctype, .suffix, .{});
+ try writer.writeByte(' ');
+ _ = try renderTypePrefix(pass, decl_ctype_pool, zcu, writer, decl_ctype, .suffix, .{});
+ try writer.writeAll(";\n");
+ },
+ .flush => {},
+ },
+ .owner_decl => |owner_decl_index| if (!found_existing) {
+ _ = try renderTypePrefix(.flush, global_ctype_pool, zcu, writer, global_ctype, .suffix, .{});
+ try writer.writeByte(';');
+ const owner_decl = zcu.declPtr(owner_decl_index);
+ const owner_mod = zcu.namespacePtr(owner_decl.src_namespace).file_scope.mod;
+ if (!owner_mod.strip) {
+ try writer.writeAll(" /* ");
+ try owner_decl.renderFullyQualifiedName(zcu, writer);
+ try writer.writeAll(" */");
+ }
+ try writer.writeByte('\n');
+ },
+ },
+ .aggregate => |aggregate_info| switch (aggregate_info.name) {
+ .anon => {},
+ .fwd_decl => |fwd_decl| if (!found_existing) {
+ try renderFwdDeclTypeName(
+ zcu,
+ writer,
+ fwd_decl,
+ fwd_decl.info(global_ctype_pool).fwd_decl,
+ if (aggregate_info.@"packed") "zig_packed(" else "",
+ );
+ try writer.writeByte(' ');
+ try renderFields(zcu, writer, global_ctype_pool, aggregate_info, 0);
+ if (aggregate_info.@"packed") try writer.writeByte(')');
+ try writer.writeAll(";\n");
+ },
+ },
}
}
@@ -2771,13 +2691,13 @@ fn genExports(o: *Object) !void {
}
}
-pub fn genLazyFn(o: *Object, lazy_fn: LazyFnMap.Entry) !void {
+pub fn genLazyFn(o: *Object, lazy_ctype_pool: *const CType.Pool, lazy_fn: LazyFnMap.Entry) !void {
const zcu = o.dg.zcu;
const ip = &zcu.intern_pool;
+ const ctype_pool = &o.dg.ctype_pool;
const w = o.writer();
const key = lazy_fn.key_ptr.*;
const val = lazy_fn.value_ptr;
- const fn_name = val.fn_name;
switch (key) {
.tag_name => {
const enum_ty = val.data.tag_name;
@@ -2787,7 +2707,7 @@ pub fn genLazyFn(o: *Object, lazy_fn: LazyFnMap.Entry) !void {
try w.writeAll("static ");
try o.dg.renderType(w, name_slice_ty);
try w.writeByte(' ');
- try w.writeAll(fn_name);
+ try w.writeAll(val.fn_name.slice(lazy_ctype_pool));
try w.writeByte('(');
try o.dg.renderTypeAndName(w, enum_ty, .{ .identifier = "tag" }, Const, .none, .complete);
try w.writeAll(") {\n switch (tag) {\n");
@@ -2829,8 +2749,9 @@ pub fn genLazyFn(o: *Object, lazy_fn: LazyFnMap.Entry) !void {
},
.never_tail, .never_inline => |fn_decl_index| {
const fn_decl = zcu.declPtr(fn_decl_index);
- const fn_cty = try o.dg.typeToCType(fn_decl.typeOf(zcu), .complete);
- const fn_info = fn_cty.cast(CType.Payload.Function).?.data;
+ const fn_ctype = try o.dg.ctypeFromType(fn_decl.typeOf(zcu), .complete);
+ const fn_info = fn_ctype.info(ctype_pool).function;
+ const fn_name = val.fn_name.slice(lazy_ctype_pool);
const fwd_decl_writer = o.dg.fwdDeclWriter();
try fwd_decl_writer.print("static zig_{s} ", .{@tagName(key)});
@@ -2843,11 +2764,13 @@ pub fn genLazyFn(o: *Object, lazy_fn: LazyFnMap.Entry) !void {
try fwd_decl_writer.writeAll(";\n");
try w.print("static zig_{s} ", .{@tagName(key)});
- try o.dg.renderFunctionSignature(w, fn_decl_index, .complete, .{ .ident = fn_name });
+ try o.dg.renderFunctionSignature(w, fn_decl_index, .complete, .{
+ .ident = fn_name,
+ });
try w.writeAll(" {\n return ");
try o.dg.renderDeclName(w, fn_decl_index, 0);
try w.writeByte('(');
- for (0..fn_info.param_types.len) |arg| {
+ for (0..fn_info.param_ctypes.len) |arg| {
if (arg > 0) try w.writeAll(", ");
try o.dg.writeCValue(w, .{ .arg = arg });
}
@@ -2931,7 +2854,7 @@ pub fn genFunc(f: *Function) !void {
for (free_locals.values()) |list| {
for (list.keys()) |local_index| {
const local = f.locals.items[local_index];
- try o.dg.renderCTypeAndName(w, local.cty_idx, .{ .local = local_index }, .{}, local.flags.alignas);
+ try o.dg.renderCTypeAndName(w, local.ctype, .{ .local = local_index }, .{}, local.flags.alignas);
try w.writeAll(";\n ");
}
}
@@ -3451,11 +3374,7 @@ fn airPtrElemPtr(f: *Function, inst: Air.Inst.Index) !CValue {
const inst_ty = f.typeOfIndex(inst);
const ptr_ty = f.typeOf(bin_op.lhs);
- const ptr_align = ptr_ty.ptrAlignment(zcu);
- const elem_ty = ptr_ty.elemType2(zcu);
- const elem_align = elem_ty.abiAlignment(zcu);
- const is_under_aligned = ptr_align.compareStrict(.lt, elem_align);
- const elem_has_bits = elem_ty.hasRuntimeBitsIgnoreComptime(zcu);
+ const elem_has_bits = ptr_ty.elemType2(zcu).hasRuntimeBitsIgnoreComptime(zcu);
const ptr = try f.resolveInst(bin_op.lhs);
const index = try f.resolveInst(bin_op.rhs);
@@ -3470,22 +3389,13 @@ fn airPtrElemPtr(f: *Function, inst: Air.Inst.Index) !CValue {
try f.renderType(writer, inst_ty);
try writer.writeByte(')');
if (elem_has_bits) try writer.writeByte('&');
- if (elem_has_bits and ptr_ty.ptrSize(zcu) == .One and !is_under_aligned) {
+ if (elem_has_bits and ptr_ty.ptrSize(zcu) == .One) {
// It's a pointer to an array, so we need to de-reference.
try f.writeCValueDeref(writer, ptr);
} else try f.writeCValue(writer, ptr, .Other);
if (elem_has_bits) {
try writer.writeByte('[');
try f.writeCValue(writer, index, .Other);
- if (is_under_aligned) {
- const factor = @divExact(elem_align.toByteUnitsOptional().?, @min(
- ptr_align.toByteUnitsOptional().?,
- f.object.dg.mod.resolved_target.result.maxIntAlignment(),
- ));
- try writer.print(" * {}", .{
- try f.fmtIntLiteral(try zcu.intValue(Type.usize, factor)),
- });
- }
try writer.writeByte(']');
}
try a.end(f, writer);
@@ -3577,13 +3487,16 @@ fn airArrayElemVal(f: *Function, inst: Air.Inst.Index) !CValue {
fn airAlloc(f: *Function, inst: Air.Inst.Index) !CValue {
const zcu = f.object.dg.zcu;
const inst_ty = f.typeOfIndex(inst);
- const elem_type = inst_ty.childType(zcu);
- if (!elem_type.isFnOrHasRuntimeBitsIgnoreComptime(zcu)) return .{ .undef = inst_ty };
+ const elem_ty = inst_ty.childType(zcu);
+ if (!elem_ty.isFnOrHasRuntimeBitsIgnoreComptime(zcu)) return .{ .undef = inst_ty };
- const local = try f.allocLocalValue(
- elem_type,
- inst_ty.ptrAlignment(zcu),
- );
+ const local = try f.allocLocalValue(.{
+ .ctype = try f.ctypeFromType(elem_ty, .complete),
+ .alignas = CType.AlignAs.fromAlignment(.{
+ .@"align" = inst_ty.ptrInfo(zcu).flags.alignment,
+ .abi = elem_ty.abiAlignment(zcu),
+ }),
+ });
log.debug("%{d}: allocated unfreeable t{d}", .{ inst, local.new_local });
const gpa = f.object.dg.zcu.gpa;
try f.allocs.put(gpa, local.new_local, true);
@@ -3596,10 +3509,13 @@ fn airRetPtr(f: *Function, inst: Air.Inst.Index) !CValue {
const elem_ty = inst_ty.childType(zcu);
if (!elem_ty.isFnOrHasRuntimeBitsIgnoreComptime(zcu)) return .{ .undef = inst_ty };
- const local = try f.allocLocalValue(
- elem_ty,
- inst_ty.ptrAlignment(zcu),
- );
+ const local = try f.allocLocalValue(.{
+ .ctype = try f.ctypeFromType(elem_ty, .complete),
+ .alignas = CType.AlignAs.fromAlignment(.{
+ .@"align" = inst_ty.ptrInfo(zcu).flags.alignment,
+ .abi = elem_ty.abiAlignment(zcu),
+ }),
+ });
log.debug("%{d}: allocated unfreeable t{d}", .{ inst, local.new_local });
const gpa = f.object.dg.zcu.gpa;
try f.allocs.put(gpa, local.new_local, true);
@@ -3608,14 +3524,14 @@ fn airRetPtr(f: *Function, inst: Air.Inst.Index) !CValue {
fn airArg(f: *Function, inst: Air.Inst.Index) !CValue {
const inst_ty = f.typeOfIndex(inst);
- const inst_cty = try f.typeToIndex(inst_ty, .parameter);
+ const inst_ctype = try f.ctypeFromType(inst_ty, .parameter);
const i = f.next_arg_index;
f.next_arg_index += 1;
- const result: CValue = if (inst_cty != try f.typeToIndex(inst_ty, .complete))
- .{ .arg_array = i }
+ const result: CValue = if (inst_ctype.eql(try f.ctypeFromType(inst_ty, .complete)))
+ .{ .arg = i }
else
- .{ .arg = i };
+ .{ .arg_array = i };
if (f.liveness.isUnused(inst)) {
const writer = f.object.writer();
@@ -3649,7 +3565,7 @@ fn airLoad(f: *Function, inst: Air.Inst.Index) !CValue {
try reap(f, inst, &.{ty_op.operand});
const is_aligned = if (ptr_info.flags.alignment != .none)
- ptr_info.flags.alignment.compare(.gte, src_ty.abiAlignment(zcu))
+ ptr_info.flags.alignment.order(src_ty.abiAlignment(zcu)).compare(.gte)
else
true;
const is_array = lowersToArray(src_ty, zcu);
@@ -3724,18 +3640,21 @@ fn airRet(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !CValue {
const op_inst = un_op.toIndex();
const op_ty = f.typeOf(un_op);
const ret_ty = if (is_ptr) op_ty.childType(zcu) else op_ty;
- const lowered_ret_ty = try lowerFnRetTy(ret_ty, zcu);
+ const ret_ctype = try f.ctypeFromType(ret_ty, .parameter);
if (op_inst != null and f.air.instructions.items(.tag)[@intFromEnum(op_inst.?)] == .call_always_tail) {
try reap(f, inst, &.{un_op});
_ = try airCall(f, op_inst.?, .always_tail);
- } else if (lowered_ret_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
+ } else if (ret_ctype.index != .void) {
const operand = try f.resolveInst(un_op);
try reap(f, inst, &.{un_op});
var deref = is_ptr;
const is_array = lowersToArray(ret_ty, zcu);
const ret_val = if (is_array) ret_val: {
- const array_local = try f.allocLocal(inst, lowered_ret_ty);
+ const array_local = try f.allocAlignedLocal(inst, .{
+ .ctype = ret_ctype,
+ .alignas = CType.AlignAs.fromAbiAlignment(ret_ty.abiAlignment(f.object.dg.zcu)),
+ });
try writer.writeAll("memcpy(");
try f.writeCValueMember(writer, array_local, .{ .identifier = "array" });
try writer.writeAll(", ");
@@ -3921,7 +3840,7 @@ fn airStore(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue {
}
const is_aligned = if (ptr_info.flags.alignment != .none)
- ptr_info.flags.alignment.compare(.gte, src_ty.abiAlignment(zcu))
+ ptr_info.flags.alignment.order(src_ty.abiAlignment(zcu)).compare(.gte)
else
true;
const is_array = lowersToArray(Type.fromInterned(ptr_info.child), zcu);
@@ -4397,22 +4316,23 @@ fn airCall(
defer gpa.free(resolved_args);
for (resolved_args, args) |*resolved_arg, arg| {
const arg_ty = f.typeOf(arg);
- const arg_cty = try f.typeToIndex(arg_ty, .parameter);
- if (f.indexToCType(arg_cty).tag() == .void) {
+ const arg_ctype = try f.ctypeFromType(arg_ty, .parameter);
+ if (arg_ctype.index == .void) {
resolved_arg.* = .none;
continue;
}
resolved_arg.* = try f.resolveInst(arg);
- if (arg_cty != try f.typeToIndex(arg_ty, .complete)) {
- const lowered_arg_ty = try lowerFnRetTy(arg_ty, zcu);
-
- const array_local = try f.allocLocal(inst, lowered_arg_ty);
+ if (!arg_ctype.eql(try f.ctypeFromType(arg_ty, .complete))) {
+ const array_local = try f.allocAlignedLocal(inst, .{
+ .ctype = arg_ctype,
+ .alignas = CType.AlignAs.fromAbiAlignment(arg_ty.abiAlignment(zcu)),
+ });
try writer.writeAll("memcpy(");
try f.writeCValueMember(writer, array_local, .{ .identifier = "array" });
try writer.writeAll(", ");
try f.writeCValue(writer, resolved_arg.*, .FunctionArgument);
try writer.writeAll(", sizeof(");
- try f.renderType(writer, lowered_arg_ty);
+ try f.renderCType(writer, arg_ctype);
try writer.writeAll("));\n");
resolved_arg.* = array_local;
}
@@ -4433,21 +4353,27 @@ fn airCall(
else => unreachable,
}).?;
const ret_ty = Type.fromInterned(fn_info.return_type);
- const lowered_ret_ty = try lowerFnRetTy(ret_ty, zcu);
+ const ret_ctype: CType = if (ret_ty.isNoReturn(zcu))
+ .{ .index = .void }
+ else
+ try f.ctypeFromType(ret_ty, .parameter);
const result_local = result: {
if (modifier == .always_tail) {
try writer.writeAll("zig_always_tail return ");
break :result .none;
- } else if (!lowered_ret_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
+ } else if (ret_ctype.index == .void) {
break :result .none;
} else if (f.liveness.isUnused(inst)) {
try writer.writeByte('(');
- try f.renderType(writer, Type.void);
+ try f.renderCType(writer, .{ .index = .void });
try writer.writeByte(')');
break :result .none;
} else {
- const local = try f.allocLocal(inst, lowered_ret_ty);
+ const local = try f.allocAlignedLocal(inst, .{
+ .ctype = ret_ctype,
+ .alignas = CType.AlignAs.fromAbiAlignment(ret_ty.abiAlignment(zcu)),
+ });
try f.writeCValue(writer, local, .Other);
try writer.writeAll(" = ");
break :result local;
@@ -4767,6 +4693,7 @@ const LocalResult = struct {
fn bitcast(f: *Function, dest_ty: Type, operand: CValue, operand_ty: Type) !LocalResult {
const zcu = f.object.dg.zcu;
const target = &f.object.dg.mod.resolved_target.result;
+ const ctype_pool = &f.object.dg.ctype_pool;
const writer = f.object.writer();
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
// Ensure padding bits have the expected value.
if (dest_ty.isAbiInt(zcu)) {
- const dest_cty = try f.typeToCType(dest_ty, .complete);
+ const dest_ctype = try f.ctypeFromType(dest_ty, .complete);
const dest_info = dest_ty.intInfo(zcu);
var bits: u16 = dest_info.bits;
- var wrap_cty: ?CType = null;
+ var wrap_ctype: ?CType = null;
var need_bitcasts = false;
try f.writeCValue(writer, local, .Other);
- if (dest_cty.castTag(.array)) |pl| {
- try writer.print("[{d}]", .{switch (target.cpu.arch.endian()) {
- .little => pl.data.len - 1,
- .big => 0,
- }});
- const elem_cty = f.indexToCType(pl.data.elem_type);
- wrap_cty = elem_cty.toSignedness(dest_info.signedness);
- need_bitcasts = wrap_cty.?.tag() == .zig_i128;
- bits -= 1;
- bits %= @as(u16, @intCast(f.byteSize(elem_cty) * 8));
- bits += 1;
+ switch (dest_ctype.info(ctype_pool)) {
+ else => {},
+ .array => |array_info| {
+ try writer.print("[{d}]", .{switch (target.cpu.arch.endian()) {
+ .little => array_info.len - 1,
+ .big => 0,
+ }});
+ wrap_ctype = array_info.elem_ctype.toSignedness(dest_info.signedness);
+ need_bitcasts = wrap_ctype.?.index == .zig_i128;
+ bits -= 1;
+ bits %= @as(u16, @intCast(f.byteSize(array_info.elem_ctype) * 8));
+ bits += 1;
+ },
}
try writer.writeAll(" = ");
if (need_bitcasts) {
try writer.writeAll("zig_bitCast_");
- try f.object.dg.renderCTypeForBuiltinFnName(writer, wrap_cty.?.toUnsigned());
+ try f.object.dg.renderCTypeForBuiltinFnName(writer, wrap_ctype.?.toUnsigned());
try writer.writeByte('(');
}
try writer.writeAll("zig_wrap_");
const info_ty = try zcu.intType(dest_info.signedness, bits);
- if (wrap_cty) |cty|
- try f.object.dg.renderCTypeForBuiltinFnName(writer, cty)
+ if (wrap_ctype) |ctype|
+ try f.object.dg.renderCTypeForBuiltinFnName(writer, ctype)
else
try f.object.dg.renderTypeForBuiltinFnName(writer, info_ty);
try writer.writeByte('(');
if (need_bitcasts) {
try writer.writeAll("zig_bitCast_");
- try f.object.dg.renderCTypeForBuiltinFnName(writer, wrap_cty.?);
+ try f.object.dg.renderCTypeForBuiltinFnName(writer, wrap_ctype.?);
try writer.writeByte('(');
}
try f.writeCValue(writer, local, .Other);
- if (dest_cty.castTag(.array)) |pl| {
- try writer.print("[{d}]", .{switch (target.cpu.arch.endian()) {
- .little => pl.data.len - 1,
- .big => 0,
- }});
+ switch (dest_ctype.info(ctype_pool)) {
+ else => {},
+ .array => |array_info| try writer.print("[{d}]", .{
+ switch (target.cpu.arch.endian()) {
+ .little => array_info.len - 1,
+ .big => 0,
+ },
+ }),
}
if (need_bitcasts) try writer.writeByte(')');
try f.object.dg.renderBuiltinInfo(writer, info_ty, .bits);
@@ -5131,10 +5063,9 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
if (is_reg) {
const output_ty = if (output == .none) inst_ty else f.typeOf(output).childType(zcu);
try writer.writeAll("register ");
- const alignment: Alignment = .none;
- const local_value = try f.allocLocalValue(output_ty, alignment);
+ const local_value = try f.allocLocal(inst, output_ty);
try f.allocs.put(gpa, local_value.new_local, false);
- try f.object.dg.renderTypeAndName(writer, output_ty, local_value, .{}, alignment, .complete);
+ try f.object.dg.renderTypeAndName(writer, output_ty, local_value, .{}, .none, .complete);
try writer.writeAll(" __asm(\"");
try writer.writeAll(constraint["={".len .. constraint.len - "}".len]);
try writer.writeAll("\")");
@@ -5164,10 +5095,9 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
if (asmInputNeedsLocal(f, constraint, input_val)) {
const input_ty = f.typeOf(input);
if (is_reg) try writer.writeAll("register ");
- const alignment: Alignment = .none;
- const local_value = try f.allocLocalValue(input_ty, alignment);
+ const local_value = try f.allocLocal(inst, input_ty);
try f.allocs.put(gpa, local_value.new_local, false);
- try f.object.dg.renderTypeAndName(writer, input_ty, local_value, Const, alignment, .complete);
+ try f.object.dg.renderTypeAndName(writer, input_ty, local_value, Const, .none, .complete);
if (is_reg) {
try writer.writeAll(" __asm(\"");
try writer.writeAll(constraint["{".len .. constraint.len - "}".len]);
@@ -5512,59 +5442,74 @@ fn fieldLocation(
end: void,
} {
const ip = &zcu.intern_pool;
- const container_ty = container_ptr_ty.childType(zcu);
- return switch (container_ty.zigTypeTag(zcu)) {
- .Struct => blk: {
- if (zcu.typeToPackedStruct(container_ty)) |struct_type| {
- if (field_ptr_ty.ptrInfo(zcu).packed_offset.host_size == 0)
- break :blk .{ .byte_offset = @divExact(zcu.structPackedFieldBitOffset(struct_type, field_index) + container_ptr_ty.ptrInfo(zcu).packed_offset.bit_offset, 8) }
+ const container_ty = Type.fromInterned(ip.indexToKey(container_ptr_ty.toIntern()).ptr_type.child);
+ switch (ip.indexToKey(container_ty.toIntern())) {
+ .struct_type => {
+ const loaded_struct = ip.loadStructType(container_ty.toIntern());
+ switch (loaded_struct.layout) {
+ .auto, .@"extern" => {
+ var field_it = loaded_struct.iterateRuntimeOrder(ip);
+ var before = true;
+ while (field_it.next()) |next_field_index| {
+ if (next_field_index == field_index) before = false;
+ if (before) continue;
+ const field_type = Type.fromInterned(loaded_struct.field_types.get(ip)[next_field_index]);
+ if (!field_type.hasRuntimeBitsIgnoreComptime(zcu)) continue;
+ return .{ .field = if (loaded_struct.fieldName(ip, next_field_index).unwrap()) |field_name|
+ .{ .identifier = ip.stringToSlice(field_name) }
+ else
+ .{ .field = next_field_index } };
+ }
+ return if (container_ty.hasRuntimeBitsIgnoreComptime(zcu)) .end else .begin;
+ },
+ .@"packed" => return if (field_ptr_ty.ptrInfo(zcu).packed_offset.host_size == 0)
+ .{ .byte_offset = @divExact(zcu.structPackedFieldBitOffset(loaded_struct, field_index) +
+ container_ptr_ty.ptrInfo(zcu).packed_offset.bit_offset, 8) }
else
- break :blk .begin;
+ .begin,
}
-
- for (field_index..container_ty.structFieldCount(zcu)) |next_field_index_usize| {
- const next_field_index: u32 = @intCast(next_field_index_usize);
- if (container_ty.structFieldIsComptime(next_field_index, zcu)) continue;
- const field_ty = container_ty.structFieldType(next_field_index, zcu);
- if (!field_ty.hasRuntimeBitsIgnoreComptime(zcu)) continue;
-
- break :blk .{ .field = if (container_ty.isSimpleTuple(zcu))
- .{ .field = next_field_index }
+ },
+ .anon_struct_type => |anon_struct_info| {
+ for (field_index..anon_struct_info.types.len) |next_field_index| {
+ if (anon_struct_info.values.get(ip)[next_field_index] != .none) continue;
+ const field_type = Type.fromInterned(anon_struct_info.types.get(ip)[next_field_index]);
+ if (!field_type.hasRuntimeBitsIgnoreComptime(zcu)) continue;
+ return .{ .field = if (anon_struct_info.fieldName(ip, next_field_index).unwrap()) |field_name|
+ .{ .identifier = ip.stringToSlice(field_name) }
else
- .{ .identifier = ip.stringToSlice(container_ty.legacyStructFieldName(next_field_index, zcu)) } };
+ .{ .field = next_field_index } };
}
- break :blk if (container_ty.hasRuntimeBitsIgnoreComptime(zcu)) .end else .begin;
+ return if (container_ty.hasRuntimeBitsIgnoreComptime(zcu)) .end else .begin;
},
- .Union => {
- const union_obj = zcu.typeToUnion(container_ty).?;
- return switch (union_obj.getLayout(ip)) {
+ .union_type => {
+ const loaded_union = ip.loadUnionType(container_ty.toIntern());
+ switch (loaded_union.getLayout(ip)) {
.auto, .@"extern" => {
- const field_ty = Type.fromInterned(union_obj.field_types.get(ip)[field_index]);
+ const field_ty = Type.fromInterned(loaded_union.field_types.get(ip)[field_index]);
if (!field_ty.hasRuntimeBitsIgnoreComptime(zcu))
- return if (container_ty.unionTagTypeSafety(zcu) != null and
- !container_ty.unionHasAllZeroBitFieldTypes(zcu))
+ return if (loaded_union.hasTag(ip) and !container_ty.unionHasAllZeroBitFieldTypes(zcu))
.{ .field = .{ .identifier = "payload" } }
else
.begin;
- const field_name = union_obj.loadTagType(ip).names.get(ip)[field_index];
- return .{ .field = if (container_ty.unionTagTypeSafety(zcu)) |_|
+ const field_name = loaded_union.loadTagType(ip).names.get(ip)[field_index];
+ return .{ .field = if (loaded_union.hasTag(ip))
.{ .payload_identifier = ip.stringToSlice(field_name) }
else
.{ .identifier = ip.stringToSlice(field_name) } };
},
- .@"packed" => .begin,
- };
+ .@"packed" => return .begin,
+ }
},
- .Pointer => switch (container_ty.ptrSize(zcu)) {
+ .ptr_type => |ptr_info| switch (ptr_info.flags.size) {
+ .One, .Many, .C => unreachable,
.Slice => switch (field_index) {
- 0 => .{ .field = .{ .identifier = "ptr" } },
- 1 => .{ .field = .{ .identifier = "len" } },
+ 0 => return .{ .field = .{ .identifier = "ptr" } },
+ 1 => return .{ .field = .{ .identifier = "len" } },
else => unreachable,
},
- .One, .Many, .C => unreachable,
},
else => unreachable,
- };
+ }
}
fn airStructFieldPtr(f: *Function, inst: Air.Inst.Index) !CValue {
@@ -5653,7 +5598,7 @@ fn fieldPtr(
const field_ptr_ty = f.typeOfIndex(inst);
// Ensure complete type definition is visible before accessing fields.
- _ = try f.typeToIndex(container_ty, .complete);
+ _ = try f.ctypeFromType(container_ty, .complete);
const writer = f.object.writer();
const local = try f.allocLocal(inst, field_ptr_ty);
@@ -5708,109 +5653,109 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {
const writer = f.object.writer();
// Ensure complete type definition is visible before accessing fields.
- _ = try f.typeToIndex(struct_ty, .complete);
+ _ = try f.ctypeFromType(struct_ty, .complete);
+
+ const field_name: CValue = switch (ip.indexToKey(struct_ty.toIntern())) {
+ .struct_type => field_name: {
+ const loaded_struct = ip.loadStructType(struct_ty.toIntern());
+ switch (loaded_struct.layout) {
+ .auto, .@"extern" => break :field_name if (loaded_struct.fieldName(ip, extra.field_index).unwrap()) |field_name|
+ .{ .identifier = ip.stringToSlice(field_name) }
+ else
+ .{ .field = extra.field_index },
+ .@"packed" => {
+ const int_info = struct_ty.intInfo(zcu);
- const field_name: CValue = switch (zcu.intern_pool.indexToKey(struct_ty.toIntern())) {
- .struct_type => switch (struct_ty.containerLayout(zcu)) {
- .auto, .@"extern" => if (struct_ty.isSimpleTuple(zcu))
- .{ .field = extra.field_index }
- else
- .{ .identifier = ip.stringToSlice(struct_ty.legacyStructFieldName(extra.field_index, zcu)) },
- .@"packed" => {
- const struct_type = zcu.typeToStruct(struct_ty).?;
- const int_info = struct_ty.intInfo(zcu);
+ const bit_offset_ty = try zcu.intType(.unsigned, Type.smallestUnsignedBits(int_info.bits - 1));
- const bit_offset_ty = try zcu.intType(.unsigned, Type.smallestUnsignedBits(int_info.bits - 1));
+ const bit_offset = zcu.structPackedFieldBitOffset(loaded_struct, extra.field_index);
- const bit_offset = zcu.structPackedFieldBitOffset(struct_type, extra.field_index);
+ const field_int_signedness = if (inst_ty.isAbiInt(zcu))
+ inst_ty.intInfo(zcu).signedness
+ else
+ .unsigned;
+ const field_int_ty = try zcu.intType(field_int_signedness, @as(u16, @intCast(inst_ty.bitSize(zcu))));
- const field_int_signedness = if (inst_ty.isAbiInt(zcu))
- inst_ty.intInfo(zcu).signedness
- else
- .unsigned;
- const field_int_ty = try zcu.intType(field_int_signedness, @as(u16, @intCast(inst_ty.bitSize(zcu))));
-
- const temp_local = try f.allocLocal(inst, field_int_ty);
- try f.writeCValue(writer, temp_local, .Other);
- try writer.writeAll(" = zig_wrap_");
- try f.object.dg.renderTypeForBuiltinFnName(writer, field_int_ty);
- try writer.writeAll("((");
- try f.renderType(writer, field_int_ty);
- try writer.writeByte(')');
- const cant_cast = int_info.bits > 64;
- if (cant_cast) {
- if (field_int_ty.bitSize(zcu) > 64) return f.fail("TODO: C backend: implement casting between types > 64 bits", .{});
- try writer.writeAll("zig_lo_");
- try f.object.dg.renderTypeForBuiltinFnName(writer, struct_ty);
- try writer.writeByte('(');
- }
- if (bit_offset > 0) {
- try writer.writeAll("zig_shr_");
- try f.object.dg.renderTypeForBuiltinFnName(writer, struct_ty);
- try writer.writeByte('(');
- }
- try f.writeCValue(writer, struct_byval, .Other);
- if (bit_offset > 0) {
- try writer.writeAll(", ");
- try f.object.dg.renderValue(writer, try zcu.intValue(bit_offset_ty, bit_offset), .FunctionArgument);
+ const temp_local = try f.allocLocal(inst, field_int_ty);
+ try f.writeCValue(writer, temp_local, .Other);
+ try writer.writeAll(" = zig_wrap_");
+ try f.object.dg.renderTypeForBuiltinFnName(writer, field_int_ty);
+ try writer.writeAll("((");
+ try f.renderType(writer, field_int_ty);
try writer.writeByte(')');
- }
- if (cant_cast) try writer.writeByte(')');
- try f.object.dg.renderBuiltinInfo(writer, field_int_ty, .bits);
- try writer.writeAll(");\n");
- if (inst_ty.eql(field_int_ty, f.object.dg.zcu)) return temp_local;
+ const cant_cast = int_info.bits > 64;
+ if (cant_cast) {
+ if (field_int_ty.bitSize(zcu) > 64) return f.fail("TODO: C backend: implement casting between types > 64 bits", .{});
+ try writer.writeAll("zig_lo_");
+ try f.object.dg.renderTypeForBuiltinFnName(writer, struct_ty);
+ try writer.writeByte('(');
+ }
+ if (bit_offset > 0) {
+ try writer.writeAll("zig_shr_");
+ try f.object.dg.renderTypeForBuiltinFnName(writer, struct_ty);
+ try writer.writeByte('(');
+ }
+ try f.writeCValue(writer, struct_byval, .Other);
+ if (bit_offset > 0) try writer.print(", {})", .{
+ try f.fmtIntLiteral(try zcu.intValue(bit_offset_ty, bit_offset)),
+ });
+ if (cant_cast) try writer.writeByte(')');
+ try f.object.dg.renderBuiltinInfo(writer, field_int_ty, .bits);
+ try writer.writeAll(");\n");
+ if (inst_ty.eql(field_int_ty, f.object.dg.zcu)) return temp_local;
- const local = try f.allocLocal(inst, inst_ty);
- try writer.writeAll("memcpy(");
- try f.writeCValue(writer, .{ .local_ref = local.new_local }, .FunctionArgument);
- try writer.writeAll(", ");
- try f.writeCValue(writer, .{ .local_ref = temp_local.new_local }, .FunctionArgument);
- try writer.writeAll(", sizeof(");
- try f.renderType(writer, inst_ty);
- try writer.writeAll("));\n");
- try freeLocal(f, inst, temp_local.new_local, null);
- return local;
- },
+ const local = try f.allocLocal(inst, inst_ty);
+ try writer.writeAll("memcpy(");
+ try f.writeCValue(writer, .{ .local_ref = local.new_local }, .FunctionArgument);
+ try writer.writeAll(", ");
+ try f.writeCValue(writer, .{ .local_ref = temp_local.new_local }, .FunctionArgument);
+ try writer.writeAll(", sizeof(");
+ try f.renderType(writer, inst_ty);
+ try writer.writeAll("));\n");
+ try freeLocal(f, inst, temp_local.new_local, null);
+ return local;
+ },
+ }
},
-
- .anon_struct_type => |anon_struct_type| if (anon_struct_type.names.len == 0)
- .{ .field = extra.field_index }
+ .anon_struct_type => |anon_struct_info| if (anon_struct_info.fieldName(ip, extra.field_index).unwrap()) |field_name|
+ .{ .identifier = ip.stringToSlice(field_name) }
else
- .{ .identifier = ip.stringToSlice(struct_ty.legacyStructFieldName(extra.field_index, zcu)) },
-
+ .{ .field = extra.field_index },
.union_type => field_name: {
- const union_obj = ip.loadUnionType(struct_ty.toIntern());
- if (union_obj.flagsPtr(ip).layout == .@"packed") {
- const operand_lval = if (struct_byval == .constant) blk: {
- const operand_local = try f.allocLocal(inst, struct_ty);
- try f.writeCValue(writer, operand_local, .Other);
- try writer.writeAll(" = ");
- try f.writeCValue(writer, struct_byval, .Initializer);
- try writer.writeAll(";\n");
- break :blk operand_local;
- } else struct_byval;
-
- const local = try f.allocLocal(inst, inst_ty);
- try writer.writeAll("memcpy(&");
- try f.writeCValue(writer, local, .Other);
- try writer.writeAll(", &");
- try f.writeCValue(writer, operand_lval, .Other);
- try writer.writeAll(", sizeof(");
- try f.renderType(writer, inst_ty);
- try writer.writeAll("));\n");
-
- if (struct_byval == .constant) {
- try freeLocal(f, inst, operand_lval.new_local, null);
- }
+ const loaded_union = ip.loadUnionType(struct_ty.toIntern());
+ switch (loaded_union.getLayout(ip)) {
+ .auto, .@"extern" => {
+ const name = loaded_union.loadTagType(ip).names.get(ip)[extra.field_index];
+ break :field_name if (loaded_union.hasTag(ip))
+ .{ .payload_identifier = ip.stringToSlice(name) }
+ else
+ .{ .identifier = ip.stringToSlice(name) };
+ },
+ .@"packed" => {
+ const operand_lval = if (struct_byval == .constant) blk: {
+ const operand_local = try f.allocLocal(inst, struct_ty);
+ try f.writeCValue(writer, operand_local, .Other);
+ try writer.writeAll(" = ");
+ try f.writeCValue(writer, struct_byval, .Initializer);
+ try writer.writeAll(";\n");
+ break :blk operand_local;
+ } else struct_byval;
+
+ const local = try f.allocLocal(inst, inst_ty);
+ try writer.writeAll("memcpy(&");
+ try f.writeCValue(writer, local, .Other);
+ try writer.writeAll(", &");
+ try f.writeCValue(writer, operand_lval, .Other);
+ try writer.writeAll(", sizeof(");
+ try f.renderType(writer, inst_ty);
+ try writer.writeAll("));\n");
+
+ if (struct_byval == .constant) {
+ try freeLocal(f, inst, operand_lval.new_local, null);
+ }
- return local;
- } else {
- const name = union_obj.loadTagType(ip).names.get(ip)[extra.field_index];
- break :field_name if (union_obj.hasTag(ip)) .{
- .payload_identifier = ip.stringToSlice(name),
- } else .{
- .identifier = ip.stringToSlice(name),
- };
+ return local;
+ },
}
},
else => unreachable,
@@ -6089,6 +6034,7 @@ fn airIsErr(f: *Function, inst: Air.Inst.Index, is_ptr: bool, operator: []const
fn airArrayToSlice(f: *Function, inst: Air.Inst.Index) !CValue {
const zcu = f.object.dg.zcu;
+ const ctype_pool = &f.object.dg.ctype_pool;
const ty_op = f.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
const operand = try f.resolveInst(ty_op.operand);
@@ -6107,18 +6053,18 @@ fn airArrayToSlice(f: *Function, inst: Air.Inst.Index) !CValue {
if (operand == .undef) {
try f.writeCValue(writer, .{ .undef = inst_ty.slicePtrFieldType(zcu) }, .Initializer);
} else {
- const ptr_cty = try f.typeToIndex(ptr_ty, .complete);
- const ptr_child_cty = f.indexToCType(ptr_cty).cast(CType.Payload.Child).?.data;
+ const ptr_ctype = try f.ctypeFromType(ptr_ty, .complete);
+ const ptr_child_ctype = ptr_ctype.info(ctype_pool).pointer.elem_ctype;
const elem_ty = array_ty.childType(zcu);
- const elem_cty = try f.typeToIndex(elem_ty, .complete);
- if (ptr_child_cty != elem_cty) {
+ const elem_ctype = try f.ctypeFromType(elem_ty, .complete);
+ if (!ptr_child_ctype.eql(elem_ctype)) {
try writer.writeByte('(');
- try f.renderCType(writer, ptr_cty);
+ try f.renderCType(writer, ptr_ctype);
try writer.writeByte(')');
}
- const operand_cty = try f.typeToCType(operand_ty, .complete);
- const operand_child_cty = operand_cty.cast(CType.Payload.Child).?.data;
- if (f.indexToCType(operand_child_cty).tag() == .array) {
+ const operand_ctype = try f.ctypeFromType(operand_ty, .complete);
+ const operand_child_ctype = operand_ctype.info(ctype_pool).pointer.elem_ctype;
+ if (operand_child_ctype.info(ctype_pool) == .array) {
try writer.writeByte('&');
try f.writeCValueDeref(writer, operand);
try writer.print("[{}]", .{try f.fmtIntLiteral(try zcu.intValue(Type.usize, 0))});
@@ -6229,8 +6175,8 @@ fn airUnBuiltinCall(
const operand_ty = f.typeOf(ty_op.operand);
const scalar_ty = operand_ty.scalarType(zcu);
- const inst_scalar_cty = try f.typeToCType(inst_scalar_ty, .complete);
- const ref_ret = inst_scalar_cty.tag() == .array;
+ const inst_scalar_ctype = try f.ctypeFromType(inst_scalar_ty, .complete);
+ const ref_ret = inst_scalar_ctype.info(&f.object.dg.ctype_pool) == .array;
const writer = f.object.writer();
const local = try f.allocLocal(inst, inst_ty);
@@ -6267,8 +6213,8 @@ fn airBinBuiltinCall(
const bin_op = f.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
const operand_ty = f.typeOf(bin_op.lhs);
- const operand_cty = try f.typeToCType(operand_ty, .complete);
- const is_big = operand_cty.tag() == .array;
+ const operand_ctype = try f.ctypeFromType(operand_ty, .complete);
+ const is_big = operand_ctype.info(&f.object.dg.ctype_pool) == .array;
const lhs = try f.resolveInst(bin_op.lhs);
const rhs = try f.resolveInst(bin_op.rhs);
@@ -6278,8 +6224,8 @@ fn airBinBuiltinCall(
const inst_scalar_ty = inst_ty.scalarType(zcu);
const scalar_ty = operand_ty.scalarType(zcu);
- const inst_scalar_cty = try f.typeToCType(inst_scalar_ty, .complete);
- const ref_ret = inst_scalar_cty.tag() == .array;
+ const inst_scalar_ctype = try f.ctypeFromType(inst_scalar_ty, .complete);
+ const ref_ret = inst_scalar_ctype.info(&f.object.dg.ctype_pool) == .array;
const writer = f.object.writer();
const local = try f.allocLocal(inst, inst_ty);
@@ -6328,8 +6274,8 @@ fn airCmpBuiltinCall(
const operand_ty = f.typeOf(data.lhs);
const scalar_ty = operand_ty.scalarType(zcu);
- const inst_scalar_cty = try f.typeToCType(inst_scalar_ty, .complete);
- const ref_ret = inst_scalar_cty.tag() == .array;
+ const inst_scalar_ctype = try f.ctypeFromType(inst_scalar_ty, .complete);
+ const ref_ret = inst_scalar_ctype.info(&f.object.dg.ctype_pool) == .array;
const writer = f.object.writer();
const local = try f.allocLocal(inst, inst_ty);
@@ -7112,9 +7058,9 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {
const writer = f.object.writer();
const local = try f.allocLocal(inst, inst_ty);
- switch (inst_ty.zigTypeTag(zcu)) {
- .Array, .Vector => {
- const a = try Assignment.init(f, inst_ty.childType(zcu));
+ switch (ip.indexToKey(inst_ty.toIntern())) {
+ inline .array_type, .vector_type => |info, tag| {
+ const a = try Assignment.init(f, Type.fromInterned(info.child));
for (resolved_elements, 0..) |element, i| {
try a.restart(f, writer);
try f.writeCValue(writer, local, .Other);
@@ -7123,94 +7069,112 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {
try f.writeCValue(writer, element, .Other);
try a.end(f, writer);
}
- if (inst_ty.sentinel(zcu)) |sentinel| {
+ if (tag == .array_type and info.sentinel != .none) {
try a.restart(f, writer);
try f.writeCValue(writer, local, .Other);
- try writer.print("[{d}]", .{resolved_elements.len});
+ try writer.print("[{d}]", .{info.len});
try a.assign(f, writer);
- try f.object.dg.renderValue(writer, sentinel, .Other);
+ try f.object.dg.renderValue(writer, Value.fromInterned(info.sentinel), .Other);
try a.end(f, writer);
}
},
- .Struct => switch (inst_ty.containerLayout(zcu)) {
- .auto, .@"extern" => for (resolved_elements, 0..) |element, field_index| {
- if (inst_ty.structFieldIsComptime(field_index, zcu)) continue;
- const field_ty = inst_ty.structFieldType(field_index, zcu);
- if (!field_ty.hasRuntimeBitsIgnoreComptime(zcu)) continue;
-
- const a = try Assignment.start(f, writer, field_ty);
- try f.writeCValueMember(writer, local, if (inst_ty.isSimpleTuple(zcu))
- .{ .field = field_index }
- else
- .{ .identifier = ip.stringToSlice(inst_ty.legacyStructFieldName(@intCast(field_index), zcu)) });
- try a.assign(f, writer);
- try f.writeCValue(writer, element, .Other);
- try a.end(f, writer);
- },
- .@"packed" => {
- try f.writeCValue(writer, local, .Other);
- try writer.writeAll(" = ");
- const int_info = inst_ty.intInfo(zcu);
+ .struct_type => {
+ const loaded_struct = ip.loadStructType(inst_ty.toIntern());
+ switch (loaded_struct.layout) {
+ .auto, .@"extern" => {
+ var field_it = loaded_struct.iterateRuntimeOrder(ip);
+ while (field_it.next()) |field_index| {
+ const field_ty = Type.fromInterned(loaded_struct.field_types.get(ip)[field_index]);
+ if (!field_ty.hasRuntimeBitsIgnoreComptime(zcu)) continue;
- const bit_offset_ty = try zcu.intType(.unsigned, Type.smallestUnsignedBits(int_info.bits - 1));
+ const a = try Assignment.start(f, writer, field_ty);
+ try f.writeCValueMember(writer, local, if (loaded_struct.fieldName(ip, field_index).unwrap()) |field_name|
+ .{ .identifier = ip.stringToSlice(field_name) }
+ else
+ .{ .field = field_index });
+ try a.assign(f, writer);
+ try f.writeCValue(writer, resolved_elements[field_index], .Other);
+ try a.end(f, writer);
+ }
+ },
+ .@"packed" => {
+ try f.writeCValue(writer, local, .Other);
+ try writer.writeAll(" = ");
+ const int_info = inst_ty.intInfo(zcu);
- var bit_offset: u64 = 0;
+ const bit_offset_ty = try zcu.intType(.unsigned, Type.smallestUnsignedBits(int_info.bits - 1));
- var empty = true;
- for (0..elements.len) |field_index| {
- if (inst_ty.structFieldIsComptime(field_index, zcu)) continue;
- const field_ty = inst_ty.structFieldType(field_index, zcu);
- if (!field_ty.hasRuntimeBitsIgnoreComptime(zcu)) continue;
+ var bit_offset: u64 = 0;
- if (!empty) {
- try writer.writeAll("zig_or_");
- try f.object.dg.renderTypeForBuiltinFnName(writer, inst_ty);
- try writer.writeByte('(');
+ var empty = true;
+ for (0..elements.len) |field_index| {
+ if (inst_ty.structFieldIsComptime(field_index, zcu)) continue;
+ const field_ty = inst_ty.structFieldType(field_index, zcu);
+ if (!field_ty.hasRuntimeBitsIgnoreComptime(zcu)) continue;
+
+ if (!empty) {
+ try writer.writeAll("zig_or_");
+ try f.object.dg.renderTypeForBuiltinFnName(writer, inst_ty);
+ try writer.writeByte('(');
+ }
+ empty = false;
}
- empty = false;
- }
- empty = true;
- for (resolved_elements, 0..) |element, field_index| {
- if (inst_ty.structFieldIsComptime(field_index, zcu)) continue;
- const field_ty = inst_ty.structFieldType(field_index, zcu);
- if (!field_ty.hasRuntimeBitsIgnoreComptime(zcu)) continue;
-
- if (!empty) try writer.writeAll(", ");
- // TODO: Skip this entire shift if val is 0?
- try writer.writeAll("zig_shlw_");
- try f.object.dg.renderTypeForBuiltinFnName(writer, inst_ty);
- try writer.writeByte('(');
+ empty = true;
+ for (resolved_elements, 0..) |element, field_index| {
+ if (inst_ty.structFieldIsComptime(field_index, zcu)) continue;
+ const field_ty = inst_ty.structFieldType(field_index, zcu);
+ if (!field_ty.hasRuntimeBitsIgnoreComptime(zcu)) continue;
- if (inst_ty.isAbiInt(zcu) and (field_ty.isAbiInt(zcu) or field_ty.isPtrAtRuntime(zcu))) {
- try f.renderIntCast(writer, inst_ty, element, .{}, field_ty, .FunctionArgument);
- } else {
+ if (!empty) try writer.writeAll(", ");
+ // TODO: Skip this entire shift if val is 0?
+ try writer.writeAll("zig_shlw_");
+ try f.object.dg.renderTypeForBuiltinFnName(writer, inst_ty);
try writer.writeByte('(');
- try f.renderType(writer, inst_ty);
- try writer.writeByte(')');
- if (field_ty.isPtrAtRuntime(zcu)) {
+
+ if (inst_ty.isAbiInt(zcu) and (field_ty.isAbiInt(zcu) or field_ty.isPtrAtRuntime(zcu))) {
+ try f.renderIntCast(writer, inst_ty, element, .{}, field_ty, .FunctionArgument);
+ } else {
try writer.writeByte('(');
- try f.renderType(writer, switch (int_info.signedness) {
- .unsigned => Type.usize,
- .signed => Type.isize,
- });
+ try f.renderType(writer, inst_ty);
try writer.writeByte(')');
+ if (field_ty.isPtrAtRuntime(zcu)) {
+ try writer.writeByte('(');
+ try f.renderType(writer, switch (int_info.signedness) {
+ .unsigned => Type.usize,
+ .signed => Type.isize,
+ });
+ try writer.writeByte(')');
+ }
+ try f.writeCValue(writer, element, .Other);
}
- try f.writeCValue(writer, element, .Other);
- }
-
- try writer.print(", {}", .{
- try f.fmtIntLiteral(try zcu.intValue(bit_offset_ty, bit_offset)),
- });
- try f.object.dg.renderBuiltinInfo(writer, inst_ty, .bits);
- try writer.writeByte(')');
- if (!empty) try writer.writeByte(')');
- bit_offset += field_ty.bitSize(zcu);
- empty = false;
- }
+ try writer.print(", {}", .{
+ try f.fmtIntLiteral(try zcu.intValue(bit_offset_ty, bit_offset)),
+ });
+ try f.object.dg.renderBuiltinInfo(writer, inst_ty, .bits);
+ try writer.writeByte(')');
+ if (!empty) try writer.writeByte(')');
- try writer.writeAll(";\n");
- },
+ bit_offset += field_ty.bitSize(zcu);
+ empty = false;
+ }
+ try writer.writeAll(";\n");
+ },
+ }
+ },
+ .anon_struct_type => |anon_struct_info| for (0..anon_struct_info.types.len) |field_index| {
+ if (anon_struct_info.values.get(ip)[field_index] != .none) continue;
+ const field_ty = Type.fromInterned(anon_struct_info.types.get(ip)[field_index]);
+ if (!field_ty.hasRuntimeBitsIgnoreComptime(zcu)) continue;
+
+ const a = try Assignment.start(f, writer, field_ty);
+ try f.writeCValueMember(writer, local, if (anon_struct_info.fieldName(ip, field_index).unwrap()) |field_name|
+ .{ .identifier = ip.stringToSlice(field_name) }
+ else
+ .{ .field = field_index });
+ try a.assign(f, writer);
+ try f.writeCValue(writer, resolved_elements[field_index], .Other);
+ try a.end(f, writer);
},
else => unreachable,
}
@@ -7225,15 +7189,15 @@ fn airUnionInit(f: *Function, inst: Air.Inst.Index) !CValue {
const extra = f.air.extraData(Air.UnionInit, ty_pl.payload).data;
const union_ty = f.typeOfIndex(inst);
- const union_obj = zcu.typeToUnion(union_ty).?;
- const field_name = union_obj.loadTagType(ip).names.get(ip)[extra.field_index];
+ const loaded_union = ip.loadUnionType(union_ty.toIntern());
+ const field_name = loaded_union.loadTagType(ip).names.get(ip)[extra.field_index];
const payload_ty = f.typeOf(extra.init);
const payload = try f.resolveInst(extra.init);
try reap(f, inst, &.{extra.init});
const writer = f.object.writer();
const local = try f.allocLocal(inst, union_ty);
- if (union_obj.getLayout(ip) == .@"packed") {
+ if (loaded_union.getLayout(ip) == .@"packed") {
try f.writeCValue(writer, local, .Other);
try writer.writeAll(" = ");
try f.writeCValue(writer, payload, .Initializer);
@@ -7465,16 +7429,16 @@ fn airCVaStart(f: *Function, inst: Air.Inst.Index) !CValue {
const inst_ty = f.typeOfIndex(inst);
const decl_index = f.object.dg.pass.decl;
const decl = zcu.declPtr(decl_index);
- const fn_cty = try f.typeToCType(decl.typeOf(zcu), .complete);
- const param_len = fn_cty.castTag(.varargs_function).?.data.param_types.len;
+ const function_ctype = try f.ctypeFromType(decl.typeOf(zcu), .complete);
+ const params_len = function_ctype.info(&f.object.dg.ctype_pool).function.param_ctypes.len;
const writer = f.object.writer();
const local = try f.allocLocal(inst, inst_ty);
try writer.writeAll("va_start(*(va_list *)&");
try f.writeCValue(writer, local, .Other);
- if (param_len > 0) {
+ if (params_len > 0) {
try writer.writeAll(", ");
- try f.writeCValue(writer, .{ .arg = param_len - 1 }, .FunctionArgument);
+ try f.writeCValue(writer, .{ .arg = params_len - 1 }, .FunctionArgument);
}
try writer.writeAll(");\n");
return local;
@@ -7823,7 +7787,7 @@ const FormatIntLiteralContext = struct {
dg: *DeclGen,
int_info: InternPool.Key.IntType,
kind: CType.Kind,
- cty: CType,
+ ctype: CType,
val: Value,
};
fn formatIntLiteral(
@@ -7834,6 +7798,7 @@ fn formatIntLiteral(
) @TypeOf(writer).Error!void {
const zcu = data.dg.zcu;
const target = &data.dg.mod.resolved_target.result;
+ const ctype_pool = &data.dg.ctype_pool;
const ExpectedContents = struct {
const base = 10;
@@ -7867,7 +7832,7 @@ fn formatIntLiteral(
} else data.val.toBigInt(&int_buf, zcu);
assert(int.fitsInTwosComp(data.int_info.signedness, data.int_info.bits));
- const c_bits: usize = @intCast(data.cty.byteSize(data.dg.ctypes.set, data.dg.mod) * 8);
+ const c_bits: usize = @intCast(data.ctype.byteSize(ctype_pool, data.dg.mod) * 8);
var one_limbs: [BigInt.calcLimbLen(1)]BigIntLimb = undefined;
const one = BigInt.Mutable.init(&one_limbs, 1).toConst();
@@ -7879,45 +7844,45 @@ fn formatIntLiteral(
defer allocator.free(wrap.limbs);
const c_limb_info: struct {
- cty: CType,
+ ctype: CType,
count: usize,
endian: std.builtin.Endian,
homogeneous: bool,
- } = switch (data.cty.tag()) {
- else => .{
- .cty = CType.initTag(.void),
- .count = 1,
- .endian = .little,
- .homogeneous = true,
- },
- .zig_u128, .zig_i128 => .{
- .cty = CType.initTag(.uint64_t),
- .count = 2,
- .endian = .big,
- .homogeneous = false,
- },
- .array => info: {
- const array_data = data.cty.castTag(.array).?.data;
- break :info .{
- .cty = data.dg.indexToCType(array_data.elem_type),
- .count = @as(usize, @intCast(array_data.len)),
- .endian = target.cpu.arch.endian(),
+ } = switch (data.ctype.info(ctype_pool)) {
+ .basic => |basic_info| switch (basic_info) {
+ else => .{
+ .ctype = .{ .index = .void },
+ .count = 1,
+ .endian = .little,
.homogeneous = true,
- };
+ },
+ .zig_u128, .zig_i128 => .{
+ .ctype = .{ .index = .uint64_t },
+ .count = 2,
+ .endian = .big,
+ .homogeneous = false,
+ },
+ },
+ .array => |array_info| .{
+ .ctype = array_info.elem_ctype,
+ .count = @intCast(array_info.len),
+ .endian = target.cpu.arch.endian(),
+ .homogeneous = true,
},
+ else => unreachable,
};
if (c_limb_info.count == 1) {
if (wrap.addWrap(int, one, data.int_info.signedness, c_bits) or
data.int_info.signedness == .signed and wrap.subWrap(int, one, data.int_info.signedness, c_bits))
return writer.print("{s}_{s}", .{
- data.cty.getStandardDefineAbbrev() orelse return writer.print("zig_{s}Int_{c}{d}", .{
+ data.ctype.getStandardDefineAbbrev() orelse return writer.print("zig_{s}Int_{c}{d}", .{
if (int.positive) "max" else "min", signAbbrev(data.int_info.signedness), c_bits,
}),
if (int.positive) "MAX" else "MIN",
});
if (!int.positive) try writer.writeByte('-');
- try data.cty.renderLiteralPrefix(writer, data.kind);
+ try data.ctype.renderLiteralPrefix(writer, data.kind, ctype_pool);
const style: struct { base: u8, case: std.fmt.Case = undefined } = switch (fmt.len) {
0 => .{ .base = 10 },
@@ -7948,7 +7913,7 @@ fn formatIntLiteral(
defer allocator.free(string);
try writer.writeAll(string);
} else {
- try data.cty.renderLiteralPrefix(writer, data.kind);
+ try data.ctype.renderLiteralPrefix(writer, data.kind, ctype_pool);
wrap.convertToTwosComplement(int, data.int_info.signedness, c_bits);
@memset(wrap.limbs[wrap.len..], 0);
wrap.len = wrap.limbs.len;
@@ -7958,7 +7923,7 @@ fn formatIntLiteral(
.signedness = undefined,
.bits = @as(u16, @intCast(@divExact(c_bits, c_limb_info.count))),
};
- var c_limb_cty: CType = undefined;
+ var c_limb_ctype: CType = undefined;
var limb_offset: usize = 0;
const most_significant_limb_i = wrap.len - limbs_per_c_limb;
@@ -7979,7 +7944,7 @@ fn formatIntLiteral(
{
// most significant limb is actually signed
c_limb_int_info.signedness = .signed;
- c_limb_cty = c_limb_info.cty.toSigned();
+ c_limb_ctype = c_limb_info.ctype.toSigned();
c_limb_mut.positive = wrap.positive;
c_limb_mut.truncate(
@@ -7989,7 +7954,7 @@ fn formatIntLiteral(
);
} else {
c_limb_int_info.signedness = .unsigned;
- c_limb_cty = c_limb_info.cty;
+ c_limb_ctype = c_limb_info.ctype;
}
if (limb_offset > 0) try writer.writeAll(", ");
@@ -7997,12 +7962,12 @@ fn formatIntLiteral(
.dg = data.dg,
.int_info = c_limb_int_info,
.kind = data.kind,
- .cty = c_limb_cty,
+ .ctype = c_limb_ctype,
.val = try zcu.intValue_big(Type.comptime_int, c_limb_mut.toConst()),
}, fmt, options, writer);
}
}
- try data.cty.renderLiteralSuffix(writer);
+ try data.ctype.renderLiteralSuffix(writer, ctype_pool);
}
const Materialize = struct {
@@ -8045,10 +8010,10 @@ const Materialize = struct {
};
const Assignment = struct {
- cty: CType.Index,
+ ctype: CType,
pub fn init(f: *Function, ty: Type) !Assignment {
- return .{ .cty = try f.typeToIndex(ty, .complete) };
+ return .{ .ctype = try f.ctypeFromType(ty, .complete) };
}
pub fn start(f: *Function, writer: anytype, ty: Type) !Assignment {
@@ -8076,7 +8041,7 @@ const Assignment = struct {
.assign => {},
.memcpy => {
try writer.writeAll(", sizeof(");
- try f.renderCType(writer, self.cty);
+ try f.renderCType(writer, self.ctype);
try writer.writeAll("))");
},
}
@@ -8084,7 +8049,7 @@ const Assignment = struct {
}
fn strategy(self: Assignment, f: *Function) enum { assign, memcpy } {
- return switch (f.indexToCType(self.cty).tag()) {
+ return switch (self.ctype.info(&f.object.dg.ctype_pool)) {
else => .assign,
.array, .vector => .memcpy,
};
@@ -8129,28 +8094,6 @@ const Vectorize = struct {
}
};
-fn lowerFnRetTy(ret_ty: Type, zcu: *Zcu) !Type {
- if (ret_ty.toIntern() == .noreturn_type) return Type.noreturn;
-
- if (lowersToArray(ret_ty, zcu)) {
- const gpa = zcu.gpa;
- const ip = &zcu.intern_pool;
- const names = [1]InternPool.NullTerminatedString{
- try ip.getOrPutString(gpa, "array"),
- };
- const types = [1]InternPool.Index{ret_ty.toIntern()};
- const values = [1]InternPool.Index{.none};
- const interned = try ip.getAnonStructType(gpa, .{
- .names = &names,
- .types = &types,
- .values = &values,
- });
- return Type.fromInterned(interned);
- }
-
- return if (ret_ty.hasRuntimeBitsIgnoreComptime(zcu)) ret_ty else Type.void;
-}
-
fn lowersToArray(ty: Type, zcu: *Zcu) bool {
return switch (ty.zigTypeTag(zcu)) {
.Array, .Vector => return true,
src/codegen/llvm.zig
@@ -2033,7 +2033,7 @@ pub const Object = struct {
owner_decl.src_node + 1, // Line
try o.lowerDebugType(int_ty),
ty.abiSize(mod) * 8,
- ty.abiAlignment(mod).toByteUnits(0) * 8,
+ (ty.abiAlignment(mod).toByteUnits() orelse 0) * 8,
try o.builder.debugTuple(enumerators),
);
@@ -2120,7 +2120,7 @@ pub const Object = struct {
0, // Line
try o.lowerDebugType(ptr_ty),
ptr_size * 8,
- ptr_align.toByteUnits(0) * 8,
+ (ptr_align.toByteUnits() orelse 0) * 8,
0, // Offset
);
@@ -2131,7 +2131,7 @@ pub const Object = struct {
0, // Line
try o.lowerDebugType(len_ty),
len_size * 8,
- len_align.toByteUnits(0) * 8,
+ (len_align.toByteUnits() orelse 0) * 8,
len_offset * 8,
);
@@ -2142,7 +2142,7 @@ pub const Object = struct {
line,
.none, // Underlying type
ty.abiSize(mod) * 8,
- ty.abiAlignment(mod).toByteUnits(0) * 8,
+ (ty.abiAlignment(mod).toByteUnits() orelse 0) * 8,
try o.builder.debugTuple(&.{
debug_ptr_type,
debug_len_type,
@@ -2170,7 +2170,7 @@ pub const Object = struct {
0, // Line
debug_elem_ty,
target.ptrBitWidth(),
- ty.ptrAlignment(mod).toByteUnits(0) * 8,
+ (ty.ptrAlignment(mod).toByteUnits() orelse 0) * 8,
0, // Offset
);
@@ -2217,7 +2217,7 @@ pub const Object = struct {
0, // Line
try o.lowerDebugType(ty.childType(mod)),
ty.abiSize(mod) * 8,
- ty.abiAlignment(mod).toByteUnits(0) * 8,
+ (ty.abiAlignment(mod).toByteUnits() orelse 0) * 8,
try o.builder.debugTuple(&.{
try o.builder.debugSubrange(
try o.builder.debugConstant(try o.builder.intConst(.i64, 0)),
@@ -2260,7 +2260,7 @@ pub const Object = struct {
0, // Line
debug_elem_type,
ty.abiSize(mod) * 8,
- ty.abiAlignment(mod).toByteUnits(0) * 8,
+ (ty.abiAlignment(mod).toByteUnits() orelse 0) * 8,
try o.builder.debugTuple(&.{
try o.builder.debugSubrange(
try o.builder.debugConstant(try o.builder.intConst(.i64, 0)),
@@ -2316,7 +2316,7 @@ pub const Object = struct {
0, // Line
try o.lowerDebugType(child_ty),
payload_size * 8,
- payload_align.toByteUnits(0) * 8,
+ (payload_align.toByteUnits() orelse 0) * 8,
0, // Offset
);
@@ -2327,7 +2327,7 @@ pub const Object = struct {
0,
try o.lowerDebugType(non_null_ty),
non_null_size * 8,
- non_null_align.toByteUnits(0) * 8,
+ (non_null_align.toByteUnits() orelse 0) * 8,
non_null_offset * 8,
);
@@ -2338,7 +2338,7 @@ pub const Object = struct {
0, // Line
.none, // Underlying type
ty.abiSize(mod) * 8,
- ty.abiAlignment(mod).toByteUnits(0) * 8,
+ (ty.abiAlignment(mod).toByteUnits() orelse 0) * 8,
try o.builder.debugTuple(&.{
debug_data_type,
debug_some_type,
@@ -2396,7 +2396,7 @@ pub const Object = struct {
0, // Line
try o.lowerDebugType(Type.anyerror),
error_size * 8,
- error_align.toByteUnits(0) * 8,
+ (error_align.toByteUnits() orelse 0) * 8,
error_offset * 8,
);
fields[payload_index] = try o.builder.debugMemberType(
@@ -2406,7 +2406,7 @@ pub const Object = struct {
0, // Line
try o.lowerDebugType(payload_ty),
payload_size * 8,
- payload_align.toByteUnits(0) * 8,
+ (payload_align.toByteUnits() orelse 0) * 8,
payload_offset * 8,
);
@@ -2417,7 +2417,7 @@ pub const Object = struct {
0, // Line
.none, // Underlying type
ty.abiSize(mod) * 8,
- ty.abiAlignment(mod).toByteUnits(0) * 8,
+ (ty.abiAlignment(mod).toByteUnits() orelse 0) * 8,
try o.builder.debugTuple(&fields),
);
@@ -2485,7 +2485,7 @@ pub const Object = struct {
0,
try o.lowerDebugType(Type.fromInterned(field_ty)),
field_size * 8,
- field_align.toByteUnits(0) * 8,
+ (field_align.toByteUnits() orelse 0) * 8,
field_offset * 8,
));
}
@@ -2497,7 +2497,7 @@ pub const Object = struct {
0, // Line
.none, // Underlying type
ty.abiSize(mod) * 8,
- ty.abiAlignment(mod).toByteUnits(0) * 8,
+ (ty.abiAlignment(mod).toByteUnits() orelse 0) * 8,
try o.builder.debugTuple(fields.items),
);
@@ -2566,7 +2566,7 @@ pub const Object = struct {
0, // Line
try o.lowerDebugType(field_ty),
field_size * 8,
- field_align.toByteUnits(0) * 8,
+ (field_align.toByteUnits() orelse 0) * 8,
field_offset * 8,
));
}
@@ -2578,7 +2578,7 @@ pub const Object = struct {
0, // Line
.none, // Underlying type
ty.abiSize(mod) * 8,
- ty.abiAlignment(mod).toByteUnits(0) * 8,
+ (ty.abiAlignment(mod).toByteUnits() orelse 0) * 8,
try o.builder.debugTuple(fields.items),
);
@@ -2621,7 +2621,7 @@ pub const Object = struct {
0, // Line
.none, // Underlying type
ty.abiSize(mod) * 8,
- ty.abiAlignment(mod).toByteUnits(0) * 8,
+ (ty.abiAlignment(mod).toByteUnits() orelse 0) * 8,
try o.builder.debugTuple(
&.{try o.lowerDebugType(Type.fromInterned(union_type.enum_tag_ty))},
),
@@ -2661,7 +2661,7 @@ pub const Object = struct {
0, // Line
try o.lowerDebugType(Type.fromInterned(field_ty)),
field_size * 8,
- field_align.toByteUnits(0) * 8,
+ (field_align.toByteUnits() orelse 0) * 8,
0, // Offset
));
}
@@ -2680,7 +2680,7 @@ pub const Object = struct {
0, // Line
.none, // Underlying type
ty.abiSize(mod) * 8,
- ty.abiAlignment(mod).toByteUnits(0) * 8,
+ (ty.abiAlignment(mod).toByteUnits() orelse 0) * 8,
try o.builder.debugTuple(fields.items),
);
@@ -2711,7 +2711,7 @@ pub const Object = struct {
0, // Line
try o.lowerDebugType(Type.fromInterned(union_type.enum_tag_ty)),
layout.tag_size * 8,
- layout.tag_align.toByteUnits(0) * 8,
+ (layout.tag_align.toByteUnits() orelse 0) * 8,
tag_offset * 8,
);
@@ -2722,7 +2722,7 @@ pub const Object = struct {
0, // Line
debug_union_type,
layout.payload_size * 8,
- layout.payload_align.toByteUnits(0) * 8,
+ (layout.payload_align.toByteUnits() orelse 0) * 8,
payload_offset * 8,
);
@@ -2739,7 +2739,7 @@ pub const Object = struct {
0, // Line
.none, // Underlying type
ty.abiSize(mod) * 8,
- ty.abiAlignment(mod).toByteUnits(0) * 8,
+ (ty.abiAlignment(mod).toByteUnits() orelse 0) * 8,
try o.builder.debugTuple(&full_fields),
);
@@ -4473,7 +4473,7 @@ pub const Object = struct {
// The value cannot be undefined, because we use the `nonnull` annotation
// for non-optional pointers. We also need to respect the alignment, even though
// the address will never be dereferenced.
- const int: u64 = ptr_ty.ptrInfo(mod).flags.alignment.toByteUnitsOptional() orelse
+ const int: u64 = ptr_ty.ptrInfo(mod).flags.alignment.toByteUnits() orelse
// Note that these 0xaa values are appropriate even in release-optimized builds
// because we need a well-defined value that is not null, and LLVM does not
// have an "undef_but_not_null" attribute. As an example, if this `alloc` AIR
src/link/Elf/Atom.zig
@@ -208,7 +208,7 @@ pub fn allocate(self: *Atom, elf_file: *Elf) !void {
zig_object.debug_aranges_section_dirty = true;
}
}
- shdr.sh_addralign = @max(shdr.sh_addralign, self.alignment.toByteUnitsOptional().?);
+ shdr.sh_addralign = @max(shdr.sh_addralign, self.alignment.toByteUnits().?);
// This function can also reallocate an atom.
// In this case we need to "unplug" it from its previous location before
src/link/Elf/relocatable.zig
@@ -330,7 +330,7 @@ fn updateSectionSizes(elf_file: *Elf) !void {
const padding = offset - shdr.sh_size;
atom_ptr.value = offset;
shdr.sh_size += padding + atom_ptr.size;
- shdr.sh_addralign = @max(shdr.sh_addralign, atom_ptr.alignment.toByteUnits(1));
+ shdr.sh_addralign = @max(shdr.sh_addralign, atom_ptr.alignment.toByteUnits() orelse 1);
}
}
src/link/Elf/thunks.zig
@@ -63,7 +63,7 @@ fn advance(shdr: *elf.Elf64_Shdr, size: u64, alignment: Atom.Alignment) !u64 {
const offset = alignment.forward(shdr.sh_size);
const padding = offset - shdr.sh_size;
shdr.sh_size += padding + size;
- shdr.sh_addralign = @max(shdr.sh_addralign, alignment.toByteUnits(1));
+ shdr.sh_addralign = @max(shdr.sh_addralign, alignment.toByteUnits() orelse 1);
return offset;
}
src/link/Elf/ZigObject.zig
@@ -313,7 +313,7 @@ pub fn inputShdr(self: ZigObject, atom_index: Atom.Index, elf_file: *Elf) elf.El
shdr.sh_addr = 0;
shdr.sh_offset = 0;
shdr.sh_size = atom.size;
- shdr.sh_addralign = atom.alignment.toByteUnits(1);
+ shdr.sh_addralign = atom.alignment.toByteUnits() orelse 1;
return shdr;
}
src/link/MachO/relocatable.zig
@@ -380,7 +380,7 @@ fn calcSectionSizes(macho_file: *MachO) !void {
if (atoms.items.len == 0) continue;
for (atoms.items) |atom_index| {
const atom = macho_file.getAtom(atom_index).?;
- const atom_alignment = atom.alignment.toByteUnits(1);
+ const atom_alignment = atom.alignment.toByteUnits() orelse 1;
const offset = mem.alignForward(u64, header.size, atom_alignment);
const padding = offset - header.size;
atom.value = offset;
src/link/C.zig
@@ -69,13 +69,13 @@ pub const DeclBlock = struct {
fwd_decl: String = String.empty,
/// Each `Decl` stores a set of used `CType`s. In `flush()`, we iterate
/// over each `Decl` and generate the definition for each used `CType` once.
- ctypes: codegen.CType.Store = .{},
- /// Key and Value storage use the ctype arena.
+ ctype_pool: codegen.CType.Pool = codegen.CType.Pool.empty,
+ /// May contain string references to ctype_pool
lazy_fns: codegen.LazyFnMap = .{},
fn deinit(db: *DeclBlock, gpa: Allocator) void {
db.lazy_fns.deinit(gpa);
- db.ctypes.deinit(gpa);
+ db.ctype_pool.deinit(gpa);
db.* = undefined;
}
};
@@ -190,11 +190,12 @@ pub fn updateFunc(
const decl = zcu.declPtr(decl_index);
const gop = try self.decl_table.getOrPut(gpa, decl_index);
if (!gop.found_existing) gop.value_ptr.* = .{};
- const ctypes = &gop.value_ptr.ctypes;
+ const ctype_pool = &gop.value_ptr.ctype_pool;
const lazy_fns = &gop.value_ptr.lazy_fns;
const fwd_decl = &self.fwd_decl_buf;
const code = &self.code_buf;
- ctypes.clearRetainingCapacity(gpa);
+ try ctype_pool.init(gpa);
+ ctype_pool.clearRetainingCapacity();
lazy_fns.clearRetainingCapacity();
fwd_decl.clearRetainingCapacity();
code.clearRetainingCapacity();
@@ -213,7 +214,8 @@ pub fn updateFunc(
.pass = .{ .decl = decl_index },
.is_naked_fn = decl.typeOf(zcu).fnCallingConvention(zcu) == .Naked,
.fwd_decl = fwd_decl.toManaged(gpa),
- .ctypes = ctypes.*,
+ .ctype_pool = ctype_pool.*,
+ .scratch = .{},
.anon_decl_deps = self.anon_decls,
.aligned_anon_decls = self.aligned_anon_decls,
},
@@ -222,12 +224,16 @@ pub fn updateFunc(
},
.lazy_fns = lazy_fns.*,
};
-
function.object.indent_writer = .{ .underlying_writer = function.object.code.writer() };
defer {
self.anon_decls = function.object.dg.anon_decl_deps;
self.aligned_anon_decls = function.object.dg.aligned_anon_decls;
fwd_decl.* = function.object.dg.fwd_decl.moveToUnmanaged();
+ ctype_pool.* = function.object.dg.ctype_pool.move();
+ ctype_pool.freeUnusedCapacity(gpa);
+ function.object.dg.scratch.deinit(gpa);
+ lazy_fns.* = function.lazy_fns.move();
+ lazy_fns.shrinkAndFree(gpa, lazy_fns.count());
code.* = function.object.code.moveToUnmanaged();
function.deinit();
}
@@ -239,16 +245,8 @@ pub fn updateFunc(
},
else => |e| return e,
};
-
- ctypes.* = function.object.dg.ctypes.move();
- lazy_fns.* = function.lazy_fns.move();
-
- // Free excess allocated memory for this Decl.
- ctypes.shrinkAndFree(gpa, ctypes.count());
- lazy_fns.shrinkAndFree(gpa, lazy_fns.count());
-
- gop.value_ptr.code = try self.addString(function.object.code.items);
gop.value_ptr.fwd_decl = try self.addString(function.object.dg.fwd_decl.items);
+ gop.value_ptr.code = try self.addString(function.object.code.items);
}
fn updateAnonDecl(self: *C, zcu: *Zcu, i: usize) !void {
@@ -269,7 +267,8 @@ fn updateAnonDecl(self: *C, zcu: *Zcu, i: usize) !void {
.pass = .{ .anon = anon_decl },
.is_naked_fn = false,
.fwd_decl = fwd_decl.toManaged(gpa),
- .ctypes = .{},
+ .ctype_pool = codegen.CType.Pool.empty,
+ .scratch = .{},
.anon_decl_deps = self.anon_decls,
.aligned_anon_decls = self.aligned_anon_decls,
},
@@ -277,14 +276,15 @@ fn updateAnonDecl(self: *C, zcu: *Zcu, i: usize) !void {
.indent_writer = undefined, // set later so we can get a pointer to object.code
};
object.indent_writer = .{ .underlying_writer = object.code.writer() };
-
defer {
self.anon_decls = object.dg.anon_decl_deps;
self.aligned_anon_decls = object.dg.aligned_anon_decls;
- object.dg.ctypes.deinit(object.dg.gpa);
fwd_decl.* = object.dg.fwd_decl.moveToUnmanaged();
+ object.dg.ctype_pool.deinit(object.dg.gpa);
+ object.dg.scratch.deinit(gpa);
code.* = object.code.moveToUnmanaged();
}
+ try object.dg.ctype_pool.init(gpa);
const c_value: codegen.CValue = .{ .constant = Value.fromInterned(anon_decl) };
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 {
else => |e| return e,
};
- // Free excess allocated memory for this Decl.
- object.dg.ctypes.shrinkAndFree(gpa, object.dg.ctypes.count());
-
+ object.dg.ctype_pool.freeUnusedCapacity(gpa);
object.dg.anon_decl_deps.values()[i] = .{
.code = try self.addString(object.code.items),
.fwd_decl = try self.addString(object.dg.fwd_decl.items),
- .ctypes = object.dg.ctypes.move(),
+ .ctype_pool = object.dg.ctype_pool.move(),
};
}
@@ -315,13 +313,13 @@ pub fn updateDecl(self: *C, zcu: *Zcu, decl_index: InternPool.DeclIndex) !void {
const decl = zcu.declPtr(decl_index);
const gop = try self.decl_table.getOrPut(gpa, decl_index);
- if (!gop.found_existing) {
- gop.value_ptr.* = .{};
- }
- const ctypes = &gop.value_ptr.ctypes;
+ errdefer _ = self.decl_table.pop();
+ if (!gop.found_existing) gop.value_ptr.* = .{};
+ const ctype_pool = &gop.value_ptr.ctype_pool;
const fwd_decl = &self.fwd_decl_buf;
const code = &self.code_buf;
- ctypes.clearRetainingCapacity(gpa);
+ try ctype_pool.init(gpa);
+ ctype_pool.clearRetainingCapacity();
fwd_decl.clearRetainingCapacity();
code.clearRetainingCapacity();
@@ -334,7 +332,8 @@ pub fn updateDecl(self: *C, zcu: *Zcu, decl_index: InternPool.DeclIndex) !void {
.pass = .{ .decl = decl_index },
.is_naked_fn = false,
.fwd_decl = fwd_decl.toManaged(gpa),
- .ctypes = ctypes.*,
+ .ctype_pool = ctype_pool.*,
+ .scratch = .{},
.anon_decl_deps = self.anon_decls,
.aligned_anon_decls = self.aligned_anon_decls,
},
@@ -345,8 +344,10 @@ pub fn updateDecl(self: *C, zcu: *Zcu, decl_index: InternPool.DeclIndex) !void {
defer {
self.anon_decls = object.dg.anon_decl_deps;
self.aligned_anon_decls = object.dg.aligned_anon_decls;
- object.dg.ctypes.deinit(object.dg.gpa);
fwd_decl.* = object.dg.fwd_decl.moveToUnmanaged();
+ ctype_pool.* = object.dg.ctype_pool.move();
+ ctype_pool.freeUnusedCapacity(gpa);
+ object.dg.scratch.deinit(gpa);
code.* = object.code.moveToUnmanaged();
}
@@ -357,12 +358,6 @@ pub fn updateDecl(self: *C, zcu: *Zcu, decl_index: InternPool.DeclIndex) !void {
},
else => |e| return e,
};
-
- ctypes.* = object.dg.ctypes.move();
-
- // Free excess allocated memory for this Decl.
- ctypes.shrinkAndFree(gpa, ctypes.count());
-
gop.value_ptr.code = try self.addString(object.code.items);
gop.value_ptr.fwd_decl = try self.addString(object.dg.fwd_decl.items);
}
@@ -416,7 +411,10 @@ pub fn flushModule(self: *C, arena: Allocator, prog_node: *std.Progress.Node) !v
// This code path happens exclusively with -ofmt=c. The flush logic for
// emit-h is in `flushEmitH` below.
- var f: Flush = .{};
+ var f: Flush = .{
+ .ctype_pool = codegen.CType.Pool.empty,
+ .lazy_ctype_pool = codegen.CType.Pool.empty,
+ };
defer f.deinit(gpa);
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
self.lazy_fwd_decl_buf.clearRetainingCapacity();
self.lazy_code_buf.clearRetainingCapacity();
- try self.flushErrDecls(zcu, &f.lazy_ctypes);
+ try f.lazy_ctype_pool.init(gpa);
+ try self.flushErrDecls(zcu, &f.lazy_ctype_pool);
// Unlike other backends, the .c code we are emitting has order-dependent decls.
// `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
{
// We need to flush lazy ctypes after flushing all decls but before flushing any decl ctypes.
// This ensures that every lazy CType.Index exactly matches the global CType.Index.
- assert(f.ctypes.count() == 0);
- try self.flushCTypes(zcu, &f, .flush, f.lazy_ctypes);
+ try f.ctype_pool.init(gpa);
+ try self.flushCTypes(zcu, &f, .flush, &f.lazy_ctype_pool);
for (self.anon_decls.keys(), self.anon_decls.values()) |anon_decl, decl_block| {
- try self.flushCTypes(zcu, &f, .{ .anon = anon_decl }, decl_block.ctypes);
+ try self.flushCTypes(zcu, &f, .{ .anon = anon_decl }, &decl_block.ctype_pool);
}
for (self.decl_table.keys(), self.decl_table.values()) |decl_index, decl_block| {
- try self.flushCTypes(zcu, &f, .{ .decl = decl_index }, decl_block.ctypes);
+ try self.flushCTypes(zcu, &f, .{ .decl = decl_index }, &decl_block.ctype_pool);
}
}
@@ -510,11 +509,11 @@ pub fn flushModule(self: *C, arena: Allocator, prog_node: *std.Progress.Node) !v
}
const Flush = struct {
- ctypes: codegen.CType.Store = .{},
- ctypes_map: std.ArrayListUnmanaged(codegen.CType.Index) = .{},
+ ctype_pool: codegen.CType.Pool,
+ ctype_global_from_decl_map: std.ArrayListUnmanaged(codegen.CType) = .{},
ctypes_buf: std.ArrayListUnmanaged(u8) = .{},
- lazy_ctypes: codegen.CType.Store = .{},
+ lazy_ctype_pool: codegen.CType.Pool,
lazy_fns: LazyFns = .{},
asm_buf: std.ArrayListUnmanaged(u8) = .{},
@@ -536,10 +535,11 @@ const Flush = struct {
f.all_buffers.deinit(gpa);
f.asm_buf.deinit(gpa);
f.lazy_fns.deinit(gpa);
- f.lazy_ctypes.deinit(gpa);
+ f.lazy_ctype_pool.deinit(gpa);
f.ctypes_buf.deinit(gpa);
- f.ctypes_map.deinit(gpa);
- f.ctypes.deinit(gpa);
+ assert(f.ctype_global_from_decl_map.items.len == 0);
+ f.ctype_global_from_decl_map.deinit(gpa);
+ f.ctype_pool.deinit(gpa);
}
};
@@ -552,88 +552,59 @@ fn flushCTypes(
zcu: *Zcu,
f: *Flush,
pass: codegen.DeclGen.Pass,
- decl_ctypes: codegen.CType.Store,
+ decl_ctype_pool: *const codegen.CType.Pool,
) FlushDeclError!void {
const gpa = self.base.comp.gpa;
+ const global_ctype_pool = &f.ctype_pool;
- const decl_ctypes_len = decl_ctypes.count();
- f.ctypes_map.clearRetainingCapacity();
- try f.ctypes_map.ensureTotalCapacity(gpa, decl_ctypes_len);
-
- var global_ctypes = f.ctypes.promote(gpa);
- defer f.ctypes.demote(global_ctypes);
+ const global_from_decl_map = &f.ctype_global_from_decl_map;
+ assert(global_from_decl_map.items.len == 0);
+ try global_from_decl_map.ensureTotalCapacity(gpa, decl_ctype_pool.items.len);
+ defer global_from_decl_map.clearRetainingCapacity();
var ctypes_buf = f.ctypes_buf.toManaged(gpa);
defer f.ctypes_buf = ctypes_buf.moveToUnmanaged();
const writer = ctypes_buf.writer();
- const slice = decl_ctypes.set.map.entries.slice();
- for (slice.items(.key), 0..) |decl_cty, decl_i| {
- const Context = struct {
- arena: Allocator,
- ctypes_map: []codegen.CType.Index,
- cached_hash: codegen.CType.Store.Set.Map.Hash,
- idx: codegen.CType.Index,
-
- pub fn hash(ctx: @This(), _: codegen.CType) codegen.CType.Store.Set.Map.Hash {
- return ctx.cached_hash;
+ for (0..decl_ctype_pool.items.len) |decl_ctype_pool_index| {
+ const PoolAdapter = struct {
+ global_from_decl_map: []const codegen.CType,
+ pub fn eql(pool_adapter: @This(), decl_ctype: codegen.CType, global_ctype: codegen.CType) bool {
+ return if (decl_ctype.toPoolIndex()) |decl_pool_index|
+ decl_pool_index < pool_adapter.global_from_decl_map.len and
+ pool_adapter.global_from_decl_map[decl_pool_index].eql(global_ctype)
+ else
+ decl_ctype.index == global_ctype.index;
}
- pub fn eql(ctx: @This(), lhs: codegen.CType, rhs: codegen.CType, _: usize) bool {
- return lhs.eqlContext(rhs, ctx);
+ pub fn copy(pool_adapter: @This(), decl_ctype: codegen.CType) codegen.CType {
+ return if (decl_ctype.toPoolIndex()) |decl_pool_index|
+ pool_adapter.global_from_decl_map[decl_pool_index]
+ else
+ decl_ctype;
}
- pub fn eqlIndex(
- ctx: @This(),
- lhs_idx: codegen.CType.Index,
- rhs_idx: codegen.CType.Index,
- ) bool {
- if (lhs_idx < codegen.CType.Tag.no_payload_count or
- rhs_idx < codegen.CType.Tag.no_payload_count) return lhs_idx == rhs_idx;
- const lhs_i = lhs_idx - codegen.CType.Tag.no_payload_count;
- if (lhs_i >= ctx.ctypes_map.len) return false;
- return ctx.ctypes_map[lhs_i] == rhs_idx;
- }
- pub fn copyIndex(ctx: @This(), idx: codegen.CType.Index) codegen.CType.Index {
- if (idx < codegen.CType.Tag.no_payload_count) return idx;
- return ctx.ctypes_map[idx - codegen.CType.Tag.no_payload_count];
- }
- };
- const decl_idx = @as(codegen.CType.Index, @intCast(codegen.CType.Tag.no_payload_count + decl_i));
- const ctx = Context{
- .arena = global_ctypes.arena.allocator(),
- .ctypes_map = f.ctypes_map.items,
- .cached_hash = decl_ctypes.indexToHash(decl_idx),
- .idx = decl_idx,
};
- const gop = try global_ctypes.set.map.getOrPutContextAdapted(gpa, decl_cty, ctx, .{
- .store = &global_ctypes.set,
- });
- const global_idx =
- @as(codegen.CType.Index, @intCast(codegen.CType.Tag.no_payload_count + gop.index));
- f.ctypes_map.appendAssumeCapacity(global_idx);
- if (!gop.found_existing) {
- errdefer _ = global_ctypes.set.map.pop();
- gop.key_ptr.* = try decl_cty.copyContext(ctx);
- }
- if (std.debug.runtime_safety) {
- const global_cty = &global_ctypes.set.map.entries.items(.key)[gop.index];
- assert(global_cty == gop.key_ptr);
- assert(decl_cty.eqlContext(global_cty.*, ctx));
- assert(decl_cty.hash(decl_ctypes.set) == global_cty.hash(global_ctypes.set));
- }
+ const decl_ctype = codegen.CType.fromPoolIndex(decl_ctype_pool_index);
+ const global_ctype, const found_existing = try global_ctype_pool.getOrPutAdapted(
+ gpa,
+ decl_ctype_pool,
+ decl_ctype,
+ PoolAdapter{ .global_from_decl_map = global_from_decl_map.items },
+ );
+ global_from_decl_map.appendAssumeCapacity(global_ctype);
try codegen.genTypeDecl(
zcu,
writer,
- global_ctypes.set,
- global_idx,
+ global_ctype_pool,
+ global_ctype,
pass,
- decl_ctypes.set,
- decl_idx,
- gop.found_existing,
+ decl_ctype_pool,
+ decl_ctype,
+ found_existing,
);
}
}
-fn flushErrDecls(self: *C, zcu: *Zcu, ctypes: *codegen.CType.Store) FlushDeclError!void {
+fn flushErrDecls(self: *C, zcu: *Zcu, ctype_pool: *codegen.CType.Pool) FlushDeclError!void {
const gpa = self.base.comp.gpa;
const fwd_decl = &self.lazy_fwd_decl_buf;
@@ -648,7 +619,8 @@ fn flushErrDecls(self: *C, zcu: *Zcu, ctypes: *codegen.CType.Store) FlushDeclErr
.pass = .flush,
.is_naked_fn = false,
.fwd_decl = fwd_decl.toManaged(gpa),
- .ctypes = ctypes.*,
+ .ctype_pool = ctype_pool.*,
+ .scratch = .{},
.anon_decl_deps = self.anon_decls,
.aligned_anon_decls = self.aligned_anon_decls,
},
@@ -659,8 +631,10 @@ fn flushErrDecls(self: *C, zcu: *Zcu, ctypes: *codegen.CType.Store) FlushDeclErr
defer {
self.anon_decls = object.dg.anon_decl_deps;
self.aligned_anon_decls = object.dg.aligned_anon_decls;
- object.dg.ctypes.deinit(gpa);
fwd_decl.* = object.dg.fwd_decl.moveToUnmanaged();
+ ctype_pool.* = object.dg.ctype_pool.move();
+ ctype_pool.freeUnusedCapacity(gpa);
+ object.dg.scratch.deinit(gpa);
code.* = object.code.moveToUnmanaged();
}
@@ -668,15 +642,14 @@ fn flushErrDecls(self: *C, zcu: *Zcu, ctypes: *codegen.CType.Store) FlushDeclErr
error.AnalysisFail => unreachable,
else => |e| return e,
};
-
- ctypes.* = object.dg.ctypes.move();
}
fn flushLazyFn(
self: *C,
zcu: *Zcu,
mod: *Module,
- ctypes: *codegen.CType.Store,
+ ctype_pool: *codegen.CType.Pool,
+ lazy_ctype_pool: *const codegen.CType.Pool,
lazy_fn: codegen.LazyFnMap.Entry,
) FlushDeclError!void {
const gpa = self.base.comp.gpa;
@@ -693,7 +666,8 @@ fn flushLazyFn(
.pass = .flush,
.is_naked_fn = false,
.fwd_decl = fwd_decl.toManaged(gpa),
- .ctypes = ctypes.*,
+ .ctype_pool = ctype_pool.*,
+ .scratch = .{},
.anon_decl_deps = .{},
.aligned_anon_decls = .{},
},
@@ -706,17 +680,17 @@ fn flushLazyFn(
// `updateFunc()` does.
assert(object.dg.anon_decl_deps.count() == 0);
assert(object.dg.aligned_anon_decls.count() == 0);
- object.dg.ctypes.deinit(gpa);
fwd_decl.* = object.dg.fwd_decl.moveToUnmanaged();
+ ctype_pool.* = object.dg.ctype_pool.move();
+ ctype_pool.freeUnusedCapacity(gpa);
+ object.dg.scratch.deinit(gpa);
code.* = object.code.moveToUnmanaged();
}
- codegen.genLazyFn(&object, lazy_fn) catch |err| switch (err) {
+ codegen.genLazyFn(&object, lazy_ctype_pool, lazy_fn) catch |err| switch (err) {
error.AnalysisFail => unreachable,
else => |e| return e,
};
-
- ctypes.* = object.dg.ctypes.move();
}
fn flushLazyFns(
@@ -724,6 +698,7 @@ fn flushLazyFns(
zcu: *Zcu,
mod: *Module,
f: *Flush,
+ lazy_ctype_pool: *const codegen.CType.Pool,
lazy_fns: codegen.LazyFnMap,
) FlushDeclError!void {
const gpa = self.base.comp.gpa;
@@ -734,7 +709,7 @@ fn flushLazyFns(
const gop = f.lazy_fns.getOrPutAssumeCapacity(entry.key_ptr.*);
if (gop.found_existing) continue;
gop.value_ptr.* = {};
- try self.flushLazyFn(zcu, mod, &f.lazy_ctypes, entry);
+ try self.flushLazyFn(zcu, mod, &f.lazy_ctype_pool, lazy_ctype_pool, entry);
}
}
@@ -748,7 +723,7 @@ fn flushDeclBlock(
extern_symbol_name: InternPool.OptionalNullTerminatedString,
) FlushDeclError!void {
const gpa = self.base.comp.gpa;
- try self.flushLazyFns(zcu, mod, f, decl_block.lazy_fns);
+ try self.flushLazyFns(zcu, mod, f, &decl_block.ctype_pool, decl_block.lazy_fns);
try f.all_buffers.ensureUnusedCapacity(gpa, 1);
fwd_decl: {
if (extern_symbol_name.unwrap()) |name| {
src/link/Coff.zig
@@ -1223,7 +1223,7 @@ fn lowerConst(self: *Coff, name: []const u8, val: Value, required_alignment: Int
atom.getSymbolPtr(self).value = try self.allocateAtom(
atom_index,
atom.size,
- @intCast(required_alignment.toByteUnitsOptional().?),
+ @intCast(required_alignment.toByteUnits().?),
);
errdefer self.freeAtom(atom_index);
@@ -1344,7 +1344,7 @@ fn updateLazySymbolAtom(
symbol.section_number = @as(coff.SectionNumber, @enumFromInt(section_index + 1));
symbol.type = .{ .complex_type = .NULL, .base_type = .NULL };
- const vaddr = try self.allocateAtom(atom_index, code_len, @intCast(required_alignment.toByteUnits(0)));
+ const vaddr = try self.allocateAtom(atom_index, code_len, @intCast(required_alignment.toByteUnits() orelse 0));
errdefer self.freeAtom(atom_index);
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
const decl_name = mod.intern_pool.stringToSlice(try decl.fullyQualifiedName(mod));
log.debug("updateDeclCode {s}{*}", .{ decl_name, decl });
- const required_alignment: u32 = @intCast(decl.getAlignment(mod).toByteUnits(0));
+ const required_alignment: u32 = @intCast(decl.getAlignment(mod).toByteUnits() orelse 0);
const decl_metadata = self.decls.get(decl_index).?;
const atom_index = decl_metadata.atom;
src/link/Elf.zig
@@ -4051,7 +4051,7 @@ fn updateSectionSizes(self: *Elf) !void {
const padding = offset - shdr.sh_size;
atom_ptr.value = offset;
shdr.sh_size += padding + atom_ptr.size;
- shdr.sh_addralign = @max(shdr.sh_addralign, atom_ptr.alignment.toByteUnits(1));
+ shdr.sh_addralign = @max(shdr.sh_addralign, atom_ptr.alignment.toByteUnits() orelse 1);
}
}
src/link/MachO.zig
@@ -2060,7 +2060,7 @@ fn calcSectionSizes(self: *MachO) !void {
for (atoms.items) |atom_index| {
const atom = self.getAtom(atom_index).?;
- const atom_alignment = atom.alignment.toByteUnits(1);
+ const atom_alignment = atom.alignment.toByteUnits() orelse 1;
const offset = mem.alignForward(u64, header.size, atom_alignment);
const padding = offset - header.size;
atom.value = offset;
src/link/Wasm.zig
@@ -2263,7 +2263,7 @@ fn setupMemory(wasm: *Wasm) !void {
}
if (wasm.findGlobalSymbol("__tls_align")) |loc| {
const sym = loc.getSymbol(wasm);
- wasm.wasm_globals.items[sym.index - wasm.imported_globals_count].init.i32_const = @intCast(segment.alignment.toByteUnitsOptional().?);
+ wasm.wasm_globals.items[sym.index - wasm.imported_globals_count].init.i32_const = @intCast(segment.alignment.toByteUnits().?);
}
if (wasm.findGlobalSymbol("__tls_base")) |loc| {
const sym = loc.getSymbol(wasm);
src/codegen.zig
@@ -548,7 +548,7 @@ pub fn generateSymbol(
}
const size = struct_type.size(ip).*;
- const alignment = struct_type.flagsPtr(ip).alignment.toByteUnitsOptional().?;
+ const alignment = struct_type.flagsPtr(ip).alignment.toByteUnits().?;
const padding = math.cast(
usize,
@@ -893,12 +893,12 @@ fn genDeclRef(
// TODO this feels clunky. Perhaps we should check for it in `genTypedValue`?
if (ty.castPtrToFn(zcu)) |fn_ty| {
if (zcu.typeToFunc(fn_ty).?.is_generic) {
- return GenResult.mcv(.{ .immediate = fn_ty.abiAlignment(zcu).toByteUnitsOptional().? });
+ return GenResult.mcv(.{ .immediate = fn_ty.abiAlignment(zcu).toByteUnits().? });
}
} else if (ty.zigTypeTag(zcu) == .Pointer) {
const elem_ty = ty.elemType2(zcu);
if (!elem_ty.hasRuntimeBits(zcu)) {
- return GenResult.mcv(.{ .immediate = elem_ty.abiAlignment(zcu).toByteUnitsOptional().? });
+ return GenResult.mcv(.{ .immediate = elem_ty.abiAlignment(zcu).toByteUnits().? });
}
}
src/Compilation.zig
@@ -3457,14 +3457,18 @@ fn processOneJob(comp: *Compilation, job: Job, prog_node: *std.Progress.Node) !v
.pass = .{ .decl = decl_index },
.is_naked_fn = false,
.fwd_decl = fwd_decl.toManaged(gpa),
- .ctypes = .{},
+ .ctype_pool = c_codegen.CType.Pool.empty,
+ .scratch = .{},
.anon_decl_deps = .{},
.aligned_anon_decls = .{},
};
defer {
- dg.ctypes.deinit(gpa);
- dg.fwd_decl.deinit();
+ fwd_decl.* = dg.fwd_decl.moveToUnmanaged();
+ fwd_decl.shrinkAndFree(gpa, fwd_decl.items.len);
+ dg.ctype_pool.deinit(gpa);
+ dg.scratch.deinit(gpa);
}
+ try dg.ctype_pool.init(gpa);
c_codegen.genHeader(&dg) catch |err| switch (err) {
error.AnalysisFail => {
@@ -3473,9 +3477,6 @@ fn processOneJob(comp: *Compilation, job: Job, prog_node: *std.Progress.Node) !v
},
else => |e| return e,
};
-
- fwd_decl.* = dg.fwd_decl.moveToUnmanaged();
- fwd_decl.shrinkAndFree(gpa, fwd_decl.items.len);
},
}
},
src/crash_report.zig
@@ -172,7 +172,7 @@ pub fn attachSegfaultHandler() void {
};
}
-fn handleSegfaultPosix(sig: i32, info: *const posix.siginfo_t, ctx_ptr: ?*const anyopaque) callconv(.C) noreturn {
+fn handleSegfaultPosix(sig: i32, info: *const posix.siginfo_t, ctx_ptr: ?*anyopaque) callconv(.C) noreturn {
// TODO: use alarm() here to prevent infinite loops
PanicSwitch.preDispatch();
src/InternPool.zig
@@ -712,7 +712,7 @@ pub const Key = union(enum) {
pub fn fieldName(
self: AnonStructType,
ip: *const InternPool,
- index: u32,
+ index: usize,
) OptionalNullTerminatedString {
if (self.names.len == 0)
return .none;
@@ -3879,20 +3879,13 @@ pub const Alignment = enum(u6) {
none = std.math.maxInt(u6),
_,
- pub fn toByteUnitsOptional(a: Alignment) ?u64 {
+ pub fn toByteUnits(a: Alignment) ?u64 {
return switch (a) {
.none => null,
else => @as(u64, 1) << @intFromEnum(a),
};
}
- pub fn toByteUnits(a: Alignment, default: u64) u64 {
- return switch (a) {
- .none => default,
- else => @as(u64, 1) << @intFromEnum(a),
- };
- }
-
pub fn fromByteUnits(n: u64) Alignment {
if (n == 0) return .none;
assert(std.math.isPowerOfTwo(n));
src/main.zig
@@ -3544,11 +3544,7 @@ fn createModule(
// If the target is not overridden, use the parent's target. Of course,
// if this is the root module then we need to proceed to resolve the
// target.
- if (cli_mod.target_arch_os_abi == null and
- cli_mod.target_mcpu == null and
- create_module.dynamic_linker == null and
- create_module.object_format == null)
- {
+ if (cli_mod.target_arch_os_abi == null and cli_mod.target_mcpu == null) {
if (parent) |p| break :t p.resolved_target;
}
src/Module.zig
@@ -5846,7 +5846,7 @@ pub fn intBitsForValue(mod: *Module, val: Value, sign: bool) u16 {
return @as(u16, @intCast(big.bitCountTwosComp()));
},
.lazy_align => |lazy_ty| {
- return Type.smallestUnsignedBits(Type.fromInterned(lazy_ty).abiAlignment(mod).toByteUnits(0)) + @intFromBool(sign);
+ return Type.smallestUnsignedBits(Type.fromInterned(lazy_ty).abiAlignment(mod).toByteUnits() orelse 0) + @intFromBool(sign);
},
.lazy_size => |lazy_ty| {
return Type.smallestUnsignedBits(Type.fromInterned(lazy_ty).abiSize(mod)) + @intFromBool(sign);
src/print_value.zig
@@ -80,7 +80,7 @@ pub fn print(
inline .u64, .i64, .big_int => |x| try writer.print("{}", .{x}),
.lazy_align => |ty| if (opt_sema) |sema| {
const a = (try Type.fromInterned(ty).abiAlignmentAdvanced(mod, .{ .sema = sema })).scalar;
- try writer.print("{}", .{a.toByteUnits(0)});
+ try writer.print("{}", .{a.toByteUnits() orelse 0});
} else try writer.print("@alignOf({})", .{Type.fromInterned(ty).fmt(mod)}),
.lazy_size => |ty| if (opt_sema) |sema| {
const s = (try Type.fromInterned(ty).abiSizeAdvanced(mod, .{ .sema = sema })).scalar;
src/Sema.zig
@@ -6508,7 +6508,7 @@ fn zirSetAlignStack(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.Inst
const alignment = try sema.resolveAlign(block, operand_src, extra.operand);
if (alignment.order(Alignment.fromNonzeroByteUnits(256)).compare(.gt)) {
return sema.fail(block, src, "attempt to @setAlignStack({d}); maximum is 256", .{
- alignment.toByteUnitsOptional().?,
+ alignment.toByteUnits().?,
});
}
@@ -17804,7 +17804,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
},
.Pointer => {
const info = ty.ptrInfo(mod);
- const alignment = if (info.flags.alignment.toByteUnitsOptional()) |alignment|
+ const alignment = if (info.flags.alignment.toByteUnits()) |alignment|
try mod.intValue(Type.comptime_int, alignment)
else
try Type.fromInterned(info.child).lazyAbiAlignment(mod);
@@ -18279,7 +18279,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
// type: type,
field_ty,
// alignment: comptime_int,
- (try mod.intValue(Type.comptime_int, alignment.toByteUnits(0))).toIntern(),
+ (try mod.intValue(Type.comptime_int, alignment.toByteUnits() orelse 0)).toIntern(),
};
field_val.* = try mod.intern(.{ .aggregate = .{
.ty = union_field_ty.toIntern(),
@@ -18436,7 +18436,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
// is_comptime: bool,
Value.makeBool(is_comptime).toIntern(),
// alignment: comptime_int,
- (try mod.intValue(Type.comptime_int, Type.fromInterned(field_ty).abiAlignment(mod).toByteUnits(0))).toIntern(),
+ (try mod.intValue(Type.comptime_int, Type.fromInterned(field_ty).abiAlignment(mod).toByteUnits() orelse 0)).toIntern(),
};
struct_field_val.* = try mod.intern(.{ .aggregate = .{
.ty = struct_field_ty.toIntern(),
@@ -18505,7 +18505,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
// is_comptime: bool,
Value.makeBool(field_is_comptime).toIntern(),
// alignment: comptime_int,
- (try mod.intValue(Type.comptime_int, alignment.toByteUnits(0))).toIntern(),
+ (try mod.intValue(Type.comptime_int, alignment.toByteUnits() orelse 0)).toIntern(),
};
field_val.* = try mod.intern(.{ .aggregate = .{
.ty = struct_field_ty.toIntern(),
@@ -22552,7 +22552,7 @@ fn zirPtrFromInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!
try sema.addSafetyCheck(block, src, is_non_zero, .cast_to_null);
}
if (ptr_align.compare(.gt, .@"1")) {
- const align_bytes_minus_1 = ptr_align.toByteUnitsOptional().? - 1;
+ const align_bytes_minus_1 = ptr_align.toByteUnits().? - 1;
const align_minus_1 = Air.internedToRef((try mod.intValue(Type.usize, align_bytes_minus_1)).toIntern());
const remainder = try block.addBinOp(.bit_and, operand_coerced, align_minus_1);
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!
try sema.addSafetyCheck(block, src, is_non_zero, .cast_to_null);
}
if (ptr_align.compare(.gt, .@"1")) {
- const align_bytes_minus_1 = ptr_align.toByteUnitsOptional().? - 1;
+ const align_bytes_minus_1 = ptr_align.toByteUnits().? - 1;
const align_minus_1 = Air.internedToRef((try mod.intValue(Type.usize, align_bytes_minus_1)).toIntern());
const remainder = try block.addBinOp(.bit_and, elem_coerced, align_minus_1);
const is_aligned = try block.addBinOp(.cmp_eq, remainder, .zero_usize);
@@ -22970,10 +22970,10 @@ fn ptrCastFull(
const msg = try sema.errMsg(block, src, "cast increases pointer alignment", .{});
errdefer msg.destroy(sema.gpa);
try sema.errNote(block, operand_src, msg, "'{}' has alignment '{d}'", .{
- operand_ty.fmt(mod), src_align.toByteUnits(0),
+ operand_ty.fmt(mod), src_align.toByteUnits() orelse 0,
});
try sema.errNote(block, src, msg, "'{}' has alignment '{d}'", .{
- dest_ty.fmt(mod), dest_align.toByteUnits(0),
+ dest_ty.fmt(mod), dest_align.toByteUnits() orelse 0,
});
try sema.errNote(block, src, msg, "use @alignCast to assert pointer alignment", .{});
break :msg msg;
@@ -23067,7 +23067,7 @@ fn ptrCastFull(
if (!dest_align.check(addr)) {
return sema.fail(block, operand_src, "pointer address 0x{X} is not aligned to {d} bytes", .{
addr,
- dest_align.toByteUnitsOptional().?,
+ dest_align.toByteUnits().?,
});
}
}
@@ -23110,7 +23110,7 @@ fn ptrCastFull(
dest_align.compare(.gt, src_align) and
try sema.typeHasRuntimeBits(Type.fromInterned(dest_info.child)))
{
- const align_bytes_minus_1 = dest_align.toByteUnitsOptional().? - 1;
+ const align_bytes_minus_1 = dest_align.toByteUnits().? - 1;
const align_minus_1 = Air.internedToRef((try mod.intValue(Type.usize, align_bytes_minus_1)).toIntern());
const ptr_int = try block.addUnOp(.int_from_ptr, ptr);
const remainder = try block.addBinOp(.bit_and, ptr_int, align_minus_1);
@@ -27837,7 +27837,7 @@ fn structFieldPtrByIndex(
const elem_size_bits = Type.fromInterned(ptr_ty_data.child).bitSize(mod);
if (elem_size_bytes * 8 == elem_size_bits) {
const byte_offset = ptr_ty_data.packed_offset.bit_offset / 8;
- const new_align: Alignment = @enumFromInt(@ctz(byte_offset | parent_align.toByteUnitsOptional().?));
+ const new_align: Alignment = @enumFromInt(@ctz(byte_offset | parent_align.toByteUnits().?));
assert(new_align != .none);
ptr_ty_data.flags.alignment = new_align;
ptr_ty_data.packed_offset = .{ .host_size = 0, .bit_offset = 0 };
@@ -29132,7 +29132,7 @@ fn coerceExtra(
.addr = .{ .int = if (dest_info.flags.alignment != .none)
(try mod.intValue(
Type.usize,
- dest_info.flags.alignment.toByteUnitsOptional().?,
+ dest_info.flags.alignment.toByteUnits().?,
)).toIntern()
else
try mod.intern_pool.getCoercedInts(
@@ -29800,7 +29800,7 @@ const InMemoryCoercionResult = union(enum) {
},
.ptr_alignment => |pair| {
try sema.errNote(block, src, msg, "pointer alignment '{d}' cannot cast into pointer alignment '{d}'", .{
- pair.actual.toByteUnits(0), pair.wanted.toByteUnits(0),
+ pair.actual.toByteUnits() orelse 0, pair.wanted.toByteUnits() orelse 0,
});
break;
},
src/target.zig
@@ -525,7 +525,7 @@ pub fn backendSupportsFeature(
.error_return_trace => use_llvm,
.is_named_enum_value => use_llvm,
.error_set_has_value => use_llvm or cpu_arch.isWasm(),
- .field_reordering => use_llvm,
+ .field_reordering => ofmt == .c or use_llvm,
.safety_checked_instructions => use_llvm,
};
}
src/type.zig
@@ -203,7 +203,7 @@ pub const Type = struct {
info.flags.alignment
else
Type.fromInterned(info.child).abiAlignment(mod);
- try writer.print("align({d}", .{alignment.toByteUnits(0)});
+ try writer.print("align({d}", .{alignment.toByteUnits() orelse 0});
if (info.packed_offset.bit_offset != 0 or info.packed_offset.host_size != 0) {
try writer.print(":{d}:{d}", .{
@@ -863,7 +863,7 @@ pub const Type = struct {
pub fn lazyAbiAlignment(ty: Type, mod: *Module) !Value {
switch (try ty.abiAlignmentAdvanced(mod, .lazy)) {
.val => |val| return val,
- .scalar => |x| return mod.intValue(Type.comptime_int, x.toByteUnits(0)),
+ .scalar => |x| return mod.intValue(Type.comptime_int, x.toByteUnits() orelse 0),
}
}
@@ -905,7 +905,7 @@ pub const Type = struct {
return .{ .scalar = intAbiAlignment(int_type.bits, target) };
},
.ptr_type, .anyframe_type => {
- return .{ .scalar = Alignment.fromByteUnits(@divExact(target.ptrBitWidth(), 8)) };
+ return .{ .scalar = ptrAbiAlignment(target) };
},
.array_type => |array_type| {
return Type.fromInterned(array_type.child).abiAlignmentAdvanced(mod, strat);
@@ -920,6 +920,9 @@ pub const Type = struct {
const alignment = std.math.ceilPowerOfTwoAssert(u32, bytes);
return .{ .scalar = Alignment.fromByteUnits(alignment) };
},
+ .stage2_c => {
+ return Type.fromInterned(vector_type.child).abiAlignmentAdvanced(mod, strat);
+ },
.stage2_x86_64 => {
if (vector_type.child == .bool_type) {
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 {
.usize,
.isize,
+ => return .{ .scalar = intAbiAlignment(target.ptrBitWidth(), target) },
+
.export_options,
.extern_options,
.type_info,
- => return .{
- .scalar = Alignment.fromByteUnits(@divExact(target.ptrBitWidth(), 8)),
- },
+ => return .{ .scalar = ptrAbiAlignment(target) },
.c_char => return .{ .scalar = cTypeAlign(target, .char) },
.c_short => return .{ .scalar = cTypeAlign(target, .short) },
@@ -1160,9 +1163,7 @@ pub const Type = struct {
const child_type = ty.optionalChild(mod);
switch (child_type.zigTypeTag(mod)) {
- .Pointer => return .{
- .scalar = Alignment.fromByteUnits(@divExact(target.ptrBitWidth(), 8)),
- },
+ .Pointer => return .{ .scalar = ptrAbiAlignment(target) },
.ErrorSet => return abiAlignmentAdvanced(Type.anyerror, mod, strat),
.NoReturn => return .{ .scalar = .@"1" },
else => {},
@@ -1274,6 +1275,10 @@ pub const Type = struct {
const total_bits = elem_bits * vector_type.len;
break :total_bytes (total_bits + 7) / 8;
},
+ .stage2_c => total_bytes: {
+ const elem_bytes: u32 = @intCast((try Type.fromInterned(vector_type.child).abiSizeAdvanced(mod, strat)).scalar);
+ break :total_bytes elem_bytes * vector_type.len;
+ },
.stage2_x86_64 => total_bytes: {
if (vector_type.child == .bool_type) break :total_bytes std.math.divCeil(u32, vector_type.len, 8) catch unreachable;
const elem_bytes: u32 = @intCast((try Type.fromInterned(vector_type.child).abiSizeAdvanced(mod, strat)).scalar);
@@ -1527,15 +1532,19 @@ pub const Type = struct {
// guaranteed to be >= that of bool's (1 byte) the added size is exactly equal
// to the child type's ABI alignment.
return AbiSizeAdvanced{
- .scalar = child_ty.abiAlignment(mod).toByteUnits(0) + payload_size,
+ .scalar = (child_ty.abiAlignment(mod).toByteUnits() orelse 0) + payload_size,
};
}
- fn intAbiSize(bits: u16, target: Target) u64 {
+ pub fn ptrAbiAlignment(target: Target) Alignment {
+ return Alignment.fromNonzeroByteUnits(@divExact(target.ptrBitWidth(), 8));
+ }
+
+ pub fn intAbiSize(bits: u16, target: Target) u64 {
return intAbiAlignment(bits, target).forward(@as(u16, @intCast((@as(u17, bits) + 7) / 8)));
}
- fn intAbiAlignment(bits: u16, target: Target) Alignment {
+ pub fn intAbiAlignment(bits: u16, target: Target) Alignment {
return Alignment.fromByteUnits(@min(
std.math.ceilPowerOfTwoPromote(u16, @as(u16, @intCast((@as(u17, bits) + 7) / 8))),
target.maxIntAlignment(),
@@ -1572,7 +1581,7 @@ pub const Type = struct {
if (len == 0) return 0;
const elem_ty = Type.fromInterned(array_type.child);
const elem_size = @max(
- (try elem_ty.abiAlignmentAdvanced(mod, strat)).scalar.toByteUnits(0),
+ (try elem_ty.abiAlignmentAdvanced(mod, strat)).scalar.toByteUnits() orelse 0,
(try elem_ty.abiSizeAdvanced(mod, strat)).scalar,
);
if (elem_size == 0) return 0;
@@ -3016,26 +3025,15 @@ pub const Type = struct {
}
/// Returns none in the case of a tuple which uses the integer index as the field name.
- pub fn structFieldName(ty: Type, field_index: u32, mod: *Module) InternPool.OptionalNullTerminatedString {
+ pub fn structFieldName(ty: Type, index: usize, mod: *Module) InternPool.OptionalNullTerminatedString {
const ip = &mod.intern_pool;
return switch (ip.indexToKey(ty.toIntern())) {
- .struct_type => ip.loadStructType(ty.toIntern()).fieldName(ip, field_index),
- .anon_struct_type => |anon_struct| anon_struct.fieldName(ip, field_index),
+ .struct_type => ip.loadStructType(ty.toIntern()).fieldName(ip, index),
+ .anon_struct_type => |anon_struct| anon_struct.fieldName(ip, index),
else => unreachable,
};
}
- /// When struct types have no field names, the names are implicitly understood to be
- /// strings corresponding to the field indexes in declaration order. It used to be the
- /// case that a NullTerminatedString would be stored for each field in this case, however,
- /// now, callers must handle the possibility that there are no names stored at all.
- /// Here we fake the previous behavior. Probably something better could be done by examining
- /// all the callsites of this function.
- pub fn legacyStructFieldName(ty: Type, i: u32, mod: *Module) InternPool.NullTerminatedString {
- return ty.structFieldName(i, mod).unwrap() orelse
- mod.intern_pool.getOrPutStringFmt(mod.gpa, "{d}", .{i}) catch @panic("OOM");
- }
-
pub fn structFieldCount(ty: Type, mod: *Module) u32 {
const ip = &mod.intern_pool;
return switch (ip.indexToKey(ty.toIntern())) {
src/Value.zig
@@ -176,7 +176,7 @@ pub fn toBigIntAdvanced(
if (opt_sema) |sema| try sema.resolveTypeLayout(Type.fromInterned(ty));
const x = switch (int.storage) {
else => unreachable,
- .lazy_align => Type.fromInterned(ty).abiAlignment(mod).toByteUnits(0),
+ .lazy_align => Type.fromInterned(ty).abiAlignment(mod).toByteUnits() orelse 0,
.lazy_size => Type.fromInterned(ty).abiSize(mod),
};
return BigIntMutable.init(&space.limbs, x).toConst();
@@ -237,9 +237,9 @@ pub fn getUnsignedIntAdvanced(val: Value, mod: *Module, opt_sema: ?*Sema) !?u64
.u64 => |x| x,
.i64 => |x| std.math.cast(u64, x),
.lazy_align => |ty| if (opt_sema) |sema|
- (try Type.fromInterned(ty).abiAlignmentAdvanced(mod, .{ .sema = sema })).scalar.toByteUnits(0)
+ (try Type.fromInterned(ty).abiAlignmentAdvanced(mod, .{ .sema = sema })).scalar.toByteUnits() orelse 0
else
- Type.fromInterned(ty).abiAlignment(mod).toByteUnits(0),
+ Type.fromInterned(ty).abiAlignment(mod).toByteUnits() orelse 0,
.lazy_size => |ty| if (opt_sema) |sema|
(try Type.fromInterned(ty).abiSizeAdvanced(mod, .{ .sema = sema })).scalar
else
@@ -289,7 +289,7 @@ pub fn toSignedInt(val: Value, mod: *Module) i64 {
.big_int => |big_int| big_int.to(i64) catch unreachable,
.i64 => |x| x,
.u64 => |x| @intCast(x),
- .lazy_align => |ty| @intCast(Type.fromInterned(ty).abiAlignment(mod).toByteUnits(0)),
+ .lazy_align => |ty| @intCast(Type.fromInterned(ty).abiAlignment(mod).toByteUnits() orelse 0),
.lazy_size => |ty| @intCast(Type.fromInterned(ty).abiSize(mod)),
},
else => unreachable,
@@ -497,7 +497,7 @@ pub fn writeToPackedMemory(
inline .u64, .i64 => |int| std.mem.writeVarPackedInt(buffer, bit_offset, bits, int, endian),
.big_int => |bigint| bigint.writePackedTwosComplement(buffer, bit_offset, bits, endian),
.lazy_align => |lazy_align| {
- const num = Type.fromInterned(lazy_align).abiAlignment(mod).toByteUnits(0);
+ const num = Type.fromInterned(lazy_align).abiAlignment(mod).toByteUnits() orelse 0;
std.mem.writeVarPackedInt(buffer, bit_offset, bits, num, endian);
},
.lazy_size => |lazy_size| {
@@ -890,7 +890,7 @@ pub fn toFloat(val: Value, comptime T: type, mod: *Module) T {
}
return @floatFromInt(x);
},
- .lazy_align => |ty| @floatFromInt(Type.fromInterned(ty).abiAlignment(mod).toByteUnits(0)),
+ .lazy_align => |ty| @floatFromInt(Type.fromInterned(ty).abiAlignment(mod).toByteUnits() orelse 0),
.lazy_size => |ty| @floatFromInt(Type.fromInterned(ty).abiSize(mod)),
},
.float => |float| switch (float.storage) {
@@ -1529,9 +1529,9 @@ pub fn floatFromIntScalar(val: Value, float_ty: Type, mod: *Module, opt_sema: ?*
},
inline .u64, .i64 => |x| floatFromIntInner(x, float_ty, mod),
.lazy_align => |ty| if (opt_sema) |sema| {
- return floatFromIntInner((try Type.fromInterned(ty).abiAlignmentAdvanced(mod, .{ .sema = sema })).scalar.toByteUnits(0), float_ty, mod);
+ return floatFromIntInner((try Type.fromInterned(ty).abiAlignmentAdvanced(mod, .{ .sema = sema })).scalar.toByteUnits() orelse 0, float_ty, mod);
} else {
- return floatFromIntInner(Type.fromInterned(ty).abiAlignment(mod).toByteUnits(0), float_ty, mod);
+ return floatFromIntInner(Type.fromInterned(ty).abiAlignment(mod).toByteUnits() orelse 0, float_ty, mod);
},
.lazy_size => |ty| if (opt_sema) |sema| {
return floatFromIntInner((try Type.fromInterned(ty).abiSizeAdvanced(mod, .{ .sema = sema })).scalar, float_ty, mod);
test/behavior/align.zig
@@ -624,7 +624,6 @@ test "sub-aligned pointer field access" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
- if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
// Originally reported at https://github.com/ziglang/zig/issues/14904
test/behavior/vector.zig
@@ -1176,18 +1176,22 @@ test "@shlWithOverflow" {
test "alignment of vectors" {
try expect(@alignOf(@Vector(2, u8)) == switch (builtin.zig_backend) {
else => 2,
+ .stage2_c => @alignOf(u8),
.stage2_x86_64 => 16,
});
try expect(@alignOf(@Vector(2, u1)) == switch (builtin.zig_backend) {
else => 1,
+ .stage2_c => @alignOf(u1),
.stage2_x86_64 => 16,
});
try expect(@alignOf(@Vector(1, u1)) == switch (builtin.zig_backend) {
else => 1,
+ .stage2_c => @alignOf(u1),
.stage2_x86_64 => 16,
});
try expect(@alignOf(@Vector(2, u16)) == switch (builtin.zig_backend) {
else => 4,
+ .stage2_c => @alignOf(u16),
.stage2_x86_64 => 16,
});
}
test/tests.zig
@@ -1164,19 +1164,26 @@ pub fn addModuleTests(b: *std.Build, options: ModuleTestOptions) *Step {
compile_c.addCSourceFile(.{
.file = these_tests.getEmittedBin(),
.flags = &.{
- // TODO output -std=c89 compatible C code
+ // Tracking issue for making the C backend generate C89 compatible code:
+ // https://github.com/ziglang/zig/issues/19468
"-std=c99",
"-pedantic",
"-Werror",
- // TODO stop violating these pedantic errors. spotted everywhere
+
+ // Tracking issue for making the C backend generate code
+ // that does not trigger warnings:
+ // https://github.com/ziglang/zig/issues/19467
+
+ // spotted everywhere
"-Wno-builtin-requires-header",
- // TODO stop violating these pedantic errors. spotted on linux
- "-Wno-address-of-packed-member",
+
+ // spotted on linux
"-Wno-gnu-folding-constant",
"-Wno-incompatible-function-pointer-types",
"-Wno-incompatible-pointer-types",
"-Wno-overlength-strings",
- // TODO stop violating these pedantic errors. spotted on darwin
+
+ // spotted on darwin
"-Wno-dollar-in-identifier-extension",
"-Wno-absolute-value",
},
tools/lldb_pretty_printers.py
@@ -354,7 +354,7 @@ def InstRef_SummaryProvider(value, _=None):
def InstIndex_SummaryProvider(value, _=None):
return 'instructions[%d]' % value.unsigned
-class Module_Decl__Module_Decl_Index_SynthProvider:
+class zig_DeclIndex_SynthProvider:
def __init__(self, value, _=None): self.value = value
def update(self):
try:
@@ -425,7 +425,7 @@ def InternPool_Find(thread):
for frame in thread:
ip = frame.FindVariable('ip') or frame.FindVariable('intern_pool')
if ip: return ip
- mod = frame.FindVariable('mod') or frame.FindVariable('module')
+ mod = frame.FindVariable('zcu') or frame.FindVariable('mod') or frame.FindVariable('module')
if mod:
ip = mod.GetChildMemberWithName('intern_pool')
if ip: return ip
@@ -617,7 +617,7 @@ type_tag_handlers = {
def value_Value_str_lit(payload):
for frame in payload.thread:
- mod = frame.FindVariable('mod') or frame.FindVariable('module')
+ mod = frame.FindVariable('zcu') or frame.FindVariable('mod') or frame.FindVariable('module')
if mod: break
else: return
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):
add(debugger, category='zig.stage2', type='Air.Inst::Air.Inst.Index', identifier='InstIndex', summary=True)
add(debugger, category='zig.stage2', regex=True, type=MultiArrayList_Entry('Air\\.Inst'), identifier='TagAndPayload', synth=True, inline_children=True, summary=True)
add(debugger, category='zig.stage2', regex=True, type='^Air\\.Inst\\.Data\\.Data__struct_[1-9][0-9]*$', inline_children=True, summary=True)
- add(debugger, category='zig.stage2', type='Module.Decl::Module.Decl.Index', synth=True)
+ add(debugger, category='zig.stage2', type='zig.DeclIndex', synth=True)
add(debugger, category='zig.stage2', type='Module.Namespace::Module.Namespace.Index', synth=True)
add(debugger, category='zig.stage2', type='Module.LazySrcLoc', identifier='zig_TaggedUnion', synth=True)
add(debugger, category='zig.stage2', type='InternPool.Index', synth=True)
build.zig
@@ -16,9 +16,7 @@ pub fn build(b: *std.Build) !void {
const only_c = b.option(bool, "only-c", "Translate the Zig compiler to C code, with only the C backend enabled") orelse false;
const target = t: {
var default_target: std.zig.CrossTarget = .{};
- if (only_c) {
- default_target.ofmt = .c;
- }
+ default_target.ofmt = b.option(std.Target.ObjectFormat, "ofmt", "Object format to target") orelse if (only_c) .c else null;
break :t b.standardTargetOptions(.{ .default_target = default_target });
};
CMakeLists.txt
@@ -564,7 +564,7 @@ set(ZIG_STAGE2_SOURCES
"${CMAKE_SOURCE_DIR}/src/clang_options_data.zig"
"${CMAKE_SOURCE_DIR}/src/codegen.zig"
"${CMAKE_SOURCE_DIR}/src/codegen/c.zig"
- "${CMAKE_SOURCE_DIR}/src/codegen/c/type.zig"
+ "${CMAKE_SOURCE_DIR}/src/codegen/c/Type.zig"
"${CMAKE_SOURCE_DIR}/src/codegen/llvm.zig"
"${CMAKE_SOURCE_DIR}/src/codegen/llvm/bindings.zig"
"${CMAKE_SOURCE_DIR}/src/glibc.zig"