authorgravatar for robin@voetter.nlRobin Voetter <robin@voetter.nl> 2023-05-29 15:25:09+02:00
committergravatar for robin@voetter.nlRobin Voetter <robin@voetter.nl> 2023-05-30 19:43:36+02:00
log8c72ad5320c67de3dfc28f91375b746794fd6cd4
tree0de7adde3ebeaf233a0a0f0e37743087f73427e7
parentaade6f1195d64ad091c065e225184aaa52628282
signaturelock-open Commit is signed but in an unrecognized format.

spirv: cache for ints


2 files changed, 216 insertions(+), 5 deletions(-)

src/codegen/spirv.zig+7-3
...@@ -1293,10 +1293,14 @@ pub const DeclGen = struct {...@@ -1293,10 +1293,14 @@ pub const DeclGen = struct {
1293 const total_len = std.math.cast(u32, ty.arrayLenIncludingSentinel()) orelse {1293 const total_len = std.math.cast(u32, ty.arrayLenIncludingSentinel()) orelse {
1294 return self.fail("array type of {} elements is too large", .{ty.arrayLenIncludingSentinel()});1294 return self.fail("array type of {} elements is too large", .{ty.arrayLenIncludingSentinel()});
1295 };1295 };
1296 _ = total_len;1296 const len_ty_ref = try self.intType2(.unsigned, 32);
1297 return self.spv.resolve(.{ .array_type = .{1297 const len_ref = try self.spv.resolve(.{ .int = .{
1298 .ty = len_ty_ref,
1299 .value = .{ .uint64 = total_len },
1300 } });
1301 return try self.spv.resolve(.{ .array_type = .{
1298 .element_type = elem_ty_ref,1302 .element_type = elem_ty_ref,
1299 .length = @intToEnum(SpvRef, 0),1303 .length = len_ref,
1300 } });1304 } });
1301 },1305 },
1302 else => unreachable, // TODO1306 else => unreachable, // TODO
src/codegen/spirv/TypeConstantCache.zig+209-2
...@@ -56,6 +56,25 @@ const Tag = enum {...@@ -56,6 +56,25 @@ const Tag = enum {
56 type_array,56 type_array,
5757
58 // -- Values58 // -- Values
59 /// Value of type u8
60 /// data is value
61 uint8,
62 /// Value of type u32
63 /// data is value
64 uint32,
65 // TODO: More specialized tags here.
66 /// Integer value for signed values that are smaller than 32 bits.
67 /// data is pointer to Int32
68 int_small,
69 /// Integer value for unsigned values that are smaller than 32 bits.
70 /// data is pointer to UInt32
71 uint_small,
72 /// Integer value for signed values that are beteen 32 and 64 bits.
73 /// data is pointer to Int64
74 int_large,
75 /// Integer value for unsinged values that are beteen 32 and 64 bits.
76 /// data is pointer to UInt64
77 uint_large,
59 /// Value of type f1678 /// Value of type f16
60 /// data is value79 /// data is value
61 float16,80 float16,
...@@ -90,6 +109,52 @@ const Tag = enum {...@@ -90,6 +109,52 @@ const Tag = enum {
90 return @bitCast(f64, bits);109 return @bitCast(f64, bits);
91 }110 }
92 };111 };
112
113 const Int32 = struct {
114 ty: Ref,
115 value: i32,
116 };
117
118 const UInt32 = struct {
119 ty: Ref,
120 value: u32,
121 };
122
123 const UInt64 = struct {
124 ty: Ref,
125 low: u32,
126 high: u32,
127
128 fn encode(ty: Ref, value: u64) Int64 {
129 return .{
130 .ty = ty,
131 .low = @truncate(u32, value),
132 .high = @truncate(u32, value >> 32),
133 };
134 }
135
136 fn decode(self: UInt64) u64 {
137 return @as(u64, self.low) | (@as(u64, self.high) << 32);
138 }
139 };
140
141 const Int64 = struct {
142 ty: Ref,
143 low: u32,
144 high: u32,
145
146 fn encode(ty: Ref, value: i64) Int64 {
147 return .{
148 .ty = ty,
149 .low = @truncate(u32, @bitCast(u64, value)),
150 .high = @truncate(u32, @bitCast(u64, value) >> 32),
151 };
152 }
153
154 fn decode(self: Int64) i64 {
155 return @bitCast(i64, @as(u64, self.low) | (@as(u64, self.high) << 32));
156 }
157 };
93};158};
94159
95pub const Ref = enum(u32) { _ };160pub const Ref = enum(u32) { _ };
...@@ -108,6 +173,7 @@ pub const Key = union(enum) {...@@ -108,6 +173,7 @@ pub const Key = union(enum) {
108 array_type: ArrayType,173 array_type: ArrayType,
109174
110 // -- values175 // -- values
176 int: Int,
111 float: Float,177 float: Float,
112178
113 pub const IntType = std.builtin.Type.Int;179 pub const IntType = std.builtin.Type.Int;
...@@ -128,6 +194,41 @@ pub const Key = union(enum) {...@@ -128,6 +194,41 @@ pub const Key = union(enum) {
128 stride: u32 = 0,194 stride: u32 = 0,
129 };195 };
130196
197 pub const Int = struct {
198 /// The type: any bitness integer.
199 ty: Ref,
200 /// The actual value. Only uint64 and int64 types
201 /// are available here: Smaller types should use these
202 /// fields.
203 value: Value,
204
205 pub const Value = union(enum) {
206 uint64: u64,
207 int64: i64,
208 };
209
210 /// Turns this value into the corresponding 32-bit literal, 2s complement signed.
211 fn toBits32(self: Int) u32 {
212 return switch (self.value) {
213 .uint64 => |val| @intCast(u32, val),
214 .int64 => |val| if (val < 0) @bitCast(u32, @intCast(i32, val)) else @intCast(u32, val),
215 };
216 }
217
218 fn toBits64(self: Int) u64 {
219 return switch (self.value) {
220 .uint64 => |val| val,
221 .int64 => |val| @bitCast(u64, val),
222 };
223 }
224
225 fn to(self: Int, comptime T: type) T {
226 return switch (self.value) {
227 inline else => |val| @intCast(T, val),
228 };
229 }
230 };
231
131 /// Represents a numberic value of some type.232 /// Represents a numberic value of some type.
132 pub const Float = struct {233 pub const Float = struct {
133 /// The type: 16, 32, or 64-bit float.234 /// The type: 16, 32, or 64-bit float.
...@@ -212,6 +313,7 @@ fn emit(...@@ -212,6 +313,7 @@ fn emit(
212 section: *Section,313 section: *Section,
213) !void {314) !void {
214 const key = self.lookup(ref);315 const key = self.lookup(ref);
316 const Lit = spec.LiteralContextDependentNumber;
215 switch (key) {317 switch (key) {
216 .void_type => {318 .void_type => {
217 try section.emit(spv.gpa, .OpTypeVoid, .{ .id_result = result_id });319 try section.emit(spv.gpa, .OpTypeVoid, .{ .id_result = result_id });
...@@ -260,9 +362,24 @@ fn emit(...@@ -260,9 +362,24 @@ fn emit(
260 try spv.decorate(result_id, .{ .ArrayStride = .{ .array_stride = array.stride } });362 try spv.decorate(result_id, .{ .ArrayStride = .{ .array_stride = array.stride } });
261 }363 }
262 },364 },
365 .int => |int| {
366 const int_type = self.lookup(int.ty).int_type;
367 const ty_id = self.resultId(int.ty);
368 const lit: Lit = switch (int_type.bits) {
369 1...32 => .{ .uint32 = int.toBits32() },
370 33...64 => .{ .uint64 = int.toBits64() },
371 else => unreachable,
372 };
373
374 try section.emit(spv.gpa, .OpConstant, .{
375 .id_result_type = ty_id,
376 .id_result = result_id,
377 .value = lit,
378 });
379 },
263 .float => |float| {380 .float => |float| {
264 const ty_id = self.resultId(float.ty);381 const ty_id = self.resultId(float.ty);
265 const lit: spec.LiteralContextDependentNumber = switch (float.value) {382 const lit: Lit = switch (float.value) {
266 .float16 => |value| .{ .uint32 = @bitCast(u16, value) },383 .float16 => |value| .{ .uint32 = @bitCast(u16, value) },
267 .float32 => |value| .{ .float32 = value },384 .float32 => |value| .{ .float32 = value },
268 .float64 => |value| .{ .float64 = value },385 .float64 => |value| .{ .float64 = value },
...@@ -330,6 +447,58 @@ pub fn resolve(self: *Self, spv: *Module, key: Key) !Ref {...@@ -330,6 +447,58 @@ pub fn resolve(self: *Self, spv: *Module, key: Key) !Ref {
330 .result_id = result_id,447 .result_id = result_id,
331 .data = try self.addExtra(spv, array),448 .data = try self.addExtra(spv, array),
332 },449 },
450 .int => |int| blk: {
451 const int_type = self.lookup(int.ty).int_type;
452 if (int_type.signedness == .unsigned and int_type.bits == 8) {
453 break :blk .{
454 .tag = .uint8,
455 .result_id = result_id,
456 .data = int.to(u8),
457 };
458 } else if (int_type.signedness == .unsigned and int_type.bits == 32) {
459 break :blk .{
460 .tag = .uint32,
461 .result_id = result_id,
462 .data = int.to(u32),
463 };
464 }
465
466 switch (int.value) {
467 inline else => |val| {
468 if (val >= 0 and val <= std.math.maxInt(u32)) {
469 break :blk .{
470 .tag = .uint_small,
471 .result_id = result_id,
472 .data = try self.addExtra(spv, Tag.UInt32{
473 .ty = int.ty,
474 .value = @intCast(u32, val),
475 }),
476 };
477 } else if (val >= std.math.minInt(i32) and val <= std.math.maxInt(i32)) {
478 break :blk .{
479 .tag = .int_small,
480 .result_id = result_id,
481 .data = try self.addExtra(spv, Tag.Int32{
482 .ty = int.ty,
483 .value = @intCast(i32, val),
484 }),
485 };
486 } else if (val < 0) {
487 break :blk .{
488 .tag = .int_large,
489 .result_id = result_id,
490 .data = try self.addExtra(spv, Tag.Int64.encode(int.ty, @intCast(i64, val))),
491 };
492 } else {
493 break :blk .{
494 .tag = .uint_large,
495 .result_id = result_id,
496 .data = try self.addExtra(spv, Tag.UInt64.encode(int.ty, @intCast(u64, val))),
497 };
498 }
499 },
500 }
501 },
333 .float => |float| switch (self.lookup(float.ty).float_type.bits) {502 .float => |float| switch (self.lookup(float.ty).float_type.bits) {
334 16 => .{503 16 => .{
335 .tag = .float16,504 .tag = .float16,
...@@ -391,9 +560,45 @@ pub fn lookup(self: *const Self, ref: Ref) Key {...@@ -391,9 +560,45 @@ pub fn lookup(self: *const Self, ref: Ref) Key {
391 .value = .{ .float32 = @bitCast(f32, data) },560 .value = .{ .float32 = @bitCast(f32, data) },
392 } },561 } },
393 .float64 => .{ .float = .{562 .float64 => .{ .float = .{
394 .ty = self.get(.{ .float_type = .{ .bits = 32 } }),563 .ty = self.get(.{ .float_type = .{ .bits = 64 } }),
395 .value = .{ .float64 = self.extraData(Tag.Float64, data).decode() },564 .value = .{ .float64 = self.extraData(Tag.Float64, data).decode() },
396 } },565 } },
566 .uint8 => .{ .int = .{
567 .ty = self.get(.{ .int_type = .{ .signedness = .unsigned, .bits = 8 } }),
568 .value = .{ .uint64 = data },
569 } },
570 .uint32 => .{ .int = .{
571 .ty = self.get(.{ .int_type = .{ .signedness = .unsigned, .bits = 32 } }),
572 .value = .{ .uint64 = data },
573 } },
574 .int_small => {
575 const payload = self.extraData(Tag.Int32, data);
576 return .{ .int = .{
577 .ty = payload.ty,
578 .value = .{ .int64 = payload.value },
579 } };
580 },
581 .uint_small => {
582 const payload = self.extraData(Tag.UInt32, data);
583 return .{ .int = .{
584 .ty = payload.ty,
585 .value = .{ .uint64 = payload.value },
586 } };
587 },
588 .int_large => {
589 const payload = self.extraData(Tag.Int64, data);
590 return .{ .int = .{
591 .ty = payload.ty,
592 .value = .{ .int64 = payload.decode() },
593 } };
594 },
595 .uint_large => {
596 const payload = self.extraData(Tag.UInt64, data);
597 return .{ .int = .{
598 .ty = payload.ty,
599 .value = .{ .uint64 = payload.decode() },
600 } };
601 },
397 };602 };
398}603}
399604
...@@ -409,6 +614,7 @@ fn addExtraAssumeCapacity(self: *Self, extra: anytype) !u32 {...@@ -409,6 +614,7 @@ fn addExtraAssumeCapacity(self: *Self, extra: anytype) !u32 {
409 const field_val = @field(extra, field.name);614 const field_val = @field(extra, field.name);
410 const word = switch (field.type) {615 const word = switch (field.type) {
411 u32 => field_val,616 u32 => field_val,
617 i32 => @bitCast(u32, field_val),
412 Ref => @enumToInt(field_val),618 Ref => @enumToInt(field_val),
413 else => @compileError("Invalid type: " ++ @typeName(field.type)),619 else => @compileError("Invalid type: " ++ @typeName(field.type)),
414 };620 };
...@@ -428,6 +634,7 @@ fn extraDataTrail(self: Self, comptime T: type, offset: u32) struct { data: T, t...@@ -428,6 +634,7 @@ fn extraDataTrail(self: Self, comptime T: type, offset: u32) struct { data: T, t
428 const word = self.extra.items[offset + i];634 const word = self.extra.items[offset + i];
429 @field(result, field.name) = switch (field.type) {635 @field(result, field.name) = switch (field.type) {
430 u32 => word,636 u32 => word,
637 i32 => @bitCast(i32, word),
431 Ref => @intToEnum(Ref, word),638 Ref => @intToEnum(Ref, word),
432 else => @compileError("Invalid type: " ++ @typeName(field.type)),639 else => @compileError("Invalid type: " ++ @typeName(field.type)),
433 };640 };