| author | |
| committer | |
| log | bde6e075dfc202fdcfa21ec9c2d90941460b002e |
| tree | fa782eaf75c76e5d7ab09ce6af58061c8e688df4 |
| parent | 423c1221f9c020a1047fc14ce8e9003d7e009914 |
| parent | 97ae2d2c29f827ebb73abbc0317cd39ac4ca4c9b |
| signature |
Fix various C ABI issues8 files changed, 143 insertions(+), 26 deletions(-)
src/Sema.zig+3-1| ... | ... | @@ -33491,7 +33491,9 @@ fn resolveStructLayout(sema: *Sema, ty: Type) CompileError!void { |
| 33491 | 33491 | return sema.failWithOwnedErrorMsg(msg); |
| 33492 | 33492 | } |
| 33493 | 33493 | |
| 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 | { | |
| 33495 | 33497 | const optimized_order = try mod.tmp_hack_arena.allocator().alloc(u32, struct_obj.fields.count()); |
| 33496 | 33498 | |
| 33497 | 33499 | for (struct_obj.fields.values(), 0..) |field, i| { |
src/codegen/llvm.zig+32-9| ... | ... | @@ -5421,10 +5421,13 @@ pub const FuncGen = struct { |
| 5421 | 5421 | // In this case the function return type is honoring the calling convention by having |
| 5422 | 5422 | // a different LLVM type than the usual one. We solve this here at the callsite |
| 5423 | 5423 | // by using our canonical type, then loading it if necessary. |
| 5424 | const alignment = Builder.Alignment.fromByteUnits( | |
| 5424 | const alignment = Builder.Alignment.fromByteUnits(@max( | |
| 5425 | 5425 | 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); | |
| 5428 | 5431 | _ = try self.wip.store(.normal, call, rp, alignment); |
| 5429 | 5432 | return if (isByRef(return_type, mod)) |
| 5430 | 5433 | rp |
| ... | ... | @@ -11555,8 +11558,17 @@ fn lowerSystemVFnRetTy(o: *Object, fn_info: InternPool.Key.FuncType) Allocator.E |
| 11555 | 11558 | .none => break, |
| 11556 | 11559 | } |
| 11557 | 11560 | } |
| 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]; | |
| 11560 | 11572 | } |
| 11561 | 11573 | return o.builder.structType(.normal, types_buffer[0..types_index]); |
| 11562 | 11574 | } |
| ... | ... | @@ -11807,10 +11819,21 @@ const ParamTypeIterator = struct { |
| 11807 | 11819 | .none => break, |
| 11808 | 11820 | } |
| 11809 | 11821 | } |
| 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 | } | |
| 11814 | 11837 | } |
| 11815 | 11838 | it.types_len = types_index; |
| 11816 | 11839 | it.types_buffer = types_buffer; |
src/codegen/llvm/Builder.zig+3-1| ... | ... | @@ -572,7 +572,9 @@ pub const Type = enum(u32) { |
| 572 | 572 | |
| 573 | 573 | pub fn isSized(self: Type, builder: *const Builder) Allocator.Error!bool { |
| 574 | 574 | 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; | |
| 576 | 578 | } |
| 577 | 579 | |
| 578 | 580 | const FormatData = struct { |
src/codegen/llvm/bindings.zig+3| ... | ... | @@ -434,6 +434,9 @@ pub const Type = opaque { |
| 434 | 434 | Packed: Bool, |
| 435 | 435 | ) void; |
| 436 | 436 | |
| 437 | pub const isSized = LLVMTypeIsSized; | |
| 438 | extern fn LLVMTypeIsSized(Ty: *Type) Bool; | |
| 439 | ||
| 437 | 440 | pub const constGEP = LLVMConstGEP2; |
| 438 | 441 | extern fn LLVMConstGEP2( |
| 439 | 442 | Ty: *Type, |
test/behavior/tuple.zig+15| ... | ... | @@ -453,3 +453,18 @@ test "tuple pointer is indexable" { |
| 453 | 453 | try expectEqual(@as(u32, 100), (&y)[0]); |
| 454 | 454 | try expectEqual(false, (&y)[1]); |
| 455 | 455 | } |
| 456 | ||
| 457 | test "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) { |
| 16 | 16 | # define ZIG_PPC32 |
| 17 | 17 | #endif |
| 18 | 18 | |
| 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 | |
| 21 | 25 | #endif |
| 22 | 26 | |
| 23 | 27 | #if defined(__aarch64__) && defined(__linux__) |
| ... | ... | @@ -191,6 +195,15 @@ struct SmallStructInts { |
| 191 | 195 | void zig_small_struct_ints(struct SmallStructInts); |
| 192 | 196 | struct SmallStructInts zig_ret_small_struct_ints(); |
| 193 | 197 | |
| 198 | struct MedStructInts { | |
| 199 | int32_t x; | |
| 200 | int32_t y; | |
| 201 | int32_t z; | |
| 202 | }; | |
| 203 | ||
| 204 | void zig_med_struct_ints(struct MedStructInts); | |
| 205 | struct MedStructInts zig_ret_med_struct_ints(); | |
| 206 | ||
| 194 | 207 | struct MedStructMixed { |
| 195 | 208 | uint32_t a; |
| 196 | 209 | float b; |
| ... | ... | @@ -339,14 +352,22 @@ void run_c_tests(void) { |
| 339 | 352 | } |
| 340 | 353 | #endif |
| 341 | 354 | |
| 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 | |
| 344 | 357 | { |
| 345 | 358 | struct SmallStructInts s = {1, 2, 3, 4}; |
| 346 | 359 | zig_small_struct_ints(s); |
| 347 | 360 | } |
| 348 | 361 | #endif |
| 349 | 362 | |
| 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 | ||
| 350 | 371 | #ifndef ZIG_NO_I128 |
| 351 | 372 | { |
| 352 | 373 | __int128 s = 0; |
| ... | ... | @@ -586,6 +607,27 @@ struct SmallStructInts c_ret_small_struct_ints() { |
| 586 | 607 | return s; |
| 587 | 608 | } |
| 588 | 609 | |
| 610 | void 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 | ||
| 622 | struct 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 | ||
| 589 | 631 | void c_med_struct_mixed(struct MedStructMixed x) { |
| 590 | 632 | assert_or_panic(x.a == 1234); |
| 591 | 633 | 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 { |
| 393 | 393 | expect(x.d == 4) catch @panic("test failure"); |
| 394 | 394 | } |
| 395 | 395 | |
| 396 | const MedStructInts = extern struct { | |
| 397 | x: i32, | |
| 398 | y: i32, | |
| 399 | z: i32, | |
| 400 | }; | |
| 401 | extern fn c_med_struct_ints(MedStructInts) void; | |
| 402 | extern fn c_ret_med_struct_ints() MedStructInts; | |
| 403 | ||
| 404 | test "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 | ||
| 422 | export 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 | ||
| 396 | 428 | const SmallPackedStruct = packed struct { |
| 397 | 429 | a: u2, |
| 398 | 430 | b: u2, |
| ... | ... | @@ -691,6 +723,14 @@ export fn zig_ret_small_struct_ints() SmallStructInts { |
| 691 | 723 | }; |
| 692 | 724 | } |
| 693 | 725 | |
| 726 | export fn zig_ret_med_struct_ints() MedStructInts { | |
| 727 | return .{ | |
| 728 | .x = 1, | |
| 729 | .y = 2, | |
| 730 | .z = 3, | |
| 731 | }; | |
| 732 | } | |
| 733 | ||
| 694 | 734 | export fn zig_ret_med_struct_mixed() MedStructMixed { |
| 695 | 735 | return .{ |
| 696 | 736 | .a = 1234, |
| ... | ... | @@ -813,11 +853,6 @@ extern fn c_ret_medium_vec() MediumVec; |
| 813 | 853 | test "medium simd vector" { |
| 814 | 854 | if (comptime builtin.cpu.arch.isPPC64()) return error.SkipZigTest; |
| 815 | 855 | |
| 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 | ||
| 821 | 856 | c_medium_vec(.{ 1, 2, 3, 4 }); |
| 822 | 857 | |
| 823 | 858 | var x = c_ret_medium_vec(); |
| ... | ... | @@ -837,11 +872,6 @@ test "big simd vector" { |
| 837 | 872 | if (comptime builtin.cpu.arch.isPPC64()) return error.SkipZigTest; |
| 838 | 873 | if (builtin.cpu.arch == .x86_64 and builtin.os.tag == .macos and builtin.mode != .Debug) return error.SkipZigTest; |
| 839 | 874 | |
| 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 | ||
| 845 | 875 | c_big_vec(.{ 1, 2, 3, 4, 5, 6, 7, 8 }); |
| 846 | 876 | |
| 847 | 877 | var x = c_ret_big_vec(); |
test/tests.zig+1-1| ... | ... | @@ -1102,7 +1102,7 @@ pub fn addModuleTests(b: *std.Build, options: ModuleTestOptions) *Step { |
| 1102 | 1102 | pub fn addCAbiTests(b: *std.Build, skip_non_native: bool, skip_release: bool) *Step { |
| 1103 | 1103 | const step = b.step("test-c-abi", "Run the C ABI tests"); |
| 1104 | 1104 | |
| 1105 | const optimize_modes: [2]OptimizeMode = .{ .Debug, .ReleaseFast }; | |
| 1105 | const optimize_modes: [3]OptimizeMode = .{ .Debug, .ReleaseSafe, .ReleaseFast }; | |
| 1106 | 1106 | |
| 1107 | 1107 | for (optimize_modes) |optimize_mode| { |
| 1108 | 1108 | if (optimize_mode != .Debug and skip_release) continue; |