376 lines
9.2 KiB
C
376 lines
9.2 KiB
C
|
// 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
|