diff --git a/src/codegen/x86_64/abi.zig b/src/codegen/x86_64/abi.zig index 0bff5bd60a2f7e918dda9fd5835d653378686cff..1e01ff508af3a29367f9cfbb1ea74d412147d70a 100644 --- a/src/codegen/x86_64/abi.zig +++ b/src/codegen/x86_64/abi.zig @@ -358,11 +358,10 @@ fn classifySystemVStruct( while (field_it.next()) |field_index| { const field_ty = Type.fromInterned(loaded_struct.field_types.get(ip)[field_index]); const field_align = loaded_struct.field_aligns.getOrNone(ip, field_index); - byte_offset = std.mem.alignForward( - u64, - byte_offset, - field_align.toByteUnits() orelse field_ty.abiAlignment(zcu).toByteUnits().?, - ); + byte_offset = switch (field_align) { + .none => field_ty.abiAlignment(zcu), + else => field_align, + }.forward(byte_offset); if (zcu.typeToStruct(field_ty)) |field_loaded_struct| { switch (field_loaded_struct.layout) { .auto => unreachable, @@ -381,6 +380,9 @@ fn classifySystemVStruct( }, .@"packed" => {}, } + } else if (field_ty.zigTypeTag(zcu) == .array) { + byte_offset = classifySystemVArray(result, byte_offset, field_ty, zcu, target); + continue; } const field_classes = std.mem.sliceTo(&classifySystemV(field_ty, zcu, target, .other), .none); for (result[@intCast(byte_offset / 8)..][0..field_classes.len], field_classes) |*result_class, field_class| @@ -388,11 +390,7 @@ fn classifySystemVStruct( byte_offset += field_ty.abiSize(zcu); } const final_byte_offset = starting_byte_offset + loaded_struct.size; - std.debug.assert(final_byte_offset == std.mem.alignForward( - u64, - byte_offset, - loaded_struct.alignment.toByteUnits().?, - )); + std.debug.assert(final_byte_offset == loaded_struct.alignment.forward(byte_offset)); return final_byte_offset; } @@ -424,6 +422,9 @@ fn classifySystemVUnion( }, .@"packed" => {}, } + } else if (field_ty.zigTypeTag(zcu) == .array) { + _ = classifySystemVArray(result, starting_byte_offset, field_ty, zcu, target); + continue; } const field_classes = std.mem.sliceTo(&classifySystemV(field_ty, zcu, target, .other), .none); for (result[@intCast(starting_byte_offset / 8)..][0..field_classes.len], field_classes) |*result_class, field_class| @@ -432,6 +433,26 @@ fn classifySystemVUnion( return starting_byte_offset + loaded_union.size; } +fn classifySystemVArray( + result: *[8]Class, + starting_byte_offset: u64, + array_ty: Type, + zcu: *Zcu, + target: *const std.Target, +) u64 { + const field_classes = std.mem.sliceTo(&classifySystemV(array_ty.childType(zcu), zcu, target, .other), .none); + var byte_offset = starting_byte_offset; + const elem_size = array_ty.childType(zcu).abiSize(zcu); + for (0..@intCast(array_ty.arrayLen(zcu))) |_| { + for (result[@intCast(byte_offset / 8)..][0..field_classes.len], field_classes) |*result_class, field_class| + result_class.* = result_class.combineSystemV(field_class); + byte_offset += elem_size; + } + const final_byte_offset = starting_byte_offset + array_ty.abiSize(zcu); + assert(final_byte_offset == byte_offset); + return final_byte_offset; +} + pub const zigcc = struct { pub const stack_align: ?InternPool.Alignment = null; pub const return_in_regs = true; diff --git a/test/c_abi/cfuncs.c b/test/c_abi/cfuncs.c index 91a33b24ad4d3ffbefc648495d1291491827677c..a1471283bfbc5ce35b9bdd4edd6e6cb6df81d831 100644 --- a/test/c_abi/cfuncs.c +++ b/test/c_abi/cfuncs.c @@ -15194,6 +15194,126 @@ void c_test_struct_f32_f32_f32_f32_f32(void) { zig_struct_f32_f32_f32_f32_f32((struct Struct_f32_f32_f32_f32_f32){ .a = 6, .b = 7, .c = 8, .d = 9, .e = 10 }, 11); } +struct Struct_array_1_f32 { + float a[1]; +}; + +struct Struct_array_1_f32 zig_ret_struct_array_1_f32(void); +void zig_struct_array_1_f32(struct Struct_array_1_f32, size_t); + +struct Struct_array_1_f32 c_ret_struct_array_1_f32(void) { + return (struct Struct_array_1_f32){ .a = { 4 } }; +} +void c_struct_array_1_f32(struct Struct_array_1_f32 s, size_t i) { + assert_or_panic(s.a[0] == 5); + assert_or_panic(i == 6); +} +void c_test_struct_array_1_f32(void) { + struct Struct_array_1_f32 s = zig_ret_struct_array_1_f32(); + assert_or_panic(s.a[0] == 1); + zig_struct_array_1_f32((struct Struct_array_1_f32){ .a = { 2 } }, 3); +} + +struct Struct_array_2_f32 { + float a[2]; +}; + +struct Struct_array_2_f32 zig_ret_struct_array_2_f32(void); +void zig_struct_array_2_f32(struct Struct_array_2_f32, size_t); + +struct Struct_array_2_f32 c_ret_struct_array_2_f32(void) { + return (struct Struct_array_2_f32){ .a = { 6, 7 } }; +} +void c_struct_array_2_f32(struct Struct_array_2_f32 s, size_t i) { + assert_or_panic(s.a[0] == 8); + assert_or_panic(s.a[1] == 9); + assert_or_panic(i == 10); +} +void c_test_struct_array_2_f32(void) { + struct Struct_array_2_f32 s = zig_ret_struct_array_2_f32(); + assert_or_panic(s.a[0] == 1); + assert_or_panic(s.a[1] == 2); + zig_struct_array_2_f32((struct Struct_array_2_f32){ .a = { 3, 4 } }, 5); +} + +struct Struct_array_3_f32 { + float a[3]; +}; + +struct Struct_array_3_f32 zig_ret_struct_array_3_f32(void); +void zig_struct_array_3_f32(struct Struct_array_3_f32, size_t); + +struct Struct_array_3_f32 c_ret_struct_array_3_f32(void) { + return (struct Struct_array_3_f32){ .a = { 8, 9, 10 } }; +} +void c_struct_array_3_f32(struct Struct_array_3_f32 s, size_t i) { + assert_or_panic(s.a[0] == 11); + assert_or_panic(s.a[1] == 12); + assert_or_panic(s.a[2] == 13); + assert_or_panic(i == 14); +} +void c_test_struct_array_3_f32(void) { + struct Struct_array_3_f32 s = zig_ret_struct_array_3_f32(); + assert_or_panic(s.a[0] == 1); + assert_or_panic(s.a[1] == 2); + assert_or_panic(s.a[2] == 3); + zig_struct_array_3_f32((struct Struct_array_3_f32){ .a = { 4, 5, 6 } }, 7); +} + +struct Struct_array_4_f32 { + float a[4]; +}; + +struct Struct_array_4_f32 zig_ret_struct_array_4_f32(void); +void zig_struct_array_4_f32(struct Struct_array_4_f32, size_t); + +struct Struct_array_4_f32 c_ret_struct_array_4_f32(void) { + return (struct Struct_array_4_f32){ .a = { 10, 11, 12, 13 } }; +} +void c_struct_array_4_f32(struct Struct_array_4_f32 s, size_t i) { + assert_or_panic(s.a[0] == 14); + assert_or_panic(s.a[1] == 15); + assert_or_panic(s.a[2] == 16); + assert_or_panic(s.a[3] == 17); + assert_or_panic(i == 18); +} +void c_test_struct_array_4_f32(void) { + struct Struct_array_4_f32 s = zig_ret_struct_array_4_f32(); + assert_or_panic(s.a[0] == 1); + assert_or_panic(s.a[1] == 2); + assert_or_panic(s.a[2] == 3); + assert_or_panic(s.a[3] == 4); + zig_struct_array_4_f32((struct Struct_array_4_f32){ .a = { 5, 6, 7, 8 } }, 9); +} + +struct Struct_array_5_f32 { + float a[5]; +}; + +struct Struct_array_5_f32 zig_ret_struct_array_5_f32(void); +void zig_struct_array_5_f32(struct Struct_array_5_f32, size_t); + +struct Struct_array_5_f32 c_ret_struct_array_5_f32(void) { + return (struct Struct_array_5_f32){ .a = { 12, 13, 14, 15, 16 } }; +} +void c_struct_array_5_f32(struct Struct_array_5_f32 s, size_t i) { + assert_or_panic(s.a[0] == 17); + assert_or_panic(s.a[1] == 18); + assert_or_panic(s.a[2] == 19); + assert_or_panic(s.a[3] == 20); + assert_or_panic(s.a[4] == 21); + assert_or_panic(i == 22); +} +void c_test_struct_array_5_f32(void) { + struct Struct_array_5_f32 s = zig_ret_struct_array_5_f32(); + assert_or_panic(s.a[0] == 1); + assert_or_panic(s.a[1] == 2); + assert_or_panic(s.a[2] == 3); + assert_or_panic(s.a[3] == 4); + assert_or_panic(s.a[4] == 5); + zig_struct_array_5_f32((struct Struct_array_5_f32){ .a = { 6, 7, 8, 9, 10 } }, 11); +} + struct Struct_f32a8 { alignas(8) float a; }; @@ -15409,6 +15529,126 @@ void c_test_struct_f64_f64_f64_f64_f64(void) { zig_struct_f64_f64_f64_f64_f64((struct Struct_f64_f64_f64_f64_f64){ .a = 6, .b = 7, .c = 8, .d = 9, .e = 10 }, 11); } +struct Struct_array_1_f64 { + double a[1]; +}; + +struct Struct_array_1_f64 zig_ret_struct_array_1_f64(void); +void zig_struct_array_1_f64(struct Struct_array_1_f64, size_t); + +struct Struct_array_1_f64 c_ret_struct_array_1_f64(void) { + return (struct Struct_array_1_f64){ .a = { 4 } }; +} +void c_struct_array_1_f64(struct Struct_array_1_f64 s, size_t i) { + assert_or_panic(s.a[0] == 5); + assert_or_panic(i == 6); +} +void c_test_struct_array_1_f64(void) { + struct Struct_array_1_f64 s = zig_ret_struct_array_1_f64(); + assert_or_panic(s.a[0] == 1); + zig_struct_array_1_f64((struct Struct_array_1_f64){ .a = { 2 } }, 3); +} + +struct Struct_array_2_f64 { + double a[2]; +}; + +struct Struct_array_2_f64 zig_ret_struct_array_2_f64(void); +void zig_struct_array_2_f64(struct Struct_array_2_f64, size_t); + +struct Struct_array_2_f64 c_ret_struct_array_2_f64(void) { + return (struct Struct_array_2_f64){ .a = { 6, 7 } }; +} +void c_struct_array_2_f64(struct Struct_array_2_f64 s, size_t i) { + assert_or_panic(s.a[0] == 8); + assert_or_panic(s.a[1] == 9); + assert_or_panic(i == 10); +} +void c_test_struct_array_2_f64(void) { + struct Struct_array_2_f64 s = zig_ret_struct_array_2_f64(); + assert_or_panic(s.a[0] == 1); + assert_or_panic(s.a[1] == 2); + zig_struct_array_2_f64((struct Struct_array_2_f64){ .a = { 3, 4 } }, 5); +} + +struct Struct_array_3_f64 { + double a[3]; +}; + +struct Struct_array_3_f64 zig_ret_struct_array_3_f64(void); +void zig_struct_array_3_f64(struct Struct_array_3_f64, size_t); + +struct Struct_array_3_f64 c_ret_struct_array_3_f64(void) { + return (struct Struct_array_3_f64){ .a = { 8, 9, 10 } }; +} +void c_struct_array_3_f64(struct Struct_array_3_f64 s, size_t i) { + assert_or_panic(s.a[0] == 11); + assert_or_panic(s.a[1] == 12); + assert_or_panic(s.a[2] == 13); + assert_or_panic(i == 14); +} +void c_test_struct_array_3_f64(void) { + struct Struct_array_3_f64 s = zig_ret_struct_array_3_f64(); + assert_or_panic(s.a[0] == 1); + assert_or_panic(s.a[1] == 2); + assert_or_panic(s.a[2] == 3); + zig_struct_array_3_f64((struct Struct_array_3_f64){ .a = { 4, 5, 6 } }, 7); +} + +struct Struct_array_4_f64 { + double a[4]; +}; + +struct Struct_array_4_f64 zig_ret_struct_array_4_f64(void); +void zig_struct_array_4_f64(struct Struct_array_4_f64, size_t); + +struct Struct_array_4_f64 c_ret_struct_array_4_f64(void) { + return (struct Struct_array_4_f64){ .a = { 10, 11, 12, 13 } }; +} +void c_struct_array_4_f64(struct Struct_array_4_f64 s, size_t i) { + assert_or_panic(s.a[0] == 14); + assert_or_panic(s.a[1] == 15); + assert_or_panic(s.a[2] == 16); + assert_or_panic(s.a[3] == 17); + assert_or_panic(i == 18); +} +void c_test_struct_array_4_f64(void) { + struct Struct_array_4_f64 s = zig_ret_struct_array_4_f64(); + assert_or_panic(s.a[0] == 1); + assert_or_panic(s.a[1] == 2); + assert_or_panic(s.a[2] == 3); + assert_or_panic(s.a[3] == 4); + zig_struct_array_4_f64((struct Struct_array_4_f64){ .a = { 5, 6, 7, 8 } }, 9); +} + +struct Struct_array_5_f64 { + double a[5]; +}; + +struct Struct_array_5_f64 zig_ret_struct_array_5_f64(void); +void zig_struct_array_5_f64(struct Struct_array_5_f64, size_t); + +struct Struct_array_5_f64 c_ret_struct_array_5_f64(void) { + return (struct Struct_array_5_f64){ .a = { 12, 13, 14, 15, 16 } }; +} +void c_struct_array_5_f64(struct Struct_array_5_f64 s, size_t i) { + assert_or_panic(s.a[0] == 17); + assert_or_panic(s.a[1] == 18); + assert_or_panic(s.a[2] == 19); + assert_or_panic(s.a[3] == 20); + assert_or_panic(s.a[4] == 21); + assert_or_panic(i == 22); +} +void c_test_struct_array_5_f64(void) { + struct Struct_array_5_f64 s = zig_ret_struct_array_5_f64(); + assert_or_panic(s.a[0] == 1); + assert_or_panic(s.a[1] == 2); + assert_or_panic(s.a[2] == 3); + assert_or_panic(s.a[3] == 4); + assert_or_panic(s.a[4] == 5); + zig_struct_array_5_f64((struct Struct_array_5_f64){ .a = { 6, 7, 8, 9, 10 } }, 11); +} + struct Struct_u32_Union_u32_u32u32 { uint32_t a; union { diff --git a/test/c_abi/main.zig b/test/c_abi/main.zig index f1bbd96806d3b507ee0448f4415f811aae2d929a..16b99134cf70bc44a77179f48c68704d7a9041ec 100644 --- a/test/c_abi/main.zig +++ b/test/c_abi/main.zig @@ -16085,6 +16085,181 @@ test "struct f32, f32, f32, f32, f32" { c_test_struct_f32_f32_f32_f32_f32(); } +const Struct_array_1_f32 = extern struct { + a: [1]f32, +}; + +comptime { + skip: { + if (builtin.cpu.arch.isWasm()) break :skip; + + _ = struct { + export fn zig_ret_struct_array_1_f32() Struct_array_1_f32 { + return .{ .a = .{1} }; + } + export fn zig_struct_array_1_f32(s: Struct_array_1_f32, i: usize) void { + expect(s.a[0] == 2) catch @panic("test failure"); + expect(i == 3) catch @panic("test failure"); + } + }; + } +} + +extern fn c_ret_struct_array_1_f32() Struct_array_1_f32; +extern fn c_struct_array_1_f32(Struct_array_1_f32, usize) void; +extern fn c_test_struct_array_1_f32() void; + +test "struct [1]f32" { + if (builtin.cpu.arch.isAARCH64()) return error.SkipZigTest; + if (builtin.cpu.arch.isArm()) return error.SkipZigTest; + if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; + if (builtin.cpu.arch.isRISCV()) return error.SkipZigTest; + if (builtin.cpu.arch == .s390x) return error.SkipZigTest; + if (builtin.cpu.arch.isWasm()) return error.SkipZigTest; + + const s = c_ret_struct_array_1_f32(); + try expect(s.a[0] == 4); + c_struct_array_1_f32(.{ .a = .{5} }, 6); + c_test_struct_array_1_f32(); +} + +const Struct_array_2_f32 = extern struct { + a: [2]f32, +}; + +export fn zig_ret_struct_array_2_f32() Struct_array_2_f32 { + return .{ .a = .{ 1, 2 } }; +} +export fn zig_struct_array_2_f32(s: Struct_array_2_f32, i: usize) void { + expect(s.a[0] == 3) catch @panic("test failure"); + expect(s.a[1] == 4) catch @panic("test failure"); + expect(i == 5) catch @panic("test failure"); +} + +extern fn c_ret_struct_array_2_f32() Struct_array_2_f32; +extern fn c_struct_array_2_f32(Struct_array_2_f32, usize) void; +extern fn c_test_struct_array_2_f32() void; + +test "struct [2]f32" { + if (builtin.cpu.arch.isAARCH64()) return error.SkipZigTest; + if (builtin.cpu.arch.isArm()) return error.SkipZigTest; + if (builtin.cpu.arch == .loongarch64 and builtin.abi.float() == .hard) return error.SkipZigTest; + if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; + if (builtin.cpu.arch.isRISCV()) return error.SkipZigTest; + + const s = c_ret_struct_array_2_f32(); + try expect(s.a[0] == 6); + try expect(s.a[1] == 7); + c_struct_array_2_f32(.{ .a = .{ 8, 9 } }, 10); + c_test_struct_array_2_f32(); +} + +const Struct_array_3_f32 = extern struct { + a: [3]f32, +}; + +export fn zig_ret_struct_array_3_f32() Struct_array_3_f32 { + return .{ .a = .{ 1, 2, 3 } }; +} +export fn zig_struct_array_3_f32(s: Struct_array_3_f32, i: usize) void { + expect(s.a[0] == 4) catch @panic("test failure"); + expect(s.a[1] == 5) catch @panic("test failure"); + expect(s.a[2] == 6) catch @panic("test failure"); + expect(i == 7) catch @panic("test failure"); +} + +extern fn c_ret_struct_array_3_f32() Struct_array_3_f32; +extern fn c_struct_array_3_f32(Struct_array_3_f32, usize) void; +extern fn c_test_struct_array_3_f32() void; + +test "struct [3]f32" { + if (builtin.cpu.arch.isAARCH64()) return error.SkipZigTest; + if (builtin.cpu.arch.isArm()) return error.SkipZigTest; + if (builtin.cpu.arch == .hexagon) return error.SkipZigTest; + if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; + + const s = c_ret_struct_array_3_f32(); + try expect(s.a[0] == 8); + try expect(s.a[1] == 9); + try expect(s.a[2] == 10); + c_struct_array_3_f32(.{ .a = .{ 11, 12, 13 } }, 14); + c_test_struct_array_3_f32(); +} + +const Struct_array_4_f32 = extern struct { + a: [4]f32, +}; + +export fn zig_ret_struct_array_4_f32() Struct_array_4_f32 { + return .{ .a = .{ 1, 2, 3, 4 } }; +} +export fn zig_struct_array_4_f32(s: Struct_array_4_f32, i: usize) void { + expect(s.a[0] == 5) catch @panic("test failure"); + expect(s.a[1] == 6) catch @panic("test failure"); + expect(s.a[2] == 7) catch @panic("test failure"); + expect(s.a[3] == 8) catch @panic("test failure"); + expect(i == 9) catch @panic("test failure"); +} + +extern fn c_ret_struct_array_4_f32() Struct_array_4_f32; +extern fn c_struct_array_4_f32(Struct_array_4_f32, usize) void; +extern fn c_test_struct_array_4_f32() void; + +test "struct [4]f32" { + if (builtin.cpu.arch.isAARCH64()) return error.SkipZigTest; + if (builtin.cpu.arch.isArm()) return error.SkipZigTest; + if (builtin.cpu.arch == .hexagon) return error.SkipZigTest; + if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; + + const s = c_ret_struct_array_4_f32(); + try expect(s.a[0] == 10); + try expect(s.a[1] == 11); + try expect(s.a[2] == 12); + try expect(s.a[3] == 13); + c_struct_array_4_f32(.{ .a = .{ 14, 15, 16, 17 } }, 18); + c_test_struct_array_4_f32(); +} + +const Struct_array_5_f32 = extern struct { + a: [5]f32, +}; + +export fn zig_ret_struct_array_5_f32() Struct_array_5_f32 { + return .{ .a = .{ 1, 2, 3, 4, 5 } }; +} +export fn zig_struct_array_5_f32(s: Struct_array_5_f32, i: usize) void { + expect(s.a[0] == 6) catch @panic("test failure"); + expect(s.a[1] == 7) catch @panic("test failure"); + expect(s.a[2] == 8) catch @panic("test failure"); + expect(s.a[3] == 9) catch @panic("test failure"); + expect(s.a[4] == 10) catch @panic("test failure"); + expect(i == 11) catch @panic("test failure"); +} + +extern fn c_ret_struct_array_5_f32() Struct_array_5_f32; +extern fn c_struct_array_5_f32(Struct_array_5_f32, usize) void; +extern fn c_test_struct_array_5_f32() void; + +test "struct [5]f32" { + if (builtin.cpu.arch.isArm()) return error.SkipZigTest; + if (builtin.cpu.arch == .hexagon) return error.SkipZigTest; + if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; + + const s = c_ret_struct_array_5_f32(); + try expect(s.a[0] == 12); + try expect(s.a[1] == 13); + try expect(s.a[2] == 14); + try expect(s.a[3] == 15); + try expect(s.a[4] == 16); + c_struct_array_5_f32(.{ .a = .{ 17, 18, 19, 20, 21 } }, 22); + c_test_struct_array_5_f32(); +} + const Struct_f32a8 = extern struct { a: f32 align(8), }; @@ -16382,6 +16557,181 @@ test "struct f64, f64, f64, f64, f64" { c_test_struct_f64_f64_f64_f64_f64(); } +const Struct_array_1_f64 = extern struct { + a: [1]f64, +}; + +comptime { + skip: { + if (builtin.cpu.arch.isWasm()) break :skip; + + _ = struct { + export fn zig_ret_struct_array_1_f64() Struct_array_1_f64 { + return .{ .a = .{1} }; + } + export fn zig_struct_array_1_f64(s: Struct_array_1_f64, i: usize) void { + expect(s.a[0] == 2) catch @panic("test failure"); + expect(i == 3) catch @panic("test failure"); + } + }; + } +} + +extern fn c_ret_struct_array_1_f64() Struct_array_1_f64; +extern fn c_struct_array_1_f64(Struct_array_1_f64, usize) void; +extern fn c_test_struct_array_1_f64() void; + +test "struct [1]f64" { + if (builtin.cpu.arch.isAARCH64()) return error.SkipZigTest; + if (builtin.cpu.arch.isArm()) return error.SkipZigTest; + if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; + if (builtin.cpu.arch.isRISCV()) return error.SkipZigTest; + if (builtin.cpu.arch == .s390x) return error.SkipZigTest; + if (builtin.cpu.arch.isWasm()) return error.SkipZigTest; + + const s = c_ret_struct_array_1_f64(); + try expect(s.a[0] == 4); + c_struct_array_1_f64(.{ .a = .{5} }, 6); + c_test_struct_array_1_f64(); +} + +const Struct_array_2_f64 = extern struct { + a: [2]f64, +}; + +export fn zig_ret_struct_array_2_f64() Struct_array_2_f64 { + return .{ .a = .{ 1, 2 } }; +} +export fn zig_struct_array_2_f64(s: Struct_array_2_f64, i: usize) void { + expect(s.a[0] == 3) catch @panic("test failure"); + expect(s.a[1] == 4) catch @panic("test failure"); + expect(i == 5) catch @panic("test failure"); +} + +extern fn c_ret_struct_array_2_f64() Struct_array_2_f64; +extern fn c_struct_array_2_f64(Struct_array_2_f64, usize) void; +extern fn c_test_struct_array_2_f64() void; + +test "struct [2]f64" { + if (builtin.cpu.arch.isAARCH64()) return error.SkipZigTest; + if (builtin.cpu.arch.isArm()) return error.SkipZigTest; + if (builtin.cpu.arch == .hexagon) return error.SkipZigTest; + if (builtin.cpu.arch == .loongarch64 and builtin.abi.float() == .hard) return error.SkipZigTest; + if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; + if (builtin.cpu.arch.isRISCV()) return error.SkipZigTest; + + const s = c_ret_struct_array_2_f64(); + try expect(s.a[0] == 6); + try expect(s.a[1] == 7); + c_struct_array_2_f64(.{ .a = .{ 8, 9 } }, 10); + c_test_struct_array_2_f64(); +} + +const Struct_array_3_f64 = extern struct { + a: [3]f64, +}; + +export fn zig_ret_struct_array_3_f64() Struct_array_3_f64 { + return .{ .a = .{ 1, 2, 3 } }; +} +export fn zig_struct_array_3_f64(s: Struct_array_3_f64, i: usize) void { + expect(s.a[0] == 4) catch @panic("test failure"); + expect(s.a[1] == 5) catch @panic("test failure"); + expect(s.a[2] == 6) catch @panic("test failure"); + expect(i == 7) catch @panic("test failure"); +} + +extern fn c_ret_struct_array_3_f64() Struct_array_3_f64; +extern fn c_struct_array_3_f64(Struct_array_3_f64, usize) void; +extern fn c_test_struct_array_3_f64() void; + +test "struct [3]f64" { + if (builtin.cpu.arch.isAARCH64()) return error.SkipZigTest; + if (builtin.cpu.arch.isArm()) return error.SkipZigTest; + if (builtin.cpu.arch == .hexagon) return error.SkipZigTest; + if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; + + const s = c_ret_struct_array_3_f64(); + try expect(s.a[0] == 8); + try expect(s.a[1] == 9); + try expect(s.a[2] == 10); + c_struct_array_3_f64(.{ .a = .{ 11, 12, 13 } }, 14); + c_test_struct_array_3_f64(); +} + +const Struct_array_4_f64 = extern struct { + a: [4]f64, +}; + +export fn zig_ret_struct_array_4_f64() Struct_array_4_f64 { + return .{ .a = .{ 1, 2, 3, 4 } }; +} +export fn zig_struct_array_4_f64(s: Struct_array_4_f64, i: usize) void { + expect(s.a[0] == 5) catch @panic("test failure"); + expect(s.a[1] == 6) catch @panic("test failure"); + expect(s.a[2] == 7) catch @panic("test failure"); + expect(s.a[3] == 8) catch @panic("test failure"); + expect(i == 9) catch @panic("test failure"); +} + +extern fn c_ret_struct_array_4_f64() Struct_array_4_f64; +extern fn c_struct_array_4_f64(Struct_array_4_f64, usize) void; +extern fn c_test_struct_array_4_f64() void; + +test "struct [4]f64" { + if (builtin.cpu.arch.isAARCH64()) return error.SkipZigTest; + if (builtin.cpu.arch.isArm()) return error.SkipZigTest; + if (builtin.cpu.arch == .hexagon) return error.SkipZigTest; + if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; + + const s = c_ret_struct_array_4_f64(); + try expect(s.a[0] == 10); + try expect(s.a[1] == 11); + try expect(s.a[2] == 12); + try expect(s.a[3] == 13); + c_struct_array_4_f64(.{ .a = .{ 14, 15, 16, 17 } }, 18); + c_test_struct_array_4_f64(); +} + +const Struct_array_5_f64 = extern struct { + a: [5]f64, +}; + +export fn zig_ret_struct_array_5_f64() Struct_array_5_f64 { + return .{ .a = .{ 1, 2, 3, 4, 5 } }; +} +export fn zig_struct_array_5_f64(s: Struct_array_5_f64, i: usize) void { + expect(s.a[0] == 6) catch @panic("test failure"); + expect(s.a[1] == 7) catch @panic("test failure"); + expect(s.a[2] == 8) catch @panic("test failure"); + expect(s.a[3] == 9) catch @panic("test failure"); + expect(s.a[4] == 10) catch @panic("test failure"); + expect(i == 11) catch @panic("test failure"); +} + +extern fn c_ret_struct_array_5_f64() Struct_array_5_f64; +extern fn c_struct_array_5_f64(Struct_array_5_f64, usize) void; +extern fn c_test_struct_array_5_f64() void; + +test "struct [5]f64" { + if (builtin.cpu.arch == .hexagon) return error.SkipZigTest; + if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; + + const s = c_ret_struct_array_5_f64(); + try expect(s.a[0] == 12); + try expect(s.a[1] == 13); + try expect(s.a[2] == 14); + try expect(s.a[3] == 15); + try expect(s.a[4] == 16); + c_struct_array_5_f64(.{ .a = .{ 17, 18, 19, 20, 21 } }, 22); + c_test_struct_array_5_f64(); +} + const Struct_u32_Union_u32_u32u32 = extern struct { a: u32, b: extern union {