| ... | @@ -12,6 +12,7 @@ const LazySrcLoc = Module.LazySrcLoc; | ... | @@ -12,6 +12,7 @@ const LazySrcLoc = Module.LazySrcLoc; |
| 12 | const Air = @import("../Air.zig"); | 12 | const Air = @import("../Air.zig"); |
| 13 | const Zir = @import("../Zir.zig"); | 13 | const Zir = @import("../Zir.zig"); |
| 14 | const Liveness = @import("../Liveness.zig"); | 14 | const Liveness = @import("../Liveness.zig"); |
| | 15 | const InternPool = @import("../InternPool.zig"); |
| 15 | | 16 | |
| 16 | const spec = @import("spirv/spec.zig"); | 17 | const spec = @import("spirv/spec.zig"); |
| 17 | const Opcode = spec.Opcode; | 18 | const Opcode = spec.Opcode; |
| ... | @@ -30,6 +31,15 @@ const SpvAssembler = @import("spirv/Assembler.zig"); | ... | @@ -30,6 +31,15 @@ const SpvAssembler = @import("spirv/Assembler.zig"); |
| 30 | | 31 | |
| 31 | const InstMap = std.AutoHashMapUnmanaged(Air.Inst.Index, IdRef); | 32 | const InstMap = std.AutoHashMapUnmanaged(Air.Inst.Index, IdRef); |
| 32 | | 33 | |
| | 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. |
| | 37 | const SpvTypeInfo = struct { |
| | 38 | ty_ref: CacheRef, |
| | 39 | }; |
| | 40 | |
| | 41 | const TypeMap = std.AutoHashMapUnmanaged(InternPool.Index, SpvTypeInfo); |
| | 42 | |
| 33 | const IncomingBlock = struct { | 43 | const 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 = .{}, |
| 80 | | 90 | |
| | 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 | } |
| 1182 | | 1202 | |
| | 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){}; |
| 1185 | | 1208 | |
| ... | @@ -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 | } |
| 1224 | | 1247 | |
| 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 | } |
| 1230 | | 1259 | |
| 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.zig | 1321 | // 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); |
| 1291 | | 1331 | |
| 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 | } |
| 1353 | | 1402 | |
| 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 { |
| 1361 | | 1415 | |
| 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 | } | | |
| 1365 | | 1418 | |
| 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 { |
| 1379 | | 1432 | |
| 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)); |
| 1381 | | 1434 | |
| 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 | } |
| 1402 | | 1460 | |
| | 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); |
| 1404 | | 1465 | |
| 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 | } |
| 1423 | | 1489 | |
| | 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); |
| 1425 | | 1494 | |
| 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 | } |
| 1445 | | 1514 | |
| 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 | }, |
| 1451 | | 1525 | |
| 1452 | .Null, | 1526 | .Null, |