| author | |
| committer | |
| log | bb15e4057c9c8bb22084990de475ab10a44592c0 |
| tree | c1dcacddfc3ff184bd924405db0759ae2625280f |
| parent | 18191b80b6381eb41adb4354a243190865801212 |
| parent | 0013042cbd539cf7eb463483633e9f7aa2fa8067 |
| signature |
float related C ABI fixes6 files changed, 273 insertions(+), 25 deletions(-)
build.zig+1-1| ... | ... | @@ -440,7 +440,7 @@ pub fn build(b: *Builder) !void { |
| 440 | 440 | b.enable_wine, |
| 441 | 441 | enable_symlinks_windows, |
| 442 | 442 | )); |
| 443 | test_step.dependOn(tests.addCAbiTests(b, skip_non_native)); | |
| 443 | test_step.dependOn(tests.addCAbiTests(b, skip_non_native, skip_release)); | |
| 444 | 444 | test_step.dependOn(tests.addLinkTests(b, test_filter, modes, enable_macos_sdk, skip_stage2_tests, enable_symlinks_windows)); |
| 445 | 445 | test_step.dependOn(tests.addStackTraceTests(b, test_filter, modes)); |
| 446 | 446 | test_step.dependOn(tests.addCliTests(b, test_filter, modes)); |
src/arch/x86_64/abi.zig+36-3| ... | ... | @@ -5,7 +5,19 @@ const assert = std.debug.assert; |
| 5 | 5 | const Register = @import("bits.zig").Register; |
| 6 | 6 | const RegisterManagerFn = @import("../../register_manager.zig").RegisterManager; |
| 7 | 7 | |
| 8 | pub const Class = enum { integer, sse, sseup, x87, x87up, complex_x87, memory, none, win_i128 }; | |
| 8 | pub const Class = enum { | |
| 9 | integer, | |
| 10 | sse, | |
| 11 | sseup, | |
| 12 | x87, | |
| 13 | x87up, | |
| 14 | complex_x87, | |
| 15 | memory, | |
| 16 | none, | |
| 17 | win_i128, | |
| 18 | float, | |
| 19 | float_combine, | |
| 20 | }; | |
| 9 | 21 | |
| 10 | 22 | pub fn classifyWindows(ty: Type, target: Target) Class { |
| 11 | 23 | // https://docs.microsoft.com/en-gb/cpp/build/x64-calling-convention?view=vs-2017 |
| ... | ... | @@ -112,7 +124,20 @@ pub fn classifySystemV(ty: Type, target: Target, ctx: Context) [8]Class { |
| 112 | 124 | return result; |
| 113 | 125 | }, |
| 114 | 126 | .Float => switch (ty.floatBits(target)) { |
| 115 | 16, 32, 64 => { | |
| 127 | 16 => { | |
| 128 | if (ctx == .other) { | |
| 129 | result[0] = .memory; | |
| 130 | } else { | |
| 131 | // TODO clang doesn't allow __fp16 as .ret or .arg | |
| 132 | result[0] = .sse; | |
| 133 | } | |
| 134 | return result; | |
| 135 | }, | |
| 136 | 32 => { | |
| 137 | result[0] = .float; | |
| 138 | return result; | |
| 139 | }, | |
| 140 | 64 => { | |
| 116 | 141 | result[0] = .sse; |
| 117 | 142 | return result; |
| 118 | 143 | }, |
| ... | ... | @@ -120,11 +145,15 @@ pub fn classifySystemV(ty: Type, target: Target, ctx: Context) [8]Class { |
| 120 | 145 | // "Arguments of types__float128, _Decimal128 and__m128 are |
| 121 | 146 | // split into two halves. The least significant ones belong |
| 122 | 147 | // to class SSE, the most significant one to class SSEUP." |
| 148 | if (ctx == .other) { | |
| 149 | result[0] = .memory; | |
| 150 | return result; | |
| 151 | } | |
| 123 | 152 | result[0] = .sse; |
| 124 | 153 | result[1] = .sseup; |
| 125 | 154 | return result; |
| 126 | 155 | }, |
| 127 | else => { | |
| 156 | 80 => { | |
| 128 | 157 | // "The 64-bit mantissa of arguments of type long double |
| 129 | 158 | // belongs to classX87, the 16-bit exponent plus 6 bytes |
| 130 | 159 | // of padding belongs to class X87UP." |
| ... | ... | @@ -132,6 +161,7 @@ pub fn classifySystemV(ty: Type, target: Target, ctx: Context) [8]Class { |
| 132 | 161 | result[1] = .x87up; |
| 133 | 162 | return result; |
| 134 | 163 | }, |
| 164 | else => unreachable, | |
| 135 | 165 | }, |
| 136 | 166 | .Vector => { |
| 137 | 167 | const elem_ty = ty.childType(); |
| ... | ... | @@ -238,6 +268,9 @@ pub fn classifySystemV(ty: Type, target: Target, ctx: Context) [8]Class { |
| 238 | 268 | combine: { |
| 239 | 269 | // "If both classes are equal, this is the resulting class." |
| 240 | 270 | if (result[result_i] == field_class[0]) { |
| 271 | if (result[result_i] == .float) { | |
| 272 | result[result_i] = .float_combine; | |
| 273 | } | |
| 241 | 274 | break :combine; |
| 242 | 275 | } |
| 243 | 276 |
src/codegen/llvm.zig+27-15| ... | ... | @@ -10395,7 +10395,12 @@ fn firstParamSRet(fn_info: Type.Payload.Function.Data, target: std.Target) bool |
| 10395 | 10395 | .mips, .mipsel => return false, |
| 10396 | 10396 | .x86_64 => switch (target.os.tag) { |
| 10397 | 10397 | .windows => return x86_64_abi.classifyWindows(fn_info.return_type, target) == .memory, |
| 10398 | else => return x86_64_abi.classifySystemV(fn_info.return_type, target, .ret)[0] == .memory, | |
| 10398 | else => { | |
| 10399 | const class = x86_64_abi.classifySystemV(fn_info.return_type, target, .ret); | |
| 10400 | if (class[0] == .memory) return true; | |
| 10401 | if (class[0] == .x87 and class[2] != .none) return true; | |
| 10402 | return false; | |
| 10403 | }, | |
| 10399 | 10404 | }, |
| 10400 | 10405 | .wasm32 => return wasm_c_abi.classifyType(fn_info.return_type, target)[0] == .indirect, |
| 10401 | 10406 | .aarch64, .aarch64_be => return aarch64_c_abi.classifyType(fn_info.return_type, target) == .memory, |
| ... | ... | @@ -10469,22 +10474,26 @@ fn lowerFnRetTy(dg: *DeclGen, fn_info: Type.Payload.Function.Data) !*llvm.Type { |
| 10469 | 10474 | llvm_types_buffer[llvm_types_index] = dg.context.intType(64); |
| 10470 | 10475 | llvm_types_index += 1; |
| 10471 | 10476 | }, |
| 10472 | .sse => { | |
| 10477 | .sse, .sseup => { | |
| 10473 | 10478 | llvm_types_buffer[llvm_types_index] = dg.context.doubleType(); |
| 10474 | 10479 | llvm_types_index += 1; |
| 10475 | 10480 | }, |
| 10476 | .sseup => { | |
| 10477 | llvm_types_buffer[llvm_types_index] = dg.context.doubleType(); | |
| 10481 | .float => { | |
| 10482 | llvm_types_buffer[llvm_types_index] = dg.context.floatType(); | |
| 10478 | 10483 | llvm_types_index += 1; |
| 10479 | 10484 | }, |
| 10480 | .x87 => { | |
| 10481 | llvm_types_buffer[llvm_types_index] = dg.context.x86FP80Type(); | |
| 10485 | .float_combine => { | |
| 10486 | llvm_types_buffer[llvm_types_index] = dg.context.floatType().vectorType(2); | |
| 10482 | 10487 | llvm_types_index += 1; |
| 10483 | 10488 | }, |
| 10484 | .x87up => { | |
| 10489 | .x87 => { | |
| 10490 | if (llvm_types_index != 0 or classes[2] != .none) { | |
| 10491 | return dg.context.voidType(); | |
| 10492 | } | |
| 10485 | 10493 | llvm_types_buffer[llvm_types_index] = dg.context.x86FP80Type(); |
| 10486 | 10494 | llvm_types_index += 1; |
| 10487 | 10495 | }, |
| 10496 | .x87up => continue, | |
| 10488 | 10497 | .complex_x87 => { |
| 10489 | 10498 | @panic("TODO"); |
| 10490 | 10499 | }, |
| ... | ... | @@ -10689,22 +10698,25 @@ const ParamTypeIterator = struct { |
| 10689 | 10698 | llvm_types_buffer[llvm_types_index] = dg.context.intType(64); |
| 10690 | 10699 | llvm_types_index += 1; |
| 10691 | 10700 | }, |
| 10692 | .sse => { | |
| 10701 | .sse, .sseup => { | |
| 10693 | 10702 | llvm_types_buffer[llvm_types_index] = dg.context.doubleType(); |
| 10694 | 10703 | llvm_types_index += 1; |
| 10695 | 10704 | }, |
| 10696 | .sseup => { | |
| 10697 | llvm_types_buffer[llvm_types_index] = dg.context.doubleType(); | |
| 10705 | .float => { | |
| 10706 | llvm_types_buffer[llvm_types_index] = dg.context.floatType(); | |
| 10698 | 10707 | llvm_types_index += 1; |
| 10699 | 10708 | }, |
| 10700 | .x87 => { | |
| 10701 | llvm_types_buffer[llvm_types_index] = dg.context.x86FP80Type(); | |
| 10709 | .float_combine => { | |
| 10710 | llvm_types_buffer[llvm_types_index] = dg.context.floatType().vectorType(2); | |
| 10702 | 10711 | llvm_types_index += 1; |
| 10703 | 10712 | }, |
| 10704 | .x87up => { | |
| 10705 | llvm_types_buffer[llvm_types_index] = dg.context.x86FP80Type(); | |
| 10706 | llvm_types_index += 1; | |
| 10713 | .x87 => { | |
| 10714 | it.zig_index += 1; | |
| 10715 | it.llvm_index += 1; | |
| 10716 | it.byval_attr = true; | |
| 10717 | return .byref; | |
| 10707 | 10718 | }, |
| 10719 | .x87up => unreachable, | |
| 10708 | 10720 | .complex_x87 => { |
| 10709 | 10721 | @panic("TODO"); |
| 10710 | 10722 | }, |
test/c_abi/cfuncs.c+102-1| ... | ... | @@ -4,7 +4,7 @@ |
| 4 | 4 | #include <stdlib.h> |
| 5 | 5 | #include <string.h> |
| 6 | 6 | |
| 7 | void zig_panic(); | |
| 7 | void zig_panic(void); | |
| 8 | 8 | |
| 9 | 9 | static void assert_or_panic(bool ok) { |
| 10 | 10 | if (!ok) { |
| ... | ... | @@ -60,6 +60,54 @@ static void assert_or_panic(bool ok) { |
| 60 | 60 | # define ZIG_NO_COMPLEX |
| 61 | 61 | #endif |
| 62 | 62 | |
| 63 | #ifdef __x86_64__ | |
| 64 | #define ZIG_NO_RAW_F16 | |
| 65 | #endif | |
| 66 | ||
| 67 | #ifdef __i386__ | |
| 68 | #define ZIG_NO_RAW_F16 | |
| 69 | #endif | |
| 70 | ||
| 71 | #ifdef __mips__ | |
| 72 | #define ZIG_NO_RAW_F16 | |
| 73 | #endif | |
| 74 | ||
| 75 | #ifdef __riscv | |
| 76 | #define ZIG_NO_RAW_F16 | |
| 77 | #endif | |
| 78 | ||
| 79 | #ifdef __wasm__ | |
| 80 | #define ZIG_NO_RAW_F16 | |
| 81 | #endif | |
| 82 | ||
| 83 | #ifdef __powerpc__ | |
| 84 | #define ZIG_NO_RAW_F16 | |
| 85 | #endif | |
| 86 | ||
| 87 | #ifdef __aarch64__ | |
| 88 | #define ZIG_NO_F128 | |
| 89 | #endif | |
| 90 | ||
| 91 | #ifdef __arm__ | |
| 92 | #define ZIG_NO_F128 | |
| 93 | #endif | |
| 94 | ||
| 95 | #ifdef __mips__ | |
| 96 | #define ZIG_NO_F128 | |
| 97 | #endif | |
| 98 | ||
| 99 | #ifdef __riscv | |
| 100 | #define ZIG_NO_F128 | |
| 101 | #endif | |
| 102 | ||
| 103 | #ifdef __powerpc__ | |
| 104 | #define ZIG_NO_F128 | |
| 105 | #endif | |
| 106 | ||
| 107 | #ifdef __APPLE__ | |
| 108 | #define ZIG_NO_F128 | |
| 109 | #endif | |
| 110 | ||
| 63 | 111 | #ifndef ZIG_NO_I128 |
| 64 | 112 | struct i128 { |
| 65 | 113 | __int128 value; |
| ... | ... | @@ -884,3 +932,56 @@ void c_func_ptr_byval(void *a, void *b, struct ByVal in, unsigned long c, void * |
| 884 | 932 | assert_or_panic((intptr_t)d == 4); |
| 885 | 933 | assert_or_panic(e == 5); |
| 886 | 934 | } |
| 935 | ||
| 936 | #ifndef ZIG_NO_RAW_F16 | |
| 937 | __fp16 c_f16(__fp16 a) { | |
| 938 | assert_or_panic(a == 12); | |
| 939 | return 34; | |
| 940 | } | |
| 941 | #endif | |
| 942 | ||
| 943 | typedef struct { | |
| 944 | __fp16 a; | |
| 945 | } f16_struct; | |
| 946 | f16_struct c_f16_struct(f16_struct a) { | |
| 947 | assert_or_panic(a.a == 12); | |
| 948 | return (f16_struct){34}; | |
| 949 | } | |
| 950 | ||
| 951 | #if defined __x86_64__ || defined __i386__ | |
| 952 | typedef long double f80; | |
| 953 | f80 c_f80(f80 a) { | |
| 954 | assert_or_panic((double)a == 12.34); | |
| 955 | return 56.78; | |
| 956 | } | |
| 957 | typedef struct { | |
| 958 | f80 a; | |
| 959 | } f80_struct; | |
| 960 | f80_struct c_f80_struct(f80_struct a) { | |
| 961 | assert_or_panic((double)a.a == 12.34); | |
| 962 | return (f80_struct){56.78}; | |
| 963 | } | |
| 964 | typedef struct { | |
| 965 | f80 a; | |
| 966 | int b; | |
| 967 | } f80_extra_struct; | |
| 968 | f80_extra_struct c_f80_extra_struct(f80_extra_struct a) { | |
| 969 | assert_or_panic((double)a.a == 12.34); | |
| 970 | assert_or_panic(a.b == 42); | |
| 971 | return (f80_extra_struct){56.78, 24}; | |
| 972 | } | |
| 973 | #endif | |
| 974 | ||
| 975 | #ifndef ZIG_NO_F128 | |
| 976 | __float128 c_f128(__float128 a) { | |
| 977 | assert_or_panic((double)a == 12.34); | |
| 978 | return 56.78; | |
| 979 | } | |
| 980 | typedef struct { | |
| 981 | __float128 a; | |
| 982 | } f128_struct; | |
| 983 | f128_struct c_f128_struct(f128_struct a) { | |
| 984 | assert_or_panic((double)a.a == 12.34); | |
| 985 | return (f128_struct){56.78}; | |
| 986 | } | |
| 987 | #endif |
test/c_abi/main.zig+99-1| ... | ... | @@ -4,7 +4,7 @@ |
| 4 | 4 | //! To run all the tests on the tier 1 architecture you can use: |
| 5 | 5 | //! zig build test-c-abi -fqemu |
| 6 | 6 | //! To run the tests on a specific architecture: |
| 7 | //! zig test -fno-stage1 -lc main.zig cfuncs.c -target mips-linux --test-cmd qemu-mips --test-cmd-bin | |
| 7 | //! zig test -lc main.zig cfuncs.c -target mips-linux --test-cmd qemu-mips --test-cmd-bin | |
| 8 | 8 | const std = @import("std"); |
| 9 | 9 | const builtin = @import("builtin"); |
| 10 | 10 | const print = std.debug.print; |
| ... | ... | @@ -13,6 +13,9 @@ const expectEqual = std.testing.expectEqual; |
| 13 | 13 | const has_i128 = builtin.cpu.arch != .x86 and !builtin.cpu.arch.isARM() and |
| 14 | 14 | !builtin.cpu.arch.isMIPS() and !builtin.cpu.arch.isPPC(); |
| 15 | 15 | |
| 16 | const has_f128 = builtin.cpu.arch.isX86() and !builtin.os.tag.isDarwin(); | |
| 17 | const has_f80 = builtin.cpu.arch.isX86(); | |
| 18 | ||
| 16 | 19 | extern fn run_c_tests() void; |
| 17 | 20 | |
| 18 | 21 | export fn zig_panic() noreturn { |
| ... | ... | @@ -764,6 +767,7 @@ extern fn c_float_array_struct(FloatArrayStruct) void; |
| 764 | 767 | extern fn c_ret_float_array_struct() FloatArrayStruct; |
| 765 | 768 | |
| 766 | 769 | test "Float array like struct" { |
| 770 | if (builtin.cpu.arch == .x86 and builtin.mode != .Debug) return error.SkipZigTest; | |
| 767 | 771 | if (comptime builtin.cpu.arch.isMIPS()) return error.SkipZigTest; |
| 768 | 772 | if (comptime builtin.cpu.arch.isPPC()) return error.SkipZigTest; |
| 769 | 773 | |
| ... | ... | @@ -824,7 +828,9 @@ extern fn c_big_vec(BigVec) void; |
| 824 | 828 | extern fn c_ret_big_vec() BigVec; |
| 825 | 829 | |
| 826 | 830 | test "big simd vector" { |
| 831 | if (comptime builtin.cpu.arch.isMIPS() and builtin.mode != .Debug) return error.SkipZigTest; | |
| 827 | 832 | if (comptime builtin.cpu.arch.isPPC64()) return error.SkipZigTest; |
| 833 | if (builtin.cpu.arch == .x86_64 and builtin.os.tag == .macos and builtin.mode != .Debug) return error.SkipZigTest; | |
| 828 | 834 | |
| 829 | 835 | c_big_vec(.{ 1, 2, 3, 4, 5, 6, 7, 8 }); |
| 830 | 836 | |
| ... | ... | @@ -875,6 +881,8 @@ test "DC: Zig passes to C" { |
| 875 | 881 | try expectOk(c_assert_DC(.{ .v1 = -0.25, .v2 = 15 })); |
| 876 | 882 | } |
| 877 | 883 | test "DC: Zig returns to C" { |
| 884 | if (builtin.cpu.arch == .x86 and builtin.mode != .Debug) return error.SkipZigTest; | |
| 885 | if (comptime builtin.cpu.arch.isMIPS() and builtin.mode != .Debug) return error.SkipZigTest; | |
| 878 | 886 | if (comptime builtin.cpu.arch.isRISCV()) return error.SkipZigTest; |
| 879 | 887 | if (comptime builtin.cpu.arch.isPPC()) return error.SkipZigTest; |
| 880 | 888 | if (comptime builtin.cpu.arch.isPPC64()) return error.SkipZigTest; |
| ... | ... | @@ -888,6 +896,8 @@ test "DC: C passes to Zig" { |
| 888 | 896 | try expectOk(c_send_DC()); |
| 889 | 897 | } |
| 890 | 898 | test "DC: C returns to Zig" { |
| 899 | if (builtin.cpu.arch == .x86 and builtin.mode != .Debug) return error.SkipZigTest; | |
| 900 | if (comptime builtin.cpu.arch.isMIPS() and builtin.mode != .Debug) return error.SkipZigTest; | |
| 891 | 901 | if (comptime builtin.cpu.arch.isRISCV()) return error.SkipZigTest; |
| 892 | 902 | if (comptime builtin.cpu.arch.isPPC()) return error.SkipZigTest; |
| 893 | 903 | if (comptime builtin.cpu.arch.isPPC64()) return error.SkipZigTest; |
| ... | ... | @@ -920,6 +930,7 @@ test "CFF: Zig passes to C" { |
| 920 | 930 | try expectOk(c_assert_CFF(.{ .v1 = 39, .v2 = 0.875, .v3 = 1.0 })); |
| 921 | 931 | } |
| 922 | 932 | test "CFF: Zig returns to C" { |
| 933 | if (builtin.cpu.arch == .x86 and builtin.mode != .Debug) return error.SkipZigTest; | |
| 923 | 934 | if (comptime builtin.cpu.arch.isMIPS()) return error.SkipZigTest; |
| 924 | 935 | if (comptime builtin.cpu.arch.isPPC()) return error.SkipZigTest; |
| 925 | 936 | if (comptime builtin.cpu.arch.isPPC64()) return error.SkipZigTest; |
| ... | ... | @@ -927,6 +938,8 @@ test "CFF: Zig returns to C" { |
| 927 | 938 | } |
| 928 | 939 | test "CFF: C passes to Zig" { |
| 929 | 940 | if (builtin.target.cpu.arch == .x86) return error.SkipZigTest; |
| 941 | if (comptime builtin.cpu.arch.isRISCV() and builtin.mode != .Debug) return error.SkipZigTest; | |
| 942 | if (builtin.cpu.arch == .aarch64 and builtin.mode != .Debug) return error.SkipZigTest; | |
| 930 | 943 | if (comptime builtin.cpu.arch.isMIPS()) return error.SkipZigTest; |
| 931 | 944 | if (comptime builtin.cpu.arch.isPPC()) return error.SkipZigTest; |
| 932 | 945 | if (comptime builtin.cpu.arch.isPPC64()) return error.SkipZigTest; |
| ... | ... | @@ -934,6 +947,9 @@ test "CFF: C passes to Zig" { |
| 934 | 947 | try expectOk(c_send_CFF()); |
| 935 | 948 | } |
| 936 | 949 | test "CFF: C returns to Zig" { |
| 950 | if (builtin.cpu.arch == .x86 and builtin.mode != .Debug) return error.SkipZigTest; | |
| 951 | if (builtin.cpu.arch == .aarch64 and builtin.mode != .Debug) return error.SkipZigTest; | |
| 952 | if (comptime builtin.cpu.arch.isRISCV() and builtin.mode != .Debug) return error.SkipZigTest; | |
| 937 | 953 | if (comptime builtin.cpu.arch.isMIPS()) return error.SkipZigTest; |
| 938 | 954 | if (comptime builtin.cpu.arch.isPPC()) return error.SkipZigTest; |
| 939 | 955 | if (comptime builtin.cpu.arch.isPPC64()) return error.SkipZigTest; |
| ... | ... | @@ -967,6 +983,7 @@ test "PD: Zig passes to C" { |
| 967 | 983 | } |
| 968 | 984 | test "PD: Zig returns to C" { |
| 969 | 985 | if (builtin.target.cpu.arch == .x86) return error.SkipZigTest; |
| 986 | if (comptime builtin.cpu.arch.isMIPS() and builtin.mode != .Debug) return error.SkipZigTest; | |
| 970 | 987 | if (comptime builtin.cpu.arch.isPPC()) return error.SkipZigTest; |
| 971 | 988 | if (comptime builtin.cpu.arch.isPPC64()) return error.SkipZigTest; |
| 972 | 989 | try expectOk(c_assert_ret_PD()); |
| ... | ... | @@ -980,6 +997,7 @@ test "PD: C passes to Zig" { |
| 980 | 997 | } |
| 981 | 998 | test "PD: C returns to Zig" { |
| 982 | 999 | if (builtin.target.cpu.arch == .x86) return error.SkipZigTest; |
| 1000 | if (comptime builtin.cpu.arch.isMIPS() and builtin.mode != .Debug) return error.SkipZigTest; | |
| 983 | 1001 | if (comptime builtin.cpu.arch.isPPC()) return error.SkipZigTest; |
| 984 | 1002 | if (comptime builtin.cpu.arch.isPPC64()) return error.SkipZigTest; |
| 985 | 1003 | try expectEqual(c_ret_PD(), .{ .v1 = null, .v2 = 0.5 }); |
| ... | ... | @@ -1014,6 +1032,7 @@ extern fn c_modify_by_ref_param(ByRef) ByRef; |
| 1014 | 1032 | |
| 1015 | 1033 | test "C function modifies by ref param" { |
| 1016 | 1034 | if (comptime builtin.cpu.arch.isPPC()) return error.SkipZigTest; |
| 1035 | if (builtin.cpu.arch == .x86_64 and builtin.os.tag == .windows and builtin.mode != .Debug) return error.SkipZigTest; | |
| 1017 | 1036 | |
| 1018 | 1037 | const res = c_modify_by_ref_param(.{ .val = 1, .arr = undefined }); |
| 1019 | 1038 | try expect(res.val == 42); |
| ... | ... | @@ -1034,6 +1053,8 @@ const ByVal = extern struct { |
| 1034 | 1053 | |
| 1035 | 1054 | extern fn c_func_ptr_byval(*anyopaque, *anyopaque, ByVal, c_ulong, *anyopaque, c_ulong) void; |
| 1036 | 1055 | test "C function that takes byval struct called via function pointer" { |
| 1056 | if (builtin.cpu.arch == .x86 and builtin.mode != .Debug) return error.SkipZigTest; | |
| 1057 | if (comptime builtin.cpu.arch.isMIPS() and builtin.mode != .Debug) return error.SkipZigTest; | |
| 1037 | 1058 | if (comptime builtin.cpu.arch.isPPC()) return error.SkipZigTest; |
| 1038 | 1059 | |
| 1039 | 1060 | var fn_ptr = &c_func_ptr_byval; |
| ... | ... | @@ -1049,3 +1070,80 @@ test "C function that takes byval struct called via function pointer" { |
| 1049 | 1070 | @as(c_ulong, 5), |
| 1050 | 1071 | ); |
| 1051 | 1072 | } |
| 1073 | ||
| 1074 | extern fn c_f16(f16) f16; | |
| 1075 | test "f16 bare" { | |
| 1076 | if (!comptime builtin.cpu.arch.isAARCH64()) return error.SkipZigTest; | |
| 1077 | ||
| 1078 | const a = c_f16(12); | |
| 1079 | try expect(a == 34); | |
| 1080 | } | |
| 1081 | ||
| 1082 | const f16_struct = extern struct { | |
| 1083 | a: f16, | |
| 1084 | }; | |
| 1085 | extern fn c_f16_struct(f16_struct) f16_struct; | |
| 1086 | test "f16 struct" { | |
| 1087 | if (builtin.target.cpu.arch == .x86) return error.SkipZigTest; | |
| 1088 | if (comptime builtin.target.cpu.arch.isMIPS()) return error.SkipZigTest; | |
| 1089 | if (comptime builtin.target.cpu.arch.isPPC()) return error.SkipZigTest; | |
| 1090 | if (comptime builtin.target.cpu.arch.isPPC()) return error.SkipZigTest; | |
| 1091 | if (comptime builtin.cpu.arch.isARM() and builtin.mode != .Debug) return error.SkipZigTest; | |
| 1092 | ||
| 1093 | const a = c_f16_struct(.{ .a = 12 }); | |
| 1094 | try expect(a.a == 34); | |
| 1095 | } | |
| 1096 | ||
| 1097 | extern fn c_f80(f80) f80; | |
| 1098 | test "f80 bare" { | |
| 1099 | if (!has_f80) return error.SkipZigTest; | |
| 1100 | ||
| 1101 | const a = c_f80(12.34); | |
| 1102 | try expect(@floatCast(f64, a) == 56.78); | |
| 1103 | } | |
| 1104 | ||
| 1105 | const f80_struct = extern struct { | |
| 1106 | a: f80, | |
| 1107 | }; | |
| 1108 | extern fn c_f80_struct(f80_struct) f80_struct; | |
| 1109 | test "f80 struct" { | |
| 1110 | if (!has_f80) return error.SkipZigTest; | |
| 1111 | if (builtin.target.cpu.arch == .x86) return error.SkipZigTest; | |
| 1112 | if (builtin.mode != .Debug) return error.SkipZigTest; | |
| 1113 | ||
| 1114 | const a = c_f80_struct(.{ .a = 12.34 }); | |
| 1115 | try expect(@floatCast(f64, a.a) == 56.78); | |
| 1116 | } | |
| 1117 | ||
| 1118 | const f80_extra_struct = extern struct { | |
| 1119 | a: f80, | |
| 1120 | b: c_int, | |
| 1121 | }; | |
| 1122 | extern fn c_f80_extra_struct(f80_extra_struct) f80_extra_struct; | |
| 1123 | test "f80 extra struct" { | |
| 1124 | if (!has_f80) return error.SkipZigTest; | |
| 1125 | if (builtin.target.cpu.arch == .x86) return error.SkipZigTest; | |
| 1126 | ||
| 1127 | const a = c_f80_extra_struct(.{ .a = 12.34, .b = 42 }); | |
| 1128 | try expect(@floatCast(f64, a.a) == 56.78); | |
| 1129 | try expect(a.b == 24); | |
| 1130 | } | |
| 1131 | ||
| 1132 | extern fn c_f128(f128) f128; | |
| 1133 | test "f128 bare" { | |
| 1134 | if (!has_f128) return error.SkipZigTest; | |
| 1135 | ||
| 1136 | const a = c_f128(12.34); | |
| 1137 | try expect(@floatCast(f64, a) == 56.78); | |
| 1138 | } | |
| 1139 | ||
| 1140 | const f128_struct = extern struct { | |
| 1141 | a: f128, | |
| 1142 | }; | |
| 1143 | extern fn c_f128_struct(f128_struct) f128_struct; | |
| 1144 | test "f128 struct" { | |
| 1145 | if (!has_f128) return error.SkipZigTest; | |
| 1146 | ||
| 1147 | const a = c_f128_struct(.{ .a = 12.34 }); | |
| 1148 | try expect(@floatCast(f64, a.a) == 56.78); | |
| 1149 | } |
test/tests.zig+8-4| ... | ... | @@ -1323,10 +1323,12 @@ const c_abi_targets = [_]CrossTarget{ |
| 1323 | 1323 | }, |
| 1324 | 1324 | }; |
| 1325 | 1325 | |
| 1326 | pub fn addCAbiTests(b: *build.Builder, skip_non_native: bool) *build.Step { | |
| 1326 | pub fn addCAbiTests(b: *build.Builder, skip_non_native: bool, skip_release: bool) *build.Step { | |
| 1327 | 1327 | const step = b.step("test-c-abi", "Run the C ABI tests"); |
| 1328 | 1328 | |
| 1329 | for (c_abi_targets) |c_abi_target| { | |
| 1329 | const modes: [2]Mode = .{ .Debug, .ReleaseFast }; | |
| 1330 | ||
| 1331 | for (modes[0 .. @as(u8, 1) + @boolToInt(!skip_release)]) |mode| for (c_abi_targets) |c_abi_target| { | |
| 1330 | 1332 | if (skip_non_native and !c_abi_target.isNative()) |
| 1331 | 1333 | continue; |
| 1332 | 1334 | |
| ... | ... | @@ -1339,14 +1341,16 @@ pub fn addCAbiTests(b: *build.Builder, skip_non_native: bool) *build.Step { |
| 1339 | 1341 | } |
| 1340 | 1342 | test_step.linkLibC(); |
| 1341 | 1343 | test_step.addCSourceFile("test/c_abi/cfuncs.c", &.{"-std=c99"}); |
| 1344 | test_step.setBuildMode(mode); | |
| 1342 | 1345 | |
| 1343 | 1346 | const triple_prefix = c_abi_target.zigTriple(b.allocator) catch unreachable; |
| 1344 | test_step.setNamePrefix(b.fmt("{s}-{s} ", .{ | |
| 1347 | test_step.setNamePrefix(b.fmt("{s}-{s}-{s} ", .{ | |
| 1345 | 1348 | "test-c-abi", |
| 1346 | 1349 | triple_prefix, |
| 1350 | @tagName(mode), | |
| 1347 | 1351 | })); |
| 1348 | 1352 | |
| 1349 | 1353 | step.dependOn(&test_step.step); |
| 1350 | } | |
| 1354 | }; | |
| 1351 | 1355 | return step; |
| 1352 | 1356 | } |