authorgravatar for robin@voetter.nlRobin Voetter <robin@voetter.nl> 2023-05-29 17:22:31+02:00
committergravatar for robin@voetter.nlRobin Voetter <robin@voetter.nl> 2023-05-30 19:43:36+02:00
loge05ace76736a8500b6ffdcd2748d1cd22e3354fe
tree94b27ea85d493e86165fc8fe1b43c632c3fdd0ff
parent8c72ad5320c67de3dfc28f91375b746794fd6cd4
signaturelock-open Commit is signed but in an unrecognized format.

spirv: cache function prototypes


2 files changed, 109 insertions(+), 19 deletions(-)

src/codegen/spirv.zig+29
...@@ -1177,6 +1177,10 @@ pub const DeclGen = struct {...@@ -1177,6 +1177,10 @@ pub const DeclGen = struct {
1177 return try self.intType(.unsigned, self.getTarget().ptrBitWidth());1177 return try self.intType(.unsigned, self.getTarget().ptrBitWidth());
1178 }1178 }
11791179
1180 fn sizeType2(self: *DeclGen) !SpvRef {
1181 return try self.intType2(.unsigned, self.getTarget().ptrBitWidth());
1182 }
1183
1180 /// Generate a union type, optionally with a known field. If the tag alignment is greater1184 /// Generate a union type, optionally with a known field. If the tag alignment is greater
1181 /// than that of the payload, a regular union (non-packed, with both tag and payload), will1185 /// than that of the payload, a regular union (non-packed, with both tag and payload), will
1182 /// be generated as follows:1186 /// be generated as follows:
...@@ -1303,6 +1307,31 @@ pub const DeclGen = struct {...@@ -1303,6 +1307,31 @@ pub const DeclGen = struct {
1303 .length = len_ref,1307 .length = len_ref,
1304 } });1308 } });
1305 },1309 },
1310 .Fn => switch (repr) {
1311 .direct => {
1312 // TODO: Put this somewhere in Sema.zig
1313 if (ty.fnIsVarArgs())
1314 return self.fail("VarArgs functions are unsupported for SPIR-V", .{});
1315
1316 const param_ty_refs = try self.gpa.alloc(SpvRef, ty.fnParamLen());
1317 defer self.gpa.free(param_ty_refs);
1318 for (param_ty_refs, 0..) |*param_type, i| {
1319 param_type.* = try self.resolveType2(ty.fnParamType(i), .direct);
1320 }
1321 const return_ty_ref = try self.resolveType2(ty.fnReturnType(), .direct);
1322
1323 return try self.spv.resolve(.{ .function_type = .{
1324 .return_type = return_ty_ref,
1325 .parameters = param_ty_refs,
1326 } });
1327 },
1328 .indirect => {
1329 // TODO: Represent function pointers properly.
1330 // For now, just use an usize type.
1331 return try self.sizeType2();
1332 },
1333 },
1334
1306 else => unreachable, // TODO1335 else => unreachable, // TODO
1307 }1336 }
1308 }1337 }
src/codegen/spirv/TypeConstantCache.zig+80-19
...@@ -54,6 +54,9 @@ const Tag = enum {...@@ -54,6 +54,9 @@ const Tag = enum {
54 /// Array type54 /// Array type
55 /// data is payload to ArrayType55 /// data is payload to ArrayType
56 type_array,56 type_array,
57 /// Function (proto)type.
58 /// data is payload to FunctionType
59 type_function,
5760
58 // -- Values61 // -- Values
59 /// Value of type u862 /// Value of type u8
...@@ -90,6 +93,13 @@ const Tag = enum {...@@ -90,6 +93,13 @@ const Tag = enum {
90 const VectorType = Key.VectorType;93 const VectorType = Key.VectorType;
91 const ArrayType = Key.ArrayType;94 const ArrayType = Key.ArrayType;
9295
96 // Trailing:
97 // - [param_len]Ref: parameter types
98 const FunctionType = struct {
99 param_len: u32,
100 return_type: Ref,
101 };
102
93 const Float64 = struct {103 const Float64 = struct {
94 // Low-order 32 bits of the value.104 // Low-order 32 bits of the value.
95 low: u32,105 low: u32,
...@@ -171,6 +181,7 @@ pub const Key = union(enum) {...@@ -171,6 +181,7 @@ pub const Key = union(enum) {
171 float_type: FloatType,181 float_type: FloatType,
172 vector_type: VectorType,182 vector_type: VectorType,
173 array_type: ArrayType,183 array_type: ArrayType,
184 function_type: FunctionType,
174185
175 // -- values186 // -- values
176 int: Int,187 int: Int,
...@@ -194,6 +205,11 @@ pub const Key = union(enum) {...@@ -194,6 +205,11 @@ pub const Key = union(enum) {
194 stride: u32 = 0,205 stride: u32 = 0,
195 };206 };
196207
208 pub const FunctionType = struct {
209 return_type: Ref,
210 parameters: []const Ref,
211 };
212
197 pub const Int = struct {213 pub const Int = struct {
198 /// The type: any bitness integer.214 /// The type: any bitness integer.
199 ty: Ref,215 ty: Ref,
...@@ -254,13 +270,33 @@ pub const Key = union(enum) {...@@ -254,13 +270,33 @@ pub const Key = union(enum) {
254 .float64 => |value| std.hash.autoHash(&hasher, @bitCast(u64, value)),270 .float64 => |value| std.hash.autoHash(&hasher, @bitCast(u64, value)),
255 }271 }
256 },272 },
273 .function_type => |func| {
274 std.hash.autoHash(&hasher, func.return_type);
275 for (func.parameters) |param_type| {
276 std.hash.autoHash(&hasher, param_type);
277 }
278 },
257 inline else => |key| std.hash.autoHash(&hasher, key),279 inline else => |key| std.hash.autoHash(&hasher, key),
258 }280 }
259 return @truncate(u32, hasher.final());281 return @truncate(u32, hasher.final());
260 }282 }
261283
262 fn eql(a: Key, b: Key) bool {284 fn eql(a: Key, b: Key) bool {
263 return std.meta.eql(a, b);285 const KeyTag = @typeInfo(Key).Union.tag_type.?;
286 const a_tag: KeyTag = a;
287 const b_tag: KeyTag = b;
288 if (a_tag != b_tag) {
289 return false;
290 }
291 return switch (a) {
292 .function_type => |a_func| {
293 const b_func = a.function_type;
294 return a_func.return_type == b_func.return_type and
295 std.mem.eql(Ref, a_func.parameters, b_func.parameters);
296 },
297 // TODO: Unroll?
298 else => std.meta.eql(a, b),
299 };
264 }300 }
265301
266 pub const Adapter = struct {302 pub const Adapter = struct {
...@@ -362,6 +398,14 @@ fn emit(...@@ -362,6 +398,14 @@ fn emit(
362 try spv.decorate(result_id, .{ .ArrayStride = .{ .array_stride = array.stride } });398 try spv.decorate(result_id, .{ .ArrayStride = .{ .array_stride = array.stride } });
363 }399 }
364 },400 },
401 .function_type => |function| {
402 try section.emitRaw(spv.gpa, .OpTypeFunction, 2 + function.parameters.len);
403 section.writeOperand(IdResult, result_id);
404 section.writeOperand(IdResult, self.resultId(function.return_type));
405 for (function.parameters) |param_type| {
406 section.writeOperand(IdResult, self.resultId(param_type));
407 }
408 },
365 .int => |int| {409 .int => |int| {
366 const int_type = self.lookup(int.ty).int_type;410 const int_type = self.lookup(int.ty).int_type;
367 const ty_id = self.resultId(int.ty);411 const ty_id = self.resultId(int.ty);
...@@ -393,18 +437,6 @@ fn emit(...@@ -393,18 +437,6 @@ fn emit(
393 }437 }
394}438}
395439
396/// Get the ref for a key that has already been added to the cache.
397fn get(self: *const Self, key: Key) Ref {
398 const adapter: Key.Adapter = .{ .self = self };
399 const index = self.map.getIndexAdapted(key, adapter).?;
400 return @intToEnum(Ref, index);
401}
402
403/// Get the result-id for a key that has already been added to the cache.
404fn getId(self: *const Self, key: Key) IdResult {
405 return self.resultId(self.get(key));
406}
407
408/// Add a key to this cache. Returns a reference to the key that440/// Add a key to this cache. Returns a reference to the key that
409/// was added. The corresponding result-id can be queried using441/// was added. The corresponding result-id can be queried using
410/// self.resultId with the result.442/// self.resultId with the result.
...@@ -447,6 +479,18 @@ pub fn resolve(self: *Self, spv: *Module, key: Key) !Ref {...@@ -447,6 +479,18 @@ pub fn resolve(self: *Self, spv: *Module, key: Key) !Ref {
447 .result_id = result_id,479 .result_id = result_id,
448 .data = try self.addExtra(spv, array),480 .data = try self.addExtra(spv, array),
449 },481 },
482 .function_type => |function| blk: {
483 const extra = try self.addExtra(spv, Tag.FunctionType{
484 .param_len = @intCast(u32, function.parameters.len),
485 .return_type = function.return_type,
486 });
487 try self.extra.appendSlice(spv.gpa, @ptrCast([]const u32, function.parameters));
488 break :blk .{
489 .tag = .type_function,
490 .result_id = result_id,
491 .data = extra,
492 };
493 },
450 .int => |int| blk: {494 .int => |int| blk: {
451 const int_type = self.lookup(int.ty).int_type;495 const int_type = self.lookup(int.ty).int_type;
452 if (int_type.signedness == .unsigned and int_type.bits == 8) {496 if (int_type.signedness == .unsigned and int_type.bits == 8) {
...@@ -523,13 +567,8 @@ pub fn resolve(self: *Self, spv: *Module, key: Key) !Ref {...@@ -523,13 +567,8 @@ pub fn resolve(self: *Self, spv: *Module, key: Key) !Ref {
523 return @intToEnum(Ref, entry.index);567 return @intToEnum(Ref, entry.index);
524}568}
525569
526/// Look op the result-id that corresponds to a particular
527/// ref.
528pub fn resultId(self: Self, ref: Ref) IdResult {
529 return self.items.items(.result_id)[@enumToInt(ref)];
530}
531
532/// Turn a Ref back into a Key.570/// Turn a Ref back into a Key.
571/// The Key is valid until the next call to resolve().
533pub fn lookup(self: *const Self, ref: Ref) Key {572pub fn lookup(self: *const Self, ref: Ref) Key {
534 const item = self.items.get(@enumToInt(ref));573 const item = self.items.get(@enumToInt(ref));
535 const data = item.data;574 const data = item.data;
...@@ -551,6 +590,15 @@ pub fn lookup(self: *const Self, ref: Ref) Key {...@@ -551,6 +590,15 @@ pub fn lookup(self: *const Self, ref: Ref) Key {
551 } },590 } },
552 .type_vector => .{ .vector_type = self.extraData(Tag.VectorType, data) },591 .type_vector => .{ .vector_type = self.extraData(Tag.VectorType, data) },
553 .type_array => .{ .array_type = self.extraData(Tag.ArrayType, data) },592 .type_array => .{ .array_type = self.extraData(Tag.ArrayType, data) },
593 .type_function => {
594 const payload = self.extraDataTrail(Tag.FunctionType, data);
595 return .{
596 .function_type = .{
597 .return_type = payload.data.return_type,
598 .parameters = @ptrCast([]const Ref, self.extra.items[payload.trail..][0..payload.data.param_len]),
599 },
600 };
601 },
554 .float16 => .{ .float = .{602 .float16 => .{ .float = .{
555 .ty = self.get(.{ .float_type = .{ .bits = 16 } }),603 .ty = self.get(.{ .float_type = .{ .bits = 16 } }),
556 .value = .{ .float16 = @bitCast(f16, @intCast(u16, data)) },604 .value = .{ .float16 = @bitCast(f16, @intCast(u16, data)) },
...@@ -602,6 +650,19 @@ pub fn lookup(self: *const Self, ref: Ref) Key {...@@ -602,6 +650,19 @@ pub fn lookup(self: *const Self, ref: Ref) Key {
602 };650 };
603}651}
604652
653/// Look op the result-id that corresponds to a particular
654/// ref.
655pub fn resultId(self: Self, ref: Ref) IdResult {
656 return self.items.items(.result_id)[@enumToInt(ref)];
657}
658
659/// Get the ref for a key that has already been added to the cache.
660fn get(self: *const Self, key: Key) Ref {
661 const adapter: Key.Adapter = .{ .self = self };
662 const index = self.map.getIndexAdapted(key, adapter).?;
663 return @intToEnum(Ref, index);
664}
665
605fn addExtra(self: *Self, spv: *Module, extra: anytype) !u32 {666fn addExtra(self: *Self, spv: *Module, extra: anytype) !u32 {
606 const fields = @typeInfo(@TypeOf(extra)).Struct.fields;667 const fields = @typeInfo(@TypeOf(extra)).Struct.fields;
607 try self.extra.ensureUnusedCapacity(spv.gpa, fields.len);668 try self.extra.ensureUnusedCapacity(spv.gpa, fields.len);