authorgravatar for alichraghi@proton.meAli Chraghi <alichraghi@proton.me> 2026-06-30 07:32:24+03:30
committergravatar for alichraghi@proton.meAli Chraghi <alichraghi@proton.me> 2026-06-30 11:58:31+03:30
log21dd8ea1d2bd4deb0773da465bfc0031d935e3fd
tree76b2c3be2dc606807274754839ecadb1ee2b85c9
parentbac1ea6548073707a0a7d7740ce7987ffd710184

InternPool: don't store unique info for `@SpirvType`

This makes two @SpirvType with exact same type info equal unlike before. Closes #35915

4 files changed, 76 insertions(+), 71 deletions(-)

src/InternPool.zig+31-52
...@@ -2148,12 +2148,26 @@ pub const Key = union(enum) {...@@ -2148,12 +2148,26 @@ pub const Key = union(enum) {
2148 };2148 };
21492149
2150 pub const SpirvType = extern struct {2150 pub const SpirvType = extern struct {
2151 /// A `spirv_reify` instruction.2151 /// If tag is `.image`, this is the sampled type or `.none` if `usage` is `.storage`.
2152 zir_index: TrackedInst.Index,2152 /// If tag is `.sampled_image`, this is the image type.
2153 /// Always 0.2153 /// If tag is `.runtime_array`, this is the element type.
2154 padding: u32 = 0,2154 /// Otherwise this is `.none`.
2155 /// A hash of this type's attributes generated by Sema.2155 ty: Index,
2156 type_hash: u64,2156 flags: Flags,
2157
2158 pub const Flags = packed struct(u32) {
2159 tag: @typeInfo(std.lang.Type.Spirv).@"union".tag_type.?,
2160 // Image type flags
2161 usage: @typeInfo(std.lang.Type.Spirv.Image.Usage).@"union".tag_type.?,
2162 format: std.lang.Type.Spirv.Image.Format,
2163 dim: std.lang.Type.Spirv.Image.Dimensionality,
2164 depth: std.lang.Type.Spirv.Image.Depth,
2165 access: std.lang.Type.Spirv.Image.Access,
2166 is_arrayed: bool,
2167 is_multisampled: bool,
2168
2169 _: u16 = 0,
2170 };
2157 };2171 };
21582172
2159 pub const FuncType = struct {2173 pub const FuncType = struct {
...@@ -5054,6 +5068,7 @@ pub const Tag = enum(u8) {...@@ -5054,6 +5068,7 @@ pub const Tag = enum(u8) {
5054 const EnumTag = Key.EnumTag;5068 const EnumTag = Key.EnumTag;
5055 const Union = Key.Union;5069 const Union = Key.Union;
5056 const TypePointer = Key.PtrType;5070 const TypePointer = Key.PtrType;
5071 const TypeSpirv = Key.SpirvType;
50575072
5058 const struct_packed_encoding = .{5073 const struct_packed_encoding = .{
5059 .summary = .@"{.payload.name%summary#\"}",5074 .summary = .@"{.payload.name%summary#\"}",
...@@ -5266,7 +5281,7 @@ pub const Tag = enum(u8) {...@@ -5266,7 +5281,7 @@ pub const Tag = enum(u8) {
5266 },5281 },
5267 .type_enum_explicit = enum_explicit_encoding,5282 .type_enum_explicit = enum_explicit_encoding,
5268 .type_enum_nonexhaustive = enum_explicit_encoding,5283 .type_enum_nonexhaustive = enum_explicit_encoding,
5269 .type_spirv = .{ .summary = .@"{.payload.name%summary#\"}", .payload = Tag.TypeSpirv },5284 .type_spirv = .{ .payload = Tag.TypeSpirv },
5270 .type_opaque = .{5285 .type_opaque = .{
5271 .summary = .@"{.payload.name%summary#\"}",5286 .summary = .@"{.payload.name%summary#\"}",
5272 .payload = TypeOpaque,5287 .payload = TypeOpaque,
...@@ -5723,34 +5738,6 @@ pub const Tag = enum(u8) {...@@ -5723,34 +5738,6 @@ pub const Tag = enum(u8) {
5723 name_nav: Nav.Index.Optional,5738 name_nav: Nav.Index.Optional,
5724 namespace: NamespaceIndex,5739 namespace: NamespaceIndex,
5725 };5740 };
5726
5727 /// Trailing:
5728 /// 0. type_hash: PackedU64
5729 pub const TypeSpirv = struct {
5730 name: NullTerminatedString,
5731 /// The index of the `reify_spirv_type` instruction.
5732 zir_index: TrackedInst.Index,
5733 /// If tag is `.image`, this is the sampled type or `.none` if `usage` is `.storage`.
5734 /// If tag is `.sampled_image`, this is the image type.
5735 /// If tag is `.runtime_array`, this is the element type.
5736 /// Otherwise this is `.none`.
5737 ty: Index,
5738 flags: Flags,
5739
5740 pub const Flags = packed struct(u32) {
5741 tag: @typeInfo(std.lang.Type.Spirv).@"union".tag_type.?,
5742 // Image type flags
5743 usage: @typeInfo(std.lang.Type.Spirv.Image.Usage).@"union".tag_type.?,
5744 format: std.lang.Type.Spirv.Image.Format,
5745 dim: std.lang.Type.Spirv.Image.Dimensionality,
5746 depth: std.lang.Type.Spirv.Image.Depth,
5747 access: std.lang.Type.Spirv.Image.Access,
5748 is_arrayed: bool,
5749 is_multisampled: bool,
5750
5751 _: u16 = 0,
5752 };
5753 };
5754};5741};
57555742
5756/// Differentiates between user-provided and compiler-generated backing types for packed and tagged types.5743/// Differentiates between user-provided and compiler-generated backing types for packed and tagged types.
...@@ -6634,11 +6621,10 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {...@@ -6634,11 +6621,10 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {
6634 };6621 };
6635 } },6622 } },
6636 .type_spirv => .{ .spirv_type = ns: {6623 .type_spirv => .{ .spirv_type = ns: {
6637 const extra_list = unwrapped_index.getExtra(ip);6624 const extra = extraData(unwrapped_index.getExtra(ip), Tag.TypeSpirv, data);
6638 const extra = extraDataTrail(extra_list, Tag.TypeSpirv, data);
6639 break :ns .{6625 break :ns .{
6640 .zir_index = extra.data.zir_index,6626 .ty = extra.ty,
6641 .type_hash = extraData(extra_list, PackedU64, extra.end).get(),6627 .flags = extra.flags,
6642 };6628 };
6643 } },6629 } },
6644 .type_opaque => .{ .opaque_type = ns: {6630 .type_opaque => .{ .opaque_type = ns: {
...@@ -8794,15 +8780,11 @@ pub fn getReifiedSpirvType(...@@ -8794,15 +8780,11 @@ pub fn getReifiedSpirvType(
8794 gpa: Allocator,8780 gpa: Allocator,
8795 io: Io,8781 io: Io,
8796 tid: Zcu.PerThread.Id,8782 tid: Zcu.PerThread.Id,
8797 ini: struct {8783 type_spirv: Key.SpirvType,
8798 zir_index: TrackedInst.Index,
8799 type_hash: u64,
8800 type_spirv: Tag.TypeSpirv,
8801 },
8802) Allocator.Error!Index {8784) Allocator.Error!Index {
8803 var gop = try ip.getOrPutKey(gpa, io, tid, .{ .spirv_type = .{8785 var gop = try ip.getOrPutKey(gpa, io, tid, .{ .spirv_type = .{
8804 .zir_index = ini.zir_index,8786 .ty = type_spirv.ty,
8805 .type_hash = ini.type_hash,8787 .flags = type_spirv.flags,
8806 } });8788 } });
8807 defer gop.deinit();8789 defer gop.deinit();
8808 if (gop == .existing) return gop.existing;8790 if (gop == .existing) return gop.existing;
...@@ -8812,11 +8794,8 @@ pub fn getReifiedSpirvType(...@@ -8812,11 +8794,8 @@ pub fn getReifiedSpirvType(
8812 const extra = local.getMutableExtra(gpa, io);8794 const extra = local.getMutableExtra(gpa, io);
8813 try items.ensureUnusedCapacity(1);8795 try items.ensureUnusedCapacity(1);
88148796
8815 try extra.ensureUnusedCapacity(@typeInfo(Tag.TypeSpirv).@"struct".field_names.len +8797 try extra.ensureUnusedCapacity(@typeInfo(Tag.TypeSpirv).@"struct".field_names.len);
8816 2 // type_hash: PackedU648798 const extra_index = addExtraAssumeCapacity(extra, type_spirv);
8817 );
8818 const extra_index = addExtraAssumeCapacity(extra, ini.type_spirv);
8819 _ = addExtraAssumeCapacity(extra, PackedU64.init(ini.type_hash));
88208799
8821 items.appendAssumeCapacity(.{ .tag = .type_spirv, .data = extra_index });8800 items.appendAssumeCapacity(.{ .tag = .type_spirv, .data = extra_index });
8822 return gop.put();8801 return gop.put();
...@@ -10711,7 +10690,7 @@ fn dumpStatsFallible(ip: *const InternPool, w: *Io.Writer, arena: Allocator) !vo...@@ -10711,7 +10690,7 @@ fn dumpStatsFallible(ip: *const InternPool, w: *Io.Writer, arena: Allocator) !vo
10711 .type_optional => 0,10690 .type_optional => 0,
10712 .type_anyframe => 0,10691 .type_anyframe => 0,
10713 .type_error_union => @sizeOf(Key.ErrorUnionType),10692 .type_error_union => @sizeOf(Key.ErrorUnionType),
10714 .type_spirv => @sizeOf(Tag.TypeSpirv) + @sizeOf(PackedU64),10693 .type_spirv => @sizeOf(Tag.TypeSpirv),
10715 .type_anyerror_union => 0,10694 .type_anyerror_union => 0,
10716 .type_error_set => b: {10695 .type_error_set => b: {
10717 const info = extraData(extra_list, Tag.ErrorSet, data);10696 const info = extraData(extra_list, Tag.ErrorSet, data);
src/Sema.zig+1-17
...@@ -20544,19 +20544,9 @@ fn zirReifySpirvType(...@@ -20544,19 +20544,9 @@ fn zirReifySpirvType(
20544 return sema.failWithUseOfUndef(block, operand_src, null);20544 return sema.failWithUseOfUndef(block, operand_src, null);
20545 }20545 }
2054620546
20547 const name = try ip.getOrPutStringFmt(
20548 gpa,
20549 io,
20550 pt.tid,
20551 "{f}__SpirvType_{d}",
20552 .{ block.type_name_ctx.fmt(ip), @intFromEnum(inst) },
20553 .no_embedded_nulls,
20554 );
20555 const tag = try sema.interpretStdLangType(block, src, .fromInterned(union_val.tag), @typeInfo(std.lang.Type.Spirv).@"union".tag_type.?);20547 const tag = try sema.interpretStdLangType(block, src, .fromInterned(union_val.tag), @typeInfo(std.lang.Type.Spirv).@"union".tag_type.?);
20556 const ip_data: InternPool.Tag.TypeSpirv = switch (tag) {20548 const ip_data: InternPool.Key.SpirvType = switch (tag) {
20557 .sampler => .{20549 .sampler => .{
20558 .name = name,
20559 .zir_index = tracked_inst,
20560 .ty = .none,20550 .ty = .none,
20561 .flags = .{20551 .flags = .{
20562 .tag = .sampler,20552 .tag = .sampler,
...@@ -20651,8 +20641,6 @@ fn zirReifySpirvType(...@@ -20651,8 +20641,6 @@ fn zirReifySpirvType(
20651 }20641 }
2065220642
20653 break :ip_data .{20643 break :ip_data .{
20654 .name = name,
20655 .zir_index = tracked_inst,
20656 .ty = blk: {20644 .ty = blk: {
20657 const sampled_type = usage_val.unionPayload(zcu).toType();20645 const sampled_type = usage_val.unionPayload(zcu).toType();
2065820646
...@@ -20728,8 +20716,6 @@ fn zirReifySpirvType(...@@ -20728,8 +20716,6 @@ fn zirReifySpirvType(
20728 return sema.fail(block, operand_src, "'sampled_image' element must be an image with 'usage = .sampled'", .{});20716 return sema.fail(block, operand_src, "'sampled_image' element must be an image with 'usage = .sampled'", .{});
20729 }20717 }
20730 break :blk .{20718 break :blk .{
20731 .name = name,
20732 .zir_index = tracked_inst,
20733 .ty = union_val.val,20719 .ty = union_val.val,
20734 .flags = .{20720 .flags = .{
20735 .tag = tag,20721 .tag = tag,
...@@ -20755,8 +20741,6 @@ fn zirReifySpirvType(...@@ -20755,8 +20741,6 @@ fn zirReifySpirvType(
20755 return sema.fail(block, operand_src, "'runtime_array' of 'runtime_array' is not allowed under the 'vulkan' os", .{});20741 return sema.fail(block, operand_src, "'runtime_array' of 'runtime_array' is not allowed under the 'vulkan' os", .{});
20756 }20742 }
20757 break :blk .{20743 break :blk .{
20758 .name = name,
20759 .zir_index = tracked_inst,
20760 .ty = union_val.val,20744 .ty = union_val.val,
20761 .flags = .{20745 .flags = .{
20762 .tag = tag,20746 .tag = tag,
src/Type.zig+15-2
...@@ -619,8 +619,21 @@ pub fn print(ty: Type, writer: *std.Io.Writer, pt: Zcu.PerThread, ctx: ?*Compari...@@ -619,8 +619,21 @@ pub fn print(ty: Type, writer: *std.Io.Writer, pt: Zcu.PerThread, ctx: ?*Compari
619 try writer.print("{f}", .{name.fmt(ip)});619 try writer.print("{f}", .{name.fmt(ip)});
620 },620 },
621 .spirv_type => {621 .spirv_type => {
622 const name = ip.loadSpirvType(ty.toIntern()).name;622 const info = ip.loadSpirvType(ty.toIntern());
623 try writer.print("{f}", .{name.fmt(ip)});623 switch (info.flags.tag) {
624 .sampler => try writer.writeAll("@SpirvType(.sampler)"),
625 .image => try writer.writeAll("@SpirvType(.image)"),
626 .sampled_image => {
627 try writer.writeAll("@SpirvType(.sampled_image, ");
628 try print(Type.fromInterned(info.ty), writer, pt, ctx);
629 try writer.writeAll(")");
630 },
631 .runtime_array => {
632 try writer.writeAll("@SpirvType(.runtime_array, ");
633 try print(Type.fromInterned(info.ty), writer, pt, ctx);
634 try writer.writeAll(")");
635 },
636 }
624 },637 },
625 .func_type => |fn_info| {638 .func_type => |fn_info| {
626 if (fn_info.is_noinline) {639 if (fn_info.is_noinline) {
test/behavior/spirv.zig+29
...@@ -1,3 +1,6 @@...@@ -1,3 +1,6 @@
1const std = @import("std");
2const expect = std.testing.expect;
3
1const Sampler = @SpirvType(.sampler);4const Sampler = @SpirvType(.sampler);
2const Image = @SpirvType(.{ .image = .{5const Image = @SpirvType(.{ .image = .{
3 .usage = .{ .sampled = u32 },6 .usage = .{ .sampled = u32 },
...@@ -45,3 +48,29 @@ test "@SpirvType" {...@@ -45,3 +48,29 @@ test "@SpirvType" {
45 _ = storage_image;48 _ = storage_image;
46 _ = runtime_array;49 _ = runtime_array;
47}50}
51
52test "@SpirvType equality" {
53 try expect(@SpirvType(.sampler) == Sampler);
54 try expect(@SpirvType(.{ .runtime_array = u32 }) == RuntimeArray);
55 try expect(@SpirvType(.{ .sampled_image = Image }) == SampledImage);
56 try expect(@SpirvType(.{ .image = .{
57 .usage = .{ .sampled = u32 },
58 .format = .unknown,
59 .dim = .@"2d",
60 .depth = .unknown,
61 .arrayed = false,
62 .multisampled = false,
63 .access = .unknown,
64 } }) == Image);
65 try expect(@SpirvType(.{ .image = .{
66 .usage = .{ .sampled = u32 },
67 .format = .unknown,
68 .dim = .@"3d",
69 .depth = .unknown,
70 .arrayed = false,
71 .multisampled = false,
72 .access = .unknown,
73 } }) != Image);
74 try expect(@SpirvType(.{ .runtime_array = u32 }) != @SpirvType(.{ .runtime_array = u8 }));
75 try expect(@SpirvType(.sampler) != @SpirvType(.{ .runtime_array = u32 }));
76}