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;...@@ -12,6 +12,7 @@ const LazySrcLoc = Module.LazySrcLoc;
12const Air = @import("../Air.zig");12const Air = @import("../Air.zig");
13const Zir = @import("../Zir.zig");13const Zir = @import("../Zir.zig");
14const Liveness = @import("../Liveness.zig");14const Liveness = @import("../Liveness.zig");
15const InternPool = @import("../InternPool.zig");
1516
16const spec = @import("spirv/spec.zig");17const spec = @import("spirv/spec.zig");
17const Opcode = spec.Opcode;18const Opcode = spec.Opcode;
...@@ -30,6 +31,15 @@ const SpvAssembler = @import("spirv/Assembler.zig");...@@ -30,6 +31,15 @@ const SpvAssembler = @import("spirv/Assembler.zig");
3031
31const InstMap = std.AutoHashMapUnmanaged(Air.Inst.Index, IdRef);32const 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
33const IncomingBlock = struct {43const IncomingBlock = struct {
34 src_label_id: IdRef,44 src_label_id: IdRef,
35 break_value_id: IdRef,45 break_value_id: IdRef,
...@@ -78,6 +88,15 @@ pub const DeclGen = struct {...@@ -78,6 +88,15 @@ pub const DeclGen = struct {
78 /// A map keeping track of which instruction generated which result-id.88 /// A map keeping track of which instruction generated which result-id.
79 inst_results: InstMap = .{},89 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
81 /// We need to keep track of result ids for block labels, as well as the 'incoming'100 /// We need to keep track of result ids for block labels, as well as the 'incoming'
82 /// blocks for a block.101 /// blocks for a block.
83 blocks: BlockMap = .{},102 blocks: BlockMap = .{},
...@@ -207,6 +226,7 @@ pub const DeclGen = struct {...@@ -207,6 +226,7 @@ pub const DeclGen = struct {
207 pub fn deinit(self: *DeclGen) void {226 pub fn deinit(self: *DeclGen) void {
208 self.args.deinit(self.gpa);227 self.args.deinit(self.gpa);
209 self.inst_results.deinit(self.gpa);228 self.inst_results.deinit(self.gpa);
229 self.type_map.deinit(self.gpa);
210 self.blocks.deinit(self.gpa);230 self.blocks.deinit(self.gpa);
211 self.func.deinit(self.gpa);231 self.func.deinit(self.gpa);
212 }232 }
...@@ -1180,6 +1200,9 @@ pub const DeclGen = struct {...@@ -1180,6 +1200,9 @@ pub const DeclGen = struct {
1180 return try self.resolveType(union_obj.enum_tag_ty.toType(), .indirect);1200 return try self.resolveType(union_obj.enum_tag_ty.toType(), .indirect);
1181 }1201 }
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
1183 var member_types = std.BoundedArray(CacheRef, 4){};1206 var member_types = std.BoundedArray(CacheRef, 4){};
1184 var member_names = std.BoundedArray(CacheString, 4){};1207 var member_names = std.BoundedArray(CacheString, 4){};
11851208
...@@ -1222,10 +1245,16 @@ pub const DeclGen = struct {...@@ -1222,10 +1245,16 @@ pub const DeclGen = struct {
1222 member_names.appendAssumeCapacity(try self.spv.resolveString("padding"));1245 member_names.appendAssumeCapacity(try self.spv.resolveString("padding"));
1223 }1246 }
12241247
1225 return try self.spv.resolve(.{ .struct_type = .{1248 const ty_ref = try self.spv.resolve(.{ .struct_type = .{
1226 .member_types = member_types.slice(),1249 .member_types = member_types.slice(),
1227 .member_names = member_names.slice(),1250 .member_names = member_names.slice(),
1228 } });1251 } });
1252
1253 entry.value_ptr.* = .{
1254 .ty_ref = ty_ref,
1255 };
1256
1257 return ty_ref;
1229 }1258 }
12301259
1231 /// Turn a Zig type into a SPIR-V Type, and return a reference to it.1260 /// Turn a Zig type into a SPIR-V Type, and return a reference to it.
...@@ -1268,15 +1297,26 @@ pub const DeclGen = struct {...@@ -1268,15 +1297,26 @@ pub const DeclGen = struct {
1268 return try self.spv.resolve(.{ .float_type = .{ .bits = bits } });1297 return try self.spv.resolve(.{ .float_type = .{ .bits = bits } });
1269 },1298 },
1270 .Array => {1299 .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
1271 const elem_ty = ty.childType(mod);1303 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);
1273 const total_len = std.math.cast(u32, ty.arrayLenIncludingSentinel(mod)) orelse {1305 const total_len = std.math.cast(u32, ty.arrayLenIncludingSentinel(mod)) orelse {
1274 return self.fail("array type of {} elements is too large", .{ty.arrayLenIncludingSentinel(mod)});1306 return self.fail("array type of {} elements is too large", .{ty.arrayLenIncludingSentinel(mod)});
1275 };1307 };
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;
1277 },1313 },
1278 .Fn => switch (repr) {1314 .Fn => switch (repr) {
1279 .direct => {1315 .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;
1280 const fn_info = mod.typeToFunc(ty).?;1320 const fn_info = mod.typeToFunc(ty).?;
1281 // TODO: Put this somewhere in Sema.zig1321 // TODO: Put this somewhere in Sema.zig
1282 if (fn_info.is_var_args)1322 if (fn_info.is_var_args)
...@@ -1289,10 +1329,16 @@ pub const DeclGen = struct {...@@ -1289,10 +1329,16 @@ pub const DeclGen = struct {
1289 }1329 }
1290 const return_ty_ref = try self.resolveType(fn_info.return_type.toType(), .direct);1330 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 = .{
1293 .return_type = return_ty_ref,1333 .return_type = return_ty_ref,
1294 .parameters = param_ty_refs,1334 .parameters = param_ty_refs,
1295 } });1335 } });
1336
1337 entry.value_ptr.* = .{
1338 .ty_ref = ty_ref,
1339 };
1340
1341 return ty_ref;
1296 },1342 },
1297 .indirect => {1343 .indirect => {
1298 // TODO: Represent function pointers properly.1344 // TODO: Represent function pointers properly.
...@@ -1338,6 +1384,9 @@ pub const DeclGen = struct {...@@ -1338,6 +1384,9 @@ pub const DeclGen = struct {
1338 } });1384 } });
1339 },1385 },
1340 .Struct => {1386 .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
1341 const struct_type = switch (ip.indexToKey(ty.toIntern())) {1390 const struct_type = switch (ip.indexToKey(ty.toIntern())) {
1342 .anon_struct_type => |tuple| {1391 .anon_struct_type => |tuple| {
1343 const member_types = try self.gpa.alloc(CacheRef, tuple.values.len);1392 const member_types = try self.gpa.alloc(CacheRef, tuple.values.len);
...@@ -1351,9 +1400,14 @@ pub const DeclGen = struct {...@@ -1351,9 +1400,14 @@ pub const DeclGen = struct {
1351 member_index += 1;1400 member_index += 1;
1352 }1401 }
13531402
1354 return try self.spv.resolve(.{ .struct_type = .{1403 const ty_ref = try self.spv.resolve(.{ .struct_type = .{
1355 .member_types = member_types[0..member_index],1404 .member_types = member_types[0..member_index],
1356 } });1405 } });
1406
1407 entry.value_ptr.* = .{
1408 .ty_ref = ty_ref,
1409 };
1410 return ty_ref;
1357 },1411 },
1358 .struct_type => |struct_type| struct_type,1412 .struct_type => |struct_type| struct_type,
1359 else => unreachable,1413 else => unreachable,
...@@ -1361,7 +1415,6 @@ pub const DeclGen = struct {...@@ -1361,7 +1415,6 @@ pub const DeclGen = struct {
13611415
1362 if (struct_type.layout == .Packed) {1416 if (struct_type.layout == .Packed) {
1363 return try self.resolveType(struct_type.backingIntType(ip).toType(), .direct);1417 return try self.resolveType(struct_type.backingIntType(ip).toType(), .direct);
1364 }
13651418
1366 var member_types = std.ArrayList(CacheRef).init(self.gpa);1419 var member_types = std.ArrayList(CacheRef).init(self.gpa);
1367 defer member_types.deinit();1420 defer member_types.deinit();
...@@ -1379,11 +1432,16 @@ pub const DeclGen = struct {...@@ -1379,11 +1432,16 @@ pub const DeclGen = struct {
13791432
1380 const name = ip.stringToSlice(try mod.declPtr(struct_type.decl.unwrap().?).getFullyQualifiedName(mod));1433 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 = .{
1383 .name = try self.spv.resolveString(name),1436 .name = try self.spv.resolveString(name),
1384 .member_types = member_types.items,1437 .member_types = member_types.items,
1385 .member_names = member_names.items,1438 .member_names = member_names.items,
1386 } });1439 } });
1440
1441 entry.value_ptr.* = .{
1442 .ty_ref = ty_ref,
1443 };
1444 return ty_ref;
1387 },1445 },
1388 .Optional => {1446 .Optional => {
1389 const payload_ty = ty.optionalChild(mod);1447 const payload_ty = ty.optionalChild(mod);
...@@ -1400,15 +1458,23 @@ pub const DeclGen = struct {...@@ -1400,15 +1458,23 @@ pub const DeclGen = struct {
1400 return payload_ty_ref;1458 return payload_ty_ref;
1401 }1459 }
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
1403 const bool_ty_ref = try self.resolveType(Type.bool, .indirect);1464 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 = .{
1406 .member_types = &.{ payload_ty_ref, bool_ty_ref },1467 .member_types = &.{ payload_ty_ref, bool_ty_ref },
1407 .member_names = &.{1468 .member_names = &.{
1408 try self.spv.resolveString("payload"),1469 try self.spv.resolveString("payload"),
1409 try self.spv.resolveString("valid"),1470 try self.spv.resolveString("valid"),
1410 },1471 },
1411 } });1472 } });
1473
1474 entry.value_ptr.* = .{
1475 .ty_ref = ty_ref,
1476 };
1477 return ty_ref;
1412 },1478 },
1413 .Union => return try self.resolveUnionType(ty, null),1479 .Union => return try self.resolveUnionType(ty, null),
1414 .ErrorSet => return try self.intType(.unsigned, 16),1480 .ErrorSet => return try self.intType(.unsigned, 16),
...@@ -1421,6 +1487,9 @@ pub const DeclGen = struct {...@@ -1421,6 +1487,9 @@ pub const DeclGen = struct {
1421 return error_ty_ref;1487 return error_ty_ref;
1422 }1488 }
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
1424 const payload_ty_ref = try self.resolveType(payload_ty, .indirect);1493 const payload_ty_ref = try self.resolveType(payload_ty, .indirect);
14251494
1426 var member_types: [2]CacheRef = undefined;1495 var member_types: [2]CacheRef = undefined;
...@@ -1443,10 +1512,15 @@ pub const DeclGen = struct {...@@ -1443,10 +1512,15 @@ pub const DeclGen = struct {
1443 // TODO: ABI padding?1512 // TODO: ABI padding?
1444 }1513 }
14451514
1446 return try self.spv.resolve(.{ .struct_type = .{1515 const ty_ref = try self.spv.resolve(.{ .struct_type = .{
1447 .member_types = &member_types,1516 .member_types = &member_types,
1448 .member_names = &member_names,1517 .member_names = &member_names,
1449 } });1518 } });
1519
1520 entry.value_ptr.* = .{
1521 .ty_ref = ty_ref,
1522 };
1523 return ty_ref;
1450 },1524 },
14511525
1452 .Null,1526 .Null,