From e4e1c21e1fa599c1f243cad9236c88676023f6a8 Mon Sep 17 00:00:00 2001 From: Evan Haas Date: Thu, 6 Oct 2022 15:29:10 -0700 Subject: [PATCH] i386 ABI: Fix some sizes and alignments This makes the following changes for i386: long long and unsigned long long have 4 byte alignment on non-Windows f64 (double) has 4-byte alignment on non-Windows long double is 80 bits and has 4 byte alignment on mingw long double on android is 64 bits, not 80: https://www.uclibc.org/docs/psABI-i386.pdf Fixes #12453 Fixes #12987 --- lib/std/target.zig | 2 +- src/type.zig | 54 +++++++++++++++++++++++++++++++++++++++------ test/standalone.zig | 3 +++ 3 files changed, 51 insertions(+), 8 deletions(-) diff --git a/lib/std/target.zig b/lib/std/target.zig index b6a8a8b9c0..1d994a170a 100644 --- a/lib/std/target.zig +++ b/lib/std/target.zig @@ -1761,7 +1761,7 @@ pub const Target = struct { } pub inline fn longDoubleIs(target: Target, comptime F: type) bool { - if (target.abi == .msvc) { + if (target.abi == .msvc or (target.abi == .android and target.cpu.arch == .i386)) { return F == f64; } return switch (F) { diff --git a/src/type.zig b/src/type.zig index ea2b6c30c2..bd0718481a 100644 --- a/src/type.zig +++ b/src/type.zig @@ -2892,12 +2892,30 @@ pub const Type = extern union { .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 => return AbiAlignmentAdvanced{ .scalar = @divExact(CType.longlong.sizeInBits(target), 8) }, - .c_ulonglong => return AbiAlignmentAdvanced{ .scalar = @divExact(CType.ulonglong.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) }, + }, .f16 => return AbiAlignmentAdvanced{ .scalar = 2 }, .f32 => return AbiAlignmentAdvanced{ .scalar = 4 }, - .f64 => return AbiAlignmentAdvanced{ .scalar = 8 }, + .f64 => switch (target.cpu.arch) { + .i386 => switch (target.os.tag) { + .windows, .uefi => return AbiAlignmentAdvanced{ .scalar = 8 }, + else => return AbiAlignmentAdvanced{ .scalar = 4 }, + }, + else => return AbiAlignmentAdvanced{ .scalar = 8 }, + }, .f128 => return AbiAlignmentAdvanced{ .scalar = 16 }, .f80 => switch (target.cpu.arch) { @@ -2916,7 +2934,10 @@ pub const Type = extern union { 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 => return AbiAlignmentAdvanced{ .scalar = abiAlignment(Type.f80, 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, }, @@ -6637,7 +6658,11 @@ pub const CType = enum { .long, .ulong => return target.cpu.arch.ptrBitWidth(), .longlong, .ulonglong => 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, .riscv64, .aarch64, @@ -6687,7 +6712,11 @@ pub const CType = enum { .long, .ulong => return target.cpu.arch.ptrBitWidth(), .longlong, .ulonglong => 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, .riscv64, .aarch64, @@ -6715,7 +6744,18 @@ pub const CType = enum { .windows, .uefi => switch (self) { .short, .ushort => return 16, .int, .uint, .long, .ulong => return 32, - .longlong, .ulonglong, .longdouble => return 64, + .longlong, .ulonglong => return 64, + .longdouble => switch (target.cpu.arch) { + .i386 => switch (target.abi) { + .gnu => return 80, + else => return 64, + }, + .x86_64 => switch (target.abi) { + .gnu => return 80, + else => return 64, + }, + else => return 64, + }, }, .macos, .ios, .tvos, .watchos => switch (self) { diff --git a/test/standalone.zig b/test/standalone.zig index b2a464d5c8..9c600dfee5 100644 --- a/test/standalone.zig +++ b/test/standalone.zig @@ -53,6 +53,9 @@ pub fn addCases(cases: *tests.StandaloneContext) void { if (builtin.cpu.arch.isAARCH64() and builtin.zig_backend == .stage2_llvm) { cases.addBuildFile("test/c_abi/build.zig", .{}); } + if (builtin.cpu.arch == .i386 and builtin.zig_backend == .stage2_llvm) { + cases.addBuildFile("test/c_abi/build.zig", .{}); + } // C ABI tests only pass for the Wasm target when using stage2 cases.addBuildFile("test/c_abi/build_wasm.zig", .{ .requires_stage2 = true,