authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2023-01-14 21:42:29+02:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2023-01-14 21:42:29+02:00
logbb15e4057c9c8bb22084990de475ab10a44592c0
treec1dcacddfc3ff184bd924405db0759ae2625280f
parent18191b80b6381eb41adb4354a243190865801212
parent0013042cbd539cf7eb463483633e9f7aa2fa8067
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #14271 from Vexu/c-abi

float related C ABI fixes

6 files changed, 273 insertions(+), 25 deletions(-)

build.zig+1-1
...@@ -440,7 +440,7 @@ pub fn build(b: *Builder) !void {...@@ -440,7 +440,7 @@ pub fn build(b: *Builder) !void {
440 b.enable_wine,440 b.enable_wine,
441 enable_symlinks_windows,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 test_step.dependOn(tests.addLinkTests(b, test_filter, modes, enable_macos_sdk, skip_stage2_tests, enable_symlinks_windows));444 test_step.dependOn(tests.addLinkTests(b, test_filter, modes, enable_macos_sdk, skip_stage2_tests, enable_symlinks_windows));
445 test_step.dependOn(tests.addStackTraceTests(b, test_filter, modes));445 test_step.dependOn(tests.addStackTraceTests(b, test_filter, modes));
446 test_step.dependOn(tests.addCliTests(b, test_filter, modes));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,7 +5,19 @@ const assert = std.debug.assert;
5const Register = @import("bits.zig").Register;5const Register = @import("bits.zig").Register;
6const RegisterManagerFn = @import("../../register_manager.zig").RegisterManager;6const RegisterManagerFn = @import("../../register_manager.zig").RegisterManager;
77
8pub const Class = enum { integer, sse, sseup, x87, x87up, complex_x87, memory, none, win_i128 };8pub 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};
921
10pub fn classifyWindows(ty: Type, target: Target) Class {22pub fn classifyWindows(ty: Type, target: Target) Class {
11 // https://docs.microsoft.com/en-gb/cpp/build/x64-calling-convention?view=vs-201723 // 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,7 +124,20 @@ pub fn classifySystemV(ty: Type, target: Target, ctx: Context) [8]Class {
112 return result;124 return result;
113 },125 },
114 .Float => switch (ty.floatBits(target)) {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 result[0] = .sse;141 result[0] = .sse;
117 return result;142 return result;
118 },143 },
...@@ -120,11 +145,15 @@ pub fn classifySystemV(ty: Type, target: Target, ctx: Context) [8]Class {...@@ -120,11 +145,15 @@ pub fn classifySystemV(ty: Type, target: Target, ctx: Context) [8]Class {
120 // "Arguments of types__float128, _Decimal128 and__m128 are145 // "Arguments of types__float128, _Decimal128 and__m128 are
121 // split into two halves. The least significant ones belong146 // split into two halves. The least significant ones belong
122 // to class SSE, the most significant one to class SSEUP."147 // to class SSE, the most significant one to class SSEUP."
148 if (ctx == .other) {
149 result[0] = .memory;
150 return result;
151 }
123 result[0] = .sse;152 result[0] = .sse;
124 result[1] = .sseup;153 result[1] = .sseup;
125 return result;154 return result;
126 },155 },
127 else => {156 80 => {
128 // "The 64-bit mantissa of arguments of type long double157 // "The 64-bit mantissa of arguments of type long double
129 // belongs to classX87, the 16-bit exponent plus 6 bytes158 // belongs to classX87, the 16-bit exponent plus 6 bytes
130 // of padding belongs to class X87UP."159 // of padding belongs to class X87UP."
...@@ -132,6 +161,7 @@ pub fn classifySystemV(ty: Type, target: Target, ctx: Context) [8]Class {...@@ -132,6 +161,7 @@ pub fn classifySystemV(ty: Type, target: Target, ctx: Context) [8]Class {
132 result[1] = .x87up;161 result[1] = .x87up;
133 return result;162 return result;
134 },163 },
164 else => unreachable,
135 },165 },
136 .Vector => {166 .Vector => {
137 const elem_ty = ty.childType();167 const elem_ty = ty.childType();
...@@ -238,6 +268,9 @@ pub fn classifySystemV(ty: Type, target: Target, ctx: Context) [8]Class {...@@ -238,6 +268,9 @@ pub fn classifySystemV(ty: Type, target: Target, ctx: Context) [8]Class {
238 combine: {268 combine: {
239 // "If both classes are equal, this is the resulting class."269 // "If both classes are equal, this is the resulting class."
240 if (result[result_i] == field_class[0]) {270 if (result[result_i] == field_class[0]) {
271 if (result[result_i] == .float) {
272 result[result_i] = .float_combine;
273 }
241 break :combine;274 break :combine;
242 }275 }
243276
src/codegen/llvm.zig+27-15
...@@ -10395,7 +10395,12 @@ fn firstParamSRet(fn_info: Type.Payload.Function.Data, target: std.Target) bool...@@ -10395,7 +10395,12 @@ fn firstParamSRet(fn_info: Type.Payload.Function.Data, target: std.Target) bool
10395 .mips, .mipsel => return false,10395 .mips, .mipsel => return false,
10396 .x86_64 => switch (target.os.tag) {10396 .x86_64 => switch (target.os.tag) {
10397 .windows => return x86_64_abi.classifyWindows(fn_info.return_type, target) == .memory,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 .wasm32 => return wasm_c_abi.classifyType(fn_info.return_type, target)[0] == .indirect,10405 .wasm32 => return wasm_c_abi.classifyType(fn_info.return_type, target)[0] == .indirect,
10401 .aarch64, .aarch64_be => return aarch64_c_abi.classifyType(fn_info.return_type, target) == .memory,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,22 +10474,26 @@ fn lowerFnRetTy(dg: *DeclGen, fn_info: Type.Payload.Function.Data) !*llvm.Type {
10469 llvm_types_buffer[llvm_types_index] = dg.context.intType(64);10474 llvm_types_buffer[llvm_types_index] = dg.context.intType(64);
10470 llvm_types_index += 1;10475 llvm_types_index += 1;
10471 },10476 },
10472 .sse => {10477 .sse, .sseup => {
10473 llvm_types_buffer[llvm_types_index] = dg.context.doubleType();10478 llvm_types_buffer[llvm_types_index] = dg.context.doubleType();
10474 llvm_types_index += 1;10479 llvm_types_index += 1;
10475 },10480 },
10476 .sseup => {10481 .float => {
10477 llvm_types_buffer[llvm_types_index] = dg.context.doubleType();10482 llvm_types_buffer[llvm_types_index] = dg.context.floatType();
10478 llvm_types_index += 1;10483 llvm_types_index += 1;
10479 },10484 },
10480 .x87 => {10485 .float_combine => {
10481 llvm_types_buffer[llvm_types_index] = dg.context.x86FP80Type();10486 llvm_types_buffer[llvm_types_index] = dg.context.floatType().vectorType(2);
10482 llvm_types_index += 1;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 llvm_types_buffer[llvm_types_index] = dg.context.x86FP80Type();10493 llvm_types_buffer[llvm_types_index] = dg.context.x86FP80Type();
10486 llvm_types_index += 1;10494 llvm_types_index += 1;
10487 },10495 },
10496 .x87up => continue,
10488 .complex_x87 => {10497 .complex_x87 => {
10489 @panic("TODO");10498 @panic("TODO");
10490 },10499 },
...@@ -10689,22 +10698,25 @@ const ParamTypeIterator = struct {...@@ -10689,22 +10698,25 @@ const ParamTypeIterator = struct {
10689 llvm_types_buffer[llvm_types_index] = dg.context.intType(64);10698 llvm_types_buffer[llvm_types_index] = dg.context.intType(64);
10690 llvm_types_index += 1;10699 llvm_types_index += 1;
10691 },10700 },
10692 .sse => {10701 .sse, .sseup => {
10693 llvm_types_buffer[llvm_types_index] = dg.context.doubleType();10702 llvm_types_buffer[llvm_types_index] = dg.context.doubleType();
10694 llvm_types_index += 1;10703 llvm_types_index += 1;
10695 },10704 },
10696 .sseup => {10705 .float => {
10697 llvm_types_buffer[llvm_types_index] = dg.context.doubleType();10706 llvm_types_buffer[llvm_types_index] = dg.context.floatType();
10698 llvm_types_index += 1;10707 llvm_types_index += 1;
10699 },10708 },
10700 .x87 => {10709 .float_combine => {
10701 llvm_types_buffer[llvm_types_index] = dg.context.x86FP80Type();10710 llvm_types_buffer[llvm_types_index] = dg.context.floatType().vectorType(2);
10702 llvm_types_index += 1;10711 llvm_types_index += 1;
10703 },10712 },
10704 .x87up => {10713 .x87 => {
10705 llvm_types_buffer[llvm_types_index] = dg.context.x86FP80Type();10714 it.zig_index += 1;
10706 llvm_types_index += 1;10715 it.llvm_index += 1;
10716 it.byval_attr = true;
10717 return .byref;
10707 },10718 },
10719 .x87up => unreachable,
10708 .complex_x87 => {10720 .complex_x87 => {
10709 @panic("TODO");10721 @panic("TODO");
10710 },10722 },
test/c_abi/cfuncs.c+102-1
...@@ -4,7 +4,7 @@...@@ -4,7 +4,7 @@
4#include <stdlib.h>4#include <stdlib.h>
5#include <string.h>5#include <string.h>
66
7void zig_panic();7void zig_panic(void);
88
9static void assert_or_panic(bool ok) {9static void assert_or_panic(bool ok) {
10 if (!ok) {10 if (!ok) {
...@@ -60,6 +60,54 @@ static void assert_or_panic(bool ok) {...@@ -60,6 +60,54 @@ static void assert_or_panic(bool ok) {
60# define ZIG_NO_COMPLEX60# define ZIG_NO_COMPLEX
61#endif61#endif
6262
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#ifndef ZIG_NO_I128111#ifndef ZIG_NO_I128
64struct i128 {112struct i128 {
65 __int128 value;113 __int128 value;
...@@ -884,3 +932,56 @@ void c_func_ptr_byval(void *a, void *b, struct ByVal in, unsigned long c, void *...@@ -884,3 +932,56 @@ void c_func_ptr_byval(void *a, void *b, struct ByVal in, unsigned long c, void *
884 assert_or_panic((intptr_t)d == 4);932 assert_or_panic((intptr_t)d == 4);
885 assert_or_panic(e == 5);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
943typedef struct {
944 __fp16 a;
945} f16_struct;
946f16_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__
952typedef long double f80;
953f80 c_f80(f80 a) {
954 assert_or_panic((double)a == 12.34);
955 return 56.78;
956}
957typedef struct {
958 f80 a;
959} f80_struct;
960f80_struct c_f80_struct(f80_struct a) {
961 assert_or_panic((double)a.a == 12.34);
962 return (f80_struct){56.78};
963}
964typedef struct {
965 f80 a;
966 int b;
967} f80_extra_struct;
968f80_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}
980typedef struct {
981 __float128 a;
982} f128_struct;
983f128_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,7 +4,7 @@
4//! To run all the tests on the tier 1 architecture you can use:4//! To run all the tests on the tier 1 architecture you can use:
5//! zig build test-c-abi -fqemu5//! zig build test-c-abi -fqemu
6//! To run the tests on a specific architecture: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-bin7//! zig test -lc main.zig cfuncs.c -target mips-linux --test-cmd qemu-mips --test-cmd-bin
8const std = @import("std");8const std = @import("std");
9const builtin = @import("builtin");9const builtin = @import("builtin");
10const print = std.debug.print;10const print = std.debug.print;
...@@ -13,6 +13,9 @@ const expectEqual = std.testing.expectEqual;...@@ -13,6 +13,9 @@ const expectEqual = std.testing.expectEqual;
13const has_i128 = builtin.cpu.arch != .x86 and !builtin.cpu.arch.isARM() and13const has_i128 = builtin.cpu.arch != .x86 and !builtin.cpu.arch.isARM() and
14 !builtin.cpu.arch.isMIPS() and !builtin.cpu.arch.isPPC();14 !builtin.cpu.arch.isMIPS() and !builtin.cpu.arch.isPPC();
1515
16const has_f128 = builtin.cpu.arch.isX86() and !builtin.os.tag.isDarwin();
17const has_f80 = builtin.cpu.arch.isX86();
18
16extern fn run_c_tests() void;19extern fn run_c_tests() void;
1720
18export fn zig_panic() noreturn {21export fn zig_panic() noreturn {
...@@ -764,6 +767,7 @@ extern fn c_float_array_struct(FloatArrayStruct) void;...@@ -764,6 +767,7 @@ extern fn c_float_array_struct(FloatArrayStruct) void;
764extern fn c_ret_float_array_struct() FloatArrayStruct;767extern fn c_ret_float_array_struct() FloatArrayStruct;
765768
766test "Float array like struct" {769test "Float array like struct" {
770 if (builtin.cpu.arch == .x86 and builtin.mode != .Debug) return error.SkipZigTest;
767 if (comptime builtin.cpu.arch.isMIPS()) return error.SkipZigTest;771 if (comptime builtin.cpu.arch.isMIPS()) return error.SkipZigTest;
768 if (comptime builtin.cpu.arch.isPPC()) return error.SkipZigTest;772 if (comptime builtin.cpu.arch.isPPC()) return error.SkipZigTest;
769773
...@@ -824,7 +828,9 @@ extern fn c_big_vec(BigVec) void;...@@ -824,7 +828,9 @@ extern fn c_big_vec(BigVec) void;
824extern fn c_ret_big_vec() BigVec;828extern fn c_ret_big_vec() BigVec;
825829
826test "big simd vector" {830test "big simd vector" {
831 if (comptime builtin.cpu.arch.isMIPS() and builtin.mode != .Debug) return error.SkipZigTest;
827 if (comptime builtin.cpu.arch.isPPC64()) return error.SkipZigTest;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;
828834
829 c_big_vec(.{ 1, 2, 3, 4, 5, 6, 7, 8 });835 c_big_vec(.{ 1, 2, 3, 4, 5, 6, 7, 8 });
830836
...@@ -875,6 +881,8 @@ test "DC: Zig passes to C" {...@@ -875,6 +881,8 @@ test "DC: Zig passes to C" {
875 try expectOk(c_assert_DC(.{ .v1 = -0.25, .v2 = 15 }));881 try expectOk(c_assert_DC(.{ .v1 = -0.25, .v2 = 15 }));
876}882}
877test "DC: Zig returns to C" {883test "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 if (comptime builtin.cpu.arch.isRISCV()) return error.SkipZigTest;886 if (comptime builtin.cpu.arch.isRISCV()) return error.SkipZigTest;
879 if (comptime builtin.cpu.arch.isPPC()) return error.SkipZigTest;887 if (comptime builtin.cpu.arch.isPPC()) return error.SkipZigTest;
880 if (comptime builtin.cpu.arch.isPPC64()) return error.SkipZigTest;888 if (comptime builtin.cpu.arch.isPPC64()) return error.SkipZigTest;
...@@ -888,6 +896,8 @@ test "DC: C passes to Zig" {...@@ -888,6 +896,8 @@ test "DC: C passes to Zig" {
888 try expectOk(c_send_DC());896 try expectOk(c_send_DC());
889}897}
890test "DC: C returns to Zig" {898test "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 if (comptime builtin.cpu.arch.isRISCV()) return error.SkipZigTest;901 if (comptime builtin.cpu.arch.isRISCV()) return error.SkipZigTest;
892 if (comptime builtin.cpu.arch.isPPC()) return error.SkipZigTest;902 if (comptime builtin.cpu.arch.isPPC()) return error.SkipZigTest;
893 if (comptime builtin.cpu.arch.isPPC64()) return error.SkipZigTest;903 if (comptime builtin.cpu.arch.isPPC64()) return error.SkipZigTest;
...@@ -920,6 +930,7 @@ test "CFF: Zig passes to C" {...@@ -920,6 +930,7 @@ test "CFF: Zig passes to C" {
920 try expectOk(c_assert_CFF(.{ .v1 = 39, .v2 = 0.875, .v3 = 1.0 }));930 try expectOk(c_assert_CFF(.{ .v1 = 39, .v2 = 0.875, .v3 = 1.0 }));
921}931}
922test "CFF: Zig returns to C" {932test "CFF: Zig returns to C" {
933 if (builtin.cpu.arch == .x86 and builtin.mode != .Debug) return error.SkipZigTest;
923 if (comptime builtin.cpu.arch.isMIPS()) return error.SkipZigTest;934 if (comptime builtin.cpu.arch.isMIPS()) return error.SkipZigTest;
924 if (comptime builtin.cpu.arch.isPPC()) return error.SkipZigTest;935 if (comptime builtin.cpu.arch.isPPC()) return error.SkipZigTest;
925 if (comptime builtin.cpu.arch.isPPC64()) return error.SkipZigTest;936 if (comptime builtin.cpu.arch.isPPC64()) return error.SkipZigTest;
...@@ -927,6 +938,8 @@ test "CFF: Zig returns to C" {...@@ -927,6 +938,8 @@ test "CFF: Zig returns to C" {
927}938}
928test "CFF: C passes to Zig" {939test "CFF: C passes to Zig" {
929 if (builtin.target.cpu.arch == .x86) return error.SkipZigTest;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 if (comptime builtin.cpu.arch.isMIPS()) return error.SkipZigTest;943 if (comptime builtin.cpu.arch.isMIPS()) return error.SkipZigTest;
931 if (comptime builtin.cpu.arch.isPPC()) return error.SkipZigTest;944 if (comptime builtin.cpu.arch.isPPC()) return error.SkipZigTest;
932 if (comptime builtin.cpu.arch.isPPC64()) return error.SkipZigTest;945 if (comptime builtin.cpu.arch.isPPC64()) return error.SkipZigTest;
...@@ -934,6 +947,9 @@ test "CFF: C passes to Zig" {...@@ -934,6 +947,9 @@ test "CFF: C passes to Zig" {
934 try expectOk(c_send_CFF());947 try expectOk(c_send_CFF());
935}948}
936test "CFF: C returns to Zig" {949test "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 if (comptime builtin.cpu.arch.isMIPS()) return error.SkipZigTest;953 if (comptime builtin.cpu.arch.isMIPS()) return error.SkipZigTest;
938 if (comptime builtin.cpu.arch.isPPC()) return error.SkipZigTest;954 if (comptime builtin.cpu.arch.isPPC()) return error.SkipZigTest;
939 if (comptime builtin.cpu.arch.isPPC64()) return error.SkipZigTest;955 if (comptime builtin.cpu.arch.isPPC64()) return error.SkipZigTest;
...@@ -967,6 +983,7 @@ test "PD: Zig passes to C" {...@@ -967,6 +983,7 @@ test "PD: Zig passes to C" {
967}983}
968test "PD: Zig returns to C" {984test "PD: Zig returns to C" {
969 if (builtin.target.cpu.arch == .x86) return error.SkipZigTest;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 if (comptime builtin.cpu.arch.isPPC()) return error.SkipZigTest;987 if (comptime builtin.cpu.arch.isPPC()) return error.SkipZigTest;
971 if (comptime builtin.cpu.arch.isPPC64()) return error.SkipZigTest;988 if (comptime builtin.cpu.arch.isPPC64()) return error.SkipZigTest;
972 try expectOk(c_assert_ret_PD());989 try expectOk(c_assert_ret_PD());
...@@ -980,6 +997,7 @@ test "PD: C passes to Zig" {...@@ -980,6 +997,7 @@ test "PD: C passes to Zig" {
980}997}
981test "PD: C returns to Zig" {998test "PD: C returns to Zig" {
982 if (builtin.target.cpu.arch == .x86) return error.SkipZigTest;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 if (comptime builtin.cpu.arch.isPPC()) return error.SkipZigTest;1001 if (comptime builtin.cpu.arch.isPPC()) return error.SkipZigTest;
984 if (comptime builtin.cpu.arch.isPPC64()) return error.SkipZigTest;1002 if (comptime builtin.cpu.arch.isPPC64()) return error.SkipZigTest;
985 try expectEqual(c_ret_PD(), .{ .v1 = null, .v2 = 0.5 });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,6 +1032,7 @@ extern fn c_modify_by_ref_param(ByRef) ByRef;
10141032
1015test "C function modifies by ref param" {1033test "C function modifies by ref param" {
1016 if (comptime builtin.cpu.arch.isPPC()) return error.SkipZigTest;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;
10171036
1018 const res = c_modify_by_ref_param(.{ .val = 1, .arr = undefined });1037 const res = c_modify_by_ref_param(.{ .val = 1, .arr = undefined });
1019 try expect(res.val == 42);1038 try expect(res.val == 42);
...@@ -1034,6 +1053,8 @@ const ByVal = extern struct {...@@ -1034,6 +1053,8 @@ const ByVal = extern struct {
10341053
1035extern fn c_func_ptr_byval(*anyopaque, *anyopaque, ByVal, c_ulong, *anyopaque, c_ulong) void;1054extern fn c_func_ptr_byval(*anyopaque, *anyopaque, ByVal, c_ulong, *anyopaque, c_ulong) void;
1036test "C function that takes byval struct called via function pointer" {1055test "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 if (comptime builtin.cpu.arch.isPPC()) return error.SkipZigTest;1058 if (comptime builtin.cpu.arch.isPPC()) return error.SkipZigTest;
10381059
1039 var fn_ptr = &c_func_ptr_byval;1060 var fn_ptr = &c_func_ptr_byval;
...@@ -1049,3 +1070,80 @@ test "C function that takes byval struct called via function pointer" {...@@ -1049,3 +1070,80 @@ test "C function that takes byval struct called via function pointer" {
1049 @as(c_ulong, 5),1070 @as(c_ulong, 5),
1050 );1071 );
1051}1072}
1073
1074extern fn c_f16(f16) f16;
1075test "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
1082const f16_struct = extern struct {
1083 a: f16,
1084};
1085extern fn c_f16_struct(f16_struct) f16_struct;
1086test "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
1097extern fn c_f80(f80) f80;
1098test "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
1105const f80_struct = extern struct {
1106 a: f80,
1107};
1108extern fn c_f80_struct(f80_struct) f80_struct;
1109test "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
1118const f80_extra_struct = extern struct {
1119 a: f80,
1120 b: c_int,
1121};
1122extern fn c_f80_extra_struct(f80_extra_struct) f80_extra_struct;
1123test "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
1132extern fn c_f128(f128) f128;
1133test "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
1140const f128_struct = extern struct {
1141 a: f128,
1142};
1143extern fn c_f128_struct(f128_struct) f128_struct;
1144test "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,10 +1323,12 @@ const c_abi_targets = [_]CrossTarget{
1323 },1323 },
1324};1324};
13251325
1326pub fn addCAbiTests(b: *build.Builder, skip_non_native: bool) *build.Step {1326pub fn addCAbiTests(b: *build.Builder, skip_non_native: bool, skip_release: bool) *build.Step {
1327 const step = b.step("test-c-abi", "Run the C ABI tests");1327 const step = b.step("test-c-abi", "Run the C ABI tests");
13281328
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 if (skip_non_native and !c_abi_target.isNative())1332 if (skip_non_native and !c_abi_target.isNative())
1331 continue;1333 continue;
13321334
...@@ -1339,14 +1341,16 @@ pub fn addCAbiTests(b: *build.Builder, skip_non_native: bool) *build.Step {...@@ -1339,14 +1341,16 @@ pub fn addCAbiTests(b: *build.Builder, skip_non_native: bool) *build.Step {
1339 }1341 }
1340 test_step.linkLibC();1342 test_step.linkLibC();
1341 test_step.addCSourceFile("test/c_abi/cfuncs.c", &.{"-std=c99"});1343 test_step.addCSourceFile("test/c_abi/cfuncs.c", &.{"-std=c99"});
1344 test_step.setBuildMode(mode);
13421345
1343 const triple_prefix = c_abi_target.zigTriple(b.allocator) catch unreachable;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 "test-c-abi",1348 "test-c-abi",
1346 triple_prefix,1349 triple_prefix,
1350 @tagName(mode),
1347 }));1351 }));
13481352
1349 step.dependOn(&test_step.step);1353 step.dependOn(&test_step.step);
1350 }1354 };
1351 return step;1355 return step;
1352}1356}