authorgravatar for robin@voetter.nlRobin Voetter <robin@voetter.nl> 2023-09-16 02:53:14+02:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-09-23 12:36:44-07:00
log240f9d740d4d04619de6c6c7dbad46c78e38c831
tree555c47664a9101fb0b1743c5c2fdd89925da8d48
parentd06862b759ce59d97049043057f95911e7557077

spirv: lower union initialization at runtime


1 files changed, 71 insertions(+), 5 deletions(-)

src/codegen/spirv.zig+71-5
...@@ -1301,6 +1301,72 @@ pub const DeclGen = struct {...@@ -1301,6 +1301,72 @@ pub const DeclGen = struct {
1301 .vector_type, .anon_struct_type => unreachable, // TODO1301 .vector_type, .anon_struct_type => unreachable, // TODO
1302 else => unreachable,1302 else => unreachable,
1303 },1303 },
1304 .un => |un| {
1305 // To initialize a union, generate a temporary variable with the
1306 // type that has the right field active, then pointer-cast and store
1307 // the active field, and finally load and return the entire union.
1308
1309 const layout = ty.unionGetLayout(mod);
1310 const union_ty = mod.typeToUnion(ty).?;
1311
1312 if (union_ty.getLayout(ip) == .Packed) {
1313 return self.todo("packed union types", .{});
1314 } else if (layout.payload_size == 0) {
1315 // No payload, so represent this as just the tag type.
1316 return try self.constant(ty.unionTagTypeSafety(mod).?, un.tag.toValue(), .indirect);
1317 }
1318
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);
1323
1324 const var_id = self.spv.allocId();
1325 try self.func.prologue.emit(self.spv.gpa, .OpVariable, .{
1326 .id_result_type = self.typeId(un_ptr_ty_ref),
1327 .id_result = var_id,
1328 .storage_class = .Function,
1329 });
1330
1331 const index_ty_ref = try self.intType(.unsigned, 32);
1332
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);
1336 const tag_ty = ty.unionTagTypeSafety(mod).?;
1337 const tag_ty_ref = try self.resolveType(tag_ty, .indirect);
1338 const tag_ptr_ty_ref = try self.spv.ptrType(tag_ty_ref, .Function);
1339 const ptr_id = try self.accessChain(tag_ptr_ty_ref, var_id, &.{index_id});
1340 const tag_id = try self.constant(tag_ty, un.tag.toValue(), .indirect);
1341 try self.func.body.emit(self.spv.gpa, .OpStore, .{
1342 .pointer = ptr_id,
1343 .object = tag_id,
1344 });
1345 }
1346
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 });
1359
1360 // Just leave the padding fields uninitialized...
1361
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,
1367 });
1368 return result_id;
1369 },
1304 else => {1370 else => {
1305 // The value cannot be generated directly, so generate it as an indirect constant,1371 // The value cannot be generated directly, so generate it as an indirect constant,
1306 // and then perform an OpLoad.1372 // and then perform an OpLoad.
...@@ -1417,7 +1483,7 @@ pub const DeclGen = struct {...@@ -1417,7 +1483,7 @@ pub const DeclGen = struct {
1417 if (has_tag and tag_first) {1483 if (has_tag and tag_first) {
1418 const tag_ty_ref = try self.resolveType(union_obj.enum_tag_ty.toType(), .indirect);1484 const tag_ty_ref = try self.resolveType(union_obj.enum_tag_ty.toType(), .indirect);
1419 member_types.appendAssumeCapacity(tag_ty_ref);1485 member_types.appendAssumeCapacity(tag_ty_ref);
1420 member_names.appendAssumeCapacity(try self.spv.resolveString("tag"));1486 member_names.appendAssumeCapacity(try self.spv.resolveString("(tag)"));
1421 }1487 }
14221488
1423 const active_field = maybe_active_field orelse layout.most_aligned_field;1489 const active_field = maybe_active_field orelse layout.most_aligned_field;
...@@ -1426,7 +1492,7 @@ pub const DeclGen = struct {...@@ -1426,7 +1492,7 @@ pub const DeclGen = struct {
1426 const active_field_size = if (active_field_ty.hasRuntimeBitsIgnoreComptime(mod)) blk: {1492 const active_field_size = if (active_field_ty.hasRuntimeBitsIgnoreComptime(mod)) blk: {
1427 const active_payload_ty_ref = try self.resolveType(active_field_ty, .indirect);1493 const active_payload_ty_ref = try self.resolveType(active_field_ty, .indirect);
1428 member_types.appendAssumeCapacity(active_payload_ty_ref);1494 member_types.appendAssumeCapacity(active_payload_ty_ref);
1429 member_names.appendAssumeCapacity(try self.spv.resolveString("payload"));1495 member_names.appendAssumeCapacity(try self.spv.resolveString("(payload)"));
1430 break :blk active_field_ty.abiSize(mod);1496 break :blk active_field_ty.abiSize(mod);
1431 } else 0;1497 } else 0;
14321498
...@@ -1434,19 +1500,19 @@ pub const DeclGen = struct {...@@ -1434,19 +1500,19 @@ pub const DeclGen = struct {
1434 if (payload_padding_len != 0) {1500 if (payload_padding_len != 0) {
1435 const payload_padding_ty_ref = try self.spv.arrayType(@as(u32, @intCast(payload_padding_len)), u8_ty_ref);1501 const payload_padding_ty_ref = try self.spv.arrayType(@as(u32, @intCast(payload_padding_len)), u8_ty_ref);
1436 member_types.appendAssumeCapacity(payload_padding_ty_ref);1502 member_types.appendAssumeCapacity(payload_padding_ty_ref);
1437 member_names.appendAssumeCapacity(try self.spv.resolveString("payload_padding"));1503 member_names.appendAssumeCapacity(try self.spv.resolveString("(payload padding)"));
1438 }1504 }
14391505
1440 if (has_tag and !tag_first) {1506 if (has_tag and !tag_first) {
1441 const tag_ty_ref = try self.resolveType(union_obj.enum_tag_ty.toType(), .indirect);1507 const tag_ty_ref = try self.resolveType(union_obj.enum_tag_ty.toType(), .indirect);
1442 member_types.appendAssumeCapacity(tag_ty_ref);1508 member_types.appendAssumeCapacity(tag_ty_ref);
1443 member_names.appendAssumeCapacity(try self.spv.resolveString("tag"));1509 member_names.appendAssumeCapacity(try self.spv.resolveString("(tag)"));
1444 }1510 }
14451511
1446 if (layout.padding != 0) {1512 if (layout.padding != 0) {
1447 const padding_ty_ref = try self.spv.arrayType(layout.padding, u8_ty_ref);1513 const padding_ty_ref = try self.spv.arrayType(layout.padding, u8_ty_ref);
1448 member_types.appendAssumeCapacity(padding_ty_ref);1514 member_types.appendAssumeCapacity(padding_ty_ref);
1449 member_names.appendAssumeCapacity(try self.spv.resolveString("padding"));1515 member_names.appendAssumeCapacity(try self.spv.resolveString("(padding)"));
1450 }1516 }
14511517
1452 const ty_ref = try self.spv.resolve(.{ .struct_type = .{1518 const ty_ref = try self.spv.resolve(.{ .struct_type = .{