diff --git a/src/codegen/loongarch/abi.zig b/src/codegen/loongarch/abi.zig index 09e42a7cb96731dbf0ee44b37ad74f0548a08c93..ba9b79d39d5be3d10e20176bc5574c9205df5ad7 100644 --- a/src/codegen/loongarch/abi.zig +++ b/src/codegen/loongarch/abi.zig @@ -95,7 +95,7 @@ const Classifier = struct { var class: Class = .ignored; const elem_ty = ty.childType(c.zcu); const elem_class = c.classifyType(elem_ty); - for (0..std.math.lossyCast(usize, ty.arrayLen(c.zcu))) |_| { + for (0..std.math.lossyCast(usize, ty.arrayLenIncludingSentinel(c.zcu))) |_| { class = class.combineMember(elem_class, elem_ty); if (class == .address) break; } diff --git a/src/codegen/s390x/abi.zig b/src/codegen/s390x/abi.zig index 7b35245fdad37be5e062bbcc873c116a78a99152..f8c7864a4a313f54085b357a93f6d943ab72524e 100644 --- a/src/codegen/s390x/abi.zig +++ b/src/codegen/s390x/abi.zig @@ -45,7 +45,7 @@ pub fn classifyType(ty: Type, context: Context, zcu: *Zcu) Class { 128 => return .pointer, }, .pointer, .optional => return .simple, - .array => switch (ty.arrayLen(zcu)) { + .array => switch (ty.arrayLenIncludingSentinel(zcu)) { 0 => return .none, 1 => switch (context) { .ret => {}, diff --git a/src/codegen/x86_64/abi.zig b/src/codegen/x86_64/abi.zig index 3ebad4dee2a9235f641e12be27684d247bfd2de1..471c09974d6bd29a29fb0fd37bd1b7e7612088b7 100644 --- a/src/codegen/x86_64/abi.zig +++ b/src/codegen/x86_64/abi.zig @@ -443,7 +443,7 @@ fn classifySystemVArray( 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 (0..@intCast(array_ty.arrayLenIncludingSentinel(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; diff --git a/test/c_abi/cfuncs.c b/test/c_abi/cfuncs.c index b74ea9ffef180944eb00c919dd5a6513fa6d32ad..a259e23413a131b4e73b5f34329e1b2e6093f44d 100644 --- a/test/c_abi/cfuncs.c +++ b/test/c_abi/cfuncs.c @@ -15314,6 +15314,106 @@ void c_test_struct_array_5_f32(void) { zig_struct_array_5_f32((struct Struct_array_5_f32){ .a = { 6, 7, 8, 9, 10 } }, 11); } +struct Struct_array_1_f32 zig_ret_struct_array_0_sentinel_f32(void); +void zig_struct_array_0_sentinel_f32(struct Struct_array_1_f32, size_t); + +struct Struct_array_1_f32 c_ret_struct_array_0_sentinel_f32(void) { + return (struct Struct_array_1_f32){ .a = { 0x1e1 } }; +} +void c_struct_array_0_sentinel_f32(struct Struct_array_1_f32 s, size_t i) { + assert_or_panic(s.a[0] == 0x1e1); + assert_or_panic(i == 2); +} +void c_test_struct_array_0_sentinel_f32(void) { + struct Struct_array_1_f32 s = zig_ret_struct_array_0_sentinel_f32(); + assert_or_panic(s.a[0] == 0x1e1); + zig_struct_array_0_sentinel_f32((struct Struct_array_1_f32){ .a = { 0x1e1 } }, 1); +} + +struct Struct_array_2_f32 zig_ret_struct_array_1_sentinel_f32(void); +void zig_struct_array_1_sentinel_f32(struct Struct_array_2_f32, size_t); + +struct Struct_array_2_f32 c_ret_struct_array_1_sentinel_f32(void) { + return (struct Struct_array_2_f32){ .a = { 4, 0x1e1 } }; +} +void c_struct_array_1_sentinel_f32(struct Struct_array_2_f32 s, size_t i) { + assert_or_panic(s.a[0] == 5); + assert_or_panic(s.a[1] == 0x1e1); + assert_or_panic(i == 6); +} +void c_test_struct_array_1_sentinel_f32(void) { + struct Struct_array_2_f32 s = zig_ret_struct_array_1_sentinel_f32(); + assert_or_panic(s.a[0] == 1); + assert_or_panic(s.a[1] == 0x1e1); + zig_struct_array_1_sentinel_f32((struct Struct_array_2_f32){ .a = { 2, 0x1e1 } }, 3); +} + +struct Struct_array_3_f32 zig_ret_struct_array_2_sentinel_f32(void); +void zig_struct_array_2_sentinel_f32(struct Struct_array_3_f32, size_t); + +struct Struct_array_3_f32 c_ret_struct_array_2_sentinel_f32(void) { + return (struct Struct_array_3_f32){ .a = { 6, 7, 0x1e1 } }; +} +void c_struct_array_2_sentinel_f32(struct Struct_array_3_f32 s, size_t i) { + assert_or_panic(s.a[0] == 8); + assert_or_panic(s.a[1] == 9); + assert_or_panic(s.a[2] == 0x1e1); + assert_or_panic(i == 10); +} +void c_test_struct_array_2_sentinel_f32(void) { + struct Struct_array_3_f32 s = zig_ret_struct_array_2_sentinel_f32(); + assert_or_panic(s.a[0] == 1); + assert_or_panic(s.a[1] == 2); + assert_or_panic(s.a[2] == 0x1e1); + zig_struct_array_2_sentinel_f32((struct Struct_array_3_f32){ .a = { 3, 4, 0x1e1 } }, 5); +} + +struct Struct_array_4_f32 zig_ret_struct_array_3_sentinel_f32(void); +void zig_struct_array_3_sentinel_f32(struct Struct_array_4_f32, size_t); + +struct Struct_array_4_f32 c_ret_struct_array_3_sentinel_f32(void) { + return (struct Struct_array_4_f32){ .a = { 8, 9, 10, 0x1e1 } }; +} +void c_struct_array_3_sentinel_f32(struct Struct_array_4_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(s.a[3] == 0x1e1); + assert_or_panic(i == 14); +} +void c_test_struct_array_3_sentinel_f32(void) { + struct Struct_array_4_f32 s = zig_ret_struct_array_3_sentinel_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] == 0x1e1); + zig_struct_array_3_sentinel_f32((struct Struct_array_4_f32){ .a = { 4, 5, 6, 0x1e1 } }, 7); +} + +struct Struct_array_5_f32 zig_ret_struct_array_4_sentinel_f32(void); +void zig_struct_array_4_sentinel_f32(struct Struct_array_5_f32, size_t); + +struct Struct_array_5_f32 c_ret_struct_array_4_sentinel_f32(void) { + return (struct Struct_array_5_f32){ .a = { 10, 11, 12, 13, 0x1e1 } }; +} +void c_struct_array_4_sentinel_f32(struct Struct_array_5_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(s.a[4] == 0x1e1); + assert_or_panic(i == 18); +} +void c_test_struct_array_4_sentinel_f32(void) { + struct Struct_array_5_f32 s = zig_ret_struct_array_4_sentinel_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] == 0x1e1); + zig_struct_array_4_sentinel_f32((struct Struct_array_5_f32){ .a = { 5, 6, 7, 8, 0x1e1 } }, 9); +} + struct Struct_f32a8 { alignas(8) float a; }; diff --git a/test/c_abi/main.zig b/test/c_abi/main.zig index 1fd267402d74dbb38e524c8e232240ff97ef5217..15cb889467a794aaadd7ce08eb33523b4ec65885 100644 --- a/test/c_abi/main.zig +++ b/test/c_abi/main.zig @@ -16278,6 +16278,193 @@ test "struct [5]f32" { c_test_struct_array_5_f32(); } +const Struct_array_0_sentinel_f32 = extern struct { + a: [0:0x1e1]f32, +}; + +export fn zig_ret_struct_array_0_sentinel_f32() Struct_array_0_sentinel_f32 { + return .{ .a = .{} }; +} +export fn zig_struct_array_0_sentinel_f32(s: Struct_array_0_sentinel_f32, i: usize) void { + var sentinel_index: usize = 0; + _ = &sentinel_index; + expect(s.a[sentinel_index] == 0x1e1) catch @panic("test failure"); + expect(i == 1) catch @panic("test failure"); +} + +extern fn c_ret_struct_array_0_sentinel_f32() Struct_array_0_sentinel_f32; +extern fn c_struct_array_0_sentinel_f32(Struct_array_0_sentinel_f32, usize) void; +extern fn c_test_struct_array_0_sentinel_f32() void; + +test "struct [0:sentinel]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; + + var sentinel_index: usize = 0; + _ = &sentinel_index; + const s = c_ret_struct_array_0_sentinel_f32(); + try expect(s.a[sentinel_index] == 0x1e1); + c_struct_array_0_sentinel_f32(.{ .a = .{} }, 2); + c_test_struct_array_0_sentinel_f32(); +} + +const Struct_array_1_sentinel_f32 = extern struct { + a: [1:0x1e1]f32, +}; + +export fn zig_ret_struct_array_1_sentinel_f32() Struct_array_1_sentinel_f32 { + return .{ .a = .{1} }; +} +export fn zig_struct_array_1_sentinel_f32(s: Struct_array_1_sentinel_f32, i: usize) void { + var sentinel_index: usize = 1; + _ = &sentinel_index; + expect(s.a[0] == 2) catch @panic("test failure"); + expect(s.a[sentinel_index] == 0x1e1) catch @panic("test failure"); + expect(i == 3) catch @panic("test failure"); +} + +extern fn c_ret_struct_array_1_sentinel_f32() Struct_array_1_sentinel_f32; +extern fn c_struct_array_1_sentinel_f32(Struct_array_1_sentinel_f32, usize) void; +extern fn c_test_struct_array_1_sentinel_f32() void; + +test "struct [1:sentinel]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; + + var sentinel_index: usize = 1; + _ = &sentinel_index; + const s = c_ret_struct_array_1_sentinel_f32(); + try expect(s.a[0] == 4); + try expect(s.a[sentinel_index] == 0x1e1); + c_struct_array_1_sentinel_f32(.{ .a = .{5} }, 6); + c_test_struct_array_1_sentinel_f32(); +} + +const Struct_array_2_sentinel_f32 = extern struct { + a: [2:0x1e1]f32, +}; + +export fn zig_ret_struct_array_2_sentinel_f32() Struct_array_2_sentinel_f32 { + return .{ .a = .{ 1, 2 } }; +} +export fn zig_struct_array_2_sentinel_f32(s: Struct_array_2_sentinel_f32, i: usize) void { + var sentinel_index: usize = 2; + _ = &sentinel_index; + expect(s.a[0] == 3) catch @panic("test failure"); + expect(s.a[1] == 4) catch @panic("test failure"); + expect(s.a[sentinel_index] == 0x1e1) catch @panic("test failure"); + expect(i == 5) catch @panic("test failure"); +} + +extern fn c_ret_struct_array_2_sentinel_f32() Struct_array_2_sentinel_f32; +extern fn c_struct_array_2_sentinel_f32(Struct_array_2_sentinel_f32, usize) void; +extern fn c_test_struct_array_2_sentinel_f32() void; + +test "struct [2:sentinel]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; + + var sentinel_index: usize = 2; + _ = &sentinel_index; + const s = c_ret_struct_array_2_sentinel_f32(); + try expect(s.a[0] == 6); + try expect(s.a[1] == 7); + try expect(s.a[sentinel_index] == 0x1e1); + c_struct_array_2_sentinel_f32(.{ .a = .{ 8, 9 } }, 10); + c_test_struct_array_2_sentinel_f32(); +} + +const Struct_array_3_sentinel_f32 = extern struct { + a: [3:0x1e1]f32, +}; + +export fn zig_ret_struct_array_3_sentinel_f32() Struct_array_3_sentinel_f32 { + return .{ .a = .{ 1, 2, 3 } }; +} +export fn zig_struct_array_3_sentinel_f32(s: Struct_array_3_sentinel_f32, i: usize) void { + var sentinel_index: usize = 3; + _ = &sentinel_index; + 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(s.a[sentinel_index] == 0x1e1) catch @panic("test failure"); + expect(i == 7) catch @panic("test failure"); +} + +extern fn c_ret_struct_array_3_sentinel_f32() Struct_array_3_sentinel_f32; +extern fn c_struct_array_3_sentinel_f32(Struct_array_3_sentinel_f32, usize) void; +extern fn c_test_struct_array_3_sentinel_f32() void; + +test "struct [3:sentinel]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; + + var sentinel_index: usize = 3; + _ = &sentinel_index; + const s = c_ret_struct_array_3_sentinel_f32(); + try expect(s.a[0] == 8); + try expect(s.a[1] == 9); + try expect(s.a[2] == 10); + try expect(s.a[sentinel_index] == 0x1e1); + c_struct_array_3_sentinel_f32(.{ .a = .{ 11, 12, 13 } }, 14); + c_test_struct_array_3_sentinel_f32(); +} + +const Struct_array_4_sentinel_f32 = extern struct { + a: [4:0x1e1]f32, +}; + +export fn zig_ret_struct_array_4_sentinel_f32() Struct_array_4_sentinel_f32 { + return .{ .a = .{ 1, 2, 3, 4 } }; +} +export fn zig_struct_array_4_sentinel_f32(s: Struct_array_4_sentinel_f32, i: usize) void { + var sentinel_index: usize = 4; + _ = &sentinel_index; + 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(s.a[sentinel_index] == 0x1e1) catch @panic("test failure"); + expect(i == 9) catch @panic("test failure"); +} + +extern fn c_ret_struct_array_4_sentinel_f32() Struct_array_4_sentinel_f32; +extern fn c_struct_array_4_sentinel_f32(Struct_array_4_sentinel_f32, usize) void; +extern fn c_test_struct_array_4_sentinel_f32() void; + +test "struct [4:sentinel]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; + + var sentinel_index: usize = 4; + _ = &sentinel_index; + const s = c_ret_struct_array_4_sentinel_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); + try expect(s.a[sentinel_index] == 0x1e1); + c_struct_array_4_sentinel_f32(.{ .a = .{ 14, 15, 16, 17 } }, 18); + c_test_struct_array_4_sentinel_f32(); +} + const Struct_f32a8 = extern struct { a: f32 align(8), };