authorgravatar for robin@voetter.nlRobin Voetter <robin@voetter.nl> 2023-08-26 12:19:28+02:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-09-23 12:36:44-07:00
logced8a2c3a650fdddc489f97a1d12dd029856fe9e
treeeee7a8fe7d1f3cd984015f997ac98e0bdb58c205
parent79f7481575005f9f63b5b3be8dd89b92b11b9c77

spirv: add type_map to map AIR types to SPIR-V types

This will help us both to make the implementation a little more efficient by caching emission for certain types like structs, and also allow us to attach extra information about types that we can use while lowering without performing a search over the entire type tree for some property.

1 files changed, 83 insertions(+), 9 deletions(-)

src/codegen/spirv.zig+83-9
......@@ -12,6 +12,7 @@ const LazySrcLoc = Module.LazySrcLoc;
1212const Air = @import("../Air.zig");
1313const Zir = @import("../Zir.zig");
1414const Liveness = @import("../Liveness.zig");
15const InternPool = @import("../InternPool.zig");
1516
1617const spec = @import("spirv/spec.zig");
1718const Opcode = spec.Opcode;
......@@ -30,6 +31,15 @@ const SpvAssembler = @import("spirv/Assembler.zig");
3031
3132const InstMap = std.AutoHashMapUnmanaged(Air.Inst.Index, IdRef);
3233
34/// We want to store some extra facts about types as mapped from Zig to SPIR-V.
35/// This structure is used to keep that extra information, as well as
36/// the cached reference to the type.
37const SpvTypeInfo = struct {
38 ty_ref: CacheRef,
39};
40
41const TypeMap = std.AutoHashMapUnmanaged(InternPool.Index, SpvTypeInfo);
42
3343const IncomingBlock = struct {
3444 src_label_id: IdRef,
3545 break_value_id: IdRef,
......@@ -78,6 +88,15 @@ pub const DeclGen = struct {
7888 /// A map keeping track of which instruction generated which result-id.
7989 inst_results: InstMap = .{},
8090
91 /// A map that maps AIR intern pool indices to SPIR-V cache references (which
92 /// is basically the same thing except for SPIR-V).
93 /// This map is typically only used for structures that are deemed heavy enough
94 /// that it is worth to store them here. The SPIR-V module also interns types,
95 /// and so the main purpose of this map is to avoid recomputation and to
96 /// cache extra information about the type rather than to aid in validity
97 /// of the SPIR-V module.
98 type_map: TypeMap = .{},
99
81100 /// We need to keep track of result ids for block labels, as well as the 'incoming'
82101 /// blocks for a block.
83102 blocks: BlockMap = .{},
......@@ -207,6 +226,7 @@ pub const DeclGen = struct {
207226 pub fn deinit(self: *DeclGen) void {
208227 self.args.deinit(self.gpa);
209228 self.inst_results.deinit(self.gpa);
229 self.type_map.deinit(self.gpa);
210230 self.blocks.deinit(self.gpa);
211231 self.func.deinit(self.gpa);
212232 }
......@@ -1180,6 +1200,9 @@ pub const DeclGen = struct {
11801200 return try self.resolveType(union_obj.enum_tag_ty.toType(), .indirect);
11811201 }
11821202
1203 const entry = try self.type_map.getOrPut(self.gpa, ty.toIntern());
1204 if (entry.found_existing) return entry.value_ptr.ty_ref;
1205
11831206 var member_types = std.BoundedArray(CacheRef, 4){};
11841207 var member_names = std.BoundedArray(CacheString, 4){};
11851208
......@@ -1222,10 +1245,16 @@ pub const DeclGen = struct {
12221245 member_names.appendAssumeCapacity(try self.spv.resolveString("padding"));
12231246 }
12241247
1225 return try self.spv.resolve(.{ .struct_type = .{
1248 const ty_ref = try self.spv.resolve(.{ .struct_type = .{
12261249 .member_types = member_types.slice(),
12271250 .member_names = member_names.slice(),
12281251 } });
1252
1253 entry.value_ptr.* = .{
1254 .ty_ref = ty_ref,
1255 };
1256
1257 return ty_ref;
12291258 }
12301259
12311260 /// Turn a Zig type into a SPIR-V Type, and return a reference to it.
......@@ -1268,15 +1297,26 @@ pub const DeclGen = struct {
12681297 return try self.spv.resolve(.{ .float_type = .{ .bits = bits } });
12691298 },
12701299 .Array => {
1300 const entry = try self.type_map.getOrPut(self.gpa, ty.toIntern());
1301 if (entry.found_existing) return entry.value_ptr.ty_ref;
1302
12711303 const elem_ty = ty.childType(mod);
1272 const elem_ty_ref = try self.resolveType(elem_ty, .direct);
1304 const elem_ty_ref = try self.resolveType(elem_ty, .indirect);
12731305 const total_len = std.math.cast(u32, ty.arrayLenIncludingSentinel(mod)) orelse {
12741306 return self.fail("array type of {} elements is too large", .{ty.arrayLenIncludingSentinel(mod)});
12751307 };
1276 return self.spv.arrayType(total_len, elem_ty_ref);
1308 const ty_ref = try self.spv.arrayType(total_len, elem_ty_ref);
1309 entry.value_ptr.* = .{
1310 .ty_ref = ty_ref,
1311 };
1312 return ty_ref;
12771313 },
12781314 .Fn => switch (repr) {
12791315 .direct => {
1316 const entry = try self.type_map.getOrPut(self.gpa, ty.toIntern());
1317 if (entry.found_existing) return entry.value_ptr.ty_ref;
1318
1319 const ip = &mod.intern_pool;
12801320 const fn_info = mod.typeToFunc(ty).?;
12811321 // TODO: Put this somewhere in Sema.zig
12821322 if (fn_info.is_var_args)
......@@ -1289,10 +1329,16 @@ pub const DeclGen = struct {
12891329 }
12901330 const return_ty_ref = try self.resolveType(fn_info.return_type.toType(), .direct);
12911331
1292 return try self.spv.resolve(.{ .function_type = .{
1332 const ty_ref = try self.spv.resolve(.{ .function_type = .{
12931333 .return_type = return_ty_ref,
12941334 .parameters = param_ty_refs,
12951335 } });
1336
1337 entry.value_ptr.* = .{
1338 .ty_ref = ty_ref,
1339 };
1340
1341 return ty_ref;
12961342 },
12971343 .indirect => {
12981344 // TODO: Represent function pointers properly.
......@@ -1338,6 +1384,9 @@ pub const DeclGen = struct {
13381384 } });
13391385 },
13401386 .Struct => {
1387 const entry = try self.type_map.getOrPut(self.gpa, ty.toIntern());
1388 if (entry.found_existing) return entry.value_ptr.ty_ref;
1389
13411390 const struct_type = switch (ip.indexToKey(ty.toIntern())) {
13421391 .anon_struct_type => |tuple| {
13431392 const member_types = try self.gpa.alloc(CacheRef, tuple.values.len);
......@@ -1351,9 +1400,14 @@ pub const DeclGen = struct {
13511400 member_index += 1;
13521401 }
13531402
1354 return try self.spv.resolve(.{ .struct_type = .{
1403 const ty_ref = try self.spv.resolve(.{ .struct_type = .{
13551404 .member_types = member_types[0..member_index],
13561405 } });
1406
1407 entry.value_ptr.* = .{
1408 .ty_ref = ty_ref,
1409 };
1410 return ty_ref;
13571411 },
13581412 .struct_type => |struct_type| struct_type,
13591413 else => unreachable,
......@@ -1361,7 +1415,6 @@ pub const DeclGen = struct {
13611415
13621416 if (struct_type.layout == .Packed) {
13631417 return try self.resolveType(struct_type.backingIntType(ip).toType(), .direct);
1364 }
13651418
13661419 var member_types = std.ArrayList(CacheRef).init(self.gpa);
13671420 defer member_types.deinit();
......@@ -1379,11 +1432,16 @@ pub const DeclGen = struct {
13791432
13801433 const name = ip.stringToSlice(try mod.declPtr(struct_type.decl.unwrap().?).getFullyQualifiedName(mod));
13811434
1382 return try self.spv.resolve(.{ .struct_type = .{
1435 const ty_ref = try self.spv.resolve(.{ .struct_type = .{
13831436 .name = try self.spv.resolveString(name),
13841437 .member_types = member_types.items,
13851438 .member_names = member_names.items,
13861439 } });
1440
1441 entry.value_ptr.* = .{
1442 .ty_ref = ty_ref,
1443 };
1444 return ty_ref;
13871445 },
13881446 .Optional => {
13891447 const payload_ty = ty.optionalChild(mod);
......@@ -1400,15 +1458,23 @@ pub const DeclGen = struct {
14001458 return payload_ty_ref;
14011459 }
14021460
1461 const entry = try self.type_map.getOrPut(self.gpa, ty.toIntern());
1462 if (entry.found_existing) return entry.value_ptr.ty_ref;
1463
14031464 const bool_ty_ref = try self.resolveType(Type.bool, .indirect);
14041465
1405 return try self.spv.resolve(.{ .struct_type = .{
1466 const ty_ref = try self.spv.resolve(.{ .struct_type = .{
14061467 .member_types = &.{ payload_ty_ref, bool_ty_ref },
14071468 .member_names = &.{
14081469 try self.spv.resolveString("payload"),
14091470 try self.spv.resolveString("valid"),
14101471 },
14111472 } });
1473
1474 entry.value_ptr.* = .{
1475 .ty_ref = ty_ref,
1476 };
1477 return ty_ref;
14121478 },
14131479 .Union => return try self.resolveUnionType(ty, null),
14141480 .ErrorSet => return try self.intType(.unsigned, 16),
......@@ -1421,6 +1487,9 @@ pub const DeclGen = struct {
14211487 return error_ty_ref;
14221488 }
14231489
1490 const entry = try self.type_map.getOrPut(self.gpa, ty.toIntern());
1491 if (entry.found_existing) return entry.value_ptr.ty_ref;
1492
14241493 const payload_ty_ref = try self.resolveType(payload_ty, .indirect);
14251494
14261495 var member_types: [2]CacheRef = undefined;
......@@ -1443,10 +1512,15 @@ pub const DeclGen = struct {
14431512 // TODO: ABI padding?
14441513 }
14451514
1446 return try self.spv.resolve(.{ .struct_type = .{
1515 const ty_ref = try self.spv.resolve(.{ .struct_type = .{
14471516 .member_types = &member_types,
14481517 .member_names = &member_names,
14491518 } });
1519
1520 entry.value_ptr.* = .{
1521 .ty_ref = ty_ref,
1522 };
1523 return ty_ref;
14501524 },
14511525
14521526 .Null,