| ... | @@ -54,6 +54,9 @@ const Tag = enum { | ... | @@ -54,6 +54,9 @@ const Tag = enum { |
| 54 | /// Array type | 54 | /// Array type |
| 55 | /// data is payload to ArrayType | 55 | /// data is payload to ArrayType |
| 56 | type_array, | 56 | type_array, |
| | 57 | /// Function (proto)type. |
| | 58 | /// data is payload to FunctionType |
| | 59 | type_function, |
| 57 | | 60 | |
| 58 | // -- Values | 61 | // -- Values |
| 59 | /// Value of type u8 | 62 | /// 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; |
| 92 | | 95 | |
| | 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, |
| 174 | | 185 | |
| 175 | // -- values | 186 | // -- 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 | }; |
| 196 | | 207 | |
| | 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 | } |
| 261 | | 283 | |
| 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 | } |
| 265 | | 301 | |
| 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 | } |
| 395 | | 439 | |
| 396 | /// Get the ref for a key that has already been added to the cache. | | |
| 397 | fn 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. | | |
| 404 | fn 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 that | 440 | /// Add a key to this cache. Returns a reference to the key that |
| 409 | /// was added. The corresponding result-id can be queried using | 441 | /// 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 | } |
| 525 | | 569 | |
| 526 | /// Look op the result-id that corresponds to a particular | | |
| 527 | /// ref. | | |
| 528 | pub 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(). |
| 533 | pub fn lookup(self: *const Self, ref: Ref) Key { | 572 | pub 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 | } |
| 604 | | 652 | |
| | 653 | /// Look op the result-id that corresponds to a particular |
| | 654 | /// ref. |
| | 655 | pub 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. |
| | 660 | fn 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 | |
| 605 | fn addExtra(self: *Self, spv: *Module, extra: anytype) !u32 { | 666 | fn 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); |