| ... | ... | @@ -12,6 +12,7 @@ const LazySrcLoc = Module.LazySrcLoc; |
| 12 | 12 | const Air = @import("../Air.zig"); |
| 13 | 13 | const Zir = @import("../Zir.zig"); |
| 14 | 14 | const Liveness = @import("../Liveness.zig"); |
| 15 | const InternPool = @import("../InternPool.zig"); |
| 15 | 16 | |
| 16 | 17 | const spec = @import("spirv/spec.zig"); |
| 17 | 18 | const Opcode = spec.Opcode; |
| ... | ... | @@ -30,6 +31,15 @@ const SpvAssembler = @import("spirv/Assembler.zig"); |
| 30 | 31 | |
| 31 | 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 | 43 | const IncomingBlock = struct { |
| 34 | 44 | src_label_id: IdRef, |
| 35 | 45 | break_value_id: IdRef, |
| ... | ... | @@ -78,6 +88,15 @@ pub const DeclGen = struct { |
| 78 | 88 | /// A map keeping track of which instruction generated which result-id. |
| 79 | 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 | 100 | /// We need to keep track of result ids for block labels, as well as the 'incoming' |
| 82 | 101 | /// blocks for a block. |
| 83 | 102 | blocks: BlockMap = .{}, |
| ... | ... | @@ -207,6 +226,7 @@ pub const DeclGen = struct { |
| 207 | 226 | pub fn deinit(self: *DeclGen) void { |
| 208 | 227 | self.args.deinit(self.gpa); |
| 209 | 228 | self.inst_results.deinit(self.gpa); |
| 229 | self.type_map.deinit(self.gpa); |
| 210 | 230 | self.blocks.deinit(self.gpa); |
| 211 | 231 | self.func.deinit(self.gpa); |
| 212 | 232 | } |
| ... | ... | @@ -1180,6 +1200,9 @@ pub const DeclGen = struct { |
| 1180 | 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 | 1206 | var member_types = std.BoundedArray(CacheRef, 4){}; |
| 1184 | 1207 | var member_names = std.BoundedArray(CacheString, 4){}; |
| 1185 | 1208 | |
| ... | ... | @@ -1222,10 +1245,16 @@ pub const DeclGen = struct { |
| 1222 | 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 | 1249 | .member_types = member_types.slice(), |
| 1227 | 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 | 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 | 1297 | return try self.spv.resolve(.{ .float_type = .{ .bits = bits } }); |
| 1269 | 1298 | }, |
| 1270 | 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 | 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 | 1305 | const total_len = std.math.cast(u32, ty.arrayLenIncludingSentinel(mod)) orelse { |
| 1274 | 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 | 1314 | .Fn => switch (repr) { |
| 1279 | 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 | 1320 | const fn_info = mod.typeToFunc(ty).?; |
| 1281 | 1321 | // TODO: Put this somewhere in Sema.zig |
| 1282 | 1322 | if (fn_info.is_var_args) |
| ... | ... | @@ -1289,10 +1329,16 @@ pub const DeclGen = struct { |
| 1289 | 1329 | } |
| 1290 | 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 | 1333 | .return_type = return_ty_ref, |
| 1294 | 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 | 1343 | .indirect => { |
| 1298 | 1344 | // TODO: Represent function pointers properly. |
| ... | ... | @@ -1338,6 +1384,9 @@ pub const DeclGen = struct { |
| 1338 | 1384 | } }); |
| 1339 | 1385 | }, |
| 1340 | 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 | 1390 | const struct_type = switch (ip.indexToKey(ty.toIntern())) { |
| 1342 | 1391 | .anon_struct_type => |tuple| { |
| 1343 | 1392 | const member_types = try self.gpa.alloc(CacheRef, tuple.values.len); |
| ... | ... | @@ -1351,9 +1400,14 @@ pub const DeclGen = struct { |
| 1351 | 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 | 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 | 1412 | .struct_type => |struct_type| struct_type, |
| 1359 | 1413 | else => unreachable, |
| ... | ... | @@ -1361,7 +1415,6 @@ pub const DeclGen = struct { |
| 1361 | 1415 | |
| 1362 | 1416 | if (struct_type.layout == .Packed) { |
| 1363 | 1417 | return try self.resolveType(struct_type.backingIntType(ip).toType(), .direct); |
| 1364 | | } |
| 1365 | 1418 | |
| 1366 | 1419 | var member_types = std.ArrayList(CacheRef).init(self.gpa); |
| 1367 | 1420 | defer member_types.deinit(); |
| ... | ... | @@ -1379,11 +1432,16 @@ pub const DeclGen = struct { |
| 1379 | 1432 | |
| 1380 | 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 | 1436 | .name = try self.spv.resolveString(name), |
| 1384 | 1437 | .member_types = member_types.items, |
| 1385 | 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 | 1446 | .Optional => { |
| 1389 | 1447 | const payload_ty = ty.optionalChild(mod); |
| ... | ... | @@ -1400,15 +1458,23 @@ pub const DeclGen = struct { |
| 1400 | 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 | 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 | 1467 | .member_types = &.{ payload_ty_ref, bool_ty_ref }, |
| 1407 | 1468 | .member_names = &.{ |
| 1408 | 1469 | try self.spv.resolveString("payload"), |
| 1409 | 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 | 1479 | .Union => return try self.resolveUnionType(ty, null), |
| 1414 | 1480 | .ErrorSet => return try self.intType(.unsigned, 16), |
| ... | ... | @@ -1421,6 +1487,9 @@ pub const DeclGen = struct { |
| 1421 | 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 | 1493 | const payload_ty_ref = try self.resolveType(payload_ty, .indirect); |
| 1425 | 1494 | |
| 1426 | 1495 | var member_types: [2]CacheRef = undefined; |
| ... | ... | @@ -1443,10 +1512,15 @@ pub const DeclGen = struct { |
| 1443 | 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 | 1516 | .member_types = &member_types, |
| 1448 | 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 | 1526 | .Null, |