Commit a06185f362

Cody Tapscott <topolarity@tapscott.me>
2022-10-10 08:24:29
C ABI: Add tests for complex float/double support
These tests will be failing on many platforms until #8465 is resolved. Luckily, the particular function signature used for __divXc3 and __mulXc3 seems to be OK on x86-64.
1 parent 879fb0c
Changed files (2)
test
test/c_abi/cfuncs.c
@@ -2,6 +2,7 @@
 #include <stdlib.h>
 #include <stdbool.h>
 #include <string.h>
+#include <complex.h>
 
 void zig_panic();
 
@@ -50,6 +51,13 @@ void zig_ptr(void *);
 
 void zig_bool(bool);
 
+// Note: These two functions match the signature of __mulsc3 and __muldc3 in compiler-rt (and libgcc)
+float complex zig_cmultf_comp(float a_r, float a_i, float b_r, float b_i);
+double complex zig_cmultd_comp(double a_r, double a_i, double b_r, double b_i);
+
+float complex zig_cmultf(float complex a, float complex b);
+double complex zig_cmultd(double complex a, double complex b);
+
 struct BigStruct {
     uint64_t a;
     uint64_t b;
@@ -167,6 +175,43 @@ void run_c_tests(void) {
 
     zig_bool(true);
 
+    // TODO: Resolve https://github.com/ziglang/zig/issues/8465
+    //{
+    //    float complex a = 1.25f + I * 2.6f;
+    //    float complex b = 11.3f - I * 1.5f;
+    //    float complex z = zig_cmultf(a, b);
+    //    assert_or_panic(creal(z) == 1.5f);
+    //    assert_or_panic(cimag(z) == 13.5f);
+    //}
+
+    {
+        double complex a = 1.25 + I * 2.6;
+        double complex b = 11.3 - I * 1.5;
+        double complex z = zig_cmultd(a, b);
+        assert_or_panic(creal(z) == 1.5);
+        assert_or_panic(cimag(z) == 13.5);
+    }
+
+    {
+        float a_r = 1.25f;
+        float a_i = 2.6f;
+        float b_r = 11.3f;
+        float b_i = -1.5f;
+        float complex z = zig_cmultf_comp(a_r, a_i, b_r, b_i);
+        assert_or_panic(creal(z) == 1.5f);
+        assert_or_panic(cimag(z) == 13.5f);
+    }
+
+    {
+        double a_r = 1.25;
+        double a_i = 2.6;
+        double b_r = 11.3;
+        double b_i = -1.5;
+        double complex z = zig_cmultd_comp(a_r, a_i, b_r, b_i);
+        assert_or_panic(creal(z) == 1.5);
+        assert_or_panic(cimag(z) == 13.5);
+    }
+
     {
         struct BigStruct s = {1, 2, 3, 4, 5};
         zig_big_struct(s);
@@ -321,6 +366,42 @@ void c_five_floats(float a, float b, float c, float d, float e) {
     assert_or_panic(e == 5.0);
 }
 
+float complex c_cmultf_comp(float a_r, float a_i, float b_r, float b_i) {
+    assert_or_panic(a_r == 1.25f);
+    assert_or_panic(a_i == 2.6f);
+    assert_or_panic(b_r == 11.3f);
+    assert_or_panic(b_i == -1.5f);
+
+    return 1.5f + I * 13.5f;
+}
+
+double complex c_cmultd_comp(double a_r, double a_i, double b_r, double b_i) {
+    assert_or_panic(a_r == 1.25);
+    assert_or_panic(a_i == 2.6);
+    assert_or_panic(b_r == 11.3);
+    assert_or_panic(b_i == -1.5);
+
+    return 1.5 + I * 13.5;
+}
+
+float complex c_cmultf(float complex a, float complex b) {
+    assert_or_panic(creal(a) == 1.25f);
+    assert_or_panic(cimag(a) == 2.6f);
+    assert_or_panic(creal(b) == 11.3f);
+    assert_or_panic(cimag(b) == -1.5f);
+
+    return 1.5f + I * 13.5f;
+}
+
+double complex c_cmultd(double complex a, double complex b) {
+    assert_or_panic(creal(a) == 1.25);
+    assert_or_panic(cimag(a) == 2.6);
+    assert_or_panic(creal(b) == 11.3);
+    assert_or_panic(cimag(b) == -1.5);
+
+    return 1.5 + I * 13.5;
+}
+
 void c_big_struct(struct BigStruct x) {
     assert_or_panic(x.a == 1);
     assert_or_panic(x.b == 2);
test/c_abi/main.zig
@@ -145,6 +145,101 @@ export fn zig_bool(x: bool) void {
     expect(x) catch @panic("test failure: zig_bool");
 }
 
+// TODO: Replace these with the correct types once we resolve
+//       https://github.com/ziglang/zig/issues/8465
+//
+// For now, we have no way of referring to the _Complex C types from Zig,
+// so our ABI is unavoidably broken on some platforms (such as i386)
+const ComplexFloat = extern struct {
+    real: f32,
+    imag: f32,
+};
+const ComplexDouble = extern struct {
+    real: f64,
+    imag: f64,
+};
+
+// Note: These two functions match the signature of __mulsc3 and __muldc3 in compiler-rt (and libgcc)
+extern fn c_cmultf_comp(a_r: f32, a_i: f32, b_r: f32, b_i: f32) ComplexFloat;
+extern fn c_cmultd_comp(a_r: f64, a_i: f64, b_r: f64, b_i: f64) ComplexDouble;
+
+extern fn c_cmultf(a: ComplexFloat, b: ComplexFloat) ComplexFloat;
+extern fn c_cmultd(a: ComplexDouble, b: ComplexDouble) ComplexDouble;
+
+test "C ABI complex float" {
+    if (true) return error.SkipZigTest; // See https://github.com/ziglang/zig/issues/8465
+
+    const a = ComplexFloat{ .real = 1.25, .imag = 2.6 };
+    const b = ComplexFloat{ .real = 11.3, .imag = -1.5 };
+
+    const z = c_cmultf(a, b);
+    expect(z.real == 1.5) catch @panic("test failure: zig_complex_float 1");
+    expect(z.imag == 13.5) catch @panic("test failure: zig_complex_float 2");
+}
+
+test "C ABI complex float by component" {
+    const a = ComplexFloat{ .real = 1.25, .imag = 2.6 };
+    const b = ComplexFloat{ .real = 11.3, .imag = -1.5 };
+
+    const z2 = c_cmultf_comp(a.real, a.imag, b.real, b.imag);
+    expect(z2.real == 1.5) catch @panic("test failure: zig_complex_float 3");
+    expect(z2.imag == 13.5) catch @panic("test failure: zig_complex_float 4");
+}
+
+test "C ABI complex double" {
+    const a = ComplexDouble{ .real = 1.25, .imag = 2.6 };
+    const b = ComplexDouble{ .real = 11.3, .imag = -1.5 };
+
+    const z = c_cmultd(a, b);
+    expect(z.real == 1.5) catch @panic("test failure: zig_complex_double 1");
+    expect(z.imag == 13.5) catch @panic("test failure: zig_complex_double 2");
+}
+
+test "C ABI complex double by component" {
+    const a = ComplexDouble{ .real = 1.25, .imag = 2.6 };
+    const b = ComplexDouble{ .real = 11.3, .imag = -1.5 };
+
+    const z = c_cmultd_comp(a.real, a.imag, b.real, b.imag);
+    expect(z.real == 1.5) catch @panic("test failure: zig_complex_double 3");
+    expect(z.imag == 13.5) catch @panic("test failure: zig_complex_double 4");
+}
+
+export fn zig_cmultf(a: ComplexFloat, b: ComplexFloat) ComplexFloat {
+    expect(a.real == 1.25) catch @panic("test failure: zig_cmultf 1");
+    expect(a.imag == 2.6) catch @panic("test failure: zig_cmultf 2");
+    expect(b.real == 11.3) catch @panic("test failure: zig_cmultf 3");
+    expect(b.imag == -1.5) catch @panic("test failure: zig_cmultf 4");
+
+    return .{ .real = 1.5, .imag = 13.5 };
+}
+
+export fn zig_cmultd(a: ComplexDouble, b: ComplexDouble) ComplexDouble {
+    expect(a.real == 1.25) catch @panic("test failure: zig_cmultd 1");
+    expect(a.imag == 2.6) catch @panic("test failure: zig_cmultd 2");
+    expect(b.real == 11.3) catch @panic("test failure: zig_cmultd 3");
+    expect(b.imag == -1.5) catch @panic("test failure: zig_cmultd 4");
+
+    return .{ .real = 1.5, .imag = 13.5 };
+}
+
+export fn zig_cmultf_comp(a_r: f32, a_i: f32, b_r: f32, b_i: f32) ComplexFloat {
+    expect(a_r == 1.25) catch @panic("test failure: zig_cmultf_comp 1");
+    expect(a_i == 2.6) catch @panic("test failure: zig_cmultf_comp 2");
+    expect(b_r == 11.3) catch @panic("test failure: zig_cmultf_comp 3");
+    expect(b_i == -1.5) catch @panic("test failure: zig_cmultf_comp 4");
+
+    return .{ .real = 1.5, .imag = 13.5 };
+}
+
+export fn zig_cmultd_comp(a_r: f64, a_i: f64, b_r: f64, b_i: f64) ComplexDouble {
+    expect(a_r == 1.25) catch @panic("test failure: zig_cmultd_comp 1");
+    expect(a_i == 2.6) catch @panic("test failure: zig_cmultd_comp 2");
+    expect(b_r == 11.3) catch @panic("test failure: zig_cmultd_comp 3");
+    expect(b_i == -1.5) catch @panic("test failure: zig_cmultd_comp 4");
+
+    return .{ .real = 1.5, .imag = 13.5 };
+}
+
 const BigStruct = extern struct {
     a: u64,
     b: u64,