| ... | ... | @@ -425,6 +425,7 @@ pub const DeclGen = struct { |
| 425 | 425 | // See https://github.com/KhronosGroup/SPIRV-LLVM-Translator/issues/1349 |
| 426 | 426 | // For now, just initialize the struct by setting the fields manually... |
| 427 | 427 | // TODO: Make this OpCompositeConstruct when we can |
| 428 | // TODO: Make this Function storage type |
| 428 | 429 | const ptr_composite_id = try self.alloc(result_ty_ref, null); |
| 429 | 430 | // Note: using 32-bit ints here because usize crashes the translator as well |
| 430 | 431 | const index_ty_ref = try self.intType(.unsigned, 32); |
| ... | ... | @@ -450,6 +451,40 @@ pub const DeclGen = struct { |
| 450 | 451 | return result_id; |
| 451 | 452 | } |
| 452 | 453 | |
| 454 | /// Construct a struct at runtime. |
| 455 | /// result_ty_ref must be an array type. |
| 456 | fn constructArray(self: *DeclGen, result_ty_ref: CacheRef, constituents: []const IdRef) !IdRef { |
| 457 | // The Khronos LLVM-SPIRV translator crashes because it cannot construct structs which' |
| 458 | // operands are not constant. |
| 459 | // See https://github.com/KhronosGroup/SPIRV-LLVM-Translator/issues/1349 |
| 460 | // For now, just initialize the struct by setting the fields manually... |
| 461 | // TODO: Make this OpCompositeConstruct when we can |
| 462 | // TODO: Make this Function storage type |
| 463 | const ptr_composite_id = try self.alloc(result_ty_ref, null); |
| 464 | // Note: using 32-bit ints here because usize crashes the translator as well |
| 465 | const index_ty_ref = try self.intType(.unsigned, 32); |
| 466 | |
| 467 | const spv_composite_ty = self.spv.cache.lookup(result_ty_ref).array_type; |
| 468 | const elem_ty_ref = spv_composite_ty.element_type; |
| 469 | const ptr_elem_ty_ref = try self.spv.ptrType(elem_ty_ref, .Generic); |
| 470 | |
| 471 | for (constituents, 0..) |constitent_id, index| { |
| 472 | const index_id = try self.spv.constInt(index_ty_ref, index); |
| 473 | const ptr_id = try self.accessChain(ptr_elem_ty_ref, ptr_composite_id, &.{index_id}); |
| 474 | try self.func.body.emit(self.spv.gpa, .OpStore, .{ |
| 475 | .pointer = ptr_id, |
| 476 | .object = constitent_id, |
| 477 | }); |
| 478 | } |
| 479 | const result_id = self.spv.allocId(); |
| 480 | try self.func.body.emit(self.spv.gpa, .OpLoad, .{ |
| 481 | .id_result_type = self.typeId(result_ty_ref), |
| 482 | .id_result = result_id, |
| 483 | .pointer = ptr_composite_id, |
| 484 | }); |
| 485 | return result_id; |
| 486 | } |
| 487 | |
| 453 | 488 | fn constructDeclRef(self: *DeclGen, ty: Type, decl_index: Decl.Index) !IdRef { |
| 454 | 489 | const mod = self.module; |
| 455 | 490 | const ty_ref = try self.resolveType(ty, .direct); |
| ... | ... | @@ -459,10 +494,9 @@ pub const DeclGen = struct { |
| 459 | 494 | switch (mod.intern_pool.indexToKey(decl.val.ip_index)) { |
| 460 | 495 | .func => { |
| 461 | 496 | // TODO: Properly lower function pointers. For now we are going to hack around it and |
| 462 | | // just generate an empty pointer. Function pointers are represented by usize for now, |
| 463 | | // though. |
| 497 | // just generate an empty pointer. Function pointers are represented by a pointer to usize. |
| 464 | 498 | // TODO: Add dependency |
| 465 | | return try self.spv.constInt(ty_ref, 0); |
| 499 | return try self.spv.constNull(ty_ref); |
| 466 | 500 | }, |
| 467 | 501 | .extern_func => unreachable, // TODO |
| 468 | 502 | else => { |
| ... | ... | @@ -1074,7 +1108,7 @@ pub const DeclGen = struct { |
| 1074 | 1108 | else => {}, |
| 1075 | 1109 | } |
| 1076 | 1110 | |
| 1077 | | log.debug("constant: ty = {}, val = {}", .{ ty.fmt(self.module), val.fmtValue(ty, self.module) }); |
| 1111 | log.debug("constant: ty = {}, val = {}", .{ ty.fmt(mod), val.fmtValue(ty, mod) }); |
| 1078 | 1112 | if (val.isUndefDeep(mod)) { |
| 1079 | 1113 | return self.spv.constUndef(result_ty_ref); |
| 1080 | 1114 | } |
| ... | ... | @@ -1270,7 +1304,7 @@ pub const DeclGen = struct { |
| 1270 | 1304 | if (array_type.sentinel != .none) { |
| 1271 | 1305 | constituents[constituents.len - 1] = try self.constant(elem_ty, array_type.sentinel.toValue(), .indirect); |
| 1272 | 1306 | } |
| 1273 | | return try self.constructStruct(result_ty_ref, constituents); |
| 1307 | return try self.constructArray(result_ty_ref, constituents); |
| 1274 | 1308 | }, |
| 1275 | 1309 | .struct_type => { |
| 1276 | 1310 | const struct_ty = mod.typeToStruct(ty).?; |
| ... | ... | @@ -1281,18 +1315,14 @@ pub const DeclGen = struct { |
| 1281 | 1315 | var constituents = std.ArrayList(IdRef).init(self.gpa); |
| 1282 | 1316 | defer constituents.deinit(); |
| 1283 | 1317 | |
| 1284 | | for (struct_ty.fields.values(), 0..) |field, i| { |
| 1285 | | if (field.is_comptime or !field.ty.hasRuntimeBits(mod)) continue; |
| 1318 | var field_it = struct_ty.runtimeFieldIterator(mod); |
| 1319 | while (field_it.next()) |field_and_index| { |
| 1320 | const field = field_and_index.field; |
| 1321 | const index = field_and_index.index; |
| 1322 | // TODO: Padding? |
| 1323 | const field_val = try val.fieldValue(mod, index); |
| 1324 | const field_id = try self.constant(field.ty, field_val, .indirect); |
| 1286 | 1325 | |
| 1287 | | const field_val = switch (aggregate.storage) { |
| 1288 | | .bytes => |bytes| try ip.get(mod.gpa, .{ .int = .{ |
| 1289 | | .ty = field.ty.toIntern(), |
| 1290 | | .storage = .{ .u64 = bytes[i] }, |
| 1291 | | } }), |
| 1292 | | .elems => |elems| elems[i], |
| 1293 | | .repeated_elem => |elem| elem, |
| 1294 | | }; |
| 1295 | | const field_id = try self.constant(field.ty, field_val.toValue(), .indirect); |
| 1296 | 1326 | try constituents.append(field_id); |
| 1297 | 1327 | } |
| 1298 | 1328 | |
| ... | ... | @@ -1306,33 +1336,35 @@ pub const DeclGen = struct { |
| 1306 | 1336 | // type that has the right field active, then pointer-cast and store |
| 1307 | 1337 | // the active field, and finally load and return the entire union. |
| 1308 | 1338 | |
| 1309 | | const layout = ty.unionGetLayout(mod); |
| 1310 | 1339 | const union_ty = mod.typeToUnion(ty).?; |
| 1311 | 1340 | |
| 1312 | 1341 | if (union_ty.getLayout(ip) == .Packed) { |
| 1313 | 1342 | return self.todo("packed union types", .{}); |
| 1314 | | } else if (layout.payload_size == 0) { |
| 1343 | } |
| 1344 | |
| 1345 | const active_field = ty.unionTagFieldIndex(un.tag.toValue(), mod).?; |
| 1346 | const layout = self.unionLayout(ty, active_field); |
| 1347 | |
| 1348 | if (layout.payload_size == 0) { |
| 1315 | 1349 | // No payload, so represent this as just the tag type. |
| 1316 | 1350 | return try self.constant(ty.unionTagTypeSafety(mod).?, un.tag.toValue(), .indirect); |
| 1317 | 1351 | } |
| 1318 | 1352 | |
| 1319 | | const has_tag = layout.tag_size != 0; |
| 1320 | | const tag_first = layout.tag_align >= layout.payload_align; |
| 1321 | | |
| 1322 | | const un_ptr_ty_ref = try self.spv.ptrType(result_ty_ref, .Function); |
| 1353 | const un_active_ty_ref = try self.resolveUnionType(ty, active_field); |
| 1354 | const un_active_ptr_ty_ref = try self.spv.ptrType(un_active_ty_ref, .Function); |
| 1355 | const un_general_ptr_ty_ref = try self.spv.ptrType(result_ty_ref, .Function); |
| 1323 | 1356 | |
| 1324 | 1357 | const var_id = self.spv.allocId(); |
| 1325 | 1358 | try self.func.prologue.emit(self.spv.gpa, .OpVariable, .{ |
| 1326 | | .id_result_type = self.typeId(un_ptr_ty_ref), |
| 1359 | .id_result_type = self.typeId(un_active_ptr_ty_ref), |
| 1327 | 1360 | .id_result = var_id, |
| 1328 | 1361 | .storage_class = .Function, |
| 1329 | 1362 | }); |
| 1330 | 1363 | |
| 1331 | 1364 | const index_ty_ref = try self.intType(.unsigned, 32); |
| 1332 | 1365 | |
| 1333 | | if (has_tag) { |
| 1334 | | const tag_index: u32 = if (tag_first) 0 else 1; |
| 1335 | | const index_id = try self.spv.constInt(index_ty_ref, tag_index); |
| 1366 | if (layout.tag_size != 0) { |
| 1367 | const index_id = try self.spv.constInt(index_ty_ref, @as(u32, @intCast(layout.tag_index))); |
| 1336 | 1368 | const tag_ty = ty.unionTagTypeSafety(mod).?; |
| 1337 | 1369 | const tag_ty_ref = try self.resolveType(tag_ty, .indirect); |
| 1338 | 1370 | const tag_ptr_ty_ref = try self.spv.ptrType(tag_ty_ref, .Function); |
| ... | ... | @@ -1344,56 +1376,39 @@ pub const DeclGen = struct { |
| 1344 | 1376 | }); |
| 1345 | 1377 | } |
| 1346 | 1378 | |
| 1347 | | const pl_index: u32 = if (tag_first) 1 else 0; |
| 1348 | | const index_id = try self.spv.constInt(index_ty_ref, pl_index); |
| 1349 | | const active_field = ty.unionTagFieldIndex(un.tag.toValue(), mod).?; |
| 1350 | | const active_field_ty = union_ty.field_types.get(ip)[active_field].toType(); |
| 1351 | | const active_field_ty_ref = try self.resolveType(active_field_ty, .indirect); |
| 1352 | | const active_field_ptr_ty_ref = try self.spv.ptrType(active_field_ty_ref, .Function); |
| 1353 | | const ptr_id = try self.accessChain(active_field_ptr_ty_ref, var_id, &.{index_id}); |
| 1354 | | const value_id = try self.constant(active_field_ty, un.val.toValue(), .indirect); |
| 1355 | | try self.func.body.emit(self.spv.gpa, .OpStore, .{ |
| 1356 | | .pointer = ptr_id, |
| 1357 | | .object = value_id, |
| 1358 | | }); |
| 1379 | if (layout.active_field_size != 0) { |
| 1380 | const index_id = try self.spv.constInt(index_ty_ref, @as(u32, @intCast(layout.active_field_index))); |
| 1381 | const active_field_ty_ref = try self.resolveType(layout.active_field_ty, .indirect); |
| 1382 | const active_field_ptr_ty_ref = try self.spv.ptrType(active_field_ty_ref, .Function); |
| 1383 | const ptr_id = try self.accessChain(active_field_ptr_ty_ref, var_id, &.{index_id}); |
| 1384 | const value_id = try self.constant(layout.active_field_ty, un.val.toValue(), .indirect); |
| 1385 | try self.func.body.emit(self.spv.gpa, .OpStore, .{ |
| 1386 | .pointer = ptr_id, |
| 1387 | .object = value_id, |
| 1388 | }); |
| 1389 | } |
| 1359 | 1390 | |
| 1360 | 1391 | // Just leave the padding fields uninitialized... |
| 1392 | // TODO: Or should we initialize them with undef explicitly? |
| 1361 | 1393 | |
| 1362 | | const result_id = self.spv.allocId(); |
| 1363 | | try self.func.body.emit(self.spv.gpa, .OpLoad, .{ |
| 1364 | | .id_result_type = self.typeId(result_ty_ref), |
| 1365 | | .id_result = result_id, |
| 1366 | | .pointer = var_id, |
| 1394 | // Now cast the pointer and load it as the 'generic' union type. |
| 1395 | |
| 1396 | const casted_var_id = self.spv.allocId(); |
| 1397 | try self.func.body.emit(self.spv.gpa, .OpBitcast, .{ |
| 1398 | .id_result_type = self.typeId(un_general_ptr_ty_ref), |
| 1399 | .id_result = casted_var_id, |
| 1400 | .operand = var_id, |
| 1367 | 1401 | }); |
| 1368 | | return result_id; |
| 1369 | | }, |
| 1370 | | else => { |
| 1371 | | // The value cannot be generated directly, so generate it as an indirect constant, |
| 1372 | | // and then perform an OpLoad. |
| 1373 | | const result_id = self.spv.allocId(); |
| 1374 | | const alignment = ty.abiAlignment(mod); |
| 1375 | | const spv_decl_index = try self.spv.allocDecl(.global); |
| 1376 | | |
| 1377 | | try self.lowerIndirectConstant( |
| 1378 | | spv_decl_index, |
| 1379 | | ty, |
| 1380 | | val, |
| 1381 | | .UniformConstant, |
| 1382 | | false, |
| 1383 | | @intCast(alignment.toByteUnits(0)), |
| 1384 | | ); |
| 1385 | | log.debug("indirect constant: index = {}", .{@intFromEnum(spv_decl_index)}); |
| 1386 | | try self.func.decl_deps.put(self.spv.gpa, spv_decl_index, {}); |
| 1387 | 1402 | |
| 1403 | const result_id = self.spv.allocId(); |
| 1388 | 1404 | try self.func.body.emit(self.spv.gpa, .OpLoad, .{ |
| 1389 | 1405 | .id_result_type = self.typeId(result_ty_ref), |
| 1390 | 1406 | .id_result = result_id, |
| 1391 | | .pointer = self.spv.declPtr(spv_decl_index).result_id, |
| 1407 | .pointer = casted_var_id, |
| 1392 | 1408 | }); |
| 1393 | | // TODO: Convert bools? This logic should hook into `load`. It should be a dead |
| 1394 | | // path though considering .Bool is handled above. |
| 1395 | 1409 | return result_id; |
| 1396 | 1410 | }, |
| 1411 | .memoized_call => unreachable, |
| 1397 | 1412 | } |
| 1398 | 1413 | } |
| 1399 | 1414 | |
| ... | ... | @@ -1458,72 +1473,61 @@ pub const DeclGen = struct { |
| 1458 | 1473 | fn resolveUnionType(self: *DeclGen, ty: Type, maybe_active_field: ?usize) !CacheRef { |
| 1459 | 1474 | const mod = self.module; |
| 1460 | 1475 | const ip = &mod.intern_pool; |
| 1461 | | const layout = ty.unionGetLayout(mod); |
| 1462 | 1476 | const union_obj = mod.typeToUnion(ty).?; |
| 1463 | 1477 | |
| 1464 | 1478 | if (union_obj.getLayout(ip) == .Packed) { |
| 1465 | 1479 | return self.todo("packed union types", .{}); |
| 1466 | 1480 | } |
| 1467 | 1481 | |
| 1482 | const layout = self.unionLayout(ty, maybe_active_field); |
| 1483 | |
| 1468 | 1484 | if (layout.payload_size == 0) { |
| 1469 | 1485 | // No payload, so represent this as just the tag type. |
| 1470 | 1486 | return try self.resolveType(union_obj.enum_tag_ty.toType(), .indirect); |
| 1471 | 1487 | } |
| 1472 | 1488 | |
| 1473 | | const entry = try self.type_map.getOrPut(self.gpa, ty.toIntern()); |
| 1474 | | if (entry.found_existing) return entry.value_ptr.ty_ref; |
| 1489 | // TODO: We need to add the active field to the key. |
| 1490 | // const entry = try self.type_map.getOrPut(self.gpa, ty.toIntern()); |
| 1491 | // if (entry.found_existing) return entry.value_ptr.ty_ref; |
| 1475 | 1492 | |
| 1476 | | var member_types = std.BoundedArray(CacheRef, 4){}; |
| 1477 | | var member_names = std.BoundedArray(CacheString, 4){}; |
| 1493 | var member_types: [4]CacheRef = undefined; |
| 1494 | var member_names: [4]CacheString = undefined; |
| 1478 | 1495 | |
| 1479 | | const has_tag = layout.tag_size != 0; |
| 1480 | | const tag_first = layout.tag_align.compare(.gte, layout.payload_align); |
| 1481 | 1496 | const u8_ty_ref = try self.intType(.unsigned, 8); // TODO: What if Int8Type is not enabled? |
| 1482 | 1497 | |
| 1483 | | if (has_tag and tag_first) { |
| 1498 | if (layout.tag_size != 0) { |
| 1484 | 1499 | const tag_ty_ref = try self.resolveType(union_obj.enum_tag_ty.toType(), .indirect); |
| 1485 | | member_types.appendAssumeCapacity(tag_ty_ref); |
| 1486 | | member_names.appendAssumeCapacity(try self.spv.resolveString("(tag)")); |
| 1500 | member_types[layout.tag_index] = tag_ty_ref; |
| 1501 | member_names[layout.tag_index] = try self.spv.resolveString("(tag)"); |
| 1487 | 1502 | } |
| 1488 | 1503 | |
| 1489 | | const active_field = maybe_active_field orelse layout.most_aligned_field; |
| 1490 | | const active_field_ty = union_obj.field_types.get(ip)[active_field].toType(); |
| 1491 | | |
| 1492 | | const active_field_size = if (active_field_ty.hasRuntimeBitsIgnoreComptime(mod)) blk: { |
| 1493 | | const active_payload_ty_ref = try self.resolveType(active_field_ty, .indirect); |
| 1494 | | member_types.appendAssumeCapacity(active_payload_ty_ref); |
| 1495 | | member_names.appendAssumeCapacity(try self.spv.resolveString("(payload)")); |
| 1496 | | break :blk active_field_ty.abiSize(mod); |
| 1497 | | } else 0; |
| 1498 | | |
| 1499 | | const payload_padding_len = layout.payload_size - active_field_size; |
| 1500 | | if (payload_padding_len != 0) { |
| 1501 | | const payload_padding_ty_ref = try self.spv.arrayType(@as(u32, @intCast(payload_padding_len)), u8_ty_ref); |
| 1502 | | member_types.appendAssumeCapacity(payload_padding_ty_ref); |
| 1503 | | member_names.appendAssumeCapacity(try self.spv.resolveString("(payload padding)")); |
| 1504 | if (layout.active_field_size != 0) { |
| 1505 | const active_payload_ty_ref = try self.resolveType(layout.active_field_ty, .indirect); |
| 1506 | member_types[layout.active_field_index] = active_payload_ty_ref; |
| 1507 | member_names[layout.active_field_index] = try self.spv.resolveString("(payload)"); |
| 1504 | 1508 | } |
| 1505 | 1509 | |
| 1506 | | if (has_tag and !tag_first) { |
| 1507 | | const tag_ty_ref = try self.resolveType(union_obj.enum_tag_ty.toType(), .indirect); |
| 1508 | | member_types.appendAssumeCapacity(tag_ty_ref); |
| 1509 | | member_names.appendAssumeCapacity(try self.spv.resolveString("(tag)")); |
| 1510 | if (layout.payload_padding_size != 0) { |
| 1511 | const payload_padding_ty_ref = try self.spv.arrayType(@intCast(layout.payload_padding_size), u8_ty_ref); |
| 1512 | member_types[layout.payload_padding_index] = payload_padding_ty_ref; |
| 1513 | member_names[layout.payload_padding_index] = try self.spv.resolveString("(payload padding)"); |
| 1510 | 1514 | } |
| 1511 | 1515 | |
| 1512 | | if (layout.padding != 0) { |
| 1513 | | const padding_ty_ref = try self.spv.arrayType(layout.padding, u8_ty_ref); |
| 1514 | | member_types.appendAssumeCapacity(padding_ty_ref); |
| 1515 | | member_names.appendAssumeCapacity(try self.spv.resolveString("(padding)")); |
| 1516 | if (layout.padding_size != 0) { |
| 1517 | const padding_ty_ref = try self.spv.arrayType(@intCast(layout.padding_size), u8_ty_ref); |
| 1518 | member_types[layout.padding_index] = padding_ty_ref; |
| 1519 | member_names[layout.padding_index] = try self.spv.resolveString("(padding)"); |
| 1516 | 1520 | } |
| 1517 | 1521 | |
| 1518 | 1522 | const ty_ref = try self.spv.resolve(.{ .struct_type = .{ |
| 1519 | 1523 | .name = try self.resolveTypeName(ty), |
| 1520 | | .member_types = member_types.slice(), |
| 1521 | | .member_names = member_names.slice(), |
| 1524 | .member_types = member_types[0..layout.total_fields], |
| 1525 | .member_names = member_names[0..layout.total_fields], |
| 1522 | 1526 | } }); |
| 1523 | 1527 | |
| 1524 | | entry.value_ptr.* = .{ |
| 1525 | | .ty_ref = ty_ref, |
| 1526 | | }; |
| 1528 | // entry.value_ptr.* = .{ |
| 1529 | // .ty_ref = ty_ref, |
| 1530 | // }; |
| 1527 | 1531 | |
| 1528 | 1532 | return ty_ref; |
| 1529 | 1533 | } |
| ... | ... | @@ -1532,7 +1536,7 @@ pub const DeclGen = struct { |
| 1532 | 1536 | fn resolveType(self: *DeclGen, ty: Type, repr: Repr) Error!CacheRef { |
| 1533 | 1537 | const mod = self.module; |
| 1534 | 1538 | const ip = &mod.intern_pool; |
| 1535 | | log.debug("resolveType: ty = {}", .{ty.fmt(self.module)}); |
| 1539 | log.debug("resolveType: ty = {}", .{ty.fmt(mod)}); |
| 1536 | 1540 | const target = self.getTarget(); |
| 1537 | 1541 | switch (ty.zigTypeTag(mod)) { |
| 1538 | 1542 | .Void, .NoReturn => return try self.spv.resolve(.void_type), |
| ... | ... | @@ -1854,6 +1858,85 @@ pub const DeclGen = struct { |
| 1854 | 1858 | }; |
| 1855 | 1859 | } |
| 1856 | 1860 | |
| 1861 | const UnionLayout = struct { |
| 1862 | active_field: usize, |
| 1863 | active_field_ty: Type, |
| 1864 | payload_size: usize, |
| 1865 | |
| 1866 | tag_size: usize, |
| 1867 | tag_index: usize, |
| 1868 | active_field_size: usize, |
| 1869 | active_field_index: usize, |
| 1870 | payload_padding_size: usize, |
| 1871 | payload_padding_index: usize, |
| 1872 | padding_size: usize, |
| 1873 | padding_index: usize, |
| 1874 | total_fields: usize, |
| 1875 | }; |
| 1876 | |
| 1877 | fn unionLayout(self: *DeclGen, ty: Type, maybe_active_field: ?usize) UnionLayout { |
| 1878 | const mod = self.module; |
| 1879 | const ip = &mod.intern_pool; |
| 1880 | const layout = ty.unionGetLayout(self.module); |
| 1881 | const union_obj = mod.typeToUnion(ty).?; |
| 1882 | |
| 1883 | const active_field = maybe_active_field orelse layout.most_aligned_field; |
| 1884 | const active_field_ty = union_obj.field_types.get(ip)[active_field].toType(); |
| 1885 | |
| 1886 | var union_layout = UnionLayout{ |
| 1887 | .active_field = active_field, |
| 1888 | .active_field_ty = active_field_ty, |
| 1889 | .payload_size = layout.payload_size, |
| 1890 | .tag_size = layout.tag_size, |
| 1891 | .tag_index = undefined, |
| 1892 | .active_field_size = undefined, |
| 1893 | .active_field_index = undefined, |
| 1894 | .payload_padding_size = undefined, |
| 1895 | .payload_padding_index = undefined, |
| 1896 | .padding_size = layout.padding, |
| 1897 | .padding_index = undefined, |
| 1898 | .total_fields = undefined, |
| 1899 | }; |
| 1900 | |
| 1901 | union_layout.active_field_size = if (active_field_ty.hasRuntimeBitsIgnoreComptime(mod)) |
| 1902 | active_field_ty.abiSize(mod) |
| 1903 | else |
| 1904 | 0; |
| 1905 | union_layout.payload_padding_size = layout.payload_size - union_layout.active_field_size; |
| 1906 | |
| 1907 | const tag_first = layout.tag_align.compare(.gte, layout.payload_align); |
| 1908 | var field_index: usize = 0; |
| 1909 | |
| 1910 | if (union_layout.tag_size != 0 and tag_first) { |
| 1911 | union_layout.tag_index = field_index; |
| 1912 | field_index += 1; |
| 1913 | } |
| 1914 | |
| 1915 | if (union_layout.active_field_size != 0) { |
| 1916 | union_layout.active_field_index = field_index; |
| 1917 | field_index += 1; |
| 1918 | } |
| 1919 | |
| 1920 | if (union_layout.payload_padding_size != 0) { |
| 1921 | union_layout.payload_padding_index = field_index; |
| 1922 | field_index += 1; |
| 1923 | } |
| 1924 | |
| 1925 | if (union_layout.tag_size != 0 and !tag_first) { |
| 1926 | union_layout.tag_index = field_index; |
| 1927 | field_index += 1; |
| 1928 | } |
| 1929 | |
| 1930 | if (union_layout.padding_size != 0) { |
| 1931 | union_layout.padding_index = field_index; |
| 1932 | field_index += 1; |
| 1933 | } |
| 1934 | |
| 1935 | union_layout.total_fields = field_index; |
| 1936 | |
| 1937 | return union_layout; |
| 1938 | } |
| 1939 | |
| 1857 | 1940 | /// The SPIR-V backend is not yet advanced enough to support the std testing infrastructure. |
| 1858 | 1941 | /// In order to be able to run tests, we "temporarily" lower test kernels into separate entry- |
| 1859 | 1942 | /// points. The test executor will then be able to invoke these to run the tests. |
| ... | ... | @@ -1995,22 +2078,60 @@ pub const DeclGen = struct { |
| 1995 | 2078 | return self.todo("importing extern variables", .{}); |
| 1996 | 2079 | } |
| 1997 | 2080 | |
| 1998 | | // TODO: integrate with variable(). |
| 2081 | // Currently, initializers for CrossWorkgroup variables is not implemented |
| 2082 | // in Mesa. Therefore we generate an initialization kernel instead. |
| 2083 | |
| 2084 | const void_ty_ref = try self.resolveType(Type.void, .direct); |
| 2085 | |
| 2086 | const initializer_proto_ty_ref = try self.spv.resolve(.{ .function_type = .{ |
| 2087 | .return_type = void_ty_ref, |
| 2088 | .parameters = &.{}, |
| 2089 | } }); |
| 1999 | 2090 | |
| 2091 | // Generate the actual variable for the global... |
| 2000 | 2092 | const final_storage_class = spvStorageClass(decl.@"addrspace"); |
| 2001 | 2093 | const actual_storage_class = switch (final_storage_class) { |
| 2002 | 2094 | .Generic => .CrossWorkgroup, |
| 2003 | 2095 | else => final_storage_class, |
| 2004 | 2096 | }; |
| 2005 | 2097 | |
| 2006 | | try self.lowerIndirectConstant( |
| 2007 | | spv_decl_index, |
| 2008 | | decl.ty, |
| 2009 | | init_val, |
| 2010 | | actual_storage_class, |
| 2011 | | final_storage_class == .Generic, |
| 2012 | | @intCast(decl.alignment.toByteUnits(0)), |
| 2013 | | ); |
| 2098 | const ty_ref = try self.resolveType(decl.ty, .indirect); |
| 2099 | const ptr_ty_ref = try self.spv.ptrType(ty_ref, actual_storage_class); |
| 2100 | |
| 2101 | const begin = self.spv.beginGlobal(); |
| 2102 | try self.spv.globals.section.emit(self.spv.gpa, .OpVariable, .{ |
| 2103 | .id_result_type = self.typeId(ptr_ty_ref), |
| 2104 | .id_result = decl_id, |
| 2105 | .storage_class = actual_storage_class, |
| 2106 | }); |
| 2107 | // TODO: We should be able to get rid of this by now... |
| 2108 | self.spv.endGlobal(spv_decl_index, begin); |
| 2109 | |
| 2110 | // Now emit the instructions that initialize the variable. |
| 2111 | const initializer_id = self.spv.allocId(); |
| 2112 | try self.func.prologue.emit(self.spv.gpa, .OpFunction, .{ |
| 2113 | .id_result_type = self.typeId(void_ty_ref), |
| 2114 | .id_result = initializer_id, |
| 2115 | .function_control = .{}, |
| 2116 | .function_type = self.typeId(initializer_proto_ty_ref), |
| 2117 | }); |
| 2118 | const root_block_id = self.spv.allocId(); |
| 2119 | try self.func.prologue.emit(self.spv.gpa, .OpLabel, .{ |
| 2120 | .id_result = root_block_id, |
| 2121 | }); |
| 2122 | self.current_block_label_id = root_block_id; |
| 2123 | |
| 2124 | const val_id = try self.constant(decl.ty, init_val, .indirect); |
| 2125 | try self.func.body.emit(self.spv.gpa, .OpStore, .{ |
| 2126 | .pointer = decl_id, |
| 2127 | .object = val_id, |
| 2128 | }); |
| 2129 | |
| 2130 | try self.func.body.emit(self.spv.gpa, .OpReturn, {}); |
| 2131 | try self.func.body.emit(self.spv.gpa, .OpFunctionEnd, {}); |
| 2132 | try self.spv.addFunction(spv_decl_index, self.func); |
| 2133 | |
| 2134 | try self.spv.initializers.append(self.spv.gpa, initializer_id); |
| 2014 | 2135 | } |
| 2015 | 2136 | } |
| 2016 | 2137 | |