From 2040f9bfd0ab874c6b7a748b9293ad31c7392459 Mon Sep 17 00:00:00 2001 From: Jacob Young Date: Sat, 25 Apr 2026 11:59:21 -0400 Subject: [PATCH] x86_64: fix c abi of `f32` struct field followed by padding Closes #31864 --- src/codegen/x86_64/CodeGen.zig | 8 +++++--- src/codegen/x86_64/abi.zig | 21 +++++++++++++-------- test/c_abi/cfuncs.c | 2 -- test/c_abi/main.zig | 23 +++++++---------------- 4 files changed, 25 insertions(+), 29 deletions(-) diff --git a/src/codegen/x86_64/CodeGen.zig b/src/codegen/x86_64/CodeGen.zig index 72a382fee1..97cee13bb3 100644 --- a/src/codegen/x86_64/CodeGen.zig +++ b/src/codegen/x86_64/CodeGen.zig @@ -181632,9 +181632,11 @@ fn splitType(self: *CodeGen, comptime parts_len: usize, ty: Type) ![parts_len]Ty else => break, }; } else { - var part_sizes: u64 = 0; - for (parts) |part| part_sizes += part.abiSize(zcu); - if (part_sizes == ty.abiSize(zcu)) return parts; + var parts_size: u64 = 0; + for (parts) |part| parts_size += part.abiSize(zcu); + const abi_size = ty.abiSize(zcu); + if (abi_size == parts_size) return parts; + if (classes[classes.len - 1] == .float and abi_size > parts_size and abi_size <= parts_size + 4) return parts; }; return self.fail("TODO implement splitType({d}, {f})", .{ parts_len, ty.fmt(pt) }); } diff --git a/src/codegen/x86_64/abi.zig b/src/codegen/x86_64/abi.zig index 911609b1f3..fcd6e63f92 100644 --- a/src/codegen/x86_64/abi.zig +++ b/src/codegen/x86_64/abi.zig @@ -300,21 +300,26 @@ pub fn classifySystemV(ty: Type, zcu: *Zcu, target: *const std.Target, ctx: Cont for (result, 0..) |class, i| switch (class) { .memory => return Class.stack, .x87up => if (i == 0 or result[i - 1] != .x87) return Class.stack, - else => continue, + else => {}, }; // "If the size of the aggregate exceeds two eightbytes and the first eight- - // byte isn’t SSE or any other eightbyte isn’t SSEUP, the whole argument + // byte isn't SSE or any other eightbyte isn't SSEUP, the whole argument // is passed in memory." if (ty_size > 16 and (result[0] != .sse or std.mem.indexOfNone(Class, result[1..], &.{ .sseup, .none }) != null)) return Class.stack; // "If SSEUP is not preceded by SSE or SSEUP, it is converted to SSE." - for (&result, 0..) |*item, i| { - if (item.* == .sseup) switch (result[i - 1]) { - .sse, .sseup => continue, - else => item.* = .sse, - }; - } + for (&result, 0..) |*class, i| switch (class.*) { + .sseup => switch (result[i - 1]) { + .sse, .sseup => {}, + else => class.* = .sse, + }, + .float => if (i + 1 < result.len) switch (result[i + 1]) { + .none => {}, + else => class.* = .float_combine, + }, + else => {}, + }; return result; }, .array => { diff --git a/test/c_abi/cfuncs.c b/test/c_abi/cfuncs.c index bd925d58b9..fc708f343e 100644 --- a/test/c_abi/cfuncs.c +++ b/test/c_abi/cfuncs.c @@ -2948,7 +2948,6 @@ void run_c_tests(void) { #if !defined(__riscv) #if !defined(__s390x__) #if !defined(__i386__) -#if !defined(__x86_64__) { struct Struct_f32a8_f32a8 s = zig_ret_struct_f32a8_f32a8(); assert_or_panic(s.a == 1.25f); @@ -2962,7 +2961,6 @@ void run_c_tests(void) { #endif #endif #endif -#endif #if !(defined(__arm__) && defined(__SOFTFP__)) #if !defined(__loongarch__) && !defined(__mips64__) diff --git a/test/c_abi/main.zig b/test/c_abi/main.zig index 353804e480..1f221260b4 100644 --- a/test/c_abi/main.zig +++ b/test/c_abi/main.zig @@ -554,22 +554,14 @@ const Struct_f32a8_f32a8 = extern struct { b: f32 align(8), }; -comptime { - skip: { - if (builtin.zig_backend == .stage2_x86_64) break :skip; +export fn zig_ret_struct_f32a8_f32a8() Struct_f32a8_f32a8 { + return .{ .a = 1.25, .b = 2.75 }; +} - _ = struct { - export fn zig_ret_struct_f32a8_f32a8() Struct_f32a8_f32a8 { - return .{ .a = 1.25, .b = 2.75 }; - } - - export fn zig_struct_f32a8_f32a8(s: Struct_f32a8_f32a8, f: f32) void { - expect(s.a == 3.125) catch @panic("test failure"); - expect(s.b == 4.375) catch @panic("test failure"); - expect(f == 5.5) catch @panic("test failure"); - } - }; - } +export fn zig_struct_f32a8_f32a8(s: Struct_f32a8_f32a8, f: f32) void { + expect(s.a == 3.125) catch @panic("test failure"); + expect(s.b == 4.375) catch @panic("test failure"); + expect(f == 5.5) catch @panic("test failure"); } extern fn c_ret_struct_f32a8_f32a8() Struct_f32a8_f32a8; @@ -584,7 +576,6 @@ test "C ABI struct f32 align(8), f32 align(8)" { if (builtin.cpu.arch.isRISCV()) return error.SkipZigTest; if (builtin.cpu.arch == .s390x) return error.SkipZigTest; if (builtin.cpu.arch == .x86) return error.SkipZigTest; - if (builtin.cpu.arch == .x86_64) return error.SkipZigTest; const s = c_ret_struct_f32a8_f32a8(); try expect(s.a == 6.625);