| ... | ... | @@ -874,12 +874,12 @@ const DeclGen = struct { |
| 874 | 874 | }, |
| 875 | 875 | .un => |un| { |
| 876 | 876 | const active_field = ty.unionTagFieldIndex(un.tag.toValue(), mod).?; |
| 877 | | const layout = self.unionLayout(ty, active_field); |
| 878 | | const payload = if (layout.active_field_size != 0) |
| 879 | | try self.constant(layout.active_field_ty, un.val.toValue(), .direct) |
| 877 | const union_obj = mod.typeToUnion(ty).?; |
| 878 | const field_ty = union_obj.field_types.get(ip)[active_field].toType(); |
| 879 | const payload = if (field_ty.hasRuntimeBitsIgnoreComptime(mod)) |
| 880 | try self.constant(field_ty, un.val.toValue(), .direct) |
| 880 | 881 | else |
| 881 | 882 | null; |
| 882 | | |
| 883 | 883 | return try self.unionInit(ty, active_field, payload); |
| 884 | 884 | }, |
| 885 | 885 | .memoized_call => unreachable, |
| ... | ... | @@ -1105,29 +1105,25 @@ const DeclGen = struct { |
| 1105 | 1105 | return try self.spv.ptrType(child_ty_ref, storage_class); |
| 1106 | 1106 | } |
| 1107 | 1107 | |
| 1108 | | /// Generate a union type, optionally with a known field. If the tag alignment is greater |
| 1109 | | /// than that of the payload, a regular union (non-packed, with both tag and payload), will |
| 1110 | | /// be generated as follows: |
| 1111 | | /// If the active field is known: |
| 1108 | /// Generate a union type. Union types are always generated with the |
| 1109 | /// most aligned field active. If the tag alignment is greater |
| 1110 | /// than that of the payload, a regular union (non-packed, with both tag and |
| 1111 | /// payload), will be generated as follows: |
| 1112 | 1112 | /// struct { |
| 1113 | 1113 | /// tag: TagType, |
| 1114 | | /// payload: ActivePayloadType, |
| 1115 | | /// payload_padding: [payload_size - @sizeOf(ActivePayloadType)]u8, |
| 1114 | /// payload: MostAlignedFieldType, |
| 1115 | /// payload_padding: [payload_size - @sizeOf(MostAlignedFieldType)]u8, |
| 1116 | 1116 | /// padding: [padding_size]u8, |
| 1117 | 1117 | /// } |
| 1118 | 1118 | /// If the payload alignment is greater than that of the tag: |
| 1119 | 1119 | /// struct { |
| 1120 | | /// payload: ActivePayloadType, |
| 1121 | | /// payload_padding: [payload_size - @sizeOf(ActivePayloadType)]u8, |
| 1120 | /// payload: MostAlignedFieldType, |
| 1121 | /// payload_padding: [payload_size - @sizeOf(MostAlignedFieldType)]u8, |
| 1122 | 1122 | /// tag: TagType, |
| 1123 | 1123 | /// padding: [padding_size]u8, |
| 1124 | 1124 | /// } |
| 1125 | | /// If the active payload is unknown, it will default back to the most aligned field. This is |
| 1126 | | /// to make sure that the overal struct has the correct alignment in spir-v. |
| 1127 | 1125 | /// If any of the fields' size is 0, it will be omitted. |
| 1128 | | /// NOTE: When the active field is set to something other than the most aligned field, the |
| 1129 | | /// resulting struct will be *underaligned*. |
| 1130 | | fn resolveUnionType(self: *DeclGen, ty: Type, maybe_active_field: ?usize) !CacheRef { |
| 1126 | fn resolveUnionType(self: *DeclGen, ty: Type) !CacheRef { |
| 1131 | 1127 | const mod = self.module; |
| 1132 | 1128 | const ip = &mod.intern_pool; |
| 1133 | 1129 | const union_obj = mod.typeToUnion(ty).?; |
| ... | ... | @@ -1136,17 +1132,13 @@ const DeclGen = struct { |
| 1136 | 1132 | return self.todo("packed union types", .{}); |
| 1137 | 1133 | } |
| 1138 | 1134 | |
| 1139 | | const layout = self.unionLayout(ty, maybe_active_field); |
| 1140 | | |
| 1141 | | if (layout.payload_size == 0) { |
| 1135 | const layout = self.unionLayout(ty); |
| 1136 | if (!layout.has_payload) { |
| 1142 | 1137 | // No payload, so represent this as just the tag type. |
| 1143 | 1138 | return try self.resolveType(union_obj.enum_tag_ty.toType(), .indirect); |
| 1144 | 1139 | } |
| 1145 | 1140 | |
| 1146 | | // TODO: We need to add the active field to the key, somehow. |
| 1147 | | if (maybe_active_field == null) { |
| 1148 | | if (self.type_map.get(ty.toIntern())) |info| return info.ty_ref; |
| 1149 | | } |
| 1141 | if (self.type_map.get(ty.toIntern())) |info| return info.ty_ref; |
| 1150 | 1142 | |
| 1151 | 1143 | var member_types: [4]CacheRef = undefined; |
| 1152 | 1144 | var member_names: [4]CacheString = undefined; |
| ... | ... | @@ -1159,10 +1151,10 @@ const DeclGen = struct { |
| 1159 | 1151 | member_names[layout.tag_index] = try self.spv.resolveString("(tag)"); |
| 1160 | 1152 | } |
| 1161 | 1153 | |
| 1162 | | if (layout.active_field_size != 0) { |
| 1163 | | const active_payload_ty_ref = try self.resolveType(layout.active_field_ty, .indirect); |
| 1164 | | member_types[layout.active_field_index] = active_payload_ty_ref; |
| 1165 | | member_names[layout.active_field_index] = try self.spv.resolveString("(payload)"); |
| 1154 | if (layout.payload_size != 0) { |
| 1155 | const payload_ty_ref = try self.resolveType(layout.payload_ty, .indirect); |
| 1156 | member_types[layout.payload_index] = payload_ty_ref; |
| 1157 | member_names[layout.payload_index] = try self.spv.resolveString("(payload)"); |
| 1166 | 1158 | } |
| 1167 | 1159 | |
| 1168 | 1160 | if (layout.payload_padding_size != 0) { |
| ... | ... | @@ -1183,9 +1175,7 @@ const DeclGen = struct { |
| 1183 | 1175 | .member_names = member_names[0..layout.total_fields], |
| 1184 | 1176 | } }); |
| 1185 | 1177 | |
| 1186 | | if (maybe_active_field == null) { |
| 1187 | | try self.type_map.put(self.gpa, ty.toIntern(), .{ .ty_ref = ty_ref }); |
| 1188 | | } |
| 1178 | try self.type_map.put(self.gpa, ty.toIntern(), .{ .ty_ref = ty_ref }); |
| 1189 | 1179 | return ty_ref; |
| 1190 | 1180 | } |
| 1191 | 1181 | |
| ... | ... | @@ -1453,7 +1443,7 @@ const DeclGen = struct { |
| 1453 | 1443 | try self.type_map.put(self.gpa, ty.toIntern(), .{ .ty_ref = ty_ref }); |
| 1454 | 1444 | return ty_ref; |
| 1455 | 1445 | }, |
| 1456 | | .Union => return try self.resolveUnionType(ty, null), |
| 1446 | .Union => return try self.resolveUnionType(ty), |
| 1457 | 1447 | .ErrorSet => return try self.intType(.unsigned, 16), |
| 1458 | 1448 | .ErrorUnion => { |
| 1459 | 1449 | const payload_ty = ty.errorUnionPayload(mod); |
| ... | ... | @@ -1567,14 +1557,16 @@ const DeclGen = struct { |
| 1567 | 1557 | } |
| 1568 | 1558 | |
| 1569 | 1559 | const UnionLayout = struct { |
| 1570 | | active_field: u32, |
| 1571 | | active_field_ty: Type, |
| 1572 | | payload_size: u32, |
| 1573 | | |
| 1560 | /// If false, this union is represented |
| 1561 | /// by only an integer of the tag type. |
| 1562 | has_payload: bool, |
| 1574 | 1563 | tag_size: u32, |
| 1575 | 1564 | tag_index: u32, |
| 1576 | | active_field_size: u32, |
| 1577 | | active_field_index: u32, |
| 1565 | /// Note: This is the size of the payload type itself, NOT the size of the ENTIRE payload. |
| 1566 | /// Use `has_payload` instead!! |
| 1567 | payload_ty: Type, |
| 1568 | payload_size: u32, |
| 1569 | payload_index: u32, |
| 1578 | 1570 | payload_padding_size: u32, |
| 1579 | 1571 | payload_padding_index: u32, |
| 1580 | 1572 | padding_size: u32, |
| ... | ... | @@ -1582,23 +1574,19 @@ const DeclGen = struct { |
| 1582 | 1574 | total_fields: u32, |
| 1583 | 1575 | }; |
| 1584 | 1576 | |
| 1585 | | fn unionLayout(self: *DeclGen, ty: Type, maybe_active_field: ?usize) UnionLayout { |
| 1577 | fn unionLayout(self: *DeclGen, ty: Type) UnionLayout { |
| 1586 | 1578 | const mod = self.module; |
| 1587 | 1579 | const ip = &mod.intern_pool; |
| 1588 | 1580 | const layout = ty.unionGetLayout(self.module); |
| 1589 | 1581 | const union_obj = mod.typeToUnion(ty).?; |
| 1590 | 1582 | |
| 1591 | | const active_field = maybe_active_field orelse layout.most_aligned_field; |
| 1592 | | const active_field_ty = union_obj.field_types.get(ip)[active_field].toType(); |
| 1593 | | |
| 1594 | 1583 | var union_layout = UnionLayout{ |
| 1595 | | .active_field = @intCast(active_field), |
| 1596 | | .active_field_ty = active_field_ty, |
| 1597 | | .payload_size = @intCast(layout.payload_size), |
| 1584 | .has_payload = layout.payload_size != 0, |
| 1598 | 1585 | .tag_size = @intCast(layout.tag_size), |
| 1599 | 1586 | .tag_index = undefined, |
| 1600 | | .active_field_size = undefined, |
| 1601 | | .active_field_index = undefined, |
| 1587 | .payload_ty = undefined, |
| 1588 | .payload_size = undefined, |
| 1589 | .payload_index = undefined, |
| 1602 | 1590 | .payload_padding_size = undefined, |
| 1603 | 1591 | .payload_padding_index = undefined, |
| 1604 | 1592 | .padding_size = @intCast(layout.padding), |
| ... | ... | @@ -1606,11 +1594,16 @@ const DeclGen = struct { |
| 1606 | 1594 | .total_fields = undefined, |
| 1607 | 1595 | }; |
| 1608 | 1596 | |
| 1609 | | union_layout.active_field_size = if (active_field_ty.hasRuntimeBitsIgnoreComptime(mod)) |
| 1610 | | @intCast(active_field_ty.abiSize(mod)) |
| 1611 | | else |
| 1612 | | 0; |
| 1613 | | union_layout.payload_padding_size = @intCast(layout.payload_size - union_layout.active_field_size); |
| 1597 | if (union_layout.has_payload) { |
| 1598 | const most_aligned_field = layout.most_aligned_field; |
| 1599 | const most_aligned_field_ty = union_obj.field_types.get(ip)[most_aligned_field].toType(); |
| 1600 | union_layout.payload_ty = most_aligned_field_ty; |
| 1601 | union_layout.payload_size = @intCast(most_aligned_field_ty.abiSize(mod)); |
| 1602 | } else { |
| 1603 | union_layout.payload_size = 0; |
| 1604 | } |
| 1605 | |
| 1606 | union_layout.payload_padding_size = @intCast(layout.payload_size - union_layout.payload_size); |
| 1614 | 1607 | |
| 1615 | 1608 | const tag_first = layout.tag_align.compare(.gte, layout.payload_align); |
| 1616 | 1609 | var field_index: u32 = 0; |
| ... | ... | @@ -1620,8 +1613,8 @@ const DeclGen = struct { |
| 1620 | 1613 | field_index += 1; |
| 1621 | 1614 | } |
| 1622 | 1615 | |
| 1623 | | if (union_layout.active_field_size != 0) { |
| 1624 | | union_layout.active_field_index = field_index; |
| 1616 | if (union_layout.payload_size != 0) { |
| 1617 | union_layout.payload_index = field_index; |
| 1625 | 1618 | field_index += 1; |
| 1626 | 1619 | } |
| 1627 | 1620 | |
| ... | ... | @@ -3300,7 +3293,7 @@ const DeclGen = struct { |
| 3300 | 3293 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 3301 | 3294 | const un_ptr_ty = self.typeOf(bin_op.lhs); |
| 3302 | 3295 | const un_ty = un_ptr_ty.childType(mod); |
| 3303 | | const layout = self.unionLayout(un_ty, null); |
| 3296 | const layout = self.unionLayout(un_ty); |
| 3304 | 3297 | |
| 3305 | 3298 | if (layout.tag_size == 0) return; |
| 3306 | 3299 | |
| ... | ... | @@ -3310,7 +3303,7 @@ const DeclGen = struct { |
| 3310 | 3303 | const union_ptr_id = try self.resolve(bin_op.lhs); |
| 3311 | 3304 | const new_tag_id = try self.resolve(bin_op.rhs); |
| 3312 | 3305 | |
| 3313 | | if (layout.payload_size == 0) { |
| 3306 | if (!layout.has_payload) { |
| 3314 | 3307 | try self.store(tag_ty, union_ptr_id, new_tag_id, .{ .is_volatile = un_ptr_ty.isVolatilePtr(mod) }); |
| 3315 | 3308 | } else { |
| 3316 | 3309 | const ptr_id = try self.accessChain(tag_ptr_ty_ref, union_ptr_id, &.{layout.tag_index}); |
| ... | ... | @@ -3325,11 +3318,11 @@ const DeclGen = struct { |
| 3325 | 3318 | const un_ty = self.typeOf(ty_op.operand); |
| 3326 | 3319 | |
| 3327 | 3320 | const mod = self.module; |
| 3328 | | const layout = self.unionLayout(un_ty, null); |
| 3321 | const layout = self.unionLayout(un_ty); |
| 3329 | 3322 | if (layout.tag_size == 0) return null; |
| 3330 | 3323 | |
| 3331 | 3324 | const union_handle = try self.resolve(ty_op.operand); |
| 3332 | | if (layout.payload_size == 0) return union_handle; |
| 3325 | if (!layout.has_payload) return union_handle; |
| 3333 | 3326 | |
| 3334 | 3327 | const tag_ty = un_ty.unionTagTypeSafety(mod).?; |
| 3335 | 3328 | return try self.extractField(tag_ty, union_handle, layout.tag_index); |
| ... | ... | @@ -3342,8 +3335,8 @@ const DeclGen = struct { |
| 3342 | 3335 | payload: ?IdRef, |
| 3343 | 3336 | ) !IdRef { |
| 3344 | 3337 | // To initialize a union, generate a temporary variable with the |
| 3345 | | // type that has the right field active, then pointer-cast and store |
| 3346 | | // the active field, and finally load and return the entire union. |
| 3338 | // union type, then get the field pointer and pointer-cast it to the |
| 3339 | // right type to store it. Finally load the entire union. |
| 3347 | 3340 | |
| 3348 | 3341 | const mod = self.module; |
| 3349 | 3342 | const ip = &mod.intern_pool; |
| ... | ... | @@ -3354,7 +3347,7 @@ const DeclGen = struct { |
| 3354 | 3347 | } |
| 3355 | 3348 | |
| 3356 | 3349 | const maybe_tag_ty = ty.unionTagTypeSafety(mod); |
| 3357 | | const layout = self.unionLayout(ty, active_field); |
| 3350 | const layout = self.unionLayout(ty); |
| 3358 | 3351 | |
| 3359 | 3352 | const tag_int = if (layout.tag_size != 0) blk: { |
| 3360 | 3353 | const tag_ty = maybe_tag_ty.?; |
| ... | ... | @@ -3365,23 +3358,12 @@ const DeclGen = struct { |
| 3365 | 3358 | break :blk tag_int_val.toUnsignedInt(mod); |
| 3366 | 3359 | } else 0; |
| 3367 | 3360 | |
| 3368 | | if (layout.payload_size == 0) { |
| 3361 | if (!layout.has_payload) { |
| 3369 | 3362 | const tag_ty_ref = try self.resolveType(maybe_tag_ty.?, .direct); |
| 3370 | 3363 | return try self.constInt(tag_ty_ref, tag_int); |
| 3371 | 3364 | } |
| 3372 | 3365 | |
| 3373 | | // TODO: Make this use self.ptrType |
| 3374 | | const un_active_ty_ref = try self.resolveUnionType(ty, active_field); |
| 3375 | | const un_active_ptr_ty_ref = try self.spv.ptrType(un_active_ty_ref, .Function); |
| 3376 | | const un_general_ty_ref = try self.resolveType(ty, .direct); |
| 3377 | | const un_general_ptr_ty_ref = try self.spv.ptrType(un_general_ty_ref, .Function); |
| 3378 | | |
| 3379 | | const tmp_id = self.spv.allocId(); |
| 3380 | | try self.func.prologue.emit(self.spv.gpa, .OpVariable, .{ |
| 3381 | | .id_result_type = self.typeId(un_active_ptr_ty_ref), |
| 3382 | | .id_result = tmp_id, |
| 3383 | | .storage_class = .Function, |
| 3384 | | }); |
| 3366 | const tmp_id = try self.alloc(ty, .{ .storage_class = .Function }); |
| 3385 | 3367 | |
| 3386 | 3368 | if (layout.tag_size != 0) { |
| 3387 | 3369 | const tag_ty_ref = try self.resolveType(maybe_tag_ty.?, .direct); |
| ... | ... | @@ -3391,10 +3373,19 @@ const DeclGen = struct { |
| 3391 | 3373 | try self.store(maybe_tag_ty.?, ptr_id, tag_id, .{}); |
| 3392 | 3374 | } |
| 3393 | 3375 | |
| 3394 | | if (layout.active_field_size != 0) { |
| 3395 | | const active_field_ptr_ty_ref = try self.ptrType(layout.active_field_ty, .Function); |
| 3396 | | const ptr_id = try self.accessChain(active_field_ptr_ty_ref, tmp_id, &.{@as(u32, @intCast(layout.active_field_index))}); |
| 3397 | | try self.store(layout.active_field_ty, ptr_id, payload.?, .{}); |
| 3376 | const payload_ty = union_ty.field_types.get(ip)[active_field].toType(); |
| 3377 | if (payload_ty.hasRuntimeBitsIgnoreComptime(mod)) { |
| 3378 | const pl_ptr_ty_ref = try self.ptrType(layout.payload_ty, .Function); |
| 3379 | const pl_ptr_id = try self.accessChain(pl_ptr_ty_ref, tmp_id, &.{layout.payload_index}); |
| 3380 | const active_pl_ptr_ty_ref = try self.ptrType(payload_ty, .Function); |
| 3381 | const active_pl_ptr_id = self.spv.allocId(); |
| 3382 | try self.func.body.emit(self.spv.gpa, .OpBitcast, .{ |
| 3383 | .id_result_type = self.typeId(active_pl_ptr_ty_ref), |
| 3384 | .id_result = active_pl_ptr_id, |
| 3385 | .operand = pl_ptr_id, |
| 3386 | }); |
| 3387 | |
| 3388 | try self.store(payload_ty, active_pl_ptr_id, payload.?, .{}); |
| 3398 | 3389 | } else { |
| 3399 | 3390 | assert(payload == null); |
| 3400 | 3391 | } |
| ... | ... | @@ -3402,34 +3393,21 @@ const DeclGen = struct { |
| 3402 | 3393 | // Just leave the padding fields uninitialized... |
| 3403 | 3394 | // TODO: Or should we initialize them with undef explicitly? |
| 3404 | 3395 | |
| 3405 | | // Now cast the pointer and load it as the 'generic' union type. |
| 3406 | | |
| 3407 | | const casted_var_id = self.spv.allocId(); |
| 3408 | | try self.func.body.emit(self.spv.gpa, .OpBitcast, .{ |
| 3409 | | .id_result_type = self.typeId(un_general_ptr_ty_ref), |
| 3410 | | .id_result = casted_var_id, |
| 3411 | | .operand = tmp_id, |
| 3412 | | }); |
| 3413 | | |
| 3414 | | const result_id = self.spv.allocId(); |
| 3415 | | try self.func.body.emit(self.spv.gpa, .OpLoad, .{ |
| 3416 | | .id_result_type = self.typeId(un_general_ty_ref), |
| 3417 | | .id_result = result_id, |
| 3418 | | .pointer = casted_var_id, |
| 3419 | | }); |
| 3420 | | |
| 3421 | | return result_id; |
| 3396 | return try self.load(ty, tmp_id, .{}); |
| 3422 | 3397 | } |
| 3423 | 3398 | |
| 3424 | 3399 | fn airUnionInit(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { |
| 3425 | 3400 | if (self.liveness.isUnused(inst)) return null; |
| 3426 | 3401 | |
| 3402 | const mod = self.module; |
| 3403 | const ip = &mod.intern_pool; |
| 3427 | 3404 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 3428 | 3405 | const extra = self.air.extraData(Air.UnionInit, ty_pl.payload).data; |
| 3429 | 3406 | const ty = self.typeOfIndex(inst); |
| 3430 | | const layout = self.unionLayout(ty, extra.field_index); |
| 3431 | 3407 | |
| 3432 | | const payload = if (layout.active_field_size != 0) |
| 3408 | const union_obj = mod.typeToUnion(ty).?; |
| 3409 | const field_ty = union_obj.field_types.get(ip)[extra.field_index].toType(); |
| 3410 | const payload = if (field_ty.hasRuntimeBitsIgnoreComptime(mod)) |
| 3433 | 3411 | try self.resolve(extra.init) |
| 3434 | 3412 | else |
| 3435 | 3413 | null; |
| ... | ... | @@ -3458,30 +3436,24 @@ const DeclGen = struct { |
| 3458 | 3436 | .Union => switch (object_ty.containerLayout(mod)) { |
| 3459 | 3437 | .Packed => unreachable, // TODO |
| 3460 | 3438 | else => { |
| 3461 | | // Store, pointer-cast, load |
| 3462 | | const un_general_ty_ref = try self.resolveType(object_ty, .indirect); |
| 3463 | | const un_general_ptr_ty_ref = try self.spv.ptrType(un_general_ty_ref, .Function); |
| 3464 | | const un_active_ty_ref = try self.resolveUnionType(object_ty, field_index); |
| 3465 | | const un_active_ptr_ty_ref = try self.spv.ptrType(un_active_ty_ref, .Function); |
| 3466 | | const field_ty_ref = try self.resolveType(field_ty, .indirect); |
| 3467 | | const field_ptr_ty_ref = try self.spv.ptrType(field_ty_ref, .Function); |
| 3468 | | |
| 3469 | | const tmp_id = self.spv.allocId(); |
| 3470 | | try self.func.prologue.emit(self.spv.gpa, .OpVariable, .{ |
| 3471 | | .id_result_type = self.typeId(un_general_ptr_ty_ref), |
| 3472 | | .id_result = tmp_id, |
| 3473 | | .storage_class = .Function, |
| 3474 | | }); |
| 3439 | // Store, ptr-elem-ptr, pointer-cast, load |
| 3440 | const layout = self.unionLayout(object_ty); |
| 3441 | assert(layout.has_payload); |
| 3442 | |
| 3443 | const tmp_id = try self.alloc(object_ty, .{ .storage_class = .Function }); |
| 3475 | 3444 | try self.store(object_ty, tmp_id, object_id, .{}); |
| 3476 | | const casted_tmp_id = self.spv.allocId(); |
| 3445 | |
| 3446 | const pl_ptr_ty_ref = try self.ptrType(layout.payload_ty, .Function); |
| 3447 | const pl_ptr_id = try self.accessChain(pl_ptr_ty_ref, tmp_id, &.{layout.payload_index}); |
| 3448 | |
| 3449 | const active_pl_ptr_ty_ref = try self.ptrType(field_ty, .Function); |
| 3450 | const active_pl_ptr_id = self.spv.allocId(); |
| 3477 | 3451 | try self.func.body.emit(self.spv.gpa, .OpBitcast, .{ |
| 3478 | | .id_result_type = self.typeId(un_active_ptr_ty_ref), |
| 3479 | | .id_result = casted_tmp_id, |
| 3480 | | .operand = tmp_id, |
| 3452 | .id_result_type = self.typeId(active_pl_ptr_ty_ref), |
| 3453 | .id_result = active_pl_ptr_id, |
| 3454 | .operand = pl_ptr_id, |
| 3481 | 3455 | }); |
| 3482 | | const layout = self.unionLayout(object_ty, field_index); |
| 3483 | | const field_ptr_id = try self.accessChain(field_ptr_ty_ref, casted_tmp_id, &.{layout.active_field_index}); |
| 3484 | | return try self.load(field_ty, field_ptr_id, .{}); |
| 3456 | return try self.load(field_ty, active_pl_ptr_id, .{}); |
| 3485 | 3457 | }, |
| 3486 | 3458 | }, |
| 3487 | 3459 | else => unreachable, |
| ... | ... | @@ -3540,18 +3512,24 @@ const DeclGen = struct { |
| 3540 | 3512 | .Union => switch (object_ty.containerLayout(mod)) { |
| 3541 | 3513 | .Packed => unreachable, // TODO |
| 3542 | 3514 | else => { |
| 3515 | const layout = self.unionLayout(object_ty); |
| 3516 | if (!layout.has_payload) { |
| 3517 | // Asked to get a pointer to a zero-sized field. Just lower this |
| 3518 | // to undefined, there is no reason to make it be a valid pointer. |
| 3519 | return try self.spv.constUndef(result_ty_ref); |
| 3520 | } |
| 3521 | |
| 3543 | 3522 | const storage_class = spvStorageClass(object_ptr_ty.ptrAddressSpace(mod)); |
| 3544 | | const un_active_ty_ref = try self.resolveUnionType(object_ty, field_index); |
| 3545 | | const un_active_ptr_ty_ref = try self.spv.ptrType(un_active_ty_ref, storage_class); |
| 3523 | const pl_ptr_ty_ref = try self.ptrType(layout.payload_ty, storage_class); |
| 3524 | const pl_ptr_id = try self.accessChain(pl_ptr_ty_ref, object_ptr, &.{layout.payload_index}); |
| 3546 | 3525 | |
| 3547 | | const casted_id = self.spv.allocId(); |
| 3526 | const active_pl_ptr_id = self.spv.allocId(); |
| 3548 | 3527 | try self.func.body.emit(self.spv.gpa, .OpBitcast, .{ |
| 3549 | | .id_result_type = self.typeId(un_active_ptr_ty_ref), |
| 3550 | | .id_result = casted_id, |
| 3551 | | .operand = object_ptr, |
| 3528 | .id_result_type = self.typeId(result_ty_ref), |
| 3529 | .id_result = active_pl_ptr_id, |
| 3530 | .operand = pl_ptr_id, |
| 3552 | 3531 | }); |
| 3553 | | const layout = self.unionLayout(object_ty, field_index); |
| 3554 | | return try self.accessChain(result_ty_ref, casted_id, &.{layout.active_field_index}); |
| 3532 | return active_pl_ptr_id; |
| 3555 | 3533 | }, |
| 3556 | 3534 | }, |
| 3557 | 3535 | else => unreachable, |