authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-07-28 19:27:43-07:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2023-07-28 19:27:43-07:00
logbde6e075dfc202fdcfa21ec9c2d90941460b002e
treefa782eaf75c76e5d7ab09ce6af58061c8e688df4
parent423c1221f9c020a1047fc14ce8e9003d7e009914
parent97ae2d2c29f827ebb73abbc0317cd39ac4ca4c9b
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #16593 from jacobly0/c-abi

Fix various C ABI issues

8 files changed, 143 insertions(+), 26 deletions(-)

src/Sema.zig+3-1
......@@ -33491,7 +33491,9 @@ fn resolveStructLayout(sema: *Sema, ty: Type) CompileError!void {
3349133491 return sema.failWithOwnedErrorMsg(msg);
3349233492 }
3349333493
33494 if (struct_obj.layout == .Auto and mod.backendSupportsFeature(.field_reordering)) {
33494 if (struct_obj.layout == .Auto and !struct_obj.is_tuple and
33495 mod.backendSupportsFeature(.field_reordering))
33496 {
3349533497 const optimized_order = try mod.tmp_hack_arena.allocator().alloc(u32, struct_obj.fields.count());
3349633498
3349733499 for (struct_obj.fields.values(), 0..) |field, i| {
src/codegen/llvm.zig+32-9
......@@ -5421,10 +5421,13 @@ pub const FuncGen = struct {
54215421 // In this case the function return type is honoring the calling convention by having
54225422 // a different LLVM type than the usual one. We solve this here at the callsite
54235423 // by using our canonical type, then loading it if necessary.
5424 const alignment = Builder.Alignment.fromByteUnits(
5424 const alignment = Builder.Alignment.fromByteUnits(@max(
54255425 o.target_data.abiAlignmentOfType(abi_ret_ty.toLlvm(&o.builder)),
5426 );
5427 const rp = try self.buildAlloca(llvm_ret_ty, alignment);
5426 return_type.abiAlignment(mod),
5427 ));
5428 assert(o.target_data.abiSizeOfType(abi_ret_ty.toLlvm(&o.builder)) >=
5429 o.target_data.abiSizeOfType(llvm_ret_ty.toLlvm(&o.builder)));
5430 const rp = try self.buildAlloca(abi_ret_ty, alignment);
54285431 _ = try self.wip.store(.normal, call, rp, alignment);
54295432 return if (isByRef(return_type, mod))
54305433 rp
......@@ -11555,8 +11558,17 @@ fn lowerSystemVFnRetTy(o: *Object, fn_info: InternPool.Key.FuncType) Allocator.E
1155511558 .none => break,
1155611559 }
1155711560 }
11558 if (classes[0] == .integer and classes[1] == .none) {
11559 return o.builder.intType(@intCast(return_type.abiSize(mod) * 8));
11561 const first_non_integer = std.mem.indexOfNone(x86_64_abi.Class, &classes, &.{.integer});
11562 if (first_non_integer == null or classes[first_non_integer.?] == .none) {
11563 assert(first_non_integer orelse classes.len == types_index);
11564 if (mod.intern_pool.indexToKey(return_type.toIntern()) == .struct_type) {
11565 var struct_it = return_type.iterateStructOffsets(mod);
11566 while (struct_it.next()) |_| {}
11567 assert((std.math.divCeil(u64, struct_it.offset, 8) catch unreachable) == types_index);
11568 if (struct_it.offset % 8 > 0) types_buffer[types_index - 1] =
11569 try o.builder.intType(@intCast(struct_it.offset % 8 * 8));
11570 }
11571 if (types_index == 1) return types_buffer[0];
1156011572 }
1156111573 return o.builder.structType(.normal, types_buffer[0..types_index]);
1156211574}
......@@ -11807,10 +11819,21 @@ const ParamTypeIterator = struct {
1180711819 .none => break,
1180811820 }
1180911821 }
11810 if (classes[0] == .integer and classes[1] == .none) {
11811 it.zig_index += 1;
11812 it.llvm_index += 1;
11813 return .abi_sized_int;
11822 const first_non_integer = std.mem.indexOfNone(x86_64_abi.Class, &classes, &.{.integer});
11823 if (first_non_integer == null or classes[first_non_integer.?] == .none) {
11824 assert(first_non_integer orelse classes.len == types_index);
11825 if (types_index == 1) {
11826 it.zig_index += 1;
11827 it.llvm_index += 1;
11828 return .abi_sized_int;
11829 }
11830 if (mod.intern_pool.indexToKey(ty.toIntern()) == .struct_type) {
11831 var struct_it = ty.iterateStructOffsets(mod);
11832 while (struct_it.next()) |_| {}
11833 assert((std.math.divCeil(u64, struct_it.offset, 8) catch unreachable) == types_index);
11834 if (struct_it.offset % 8 > 0) types_buffer[types_index - 1] =
11835 try it.object.builder.intType(@intCast(struct_it.offset % 8 * 8));
11836 }
1181411837 }
1181511838 it.types_len = types_index;
1181611839 it.types_buffer = types_buffer;
src/codegen/llvm/Builder.zig+3-1
......@@ -572,7 +572,9 @@ pub const Type = enum(u32) {
572572
573573 pub fn isSized(self: Type, builder: *const Builder) Allocator.Error!bool {
574574 var visited: IsSizedVisited = .{};
575 return self.isSizedVisited(&visited, builder);
575 const result = try self.isSizedVisited(&visited, builder);
576 if (builder.useLibLlvm()) assert(result == self.toLlvm(builder).isSized().toBool());
577 return result;
576578 }
577579
578580 const FormatData = struct {
src/codegen/llvm/bindings.zig+3
......@@ -434,6 +434,9 @@ pub const Type = opaque {
434434 Packed: Bool,
435435 ) void;
436436
437 pub const isSized = LLVMTypeIsSized;
438 extern fn LLVMTypeIsSized(Ty: *Type) Bool;
439
437440 pub const constGEP = LLVMConstGEP2;
438441 extern fn LLVMConstGEP2(
439442 Ty: *Type,
test/behavior/tuple.zig+15
......@@ -453,3 +453,18 @@ test "tuple pointer is indexable" {
453453 try expectEqual(@as(u32, 100), (&y)[0]);
454454 try expectEqual(false, (&y)[1]);
455455}
456
457test "coerce anon tuple to tuple" {
458 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
459 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
460 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
461 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; // TODO
462 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
463
464 var x: u8 = 1;
465 var y: u16 = 2;
466 var t = .{ x, y };
467 var s: struct { u8, u16 } = t;
468 try expectEqual(x, s[0]);
469 try expectEqual(y, s[1]);
470}
test/c_abi/cfuncs.c+46-4
......@@ -16,8 +16,12 @@ static void assert_or_panic(bool ok) {
1616# define ZIG_PPC32
1717#endif
1818
19#if defined __riscv && defined _ILP32
20# define ZIG_RISCV32
19#ifdef __riscv
20# ifdef _ILP32
21# define ZIG_RISCV32
22# else
23# define ZIG_RISCV64
24# endif
2125#endif
2226
2327#if defined(__aarch64__) && defined(__linux__)
......@@ -191,6 +195,15 @@ struct SmallStructInts {
191195void zig_small_struct_ints(struct SmallStructInts);
192196struct SmallStructInts zig_ret_small_struct_ints();
193197
198struct MedStructInts {
199 int32_t x;
200 int32_t y;
201 int32_t z;
202};
203
204void zig_med_struct_ints(struct MedStructInts);
205struct MedStructInts zig_ret_med_struct_ints();
206
194207struct MedStructMixed {
195208 uint32_t a;
196209 float b;
......@@ -339,14 +352,22 @@ void run_c_tests(void) {
339352 }
340353#endif
341354
342#if !defined __i386__ && !defined __arm__ && !defined __mips__ && \
343 !defined ZIG_PPC32 && !defined _ARCH_PPC64
355#if !defined __i386__ && !defined __arm__ && !defined __aarch64__ && \
356 !defined __mips__ && !defined __powerpc__ && !defined ZIG_RISCV64
344357 {
345358 struct SmallStructInts s = {1, 2, 3, 4};
346359 zig_small_struct_ints(s);
347360 }
348361#endif
349362
363#if !defined __i386__ && !defined __arm__ && !defined __aarch64__ && \
364 !defined __mips__ && !defined __powerpc__ && !defined ZIG_RISCV64
365 {
366 struct MedStructInts s = {1, 2, 3};
367 zig_med_struct_ints(s);
368 }
369#endif
370
350371#ifndef ZIG_NO_I128
351372 {
352373 __int128 s = 0;
......@@ -586,6 +607,27 @@ struct SmallStructInts c_ret_small_struct_ints() {
586607 return s;
587608}
588609
610void c_med_struct_ints(struct MedStructInts s) {
611 assert_or_panic(s.x == 1);
612 assert_or_panic(s.y == 2);
613 assert_or_panic(s.z == 3);
614
615 struct MedStructInts s2 = zig_ret_med_struct_ints();
616
617 assert_or_panic(s2.x == 1);
618 assert_or_panic(s2.y == 2);
619 assert_or_panic(s2.z == 3);
620}
621
622struct MedStructInts c_ret_med_struct_ints() {
623 struct MedStructInts s = {
624 .x = 1,
625 .y = 2,
626 .z = 3,
627 };
628 return s;
629}
630
589631void c_med_struct_mixed(struct MedStructMixed x) {
590632 assert_or_panic(x.a == 1234);
591633 assert_or_panic(x.b == 100.0f);
test/c_abi/main.zig+40-10
......@@ -393,6 +393,38 @@ export fn zig_small_struct_ints(x: SmallStructInts) void {
393393 expect(x.d == 4) catch @panic("test failure");
394394}
395395
396const MedStructInts = extern struct {
397 x: i32,
398 y: i32,
399 z: i32,
400};
401extern fn c_med_struct_ints(MedStructInts) void;
402extern fn c_ret_med_struct_ints() MedStructInts;
403
404test "C ABI medium struct of ints" {
405 if (builtin.cpu.arch == .x86) return error.SkipZigTest;
406 if (comptime builtin.cpu.arch.isMIPS()) return error.SkipZigTest;
407 if (comptime builtin.cpu.arch.isPPC()) return error.SkipZigTest;
408 if (comptime builtin.cpu.arch.isPPC64()) return error.SkipZigTest;
409
410 var s = MedStructInts{
411 .x = 1,
412 .y = 2,
413 .z = 3,
414 };
415 c_med_struct_ints(s);
416 var s2 = c_ret_med_struct_ints();
417 try expect(s2.x == 1);
418 try expect(s2.y == 2);
419 try expect(s2.z == 3);
420}
421
422export fn zig_med_struct_ints(s: MedStructInts) void {
423 expect(s.x == 1) catch @panic("test failure");
424 expect(s.y == 2) catch @panic("test failure");
425 expect(s.z == 3) catch @panic("test failure");
426}
427
396428const SmallPackedStruct = packed struct {
397429 a: u2,
398430 b: u2,
......@@ -691,6 +723,14 @@ export fn zig_ret_small_struct_ints() SmallStructInts {
691723 };
692724}
693725
726export fn zig_ret_med_struct_ints() MedStructInts {
727 return .{
728 .x = 1,
729 .y = 2,
730 .z = 3,
731 };
732}
733
694734export fn zig_ret_med_struct_mixed() MedStructMixed {
695735 return .{
696736 .a = 1234,
......@@ -813,11 +853,6 @@ extern fn c_ret_medium_vec() MediumVec;
813853test "medium simd vector" {
814854 if (comptime builtin.cpu.arch.isPPC64()) return error.SkipZigTest;
815855
816 if (builtin.cpu.arch == .x86_64 and builtin.os.tag == .linux) {
817 // TODO: https://github.com/ziglang/zig/issues/14908
818 return error.SkipZigTest;
819 }
820
821856 c_medium_vec(.{ 1, 2, 3, 4 });
822857
823858 var x = c_ret_medium_vec();
......@@ -837,11 +872,6 @@ test "big simd vector" {
837872 if (comptime builtin.cpu.arch.isPPC64()) return error.SkipZigTest;
838873 if (builtin.cpu.arch == .x86_64 and builtin.os.tag == .macos and builtin.mode != .Debug) return error.SkipZigTest;
839874
840 if (builtin.cpu.arch == .x86_64 and builtin.os.tag == .linux) {
841 // TODO: https://github.com/ziglang/zig/issues/14908
842 return error.SkipZigTest;
843 }
844
845875 c_big_vec(.{ 1, 2, 3, 4, 5, 6, 7, 8 });
846876
847877 var x = c_ret_big_vec();
test/tests.zig+1-1
......@@ -1102,7 +1102,7 @@ pub fn addModuleTests(b: *std.Build, options: ModuleTestOptions) *Step {
11021102pub fn addCAbiTests(b: *std.Build, skip_non_native: bool, skip_release: bool) *Step {
11031103 const step = b.step("test-c-abi", "Run the C ABI tests");
11041104
1105 const optimize_modes: [2]OptimizeMode = .{ .Debug, .ReleaseFast };
1105 const optimize_modes: [3]OptimizeMode = .{ .Debug, .ReleaseSafe, .ReleaseFast };
11061106
11071107 for (optimize_modes) |optimize_mode| {
11081108 if (optimize_mode != .Debug and skip_release) continue;