aboutsummaryrefslogtreecommitdiff
path: root/src/type.zig
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2022-05-03 23:44:32 -0700
committerAndrew Kelley <andrew@ziglang.org>2022-05-04 17:34:16 -0700
commit259f784241fb44e0a1b570daaf31ba2b9f164106 (patch)
treeff024852310df27dfad242c12af8d8a77a290988 /src/type.zig
parent080e870a717124204cbfa58a1f29061a701b0362 (diff)
downloadzig-259f784241fb44e0a1b570daaf31ba2b9f164106.tar.gz
zig-259f784241fb44e0a1b570daaf31ba2b9f164106.zip
stage2: improve `@sizeOf` and `@alignOf` integers
Prior to this commit, the logic for ABI size and ABI alignment for integers was naive and incorrect. This results in wasted hardware as well as undefined behavior in the LLVM backend when we memset an incorrect number of bytes to 0xaa due to disagreeing with LLVM about the ABI size of integers. This commit introduces a "max int align" value which is different per Target. This value is used to derive the ABI size and alignment of all integers. This commit makes an interesting change from stage1, which treats 128-bit integers as 16-bytes aligned for x86_64-linux. stage1 is incorrect. The maximum integer alignment on this system is only 8 bytes. This change breaks the behavior test called "128-bit cmpxchg" because on that target, 128-bit cmpxchg does require a 16-bytes aligned pointer to a 128 bit integer. However, this alignment property does not belong on *all* 128 bit integers - only on the pointer type in the `@cmpxchg` builtin function prototype. The user can then use an alignment override annotation on a 128-bit integer variable or struct field to obtain such a pointer.
Diffstat (limited to 'src/type.zig')
-rw-r--r--src/type.zig38
1 files changed, 23 insertions, 15 deletions
diff --git a/src/type.zig b/src/type.zig
index c96c512d9a..44432b95f6 100644
--- a/src/type.zig
+++ b/src/type.zig
@@ -2788,11 +2788,6 @@ pub const Type = extern union {
return AbiAlignmentAdvanced{ .scalar = target_util.defaultFunctionAlignment(target) };
},
- .i16, .u16 => return AbiAlignmentAdvanced{ .scalar = 2 },
- .i32, .u32 => return AbiAlignmentAdvanced{ .scalar = 4 },
- .i64, .u64 => return AbiAlignmentAdvanced{ .scalar = 8 },
- .u128, .i128 => return AbiAlignmentAdvanced{ .scalar = 16 },
-
.isize,
.usize,
.single_const_pointer_to_comptime_int,
@@ -2865,14 +2860,15 @@ pub const Type = extern union {
// ABI alignment of vectors?
.vector => return AbiAlignmentAdvanced{ .scalar = 16 },
+ .i16, .u16 => return AbiAlignmentAdvanced{ .scalar = intAbiAlignment(16, target) },
+ .i32, .u32 => return AbiAlignmentAdvanced{ .scalar = intAbiAlignment(32, target) },
+ .i64, .u64 => return AbiAlignmentAdvanced{ .scalar = intAbiAlignment(64, target) },
+ .u128, .i128 => return AbiAlignmentAdvanced{ .scalar = intAbiAlignment(128, target) },
+
.int_signed, .int_unsigned => {
const bits: u16 = ty.cast(Payload.Bits).?.data;
if (bits == 0) return AbiAlignmentAdvanced{ .scalar = 0 };
- if (bits <= 8) return AbiAlignmentAdvanced{ .scalar = 1 };
- if (bits <= 16) return AbiAlignmentAdvanced{ .scalar = 2 };
- if (bits <= 32) return AbiAlignmentAdvanced{ .scalar = 4 };
- if (bits <= 64) return AbiAlignmentAdvanced{ .scalar = 8 };
- return AbiAlignmentAdvanced{ .scalar = 16 };
+ return AbiAlignmentAdvanced{ .scalar = intAbiAlignment(bits, target) };
},
.optional => {
@@ -3113,10 +3109,6 @@ pub const Type = extern union {
assert(elem_size >= payload.elem_type.abiAlignment(target));
return (payload.len + 1) * elem_size;
},
- .i16, .u16 => return 2,
- .i32, .u32 => return 4,
- .i64, .u64 => return 8,
- .u128, .i128 => return 16,
.isize,
.usize,
@@ -3189,10 +3181,14 @@ pub const Type = extern union {
.error_set_merged,
=> return 2, // TODO revisit this when we have the concept of the error tag type
+ .i16, .u16 => return intAbiSize(16, target),
+ .i32, .u32 => return intAbiSize(32, target),
+ .i64, .u64 => return intAbiSize(64, target),
+ .u128, .i128 => return intAbiSize(128, target),
.int_signed, .int_unsigned => {
const bits: u16 = self.cast(Payload.Bits).?.data;
if (bits == 0) return 0;
- return std.math.ceilPowerOfTwoPromote(u16, (bits + 7) / 8);
+ return intAbiSize(bits, target);
},
.optional => {
@@ -3234,6 +3230,18 @@ pub const Type = extern union {
};
}
+ fn intAbiSize(bits: u16, target: Target) u64 {
+ const alignment = intAbiAlignment(bits, target);
+ return std.mem.alignForwardGeneric(u64, (bits + 7) / 8, alignment);
+ }
+
+ fn intAbiAlignment(bits: u16, target: Target) u32 {
+ return @minimum(
+ std.math.ceilPowerOfTwoPromote(u16, (bits + 7) / 8),
+ target.maxIntAlignment(),
+ );
+ }
+
/// Asserts the type has the bit size already resolved.
pub fn bitSize(ty: Type, target: Target) u64 {
return switch (ty.tag()) {