|  | // 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 |