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) {
21482148 };
21492149
21502150 pub const SpirvType = extern struct {
2151 /// A `spirv_reify` instruction.
2152 zir_index: TrackedInst.Index,
2153 /// Always 0.
2154 padding: u32 = 0,
2155 /// A hash of this type's attributes generated by Sema.
2156 type_hash: u64,
2151 /// If tag is `.image`, this is the sampled type or `.none` if `usage` is `.storage`.
2152 /// If tag is `.sampled_image`, this is the image type.
2153 /// If tag is `.runtime_array`, this is the element type.
2154 /// Otherwise this is `.none`.
2155 ty: Index,
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 };
21572171 };
21582172
21592173 pub const FuncType = struct {
......@@ -5054,6 +5068,7 @@ pub const Tag = enum(u8) {
50545068 const EnumTag = Key.EnumTag;
50555069 const Union = Key.Union;
50565070 const TypePointer = Key.PtrType;
5071 const TypeSpirv = Key.SpirvType;
50575072
50585073 const struct_packed_encoding = .{
50595074 .summary = .@"{.payload.name%summary#\"}",
......@@ -5266,7 +5281,7 @@ pub const Tag = enum(u8) {
52665281 },
52675282 .type_enum_explicit = enum_explicit_encoding,
52685283 .type_enum_nonexhaustive = enum_explicit_encoding,
5269 .type_spirv = .{ .summary = .@"{.payload.name%summary#\"}", .payload = Tag.TypeSpirv },
5284 .type_spirv = .{ .payload = Tag.TypeSpirv },
52705285 .type_opaque = .{
52715286 .summary = .@"{.payload.name%summary#\"}",
52725287 .payload = TypeOpaque,
......@@ -5723,34 +5738,6 @@ pub const Tag = enum(u8) {
57235738 name_nav: Nav.Index.Optional,
57245739 namespace: NamespaceIndex,
57255740 };
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 };
57545741};
57555742
57565743/// 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 {
66346621 };
66356622 } },
66366623 .type_spirv => .{ .spirv_type = ns: {
6637 const extra_list = unwrapped_index.getExtra(ip);
6638 const extra = extraDataTrail(extra_list, Tag.TypeSpirv, data);
6624 const extra = extraData(unwrapped_index.getExtra(ip), Tag.TypeSpirv, data);
66396625 break :ns .{
6640 .zir_index = extra.data.zir_index,
6641 .type_hash = extraData(extra_list, PackedU64, extra.end).get(),
6626 .ty = extra.ty,
6627 .flags = extra.flags,
66426628 };
66436629 } },
66446630 .type_opaque => .{ .opaque_type = ns: {
......@@ -8794,15 +8780,11 @@ pub fn getReifiedSpirvType(
87948780 gpa: Allocator,
87958781 io: Io,
87968782 tid: Zcu.PerThread.Id,
8797 ini: struct {
8798 zir_index: TrackedInst.Index,
8799 type_hash: u64,
8800 type_spirv: Tag.TypeSpirv,
8801 },
8783 type_spirv: Key.SpirvType,
88028784) Allocator.Error!Index {
88038785 var gop = try ip.getOrPutKey(gpa, io, tid, .{ .spirv_type = .{
8804 .zir_index = ini.zir_index,
8805 .type_hash = ini.type_hash,
8786 .ty = type_spirv.ty,
8787 .flags = type_spirv.flags,
88068788 } });
88078789 defer gop.deinit();
88088790 if (gop == .existing) return gop.existing;
......@@ -8812,11 +8794,8 @@ pub fn getReifiedSpirvType(
88128794 const extra = local.getMutableExtra(gpa, io);
88138795 try items.ensureUnusedCapacity(1);
88148796
8815 try extra.ensureUnusedCapacity(@typeInfo(Tag.TypeSpirv).@"struct".field_names.len +
8816 2 // type_hash: PackedU64
8817 );
8818 const extra_index = addExtraAssumeCapacity(extra, ini.type_spirv);
8819 _ = addExtraAssumeCapacity(extra, PackedU64.init(ini.type_hash));
8797 try extra.ensureUnusedCapacity(@typeInfo(Tag.TypeSpirv).@"struct".field_names.len);
8798 const extra_index = addExtraAssumeCapacity(extra, type_spirv);
88208799
88218800 items.appendAssumeCapacity(.{ .tag = .type_spirv, .data = extra_index });
88228801 return gop.put();
......@@ -10711,7 +10690,7 @@ fn dumpStatsFallible(ip: *const InternPool, w: *Io.Writer, arena: Allocator) !vo
1071110690 .type_optional => 0,
1071210691 .type_anyframe => 0,
1071310692 .type_error_union => @sizeOf(Key.ErrorUnionType),
10714 .type_spirv => @sizeOf(Tag.TypeSpirv) + @sizeOf(PackedU64),
10693 .type_spirv => @sizeOf(Tag.TypeSpirv),
1071510694 .type_anyerror_union => 0,
1071610695 .type_error_set => b: {
1071710696 const info = extraData(extra_list, Tag.ErrorSet, data);
src/Sema.zig+1-17
......@@ -20544,19 +20544,9 @@ fn zirReifySpirvType(
2054420544 return sema.failWithUseOfUndef(block, operand_src, null);
2054520545 }
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 );
2055520547 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) {
2055720549 .sampler => .{
20558 .name = name,
20559 .zir_index = tracked_inst,
2056020550 .ty = .none,
2056120551 .flags = .{
2056220552 .tag = .sampler,
......@@ -20651,8 +20641,6 @@ fn zirReifySpirvType(
2065120641 }
2065220642
2065320643 break :ip_data .{
20654 .name = name,
20655 .zir_index = tracked_inst,
2065620644 .ty = blk: {
2065720645 const sampled_type = usage_val.unionPayload(zcu).toType();
2065820646
......@@ -20728,8 +20716,6 @@ fn zirReifySpirvType(
2072820716 return sema.fail(block, operand_src, "'sampled_image' element must be an image with 'usage = .sampled'", .{});
2072920717 }
2073020718 break :blk .{
20731 .name = name,
20732 .zir_index = tracked_inst,
2073320719 .ty = union_val.val,
2073420720 .flags = .{
2073520721 .tag = tag,
......@@ -20755,8 +20741,6 @@ fn zirReifySpirvType(
2075520741 return sema.fail(block, operand_src, "'runtime_array' of 'runtime_array' is not allowed under the 'vulkan' os", .{});
2075620742 }
2075720743 break :blk .{
20758 .name = name,
20759 .zir_index = tracked_inst,
2076020744 .ty = union_val.val,
2076120745 .flags = .{
2076220746 .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
619619 try writer.print("{f}", .{name.fmt(ip)});
620620 },
621621 .spirv_type => {
622 const name = ip.loadSpirvType(ty.toIntern()).name;
623 try writer.print("{f}", .{name.fmt(ip)});
622 const info = ip.loadSpirvType(ty.toIntern());
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 }
624637 },
625638 .func_type => |fn_info| {
626639 if (fn_info.is_noinline) {
test/behavior/spirv.zig+29
......@@ -1,3 +1,6 @@
1const std = @import("std");
2const expect = std.testing.expect;
3
14const Sampler = @SpirvType(.sampler);
25const Image = @SpirvType(.{ .image = .{
36 .usage = .{ .sampled = u32 },
......@@ -45,3 +48,29 @@ test "@SpirvType" {
4548 _ = storage_image;
4649 _ = runtime_array;
4750}
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}