authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-04-26 04:22:38+02:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-04-26 04:22:38+02:00
logf0a7e3ccae45ce7d09038204c16155d5b98ad560
treec165ed76e2432b7753334bb69bc1cfc1ac69be88
parente7d74e49b0dd91e679aa9063311a4513339cedd0
parent2040f9bfd0ab874c6b7a748b9293ad31c7392459

Merge pull request 'fix more c abi bugs' (#32071) from c-abi-padding into master

Reviewed-on: https://codeberg.org/ziglang/zig/pulls/32071 Reviewed-by: Andrew Kelley <andrew@ziglang.org>

6 files changed, 234 insertions(+), 75 deletions(-)

src/codegen/aarch64/abi.zig+49-43
...@@ -1,5 +1,6 @@...@@ -1,5 +1,6 @@
1const assert = @import("std").debug.assert;1const assert = @import("std").debug.assert;
2const std = @import("std");2const std = @import("std");
3const InternPool = @import("../../InternPool.zig");
3const Type = @import("../../Type.zig");4const Type = @import("../../Type.zig");
4const Zcu = @import("../../Zcu.zig");5const Zcu = @import("../../Zcu.zig");
56
...@@ -15,12 +16,10 @@ pub const Class = union(enum) {...@@ -15,12 +16,10 @@ pub const Class = union(enum) {
15pub fn classifyType(ty: Type, zcu: *Zcu) Class {16pub fn classifyType(ty: Type, zcu: *Zcu) Class {
16 assert(ty.hasRuntimeBits(zcu));17 assert(ty.hasRuntimeBits(zcu));
1718
18 var maybe_float_bits: ?u16 = null;
19 switch (ty.zigTypeTag(zcu)) {19 switch (ty.zigTypeTag(zcu)) {
20 .@"struct" => {20 .@"struct" => {
21 if (ty.containerLayout(zcu) == .@"packed") return .byval;21 if (ty.containerLayout(zcu) == .@"packed") return .byval;
22 const float_count = countFloats(ty, zcu, &maybe_float_bits);22 if (countFloats(ty, zcu)) |float| return .{ .float_array = float.count };
23 if (float_count <= sret_float_count) return .{ .float_array = float_count };
2423
25 const bit_size = ty.bitSize(zcu);24 const bit_size = ty.bitSize(zcu);
26 if (bit_size > 128) return .memory;25 if (bit_size > 128) return .memory;
...@@ -29,8 +28,7 @@ pub fn classifyType(ty: Type, zcu: *Zcu) Class {...@@ -29,8 +28,7 @@ pub fn classifyType(ty: Type, zcu: *Zcu) Class {
29 },28 },
30 .@"union" => {29 .@"union" => {
31 if (ty.containerLayout(zcu) == .@"packed") return .byval;30 if (ty.containerLayout(zcu) == .@"packed") return .byval;
32 const float_count = countFloats(ty, zcu, &maybe_float_bits);31 if (countFloats(ty, zcu)) |float| return .{ .float_array = float.count };
33 if (float_count <= sret_float_count) return .{ .float_array = float_count };
3432
35 const bit_size = ty.bitSize(zcu);33 const bit_size = ty.bitSize(zcu);
36 if (bit_size > 128) return .memory;34 if (bit_size > 128) return .memory;
...@@ -70,46 +68,52 @@ pub fn classifyType(ty: Type, zcu: *Zcu) Class {...@@ -70,46 +68,52 @@ pub fn classifyType(ty: Type, zcu: *Zcu) Class {
70 }68 }
71}69}
7270
73const sret_float_count = 4;71const CountFloatsResult = struct {
74fn countFloats(ty: Type, zcu: *Zcu, maybe_float_bits: *?u16) u8 {72 ty: Type,
73 count: std.math.IntFittingRange(0, max_count),
74
75 const none: CountFloatsResult = .{ .ty = .void, .count = 0 };
76
77 const max_count = 4;
78};
79fn countFloats(ty: Type, zcu: *Zcu) ?CountFloatsResult {
75 const ip = &zcu.intern_pool;80 const ip = &zcu.intern_pool;
76 const target = zcu.getTarget();81 if (!ty.hasRuntimeBits(zcu)) return .none;
77 const invalid = std.math.maxInt(u8);
78 switch (ty.zigTypeTag(zcu)) {82 switch (ty.zigTypeTag(zcu)) {
79 .@"union" => {83 .@"union" => {
80 const union_obj = zcu.typeToUnion(ty).?;84 const loaded_union = zcu.typeToUnion(ty).?;
81 var max_count: u8 = 0;85 var result: CountFloatsResult = .none;
82 for (union_obj.field_types.get(ip)) |field_ty| {86 for (loaded_union.field_types.get(ip)) |field_ty| {
83 const field_count = countFloats(Type.fromInterned(field_ty), zcu, maybe_float_bits);87 const float = countFloats(Type.fromInterned(field_ty), zcu) orelse return null;
84 if (field_count == invalid) return invalid;88 if (result.ty.toIntern() == .void_type) {
85 if (field_count > max_count) max_count = field_count;89 result.ty = float.ty;
86 if (max_count > sret_float_count) return invalid;90 } else if (result.ty.bitSize(zcu) != float.ty.bitSize(zcu)) return null;
91 result.count = @max(result.count, float.count);
87 }92 }
88 return max_count;93 if (ty.abiSize(zcu) != result.ty.abiSize(zcu) * result.count) return null;
94 return result;
89 },95 },
90 .@"struct" => {96 .@"struct" => {
91 const fields_len = ty.structFieldCount(zcu);97 var result: CountFloatsResult = .none;
92 var count: u8 = 0;98 var field_it: InternPool.LoadedStructType.RuntimeOrderIterator = if (zcu.typeToStruct(ty)) |loaded_struct|
93 var i: u32 = 0;99 loaded_struct.iterateRuntimeOrder(ip)
94 while (i < fields_len) : (i += 1) {100 else
95 const field_ty = ty.fieldType(i, zcu);101 .{ .runtime_order = null, .fields_len = ty.structFieldCount(zcu), .next_index = 0 };
96 const field_count = countFloats(field_ty, zcu, maybe_float_bits);102 while (field_it.next()) |field_index| {
97 if (field_count == invalid) return invalid;103 if (ty.structFieldOffset(field_index, zcu) != result.ty.abiSize(zcu) * result.count) return null;
98 count += field_count;104 const field_ty = ty.fieldType(field_index, zcu);
99 if (count > sret_float_count) return invalid;105 const float = countFloats(field_ty, zcu) orelse return null;
106 if (result.ty.toIntern() == .void_type) {
107 result.ty = float.ty;
108 } else if (result.ty.bitSize(zcu) != float.ty.bitSize(zcu)) return null;
109 if (float.count > CountFloatsResult.max_count - result.count) return null;
110 result.count += float.count;
100 }111 }
101 return count;112 if (ty.abiSize(zcu) != result.ty.abiSize(zcu) * result.count) return null;
113 return result;
102 },114 },
103 .float => {115 .float => return .{ .ty = ty, .count = 1 },
104 const float_bits = maybe_float_bits.* orelse {116 else => return null,
105 maybe_float_bits.* = ty.floatBits(target);
106 return 1;
107 };
108 if (ty.floatBits(target) == float_bits) return 1;
109 return invalid;
110 },
111 .void => return 0,
112 else => return invalid,
113 }117 }
114}118}
115119
...@@ -117,17 +121,19 @@ pub fn getFloatArrayType(ty: Type, zcu: *Zcu) ?Type {...@@ -117,17 +121,19 @@ pub fn getFloatArrayType(ty: Type, zcu: *Zcu) ?Type {
117 const ip = &zcu.intern_pool;121 const ip = &zcu.intern_pool;
118 switch (ty.zigTypeTag(zcu)) {122 switch (ty.zigTypeTag(zcu)) {
119 .@"union" => {123 .@"union" => {
120 const union_obj = zcu.typeToUnion(ty).?;124 const loaded_union = zcu.typeToUnion(ty).?;
121 for (union_obj.field_types.get(ip)) |field_ty| {125 for (loaded_union.field_types.get(ip)) |field_ty| {
122 if (getFloatArrayType(Type.fromInterned(field_ty), zcu)) |some| return some;126 if (getFloatArrayType(Type.fromInterned(field_ty), zcu)) |some| return some;
123 }127 }
124 return null;128 return null;
125 },129 },
126 .@"struct" => {130 .@"struct" => {
127 const fields_len = ty.structFieldCount(zcu);131 var field_it: InternPool.LoadedStructType.RuntimeOrderIterator = if (zcu.typeToStruct(ty)) |loaded_struct|
128 var i: u32 = 0;132 loaded_struct.iterateRuntimeOrder(ip)
129 while (i < fields_len) : (i += 1) {133 else
130 const field_ty = ty.fieldType(i, zcu);134 .{ .runtime_order = null, .fields_len = ty.structFieldCount(zcu), .next_index = 0 };
135 while (field_it.next()) |field_index| {
136 const field_ty = ty.fieldType(field_index, zcu);
131 if (getFloatArrayType(field_ty, zcu)) |some| return some;137 if (getFloatArrayType(field_ty, zcu)) |some| return some;
132 }138 }
133 return null;139 return null;
src/codegen/llvm/FuncGen.zig+7-6
...@@ -6707,17 +6707,18 @@ const ParamTypeIterator = struct {...@@ -6707,17 +6707,18 @@ const ParamTypeIterator = struct {
6707 .double_integer => return Lowering{ .i64_array = 2 },6707 .double_integer => return Lowering{ .i64_array = 2 },
6708 .fields => {6708 .fields => {
6709 it.types_len = 0;6709 it.types_len = 0;
6710 var offset: u64 = 0;6710 var field_it: InternPool.LoadedStructType.RuntimeOrderIterator = if (zcu.typeToStruct(ty)) |loaded_struct|
6711 for (0..ty.structFieldCount(zcu)) |field_index| {6711 loaded_struct.iterateRuntimeOrder(&zcu.intern_pool)
6712 else
6713 .{ .runtime_order = null, .fields_len = ty.structFieldCount(zcu), .next_index = 0 };
6714 while (field_it.next()) |field_index| {
6712 const field_ty = ty.fieldType(field_index, zcu);6715 const field_ty = ty.fieldType(field_index, zcu);
6713 if (!field_ty.hasRuntimeBits(zcu)) continue;6716 if (!field_ty.hasRuntimeBits(zcu)) continue;
6714 offset = field_ty.abiAlignment(zcu).forward(offset);
6715 it.types_buffer[it.types_len] = try it.object.lowerType(field_ty);6717 it.types_buffer[it.types_len] = try it.object.lowerType(field_ty);
6716 it.offsets_buffer[it.types_len] = offset;6718 it.offsets_buffer[it.types_len] = ty.structFieldOffset(field_index, zcu);
6717 it.types_len += 1;6719 it.types_len += 1;
6718 offset += field_ty.abiSize(zcu);
6719 }6720 }
6720 it.offsets_buffer[it.types_len] = offset;6721 it.offsets_buffer[it.types_len] = ty.abiSize(zcu);
6721 it.llvm_index += it.types_len - 1;6722 it.llvm_index += it.types_len - 1;
6722 return .multiple_llvm_types;6723 return .multiple_llvm_types;
6723 },6724 },
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+93-13
...@@ -1,5 +1,6 @@...@@ -1,5 +1,6 @@
1#include <complex.h>1#include <complex.h>
2#include <inttypes.h>2#include <inttypes.h>
3#include <stdalign.h>
3#include <stdbool.h>4#include <stdbool.h>
4#include <stdlib.h>5#include <stdlib.h>
5#include <string.h>6#include <string.h>
...@@ -209,7 +210,7 @@ struct Struct_u8 zig_ret_struct_u8(void);...@@ -209,7 +210,7 @@ struct Struct_u8 zig_ret_struct_u8(void);
209void zig_struct_u8(struct Struct_u8, size_t);210void zig_struct_u8(struct Struct_u8, size_t);
210211
211struct Struct_u8 c_ret_struct_u8(void) {212struct Struct_u8 c_ret_struct_u8(void) {
212 return (struct Struct_u8){ 4 };213 return (struct Struct_u8){ .a = 4 };
213}214}
214215
215void c_struct_u8(struct Struct_u8 s, size_t i) {216void c_struct_u8(struct Struct_u8 s, size_t i) {
...@@ -226,7 +227,7 @@ struct Struct_u16 zig_ret_struct_u16(void);...@@ -226,7 +227,7 @@ struct Struct_u16 zig_ret_struct_u16(void);
226void zig_struct_u16(struct Struct_u16, size_t);227void zig_struct_u16(struct Struct_u16, size_t);
227228
228struct Struct_u16 c_ret_struct_u16(void) {229struct Struct_u16 c_ret_struct_u16(void) {
229 return (struct Struct_u16){ 10 };230 return (struct Struct_u16){ .a = 10 };
230}231}
231232
232void c_struct_u16(struct Struct_u16 s, size_t i) {233void c_struct_u16(struct Struct_u16 s, size_t i) {
...@@ -243,7 +244,7 @@ struct Struct_u32 zig_ret_struct_u32(void);...@@ -243,7 +244,7 @@ struct Struct_u32 zig_ret_struct_u32(void);
243void zig_struct_u32(struct Struct_u32, size_t);244void zig_struct_u32(struct Struct_u32, size_t);
244245
245struct Struct_u32 c_ret_struct_u32(void) {246struct Struct_u32 c_ret_struct_u32(void) {
246 return (struct Struct_u32){ 16 };247 return (struct Struct_u32){ .a = 16 };
247}248}
248249
249void c_struct_u32(struct Struct_u32 s, size_t i) {250void c_struct_u32(struct Struct_u32 s, size_t i) {
...@@ -260,7 +261,7 @@ struct Struct_u64 zig_ret_struct_u64(void);...@@ -260,7 +261,7 @@ struct Struct_u64 zig_ret_struct_u64(void);
260void zig_struct_u64(struct Struct_u64, size_t);261void zig_struct_u64(struct Struct_u64, size_t);
261262
262struct Struct_u64 c_ret_struct_u64(void) {263struct Struct_u64 c_ret_struct_u64(void) {
263 return (struct Struct_u64){ 22 };264 return (struct Struct_u64){ .a = 22 };
264}265}
265266
266void c_struct_u64(struct Struct_u64 s, size_t i) {267void c_struct_u64(struct Struct_u64 s, size_t i) {
...@@ -286,7 +287,7 @@ void zig_struct_u64_u64_7(size_t, size_t, size_t, size_t, size_t, size_t, size_t...@@ -286,7 +287,7 @@ void zig_struct_u64_u64_7(size_t, size_t, size_t, size_t, size_t, size_t, size_t
286void zig_struct_u64_u64_8(size_t, size_t, size_t, size_t, size_t, size_t, size_t, size_t, struct Struct_u64_u64, size_t);287void zig_struct_u64_u64_8(size_t, size_t, size_t, size_t, size_t, size_t, size_t, size_t, struct Struct_u64_u64, size_t);
287288
288struct Struct_u64_u64 c_ret_struct_u64_u64(void) {289struct Struct_u64_u64 c_ret_struct_u64_u64(void) {
289 return (struct Struct_u64_u64){ 21, 22 };290 return (struct Struct_u64_u64){ .a = 21, .b = 22 };
290}291}
291292
292void c_struct_u64_u64_0(struct Struct_u64_u64 s, size_t i) {293void c_struct_u64_u64_0(struct Struct_u64_u64 s, size_t i) {
...@@ -344,7 +345,7 @@ struct Struct_f32 zig_ret_struct_f32(void);...@@ -344,7 +345,7 @@ struct Struct_f32 zig_ret_struct_f32(void);
344void zig_struct_f32(struct Struct_f32);345void zig_struct_f32(struct Struct_f32);
345346
346struct Struct_f32 c_ret_struct_f32(void) {347struct Struct_f32 c_ret_struct_f32(void) {
347 return (struct Struct_f32){ 2.5f };348 return (struct Struct_f32){ .a = 2.5f };
348}349}
349350
350void c_struct_f32(struct Struct_f32 s) {351void c_struct_f32(struct Struct_f32 s) {
...@@ -360,13 +361,49 @@ struct Struct_f64 zig_ret_struct_f64(void);...@@ -360,13 +361,49 @@ struct Struct_f64 zig_ret_struct_f64(void);
360void zig_struct_f64(struct Struct_f64);361void zig_struct_f64(struct Struct_f64);
361362
362struct Struct_f64 c_ret_struct_f64(void) {363struct Struct_f64 c_ret_struct_f64(void) {
363 return (struct Struct_f64){ 2.5 };364 return (struct Struct_f64){ .a = 2.5 };
364}365}
365366
366void c_struct_f64(struct Struct_f64 s) {367void c_struct_f64(struct Struct_f64 s) {
367 assert_or_panic(s.a == 2.5);368 assert_or_panic(s.a == 2.5);
368}369}
369370
371struct Struct_f32a8 {
372 alignas(8) float a;
373};
374
375struct Struct_f32a8 zig_ret_struct_f32a8(void);
376
377void zig_struct_f32a8(struct Struct_f32a8, float);
378
379struct Struct_f32a8 c_ret_struct_f32a8(void) {
380 return (struct Struct_f32a8){ .a = 4.125f };
381}
382
383void c_struct_f32a8(struct Struct_f32a8 s, float f) {
384 assert_or_panic(s.a == 5.375f);
385 assert_or_panic(f == 6.5f);
386}
387
388struct Struct_f32a8_f32a8 {
389 alignas(8) float a;
390 alignas(8) float b;
391};
392
393struct Struct_f32a8_f32a8 zig_ret_struct_f32a8_f32a8(void);
394
395void zig_struct_f32a8_f32a8(struct Struct_f32a8_f32a8, float);
396
397struct Struct_f32a8_f32a8 c_ret_struct_f32a8_f32a8(void) {
398 return (struct Struct_f32a8_f32a8){ .a = 6.625f, .b = 7.875f };
399}
400
401void c_struct_f32a8_f32a8(struct Struct_f32a8_f32a8 s, float f) {
402 assert_or_panic(s.a == 8.0625f);
403 assert_or_panic(s.b == 9.1875f);
404 assert_or_panic(f == 10.5f);
405}
406
370struct Struct_f32f32_f32 {407struct Struct_f32f32_f32 {
371 struct {408 struct {
372 float b, c;409 float b, c;
...@@ -379,7 +416,7 @@ struct Struct_f32f32_f32 zig_ret_struct_f32f32_f32(void);...@@ -379,7 +416,7 @@ struct Struct_f32f32_f32 zig_ret_struct_f32f32_f32(void);
379void zig_struct_f32f32_f32(struct Struct_f32f32_f32);416void zig_struct_f32f32_f32(struct Struct_f32f32_f32);
380417
381struct Struct_f32f32_f32 c_ret_struct_f32f32_f32(void) {418struct Struct_f32f32_f32 c_ret_struct_f32f32_f32(void) {
382 return (struct Struct_f32f32_f32){ { 1.0f, 2.0f }, 3.0f };419 return (struct Struct_f32f32_f32){ .a = { .b = 1.0f, .c = 2.0f }, .d = 3.0f };
383}420}
384421
385void c_struct_f32f32_f32(struct Struct_f32f32_f32 s) {422void c_struct_f32f32_f32(struct Struct_f32f32_f32 s) {
...@@ -400,7 +437,7 @@ struct Struct_f32_f32f32 zig_ret_struct_f32_f32f32(void);...@@ -400,7 +437,7 @@ struct Struct_f32_f32f32 zig_ret_struct_f32_f32f32(void);
400void zig_struct_f32_f32f32(struct Struct_f32_f32f32);437void zig_struct_f32_f32f32(struct Struct_f32_f32f32);
401438
402struct Struct_f32_f32f32 c_ret_struct_f32_f32f32(void) {439struct Struct_f32_f32f32 c_ret_struct_f32_f32f32(void) {
403 return (struct Struct_f32_f32f32){ 1.0f, { 2.0f, 3.0f } };440 return (struct Struct_f32_f32f32){ .a = 1.0f, .b = { .c = 2.0f, .d = 3.0f } };
404}441}
405442
406void c_struct_f32_f32f32(struct Struct_f32_f32f32 s) {443void c_struct_f32_f32f32(struct Struct_f32_f32f32 s) {
...@@ -2870,7 +2907,7 @@ void run_c_tests(void) {...@@ -2870,7 +2907,7 @@ void run_c_tests(void) {
2870 {2907 {
2871 struct Struct_f32 s = zig_ret_struct_f32();2908 struct Struct_f32 s = zig_ret_struct_f32();
2872 assert_or_panic(s.a == 2.5f);2909 assert_or_panic(s.a == 2.5f);
2873 zig_struct_f32((struct Struct_f32){ 2.5f });2910 zig_struct_f32((struct Struct_f32){ .a = 2.5f });
2874 }2911 }
2875#endif2912#endif
28762913
...@@ -2879,17 +2916,60 @@ void run_c_tests(void) {...@@ -2879,17 +2916,60 @@ void run_c_tests(void) {
2879 {2916 {
2880 struct Struct_f64 s = zig_ret_struct_f64();2917 struct Struct_f64 s = zig_ret_struct_f64();
2881 assert_or_panic(s.a == 2.5);2918 assert_or_panic(s.a == 2.5);
2882 zig_struct_f64((struct Struct_f64){ 2.5 });2919 zig_struct_f64((struct Struct_f64){ .a = 2.5 });
2883 }2920 }
2884#endif2921#endif
2922#endif
28852923
2924#if !defined(__arm__)
2925#if !defined(__loongarch__)
2926#if !defined(__mips64__)
2927#if !defined(__powerpc__)
2928#if !defined(ZIG_RISCV32)
2929#if !defined(__s390x__)
2930#if !defined(__i386__)
2931 {
2932 struct Struct_f32a8 s = zig_ret_struct_f32a8();
2933 assert_or_panic(s.a == 1.25f);
2934 zig_struct_f32a8((struct Struct_f32a8){ .a = 2.75f }, 3.5f);
2935 }
2936#endif
2937#endif
2938#endif
2939#endif
2940#endif
2941#endif
2942#endif
2943
2944#if !defined(__arm__)
2945#if !defined(__loongarch__)
2946#if !defined(__mips64__)
2947#if !defined(__powerpc__)
2948#if !defined(__riscv)
2949#if !defined(__s390x__)
2950#if !defined(__i386__)
2951 {
2952 struct Struct_f32a8_f32a8 s = zig_ret_struct_f32a8_f32a8();
2953 assert_or_panic(s.a == 1.25f);
2954 assert_or_panic(s.b == 2.75f);
2955 zig_struct_f32a8_f32a8((struct Struct_f32a8_f32a8){ .a = 3.125f, .b = 4.375f }, 5.5f);
2956 }
2957#endif
2958#endif
2959#endif
2960#endif
2961#endif
2962#endif
2963#endif
2964
2965#if !(defined(__arm__) && defined(__SOFTFP__))
2886#if !defined(__loongarch__) && !defined(__mips64__)2966#if !defined(__loongarch__) && !defined(__mips64__)
2887 {2967 {
2888 struct Struct_f32f32_f32 s = zig_ret_struct_f32f32_f32();2968 struct Struct_f32f32_f32 s = zig_ret_struct_f32f32_f32();
2889 assert_or_panic(s.a.b == 1.0f);2969 assert_or_panic(s.a.b == 1.0f);
2890 assert_or_panic(s.a.c == 2.0f);2970 assert_or_panic(s.a.c == 2.0f);
2891 assert_or_panic(s.d == 3.0f);2971 assert_or_panic(s.d == 3.0f);
2892 zig_struct_f32f32_f32((struct Struct_f32f32_f32){ { 1.0f, 2.0f }, 3.0f });2972 zig_struct_f32f32_f32((struct Struct_f32f32_f32){ .a = { .b = 1.0f, .c = 2.0f }, .d = 3.0f });
2893 }2973 }
28942974
2895 {2975 {
...@@ -2897,7 +2977,7 @@ void run_c_tests(void) {...@@ -2897,7 +2977,7 @@ void run_c_tests(void) {
2897 assert_or_panic(s.a == 1.0f);2977 assert_or_panic(s.a == 1.0f);
2898 assert_or_panic(s.b.c == 2.0f);2978 assert_or_panic(s.b.c == 2.0f);
2899 assert_or_panic(s.b.d == 3.0f);2979 assert_or_panic(s.b.d == 3.0f);
2900 zig_struct_f32_f32f32((struct Struct_f32_f32f32){ 1.0f, { 2.0f, 3.0f } });2980 zig_struct_f32_f32f32((struct Struct_f32_f32f32){ .a = 1.0f, .b = { .c = 2.0f, .d = 3.0f } });
2901 }2981 }
2902#endif2982#endif
2903#endif2983#endif
test/c_abi/main.zig+67-2
...@@ -444,7 +444,7 @@ extern fn c_struct_u64_u64_6(usize, usize, usize, usize, usize, usize, Struct_u6...@@ -444,7 +444,7 @@ extern fn c_struct_u64_u64_6(usize, usize, usize, usize, usize, usize, Struct_u6
444extern fn c_struct_u64_u64_7(usize, usize, usize, usize, usize, usize, usize, Struct_u64_u64, usize) void;444extern fn c_struct_u64_u64_7(usize, usize, usize, usize, usize, usize, usize, Struct_u64_u64, usize) void;
445extern fn c_struct_u64_u64_8(usize, usize, usize, usize, usize, usize, usize, usize, Struct_u64_u64, usize) void;445extern fn c_struct_u64_u64_8(usize, usize, usize, usize, usize, usize, usize, usize, Struct_u64_u64, usize) void;
446446
447test "C ABI struct u64 u64" {447test "C ABI struct u64, u64" {
448 if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest;448 if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest;
449 if (builtin.cpu.arch.isPowerPC32()) return error.SkipZigTest;449 if (builtin.cpu.arch.isPowerPC32()) return error.SkipZigTest;
450 if (builtin.cpu.arch == .hexagon) return error.SkipZigTest;450 if (builtin.cpu.arch == .hexagon) return error.SkipZigTest;
...@@ -518,6 +518,71 @@ test "C ABI struct f64" {...@@ -518,6 +518,71 @@ test "C ABI struct f64" {
518 c_struct_f64(.{ .a = 2.5 });518 c_struct_f64(.{ .a = 2.5 });
519}519}
520520
521const Struct_f32a8 = extern struct {
522 a: f32 align(8),
523};
524
525export fn zig_ret_struct_f32a8() Struct_f32a8 {
526 return .{ .a = 1.25 };
527}
528
529export fn zig_struct_f32a8(s: Struct_f32a8, f: f32) void {
530 expect(s.a == 2.75) catch @panic("test failure");
531 expect(f == 3.5) catch @panic("test failure");
532}
533
534extern fn c_ret_struct_f32a8() Struct_f32a8;
535
536extern fn c_struct_f32a8(Struct_f32a8, f32) void;
537
538test "C ABI struct f32 align(8)" {
539 if (builtin.cpu.arch.isArm()) return error.SkipZigTest;
540 if (builtin.cpu.arch.isLoongArch()) return error.SkipZigTest;
541 if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest;
542 if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest;
543 if (builtin.cpu.arch == .riscv32) return error.SkipZigTest;
544 if (builtin.cpu.arch == .s390x) return error.SkipZigTest;
545 if (builtin.cpu.arch == .x86) return error.SkipZigTest;
546
547 const s = c_ret_struct_f32a8();
548 try expect(s.a == 4.125);
549 c_struct_f32a8(.{ .a = 5.375 }, 6.5);
550}
551
552const Struct_f32a8_f32a8 = extern struct {
553 a: f32 align(8),
554 b: f32 align(8),
555};
556
557export fn zig_ret_struct_f32a8_f32a8() Struct_f32a8_f32a8 {
558 return .{ .a = 1.25, .b = 2.75 };
559}
560
561export fn zig_struct_f32a8_f32a8(s: Struct_f32a8_f32a8, f: f32) void {
562 expect(s.a == 3.125) catch @panic("test failure");
563 expect(s.b == 4.375) catch @panic("test failure");
564 expect(f == 5.5) catch @panic("test failure");
565}
566
567extern fn c_ret_struct_f32a8_f32a8() Struct_f32a8_f32a8;
568
569extern fn c_struct_f32a8_f32a8(Struct_f32a8_f32a8, f32) void;
570
571test "C ABI struct f32 align(8), f32 align(8)" {
572 if (builtin.cpu.arch.isArm()) return error.SkipZigTest;
573 if (builtin.cpu.arch.isLoongArch()) return error.SkipZigTest;
574 if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest;
575 if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest;
576 if (builtin.cpu.arch.isRISCV()) return error.SkipZigTest;
577 if (builtin.cpu.arch == .s390x) return error.SkipZigTest;
578 if (builtin.cpu.arch == .x86) return error.SkipZigTest;
579
580 const s = c_ret_struct_f32a8_f32a8();
581 try expect(s.a == 6.625);
582 try expect(s.b == 7.875);
583 c_struct_f32a8_f32a8(.{ .a = 8.0625, .b = 9.1875 }, 10.5);
584}
585
521const Struct_f32f32_f32 = extern struct {586const Struct_f32f32_f32 = extern struct {
522 a: extern struct { b: f32, c: f32 },587 a: extern struct { b: f32, c: f32 },
523 d: f32,588 d: f32,
...@@ -537,7 +602,7 @@ extern fn c_ret_struct_f32f32_f32() Struct_f32f32_f32;...@@ -537,7 +602,7 @@ extern fn c_ret_struct_f32f32_f32() Struct_f32f32_f32;
537602
538extern fn c_struct_f32f32_f32(Struct_f32f32_f32) void;603extern fn c_struct_f32f32_f32(Struct_f32f32_f32) void;
539604
540test "C ABI struct {f32,f32} f32" {605test "C ABI struct {f32, f32}, f32" {
541 if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest;606 if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest;
542 if (builtin.cpu.arch.isPowerPC32()) return error.SkipZigTest;607 if (builtin.cpu.arch.isPowerPC32()) return error.SkipZigTest;
543 if (builtin.cpu.arch.isArm() and builtin.abi.float() == .soft) return error.SkipZigTest;608 if (builtin.cpu.arch.isArm() and builtin.abi.float() == .soft) return error.SkipZigTest;