authorgravatar for robin@voetter.nlRobin Voetter <robin@voetter.nl> 2023-09-16 13:14:38+02:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-09-23 12:36:44-07:00
logb30cd679878ab0fab7f1e1589c348a2477d542aa
tree15125b5a26e6b0d4d6393570373bbd0bd220c3c0
parent240f9d740d4d04619de6c6c7dbad46c78e38c831

spirv: put global var initializers in functions


2 files changed, 239 insertions(+), 113 deletions(-)

src/codegen/spirv.zig+234-113
...@@ -425,6 +425,7 @@ pub const DeclGen = struct {...@@ -425,6 +425,7 @@ pub const DeclGen = struct {
425 // See https://github.com/KhronosGroup/SPIRV-LLVM-Translator/issues/1349425 // See https://github.com/KhronosGroup/SPIRV-LLVM-Translator/issues/1349
426 // For now, just initialize the struct by setting the fields manually...426 // For now, just initialize the struct by setting the fields manually...
427 // TODO: Make this OpCompositeConstruct when we can427 // TODO: Make this OpCompositeConstruct when we can
428 // TODO: Make this Function storage type
428 const ptr_composite_id = try self.alloc(result_ty_ref, null);429 const ptr_composite_id = try self.alloc(result_ty_ref, null);
429 // Note: using 32-bit ints here because usize crashes the translator as well430 // Note: using 32-bit ints here because usize crashes the translator as well
430 const index_ty_ref = try self.intType(.unsigned, 32);431 const index_ty_ref = try self.intType(.unsigned, 32);
...@@ -450,6 +451,40 @@ pub const DeclGen = struct {...@@ -450,6 +451,40 @@ pub const DeclGen = struct {
450 return result_id;451 return result_id;
451 }452 }
452453
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 fn constructDeclRef(self: *DeclGen, ty: Type, decl_index: Decl.Index) !IdRef {488 fn constructDeclRef(self: *DeclGen, ty: Type, decl_index: Decl.Index) !IdRef {
454 const mod = self.module;489 const mod = self.module;
455 const ty_ref = try self.resolveType(ty, .direct);490 const ty_ref = try self.resolveType(ty, .direct);
...@@ -459,10 +494,9 @@ pub const DeclGen = struct {...@@ -459,10 +494,9 @@ pub const DeclGen = struct {
459 switch (mod.intern_pool.indexToKey(decl.val.ip_index)) {494 switch (mod.intern_pool.indexToKey(decl.val.ip_index)) {
460 .func => {495 .func => {
461 // TODO: Properly lower function pointers. For now we are going to hack around it and496 // 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,497 // just generate an empty pointer. Function pointers are represented by a pointer to usize.
463 // though.
464 // TODO: Add dependency498 // TODO: Add dependency
465 return try self.spv.constInt(ty_ref, 0);499 return try self.spv.constNull(ty_ref);
466 },500 },
467 .extern_func => unreachable, // TODO501 .extern_func => unreachable, // TODO
468 else => {502 else => {
...@@ -1074,7 +1108,7 @@ pub const DeclGen = struct {...@@ -1074,7 +1108,7 @@ pub const DeclGen = struct {
1074 else => {},1108 else => {},
1075 }1109 }
10761110
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 if (val.isUndefDeep(mod)) {1112 if (val.isUndefDeep(mod)) {
1079 return self.spv.constUndef(result_ty_ref);1113 return self.spv.constUndef(result_ty_ref);
1080 }1114 }
...@@ -1270,7 +1304,7 @@ pub const DeclGen = struct {...@@ -1270,7 +1304,7 @@ pub const DeclGen = struct {
1270 if (array_type.sentinel != .none) {1304 if (array_type.sentinel != .none) {
1271 constituents[constituents.len - 1] = try self.constant(elem_ty, array_type.sentinel.toValue(), .indirect);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 .struct_type => {1309 .struct_type => {
1276 const struct_ty = mod.typeToStruct(ty).?;1310 const struct_ty = mod.typeToStruct(ty).?;
...@@ -1281,18 +1315,14 @@ pub const DeclGen = struct {...@@ -1281,18 +1315,14 @@ pub const DeclGen = struct {
1281 var constituents = std.ArrayList(IdRef).init(self.gpa);1315 var constituents = std.ArrayList(IdRef).init(self.gpa);
1282 defer constituents.deinit();1316 defer constituents.deinit();
12831317
1284 for (struct_ty.fields.values(), 0..) |field, i| {1318 var field_it = struct_ty.runtimeFieldIterator(mod);
1285 if (field.is_comptime or !field.ty.hasRuntimeBits(mod)) continue;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);
12861325
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 try constituents.append(field_id);1326 try constituents.append(field_id);
1297 }1327 }
12981328
...@@ -1306,33 +1336,35 @@ pub const DeclGen = struct {...@@ -1306,33 +1336,35 @@ pub const DeclGen = struct {
1306 // type that has the right field active, then pointer-cast and store1336 // type that has the right field active, then pointer-cast and store
1307 // the active field, and finally load and return the entire union.1337 // the active field, and finally load and return the entire union.
13081338
1309 const layout = ty.unionGetLayout(mod);
1310 const union_ty = mod.typeToUnion(ty).?;1339 const union_ty = mod.typeToUnion(ty).?;
13111340
1312 if (union_ty.getLayout(ip) == .Packed) {1341 if (union_ty.getLayout(ip) == .Packed) {
1313 return self.todo("packed union types", .{});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 // No payload, so represent this as just the tag type.1349 // No payload, so represent this as just the tag type.
1316 return try self.constant(ty.unionTagTypeSafety(mod).?, un.tag.toValue(), .indirect);1350 return try self.constant(ty.unionTagTypeSafety(mod).?, un.tag.toValue(), .indirect);
1317 }1351 }
13181352
1319 const has_tag = layout.tag_size != 0;1353 const un_active_ty_ref = try self.resolveUnionType(ty, active_field);
1320 const tag_first = layout.tag_align >= layout.payload_align;1354 const un_active_ptr_ty_ref = try self.spv.ptrType(un_active_ty_ref, .Function);
13211355 const un_general_ptr_ty_ref = try self.spv.ptrType(result_ty_ref, .Function);
1322 const un_ptr_ty_ref = try self.spv.ptrType(result_ty_ref, .Function);
13231356
1324 const var_id = self.spv.allocId();1357 const var_id = self.spv.allocId();
1325 try self.func.prologue.emit(self.spv.gpa, .OpVariable, .{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 .id_result = var_id,1360 .id_result = var_id,
1328 .storage_class = .Function,1361 .storage_class = .Function,
1329 });1362 });
13301363
1331 const index_ty_ref = try self.intType(.unsigned, 32);1364 const index_ty_ref = try self.intType(.unsigned, 32);
13321365
1333 if (has_tag) {1366 if (layout.tag_size != 0) {
1334 const tag_index: u32 = if (tag_first) 0 else 1;1367 const index_id = try self.spv.constInt(index_ty_ref, @as(u32, @intCast(layout.tag_index)));
1335 const index_id = try self.spv.constInt(index_ty_ref, tag_index);
1336 const tag_ty = ty.unionTagTypeSafety(mod).?;1368 const tag_ty = ty.unionTagTypeSafety(mod).?;
1337 const tag_ty_ref = try self.resolveType(tag_ty, .indirect);1369 const tag_ty_ref = try self.resolveType(tag_ty, .indirect);
1338 const tag_ptr_ty_ref = try self.spv.ptrType(tag_ty_ref, .Function);1370 const tag_ptr_ty_ref = try self.spv.ptrType(tag_ty_ref, .Function);
...@@ -1344,56 +1376,39 @@ pub const DeclGen = struct {...@@ -1344,56 +1376,39 @@ pub const DeclGen = struct {
1344 });1376 });
1345 }1377 }
13461378
1347 const pl_index: u32 = if (tag_first) 1 else 0;1379 if (layout.active_field_size != 0) {
1348 const index_id = try self.spv.constInt(index_ty_ref, pl_index);1380 const index_id = try self.spv.constInt(index_ty_ref, @as(u32, @intCast(layout.active_field_index)));
1349 const active_field = ty.unionTagFieldIndex(un.tag.toValue(), mod).?;1381 const active_field_ty_ref = try self.resolveType(layout.active_field_ty, .indirect);
1350 const active_field_ty = union_ty.field_types.get(ip)[active_field].toType();1382 const active_field_ptr_ty_ref = try self.spv.ptrType(active_field_ty_ref, .Function);
1351 const active_field_ty_ref = try self.resolveType(active_field_ty, .indirect);1383 const ptr_id = try self.accessChain(active_field_ptr_ty_ref, var_id, &.{index_id});
1352 const active_field_ptr_ty_ref = try self.spv.ptrType(active_field_ty_ref, .Function);1384 const value_id = try self.constant(layout.active_field_ty, un.val.toValue(), .indirect);
1353 const ptr_id = try self.accessChain(active_field_ptr_ty_ref, var_id, &.{index_id});1385 try self.func.body.emit(self.spv.gpa, .OpStore, .{
1354 const value_id = try self.constant(active_field_ty, un.val.toValue(), .indirect);1386 .pointer = ptr_id,
1355 try self.func.body.emit(self.spv.gpa, .OpStore, .{1387 .object = value_id,
1356 .pointer = ptr_id,1388 });
1357 .object = value_id,1389 }
1358 });
13591390
1360 // Just leave the padding fields uninitialized...1391 // Just leave the padding fields uninitialized...
1392 // TODO: Or should we initialize them with undef explicitly?
13611393
1362 const result_id = self.spv.allocId();1394 // Now cast the pointer and load it as the 'generic' union type.
1363 try self.func.body.emit(self.spv.gpa, .OpLoad, .{1395
1364 .id_result_type = self.typeId(result_ty_ref),1396 const casted_var_id = self.spv.allocId();
1365 .id_result = result_id,1397 try self.func.body.emit(self.spv.gpa, .OpBitcast, .{
1366 .pointer = var_id,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, {});
13871402
1403 const result_id = self.spv.allocId();
1388 try self.func.body.emit(self.spv.gpa, .OpLoad, .{1404 try self.func.body.emit(self.spv.gpa, .OpLoad, .{
1389 .id_result_type = self.typeId(result_ty_ref),1405 .id_result_type = self.typeId(result_ty_ref),
1390 .id_result = result_id,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 return result_id;1409 return result_id;
1396 },1410 },
1411 .memoized_call => unreachable,
1397 }1412 }
1398 }1413 }
13991414
...@@ -1458,72 +1473,61 @@ pub const DeclGen = struct {...@@ -1458,72 +1473,61 @@ pub const DeclGen = struct {
1458 fn resolveUnionType(self: *DeclGen, ty: Type, maybe_active_field: ?usize) !CacheRef {1473 fn resolveUnionType(self: *DeclGen, ty: Type, maybe_active_field: ?usize) !CacheRef {
1459 const mod = self.module;1474 const mod = self.module;
1460 const ip = &mod.intern_pool;1475 const ip = &mod.intern_pool;
1461 const layout = ty.unionGetLayout(mod);
1462 const union_obj = mod.typeToUnion(ty).?;1476 const union_obj = mod.typeToUnion(ty).?;
14631477
1464 if (union_obj.getLayout(ip) == .Packed) {1478 if (union_obj.getLayout(ip) == .Packed) {
1465 return self.todo("packed union types", .{});1479 return self.todo("packed union types", .{});
1466 }1480 }
14671481
1482 const layout = self.unionLayout(ty, maybe_active_field);
1483
1468 if (layout.payload_size == 0) {1484 if (layout.payload_size == 0) {
1469 // No payload, so represent this as just the tag type.1485 // No payload, so represent this as just the tag type.
1470 return try self.resolveType(union_obj.enum_tag_ty.toType(), .indirect);1486 return try self.resolveType(union_obj.enum_tag_ty.toType(), .indirect);
1471 }1487 }
14721488
1473 const entry = try self.type_map.getOrPut(self.gpa, ty.toIntern());1489 // TODO: We need to add the active field to the key.
1474 if (entry.found_existing) return entry.value_ptr.ty_ref;1490 // const entry = try self.type_map.getOrPut(self.gpa, ty.toIntern());
1491 // if (entry.found_existing) return entry.value_ptr.ty_ref;
14751492
1476 var member_types = std.BoundedArray(CacheRef, 4){};1493 var member_types: [4]CacheRef = undefined;
1477 var member_names = std.BoundedArray(CacheString, 4){};1494 var member_names: [4]CacheString = undefined;
14781495
1479 const has_tag = layout.tag_size != 0;
1480 const tag_first = layout.tag_align.compare(.gte, layout.payload_align);
1481 const u8_ty_ref = try self.intType(.unsigned, 8); // TODO: What if Int8Type is not enabled?1496 const u8_ty_ref = try self.intType(.unsigned, 8); // TODO: What if Int8Type is not enabled?
14821497
1483 if (has_tag and tag_first) {1498 if (layout.tag_size != 0) {
1484 const tag_ty_ref = try self.resolveType(union_obj.enum_tag_ty.toType(), .indirect);1499 const tag_ty_ref = try self.resolveType(union_obj.enum_tag_ty.toType(), .indirect);
1485 member_types.appendAssumeCapacity(tag_ty_ref);1500 member_types[layout.tag_index] = tag_ty_ref;
1486 member_names.appendAssumeCapacity(try self.spv.resolveString("(tag)"));1501 member_names[layout.tag_index] = try self.spv.resolveString("(tag)");
1487 }1502 }
14881503
1489 const active_field = maybe_active_field orelse layout.most_aligned_field;1504 if (layout.active_field_size != 0) {
1490 const active_field_ty = union_obj.field_types.get(ip)[active_field].toType();1505 const active_payload_ty_ref = try self.resolveType(layout.active_field_ty, .indirect);
14911506 member_types[layout.active_field_index] = active_payload_ty_ref;
1492 const active_field_size = if (active_field_ty.hasRuntimeBitsIgnoreComptime(mod)) blk: {1507 member_names[layout.active_field_index] = try self.spv.resolveString("(payload)");
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 }1508 }
15051509
1506 if (has_tag and !tag_first) {1510 if (layout.payload_padding_size != 0) {
1507 const tag_ty_ref = try self.resolveType(union_obj.enum_tag_ty.toType(), .indirect);1511 const payload_padding_ty_ref = try self.spv.arrayType(@intCast(layout.payload_padding_size), u8_ty_ref);
1508 member_types.appendAssumeCapacity(tag_ty_ref);1512 member_types[layout.payload_padding_index] = payload_padding_ty_ref;
1509 member_names.appendAssumeCapacity(try self.spv.resolveString("(tag)"));1513 member_names[layout.payload_padding_index] = try self.spv.resolveString("(payload padding)");
1510 }1514 }
15111515
1512 if (layout.padding != 0) {1516 if (layout.padding_size != 0) {
1513 const padding_ty_ref = try self.spv.arrayType(layout.padding, u8_ty_ref);1517 const padding_ty_ref = try self.spv.arrayType(@intCast(layout.padding_size), u8_ty_ref);
1514 member_types.appendAssumeCapacity(padding_ty_ref);1518 member_types[layout.padding_index] = padding_ty_ref;
1515 member_names.appendAssumeCapacity(try self.spv.resolveString("(padding)"));1519 member_names[layout.padding_index] = try self.spv.resolveString("(padding)");
1516 }1520 }
15171521
1518 const ty_ref = try self.spv.resolve(.{ .struct_type = .{1522 const ty_ref = try self.spv.resolve(.{ .struct_type = .{
1519 .name = try self.resolveTypeName(ty),1523 .name = try self.resolveTypeName(ty),
1520 .member_types = member_types.slice(),1524 .member_types = member_types[0..layout.total_fields],
1521 .member_names = member_names.slice(),1525 .member_names = member_names[0..layout.total_fields],
1522 } });1526 } });
15231527
1524 entry.value_ptr.* = .{1528 // entry.value_ptr.* = .{
1525 .ty_ref = ty_ref,1529 // .ty_ref = ty_ref,
1526 };1530 // };
15271531
1528 return ty_ref;1532 return ty_ref;
1529 }1533 }
...@@ -1532,7 +1536,7 @@ pub const DeclGen = struct {...@@ -1532,7 +1536,7 @@ pub const DeclGen = struct {
1532 fn resolveType(self: *DeclGen, ty: Type, repr: Repr) Error!CacheRef {1536 fn resolveType(self: *DeclGen, ty: Type, repr: Repr) Error!CacheRef {
1533 const mod = self.module;1537 const mod = self.module;
1534 const ip = &mod.intern_pool;1538 const ip = &mod.intern_pool;
1535 log.debug("resolveType: ty = {}", .{ty.fmt(self.module)});1539 log.debug("resolveType: ty = {}", .{ty.fmt(mod)});
1536 const target = self.getTarget();1540 const target = self.getTarget();
1537 switch (ty.zigTypeTag(mod)) {1541 switch (ty.zigTypeTag(mod)) {
1538 .Void, .NoReturn => return try self.spv.resolve(.void_type),1542 .Void, .NoReturn => return try self.spv.resolve(.void_type),
...@@ -1854,6 +1858,85 @@ pub const DeclGen = struct {...@@ -1854,6 +1858,85 @@ pub const DeclGen = struct {
1854 };1858 };
1855 }1859 }
18561860
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 /// The SPIR-V backend is not yet advanced enough to support the std testing infrastructure.1940 /// The SPIR-V backend is not yet advanced enough to support the std testing infrastructure.
1858 /// In order to be able to run tests, we "temporarily" lower test kernels into separate entry-1941 /// In order to be able to run tests, we "temporarily" lower test kernels into separate entry-
1859 /// points. The test executor will then be able to invoke these to run the tests.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,22 +2078,60 @@ pub const DeclGen = struct {
1995 return self.todo("importing extern variables", .{});2078 return self.todo("importing extern variables", .{});
1996 }2079 }
19972080
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 } });
19992090
2091 // Generate the actual variable for the global...
2000 const final_storage_class = spvStorageClass(decl.@"addrspace");2092 const final_storage_class = spvStorageClass(decl.@"addrspace");
2001 const actual_storage_class = switch (final_storage_class) {2093 const actual_storage_class = switch (final_storage_class) {
2002 .Generic => .CrossWorkgroup,2094 .Generic => .CrossWorkgroup,
2003 else => final_storage_class,2095 else => final_storage_class,
2004 };2096 };
20052097
2006 try self.lowerIndirectConstant(2098 const ty_ref = try self.resolveType(decl.ty, .indirect);
2007 spv_decl_index,2099 const ptr_ty_ref = try self.spv.ptrType(ty_ref, actual_storage_class);
2008 decl.ty,2100
2009 init_val,2101 const begin = self.spv.beginGlobal();
2010 actual_storage_class,2102 try self.spv.globals.section.emit(self.spv.gpa, .OpVariable, .{
2011 final_storage_class == .Generic,2103 .id_result_type = self.typeId(ptr_ty_ref),
2012 @intCast(decl.alignment.toByteUnits(0)),2104 .id_result = decl_id,
2013 );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 }
20162137
src/codegen/spirv/Module.zig+5
...@@ -174,6 +174,9 @@ globals: struct {...@@ -174,6 +174,9 @@ globals: struct {
174 section: Section = .{},174 section: Section = .{},
175} = .{},175} = .{},
176176
177/// The function IDs of global variable initializers
178initializers: std.ArrayListUnmanaged(IdRef) = .{},
179
177pub fn init(gpa: Allocator, arena: Allocator) Module {180pub fn init(gpa: Allocator, arena: Allocator) Module {
178 return .{181 return .{
179 .gpa = gpa,182 .gpa = gpa,
...@@ -202,6 +205,8 @@ pub fn deinit(self: *Module) void {...@@ -202,6 +205,8 @@ pub fn deinit(self: *Module) void {
202 self.globals.globals.deinit(self.gpa);205 self.globals.globals.deinit(self.gpa);
203 self.globals.section.deinit(self.gpa);206 self.globals.section.deinit(self.gpa);
204207
208 self.initializers.deinit(self.gpa);
209
205 self.* = undefined;210 self.* = undefined;
206}211}
207212