aboutsummaryrefslogtreecommitdiff
path: root/src/type.zig
diff options
context:
space:
mode:
Diffstat (limited to 'src/type.zig')
-rw-r--r--src/type.zig549
1 files changed, 422 insertions, 127 deletions
diff --git a/src/type.zig b/src/type.zig
index 5c74f39290..3a072a2f5b 100644
--- a/src/type.zig
+++ b/src/type.zig
@@ -2892,41 +2892,24 @@ pub const Type = extern union {
.anyframe_T,
=> return AbiAlignmentAdvanced{ .scalar = @divExact(target.cpu.arch.ptrBitWidth(), 8) },
- .c_short => return AbiAlignmentAdvanced{ .scalar = @divExact(CType.short.sizeInBits(target), 8) },
- .c_ushort => return AbiAlignmentAdvanced{ .scalar = @divExact(CType.ushort.sizeInBits(target), 8) },
- .c_int => return AbiAlignmentAdvanced{ .scalar = @divExact(CType.int.sizeInBits(target), 8) },
- .c_uint => return AbiAlignmentAdvanced{ .scalar = @divExact(CType.uint.sizeInBits(target), 8) },
- .c_long => return AbiAlignmentAdvanced{ .scalar = @divExact(CType.long.sizeInBits(target), 8) },
- .c_ulong => return AbiAlignmentAdvanced{ .scalar = @divExact(CType.ulong.sizeInBits(target), 8) },
- .c_longlong => switch (target.cpu.arch) {
- .i386 => switch (target.os.tag) {
- .windows, .uefi => return AbiAlignmentAdvanced{ .scalar = 8 },
- else => return AbiAlignmentAdvanced{ .scalar = 4 },
- },
- else => return AbiAlignmentAdvanced{ .scalar = @divExact(CType.longlong.sizeInBits(target), 8) },
- },
- .c_ulonglong => switch (target.cpu.arch) {
- .i386 => switch (target.os.tag) {
- .windows, .uefi => return AbiAlignmentAdvanced{ .scalar = 8 },
- else => return AbiAlignmentAdvanced{ .scalar = 4 },
- },
- else => return AbiAlignmentAdvanced{ .scalar = @divExact(CType.ulonglong.sizeInBits(target), 8) },
- },
+ .c_short => return AbiAlignmentAdvanced{ .scalar = CType.short.alignment(target) },
+ .c_ushort => return AbiAlignmentAdvanced{ .scalar = CType.ushort.alignment(target) },
+ .c_int => return AbiAlignmentAdvanced{ .scalar = CType.int.alignment(target) },
+ .c_uint => return AbiAlignmentAdvanced{ .scalar = CType.uint.alignment(target) },
+ .c_long => return AbiAlignmentAdvanced{ .scalar = CType.long.alignment(target) },
+ .c_ulong => return AbiAlignmentAdvanced{ .scalar = CType.ulong.alignment(target) },
+ .c_longlong => return AbiAlignmentAdvanced{ .scalar = CType.longlong.alignment(target) },
+ .c_ulonglong => return AbiAlignmentAdvanced{ .scalar = CType.ulonglong.alignment(target) },
+ .c_longdouble => return AbiAlignmentAdvanced{ .scalar = CType.longdouble.alignment(target) },
.f16 => return AbiAlignmentAdvanced{ .scalar = 2 },
- .f32 => return AbiAlignmentAdvanced{ .scalar = 4 },
- .f64 => switch (target.cpu.arch) {
- .i386 => switch (target.os.tag) {
- .windows, .uefi => return AbiAlignmentAdvanced{ .scalar = 8 },
- else => return AbiAlignmentAdvanced{ .scalar = 4 },
- },
+ .f32 => return AbiAlignmentAdvanced{ .scalar = CType.float.alignment(target) },
+ .f64 => switch (CType.double.sizeInBits(target)) {
+ 64 => return AbiAlignmentAdvanced{ .scalar = CType.double.alignment(target) },
else => return AbiAlignmentAdvanced{ .scalar = 8 },
},
- .f128 => return AbiAlignmentAdvanced{ .scalar = 16 },
-
- .f80 => switch (target.cpu.arch) {
- .i386 => return AbiAlignmentAdvanced{ .scalar = 4 },
- .x86_64 => return AbiAlignmentAdvanced{ .scalar = 16 },
+ .f80 => switch (CType.longdouble.sizeInBits(target)) {
+ 80 => return AbiAlignmentAdvanced{ .scalar = CType.longdouble.alignment(target) },
else => {
var payload: Payload.Bits = .{
.base = .{ .tag = .int_unsigned },
@@ -2936,17 +2919,7 @@ pub const Type = extern union {
return AbiAlignmentAdvanced{ .scalar = abiAlignment(u80_ty, target) };
},
},
- .c_longdouble => switch (CType.longdouble.sizeInBits(target)) {
- 16 => return AbiAlignmentAdvanced{ .scalar = abiAlignment(Type.f16, target) },
- 32 => return AbiAlignmentAdvanced{ .scalar = abiAlignment(Type.f32, target) },
- 64 => return AbiAlignmentAdvanced{ .scalar = abiAlignment(Type.f64, target) },
- 80 => if (target.cpu.arch == .i386 and target.isMinGW())
- return AbiAlignmentAdvanced{ .scalar = 4 }
- else
- return AbiAlignmentAdvanced{ .scalar = abiAlignment(Type.f80, target) },
- 128 => return AbiAlignmentAdvanced{ .scalar = abiAlignment(Type.f128, target) },
- else => unreachable,
- },
+ .f128 => return AbiAlignmentAdvanced{ .scalar = 16 },
// TODO revisit this when we have the concept of the error tag type
.anyerror_void_error_union,
@@ -3411,16 +3384,8 @@ pub const Type = extern union {
.f32 => return AbiSizeAdvanced{ .scalar = 4 },
.f64 => return AbiSizeAdvanced{ .scalar = 8 },
.f128 => return AbiSizeAdvanced{ .scalar = 16 },
-
- .f80 => switch (target.cpu.arch) {
- .i386 => switch (target.os.tag) {
- .windows => switch (target.abi) {
- .msvc => return AbiSizeAdvanced{ .scalar = 16 },
- else => return AbiSizeAdvanced{ .scalar = 12 },
- },
- else => return AbiSizeAdvanced{ .scalar = 12 },
- },
- .x86_64 => return AbiSizeAdvanced{ .scalar = 16 },
+ .f80 => switch (CType.longdouble.sizeInBits(target)) {
+ 80 => return AbiSizeAdvanced{ .scalar = std.mem.alignForward(10, CType.longdouble.alignment(target)) },
else => {
var payload: Payload.Bits = .{
.base = .{ .tag = .int_unsigned },
@@ -3469,20 +3434,8 @@ pub const Type = extern union {
if (!child_type.hasRuntimeBits()) return AbiSizeAdvanced{ .scalar = 1 };
- switch (child_type.zigTypeTag()) {
- .Pointer => {
- const ptr_info = child_type.ptrInfo().data;
- const has_null = switch (ptr_info.size) {
- .Slice, .C => true,
- else => ptr_info.@"allowzero",
- };
- if (!has_null) {
- const ptr_size_bytes = @divExact(target.cpu.arch.ptrBitWidth(), 8);
- return AbiSizeAdvanced{ .scalar = ptr_size_bytes };
- }
- },
- .ErrorSet => return abiSizeAdvanced(Type.anyerror, target, strat),
- else => {},
+ if (ty.optionalReprIsPayload()) {
+ return abiSizeAdvanced(child_type, target, strat);
}
const payload_size = switch (try child_type.abiSizeAdvanced(target, strat)) {
@@ -3747,28 +3700,10 @@ pub const Type = extern union {
.int_signed, .int_unsigned => return ty.cast(Payload.Bits).?.data,
- .optional => {
- var buf: Payload.ElemType = undefined;
- const child_type = ty.optionalChild(&buf);
- if (!child_type.hasRuntimeBits()) return 8;
-
- if (child_type.zigTypeTag() == .Pointer and !child_type.isCPtr() and !child_type.isSlice())
- return target.cpu.arch.ptrBitWidth();
-
- // Optional types are represented as a struct with the child type as the first
- // field and a boolean as the second. Since the child type's abi alignment is
- // guaranteed to be >= that of bool's (1 byte) the added size is exactly equal
- // to the child type's ABI alignment.
- const child_bit_size = try bitSizeAdvanced(child_type, target, sema_kit);
- return child_bit_size + 1;
- },
-
- .error_union => {
- const payload = ty.castTag(.error_union).?.data;
- if (!payload.payload.hasRuntimeBits()) {
- return payload.error_set.bitSizeAdvanced(target, sema_kit);
- }
- @panic("TODO bitSize error union");
+ .optional, .error_union => {
+ // Optionals and error unions are not packed so their bitsize
+ // includes padding bits.
+ return (try abiSizeAdvanced(ty, target, if (sema_kit) |sk| .{ .sema_kit = sk } else .eager)).scalar * 8;
},
.atomic_order,
@@ -4045,8 +3980,8 @@ pub const Type = extern union {
.Pointer => {
const info = child_ty.ptrInfo().data;
switch (info.size) {
- .Slice, .C => return false,
- .Many, .One => return !info.@"allowzero",
+ .C => return false,
+ .Slice, .Many, .One => return !info.@"allowzero",
}
},
.ErrorSet => return true,
@@ -6668,45 +6603,80 @@ pub const CType = enum {
ulonglong,
longdouble,
+ // We don't have a `c_float`/`c_double` type in Zig, but these
+ // are useful for querying target-correct alignment and checking
+ // whether C's double is f64 or f32
+ float,
+ double,
+
pub fn sizeInBits(self: CType, target: Target) u16 {
switch (target.os.tag) {
.freestanding, .other => switch (target.cpu.arch) {
.msp430 => switch (self) {
.short, .ushort, .int, .uint => return 16,
- .long, .ulong => return 32,
- .longlong, .ulonglong, .longdouble => return 64,
+ .float, .long, .ulong => return 32,
+ .longlong, .ulonglong, .double, .longdouble => return 64,
},
.avr => switch (self) {
.short, .ushort, .int, .uint => return 16,
- .long, .ulong, .longdouble => return 32,
+ .long, .ulong, .float, .double, .longdouble => return 32,
.longlong, .ulonglong => return 64,
},
+ .tce, .tcele => switch (self) {
+ .short, .ushort => return 16,
+ .int, .uint, .long, .ulong, .longlong, .ulonglong => return 32,
+ .float, .double, .longdouble => return 32,
+ },
+ .mips64, .mips64el => switch (self) {
+ .short, .ushort => return 16,
+ .int, .uint, .float => return 32,
+ .long, .ulong => return if (target.abi != .gnuabin32) 64 else 32,
+ .longlong, .ulonglong, .double => return 64,
+ .longdouble => return 128,
+ },
+ .x86_64 => switch (self) {
+ .short, .ushort => return 16,
+ .int, .uint, .float => return 32,
+ .long, .ulong => switch (target.abi) {
+ .gnux32, .muslx32 => return 32,
+ else => return 64,
+ },
+ .longlong, .ulonglong, .double => return 64,
+ .longdouble => return 80,
+ },
else => switch (self) {
.short, .ushort => return 16,
- .int, .uint => return 32,
+ .int, .uint, .float => return 32,
.long, .ulong => return target.cpu.arch.ptrBitWidth(),
- .longlong, .ulonglong => return 64,
+ .longlong, .ulonglong, .double => return 64,
.longdouble => switch (target.cpu.arch) {
.i386 => switch (target.abi) {
.android => return 64,
else => return 80,
},
- .x86_64 => return 80,
+ .powerpc,
+ .powerpcle,
+ .powerpc64,
+ .powerpc64le,
+ => switch (target.abi) {
+ .musl,
+ .musleabi,
+ .musleabihf,
+ .muslx32,
+ => return 64,
+ else => return 128,
+ },
+
+ .riscv32,
.riscv64,
.aarch64,
.aarch64_be,
.aarch64_32,
.s390x,
- .mips64,
- .mips64el,
.sparc,
.sparc64,
.sparcel,
- .powerpc,
- .powerpcle,
- .powerpc64,
- .powerpc64le,
.wasm32,
.wasm64,
=> return 128,
@@ -6730,23 +6700,78 @@ pub const CType = enum {
.fuchsia,
.minix,
=> switch (target.cpu.arch) {
+ .msp430 => switch (self) {
+ .short, .ushort, .int, .uint => return 16,
+ .long, .ulong, .float => return 32,
+ .longlong, .ulonglong, .double, .longdouble => return 64,
+ },
.avr => switch (self) {
.short, .ushort, .int, .uint => return 16,
- .long, .ulong, .longdouble => return 32,
+ .long, .ulong, .float, .double, .longdouble => return 32,
.longlong, .ulonglong => return 64,
},
+ .tce, .tcele => switch (self) {
+ .short, .ushort => return 16,
+ .int, .uint, .long, .ulong, .longlong, .ulonglong => return 32,
+ .float, .double, .longdouble => return 32,
+ },
+ .mips64, .mips64el => switch (self) {
+ .short, .ushort => return 16,
+ .int, .uint, .float => return 32,
+ .long, .ulong => return if (target.abi != .gnuabin32) 64 else 32,
+ .longlong, .ulonglong, .double => return 64,
+ .longdouble => if (target.os.tag == .freebsd) return 64 else return 128,
+ },
+ .x86_64 => switch (self) {
+ .short, .ushort => return 16,
+ .int, .uint, .float => return 32,
+ .long, .ulong => switch (target.abi) {
+ .gnux32, .muslx32 => return 32,
+ else => return 64,
+ },
+ .longlong, .ulonglong, .double => return 64,
+ .longdouble => return 80,
+ },
else => switch (self) {
.short, .ushort => return 16,
- .int, .uint => return 32,
+ .int, .uint, .float => return 32,
.long, .ulong => return target.cpu.arch.ptrBitWidth(),
- .longlong, .ulonglong => return 64,
+ .longlong, .ulonglong, .double => return 64,
.longdouble => switch (target.cpu.arch) {
.i386 => switch (target.abi) {
.android => return 64,
else => return 80,
},
- .x86_64 => return 80,
+ .powerpc,
+ .powerpcle,
+ => switch (target.abi) {
+ .musl,
+ .musleabi,
+ .musleabihf,
+ .muslx32,
+ => return 64,
+ else => switch (target.os.tag) {
+ .freebsd, .netbsd, .openbsd => return 64,
+ else => return 128,
+ },
+ },
+
+ .powerpc64,
+ .powerpc64le,
+ => switch (target.abi) {
+ .musl,
+ .musleabi,
+ .musleabihf,
+ .muslx32,
+ => return 64,
+ else => switch (target.os.tag) {
+ .freebsd, .openbsd => return 64,
+ else => return 128,
+ },
+ },
+
+ .riscv32,
.riscv64,
.aarch64,
.aarch64_be,
@@ -6757,10 +6782,6 @@ pub const CType = enum {
.sparc,
.sparc64,
.sparcel,
- .powerpc,
- .powerpcle,
- .powerpc64,
- .powerpc64le,
.wasm32,
.wasm64,
=> return 128,
@@ -6770,37 +6791,77 @@ pub const CType = enum {
},
},
- .windows, .uefi => switch (self) {
- .short, .ushort => return 16,
- .int, .uint, .long, .ulong => return 32,
- .longlong, .ulonglong => return 64,
- .longdouble => switch (target.cpu.arch) {
- .i386 => switch (target.abi) {
- .gnu => return 80,
+ .windows, .uefi => switch (target.cpu.arch) {
+ .i386 => switch (self) {
+ .short, .ushort => return 16,
+ .int, .uint, .float => return 32,
+ .long, .ulong => return 32,
+ .longlong, .ulonglong, .double => return 64,
+ .longdouble => switch (target.abi) {
+ .gnu, .gnuilp32, .cygnus => return 80,
else => return 64,
},
- .x86_64 => switch (target.abi) {
- .gnu => return 80,
+ },
+ .x86_64 => switch (self) {
+ .short, .ushort => return 16,
+ .int, .uint, .float => return 32,
+ .long, .ulong => switch (target.abi) {
+ .cygnus => return 64,
+ else => return 32,
+ },
+ .longlong, .ulonglong, .double => return 64,
+ .longdouble => switch (target.abi) {
+ .gnu, .gnuilp32, .cygnus => return 80,
else => return 64,
},
- else => return 64,
+ },
+ else => switch (self) {
+ .short, .ushort => return 16,
+ .int, .uint, .float => return 32,
+ .long, .ulong => return 32,
+ .longlong, .ulonglong, .double => return 64,
+ .longdouble => return 64,
},
},
.macos, .ios, .tvos, .watchos => switch (self) {
.short, .ushort => return 16,
- .int, .uint => return 32,
- .long, .ulong, .longlong, .ulonglong => return 64,
+ .int, .uint, .float => return 32,
+ .long, .ulong => switch (target.cpu.arch) {
+ .i386, .arm, .aarch64_32 => return 32,
+ .x86_64 => switch (target.abi) {
+ .gnux32, .muslx32 => return 32,
+ else => return 64,
+ },
+ else => return 64,
+ },
+ .longlong, .ulonglong, .double => return 64,
.longdouble => switch (target.cpu.arch) {
- .i386, .x86_64 => return 80,
+ .i386 => switch (target.abi) {
+ .android => return 64,
+ else => return 80,
+ },
+ .x86_64 => return 80,
else => return 64,
},
},
+ .nvcl, .cuda => switch (self) {
+ .short, .ushort => return 16,
+ .int, .uint, .float => return 32,
+ .long, .ulong => switch (target.cpu.arch) {
+ .nvptx => return 32,
+ .nvptx64 => return 64,
+ else => return 64,
+ },
+ .longlong, .ulonglong, .double => return 64,
+ .longdouble => return 64,
+ },
+
.amdhsa, .amdpal => switch (self) {
.short, .ushort => return 16,
- .int, .uint => return 32,
- .long, .ulong, .longlong, .ulonglong => return 64,
+ .int, .uint, .float => return 32,
+ .long, .ulong, .longlong, .ulonglong, .double => return 64,
.longdouble => return 128,
},
@@ -6811,8 +6872,6 @@ pub const CType = enum {
.rtems,
.nacl,
.aix,
- .cuda,
- .nvcl,
.ps4,
.ps5,
.elfiamcu,
@@ -6828,4 +6887,240 @@ pub const CType = enum {
=> @panic("TODO specify the C integer and float type sizes for this OS"),
}
}
+
+ pub fn alignment(self: CType, target: Target) u16 {
+
+ // Overrides for unusual alignments
+ switch (target.cpu.arch) {
+ .avr => switch (self) {
+ .short, .ushort => return 2,
+ else => return 1,
+ },
+ .i386 => switch (target.os.tag) {
+ .windows, .uefi => switch (self) {
+ .longlong, .ulonglong, .double => return 8,
+ .longdouble => switch (target.abi) {
+ .gnu, .gnuilp32, .cygnus => return 4,
+ else => return 8,
+ },
+ else => {},
+ },
+ else => {},
+ },
+ else => {},
+ }
+
+ // Next-power-of-two-aligned, up to a maximum.
+ return @min(
+ std.math.ceilPowerOfTwoAssert(u16, (self.sizeInBits(target) + 7) / 8),
+ switch (target.cpu.arch) {
+ .arm, .armeb, .thumb, .thumbeb => switch (target.os.tag) {
+ .netbsd => switch (target.abi) {
+ .gnueabi,
+ .gnueabihf,
+ .eabi,
+ .eabihf,
+ .android,
+ .musleabi,
+ .musleabihf,
+ => 8,
+
+ else => @as(u16, 4),
+ },
+ .ios, .tvos, .watchos => 4,
+ else => 8,
+ },
+
+ .msp430,
+ .avr,
+ => 2,
+
+ .arc,
+ .csky,
+ .i386,
+ .xcore,
+ .dxil,
+ .loongarch32,
+ .tce,
+ .tcele,
+ .le32,
+ .amdil,
+ .hsail,
+ .spir,
+ .spirv32,
+ .kalimba,
+ .shave,
+ .renderscript32,
+ .ve,
+ .spu_2,
+ => 4,
+
+ .aarch64_32,
+ .amdgcn,
+ .amdil64,
+ .bpfel,
+ .bpfeb,
+ .hexagon,
+ .hsail64,
+ .loongarch64,
+ .m68k,
+ .mips,
+ .mipsel,
+ .sparc,
+ .sparcel,
+ .sparc64,
+ .lanai,
+ .le64,
+ .nvptx,
+ .nvptx64,
+ .r600,
+ .s390x,
+ .spir64,
+ .spirv64,
+ .renderscript64,
+ => 8,
+
+ .aarch64,
+ .aarch64_be,
+ .mips64,
+ .mips64el,
+ .powerpc,
+ .powerpcle,
+ .powerpc64,
+ .powerpc64le,
+ .riscv32,
+ .riscv64,
+ .x86_64,
+ .wasm32,
+ .wasm64,
+ => 16,
+ },
+ );
+ }
+
+ pub fn preferredAlignment(self: CType, target: Target) u16 {
+
+ // Overrides for unusual alignments
+ switch (target.cpu.arch) {
+ .arm, .armeb, .thumb, .thumbeb => switch (target.os.tag) {
+ .netbsd => switch (target.abi) {
+ .gnueabi,
+ .gnueabihf,
+ .eabi,
+ .eabihf,
+ .android,
+ .musleabi,
+ .musleabihf,
+ => {},
+
+ else => switch (self) {
+ .longdouble => return 4,
+ else => {},
+ },
+ },
+ .ios, .tvos, .watchos => switch (self) {
+ .longdouble => return 4,
+ else => {},
+ },
+ else => {},
+ },
+ .arc => switch (self) {
+ .longdouble => return 4,
+ else => {},
+ },
+ .avr => switch (self) {
+ .int, .uint, .long, .ulong, .float, .longdouble => return 1,
+ .short, .ushort => return 2,
+ .double => return 4,
+ .longlong, .ulonglong => return 8,
+ },
+ .i386 => switch (target.os.tag) {
+ .windows, .uefi => switch (self) {
+ .longdouble => switch (target.abi) {
+ .gnu, .gnuilp32, .cygnus => return 4,
+ else => return 8,
+ },
+ else => {},
+ },
+ else => switch (self) {
+ .longdouble => return 4,
+ else => {},
+ },
+ },
+ else => {},
+ }
+
+ // Next-power-of-two-aligned, up to a maximum.
+ return @min(
+ std.math.ceilPowerOfTwoAssert(u16, (self.sizeInBits(target) + 7) / 8),
+ switch (target.cpu.arch) {
+ .msp430 => @as(u16, 2),
+
+ .csky,
+ .xcore,
+ .dxil,
+ .loongarch32,
+ .tce,
+ .tcele,
+ .le32,
+ .amdil,
+ .hsail,
+ .spir,
+ .spirv32,
+ .kalimba,
+ .shave,
+ .renderscript32,
+ .ve,
+ .spu_2,
+ => 4,
+
+ .arc,
+ .arm,
+ .armeb,
+ .avr,
+ .thumb,
+ .thumbeb,
+ .aarch64_32,
+ .amdgcn,
+ .amdil64,
+ .bpfel,
+ .bpfeb,
+ .hexagon,
+ .hsail64,
+ .i386,
+ .loongarch64,
+ .m68k,
+ .mips,
+ .mipsel,
+ .sparc,
+ .sparcel,
+ .sparc64,
+ .lanai,
+ .le64,
+ .nvptx,
+ .nvptx64,
+ .r600,
+ .s390x,
+ .spir64,
+ .spirv64,
+ .renderscript64,
+ => 8,
+
+ .aarch64,
+ .aarch64_be,
+ .mips64,
+ .mips64el,
+ .powerpc,
+ .powerpcle,
+ .powerpc64,
+ .powerpc64le,
+ .riscv32,
+ .riscv64,
+ .x86_64,
+ .wasm32,
+ .wasm64,
+ => 16,
+ },
+ );
+ }
};