| ... | @@ -1301,6 +1301,72 @@ pub const DeclGen = struct { | ... | @@ -1301,6 +1301,72 @@ pub const DeclGen = struct { |
| 1301 | .vector_type, .anon_struct_type => unreachable, // TODO | 1301 | .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 | } |
| 1422 | | 1488 | |
| 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; |
| 1432 | | 1498 | |
| ... | @@ -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 | } |
| 1439 | | 1505 | |
| 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 | } |
| 1445 | | 1511 | |
| 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 | } |
| 1451 | | 1517 | |
| 1452 | const ty_ref = try self.spv.resolve(.{ .struct_type = .{ | 1518 | const ty_ref = try self.spv.resolve(.{ .struct_type = .{ |