| // RUN: %clang_builtins %s %librt -lm -o %t && %run %t |
| // REQUIRES: librt_has_divtc3 |
| // REQUIRES: c99-complex |
| |
| // |
| // This test should be XFAILed on 32-bit sparc (sparc-target-arch, Issue |
| // #41838), but that is currently hidden, which caused an XPASS (Issue #72398). |
| // |
| #include <stdio.h> |
| |
| #include "int_lib.h" |
| #include "int_math.h" |
| #include <complex.h> |
| #include <math.h> |
| |
| // Returns: the quotient of (a + ib) / (c + id) |
| #if defined(CRT_HAS_TF_MODE) |
| |
| COMPILER_RT_ABI Qcomplex __divtc3(tf_float __a, tf_float __b, tf_float __c, |
| tf_float __d); |
| |
| enum {zero, non_zero, inf, NaN, non_zero_nan}; |
| |
| static int classify(Qcomplex x) { |
| tf_float real = COMPLEXTF_REAL(x); |
| tf_float imag = COMPLEXTF_IMAGINARY(x); |
| if (real == 0.0 && imag == 0.0) |
| return zero; |
| if (crt_isinf(real) || crt_isinf(imag)) |
| return inf; |
| if (crt_isnan(real) && crt_isnan(imag)) |
| return NaN; |
| if (crt_isnan(real)) { |
| if (imag == 0.0) |
| return NaN; |
| return non_zero_nan; |
| } |
| if (crt_isnan(imag)) { |
| if (real == 0.0) |
| return NaN; |
| return non_zero_nan; |
| } |
| return non_zero; |
| } |
| |
| static int test__divtc3(tf_float a, tf_float b, tf_float c, tf_float d) { |
| Qcomplex r = __divtc3(a, b, c, d); |
| Qcomplex dividend; |
| Qcomplex divisor; |
| |
| COMPLEXTF_REAL(dividend) = a; |
| COMPLEXTF_IMAGINARY(dividend) = b; |
| COMPLEXTF_REAL(divisor) = c; |
| COMPLEXTF_IMAGINARY(divisor) = d; |
| |
| switch (classify(dividend)) { |
| case zero: |
| switch (classify(divisor)) { |
| case zero: |
| if (classify(r) != NaN) |
| return 1; |
| break; |
| case non_zero: |
| if (classify(r) != zero) |
| return 1; |
| break; |
| case inf: |
| if (classify(r) != zero) |
| return 1; |
| break; |
| case NaN: |
| if (classify(r) != NaN) |
| return 1; |
| break; |
| case non_zero_nan: |
| if (classify(r) != NaN) |
| return 1; |
| break; |
| } |
| break; |
| case non_zero: |
| switch (classify(divisor)) { |
| case zero: |
| if (classify(r) != inf) |
| return 1; |
| break; |
| case non_zero: |
| if (classify(r) != non_zero) |
| return 1; |
| { |
| tf_float zReal = (a * c + b * d) / (c * c + d * d); |
| tf_float zImag = (b * c - a * d) / (c * c + d * d); |
| Qcomplex diff = |
| __divtc3(COMPLEXTF_REAL(r) - zReal, COMPLEXTF_IMAGINARY(r) - zImag, |
| COMPLEXTF_REAL(r), COMPLEXTF_IMAGINARY(r)); |
| // cabsl(z) == hypotl(creall(z), cimagl(z)) |
| #ifdef CRT_LDBL_128BIT |
| if (hypotl(COMPLEXTF_REAL(diff), COMPLEXTF_IMAGINARY(diff)) > 1.e-6) |
| #else |
| // Avoid dependency on __trunctfxf2 for ld80 platforms and use double instead. |
| if (hypot(COMPLEXTF_REAL(diff), COMPLEXTF_IMAGINARY(diff)) > 1.e-6) |
| #endif |
| return 1; |
| } |
| break; |
| case inf: |
| if (classify(r) != zero) |
| return 1; |
| break; |
| case NaN: |
| if (classify(r) != NaN) |
| return 1; |
| break; |
| case non_zero_nan: |
| if (classify(r) != NaN) |
| return 1; |
| break; |
| } |
| break; |
| case inf: |
| switch (classify(divisor)) { |
| case zero: |
| if (classify(r) != inf) |
| return 1; |
| break; |
| case non_zero: |
| if (classify(r) != inf) |
| return 1; |
| break; |
| case inf: |
| if (classify(r) != NaN) |
| return 1; |
| break; |
| case NaN: |
| if (classify(r) != NaN) |
| return 1; |
| break; |
| case non_zero_nan: |
| if (classify(r) != NaN) |
| return 1; |
| break; |
| } |
| break; |
| case NaN: |
| switch (classify(divisor)) { |
| case zero: |
| if (classify(r) != NaN) |
| return 1; |
| break; |
| case non_zero: |
| if (classify(r) != NaN) |
| return 1; |
| break; |
| case inf: |
| if (classify(r) != NaN) |
| return 1; |
| break; |
| case NaN: |
| if (classify(r) != NaN) |
| return 1; |
| break; |
| case non_zero_nan: |
| if (classify(r) != NaN) |
| return 1; |
| break; |
| } |
| break; |
| case non_zero_nan: |
| switch (classify(divisor)) { |
| case zero: |
| if (classify(r) != inf) |
| return 1; |
| break; |
| case non_zero: |
| if (classify(r) != NaN) |
| return 1; |
| break; |
| case inf: |
| if (classify(r) != NaN) |
| return 1; |
| break; |
| case NaN: |
| if (classify(r) != NaN) |
| return 1; |
| break; |
| case non_zero_nan: |
| if (classify(r) != NaN) |
| return 1; |
| break; |
| } |
| break; |
| } |
| |
| return 0; |
| } |
| |
| tf_float x[][2] = {{1.e-6, 1.e-6}, |
| {-1.e-6, 1.e-6}, |
| {-1.e-6, -1.e-6}, |
| {1.e-6, -1.e-6}, |
| |
| {1.e+6, 1.e-6}, |
| {-1.e+6, 1.e-6}, |
| {-1.e+6, -1.e-6}, |
| {1.e+6, -1.e-6}, |
| |
| {1.e-6, 1.e+6}, |
| {-1.e-6, 1.e+6}, |
| {-1.e-6, -1.e+6}, |
| {1.e-6, -1.e+6}, |
| |
| {1.e+6, 1.e+6}, |
| {-1.e+6, 1.e+6}, |
| {-1.e+6, -1.e+6}, |
| {1.e+6, -1.e+6}, |
| |
| {NAN, NAN}, |
| {-INFINITY, NAN}, |
| {-2, NAN}, |
| {-1, NAN}, |
| {-0.5, NAN}, |
| {-0., NAN}, |
| {+0., NAN}, |
| {0.5, NAN}, |
| {1, NAN}, |
| {2, NAN}, |
| {INFINITY, NAN}, |
| |
| {NAN, -INFINITY}, |
| {-INFINITY, -INFINITY}, |
| {-2, -INFINITY}, |
| {-1, -INFINITY}, |
| {-0.5, -INFINITY}, |
| {-0., -INFINITY}, |
| {+0., -INFINITY}, |
| {0.5, -INFINITY}, |
| {1, -INFINITY}, |
| {2, -INFINITY}, |
| {INFINITY, -INFINITY}, |
| |
| {NAN, -2}, |
| {-INFINITY, -2}, |
| {-2, -2}, |
| {-1, -2}, |
| {-0.5, -2}, |
| {-0., -2}, |
| {+0., -2}, |
| {0.5, -2}, |
| {1, -2}, |
| {2, -2}, |
| {INFINITY, -2}, |
| |
| {NAN, -1}, |
| {-INFINITY, -1}, |
| {-2, -1}, |
| {-1, -1}, |
| {-0.5, -1}, |
| {-0., -1}, |
| {+0., -1}, |
| {0.5, -1}, |
| {1, -1}, |
| {2, -1}, |
| {INFINITY, -1}, |
| |
| {NAN, -0.5}, |
| {-INFINITY, -0.5}, |
| {-2, -0.5}, |
| {-1, -0.5}, |
| {-0.5, -0.5}, |
| {-0., -0.5}, |
| {+0., -0.5}, |
| {0.5, -0.5}, |
| {1, -0.5}, |
| {2, -0.5}, |
| {INFINITY, -0.5}, |
| |
| {NAN, -0.}, |
| {-INFINITY, -0.}, |
| {-2, -0.}, |
| {-1, -0.}, |
| {-0.5, -0.}, |
| {-0., -0.}, |
| {+0., -0.}, |
| {0.5, -0.}, |
| {1, -0.}, |
| {2, -0.}, |
| {INFINITY, -0.}, |
| |
| {NAN, 0.}, |
| {-INFINITY, 0.}, |
| {-2, 0.}, |
| {-1, 0.}, |
| {-0.5, 0.}, |
| {-0., 0.}, |
| {+0., 0.}, |
| {0.5, 0.}, |
| {1, 0.}, |
| {2, 0.}, |
| {INFINITY, 0.}, |
| |
| {NAN, 0.5}, |
| {-INFINITY, 0.5}, |
| {-2, 0.5}, |
| {-1, 0.5}, |
| {-0.5, 0.5}, |
| {-0., 0.5}, |
| {+0., 0.5}, |
| {0.5, 0.5}, |
| {1, 0.5}, |
| {2, 0.5}, |
| {INFINITY, 0.5}, |
| |
| {NAN, 1}, |
| {-INFINITY, 1}, |
| {-2, 1}, |
| {-1, 1}, |
| {-0.5, 1}, |
| {-0., 1}, |
| {+0., 1}, |
| {0.5, 1}, |
| {1, 1}, |
| {2, 1}, |
| {INFINITY, 1}, |
| |
| {NAN, 2}, |
| {-INFINITY, 2}, |
| {-2, 2}, |
| {-1, 2}, |
| {-0.5, 2}, |
| {-0., 2}, |
| {+0., 2}, |
| {0.5, 2}, |
| {1, 2}, |
| {2, 2}, |
| {INFINITY, 2}, |
| |
| {NAN, INFINITY}, |
| {-INFINITY, INFINITY}, |
| {-2, INFINITY}, |
| {-1, INFINITY}, |
| {-0.5, INFINITY}, |
| {-0., INFINITY}, |
| {+0., INFINITY}, |
| {0.5, INFINITY}, |
| {1, INFINITY}, |
| {2, INFINITY}, |
| {INFINITY, INFINITY} |
| |
| }; |
| |
| int main() { |
| const unsigned N = sizeof(x) / sizeof(x[0]); |
| unsigned i, j; |
| for (i = 0; i < N; ++i) { |
| for (j = 0; j < N; ++j) { |
| if (test__divtc3(x[i][0], x[i][1], x[j][0], x[j][1])) { |
| fprintf(stderr, "Failed for %g, %g, %g, %g\n", (double)x[i][0], |
| (double)x[i][1], (double)x[j][0], (double)x[j][1]); |
| return 1; |
| } |
| } |
| } |
| |
| fprintf(stderr, "No errors found.\n"); |
| return 0; |
| } |
| |
| #else |
| |
| int main() { |
| printf("skipped\n"); |
| return 0; |
| } |
| |
| #endif // CRT_HAS_TF_MODE |