authorgravatar for robin@voetter.nlRobin Voetter <robin@voetter.nl> 2023-10-07 14:21:59+02:00
committergravatar for robin@voetter.nlRobin Voetter <robin@voetter.nl> 2023-10-15 13:59:24+02:00
logab701c3d375b102bc291f80a791109cb109964ba
tree59674ae05f842a378498ad86e4b84f070d7a4bdd
parent08ea9a9ff6962c40eb87ab4951bc07a05b3831c9
signaturebadge-check Signed by SSH key SHA256:CQ99aPxq+RueiL9u7z0FEki5Fm7V6T8q4PrEGmINrA4

spirv: anon decl refs


3 files changed, 163 insertions(+), 5 deletions(-)

src/codegen/llvm.zig+1
...@@ -3050,6 +3050,7 @@ pub const Object = struct {...@@ -3050,6 +3050,7 @@ pub const Object = struct {
3050 decl_val: InternPool.Index,3050 decl_val: InternPool.Index,
3051 llvm_addr_space: Builder.AddrSpace,3051 llvm_addr_space: Builder.AddrSpace,
3052 ) Error!Builder.Variable.Index {3052 ) Error!Builder.Variable.Index {
3053 // TODO: Add address space to the anon_decl_map
3053 const gop = try o.anon_decl_map.getOrPut(o.gpa, decl_val);3054 const gop = try o.anon_decl_map.getOrPut(o.gpa, decl_val);
3054 if (gop.found_existing) return gop.value_ptr.ptr(&o.builder).kind.variable;3055 if (gop.found_existing) return gop.value_ptr.ptr(&o.builder).kind.variable;
3055 errdefer assert(o.anon_decl_map.remove(decl_val));3056 errdefer assert(o.anon_decl_map.remove(decl_val));
src/codegen/spirv.zig+157-3
...@@ -52,9 +52,12 @@ const Block = struct {...@@ -52,9 +52,12 @@ const Block = struct {
5252
53const BlockMap = std.AutoHashMapUnmanaged(Air.Inst.Index, *Block);53const BlockMap = std.AutoHashMapUnmanaged(Air.Inst.Index, *Block);
5454
55/// Maps Zig decl indices to linking SPIR-V linking information.55/// Maps Zig decl indices to SPIR-V linking information.
56pub const DeclLinkMap = std.AutoHashMap(Module.Decl.Index, SpvModule.Decl.Index);56pub const DeclLinkMap = std.AutoHashMap(Module.Decl.Index, SpvModule.Decl.Index);
5757
58/// Maps anon decl indices to SPIR-V linking information.
59pub const AnonDeclLinkMap = std.AutoHashMap(struct { InternPool.Index, StorageClass }, SpvModule.Decl.Index);
60
58/// This structure is used to compile a declaration, and contains all relevant meta-information to deal with that.61/// This structure is used to compile a declaration, and contains all relevant meta-information to deal with that.
59pub const DeclGen = struct {62pub const DeclGen = struct {
60 /// A general-purpose allocator that can be used for any allocations for this DeclGen.63 /// A general-purpose allocator that can be used for any allocations for this DeclGen.
...@@ -77,9 +80,12 @@ pub const DeclGen = struct {...@@ -77,9 +80,12 @@ pub const DeclGen = struct {
77 /// Note: If the declaration is not a function, this value will be undefined!80 /// Note: If the declaration is not a function, this value will be undefined!
78 liveness: Liveness,81 liveness: Liveness,
7982
80 /// Maps Zig Decl indices to SPIR-V globals.83 /// Maps Zig Decl indices to SPIR-V decl indices.
81 decl_link: *DeclLinkMap,84 decl_link: *DeclLinkMap,
8285
86 /// Maps Zig anon decl indices to SPIR-V decl indices.
87 anon_decl_link: *AnonDeclLinkMap,
88
83 /// An array of function argument result-ids. Each index corresponds with the89 /// An array of function argument result-ids. Each index corresponds with the
84 /// function argument of the same index.90 /// function argument of the same index.
85 args: std.ArrayListUnmanaged(IdRef) = .{},91 args: std.ArrayListUnmanaged(IdRef) = .{},
...@@ -182,6 +188,7 @@ pub const DeclGen = struct {...@@ -182,6 +188,7 @@ pub const DeclGen = struct {
182 module: *Module,188 module: *Module,
183 spv: *SpvModule,189 spv: *SpvModule,
184 decl_link: *DeclLinkMap,190 decl_link: *DeclLinkMap,
191 anon_decl_link: *AnonDeclLinkMap,
185 ) DeclGen {192 ) DeclGen {
186 return .{193 return .{
187 .gpa = allocator,194 .gpa = allocator,
...@@ -191,6 +198,7 @@ pub const DeclGen = struct {...@@ -191,6 +198,7 @@ pub const DeclGen = struct {
191 .air = undefined,198 .air = undefined,
192 .liveness = undefined,199 .liveness = undefined,
193 .decl_link = decl_link,200 .decl_link = decl_link,
201 .anon_decl_link = anon_decl_link,
194 .next_arg_index = undefined,202 .next_arg_index = undefined,
195 .current_block_label_id = undefined,203 .current_block_label_id = undefined,
196 .error_msg = undefined,204 .error_msg = undefined,
...@@ -301,6 +309,89 @@ pub const DeclGen = struct {...@@ -301,6 +309,89 @@ pub const DeclGen = struct {
301 return entry.value_ptr.*;309 return entry.value_ptr.*;
302 }310 }
303311
312 fn resolveAnonDecl(self: *DeclGen, val: InternPool.Index, storage_class: StorageClass) !IdRef {
313 // TODO: This cannot be a function at this point, but it should probably be handled anyway.
314 const spv_decl_index = blk: {
315 const entry = try self.anon_decl_link.getOrPut(.{ val, storage_class });
316 if (entry.found_existing) {
317 try self.func.decl_deps.put(self.spv.gpa, entry.value_ptr.*, {});
318 return self.spv.declPtr(entry.value_ptr.*).result_id;
319 }
320
321 const spv_decl_index = try self.spv.allocDecl(.global);
322 try self.func.decl_deps.put(self.spv.gpa, spv_decl_index, {});
323 entry.value_ptr.* = spv_decl_index;
324 break :blk spv_decl_index;
325 };
326
327 const mod = self.module;
328 const ty = mod.intern_pool.typeOf(val).toType();
329 const ty_ref = try self.resolveType(ty, .indirect);
330 const ptr_ty_ref = try self.spv.ptrType(ty_ref, storage_class);
331
332 const var_id = self.spv.declPtr(spv_decl_index).result_id;
333
334 const section = &self.spv.sections.types_globals_constants;
335 try section.emit(self.spv.gpa, .OpVariable, .{
336 .id_result_type = self.typeId(ptr_ty_ref),
337 .id_result = var_id,
338 .storage_class = storage_class,
339 });
340
341 // TODO: At some point we will be able to generate this all constant here, but then all of
342 // constant() will need to be implemented such that it doesn't generate any at-runtime code.
343 // NOTE: Because this is a global, we really only want to initialize it once. Therefore the
344 // constant lowering of this value will need to be deferred to some other function, which
345 // is then added to the list of initializers using endGlobal().
346
347 // Save the current state so that we can temporarily generate into a different function.
348 // TODO: This should probably be made a little more robust.
349 const func = self.func;
350 defer self.func = func;
351 const block_label_id = self.current_block_label_id;
352 defer self.current_block_label_id = block_label_id;
353
354 self.func = .{};
355
356 // TODO: Merge this with genDecl?
357 const begin = self.spv.beginGlobal();
358
359 const void_ty_ref = try self.resolveType(Type.void, .direct);
360 const initializer_proto_ty_ref = try self.spv.resolve(.{ .function_type = .{
361 .return_type = void_ty_ref,
362 .parameters = &.{},
363 } });
364
365 const initializer_id = self.spv.allocId();
366 try self.func.prologue.emit(self.spv.gpa, .OpFunction, .{
367 .id_result_type = self.typeId(void_ty_ref),
368 .id_result = initializer_id,
369 .function_control = .{},
370 .function_type = self.typeId(initializer_proto_ty_ref),
371 });
372 const root_block_id = self.spv.allocId();
373 try self.func.prologue.emit(self.spv.gpa, .OpLabel, .{
374 .id_result = root_block_id,
375 });
376 self.current_block_label_id = root_block_id;
377
378 const val_id = try self.constant(ty, val.toValue(), .indirect);
379 try self.func.body.emit(self.spv.gpa, .OpStore, .{
380 .pointer = var_id,
381 .object = val_id,
382 });
383
384 self.spv.endGlobal(spv_decl_index, begin, var_id, initializer_id);
385 try self.func.body.emit(self.spv.gpa, .OpReturn, {});
386 try self.func.body.emit(self.spv.gpa, .OpFunctionEnd, {});
387 try self.spv.addFunction(spv_decl_index, self.func);
388
389 try self.spv.debugNameFmt(var_id, "__anon_{d}", .{@intFromEnum(val)});
390 try self.spv.debugNameFmt(initializer_id, "initializer of __anon_{d}", .{@intFromEnum(val)});
391
392 return var_id;
393 }
394
304 /// Start a new SPIR-V block, Emits the label of the new block, and stores which395 /// Start a new SPIR-V block, Emits the label of the new block, and stores which
305 /// block we are currently generating.396 /// block we are currently generating.
306 /// Note that there is no such thing as nested blocks like in ZIR or AIR, so we don't need to397 /// Note that there is no such thing as nested blocks like in ZIR or AIR, so we don't need to
...@@ -767,7 +858,7 @@ pub const DeclGen = struct {...@@ -767,7 +858,7 @@ pub const DeclGen = struct {
767 switch (mod.intern_pool.indexToKey(ptr_val.toIntern()).ptr.addr) {858 switch (mod.intern_pool.indexToKey(ptr_val.toIntern()).ptr.addr) {
768 .decl => |decl| return try self.constantDeclRef(ptr_ty, decl),859 .decl => |decl| return try self.constantDeclRef(ptr_ty, decl),
769 .mut_decl => |decl_mut| return try self.constantDeclRef(ptr_ty, decl_mut.decl),860 .mut_decl => |decl_mut| return try self.constantDeclRef(ptr_ty, decl_mut.decl),
770 .anon_decl => @panic("TODO"),861 .anon_decl => |anon_decl| return try self.constantAnonDeclRef(ptr_ty, anon_decl),
771 .int => |int| {862 .int => |int| {
772 const ptr_id = self.spv.allocId();863 const ptr_id = self.spv.allocId();
773 // TODO: This can probably be an OpSpecConstantOp Bitcast, but864 // TODO: This can probably be an OpSpecConstantOp Bitcast, but
...@@ -813,6 +904,69 @@ pub const DeclGen = struct {...@@ -813,6 +904,69 @@ pub const DeclGen = struct {
813 }904 }
814 }905 }
815906
907 fn constantAnonDeclRef(self: *DeclGen, ty: Type, decl_val: InternPool.Index) !IdRef {
908 // TODO: Merge this function with constantDeclRef.
909
910 const mod = self.module;
911 const ip = &mod.intern_pool;
912 const ty_ref = try self.resolveType(ty, .direct);
913 const decl_ty = ip.typeOf(decl_val).toType();
914
915 if (decl_val.toValue().getFunction(mod)) |func| {
916 _ = func;
917 unreachable; // TODO
918 } else if (decl_val.toValue().getExternFunc(mod)) |func| {
919 _ = func;
920 unreachable;
921 }
922
923 // const is_fn_body = decl_ty.zigTypeTag(mod) == .Fn;
924 if (!decl_ty.isFnOrHasRuntimeBitsIgnoreComptime(mod)) {
925 // Pointer to nothing - return undefoined
926 return self.spv.constUndef(ty_ref);
927 }
928
929 if (decl_ty.zigTypeTag(mod) == .Fn) {
930 unreachable; // TODO
931 }
932
933 const final_storage_class = spvStorageClass(ty.ptrAddressSpace(mod));
934 const actual_storage_class = switch (final_storage_class) {
935 .Generic => .CrossWorkgroup,
936 else => |other| other,
937 };
938
939 const decl_id = try self.resolveAnonDecl(decl_val, actual_storage_class);
940 const decl_ty_ref = try self.resolveType(decl_ty, .indirect);
941 const decl_ptr_ty_ref = try self.spv.ptrType(decl_ty_ref, final_storage_class);
942
943 const ptr_id = switch (final_storage_class) {
944 .Generic => blk: {
945 const result_id = self.spv.allocId();
946 try self.func.body.emit(self.spv.gpa, .OpPtrCastToGeneric, .{
947 .id_result_type = self.typeId(decl_ptr_ty_ref),
948 .id_result = result_id,
949 .pointer = decl_id,
950 });
951 break :blk result_id;
952 },
953 else => decl_id,
954 };
955
956 if (decl_ptr_ty_ref != ty_ref) {
957 // Differing pointer types, insert a cast.
958 const casted_ptr_id = self.spv.allocId();
959 try self.func.body.emit(self.spv.gpa, .OpBitcast, .{
960 .id_result_type = self.typeId(ty_ref),
961 .id_result = casted_ptr_id,
962 .operand = ptr_id,
963 });
964 return casted_ptr_id;
965 } else {
966 return ptr_id;
967 }
968 }
969
816 fn constantDeclRef(self: *DeclGen, ty: Type, decl_index: Decl.Index) !IdRef {970 fn constantDeclRef(self: *DeclGen, ty: Type, decl_index: Decl.Index) !IdRef {
817 const mod = self.module;971 const mod = self.module;
818 const ty_ref = try self.resolveType(ty, .direct);972 const ty_ref = try self.resolveType(ty, .direct);
src/link/SpirV.zig+5-2
...@@ -48,6 +48,7 @@ base: link.File,...@@ -48,6 +48,7 @@ base: link.File,
48spv: SpvModule,48spv: SpvModule,
49spv_arena: ArenaAllocator,49spv_arena: ArenaAllocator,
50decl_link: codegen.DeclLinkMap,50decl_link: codegen.DeclLinkMap,
51anon_decl_link: codegen.AnonDeclLinkMap,
5152
52pub fn createEmpty(gpa: Allocator, options: link.Options) !*SpirV {53pub fn createEmpty(gpa: Allocator, options: link.Options) !*SpirV {
53 const self = try gpa.create(SpirV);54 const self = try gpa.create(SpirV);
...@@ -61,6 +62,7 @@ pub fn createEmpty(gpa: Allocator, options: link.Options) !*SpirV {...@@ -61,6 +62,7 @@ pub fn createEmpty(gpa: Allocator, options: link.Options) !*SpirV {
61 .spv = undefined,62 .spv = undefined,
62 .spv_arena = ArenaAllocator.init(gpa),63 .spv_arena = ArenaAllocator.init(gpa),
63 .decl_link = codegen.DeclLinkMap.init(self.base.allocator),64 .decl_link = codegen.DeclLinkMap.init(self.base.allocator),
65 .anon_decl_link = codegen.AnonDeclLinkMap.init(self.base.allocator),
64 };66 };
65 self.spv = SpvModule.init(gpa, self.spv_arena.allocator());67 self.spv = SpvModule.init(gpa, self.spv_arena.allocator());
66 errdefer self.deinit();68 errdefer self.deinit();
...@@ -102,6 +104,7 @@ pub fn deinit(self: *SpirV) void {...@@ -102,6 +104,7 @@ pub fn deinit(self: *SpirV) void {
102 self.spv.deinit();104 self.spv.deinit();
103 self.spv_arena.deinit();105 self.spv_arena.deinit();
104 self.decl_link.deinit();106 self.decl_link.deinit();
107 self.anon_decl_link.deinit();
105}108}
106109
107pub fn updateFunc(self: *SpirV, module: *Module, func_index: InternPool.Index, air: Air, liveness: Liveness) !void {110pub fn updateFunc(self: *SpirV, module: *Module, func_index: InternPool.Index, air: Air, liveness: Liveness) !void {
...@@ -113,7 +116,7 @@ pub fn updateFunc(self: *SpirV, module: *Module, func_index: InternPool.Index, a...@@ -113,7 +116,7 @@ pub fn updateFunc(self: *SpirV, module: *Module, func_index: InternPool.Index, a
113 const decl = module.declPtr(func.owner_decl);116 const decl = module.declPtr(func.owner_decl);
114 log.debug("lowering function {s}", .{module.intern_pool.stringToSlice(decl.name)});117 log.debug("lowering function {s}", .{module.intern_pool.stringToSlice(decl.name)});
115118
116 var decl_gen = codegen.DeclGen.init(self.base.allocator, module, &self.spv, &self.decl_link);119 var decl_gen = codegen.DeclGen.init(self.base.allocator, module, &self.spv, &self.decl_link, &self.anon_decl_link);
117 defer decl_gen.deinit();120 defer decl_gen.deinit();
118121
119 if (try decl_gen.gen(func.owner_decl, air, liveness)) |msg| {122 if (try decl_gen.gen(func.owner_decl, air, liveness)) |msg| {
...@@ -129,7 +132,7 @@ pub fn updateDecl(self: *SpirV, module: *Module, decl_index: Module.Decl.Index)...@@ -129,7 +132,7 @@ pub fn updateDecl(self: *SpirV, module: *Module, decl_index: Module.Decl.Index)
129 const decl = module.declPtr(decl_index);132 const decl = module.declPtr(decl_index);
130 log.debug("lowering declaration {s}", .{module.intern_pool.stringToSlice(decl.name)});133 log.debug("lowering declaration {s}", .{module.intern_pool.stringToSlice(decl.name)});
131134
132 var decl_gen = codegen.DeclGen.init(self.base.allocator, module, &self.spv, &self.decl_link);135 var decl_gen = codegen.DeclGen.init(self.base.allocator, module, &self.spv, &self.decl_link, &self.anon_decl_link);
133 defer decl_gen.deinit();136 defer decl_gen.deinit();
134137
135 if (try decl_gen.gen(decl_index, undefined, undefined)) |msg| {138 if (try decl_gen.gen(decl_index, undefined, undefined)) |msg| {