| ... | ... | @@ -3542,9 +3542,19 @@ pub const Type = extern union { |
| 3542 | 3542 | ); |
| 3543 | 3543 | } |
| 3544 | 3544 | |
| 3545 | | /// Asserts the type has the bit size already resolved. |
| 3546 | 3545 | pub fn bitSize(ty: Type, target: Target) u64 { |
| 3547 | | return switch (ty.tag()) { |
| 3546 | return bitSizeAdvanced(ty, target, null) catch unreachable; |
| 3547 | } |
| 3548 | |
| 3549 | /// If you pass `sema_kit`, any recursive type resolutions will happen if |
| 3550 | /// necessary, possibly returning a CompileError. Passing `null` instead asserts |
| 3551 | /// the type is fully resolved, and there will be no error, guaranteed. |
| 3552 | pub fn bitSizeAdvanced( |
| 3553 | ty: Type, |
| 3554 | target: Target, |
| 3555 | sema_kit: ?Module.WipAnalysis, |
| 3556 | ) Module.CompileError!u64 { |
| 3557 | switch (ty.tag()) { |
| 3548 | 3558 | .fn_noreturn_no_args => unreachable, // represents machine code; not a pointer |
| 3549 | 3559 | .fn_void_no_args => unreachable, // represents machine code; not a pointer |
| 3550 | 3560 | .fn_naked_noreturn_no_args => unreachable, // represents machine code; not a pointer |
| ... | ... | @@ -3568,40 +3578,30 @@ pub const Type = extern union { |
| 3568 | 3578 | .generic_poison => unreachable, |
| 3569 | 3579 | .bound_fn => unreachable, |
| 3570 | 3580 | |
| 3571 | | .void => 0, |
| 3572 | | .bool, .u1 => 1, |
| 3573 | | .u8, .i8 => 8, |
| 3574 | | .i16, .u16, .f16 => 16, |
| 3575 | | .u29 => 29, |
| 3576 | | .i32, .u32, .f32 => 32, |
| 3577 | | .i64, .u64, .f64 => 64, |
| 3578 | | .f80 => 80, |
| 3579 | | .u128, .i128, .f128 => 128, |
| 3581 | .void => return 0, |
| 3582 | .bool, .u1 => return 1, |
| 3583 | .u8, .i8 => return 8, |
| 3584 | .i16, .u16, .f16 => return 16, |
| 3585 | .u29 => return 29, |
| 3586 | .i32, .u32, .f32 => return 32, |
| 3587 | .i64, .u64, .f64 => return 64, |
| 3588 | .f80 => return 80, |
| 3589 | .u128, .i128, .f128 => return 128, |
| 3580 | 3590 | |
| 3581 | 3591 | .@"struct" => { |
| 3582 | | const field_count = ty.structFieldCount(); |
| 3583 | | if (field_count == 0) return 0; |
| 3584 | | |
| 3585 | | const struct_obj = ty.castTag(.@"struct").?.data; |
| 3586 | | assert(struct_obj.haveFieldTypes()); |
| 3587 | | |
| 3588 | | switch (struct_obj.layout) { |
| 3589 | | .Auto, .Extern => { |
| 3590 | | var total: u64 = 0; |
| 3591 | | for (struct_obj.fields.values()) |field| { |
| 3592 | | total += field.ty.bitSize(target); |
| 3593 | | } |
| 3594 | | return total; |
| 3595 | | }, |
| 3596 | | .Packed => return struct_obj.packedIntegerBits(target), |
| 3592 | if (sema_kit) |sk| _ = try sk.sema.resolveTypeFields(sk.block, sk.src, ty); |
| 3593 | var total: u64 = 0; |
| 3594 | for (ty.structFields().values()) |field| { |
| 3595 | total += try bitSizeAdvanced(field.ty, target, sema_kit); |
| 3597 | 3596 | } |
| 3597 | return total; |
| 3598 | 3598 | }, |
| 3599 | 3599 | |
| 3600 | 3600 | .tuple, .anon_struct => { |
| 3601 | | const tuple = ty.tupleFields(); |
| 3601 | if (sema_kit) |sk| _ = try sk.sema.resolveTypeFields(sk.block, sk.src, ty); |
| 3602 | 3602 | var total: u64 = 0; |
| 3603 | | for (tuple.types) |field_ty| { |
| 3604 | | total += field_ty.bitSize(target); |
| 3603 | for (ty.tupleFields().types) |field_ty| { |
| 3604 | total += try bitSizeAdvanced(field_ty, target, sema_kit); |
| 3605 | 3605 | } |
| 3606 | 3606 | return total; |
| 3607 | 3607 | }, |
| ... | ... | @@ -3609,37 +3609,35 @@ pub const Type = extern union { |
| 3609 | 3609 | .enum_simple, .enum_full, .enum_nonexhaustive, .enum_numbered => { |
| 3610 | 3610 | var buffer: Payload.Bits = undefined; |
| 3611 | 3611 | const int_tag_ty = ty.intTagType(&buffer); |
| 3612 | | return int_tag_ty.bitSize(target); |
| 3612 | return try bitSizeAdvanced(int_tag_ty, target, sema_kit); |
| 3613 | 3613 | }, |
| 3614 | 3614 | |
| 3615 | 3615 | .@"union", .union_tagged => { |
| 3616 | if (sema_kit) |sk| _ = try sk.sema.resolveTypeFields(sk.block, sk.src, ty); |
| 3616 | 3617 | const union_obj = ty.cast(Payload.Union).?.data; |
| 3617 | | |
| 3618 | | const fields = union_obj.fields; |
| 3619 | | if (fields.count() == 0) return 0; |
| 3620 | | |
| 3621 | 3618 | assert(union_obj.haveFieldTypes()); |
| 3622 | 3619 | |
| 3623 | 3620 | var size: u64 = 0; |
| 3624 | | for (fields.values()) |field| { |
| 3625 | | size = @maximum(size, field.ty.bitSize(target)); |
| 3621 | for (union_obj.fields.values()) |field| { |
| 3622 | size = @maximum(size, try bitSizeAdvanced(field.ty, target, sema_kit)); |
| 3626 | 3623 | } |
| 3627 | 3624 | return size; |
| 3628 | 3625 | }, |
| 3629 | 3626 | |
| 3630 | 3627 | .vector => { |
| 3631 | 3628 | const payload = ty.castTag(.vector).?.data; |
| 3632 | | const elem_bit_size = payload.elem_type.bitSize(target); |
| 3629 | const elem_bit_size = try bitSizeAdvanced(payload.elem_type, target, sema_kit); |
| 3633 | 3630 | return elem_bit_size * payload.len; |
| 3634 | 3631 | }, |
| 3635 | | .array_u8 => 8 * ty.castTag(.array_u8).?.data, |
| 3636 | | .array_u8_sentinel_0 => 8 * (ty.castTag(.array_u8_sentinel_0).?.data + 1), |
| 3632 | .array_u8 => return 8 * ty.castTag(.array_u8).?.data, |
| 3633 | .array_u8_sentinel_0 => return 8 * (ty.castTag(.array_u8_sentinel_0).?.data + 1), |
| 3637 | 3634 | .array => { |
| 3638 | 3635 | const payload = ty.castTag(.array).?.data; |
| 3639 | 3636 | const elem_size = std.math.max(payload.elem_type.abiAlignment(target), payload.elem_type.abiSize(target)); |
| 3640 | 3637 | if (elem_size == 0 or payload.len == 0) |
| 3641 | | return 0; |
| 3642 | | return (payload.len - 1) * 8 * elem_size + payload.elem_type.bitSize(target); |
| 3638 | return @as(u64, 0); |
| 3639 | const elem_bit_size = try bitSizeAdvanced(payload.elem_type, target, sema_kit); |
| 3640 | return (payload.len - 1) * 8 * elem_size + elem_bit_size; |
| 3643 | 3641 | }, |
| 3644 | 3642 | .array_sentinel => { |
| 3645 | 3643 | const payload = ty.castTag(.array_sentinel).?.data; |
| ... | ... | @@ -3647,14 +3645,15 @@ pub const Type = extern union { |
| 3647 | 3645 | payload.elem_type.abiAlignment(target), |
| 3648 | 3646 | payload.elem_type.abiSize(target), |
| 3649 | 3647 | ); |
| 3650 | | return payload.len * 8 * elem_size + payload.elem_type.bitSize(target); |
| 3648 | const elem_bit_size = try bitSizeAdvanced(payload.elem_type, target, sema_kit); |
| 3649 | return payload.len * 8 * elem_size + elem_bit_size; |
| 3651 | 3650 | }, |
| 3652 | 3651 | |
| 3653 | 3652 | .isize, |
| 3654 | 3653 | .usize, |
| 3655 | 3654 | .@"anyframe", |
| 3656 | 3655 | .anyframe_T, |
| 3657 | | => target.cpu.arch.ptrBitWidth(), |
| 3656 | => return target.cpu.arch.ptrBitWidth(), |
| 3658 | 3657 | |
| 3659 | 3658 | .const_slice, |
| 3660 | 3659 | .mut_slice, |
| ... | ... | @@ -3662,7 +3661,7 @@ pub const Type = extern union { |
| 3662 | 3661 | |
| 3663 | 3662 | .const_slice_u8, |
| 3664 | 3663 | .const_slice_u8_sentinel_0, |
| 3665 | | => target.cpu.arch.ptrBitWidth() * 2, |
| 3664 | => return target.cpu.arch.ptrBitWidth() * 2, |
| 3666 | 3665 | |
| 3667 | 3666 | .optional_single_const_pointer, |
| 3668 | 3667 | .optional_single_mut_pointer, |
| ... | ... | @@ -3681,8 +3680,8 @@ pub const Type = extern union { |
| 3681 | 3680 | }, |
| 3682 | 3681 | |
| 3683 | 3682 | .pointer => switch (ty.castTag(.pointer).?.data.size) { |
| 3684 | | .Slice => target.cpu.arch.ptrBitWidth() * 2, |
| 3685 | | else => target.cpu.arch.ptrBitWidth(), |
| 3683 | .Slice => return target.cpu.arch.ptrBitWidth() * 2, |
| 3684 | else => return target.cpu.arch.ptrBitWidth(), |
| 3686 | 3685 | }, |
| 3687 | 3686 | |
| 3688 | 3687 | .manyptr_u8, |
| ... | ... | @@ -3708,7 +3707,7 @@ pub const Type = extern union { |
| 3708 | 3707 | .error_set_merged, |
| 3709 | 3708 | => return 16, // TODO revisit this when we have the concept of the error tag type |
| 3710 | 3709 | |
| 3711 | | .int_signed, .int_unsigned => ty.cast(Payload.Bits).?.data, |
| 3710 | .int_signed, .int_unsigned => return ty.cast(Payload.Bits).?.data, |
| 3712 | 3711 | |
| 3713 | 3712 | .optional => { |
| 3714 | 3713 | var buf: Payload.ElemType = undefined; |
| ... | ... | @@ -3722,7 +3721,8 @@ pub const Type = extern union { |
| 3722 | 3721 | // field and a boolean as the second. Since the child type's abi alignment is |
| 3723 | 3722 | // guaranteed to be >= that of bool's (1 byte) the added size is exactly equal |
| 3724 | 3723 | // to the child type's ABI alignment. |
| 3725 | | return child_type.bitSize(target) + 1; |
| 3724 | const child_bit_size = try bitSizeAdvanced(child_type, target, sema_kit); |
| 3725 | return child_bit_size + 1; |
| 3726 | 3726 | }, |
| 3727 | 3727 | |
| 3728 | 3728 | .error_union => { |
| ... | ... | @@ -3730,9 +3730,9 @@ pub const Type = extern union { |
| 3730 | 3730 | if (!payload.error_set.hasRuntimeBits() and !payload.payload.hasRuntimeBits()) { |
| 3731 | 3731 | return 0; |
| 3732 | 3732 | } else if (!payload.error_set.hasRuntimeBits()) { |
| 3733 | | return payload.payload.bitSize(target); |
| 3733 | return payload.payload.bitSizeAdvanced(target, sema_kit); |
| 3734 | 3734 | } else if (!payload.payload.hasRuntimeBits()) { |
| 3735 | | return payload.error_set.bitSize(target); |
| 3735 | return payload.error_set.bitSizeAdvanced(target, sema_kit); |
| 3736 | 3736 | } |
| 3737 | 3737 | @panic("TODO bitSize error union"); |
| 3738 | 3738 | }, |
| ... | ... | @@ -3749,7 +3749,7 @@ pub const Type = extern union { |
| 3749 | 3749 | .extern_options, |
| 3750 | 3750 | .type_info, |
| 3751 | 3751 | => @panic("TODO at some point we gotta resolve builtin types"), |
| 3752 | | }; |
| 3752 | } |
| 3753 | 3753 | } |
| 3754 | 3754 | |
| 3755 | 3755 | pub fn isSinglePointer(self: Type) bool { |
| ... | ... | @@ -5506,6 +5506,7 @@ pub const Type = extern union { |
| 5506 | 5506 | switch (ty.tag()) { |
| 5507 | 5507 | .@"struct" => { |
| 5508 | 5508 | const struct_obj = ty.castTag(.@"struct").?.data; |
| 5509 | assert(struct_obj.haveFieldTypes()); |
| 5509 | 5510 | return struct_obj.fields.count(); |
| 5510 | 5511 | }, |
| 5511 | 5512 | .empty_struct, .empty_struct_literal => return 0, |