authorgravatar for gwenzek@users.noreply.github.comGuillaume Wenzek <gwenzek@users.noreply.github.com> 2022-11-18 13:05:25+01:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-01-09 14:33:27-07:00
log4428e3837c0cb5fba3864cbe72cfe7cf4f94b40a
tree0b7fe40e7c1d24d59caef742da81ab39516c1c15
parent1702404adfa91df4829e25ea8835bf6b7633ac01

add C ABI tests with double

const DC = extern struct { v1: f64, v2: u8 }; const CFF = extern struct { v1: u8, v2: f32, v3: f32 }; const PD = extern struct { v1: ?*anyopaque, v2: f64 }; Signed-off-by: Guillaume Wenzek <gwenzek@users.noreply.github.com>

2 files changed, 231 insertions(+), 1 deletions(-)

test/c_abi/cfuncs.c+63
......@@ -770,3 +770,66 @@ void c_ptr_size_float_struct(Vector2 vec) {
770770Vector2 c_ret_ptr_size_float_struct(void) {
771771 return (Vector2){3, 4};
772772}
773
774/// Tests for Double + Char struct
775struct DC { double v1; char v2; };
776
777int c_assert_DC(struct DC lv){
778 if (lv.v1 != -0.25) return 1;
779 if (lv.v2 != 15) return 2;
780 return 0;
781}
782struct DC c_ret_DC(){
783 struct DC lv = { .v1 = -0.25, .v2 = 15 };
784 return lv;
785}
786int zig_assert_DC(struct DC);
787int c_send_DC(){
788 return zig_assert_DC(c_ret_DC());
789}
790struct DC zig_ret_DC();
791int c_assert_ret_DC(){
792 return c_assert_DC(zig_ret_DC());
793}
794
795/// Tests for Char + Float + Float struct
796struct CFF { char v1; float v2; float v3; };
797
798int c_assert_CFF(struct CFF lv){
799 if (lv.v1 != 39) return 1;
800 if (lv.v2 != 0.875) return 2;
801 if (lv.v3 != 1.0) return 3;
802 return 0;
803}
804struct CFF c_ret_CFF(){
805 struct CFF lv = { .v1 = 39, .v2 = 0.875, .v3 = 1.0 };
806 return lv;
807}
808int zig_assert_CFF(struct CFF);
809int c_send_CFF(){
810 return zig_assert_CFF(c_ret_CFF());
811}
812struct CFF zig_ret_CFF();
813int c_assert_ret_CFF(){
814 return c_assert_CFF(zig_ret_CFF());
815}
816
817struct PD { void* v1; double v2; };
818
819int c_assert_PD(struct PD lv){
820 if (lv.v1 != 0) return 1;
821 if (lv.v2 != 0.5) return 2;
822 return 0;
823}
824struct PD c_ret_PD(){
825 struct PD lv = { .v1 = 0, .v2 = 0.5 };
826 return lv;
827}
828int zig_assert_PD(struct PD);
829int c_send_PD(){
830 return zig_assert_PD(c_ret_PD());
831}
832struct PD zig_ret_PD();
833int c_assert_ret_PD(){
834 return c_assert_PD(zig_ret_PD());
835}
test/c_abi/main.zig+168-1
......@@ -1,8 +1,16 @@
1//! Tests for the C ABI.
2//! Those tests are passing back and forth struct and values across C ABI
3//! by combining Zig code here and its mirror in cfunc.c
4//! To run all the tests on the tier 1 architecture you can use:
5//! zig build test-c-abi -fqemu
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
18const std = @import("std");
29const builtin = @import("builtin");
310const print = std.debug.print;
411const expect = std.testing.expect;
5const has_i128 = builtin.cpu.arch != .i386 and !builtin.cpu.arch.isARM() and
12const expectEqual = std.testing.expectEqual;
13const has_i128 = builtin.cpu.arch != .x86 and !builtin.cpu.arch.isARM() and
614 !builtin.cpu.arch.isMIPS() and !builtin.cpu.arch.isPPC();
715
816extern fn run_c_tests() void;
......@@ -831,3 +839,162 @@ test "C ABI pointer sized float struct" {
831839 try expect(x.x == 3);
832840 try expect(x.y == 4);
833841}
842
843//=== Helpers for struct test ===//
844pub inline fn expectOk(c_err: c_int) !void {
845 if (c_err != 0) {
846 std.debug.print("ABI mismatch on field v{d}.\n", .{c_err});
847 return error.TestExpectedEqual;
848 }
849}
850
851/// Tests for Double + Char struct
852const DC = extern struct { v1: f64, v2: u8 };
853test "DC: Zig passes to C" {
854 if (builtin.target.cpu.arch == .x86_64 and builtin.target.os.tag != .windows)
855 return error.SkipZigTest;
856 if (comptime builtin.cpu.arch.isMIPS()) return error.SkipZigTest;
857 if (comptime builtin.cpu.arch.isRISCV()) return error.SkipZigTest;
858 if (comptime builtin.cpu.arch.isPPC()) return error.SkipZigTest;
859 if (comptime builtin.cpu.arch.isPPC64()) return error.SkipZigTest;
860 try expectOk(c_assert_DC(.{ .v1 = -0.25, .v2 = 15 }));
861}
862test "DC: Zig returns to C" {
863 if (comptime builtin.cpu.arch.isRISCV()) return error.SkipZigTest;
864 if (comptime builtin.cpu.arch.isPPC()) return error.SkipZigTest;
865 if (comptime builtin.cpu.arch.isPPC64()) return error.SkipZigTest;
866 try expectOk(c_assert_ret_DC());
867}
868test "DC: C passes to Zig" {
869 if (builtin.target.cpu.arch == .x86_64 and builtin.target.os.tag != .windows)
870 return error.SkipZigTest;
871 if (comptime builtin.cpu.arch.isMIPS()) return error.SkipZigTest;
872 if (comptime builtin.cpu.arch.isRISCV()) return error.SkipZigTest;
873 if (comptime builtin.cpu.arch.isPPC()) return error.SkipZigTest;
874 if (comptime builtin.cpu.arch.isPPC64()) return error.SkipZigTest;
875 try expectOk(c_send_DC());
876}
877test "DC: C returns to Zig" {
878 if (comptime builtin.cpu.arch.isRISCV()) return error.SkipZigTest;
879 if (comptime builtin.cpu.arch.isPPC()) return error.SkipZigTest;
880 if (comptime builtin.cpu.arch.isPPC64()) return error.SkipZigTest;
881 try expectEqual(c_ret_DC(), .{ .v1 = -0.25, .v2 = 15 });
882}
883
884pub extern fn c_assert_DC(lv: DC) c_int;
885pub extern fn c_assert_ret_DC() c_int;
886pub extern fn c_send_DC() c_int;
887pub extern fn c_ret_DC() DC;
888pub export fn zig_assert_DC(lv: DC) c_int {
889 var err: c_int = 0;
890 if (lv.v1 != -0.25) err = 1;
891 if (lv.v2 != 15) err = 2;
892 if (err != 0) std.debug.print("Received {}", .{lv});
893 return err;
894}
895pub export fn zig_ret_DC() DC {
896 return .{ .v1 = -0.25, .v2 = 15 };
897}
898
899/// Tests for Char + Float + FloatRect struct
900const CFF = extern struct { v1: u8, v2: f32, v3: f32 };
901
902test "CFF: Zig passes to C" {
903 if (builtin.target.cpu.arch.isX86() and builtin.target.os.tag != .windows)
904 return error.SkipZigTest;
905 if (comptime builtin.cpu.arch.isMIPS()) return error.SkipZigTest;
906 if (comptime builtin.cpu.arch.isPPC()) return error.SkipZigTest;
907 if (comptime builtin.cpu.arch.isPPC64()) return error.SkipZigTest;
908 try expectOk(c_assert_CFF(.{ .v1 = 39, .v2 = 0.875, .v3 = 1.0 }));
909}
910test "CFF: Zig returns to C" {
911 if (comptime builtin.cpu.arch.isMIPS()) return error.SkipZigTest;
912 if (comptime builtin.cpu.arch.isPPC()) return error.SkipZigTest;
913 if (comptime builtin.cpu.arch.isPPC64()) return error.SkipZigTest;
914 try expectOk(c_assert_ret_CFF());
915}
916test "CFF: C passes to Zig" {
917 if (builtin.target.cpu.arch.isX86() and builtin.target.os.tag != .windows)
918 return error.SkipZigTest;
919 if (comptime builtin.cpu.arch.isMIPS()) return error.SkipZigTest;
920 if (comptime builtin.cpu.arch.isPPC()) return error.SkipZigTest;
921 if (comptime builtin.cpu.arch.isPPC64()) return error.SkipZigTest;
922
923 try expectOk(c_send_CFF());
924}
925test "CFF: C returns to Zig" {
926 // segfault on aarch64 and mips
927 if (builtin.target.cpu.arch == .aarch64) return error.SkipZigTest;
928 if (comptime builtin.cpu.arch.isMIPS()) return error.SkipZigTest;
929 if (comptime builtin.cpu.arch.isPPC()) return error.SkipZigTest;
930 if (comptime builtin.cpu.arch.isPPC64()) return error.SkipZigTest;
931 try expectEqual(c_ret_CFF(), .{ .v1 = 39, .v2 = 0.875, .v3 = 1.0 });
932}
933pub extern fn c_assert_CFF(lv: CFF) c_int;
934pub extern fn c_assert_ret_CFF() c_int;
935pub extern fn c_send_CFF() c_int;
936pub extern fn c_ret_CFF() CFF;
937pub export fn zig_assert_CFF(lv: CFF) c_int {
938 var err: c_int = 0;
939 if (lv.v1 != 39) err = 1;
940 if (lv.v2 != 0.875) err = 2;
941 if (lv.v3 != 1.0) err = 3;
942 if (err != 0) std.debug.print("Received {}", .{lv});
943 return err;
944}
945pub export fn zig_ret_CFF() CFF {
946 return .{ .v1 = 39, .v2 = 0.875, .v3 = 1.0 };
947}
948
949/// Tests for Pointer + Double struct
950const PD = extern struct { v1: ?*anyopaque, v2: f64 };
951
952test "PD: Zig passes to C" {
953 if (builtin.target.cpu.arch.isX86() and builtin.target.os.tag != .windows)
954 return error.SkipZigTest;
955 if (comptime builtin.cpu.arch.isMIPS()) return error.SkipZigTest;
956 if (comptime builtin.cpu.arch.isPPC()) return error.SkipZigTest;
957 if (comptime builtin.cpu.arch.isPPC64()) return error.SkipZigTest;
958 try expectOk(c_assert_PD(.{ .v1 = null, .v2 = 0.5 }));
959}
960test "PD: Zig returns to C" {
961 if (builtin.target.cpu.arch == .x86) return error.SkipZigTest;
962 if (comptime builtin.cpu.arch.isPPC()) return error.SkipZigTest;
963 if (comptime builtin.cpu.arch.isPPC64()) return error.SkipZigTest;
964 try expectOk(c_assert_ret_PD());
965}
966test "PD: C passes to Zig" {
967 if (builtin.target.cpu.arch.isX86() and builtin.target.os.tag != .windows)
968 return error.SkipZigTest;
969 if (comptime builtin.cpu.arch.isMIPS()) return error.SkipZigTest;
970 if (comptime builtin.cpu.arch.isPPC()) return error.SkipZigTest;
971 if (comptime builtin.cpu.arch.isPPC64()) return error.SkipZigTest;
972 try expectOk(c_send_PD());
973}
974test "PD: C returns to Zig" {
975 if (builtin.target.cpu.arch == .x86) return error.SkipZigTest;
976 if (comptime builtin.cpu.arch.isPPC()) return error.SkipZigTest;
977 if (comptime builtin.cpu.arch.isPPC64()) return error.SkipZigTest;
978 try expectEqual(c_ret_PD(), .{ .v1 = null, .v2 = 0.5 });
979}
980pub extern fn c_assert_PD(lv: PD) c_int;
981pub extern fn c_assert_ret_PD() c_int;
982pub extern fn c_send_PD() c_int;
983pub extern fn c_ret_PD() PD;
984pub export fn zig_c_assert_PD(lv: PD) c_int {
985 var err: c_int = 0;
986 if (lv.v1 != null) err = 1;
987 if (lv.v2 != 0.5) err = 2;
988 if (err != 0) std.debug.print("Received {}", .{lv});
989 return err;
990}
991pub export fn zig_ret_PD() PD {
992 return .{ .v1 = null, .v2 = 0.5 };
993}
994pub export fn zig_assert_PD(lv: PD) c_int {
995 var err: c_int = 0;
996 if (lv.v1 != null) err = 1;
997 if (lv.v2 != 0.5) err = 2;
998 if (err != 0) std.debug.print("Received {}", .{lv});
999 return err;
1000}