authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2026-04-25 11:59:21-04:00
committergravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2026-04-25 12:10:35-04:00
log2040f9bfd0ab874c6b7a748b9293ad31c7392459
tree64d50a3c30c144ca9d9997d2a1378f07fc1f6b05
parentcb1c7319b575372009185c25eac7b29b93ae83f4

x86_64: fix c abi of `f32` struct field followed by padding

Closes #31864

4 files changed, 25 insertions(+), 29 deletions(-)

src/codegen/x86_64/CodeGen.zig+5-3
...@@ -181632,9 +181632,11 @@ fn splitType(self: *CodeGen, comptime parts_len: usize, ty: Type) ![parts_len]Ty...@@ -181632,9 +181632,11 @@ fn splitType(self: *CodeGen, comptime parts_len: usize, ty: Type) ![parts_len]Ty
181632 else => break,181632 else => break,
181633 };181633 };
181634 } else {181634 } else {
181635 var part_sizes: u64 = 0;181635 var parts_size: u64 = 0;
181636 for (parts) |part| part_sizes += part.abiSize(zcu);181636 for (parts) |part| parts_size += part.abiSize(zcu);
181637 if (part_sizes == ty.abiSize(zcu)) return parts;181637 const abi_size = ty.abiSize(zcu);
181638 if (abi_size == parts_size) return parts;
181639 if (classes[classes.len - 1] == .float and abi_size > parts_size and abi_size <= parts_size + 4) return parts;
181638 };181640 };
181639 return self.fail("TODO implement splitType({d}, {f})", .{ parts_len, ty.fmt(pt) });181641 return self.fail("TODO implement splitType({d}, {f})", .{ parts_len, ty.fmt(pt) });
181640}181642}
src/codegen/x86_64/abi.zig+13-8
...@@ -300,21 +300,26 @@ pub fn classifySystemV(ty: Type, zcu: *Zcu, target: *const std.Target, ctx: Cont...@@ -300,21 +300,26 @@ pub fn classifySystemV(ty: Type, zcu: *Zcu, target: *const std.Target, ctx: Cont
300 for (result, 0..) |class, i| switch (class) {300 for (result, 0..) |class, i| switch (class) {
301 .memory => return Class.stack,301 .memory => return Class.stack,
302 .x87up => if (i == 0 or result[i - 1] != .x87) return Class.stack,302 .x87up => if (i == 0 or result[i - 1] != .x87) return Class.stack,
303 else => continue,303 else => {},
304 };304 };
305 // "If the size of the aggregate exceeds two eightbytes and the first eight-305 // "If the size of the aggregate exceeds two eightbytes and the first eight-
306 // byte isn’t SSE or any other eightbyte isn’t SSEUP, the whole argument306 // byte isn't SSE or any other eightbyte isn't SSEUP, the whole argument
307 // is passed in memory."307 // is passed in memory."
308 if (ty_size > 16 and (result[0] != .sse or308 if (ty_size > 16 and (result[0] != .sse or
309 std.mem.indexOfNone(Class, result[1..], &.{ .sseup, .none }) != null)) return Class.stack;309 std.mem.indexOfNone(Class, result[1..], &.{ .sseup, .none }) != null)) return Class.stack;
310310
311 // "If SSEUP is not preceded by SSE or SSEUP, it is converted to SSE."311 // "If SSEUP is not preceded by SSE or SSEUP, it is converted to SSE."
312 for (&result, 0..) |*item, i| {312 for (&result, 0..) |*class, i| switch (class.*) {
313 if (item.* == .sseup) switch (result[i - 1]) {313 .sseup => switch (result[i - 1]) {
314 .sse, .sseup => continue,314 .sse, .sseup => {},
315 else => item.* = .sse,315 else => class.* = .sse,
316 };316 },
317 }317 .float => if (i + 1 < result.len) switch (result[i + 1]) {
318 .none => {},
319 else => class.* = .float_combine,
320 },
321 else => {},
322 };
318 return result;323 return result;
319 },324 },
320 .array => {325 .array => {
test/c_abi/cfuncs.c-2
...@@ -2948,7 +2948,6 @@ void run_c_tests(void) {...@@ -2948,7 +2948,6 @@ void run_c_tests(void) {
2948#if !defined(__riscv)2948#if !defined(__riscv)
2949#if !defined(__s390x__)2949#if !defined(__s390x__)
2950#if !defined(__i386__)2950#if !defined(__i386__)
2951#if !defined(__x86_64__)
2952 {2951 {
2953 struct Struct_f32a8_f32a8 s = zig_ret_struct_f32a8_f32a8();2952 struct Struct_f32a8_f32a8 s = zig_ret_struct_f32a8_f32a8();
2954 assert_or_panic(s.a == 1.25f);2953 assert_or_panic(s.a == 1.25f);
...@@ -2962,7 +2961,6 @@ void run_c_tests(void) {...@@ -2962,7 +2961,6 @@ void run_c_tests(void) {
2962#endif2961#endif
2963#endif2962#endif
2964#endif2963#endif
2965#endif
29662964
2967#if !(defined(__arm__) && defined(__SOFTFP__))2965#if !(defined(__arm__) && defined(__SOFTFP__))
2968#if !defined(__loongarch__) && !defined(__mips64__)2966#if !defined(__loongarch__) && !defined(__mips64__)
test/c_abi/main.zig+7-16
...@@ -554,22 +554,14 @@ const Struct_f32a8_f32a8 = extern struct {...@@ -554,22 +554,14 @@ const Struct_f32a8_f32a8 = extern struct {
554 b: f32 align(8),554 b: f32 align(8),
555};555};
556556
557comptime {557export fn zig_ret_struct_f32a8_f32a8() Struct_f32a8_f32a8 {
558 skip: {558 return .{ .a = 1.25, .b = 2.75 };
559 if (builtin.zig_backend == .stage2_x86_64) break :skip;559}
560
561 _ = struct {
562 export fn zig_ret_struct_f32a8_f32a8() Struct_f32a8_f32a8 {
563 return .{ .a = 1.25, .b = 2.75 };
564 }
565560
566 export fn zig_struct_f32a8_f32a8(s: Struct_f32a8_f32a8, f: f32) void {561export fn zig_struct_f32a8_f32a8(s: Struct_f32a8_f32a8, f: f32) void {
567 expect(s.a == 3.125) catch @panic("test failure");562 expect(s.a == 3.125) catch @panic("test failure");
568 expect(s.b == 4.375) catch @panic("test failure");563 expect(s.b == 4.375) catch @panic("test failure");
569 expect(f == 5.5) catch @panic("test failure");564 expect(f == 5.5) catch @panic("test failure");
570 }
571 };
572 }
573}565}
574566
575extern fn c_ret_struct_f32a8_f32a8() Struct_f32a8_f32a8;567extern fn c_ret_struct_f32a8_f32a8() Struct_f32a8_f32a8;
...@@ -584,7 +576,6 @@ test "C ABI struct f32 align(8), f32 align(8)" {...@@ -584,7 +576,6 @@ test "C ABI struct f32 align(8), f32 align(8)" {
584 if (builtin.cpu.arch.isRISCV()) return error.SkipZigTest;576 if (builtin.cpu.arch.isRISCV()) return error.SkipZigTest;
585 if (builtin.cpu.arch == .s390x) return error.SkipZigTest;577 if (builtin.cpu.arch == .s390x) return error.SkipZigTest;
586 if (builtin.cpu.arch == .x86) return error.SkipZigTest;578 if (builtin.cpu.arch == .x86) return error.SkipZigTest;
587 if (builtin.cpu.arch == .x86_64) return error.SkipZigTest;
588579
589 const s = c_ret_struct_f32a8_f32a8();580 const s = c_ret_struct_f32a8_f32a8();
590 try expect(s.a == 6.625);581 try expect(s.a == 6.625);