diff --git a/BitInt_fixdfqi_test.c b/BitInt_fixdfqi_test.c new file mode 100644 --- /dev/null +++ b/BitInt_fixdfqi_test.c @@ -0,0 +1,127 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t +// REQUIRES: librt_has_fixsfqi +// REQUIRES: int128 + +#include + +// Returns: convert a to a signed long long, rounding toward zero. + +// Assumption: float is a IEEE 32 bit floating point type +// su_int is a 32 bit integral type +// value in float is representable in _BitInt(256) (no range checking performed) + +// seee eeee emmm mmmm mmmm mmmm mmmm mmmm + +typedef union { + _BitInt(256) all; + struct { + unsigned long long t0; + unsigned long long t1; + unsigned long long t2; + signed long long t3; + } s; +} twords; + +static __inline _BitInt(256) make_qi(long long t3, long long t2, + long long t1, long long t0) { + twords r; + r.s.t3 = t3; + r.s.t2 = t2; + r.s.t1 = t1; + r.s.t0 = t0; + return r.all; +} + +int test__fixdfqi(double a, _BitInt(256) expected) +{ + _BitInt(256) x = a; + if (x != expected) + { + twords xt; + xt.all = x; + twords expectedt; + expectedt.all = expected; + printf("error in __fixsfqi(%A) = 0x%.16llX%.16llX%.16llX%.16llX, expected 0x%.16llX%.16llX%.16llX%.16llX\n", + a, xt.s.t3, xt.s.t2, xt.s.t1, xt.s.t0, expectedt.s.t3, expectedt.s.t2, expectedt.s.t1, expectedt.s.t0); + } + return x != expected; +} + +int main() +{ + if (test__fixdfqi(0.0, 0)) + return 1; + + if (test__fixdfqi(0.5, 0)) + return 1; + if (test__fixdfqi(0.99, 0)) + return 1; + if (test__fixdfqi(1.0, 1)) + return 1; + if (test__fixdfqi(1.5, 1)) + return 1; + if (test__fixdfqi(1.99, 1)) + return 1; + if (test__fixdfqi(2.0, 2)) + return 1; + if (test__fixdfqi(2.01, 2)) + return 1; + if (test__fixdfqi(-0.5, 0)) + return 1; + if (test__fixdfqi(-0.99, 0)) + return 1; + if (test__fixdfqi(-1.0, -1)) + return 1; + if (test__fixdfqi(-1.5, -1)) + return 1; + if (test__fixdfqi(-1.99, -1)) + return 1; + if (test__fixdfqi(-2.0, -2)) + return 1; + if (test__fixdfqi(-2.01, -2)) + return 1; + + if (test__fixdfqi(0x1.FFFFFEp+62, 0x7FFFFF8000000000LL)) + return 1; + if (test__fixdfqi(0x1.FFFFFCp+62, 0x7FFFFF0000000000LL)) + return 1; + + if (test__fixdfqi(-0x1.FFFFFEp+62, make_qi(0xFFFFFFFFFFFFFFFFLL, + 0xFFFFFFFFFFFFFFFFLL, + 0xFFFFFFFFFFFFFFFFLL, + 0x8000008000000000LL))) + return 1; + if (test__fixdfqi(-0x1.FFFFFCp+62, make_qi(0xFFFFFFFFFFFFFFFFLL, + 0xFFFFFFFFFFFFFFFFLL, + 0xFFFFFFFFFFFFFFFFLL, + 0x8000010000000000LL))) + return 1; + + // if (test__fixdfqi(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFFFFFFFC00LL)) + // return 1; + // if (test__fixdfqi(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFFFFFFF800LL)) + // return 1; + + // if (test__fixdfqi(-0x1.FFFFFFFFFFFFFp+62, make_qi(0xFFFFFFFFFFFFFFFFLL, + // 0xFFFFFFFFFFFFFFFFLL, + // 0xFFFFFFFFFFFFFFFFLL, + // 0x8000000000000400LL))) + // return 1; + // if (test__fixdfqi(-0x1.FFFFFFFFFFFFEp+62, make_qi(0xFFFFFFFFFFFFFFFFLL, + // 0xFFFFFFFFFFFFFFFFLL, + // 0xFFFFFFFFFFFFFFFFLL, + // 0x8000000000000800LL))) + // return 1; + + // if (test__fixdfqi(0x1.FFFFFFFFFFFFFp+126, make_qi(0, 0, 0x7FFFFFFFFFFFFC00LL, 0))) + // return 1; + // if (test__fixdfqi(0x1.FFFFFFFFFFFFEp+126, make_qi(0, 0, 0x7FFFFFFFFFFFF800LL, 0))) + // return 1; + + // if (test__fixdfqi(-0x1.FFFFFFFFFFFFFp+126, make_qi(0x8000000000000400LL, 0, 0, 0))) + // return 1; + // if (test__fixdfqi(-0x1.FFFFFFFFFFFFEp+126, make_qi(0x8000000000000800LL, 0, 0, 0))) + // return 1; + printf("passed\n"); + return 0; +} diff --git a/BitInt_fixsfqi_test.c b/BitInt_fixsfqi_test.c new file mode 100644 --- /dev/null +++ b/BitInt_fixsfqi_test.c @@ -0,0 +1,113 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t +// REQUIRES: librt_has_fixsfqi +// REQUIRES: int128 + +#include + +// Returns: convert a to a signed long long, rounding toward zero. + +// Assumption: float is a IEEE 32 bit floating point type +// su_int is a 32 bit integral type +// value in float is representable in _BitInt(256) (no range checking performed) + +// seee eeee emmm mmmm mmmm mmmm mmmm mmmm + +typedef union { + _BitInt(256) all; + struct { + unsigned long long t0; + unsigned long long t1; + unsigned long long t2; + signed long long t3; + } s; +} twords; + +static __inline _BitInt(256) make_qi(long long t3, long long t2, + long long t1, long long t0) { + twords r; + r.s.t3 = t3; + r.s.t2 = t2; + r.s.t1 = t1; + r.s.t0 = t0; + return r.all; +} + +int test__fixsfqi(float a, _BitInt(256) expected) +{ + _BitInt(256) x = a; + if (x != expected) + { + twords xt; + xt.all = x; + twords expectedt; + expectedt.all = expected; + printf("error in __fixsfqi(%A) = 0x%.16llX%.16llX%.16llX%.16llX, expected 0x%.16llX%.16llX%.16llX%.16llX\n", + a, xt.s.t3, xt.s.t2, xt.s.t1, xt.s.t0, expectedt.s.t3, expectedt.s.t2, expectedt.s.t1, expectedt.s.t0); + } + return x != expected; +} + +int main() +{ + if (test__fixsfqi(0.0F, 0)) + return 1; + + if (test__fixsfqi(0.5F, 0)) + return 1; + if (test__fixsfqi(0.99F, 0)) + return 1; + if (test__fixsfqi(1.0F, 1)) + return 1; + if (test__fixsfqi(1.5F, 1)) + return 1; + if (test__fixsfqi(1.99F, 1)) + return 1; + if (test__fixsfqi(2.0F, 2)) + return 1; + if (test__fixsfqi(2.01F, 2)) + return 1; + if (test__fixsfqi(-0.5F, 0)) + return 1; + if (test__fixsfqi(-0.99F, 0)) + return 1; + if (test__fixsfqi(-1.0F, -1)) + return 1; + if (test__fixsfqi(-1.5F, -1)) + return 1; + if (test__fixsfqi(-1.99F, -1)) + return 1; + if (test__fixsfqi(-2.0F, -2)) + return 1; + if (test__fixsfqi(-2.01F, -2)) + return 1; + + if (test__fixsfqi(0x1.FFFFFEp+62F, 0x7FFFFF8000000000LL)) + return 1; + if (test__fixsfqi(0x1.FFFFFCp+62F, 0x7FFFFF0000000000LL)) + return 1; + + if (test__fixsfqi(-0x1.FFFFFEp+62F, make_qi(0xFFFFFFFFFFFFFFFFLL, + 0xFFFFFFFFFFFFFFFFLL, + 0xFFFFFFFFFFFFFFFFLL, + 0x8000008000000000LL))) + return 1; + if (test__fixsfqi(-0x1.FFFFFCp+62F, make_qi(0xFFFFFFFFFFFFFFFFLL, + 0xFFFFFFFFFFFFFFFFLL, + 0xFFFFFFFFFFFFFFFFLL, + 0x8000010000000000LL))) + return 1; + + if (test__fixsfqi(0x1.FFFFFEp+126F, make_qi(0, 0, 0x7FFFFF8000000000LL, 0))) + return 1; + if (test__fixsfqi(0x1.FFFFFCp+126F, make_qi(0, 0, 0x7FFFFF0000000000LL, 0))) + return 1; + + if (test__fixsfqi(-0x1.FFFFFEp+126F, make_qi(0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, + 0x8000008000000000LL, 0))) + return 1; + if (test__fixsfqi(-0x1.FFFFFCp+126F, make_qi(0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, + 0x8000010000000000LL, 0))) + return 1; + printf("passed\n"); + return 0; +} diff --git a/BitInt_fixunsdfqi_test.c b/BitInt_fixunsdfqi_test.c new file mode 100644 --- /dev/null +++ b/BitInt_fixunsdfqi_test.c @@ -0,0 +1,130 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t +// REQUIRES: librt_has_fixunsdfti +// REQUIRES: int128 + +#include + + +// Returns: convert a to a unsigned long long, rounding toward zero. +// Negative values all become zero. + +// Assumption: float is a IEEE 32 bit floating point type +// unsigned _BitInt(256) is a 64 bit integral type +// value in float is representable in unsigned _BitInt(256) or is negative +// (no range checking performed) + +// seee eeee emmm mmmm mmmm mmmm mmmm mmmm + +typedef union { + _BitInt(256) all; + struct { + unsigned long long t0; + unsigned long long t1; + unsigned long long t2; + unsigned long long t3; + } s; +} utwords; + +static __inline _BitInt(256) make_qi(long long t3, long long t2, + long long t1, long long t0) { + utwords r; + r.s.t3 = t3; + r.s.t2 = t2; + r.s.t1 = t1; + r.s.t0 = t0; + return r.all; +} + +int test__fixunsdfti(double a, unsigned _BitInt(256) expected) +{ + unsigned _BitInt(256) x = a; + if (x != expected) + { + utwords xt; + xt.all = x; + utwords expectedt; + expectedt.all = expected; + printf("error in __fixunsdfti(%A) = 0x%.16llX%.16llX%.16llX%.16llX, expected 0x%.16llX%.16llX%.16llX%.16llX\n", + a, xt.s.t3, xt.s.t2, xt.s.t1, xt.s.t0, expectedt.s.t3, expectedt.s.t2, expectedt.s.t1, expectedt.s.t0); + } + return x != expected; +} + +int main() +{ + if (test__fixunsdfti(0.0, 0)) + return 1; + + if (test__fixunsdfti(0.5, 0)) + return 1; + if (test__fixunsdfti(0.99, 0)) + return 1; + if (test__fixunsdfti(1.0, 1)) + return 1; + if (test__fixunsdfti(1.5, 1)) + return 1; + if (test__fixunsdfti(1.99, 1)) + return 1; + if (test__fixunsdfti(2.0, 2)) + return 1; + if (test__fixunsdfti(2.01, 2)) + return 1; + if (test__fixunsdfti(-0.5, 0)) + return 1; + if (test__fixunsdfti(-0.99, 0)) + return 1; +#if TARGET_LIBGCC + if (test__fixunsdfti(-1.0, 0)) // libgcc ignores "returns 0 for negative input" spec + return 1; + if (test__fixunsdfti(-1.5, 0)) + return 1; + if (test__fixunsdfti(-1.99, 0)) + return 1; + if (test__fixunsdfti(-2.0, 0)) + return 1; + if (test__fixunsdfti(-2.01, 0)) + return 1; +#endif + + if (test__fixunsdfti(0x1.FFFFFEp+62, 0x7FFFFF8000000000LL)) + return 1; + if (test__fixunsdfti(0x1.FFFFFCp+62, 0x7FFFFF0000000000LL)) + return 1; + +#if TARGET_LIBGCC + if (test__fixunsdfti(-0x1.FFFFFEp+62, 0)) + return 1; + if (test__fixunsdfti(-0x1.FFFFFCp+62, 0)) + return 1; +#endif + + // if (test__fixunsdfti(0x1.FFFFFFFFFFFFFp+63, 0xFFFFFFFFFFFFF800ULL)) + // return 1; + // if (test__fixunsdfti(0x1.0000000000000p+63, 0x8000000000000000ULL)) + // return 1; + // if (test__fixunsdfti(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFFFFFFFC00ULL)) + // return 1; + // if (test__fixunsdfti(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFFFFFFF800ULL)) + // return 1; + + // if (test__fixunsdfti(0x1.FFFFFFFFFFFFFp+127, make_qi(0, 0, 0xFFFFFFFFFFFFF800ULL, 0))) + // return 1; + // if (test__fixunsdfti(0x1.0000000000000p+127, make_qi(0, 0, 0x8000000000000000ULL, 0))) + // return 1; + // if (test__fixunsdfti(0x1.FFFFFFFFFFFFFp+126, make_qi(0, 0, 0x7FFFFFFFFFFFFC00ULL, 0))) + // return 1; + // if (test__fixunsdfti(0x1.FFFFFFFFFFFFEp+126, make_qi(0, 0, 0x7FFFFFFFFFFFF800ULL, 0))) + // return 1; + // if (test__fixunsdfti(0x1.0000000000000p+128, make_qi(0, 0, 0xFFFFFFFFFFFFFFFFULL, + // 0xFFFFFFFFFFFFFFFFULL))) + // return 1; + +#if TARGET_LIBGCC + if (test__fixunsdfti(-0x1.FFFFFFFFFFFFFp+62, 0)) + return 1; + if (test__fixunsdfti(-0x1.FFFFFFFFFFFFEp+62, 0)) + return 1; +#endif + printf("passed\n"); + return 0; +} diff --git a/BitInt_fixunssfqi_test.c b/BitInt_fixunssfqi_test.c new file mode 100644 --- /dev/null +++ b/BitInt_fixunssfqi_test.c @@ -0,0 +1,120 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t +// REQUIRES: librt_has_fixunssfti +// REQUIRES: int128 + +#include + + +// Returns: convert a to a unsigned long long, rounding toward zero. +// Negative values all become zero. + +// Assumption: float is a IEEE 32 bit floating point type +// unsigned _BitInt(256) is a 64 bit integral type +// value in float is representable in unsigned _BitInt(256) or is negative +// (no range checking performed) + +// seee eeee emmm mmmm mmmm mmmm mmmm mmmm + +typedef union { + _BitInt(256) all; + struct { + unsigned long long t0; + unsigned long long t1; + unsigned long long t2; + unsigned long long t3; + } s; +} utwords; + +static __inline _BitInt(256) make_qi(long long t3, long long t2, + long long t1, long long t0) { + utwords r; + r.s.t3 = t3; + r.s.t2 = t2; + r.s.t1 = t1; + r.s.t0 = t0; + return r.all; +} + +int test__fixunssfti(float a, unsigned _BitInt(256) expected) +{ + unsigned _BitInt(256) x = a; + if (x != expected) + { + utwords xt; + xt.all = x; + utwords expectedt; + expectedt.all = expected; + printf("error in __fixunssfti(%A) = 0x%.16llX%.16llX%.16llX%.16llX, expected 0x%.16llX%.16llX%.16llX%.16llX\n", + a, xt.s.t3, xt.s.t2, xt.s.t1, xt.s.t0, expectedt.s.t3, expectedt.s.t2, expectedt.s.t1, expectedt.s.t0); + } + return x != expected; +} + +int main() +{ + if (test__fixunssfti(0.0F, 0)) + return 1; + if (test__fixunssfti(0.5F, 0)) + return 1; + if (test__fixunssfti(0.99F, 0)) + return 1; + if (test__fixunssfti(1.0F, 1)) + return 1; + if (test__fixunssfti(1.5F, 1)) + return 1; + if (test__fixunssfti(1.99F, 1)) + return 1; + if (test__fixunssfti(2.0F, 2)) + return 1; + if (test__fixunssfti(2.01F, 2)) + return 1; + if (test__fixunssfti(-0.5F, 0)) + return 1; + if (test__fixunssfti(-0.99F, 0)) + return 1; +#if TARGET_LIBGCC + if (test__fixunssfti(-1.0F, 0)) // libgcc ignores "returns 0 for negative input" spec + return 1; + if (test__fixunssfti(-1.5F, 0)) + return 1; + if (test__fixunssfti(-1.99F, 0)) + return 1; + if (test__fixunssfti(-2.0F, 0)) + return 1; + if (test__fixunssfti(-2.01F, 0)) + return 1; +#endif + + if (test__fixunssfti(0x1.FFFFFEp+63F, 0xFFFFFF0000000000ULL)) + return 1; + if (test__fixunssfti(0x1.000000p+63F, 0x8000000000000000ULL)) + return 1; + if (test__fixunssfti(0x1.FFFFFEp+62F, 0x7FFFFF8000000000LL)) + return 1; + if (test__fixunssfti(0x1.FFFFFCp+62F, 0x7FFFFF0000000000LL)) + return 1; + + if (test__fixunssfti(0x1.FFFFFEp+127F, make_qi(0, 0, 0xFFFFFF0000000000ULL, 0))) + return 1; + if (test__fixunssfti(0x1.000000p+127F, make_qi(0, 0, 0x8000000000000000ULL, 0))) + return 1; + if (test__fixunssfti(0x1.FFFFFEp+126F, make_qi(0, 0, 0x7FFFFF8000000000LL, 0))) + return 1; + if (test__fixunssfti(0x1.FFFFFCp+126F, make_qi(0, 0, 0x7FFFFF0000000000LL, 0))) + return 1; + +#if TARGET_LIBGCC + if (test__fixunssfti(-0x1.FFFFFEp+62F, 0x0000000000000000LL)) + return 1; + if (test__fixunssfti(-0x1.FFFFFCp+62F, 0x0000000000000000LL)) + return 1; + if (test__fixunssfti(-0x1.FFFFFEp+126F, 0x0000000000000000LL)) + return 1; + if (test__fixunssfti(-0x1.FFFFFCp+126F, 0x0000000000000000LL)) + return 1; +#endif + if (test__fixunssfti(-2.01F, -2)) + return 1; + printf("passed\n"); + return 0; +} diff --git a/BitInt_floatqidf_test.c b/BitInt_floatqidf_test.c new file mode 100644 --- /dev/null +++ b/BitInt_floatqidf_test.c @@ -0,0 +1,173 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t +// REQUIRES: librt_has_floatqidf +// REQUIRES: int128 + +#include +#include + +// Returns: convert a to a double, rounding toward even. + +// Assumption: double is a IEEE 64 bit floating point type +// _BitInt(256) is a 64 bit integral type + +// seee eeee eeee mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm + +typedef union { + _BitInt(256) all; + struct { + unsigned long long t0; + unsigned long long t1; + unsigned long long t2; + signed long long t3; + } s; +} twords; + +static __inline _BitInt(256) make_qi(long long t3, long long t2, + long long t1, long long t0) { + twords r; + r.s.t3 = t3; + r.s.t2 = t2; + r.s.t1 = t1; + r.s.t0 = t0; + return r.all; +} + +double __floatqidf(_BitInt(256) a); + +int test__floatqidf(_BitInt(256) a, double expected) +{ + double x = a; + if (x != expected) + { + twords at; + at.all = a; + printf("error in __floatqidf(0x%.16llX%.16llX) = %a, expected %a\n", + at.s.t1, at.s.t0, x, expected); + } + return x != expected; +} + +int test__floatqidfNaN(_BitInt(256) a, double expected) +{ + double x = a; + if (!(x != expected)) + { + twords at; + at.all = a; + printf("error in __floatqidf(0x%.16llX%.16llX) = %a, expected %a\n", + at.s.t1, at.s.t0, x, expected); + } + return !(x != expected); +} + +int main() +{ + if (test__floatqidf(0, 0.0)) + return 1; + + if (test__floatqidf(1, 1.0)) + return 1; + if (test__floatqidf(2, 2.0)) + return 1; + if (test__floatqidf(20, 20.0)) + return 1; + if (test__floatqidf(-1, -1.0)) + return 1; + if (test__floatqidf(-2, -2.0)) + return 1; + + if (test__floatqidf(0x7FFFFF8000000000LL, 0x1.FFFFFEp+62)) + return 1; + // if (test__floatqidf(0x7FFFFFFFFFFFF800LL, 0x1.FFFFFFFFFFFFEp+62)) + // return 1; + if (test__floatqidf(0x7FFFFF0000000000LL, 0x1.FFFFFCp+62)) + return 1; + // if (test__floatqidf(0x7FFFFFFFFFFFF000LL, 0x1.FFFFFFFFFFFFCp+62)) + // return 1; + + // if (test__floatqidf(make_qi(0x8000008000000000LL, 0, 0, 0), -0x1.FFFFFEp+126)) + // return 1; + // if (test__floatqidf(make_qi(0x8000000000000800LL, 0, 0, 0), -0x1.FFFFFFFFFFFFEp+126)) + // return 1; + // if (test__floatqidf(make_qi(0x8000010000000000LL, 0, 0, 0), -0x1.FFFFFCp+126)) + // return 1; + // if (test__floatqidf(make_qi(0x8000000000001000LL, 0, 0, 0), -0x1.FFFFFFFFFFFFCp+126)) + // return 1; + + // if (test__floatqidf(make_qi(0x8000000000000000LL, 0, 0, 0), -0x1.000000p+127)) + // return 1; + // if (test__floatqidf(make_qi(0x8000000000000001LL, 0, 0, 0), -0x1.000000p+127)) + // return 1; + + if (test__floatqidf(make_qi(0xFFFFFFFFFFFFFFFFLL, 0xFFFFFFFFFFFFFFFFLL, + 0xFFFFFFFFFFFFFFFFLL, 0x8000008000000000LL), + -0x1.FFFFFEp+62)) + return 1; + if (test__floatqidf(make_qi(0xFFFFFFFFFFFFFFFFLL, 0xFFFFFFFFFFFFFFFFLL, + 0xFFFFFFFFFFFFFFFFLL, 0x8000010000000000LL), + -0x1.FFFFFCp+62)) + return 1; + + if (test__floatqidf(make_qi(0xFFFFFFFFFFFFFFFFLL, 0xFFFFFFFFFFFFFFFFLL, + 0xFFFFFFFFFFFFFFFFLL, 0x8000000000000000LL), + -0x1.000000p+63)) + return 1; + if (test__floatqidf(make_qi(0xFFFFFFFFFFFFFFFFLL, 0xFFFFFFFFFFFFFFFFLL, + 0xFFFFFFFFFFFFFFFFLL, 0x8000000000000001LL), + -0x1.000000p+63)) + return 1; + + if (test__floatqidf(0x0007FB72E8000000LL, 0x1.FEDCBAp+50)) + return 1; + + if (test__floatqidf(0x0007FB72EA000000LL, 0x1.FEDCBAp+50)) + return 1; + if (test__floatqidf(0x0007FB72EB000000LL, 0x1.FEDCBAp+50)) + return 1; + // if (test__floatqidf(0x0007FB72EBFFFFFFLL, 0x1.FEDCBAFFFFFFCp+50)) + // return 1; + if (test__floatqidf(0x0007FB72EBFFFFFFLL, 0x1.FEDCBAp+50)) + return 1; + if (test__floatqidf(0x0007FB72EC000000LL, 0x1.FEDCBCp+50)) + return 1; + // if (test__floatqidf(0x0007FB72E8000001LL, 0x1.FEDCBA0000004p+50)) + // return 1; + + if (test__floatqidf(0x0007FB72E6000000LL, 0x1.FEDCBAp+50)) + return 1; + if (test__floatqidf(0x0007FB72E7000000LL, 0x1.FEDCBAp+50)) + return 1; + // if (test__floatqidf(0x0007FB72E7FFFFFFLL, 0x1.FEDCB9FFFFFFCp+50)) + // return 1; + // if (test__floatqidf(0x0007FB72E4000001LL, 0x1.FEDCB90000004p+50)) + // return 1; + if (test__floatqidf(0x0007FB72E4000000LL, 0x1.FEDCB8p+50)) + return 1; + + if (test__floatqidf(make_qi(0, 0, 0x0007FB72E8000000LL, 0), 0x1.FEDCBAp+114)) + return 1; + + if (test__floatqidf(make_qi(0, 0, 0x0007FB72EA000000LL, 0), 0x1.FEDCBAp+114)) + return 1; + if (test__floatqidf(make_qi(0, 0, 0x0007FB72EB000000LL, 0), 0x1.FEDCBAp+114)) + return 1; + if (test__floatqidf(make_qi(0, 0, 0x0007FB72EBFFFFFFLL, 0), 0x1.FEDCBAp+114)) + return 1; + if (test__floatqidf(make_qi(0, 0, 0x0007FB72EC000000LL, 0), 0x1.FEDCBCp+114)) + return 1; + if (test__floatqidf(make_qi(0, 0, 0x0007FB72E8000001LL, 0), 0x1.FEDCBAp+114)) + return 1; + + if (test__floatqidf(make_qi(0, 0, 0x0007FB72E6000000LL, 0), 0x1.FEDCBAp+114)) + return 1; + if (test__floatqidf(make_qi(0, 0, 0x0007FB72E7000000LL, 0), 0x1.FEDCBAp+114)) + return 1; + if (test__floatqidf(make_qi(0, 0, 0x0007FB72E7FFFFFFLL, 0), 0x1.FEDCBAp+114)) + return 1; + if (test__floatqidf(make_qi(0, 0, 0x0007FB72E4000001LL, 0), 0x1.FEDCBAp+114)) + return 1; + if (test__floatqidf(make_qi(0, 0, 0x0007FB72E4000000LL, 0), 0x1.FEDCB8p+114)) + return 1; + printf("passed\n"); + return 0; +} diff --git a/BitInt_floatqisf_test.c b/BitInt_floatqisf_test.c new file mode 100644 --- /dev/null +++ b/BitInt_floatqisf_test.c @@ -0,0 +1,151 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t +// REQUIRES: librt_has_floattidf +// REQUIRES: int128 + +#include +#include + +// Returns: convert a to a double, rounding toward even. + +// Assumption: double is a IEEE 64 bit floating point type +// _BitInt(256) is a 64 bit integral type + +// seee eeee eeee mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm + +typedef union { + _BitInt(256) all; + struct { + unsigned long long t0; + unsigned long long t1; + unsigned long long t2; + signed long long t3; + } s; +} twords; + +static __inline _BitInt(256) make_qi(long long t3, long long t2, + long long t1, long long t0) { + twords r; + r.s.t3 = t3; + r.s.t2 = t2; + r.s.t1 = t1; + r.s.t0 = t0; + return r.all; +} + +int test__floatqisf(_BitInt(256) a, float expected) +{ + float x = a; + if (x != expected) + { + twords at; + at.all = a; + printf("error in __floatqisf(0x%.16llX%.16llX) = %a, expected %a\n", + at.s.t1, at.s.t0, x, expected); + } + return x != expected; +} + +int test__floatqisfNaN(_BitInt(256) a, float expected) +{ + float x = a; + if (!(x != expected)) + { + twords at; + at.all = a; + printf("error in __floatqisf(0x%.16llX%.16llX) = %a, expected %a\n", + at.s.t1, at.s.t0, x, expected); + } + return !(x != expected); +} + +int main() +{ + if (test__floatqisf(0, 0.0F)) + return 1; + + if (test__floatqisf(1, 1.0F)) + return 1; + if (test__floatqisf(2, 2.0F)) + return 1; + if (test__floatqisf(-1, -1.0F)) + return 1; + if (test__floatqisf(-2, -2.0F)) + return 1; + + if (test__floatqisf(0x7FFFFF8000000000LL, 0x1.FFFFFEp+62F)) + return 1; + if (test__floatqisf(0x7FFFFF0000000000LL, 0x1.FFFFFCp+62F)) + return 1; + + if (test__floatqisf(make_qi(0xFFFFFFFFFFFFFFFFLL, 0xFFFFFFFFFFFFFFFFLL, + 0xFFFFFFFFFFFFFFFFLL, 0x8000008000000000LL), + -0x1.FFFFFEp+62F)) + return 1; + if (test__floatqisf(make_qi(0xFFFFFFFFFFFFFFFFLL, 0xFFFFFFFFFFFFFFFFLL, + 0xFFFFFFFFFFFFFFFFLL, 0x8000010000000000LL), + -0x1.FFFFFCp+62F)) + return 1; + + if (test__floatqisf(make_qi(0xFFFFFFFFFFFFFFFFLL, 0xFFFFFFFFFFFFFFFFLL, + 0xFFFFFFFFFFFFFFFFLL, 0x8000000000000000LL), + -0x1.000000p+63F)) + return 1; + if (test__floatqisf(make_qi(0xFFFFFFFFFFFFFFFFLL, 0xFFFFFFFFFFFFFFFFLL, + 0xFFFFFFFFFFFFFFFFLL, 0x8000000000000001LL), + -0x1.000000p+63F)) + return 1; + + if (test__floatqisf(0x0007FB72E8000000LL, 0x1.FEDCBAp+50F)) + return 1; + + if (test__floatqisf(0x0007FB72EA000000LL, 0x1.FEDCBAp+50F)) + return 1; + if (test__floatqisf(0x0007FB72EB000000LL, 0x1.FEDCBAp+50F)) + return 1; + if (test__floatqisf(0x0007FB72EBFFFFFFLL, 0x1.FEDCBAp+50F)) + return 1; + if (test__floatqisf(0x0007FB72EC000000LL, 0x1.FEDCBCp+50F)) + return 1; + if (test__floatqisf(0x0007FB72E8000001LL, 0x1.FEDCBAp+50F)) + return 1; + + if (test__floatqisf(0x0007FB72E6000000LL, 0x1.FEDCBAp+50F)) + return 1; + if (test__floatqisf(0x0007FB72E7000000LL, 0x1.FEDCBAp+50F)) + return 1; + if (test__floatqisf(0x0007FB72E7FFFFFFLL, 0x1.FEDCBAp+50F)) + return 1; + if (test__floatqisf(0x0007FB72E4000001LL, 0x1.FEDCBAp+50F)) + return 1; + if (test__floatqisf(0x0007FB72E4000000LL, 0x1.FEDCB8p+50F)) + return 1; + + if (test__floatqisf(make_qi(0, 0, 0x0007FB72E8000000LL, 0), 0x1.FEDCBAp+114F)) + return 1; + + if (test__floatqisf(make_qi(0, 0, 0x0007FB72EA000000LL, 0), 0x1.FEDCBAp+114F)) + return 1; + if (test__floatqisf(make_qi(0, 0, 0x0007FB72EB000000LL, 0), 0x1.FEDCBAp+114F)) + return 1; + if (test__floatqisf(make_qi(0, 0, 0x0007FB72EBFFFFFFLL, 0), 0x1.FEDCBAp+114F)) + return 1; + if (test__floatqisf(make_qi(0, 0, 0x0007FB72EC000000LL, 0), 0x1.FEDCBCp+114F)) + return 1; + if (test__floatqisf(make_qi(0, 0, 0x0007FB72E8000001LL, 0), 0x1.FEDCBAp+114F)) + return 1; + + if (test__floatqisf(make_qi(0, 0, 0x0007FB72E6000000LL, 0), 0x1.FEDCBAp+114F)) + return 1; + if (test__floatqisf(make_qi(0, 0, 0x0007FB72E7000000LL, 0), 0x1.FEDCBAp+114F)) + return 1; + if (test__floatqisf(make_qi(0, 0, 0x0007FB72E7FFFFFFLL, 0), 0x1.FEDCBAp+114F)) + return 1; + if (test__floatqisf(make_qi(0, 0, 0x0007FB72E4000001LL, 0), 0x1.FEDCBAp+114F)) + return 1; + if (test__floatqisf(make_qi(0, 0, 0x0007FB72E4000000LL, 0), 0x1.FEDCB8p+114F)) + return 1; + if (test__floatqisfNaN(make_qi(0, 1, 0x0007FB72E4000000LL, 0), make_qi(0, 1, 0x0007FB72E4000000LL, 0))) + return 1; + printf("passed\n"); + return 0; +} diff --git a/BitInt_floatunqidf_test.c b/BitInt_floatunqidf_test.c new file mode 100644 --- /dev/null +++ b/BitInt_floatunqidf_test.c @@ -0,0 +1,168 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t +// REQUIRES: librt_has_floatunqidf + +#include + +// Returns: convert a to a float, rounding toward even. + +// Assumption: float is a IEEE 32 bit floating point type +// unsigned _BitInt(256) is a 128 bit integral type + +// seee eeee emmm mmmm mmmm mmmm mmmm mmmm +typedef union { + _BitInt(256) all; + struct { + unsigned long long t0; + unsigned long long t1; + unsigned long long t2; + unsigned long long t3; + } s; +} utwords; + +static __inline _BitInt(256) make_qi(long long t3, long long t2, + long long t1, long long t0) { + utwords r; + r.s.t3 = t3; + r.s.t2 = t2; + r.s.t1 = t1; + r.s.t0 = t0; + return r.all; +} + +int test__floatunqidf(unsigned _BitInt(256) a, double expected) +{ + double x = a; + if (x != expected) + { + utwords at; + at.all = a; + printf("error in __floatunqidf(0x%.16llX%.16llX%.16llX%.16llX) = %a, expected %a\n", + at.s.t3, at.s.t2, at.s.t1, at.s.t0, x, expected); + } + return x != expected; +} + +int main() +{ + if (test__floatunqidf(0, 0.0)) + return 1; + + if (test__floatunqidf(1, 1.0)) + return 1; + if (test__floatunqidf(2, 2.0)) + return 1; + if (test__floatunqidf(20, 20.0)) + return 1; + + if (test__floatunqidf(0x7FFFFF8000000000LL, 0x1.FFFFFEp+62)) + return 1; + // if (test__floatunqidf(0x7FFFFFFFFFFFF800LL, 0x1.FFFFFFFFFFFFEp+62)) + // return 1; + if (test__floatunqidf(0x7FFFFF0000000000LL, 0x1.FFFFFCp+62)) + return 1; + // if (test__floatunqidf(0x7FFFFFFFFFFFF000LL, 0x1.FFFFFFFFFFFFCp+62)) + // return 1; + + // if (test__floatunqidf(make_qi(0, 0, 0x8000008000000000LL, 0), 0x1.000001p+127)) + // return 1; + // if (test__floatunqidf(make_qi(0, 0, 0x8000000000000800LL, 0), 0x1.0000000000001p+127)) + // return 1; + // if (test__floatunqidf(make_qi(0, 0, 0x8000010000000000LL, 0), 0x1.000002p+127)) + // return 1; + // if (test__floatunqidf(make_qi(0, 0, 0x8000000000001000LL, 0), 0x1.0000000000002p+127)) + // return 1; + + // if (test__floatunqidf(make_qi(0, 0, 0x8000000000000000LL, 0), 0x1.000000p+127)) + // return 1; + // if (test__floatunqidf(make_qi(0, 0, 0x8000000000000001LL, 0), 0x1.0000000000000002p+127)) + // return 1; + + if (test__floatunqidf(0x0007FB72E8000000LL, 0x1.FEDCBAp+50)) + return 1; + + // if (test__floatunqidf(0x0007FB72EA000000LL, 0x1.FEDCBA8p+50)) + // return 1; + // if (test__floatunqidf(0x0007FB72EB000000LL, 0x1.FEDCBACp+50)) + // return 1; + // if (test__floatunqidf(0x0007FB72EBFFFFFFLL, 0x1.FEDCBAFFFFFFCp+50)) + // return 1; + // if (test__floatunqidf(0x0007FB72EC000000LL, 0x1.FEDCBBp+50)) + // return 1; + // if (test__floatunqidf(0x0007FB72E8000001LL, 0x1.FEDCBA0000004p+50)) + // return 1; + + // if (test__floatunqidf(0x0007FB72E6000000LL, 0x1.FEDCB98p+50)) + // return 1; + // if (test__floatunqidf(0x0007FB72E7000000LL, 0x1.FEDCB9Cp+50)) + // return 1; + // if (test__floatunqidf(0x0007FB72E7FFFFFFLL, 0x1.FEDCB9FFFFFFCp+50)) + // return 1; + // if (test__floatunqidf(0x0007FB72E4000001LL, 0x1.FEDCB90000004p+50)) + // return 1; + // if (test__floatunqidf(0x0007FB72E4000000LL, 0x1.FEDCB9p+50)) + // return 1; + + // if (test__floatunqidf(0x023479FD0E092DC0LL, 0x1.1A3CFE870496Ep+57)) + // return 1; + // if (test__floatunqidf(0x023479FD0E092DA1LL, 0x1.1A3CFE870496Dp+57)) + // return 1; + // if (test__floatunqidf(0x023479FD0E092DB0LL, 0x1.1A3CFE870496Ep+57)) + // return 1; + // if (test__floatunqidf(0x023479FD0E092DB8LL, 0x1.1A3CFE870496Ep+57)) + // return 1; + // if (test__floatunqidf(0x023479FD0E092DB6LL, 0x1.1A3CFE870496Ep+57)) + // return 1; + // if (test__floatunqidf(0x023479FD0E092DBFLL, 0x1.1A3CFE870496Ep+57)) + // return 1; + // if (test__floatunqidf(0x023479FD0E092DC1LL, 0x1.1A3CFE870496Ep+57)) + // return 1; + // if (test__floatunqidf(0x023479FD0E092DC7LL, 0x1.1A3CFE870496Ep+57)) + // return 1; + // if (test__floatunqidf(0x023479FD0E092DC8LL, 0x1.1A3CFE870496Ep+57)) + // return 1; + // if (test__floatunqidf(0x023479FD0E092DCFLL, 0x1.1A3CFE870496Ep+57)) + // return 1; + // if (test__floatunqidf(0x023479FD0E092DD0LL, 0x1.1A3CFE870496Ep+57)) + // return 1; + // if (test__floatunqidf(0x023479FD0E092DD1LL, 0x1.1A3CFE870496Fp+57)) + // return 1; + // if (test__floatunqidf(0x023479FD0E092DD8LL, 0x1.1A3CFE870496Fp+57)) + // return 1; + // if (test__floatunqidf(0x023479FD0E092DDFLL, 0x1.1A3CFE870496Fp+57)) + // return 1; + // if (test__floatunqidf(0x023479FD0E092DE0LL, 0x1.1A3CFE870496Fp+57)) + // return 1; + + // if (test__floatunqidf(make_qi(0, 0, 0x023479FD0E092DC0LL, 0), 0x1.1A3CFE870496Ep+121)) + // return 1; + // if (test__floatunqidf(make_qi(0, 0, 0x023479FD0E092DA1LL, 1), 0x1.1A3CFE870496Dp+121)) + // return 1; + // if (test__floatunqidf(make_qi(0, 0, 0x023479FD0E092DB0LL, 2), 0x1.1A3CFE870496Ep+121)) + // return 1; + // if (test__floatunqidf(make_qi(0, 0, 0x023479FD0E092DB8LL, 3), 0x1.1A3CFE870496Ep+121)) + // return 1; + // if (test__floatunqidf(make_qi(0, 0, 0x023479FD0E092DB6LL, 4), 0x1.1A3CFE870496Ep+121)) + // return 1; + // if (test__floatunqidf(make_qi(0, 0, 0x023479FD0E092DBFLL, 5), 0x1.1A3CFE870496Ep+121)) + // return 1; + // if (test__floatunqidf(make_qi(0, 0, 0x023479FD0E092DC1LL, 6), 0x1.1A3CFE870496Ep+121)) + // return 1; + // if (test__floatunqidf(make_qi(0, 0, 0x023479FD0E092DC7LL, 7), 0x1.1A3CFE870496Ep+121)) + // return 1; + // if (test__floatunqidf(make_qi(0, 0, 0x023479FD0E092DC8LL, 8), 0x1.1A3CFE870496Ep+121)) + // return 1; + // if (test__floatunqidf(make_qi(0, 0, 0x023479FD0E092DCFLL, 9), 0x1.1A3CFE870496Ep+121)) + // return 1; + // if (test__floatunqidf(make_qi(0, 0, 0x023479FD0E092DD0LL, 0), 0x1.1A3CFE870496Ep+121)) + // return 1; + // if (test__floatunqidf(make_qi(0, 0, 0x023479FD0E092DD1LL, 11), 0x1.1A3CFE870496Fp+121)) + // return 1; + // if (test__floatunqidf(make_qi(0, 0, 0x023479FD0E092DD8LL, 12), 0x1.1A3CFE870496Fp+121)) + // return 1; + // if (test__floatunqidf(make_qi(0, 0, 0x023479FD0E092DDFLL, 13), 0x1.1A3CFE870496Fp+121)) + // return 1; + // if (test__floatunqidf(make_qi(0, 0, 0x023479FD0E092DE0LL, 14), 0x1.1A3CFE870496Fp+121)) + // return 1; + printf("passed\n"); + return 0; +} diff --git a/BitInt_floatunqisf_test.c b/BitInt_floatunqisf_test.c new file mode 100644 --- /dev/null +++ b/BitInt_floatunqisf_test.c @@ -0,0 +1,158 @@ +// RUN: %clang_builtins %s %librt -o %t && %run %t +// REQUIRES: librt_has_floatunqisf + +#include + +// Returns: convert a to a float, rounding toward even. + +// Assumption: float is a IEEE 32 bit floating point type +// unsigned _BitInt(256) is a 128 bit integral type + +// seee eeee emmm mmmm mmmm mmmm mmmm mmmm +typedef union { + _BitInt(256) all; + struct { + unsigned long long t0; + unsigned long long t1; + unsigned long long t2; + unsigned long long t3; + } s; +} utwords; + +static __inline _BitInt(256) make_qi(long long t3, long long t2, + long long t1, long long t0) { + utwords r; + r.s.t3 = t3; + r.s.t2 = t2; + r.s.t1 = t1; + r.s.t0 = t0; + return r.all; +} + +int test__floatunqisf(unsigned _BitInt(256) a, float expected) +{ + float x = a; + if (x != expected) + { + utwords at; + at.all = a; + printf("error in __floatunqisf(0x%.16llX%.16llX%.16llX%.16llX) = %a, expected %a\n", + at.s.t3, at.s.t2, at.s.t1, at.s.t0, x, expected); + } + return x != expected; +} + +int main() +{ + if (test__floatunqisf(0, 0.0F)) + return 1; + + if (test__floatunqisf(1, 1.0F)) + return 1; + if (test__floatunqisf(2, 2.0F)) + return 1; + if (test__floatunqisf(20, 20.0F)) + return 1; + + if (test__floatunqisf(0x7FFFFF8000000000LL, 0x1.FFFFFEp+62F)) + return 1; + if (test__floatunqisf(0x7FFFFF0000000000LL, 0x1.FFFFFCp+62F)) + return 1; + + if (test__floatunqisf(make_qi(0, 0, 0x8000008000000000LL, 0), 0x1.000001p+127F)) + return 1; + if (test__floatunqisf(make_qi(0, 0, 0x8000000000000800LL, 0), 0x1.0p+127F)) + return 1; + if (test__floatunqisf(make_qi(0, 0, 0x8000010000000000LL, 0), 0x1.000002p+127F)) + return 1; + + if (test__floatunqisf(make_qi(0, 0, 0x8000000000000000LL, 0), 0x1.000000p+127F)) + return 1; + + if (test__floatunqisf(0x0007FB72E8000000LL, 0x1.FEDCBAp+50F)) + return 1; + + if (test__floatunqisf(0x0007FB72EA000000LL, 0x1.FEDCBA8p+50F)) + return 1; + if (test__floatunqisf(0x0007FB72EB000000LL, 0x1.FEDCBACp+50F)) + return 1; + + if (test__floatunqisf(0x0007FB72EC000000LL, 0x1.FEDCBBp+50F)) + return 1; + + if (test__floatunqisf(0x0007FB72E6000000LL, 0x1.FEDCB98p+50F)) + return 1; + if (test__floatunqisf(0x0007FB72E7000000LL, 0x1.FEDCB9Cp+50F)) + return 1; + if (test__floatunqisf(0x0007FB72E4000000LL, 0x1.FEDCB9p+50F)) + return 1; + + if (test__floatunqisf(0xFFFFFFFFFFFFFFFELL, 0x1p+64F)) + return 1; + if (test__floatunqisf(0xFFFFFFFFFFFFFFFFLL, 0x1p+64F)) + return 1; + + if (test__floatunqisf(0x0007FB72E8000000LL, 0x1.FEDCBAp+50F)) + return 1; + + if (test__floatunqisf(0x0007FB72EA000000LL, 0x1.FEDCBAp+50F)) + return 1; + if (test__floatunqisf(0x0007FB72EB000000LL, 0x1.FEDCBAp+50F)) + return 1; + if (test__floatunqisf(0x0007FB72EBFFFFFFLL, 0x1.FEDCBAp+50F)) + return 1; + if (test__floatunqisf(0x0007FB72EC000000LL, 0x1.FEDCBCp+50F)) + return 1; + if (test__floatunqisf(0x0007FB72E8000001LL, 0x1.FEDCBAp+50F)) + return 1; + + if (test__floatunqisf(0x0007FB72E6000000LL, 0x1.FEDCBAp+50F)) + return 1; + if (test__floatunqisf(0x0007FB72E7000000LL, 0x1.FEDCBAp+50F)) + return 1; + if (test__floatunqisf(0x0007FB72E7FFFFFFLL, 0x1.FEDCBAp+50F)) + return 1; + if (test__floatunqisf(0x0007FB72E4000001LL, 0x1.FEDCBAp+50F)) + return 1; + if (test__floatunqisf(0x0007FB72E4000000LL, 0x1.FEDCB8p+50F)) + return 1; + + if (test__floatunqisf(make_qi(0, 0, 0x0000000000001FEDLL, 0xCB90000000000001LL), + 0x1.FEDCBAp+76F)) + return 1; + if (test__floatunqisf(make_qi(0, 0, 0x0000000000001FEDLL, 0xCBA0000000000000LL), + 0x1.FEDCBAp+76F)) + return 1; + if (test__floatunqisf(make_qi(0, 0, 0x0000000000001FEDLL, 0xCBAFFFFFFFFFFFFFLL), + 0x1.FEDCBAp+76F)) + return 1; + if (test__floatunqisf(make_qi(0, 0, 0x0000000000001FEDLL, 0xCBB0000000000000LL), + 0x1.FEDCBCp+76F)) + return 1; + if (test__floatunqisf(make_qi(0, 0, 0x0000000000001FEDLL, 0xCBB0000000000001LL), + 0x1.FEDCBCp+76F)) + return 1; + if (test__floatunqisf(make_qi(0, 0, 0x0000000000001FEDLL, 0xCBBFFFFFFFFFFFFFLL), + 0x1.FEDCBCp+76F)) + return 1; + if (test__floatunqisf(make_qi(0, 0, 0x0000000000001FEDLL, 0xCBC0000000000000LL), + 0x1.FEDCBCp+76F)) + return 1; + if (test__floatunqisf(make_qi(0, 0, 0x0000000000001FEDLL, 0xCBC0000000000001LL), + 0x1.FEDCBCp+76F)) + return 1; + if (test__floatunqisf(make_qi(0, 0, 0x0000000000001FEDLL, 0xCBD0000000000000LL), + 0x1.FEDCBCp+76F)) + return 1; + if (test__floatunqisf(make_qi(0, 0, 0x0000000000001FEDLL, 0xCBD0000000000001LL), + 0x1.FEDCBEp+76F)) + return 1; + if (test__floatunqisf(make_qi(0, 0, 0x0000000000001FEDLL, 0xCBDFFFFFFFFFFFFFLL), + 0x1.FEDCBEp+76F)) + return 1; + if (test__floatunqisf(make_qi(0, 0, 0x0000000000001FEDLL, 0xCBE0000000000000LL), + 0x1.FEDCBEp+76F)) + return 1; + printf("passed\n"); + return 0; +} diff --git a/fix.c b/fix.c new file mode 100644 --- /dev/null +++ b/fix.c @@ -0,0 +1,32 @@ +// clang -Xclang -fexperimental-max-bitint-width=256 fix.c +// Changes into _BitInt(2560) also works. +#include +// static __inline float fromRep(unsigned int x) { +// const union { +// float f; +// int i; +// } rep = {.i = x}; +// return rep.f; +// } + +// typedef union { +// _BitInt(129) x; +// unsigned int y[5]; +// } bitint; + // bitint a; + // a.x = b; + // printf("%d\n", a.y[0]); + // printf("%d\n", a.y[1]); + // printf("%d\n", a.y[2]); + // printf("%d\n", a.y[3]); + // printf("%d\n", a.y[4]); + +int main() { + double b = -1231231512312341231231245123123123213123123123123125123123123.14123; + _BitInt(128) c = b; + int* d = (int*)&c; + printf("%d\n", d[0]); + printf("%d\n", d[1]); + printf("%d\n", d[2]); + printf("%d\n", d[3]); +} diff --git a/fixdfdi_single_source.c b/fixdfdi_single_source.c new file mode 100644 --- /dev/null +++ b/fixdfdi_single_source.c @@ -0,0 +1,72 @@ +//===-- fixsfsi.c - Implement __fixsf8i -----------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +#include +#include + +#define significandBits 52 +#define signBit 0x8000000000000000 // (REP_C(1) << (significandBits + exponentBits)) +#define exponentBias 1023 //(maxExponent >> 1) +#define implicitBit 0x10000000000000 // (REP_C(1) << significandBits) + +#define absMask 0x7FFFFFFFFFFFFFFF //(signBit - 1U) +#define significandMask (implicitBit - 1U) + +static __inline unsigned long long toRep(double x) { + const union { + double f; + unsigned long long i; + } rep = {.f = x}; + return rep.i; +} + +static __inline double fromRep(unsigned long long x) { + const union { + double f; + long long i; + } rep = {.i = x}; + return rep.f; +} + +long long foo(double a) { + const long long fixint_max = (long long)((~(unsigned long long)0) / 2); + const long long fixint_min = -fixint_max - 1; + // Break a into sign, exponent, significand parts. + const unsigned long long aRep = toRep(a); + const unsigned long long aAbs = aRep & absMask; + const long long sign = aRep & signBit ? -1 : 1; + const long long exponent = (aAbs >> significandBits) - exponentBias; + const unsigned long long significand = (aAbs & significandMask) | implicitBit; + + // If exponent is negative, the result is zero. + if (exponent < 0) + return 0; + + // If the value is too large for the integer type, saturate. + if ((unsigned)exponent >= sizeof(long long) * 8) + return sign == 1 ? fixint_max : fixint_min; + + // If 0 <= exponent < significandBits, right shift to get the result. + // Otherwise, shift left. + if (exponent < significandBits) + return sign * (significand >> (significandBits - exponent)); + else + return sign * ((long long)significand << (exponent - significandBits)); +} + +int main() { + // fesetround(FE_UPWARD); + // fesetround(FE_TONEAREST); + // fesetround(FE_TOWARDZERO); + // fesetround(FE_UPWARD); + double a = fromRep(0x40A011CCCCCCCCCD); + // printf("intput a double:\n"); + // scanf("%f", &a); + long long b = foo(a); + printf("conversion result = %lld\n", b); + return 0; +} \ No newline at end of file diff --git a/fixdfdi_single_source_readable.ll b/fixdfdi_single_source_readable.ll new file mode 100644 --- /dev/null +++ b/fixdfdi_single_source_readable.ll @@ -0,0 +1,43 @@ +define dso_local i64 @foo(double noundef %a) local_unnamed_addr #0 { +entry: + %0 = bitcast double %a to i64 + %tobool.not = icmp sgt i64 %0, -1 + %conv = select i1 %tobool.not, i64 1, i64 -1 + %and = lshr i64 %0, 52 + %shr = and i64 %and, 2047 + %and2 = and i64 %0, 4503599627370495 + %or = or i64 %and2, 4503599627370496 + %cmp = icmp ult i64 %shr, 1023 + br i1 %cmp, label %cleanup, label %if.end + +if.end: ; preds = %entry + %sub = add nuw nsw i64 %shr, 4294966273 + %conv5 = and i64 %sub, 4294967232 + %cmp6.not = icmp eq i64 %conv5, 0 + br i1 %cmp6.not, label %if.end12, label %if.then8 + +if.then8: ; preds = %if.end + %cond11 = select i1 %tobool.not, i64 9223372036854775807, i64 -9223372036854775808 + br label %cleanup + +if.end12: ; preds = %if.end + %cmp13 = icmp ult i64 %shr, 1075 + br i1 %cmp13, label %if.then15, label %if.else + +if.then15: ; preds = %if.end12 + %sub16 = sub nuw nsw i64 1075, %shr + %shr17 = lshr i64 %or, %sub16 + %mul = mul nsw i64 %shr17, %conv + br label %cleanup + +if.else: ; preds = %if.end12 + %sub18 = add nsw i64 %shr, -1075 + %shl = shl i64 %or, %sub18 + %mul19 = mul nsw i64 %shl, %conv + br label %cleanup + +cleanup: ; preds = %entry, %if.else, %if.then15, %if.then8 + %retval.0 = phi i64 [ %cond11, %if.then8 ], [ %mul, %if.then15 ], [ %mul19, %if.else ], [ 0, %entry ] + ret i64 %retval.0 +} + diff --git a/fixsfdi_single_source.c b/fixsfdi_single_source.c new file mode 100644 --- /dev/null +++ b/fixsfdi_single_source.c @@ -0,0 +1,72 @@ +//===-- fixsfsi.c - Implement __fixsf8i -----------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +#include +#include + +#define significandBits 23 +#define signBit 0x80000000 // (REP_C(1) << (significandBits + exponentBits)) +#define exponentBias 127 //(maxExponent >> 1) +#define implicitBit 0x800000 // (REP_C(1) << significandBits) + +#define absMask 0x7FFFFFFF //(signBit - 1U) +#define significandMask (implicitBit - 1U) + +static __inline unsigned long long toRep(float x) { + const union { + float f; + unsigned int i; + } rep = {.f = x}; + return rep.i; +} + +static __inline float fromRep(unsigned int x) { + const union { + float f; + int i; + } rep = {.i = x}; + return rep.f; +} + +long long foo(float a) { + const long long fixint_max = (long long)((~(unsigned long long)0) / 2); + const long long fixint_min = -fixint_max - 1; + // Break a into sign, exponent, significand parts. + const unsigned long long aRep = toRep(a); + const unsigned long long aAbs = aRep & absMask; + const long long sign = aRep & signBit ? -1 : 1; + const long long exponent = (aAbs >> significandBits) - exponentBias; + const unsigned long long significand = (aAbs & significandMask) | implicitBit; + + // If exponent is negative, the result is zero. + if (exponent < 0) + return 0; + + // If the value is too large for the integer type, saturate. + if ((unsigned)exponent >= sizeof(long long) * 8) + return sign == 1 ? fixint_max : fixint_min; + + // If 0 <= exponent < significandBits, right shift to get the result. + // Otherwise, shift left. + if (exponent < significandBits) + return sign * (significand >> (significandBits - exponent)); + else + return sign * ((long long)significand << (exponent - significandBits)); +} + +int main() { + // fesetround(FE_UPWARD); + // fesetround(FE_TONEAREST); + // fesetround(FE_TOWARDZERO); + // fesetround(FE_UPWARD); + float a = -3.14;//fromRep(0x44ff7334); + // printf("intput a float:\n"); + // scanf("%f", &a); + long long b = foo(a); + printf("conversion result = %lld\n", b); + return 0; +} \ No newline at end of file diff --git a/fixsfdi_single_source_readable.ll b/fixsfdi_single_source_readable.ll new file mode 100644 --- /dev/null +++ b/fixsfdi_single_source_readable.ll @@ -0,0 +1,44 @@ +; Function Attrs: mustprogress nofree norecurse nosync nounwind readnone willreturn uwtable +define dso_local i64 @foo(float noundef %a) local_unnamed_addr #0 { +entry: + %0 = bitcast float %a to i32 + %conv.i = zext i32 %0 to i64 + %tobool.not = icmp sgt i32 %0, -1 + %conv = select i1 %tobool.not, i64 1, i64 -1 + %and = lshr i64 %conv.i, 23 + %shr = and i64 %and, 255 + %and2 = and i64 %conv.i, 8388607 + %or = or i64 %and2, 8388608 + %cmp = icmp ult i64 %shr, 127 + br i1 %cmp, label %cleanup, label %if.end + +if.end: ; preds = %entry + %sub = add nuw nsw i64 %shr, 4294967169 + %conv5 = and i64 %sub, 4294967232 + %cmp6.not = icmp eq i64 %conv5, 0 + br i1 %cmp6.not, label %if.end12, label %if.then8 + +if.then8: ; preds = %if.end + %cond11 = select i1 %tobool.not, i64 9223372036854775807, i64 -9223372036854775808 + br label %cleanup + +if.end12: ; preds = %if.end + %cmp13 = icmp ult i64 %shr, 150 + br i1 %cmp13, label %if.then15, label %if.else + +if.then15: ; preds = %if.end12 + %sub16 = sub nuw nsw i64 150, %shr + %shr17 = lshr i64 %or, %sub16 + %mul = mul nsw i64 %shr17, %conv + br label %cleanup + +if.else: ; preds = %if.end12 + %sub18 = add nsw i64 %shr, -150 + %shl = shl i64 %or, %sub18 + %mul19 = mul nsw i64 %shl, %conv + br label %cleanup + +cleanup: ; preds = %entry, %if.else, %if.then15, %if.then8 + %retval.0 = phi i64 [ %cond11, %if.then8 ], [ %mul, %if.then15 ], [ %mul19, %if.else ], [ 0, %entry ] + ret i64 %retval.0 +} diff --git a/fixsfsi_single_source.c b/fixsfsi_single_source.c new file mode 100644 --- /dev/null +++ b/fixsfsi_single_source.c @@ -0,0 +1,71 @@ +//===-- fixsfsi.c - Implement __fixsfsi -----------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +#include +#include + +#define significandBits 23 +#define signBit 0x80000000 // (REP_C(1) << (significandBits + exponentBits)) +#define exponentBias 127 //(maxExponent >> 1) +#define implicitBit 0x800000 // (REP_C(1) << significandBits) + +#define absMask 0x7FFFFFFF //(signBit - 1U) +#define significandMask (implicitBit - 1U) + +static __inline unsigned int toRep(float x) { + const union { + float f; + unsigned int i; + } rep = {.f = x}; + return rep.i; +} + +static __inline float fromRep(unsigned int x) { + const union { + float f; + int i; + } rep = {.i = x}; + return rep.f; +} + +int foo(float a) { + const int fixint_max = (int)((~(unsigned int)0) / 2); + const int fixint_min = -fixint_max - 1; + // Break a into sign, exponent, significand parts. + const unsigned int aRep = toRep(a); + const unsigned int aAbs = aRep & absMask; + const int sign = aRep & signBit ? -1 : 1; + const int exponent = (aAbs >> significandBits) - exponentBias; + const unsigned int significand = (aAbs & significandMask) | implicitBit; + + // If exponent is negative, the result is zero. + if (exponent < 0) + return 0; + + // If the value is too large for the integer type, saturate. + if ((unsigned)exponent >= sizeof(int) * 8) + return sign == 1 ? fixint_max : fixifixsfsi_single_source_readablent_min; + + // If 0 <= exponent < significandBits, right shift to get the result. + // Otherwise, shift left. + if (exponent < significandBits) + return sign * (significand >> (significandBits - exponent)); + else + return sign * ((int)significand << (exponent - significandBits)); +} + +int main() { + // fesetround(FE_UPWARD); + // fesetround(FE_TONEAREST); + // fesetround(FE_TOWARDZERO); + // fesetround(FE_UPWARD); + float a = fromRep(0x44ff7334); + // printf("intput a float:\n"); + // scanf("%f", &a); + int b = foo(a); + printf("conversion result = %d\n", b); +} \ No newline at end of file diff --git a/fixsfsi_single_source_readable.ll b/fixsfsi_single_source_readable.ll new file mode 100644 --- /dev/null +++ b/fixsfsi_single_source_readable.ll @@ -0,0 +1,58 @@ +; ModuleID = 'fixsfsi_single_source.c' +source_filename = "fixsfsi_single_source.c" +target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +; Function Attrs: mustprogress nofree norecurse nosync nounwind readnone willreturn uwtable +define dso_local i32 @foo(float noundef %a) local_unnamed_addr #0 { +entry: + %aRep = bitcast float %a to i32 + %tobool.not = icmp sgt i32 %aRep, -1 + %sign = select i1 %tobool.not, i32 1, i32 -1 + %and = lshr i32 %aRep, 23 + %exponent_with_bias = and i32 %and, 255 + %aAbs = and i32 %aRep, 8388607 + %significand = or i32 %aAbs, 8388608 + %cmp = icmp ult i32 %exponent_with_bias, 127 + br i1 %cmp, label %cleanup, label %if.end + +if.end: ; preds = %entry + %add1 = add nsw i32 %exponent_with_bias, -159 + %cmp3 = icmp ult i32 %add1, -32 + br i1 %cmp3, label %if.then5, label %if.end9 + +if.then5: ; preds = %if.end + %cond8 = select i1 %tobool.not, i32 2147483647, i32 -2147483648 + br label %cleanup + +if.end9: ; preds = %if.end + %cmp10 = icmp ult i32 %exponent_with_bias, 150 + br i1 %cmp10, label %if.then12, label %if.else + +if.then12: ; preds = %if.end9 + %sub13 = sub nuw nsw i32 150, %exponent_with_bias + %shr14 = lshr i32 %significand, %sub13 + %mul = mul nsw i32 %shr14, %sign + br label %cleanup + +if.else: ; preds = %if.end9 + %sub15 = add nsw i32 %exponent_with_bias, -150 + %shl = shl nuw i32 %significand, %sub15 + %mul16 = mul nsw i32 %shl, %sign + br label %cleanup + +cleanup: ; preds = %entry, %if.else, %if.then12, %if.then5 + %retval.0 = phi i32 [ %cond8, %if.then5 ], [ %mul, %if.then12 ], [ %mul16, %if.else ], [ 0, %entry ] + ret i32 %retval.0 +} + +attributes #0 = { mustprogress nofree norecurse nosync nounwind readnone willreturn uwtable "frame-pointer"="none" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" } + +!llvm.module.flags = !{!0, !1, !2, !3} +!llvm.ident = !{!4} + +!0 = !{i32 1, !"wchar_size", i32 4} +!1 = !{i32 8, !"PIC Level", i32 2} +!2 = !{i32 7, !"PIE Level", i32 2} +!3 = !{i32 7, !"uwtable", i32 2} +!4 = !{!"clang version 16.0.0 (https://github.com/llvm/llvm-project.git 6c1dd0b7329f6ed2e402468c74355f09447052e3)"} diff --git a/float.c b/float.c new file mode 100644 --- /dev/null +++ b/float.c @@ -0,0 +1,7 @@ +// clang -Xclang -fexperimental-max-bitint-width=2560 -mllvm -expand-fp-convert-bits=32 float.c +#include +int main() { + unsigned _BitInt(256) a = -1238; + float b = a; + printf("%f\n", b); +} diff --git a/floatdidf_single_source.c b/floatdidf_single_source.c new file mode 100644 --- /dev/null +++ b/floatdidf_single_source.c @@ -0,0 +1,75 @@ +//===-- lib/floatsisf.c - integer -> single-precision conversion --*- C -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements integer to single-precision conversion for the +// compiler-rt library in the IEEE-754 default round-to-nearest, ties-to-even +// mode. +// +//===----------------------------------------------------------------------===// + +#include +#include + +#define significandBits 52 +#define typeWidth 64 //(sizeof(unsigned long long) * __CHAR_BIT__) +#define exponentBits 11 // (typeWidth - significandBits - 1) + +#define exponentBias 1023 //(maxExponent >> 1) + +#define implicitBit 0x10000000000000 // (REP_C(1) << significandBits) + +#define signBit 0x8000000000000000 // (REP_C(1) << (significandBits + exponentBits)) + +static __inline double fromRep(unsigned long long x) { + const union { + double f; + long long i; + } rep = {.i = x}; + return rep.f; +} + +double foo(long long a) { + const long long aWidth = sizeof a * __CHAR_BIT__; + // Handle zero as a special case to protect clz + if (a == 0) + return fromRep(0); + // All other cases begin by extracting the sign and absolute value of a + unsigned long long sign = 0; + if (a < 0) { + sign = signBit; + a = -a; + } + // Exponent of (fp_t)a is the width of abs(a). + const long long exponent = (aWidth - 1) - __builtin_clzll(a); + unsigned long long result; + // Shift a into the significand field, rounding if it is a right-shift + if (exponent <= significandBits) { + const long long shift = significandBits - exponent; + result = (unsigned long long)a << shift ^ implicitBit; + } else { + const long long shift = exponent - significandBits; + result = (unsigned long long)a >> shift ^ implicitBit; + unsigned long long round = (unsigned long long)a << (typeWidth - shift); + if (round > signBit) + result++; + if (round == signBit) + result += result & 1; + } + // Insert the exponent + result += (unsigned long long)(exponent + exponentBias) << significandBits; + // Insert the sign bit and return + return fromRep(result | sign); +} + +int main() { + long long a; + printf("intput a integer:\n"); + scanf("%lld", &a); + double b = foo(a); + printf("conversion result = %f\n", b); +} \ No newline at end of file diff --git a/floatdidf_single_source_bitint.c b/floatdidf_single_source_bitint.c new file mode 100644 --- /dev/null +++ b/floatdidf_single_source_bitint.c @@ -0,0 +1,75 @@ +//===-- lib/floatsisf.c - integer -> single-precision conversion --*- C -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements integer to single-precision conversion for the +// compiler-rt library in the IEEE-754 default round-to-nearest, ties-to-even +// mode. +// +//===----------------------------------------------------------------------===// + +#include +#include + +#define significandBits 52 +#define typeWidth 64 //(sizeof(unsigned _BitInt(64)) * __CHAR_BIT__) +#define exponentBits 11 // (typeWidth - significandBits - 1) + +#define exponentBias 1023 //(maxExponent >> 1) + +#define implicitBit 0x10000000000000 // (REP_C(1) << significandBits) + +#define signBit 0x8000000000000000 // (REP_C(1) << (significandBits + exponentBits)) + +static __inline double fromRep(unsigned _BitInt(64) x) { + const union { + double f; + _BitInt(64) i; + } rep = {.i = x}; + return rep.f; +} + +double foo(_BitInt(128) a) { + const _BitInt(64) aWidth = sizeof a * __CHAR_BIT__; + // Handle zero as a special case to protect clz + if (a == 0) + return fromRep(0); + // All other cases begin by extracting the sign and absolute value of a + unsigned _BitInt(128) sign = 0; + if (a < 0) { + sign = signBit; + a = -a; + } + // Exponent of (fp_t)a is the width of abs(a). + const _BitInt(64) exponent = (aWidth - 1) - __builtin_clzll(a); + unsigned _BitInt(128) result; + // Shift a into the significand field, rounding if it is a right-shift + if (exponent <= significandBits) { + const _BitInt(64) shift = significandBits - exponent; + result = (unsigned _BitInt(128))a << shift ^ implicitBit; + } else { + const _BitInt(64) shift = exponent - significandBits; + result = (unsigned _BitInt(128))a >> shift ^ implicitBit; + unsigned _BitInt(128) round = (unsigned _BitInt(64))a << (typeWidth - shift); + if (round > signBit) + result++; + if (round == signBit) + result += result & 1; + } + // Insert the exponent + result += (unsigned _BitInt(64))(exponent + exponentBias) << significandBits; + // Insert the sign bit and return + return fromRep(result | sign); +} + +int main() { + _BitInt(64) a; + printf("intput a integer:\n"); + scanf("%lld", &a); + double b = foo(a); + printf("conversion result = %f\n", b); +} \ No newline at end of file diff --git a/floatdidf_single_source_readable.ll b/floatdidf_single_source_readable.ll new file mode 100644 --- /dev/null +++ b/floatdidf_single_source_readable.ll @@ -0,0 +1,47 @@ +define dso_local double @foo(i64 noundef %a) local_unnamed_addr #0 { +entry: + %cmp = icmp eq i64 %a, 0 + br i1 %cmp, label %cleanup, label %if.end + +if.end: ; preds = %entry + %0 = and i64 %a, -9223372036854775808 + %1 = tail call i64 @llvm.abs.i64(i64 %a, i1 true) + %2 = tail call i64 @llvm.ctlz.i64(i64 %1, i1 true), !range !5 + %sub4 = xor i64 %2, 63 + %cmp5 = icmp ult i64 %sub4, 53 + br i1 %cmp5, label %if.then7, label %if.else + +if.then7: ; preds = %if.end + %sub8 = sub nuw nsw i64 52, %sub4 + %shl = shl i64 %1, %sub8 + %xor = xor i64 %shl, 4503599627370496 + br label %if.end22 + +if.else: ; preds = %if.end + %sub10 = sub nsw i64 11, %2 + %shr = lshr i64 %1, %sub10 + %xor11 = xor i64 %shr, 4503599627370496 + %sub12 = add nuw nsw i64 %2, 53 + %shl13 = shl i64 %1, %sub12 + %cmp14 = icmp ugt i64 %shl13, -9223372036854775808 + %inc = zext i1 %cmp14 to i64 + %spec.select43 = add nuw i64 %xor11, %inc + %cmp18 = icmp eq i64 %shl13, -9223372036854775808 + %and = and i64 %spec.select43, 1 + %add = select i1 %cmp18, i64 %and, i64 0 + %result.1 = add nuw i64 %add, %spec.select43 + br label %if.end22 + +if.end22: ; preds = %if.else, %if.then7 + %result.2 = phi i64 [ %xor, %if.then7 ], [ %result.1, %if.else ] + %3 = shl nuw nsw i64 %2, 52 + %shl24 = sub nuw nsw i64 4890909195324358656, %3 + %add25 = add i64 %shl24, %result.2 + %or = or i64 %add25, %0 + %4 = bitcast i64 %or to double + br label %cleanup + +cleanup: ; preds = %entry, %if.end22 + %retval.0 = phi double [ %4, %if.end22 ], [ 0.000000e+00, %entry ] + ret double %retval.0 +} diff --git a/floatdisf_single_source.c b/floatdisf_single_source.c new file mode 100644 --- /dev/null +++ b/floatdisf_single_source.c @@ -0,0 +1,98 @@ +//===-- floattidf.c - Implement __floattidf -------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements __floattidf for the compiler_rt library. +// +//===----------------------------------------------------------------------===// + +// Returns: convert a to a double, rounding toward even. + +// Assumption: double is a IEEE 64 bit floating point type +// _BitInt(64) is a 128 bit integral type + +// seee eeee eeee mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm +// mmmm + +#include +#define DBL_MANT_DIG 53 + +typedef union { + _BitInt(64) all; + struct { + unsigned _BitInt(64) low; + _BitInt(64) high; + } s; +} twords; + +typedef union { + unsigned _BitInt(64) all; + struct { + unsigned int low; + unsigned int high; + } s; +} udwords; + +typedef union { + unsigned int u; + float f; +} float_bits; + +float __floatdisf(_BitInt(64) a) { + if (a == 0) + return 0.0F; + const unsigned N = sizeof(_BitInt(64)) * __CHAR_BIT__; + const _BitInt(64) s = a >> (N - 1); + a = (a ^ s) - s; + int sd = N - __builtin_clzll(a); // number of significant digits + int e = sd - 1; // exponent + if (sd > 24) { + // start: 0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx + // finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR + // 12345678901234567890123456 + // 1 = msb 1 bit + // P = bit 24-1 bits to the right of 1 + // Q = bit 24 bits to the right of 1 + // R = "or" of all bits to the right of Q + switch (sd) { + case 24 + 1: + a <<= 1; + break; + case 24 + 2: + break; + default: + a = ((unsigned _BitInt(64))a >> (sd - (24 + 2))) | + ((a & ((unsigned _BitInt(64))(-1) >> ((N + 24 + 2) - sd))) != 0); + }; + // finish: + a |= (a & 4) != 0; // Or P into R + ++a; // round - this step may add a significant bit + a >>= 2; // dump Q and R + // a is now rounded to 24 or 24+1 bits + if (a & ((unsigned _BitInt(64))1 << 24)) { + a >>= 1; + ++e; + } + // a is now rounded to 24 bits + } else { + a <<= (24 - sd); + // a is now rounded to 24 bits + } + float_bits fb; + fb.u = ((unsigned int)s & 0x80000000) | // sign + ((e + 127) << 23) | // exponent + ((unsigned int)a & 0x007FFFFF); // mantissa + return fb.f; +} + +int main() { + long long a; + printf("intput a integer:\n"); + scanf("%lld", &a); + double b = __floatdisf(a); + printf("conversion result = %f\n", b); +} \ No newline at end of file diff --git a/floatdisf_single_source_readable.ll b/floatdisf_single_source_readable.ll new file mode 100644 --- /dev/null +++ b/floatdisf_single_source_readable.ll @@ -0,0 +1,75 @@ +; Function Attrs: mustprogress nofree nosync nounwind readnone willreturn uwtable +define dso_local float @__floatdisf(i64 noundef %a) local_unnamed_addr #0 { +entry: + %cmp = icmp eq i64 %a, 0 + br i1 %cmp, label %return, label %if.end + +if.end: ; preds = %entry + %shr = ashr i64 %a, 63 + %xor = xor i64 %shr, %a + %sub = sub nsw i64 %xor, %shr + %0 = tail call i64 @llvm.ctlz.i64(i64 %sub, i1 true), !range !5 + %cast = trunc i64 %0 to i32 + %sub1 = sub nuw nsw i32 64, %cast + %sub2 = xor i32 %cast, 63 + %cmp3 = icmp ult i32 %cast, 40 + br i1 %cmp3, label %if.then4, label %if.else + +if.then4: ; preds = %if.end + switch i32 %sub1, label %sw.default [ + i32 25, label %sw.bb + i32 26, label %sw.epilog + ] + +sw.bb: ; preds = %if.then4 + %shl = shl i64 %sub, 1 + br label %sw.epilog + +sw.default: ; preds = %if.then4 + %sub5 = sub nsw i64 38, %0 + %sh_prom = and i64 %sub5, 4294967295 + %shr6 = lshr i64 %sub, %sh_prom + %shr9 = lshr i64 274877906943, %0 + %and = and i64 %shr9, %sub + %cmp10 = icmp ne i64 %and, 0 + %conv11 = zext i1 %cmp10 to i64 + %or = or i64 %shr6, %conv11 + br label %sw.epilog + +sw.epilog: ; preds = %sw.default, %if.then4, %sw.bb + %a.addr.0 = phi i64 [ %or, %sw.default ], [ %sub, %if.then4 ], [ %shl, %sw.bb ] + %1 = lshr i64 %a.addr.0, 2 + %2 = and i64 %1, 1 + %or16 = or i64 %2, %a.addr.0 + %inc = add nsw i64 %or16, 1 + %3 = and i64 %inc, 67108864 + %tobool.not = icmp eq i64 %3, 0 + %spec.select.v = select i1 %tobool.not, i64 2, i64 3 + %spec.select = ashr i64 %inc, %spec.select.v + %spec.select56 = select i1 %tobool.not, i32 %sub2, i32 %sub1 + br label %if.end26 + +if.else: ; preds = %if.end + %sub23 = add nuw nsw i64 %0, 4294967256 + %sh_prom24 = and i64 %sub23, 4294967295 + %shl25 = shl i64 %sub, %sh_prom24 + br label %if.end26 + +if.end26: ; preds = %sw.epilog, %if.else + %a.addr.1 = phi i64 [ %shl25, %if.else ], [ %spec.select, %sw.epilog ] + %e.0 = phi i32 [ %sub2, %if.else ], [ %spec.select56, %sw.epilog ] + %conv27 = trunc i64 %shr to i32 + %and28 = and i32 %conv27, -2147483648 + %add = shl nuw nsw i32 %e.0, 23 + %shl29 = add nuw nsw i32 %add, 1065353216 + %conv31 = trunc i64 %a.addr.1 to i32 + %and32 = and i32 %conv31, 8388607 + %or30 = or i32 %and32, %and28 + %or33 = or i32 %or30, %shl29 + %4 = bitcast i32 %or33 to float + br label %return + +return: ; preds = %entry, %if.end26 + %retval.0 = phi float [ %4, %if.end26 ], [ 0.000000e+00, %entry ] + ret float %retval.0 +} diff --git a/floatsisf_single_source.c b/floatsisf_single_source.c new file mode 100644 --- /dev/null +++ b/floatsisf_single_source.c @@ -0,0 +1,81 @@ +//===-- lib/floatsisf.c - integer -> single-precision conversion --*- C -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements integer to single-precision conversion for the +// compiler-rt library in the IEEE-754 default round-to-nearest, ties-to-even +// mode. +// +//===----------------------------------------------------------------------===// + +#include +#include + +#define clzsi __builtin_clz + +// #define UINT32_C(c) c ## U + +// #define REP_C UINT32_C + +#define significandBits 23 +#define typeWidth 32 //(sizeof(unsigned int) * __CHAR_BIT__) +#define exponentBits 8 // (typeWidth - significandBits - 1) + +#define exponentBias 127 //(maxExponent >> 1) + +#define implicitBit 0x800000 // (REP_C(1) << significandBits) + +#define signBit 0x80000000 // (REP_C(1) << (significandBits + exponentBits)) + +static __inline float fromRep(unsigned int x) { + const union { + float f; + int i; + } rep = {.i = x}; + return rep.f; +} + +float foo(int a) { + const int aWidth = sizeof a * __CHAR_BIT__; + // Handle zero as a special case to protect clz + if (a == 0) + return fromRep(0); + // All other cases begin by extracting the sign and absolute value of a + unsigned int sign = 0; + if (a < 0) { + sign = signBit; + a = -a; + } + // Exponent of (fp_t)a is the width of abs(a). + const int exponent = (aWidth - 1) - clzsi(a); + unsigned int result; + // Shift a into the significand field, rounding if it is a right-shift + if (exponent <= significandBits) { + const int shift = significandBits - exponent; + result = (unsigned int)a << shift ^ implicitBit; + } else { + const int shift = exponent - significandBits; + result = (unsigned int)a >> shift ^ implicitBit; + unsigned int round = (unsigned int)a << (typeWidth - shift); + if (round > signBit) + result++; + if (round == signBit) + result += result & 1; + } + // Insert the exponent + result += (unsigned int)(exponent + exponentBias) << significandBits; + // Insert the sign bit and return + return fromRep(result | sign); +} + +int main() { + int a; + printf("intput a integer:\n"); + scanf("%d", &a); + float b = foo(a); + printf("conversion result = %f\n", b); +} \ No newline at end of file diff --git a/floatsisf_single_source_readable.ll b/floatsisf_single_source_readable.ll new file mode 100644 --- /dev/null +++ b/floatsisf_single_source_readable.ll @@ -0,0 +1,48 @@ +; Function Attrs: mustprogress nofree nosync nounwind readnone willreturn uwtable +define dso_local float @foo(i32 noundef %a) local_unnamed_addr #0 { +entry: + %cmp = icmp eq i32 %a, 0 + br i1 %cmp, label %cleanup, label %if.end + +if.end: ; preds = %entry + %0 = and i32 %a, -2147483648 + %1 = tail call i32 @llvm.abs.i32(i32 %a, i1 true) + %2 = tail call i32 @llvm.ctlz.i32(i32 %1, i1 true), !range !5 + %sub4 = xor i32 %2, 31 + %cmp5 = icmp ult i32 %sub4, 24 + br i1 %cmp5, label %if.then6, label %if.else + +if.then6: ; preds = %if.end + %sub7 = sub nuw nsw i32 23, %sub4 + %shl = shl i32 %1, %sub7 + %xor = xor i32 %shl, 8388608 + br label %if.end19 + +if.else: ; preds = %if.end + %sub9 = sub nsw i32 8, %2 + %shr = lshr i32 %1, %sub9 + %xor10 = xor i32 %shr, 8388608 + %sub11 = add nuw nsw i32 %2, 24 + %shl12 = shl i32 %1, %sub11 + %cmp13 = icmp ugt i32 %shl12, -2147483648 + %inc = zext i1 %cmp13 to i32 + %spec.select40 = add nuw i32 %xor10, %inc + %cmp16 = icmp eq i32 %shl12, -2147483648 + %and = and i32 %spec.select40, 1 + %add = select i1 %cmp16, i32 %and, i32 0 + %result.1 = add nuw i32 %add, %spec.select40 + br label %if.end19 + +if.end19: ; preds = %if.else, %if.then6 + %result.2 = phi i32 [ %xor, %if.then6 ], [ %result.1, %if.else ] + %3 = shl nuw nsw i32 %2, 23 + %shl21 = sub nuw nsw i32 1325400064, %3 + %add22 = add i32 %shl21, %result.2 + %or = or i32 %add22, %0 + %4 = bitcast i32 %or to float + br label %cleanup + +cleanup: ; preds = %entry, %if.end19 + %retval.0 = phi float [ %4, %if.end19 ], [ 0.000000e+00, %entry ] + ret float %retval.0 +} diff --git a/floattidf_single_source.c b/floattidf_single_source.c new file mode 100644 --- /dev/null +++ b/floattidf_single_source.c @@ -0,0 +1,102 @@ +//===-- floattidf.c - Implement __floattidf -------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements __floattidf for the compiler_rt library. +// +//===----------------------------------------------------------------------===// + +// Returns: convert a to a double, rounding toward even. + +// Assumption: double is a IEEE 64 bit floating point type +// _BitInt(128) is a 128 bit integral type + +// seee eeee eeee mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm +// mmmm + +#include +#define DBL_MANT_DIG 53 + +typedef union { + _BitInt(128) all; + struct { + unsigned long long low; + long long high; + } s; +} twords; + +typedef union { + unsigned long long all; + struct { + unsigned int low; + unsigned int high; + } s; +} udwords; + +typedef union { + udwords u; + double f; +} double_bits; + +int __clzti2(_BitInt(128) a) { + twords x; + x.all = a; + const long long f = -(x.s.high == 0); + return __builtin_clzll((x.s.high & ~f) | (x.s.low & f)) + + ((int)f & ((int)(sizeof(long long) * __CHAR_BIT__))); +} + +double __floattidf(_BitInt(128) a) { + if (a == 0) + return 0.0; + const unsigned N = sizeof(_BitInt(128)) * __CHAR_BIT__; + const _BitInt(128) s = a >> (N - 1); + a = (a ^ s) - s; + int sd = N - __builtin_clzll(a); // number of significant digits + int e = sd - 1; // exponent + if (sd > DBL_MANT_DIG) { + switch (sd) { + case DBL_MANT_DIG + 1: + a <<= 1; + break; + case DBL_MANT_DIG + 2: + break; + default: + a = ((unsigned _BitInt(128))a >> (sd - (DBL_MANT_DIG + 2))) | + ((a & ((unsigned _BitInt(128))(-1) >> ((N + DBL_MANT_DIG + 2) - sd))) != 0); + }; + // finish: + a |= (a & 4) != 0; // Or P into R + ++a; // round - this step may add a significant bit + a >>= 2; // dump Q and R + // a is now rounded to DBL_MANT_DIG or DBL_MANT_DIG+1 bits + if (a & ((unsigned _BitInt(128))1 << DBL_MANT_DIG)) { + a >>= 1; + ++e; + } + // a is now rounded to DBL_MANT_DIG bits + } else { + a <<= (DBL_MANT_DIG - sd); + // a is now rounded to DBL_MANT_DIG bits + } + double_bits fb; + fb.u.s.high = ((unsigned int)s & 0x80000000) | // sign + ((e + 1023) << 20) | // exponent + ((unsigned int)(a >> 32) & 0x000FFFFF); // mantissa-high + fb.u.s.low = (unsigned int)a; // mantissa-low + return fb.f; +} + +int main() { + twords a; + printf("intput a integer low:\n"); + scanf("%lld", &a.s.low); + printf("intput a integer low:\n"); + scanf("%lld", &a.s.high); + double b = __floattidf(a.all); + printf("conversion result = %f\n", b); +} \ No newline at end of file diff --git a/floattidf_single_source_readable.ll b/floattidf_single_source_readable.ll new file mode 100644 --- /dev/null +++ b/floattidf_single_source_readable.ll @@ -0,0 +1,56 @@ +; Function Attrs: mustprogress nofree nosync nounwind readnone willreturn uwtable +define dso_local double @__floattidf(i64 noundef %a.coerce0, i64 noundef %a.coerce1) local_unnamed_addr #0 { +entry: + %a.sroa.2.0.insert.ext = zext i64 %a.coerce1 to i128 + %a.sroa.2.0.insert.shift = shl nuw i128 %a.sroa.2.0.insert.ext, 64 + %a.sroa.0.0.insert.ext = zext i64 %a.coerce0 to i128 + %a.sroa.0.0.insert.insert = or i128 %a.sroa.2.0.insert.shift, %a.sroa.0.0.insert.ext + %cmp = icmp eq i128 %a.sroa.0.0.insert.insert, 0 + br i1 %cmp, label %return, label %if.end + +if.end: ; preds = %entry + %shr = ashr i128 %a.sroa.2.0.insert.shift, 127 + %xor = xor i128 %a.sroa.0.0.insert.insert, %shr + %sub = sub nsw i128 %xor, %shr + %conv = trunc i128 %sub to i64 + %0 = tail call i64 @llvm.ctlz.i64(i64 %conv, i1 true), !range !5 + %cast = trunc i64 %0 to i32 + %sub2 = sub nuw nsw i64 128, %0 + %sub3 = xor i64 %0, 127 + %sub7 = sub nuw nsw i32 73, %cast + %sh_prom = zext i32 %sub7 to i128 + %shr8 = lshr i128 %sub, %sh_prom + %sub9 = add nuw nsw i32 %cast, 55 + %sh_prom10 = zext i32 %sub9 to i128 + %shr11 = lshr i128 -1, %sh_prom10 + %and = and i128 %shr11, %sub + %cmp12 = icmp ne i128 %and, 0 + %1 = trunc i128 %shr8 to i32 + %2 = lshr i32 %1, 2 + %3 = and i32 %2, 1 + %4 = zext i1 %cmp12 to i32 + %5 = or i32 %3, %4 + %6 = zext i32 %5 to i128 + %or19 = or i128 %shr8, %6 + %inc = add nuw nsw i128 %or19, 1 + %7 = and i128 %inc, 36028797018963968 + %tobool.not = icmp eq i128 %7, 0 + %a.addr.1.off0.v.v = select i1 %tobool.not, i128 2, i128 3 + %a.addr.1.off0.v = lshr i128 %inc, %a.addr.1.off0.v.v + %a.addr.1.off0 = trunc i128 %a.addr.1.off0.v to i64 + %e.0 = select i1 %tobool.not, i64 %sub3, i64 %sub2 + %conv30 = trunc i128 %shr to i64 + %and31 = and i64 %conv30, 2147483648 + %add = shl nuw nsw i64 %e.0, 20 + %shl32 = add nuw nsw i64 %add, 1072693248 + %or33 = or i64 %shl32, %and31 + %fb.sroa.0.4.insert.ext66 = shl nuw i64 %or33, 32 + %8 = and i64 %a.addr.1.off0, 4503599627370495 + %fb.sroa.0.0.insert.insert = or i64 %fb.sroa.0.4.insert.ext66, %8 + %9 = bitcast i64 %fb.sroa.0.0.insert.insert to double + br label %return + +return: ; preds = %entry, %if.end + %retval.0 = phi double [ %9, %if.end ], [ 0.000000e+00, %entry ] + ret double %retval.0 +} diff --git a/floattisf_single_source.c b/floattisf_single_source.c new file mode 100644 --- /dev/null +++ b/floattisf_single_source.c @@ -0,0 +1,95 @@ +//===-- floattidf.c - Implement __floattisf -------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements __floattisf for the compiler_rt library. +// +//===----------------------------------------------------------------------===// + +// Returns: convert a to a double, rounding toward even. + +// Assumption: double is a IEEE 64 bit floating point type +// _BitInt(128) is a 128 bit integral type + +// seee eeee eeee mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm +// mmmm + +#include +#define FLT_MANT_DIG 24 + +typedef union { + _BitInt(128) all; + struct { + unsigned long long low; + long long high; + } s; +} twords; + +typedef union { + unsigned int u; + float f; +} float_bits; + +int __clzti2(_BitInt(128) a) { + twords x; + x.all = a; + const long long f = -(x.s.high == 0); + return __builtin_clzll((x.s.high & ~f) | (x.s.low & f)) + + ((int)f & ((int)(sizeof(long long) * __CHAR_BIT__))); +} + +extern int __clzti2a(_BitInt(128) a); + +float __floattisf(_BitInt(128) a) { + if (a == 0) + return 0.0; + const unsigned N = sizeof(_BitInt(128)) * __CHAR_BIT__; + const _BitInt(128) s = a >> (N - 1); + a = (a ^ s) - s; + int sd = N - __clzti2a(a); // number of significant digits + int e = sd - 1; // exponent + if (sd > FLT_MANT_DIG) { + switch (sd) { + case FLT_MANT_DIG + 1: + a <<= 1; + break; + case FLT_MANT_DIG + 2: + break; + default: + a = ((unsigned _BitInt(128))a >> (sd - (FLT_MANT_DIG + 2))) | + ((a & ((unsigned _BitInt(128))(-1) >> ((N + FLT_MANT_DIG + 2) - sd))) != 0); + }; + // finish: + a |= (a & 4) != 0; // Or P into R + ++a; // round - this step may add a significant bit + a >>= 2; // dump Q and R + // a is now rounded to DBL_MANT_DIG or DBL_MANT_DIG+1 bits + if (a & ((unsigned _BitInt(128))1 << FLT_MANT_DIG)) { + a >>= 1; + ++e; + } + // a is now rounded to DBL_MANT_DIG bits + } else { + a <<= (FLT_MANT_DIG - sd); + // a is now rounded to DBL_MANT_DIG bits + } + float_bits fb; + fb.u = ((unsigned int)s & 0x80000000) | // sign + ((e + 127) << 23) | // exponent + ((unsigned int)a & 0x007FFFFF); // mantissa + return fb.f; +} + +int main() { + twords a; + printf("intput a integer low:\n"); + scanf("%lld", &a.s.low); + printf("intput a integer high:\n"); + scanf("%lld", &a.s.high); + float b = __floattisf(a.all); + printf("conversion result = %f\n", b); +} \ No newline at end of file diff --git a/floattisf_single_source_readable.ll b/floattisf_single_source_readable.ll new file mode 100644 --- /dev/null +++ b/floattisf_single_source_readable.ll @@ -0,0 +1,99 @@ +; ModuleID = 'floattisf_single_source.c' +source_filename = "floattisf_single_source.c" +target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +define dso_local float @__floattisf(i64 noundef %a.coerce0, i64 noundef %a.coerce1) local_unnamed_addr #0 { +entry: + %a.sroa.2.0.insert.ext = zext i64 %a.coerce1 to i128 + %a.sroa.2.0.insert.shift = shl nuw i128 %a.sroa.2.0.insert.ext, 64 + %a.sroa.0.0.insert.ext = zext i64 %a.coerce0 to i128 + %a.sroa.0.0.insert.insert = or i128 %a.sroa.2.0.insert.shift, %a.sroa.0.0.insert.ext + %cmp = icmp eq i128 %a.sroa.0.0.insert.insert, 0 + br i1 %cmp, label %return, label %if.end + +if.end: ; preds = %entry + %shr = ashr i128 %a.sroa.2.0.insert.shift, 127 + %xor = xor i128 %a.sroa.0.0.insert.insert, %shr + %sub = sub nsw i128 %xor, %shr + %coerce.sroa.0.0.extract.trunc = trunc i128 %sub to i64 + %coerce.sroa.2.0.extract.shift = lshr i128 %sub, 64 + %coerce.sroa.2.0.extract.trunc = trunc i128 %coerce.sroa.2.0.extract.shift to i64 + %cmp.i = icmp eq i64 %coerce.sroa.2.0.extract.trunc, 0 + %0 = select i1 %cmp.i, i64 %coerce.sroa.0.0.extract.trunc, i64 %coerce.sroa.2.0.extract.trunc + %1 = tail call i64 @llvm.ctlz.i64(i64 %0, i1 true), !range !5 + %cast.i = trunc i64 %1 to i32 + %and6.i = select i1 %cmp.i, i32 64, i32 0 + %add.i = or i32 %and6.i, %cast.i + %sub2 = sub nuw nsw i32 128, %add.i + %sub3 = xor i32 %add.i, 127 + %cmp4 = icmp ult i32 %add.i, 104 + br i1 %cmp4, label %if.then5, label %if.else + +if.then5: ; preds = %if.end + %trunc = trunc i32 %sub2 to i8 + switch i8 %trunc, label %sw.default [ + i8 25, label %sw.bb + i8 26, label %sw.epilog + ] + +sw.bb: ; preds = %if.then5 + %shl = shl i128 %sub, 1 + br label %sw.epilog + +sw.default: ; preds = %if.then5 + %sub6 = sub nsw i32 102, %add.i + %sh_prom = zext i32 %sub6 to i128 + %shr7 = lshr i128 %sub, %sh_prom + %sub8 = add nuw nsw i32 %add.i, 26 + %sh_prom9 = zext i32 %sub8 to i128 + %shr10 = lshr i128 -1, %sh_prom9 + %and = and i128 %shr10, %sub + %cmp11 = icmp ne i128 %and, 0 + %conv12 = zext i1 %cmp11 to i128 + %or = or i128 %shr7, %conv12 + br label %sw.epilog + +sw.epilog: ; preds = %sw.default, %if.then5, %sw.bb + %a.addr.0 = phi i128 [ %or, %sw.default ], [ %sub, %if.then5 ], [ %shl, %sw.bb ] + %2 = trunc i128 %a.addr.0 to i32 + %3 = lshr i32 %2, 2 + %4 = and i32 %3, 1 + %conv16 = zext i32 %4 to i128 + %or17 = or i128 %a.addr.0, %conv16 + %inc = add nsw i128 %or17, 1 + %shr18 = ashr i128 %inc, 2 + %5 = and i128 %inc, 67108864 + %tobool.not = icmp eq i128 %5, 0 + %extract.t57 = trunc i128 %shr18 to i32 + br i1 %tobool.not, label %if.end27, label %if.then20 + +if.then20: ; preds = %sw.epilog + %6 = lshr i128 %shr18, 1 + %extract.t = trunc i128 %6 to i32 + br label %if.end27 + +if.else: ; preds = %if.end + %sub24 = add nsw i32 %add.i, -104 + %sh_prom25 = zext i32 %sub24 to i128 + %shl26 = shl i128 %sub, %sh_prom25 + %extract.t58 = trunc i128 %shl26 to i32 + br label %if.end27 + +if.end27: ; preds = %sw.epilog, %if.then20, %if.else + %a.addr.1.off0 = phi i32 [ %extract.t, %if.then20 ], [ %extract.t57, %sw.epilog ], [ %extract.t58, %if.else ] + %e.0 = phi i32 [ %sub2, %if.then20 ], [ %sub3, %sw.epilog ], [ %sub3, %if.else ] + %conv28 = trunc i128 %shr to i32 + %and29 = and i32 %conv28, -2147483648 + %add = shl nuw nsw i32 %e.0, 23 + %shl30 = add nuw nsw i32 %add, 1065353216 + %and33 = and i32 %a.addr.1.off0, 8388607 + %or31 = or i32 %and33, %and29 + %or34 = or i32 %or31, %shl30 + %7 = bitcast i32 %or34 to float + br label %return + +return: ; preds = %entry, %if.end27 + %retval.0 = phi float [ %7, %if.end27 ], [ 0.000000e+00, %entry ] + ret float %retval.0 +} diff --git a/llvm/include/llvm/CodeGen/MachinePassRegistry.def b/llvm/include/llvm/CodeGen/MachinePassRegistry.def --- a/llvm/include/llvm/CodeGen/MachinePassRegistry.def +++ b/llvm/include/llvm/CodeGen/MachinePassRegistry.def @@ -44,6 +44,7 @@ FUNCTION_PASS("ee-instrument", EntryExitInstrumenterPass, (false)) FUNCTION_PASS("post-inline-ee-instrument", EntryExitInstrumenterPass, (true)) FUNCTION_PASS("expand-large-div-rem", ExpandLargeDivRemPass, ()) +FUNCTION_PASS("expand-large-fp-convert", ExpandLargeFpConvertPass, ()) FUNCTION_PASS("expand-reductions", ExpandReductionsPass, ()) FUNCTION_PASS("expandvp", ExpandVectorPredicationPass, ()) FUNCTION_PASS("lowerinvoke", LowerInvokePass, ()) diff --git a/llvm/include/llvm/CodeGen/Passes.h b/llvm/include/llvm/CodeGen/Passes.h --- a/llvm/include/llvm/CodeGen/Passes.h +++ b/llvm/include/llvm/CodeGen/Passes.h @@ -490,6 +490,9 @@ // Expands large div/rem instructions. FunctionPass *createExpandLargeDivRemPass(); + // Expands large div/rem instructions. + FunctionPass *createExpandLargeFpConvertPass(); + // This pass expands memcmp() to load/stores. FunctionPass *createExpandMemCmpPass(); diff --git a/llvm/include/llvm/InitializePasses.h b/llvm/include/llvm/InitializePasses.h --- a/llvm/include/llvm/InitializePasses.h +++ b/llvm/include/llvm/InitializePasses.h @@ -138,6 +138,7 @@ void initializeEdgeBundlesPass(PassRegistry&); void initializeEHContGuardCatchretPass(PassRegistry &); void initializeEliminateAvailableExternallyLegacyPassPass(PassRegistry&); +void initializeExpandLargeFpConvertLegacyPassPass(PassRegistry&); void initializeExpandLargeDivRemLegacyPassPass(PassRegistry&); void initializeExpandMemCmpPassPass(PassRegistry&); void initializeExpandPostRAPass(PassRegistry&); diff --git a/llvm/lib/CodeGen/CMakeLists.txt b/llvm/lib/CodeGen/CMakeLists.txt --- a/llvm/lib/CodeGen/CMakeLists.txt +++ b/llvm/lib/CodeGen/CMakeLists.txt @@ -53,6 +53,7 @@ EHContGuardCatchret.cpp ExecutionDomainFix.cpp ExpandLargeDivRem.cpp + ExpandLargeFpConvert.cpp ExpandMemCmp.cpp ExpandPostRAPseudos.cpp ExpandReductions.cpp diff --git a/llvm/lib/CodeGen/CodeGen.cpp b/llvm/lib/CodeGen/CodeGen.cpp --- a/llvm/lib/CodeGen/CodeGen.cpp +++ b/llvm/lib/CodeGen/CodeGen.cpp @@ -37,6 +37,7 @@ initializeEarlyMachineLICMPass(Registry); initializeEarlyTailDuplicatePass(Registry); initializeExpandLargeDivRemLegacyPassPass(Registry); + initializeExpandLargeFpConvertLegacyPassPass(Registry); initializeExpandMemCmpPassPass(Registry); initializeExpandPostRAPass(Registry); initializeFEntryInserterPass(Registry); diff --git a/llvm/lib/CodeGen/ExpandLargeFpConvert.cpp b/llvm/lib/CodeGen/ExpandLargeFpConvert.cpp new file mode 100644 --- /dev/null +++ b/llvm/lib/CodeGen/ExpandLargeFpConvert.cpp @@ -0,0 +1,509 @@ +//===--- ExpandLargeFpConvert.cpp - Expand large fp convert----------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// + +// This pass expands ‘fptoui .. to’, ‘fptosi .. to’, ‘uitofp .. to’, +// ‘sitofp .. to’ instructions with a bitwidth above a threshold into a call to +// auto-generated functions. This is useful for targets like x86_64 that cannot +// lower fp convertions with more than 128 bits. +// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/Analysis/GlobalsModRef.h" +#include "llvm/CodeGen/Passes.h" +#include "llvm/CodeGen/TargetLowering.h" +#include "llvm/CodeGen/TargetPassConfig.h" +#include "llvm/CodeGen/TargetSubtargetInfo.h" +#include "llvm/IR/IRBuilder.h" +#include "llvm/IR/InstIterator.h" +#include "llvm/IR/PassManager.h" +#include "llvm/InitializePasses.h" +#include "llvm/Pass.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Target/TargetMachine.h" +// #include "llvm/Transforms/Utils/IntegerDivision.h" +#include + +using namespace llvm; + +static cl::opt + ExpandFpConvertBits("expand-fp-convert-bits", cl::Hidden, + cl::init(llvm::IntegerType::MAX_INT_BITS), + cl::desc("fp convert instructions on integers with " + "more than bits are expanded.")); + +// static bool isConstantPowerOfTwo(llvm::Value *V, bool SignedOp) { +// auto *C = dyn_cast(V); +// if (!C) +// return false; + +// APInt Val = C->getValue(); +// if (SignedOp && Val.isNegative()) +// Val = -Val; +// return Val.isPowerOf2(); +// } + +// static bool isSigned(unsigned int Opcode) { +// return Opcode == Instruction::FPToSI || Opcode == Instruction::SIToFP; +// } + +/// Generate code to convert a fp number to integer, replacing FPToS(U)I with +/// the generated code. This currently generates code similarly to compiler-rt's +/// implementations, but future work includes generating more specialized code +/// when more information about the operands are known. +/// +/// Replace fp to integer with generated code. +static bool expandFPToI(Instruction *FPToI) { + IRBuilder<> Builder(FPToI); + auto* FloatVal = FPToI->getOperand(0); + IntegerType *IntTy = cast(FPToI->getType()); + + unsigned BitWidth = FPToI->getType()->getIntegerBitWidth(); + unsigned FPMantissaWidth = 23; //FloatVal->getType()->getFPMantissaWidth() - 1; + unsigned FloatWidth = 32; //pow(2, int(log2(FPMantissaWidth)) + 1); + unsigned ExponentWidth = FloatWidth - FPMantissaWidth - 1; + // unsigned signBit = 1u << FloatWidth; + unsigned implicitBit = 1u << FPMantissaWidth; + unsigned significandMask = implicitBit - 1; + + BasicBlock *IBB = Builder.GetInsertBlock(); + Function *F = IBB->getParent(); + + BasicBlock *Entry = Builder.GetInsertBlock(); + Entry->setName(Twine(Entry->getName(), "_entry")); + BasicBlock *End = IBB->splitBasicBlock(Builder.GetInsertPoint(), + "cleanup"); + BasicBlock *IfEnd = BasicBlock::Create(Builder.getContext(), + "if.end", F, End); + BasicBlock *IfThen5 = BasicBlock::Create(Builder.getContext(), + "if.then5", F, End); + BasicBlock *IfEnd9 = BasicBlock::Create(Builder.getContext(), + "if.end9", F, End); + BasicBlock *IfThen12 = BasicBlock::Create(Builder.getContext(), + "if.then12", F, End); + BasicBlock *IfElse = BasicBlock::Create(Builder.getContext(), + "if.else", F, End); + + Entry->getTerminator()->eraseFromParent(); + + //entry: + Builder.SetInsertPoint(Entry); + Value *aRep0 = nullptr; + if (FloatVal->getType()->getFPMantissaWidth() > 32) { + Value *aRep0_0 = Builder.CreateFPTrunc(FloatVal, Builder.getFloatTy(), "aRep0_0"); + aRep0 = Builder.CreateBitCast(aRep0_0, Builder.getIntNTy(FloatWidth), "aRep0"); + } else + aRep0 = Builder.CreateBitCast(FloatVal, Builder.getIntNTy(FloatWidth), "aRep0"); + Value *aRep = Builder.CreateZExt(aRep0, FPToI->getType(), "aRep"); + Value *tobool_not = Builder.CreateICmpSGT(aRep0, ConstantInt::getSigned(Builder.getInt32Ty(), -1), "tobool.not"); + Value *sign = Builder.CreateSelect(tobool_not, ConstantInt::getSigned(IntTy, 1), ConstantInt::getSigned(IntTy, -1), "sign"); + Value *andf = Builder.CreateLShr(aRep, Builder.getIntN(BitWidth, FPMantissaWidth), "and"); + Value *exponent_with_bias = Builder.CreateAnd(andf, Builder.getIntN(BitWidth, (1u << ExponentWidth) - 1), "exponent_with_bias"); + Value *aAbs = Builder.CreateAnd(aRep, Builder.getIntN(BitWidth, significandMask), "aAbs"); + Value *significand = Builder.CreateOr(aAbs, Builder.getIntN(BitWidth, implicitBit), "significand"); + Value *cmp = Builder.CreateICmpULT(exponent_with_bias, Builder.getIntN(BitWidth, (1u << (ExponentWidth - 1)) - 1), "cmp"); + Builder.CreateCondBr(cmp, End, IfEnd); + + //if.end: + Builder.SetInsertPoint(IfEnd); + Value *add1 = Builder.CreateAdd(exponent_with_bias, ConstantInt::getSigned(IntTy, -int64_t((1u << (ExponentWidth - 1)) + BitWidth - 1)), "add1"); + Value *cmp3 = Builder.CreateICmpULT(add1, ConstantInt::getSigned(IntTy, -BitWidth), "cmp3"); + Builder.CreateCondBr(cmp3, IfThen5, IfEnd9); + + //if.then5: + Builder.SetInsertPoint(IfThen5); + Value *neg_one = Builder.CreateSExt(ConstantInt::getSigned(Builder.getInt32Ty(), -1), IntTy, "inf_temp"); + Value *neg_inf = Builder.CreateShl(ConstantInt::getSigned(IntTy, 1), ConstantInt::getSigned(IntTy, BitWidth - 1), "inf_temp2"); + Value *pos_inf = Builder.CreateXor(neg_one, neg_inf, "inf_temp3"); + Value *cond8 = Builder.CreateSelect(tobool_not, pos_inf, neg_inf, "cond8"); + Builder.CreateBr(End); + + //if.end9: + Builder.SetInsertPoint(IfEnd9); + Value *cmp10 = Builder.CreateICmpULT(exponent_with_bias, Builder.getIntN(BitWidth, (1u << (ExponentWidth - 1)) + FPMantissaWidth - 1), "cmp10"); + Builder.CreateCondBr(cmp10, IfThen12, IfElse); + + //if.then12: + Builder.SetInsertPoint(IfThen12); + Value *sub13 = Builder.CreateSub(Builder.getIntN(BitWidth, (1u << (ExponentWidth - 1)) + FPMantissaWidth - 1), exponent_with_bias, "sub13"); + Value *shr14 = Builder.CreateLShr(significand, sub13, "shr14"); + Value *mul = Builder.CreateMul(shr14, sign, "mul"); + Builder.CreateBr(End); + + //if.else: + Builder.SetInsertPoint(IfElse); + Value *sub15 = Builder.CreateAdd(exponent_with_bias, ConstantInt::getSigned(IntTy, -int64_t((1u << (ExponentWidth - 1)) + FPMantissaWidth - 1)), "sub15"); + Value *shl = Builder.CreateShl(significand, sub15, "shl"); + Value *mul16 = Builder.CreateMul(shl, sign, "mul16"); + Builder.CreateBr(End); + + //cleanup: + Builder.SetInsertPoint(End, End->begin()); + PHINode *retval_0 = Builder.CreatePHI(FPToI->getType(), 4); + + retval_0->addIncoming(cond8, IfThen5); + retval_0->addIncoming(mul, IfThen12); + retval_0->addIncoming(mul16, IfElse); + retval_0->addIncoming(Builder.getIntN(BitWidth, 0), Entry); + + FPToI->replaceAllUsesWith(retval_0); + FPToI->dropAllReferences(); + FPToI->eraseFromParent(); + return true; +} + +/// Generate code to convert a fp number to integer, replacing S(U)IToFP with +/// the generated code. This currently generates code similarly to compiler-rt's +/// implementations, but future work includes generating more specialized code +/// when more information about the operands are known. +/// +/// Replace integer to fp with generated code. +static bool expandIToFPA(Instruction* IToFP) { + IRBuilder<> Builder(IToFP); + auto* IntVal = IToFP->getOperand(0); + IntegerType *IntTy = cast(IntVal->getType()); + unsigned BitWidth = IntVal->getType()->getIntegerBitWidth(); + unsigned FPMantissaWidth = IToFP->getType()->getFPMantissaWidth() - 1; + unsigned FloatWidth = pow(2, int(log2(FPMantissaWidth)) + 1); + + BasicBlock *IBB = Builder.GetInsertBlock(); + Function *F = IBB->getParent(); + Function *CTLZ = Intrinsic::getDeclaration(F->getParent(), Intrinsic::ctlz, + IntTy); + Function *ABS = Intrinsic::getDeclaration(F->getParent(), Intrinsic::abs, + IntTy); + ConstantInt *True = Builder.getTrue(); + + BasicBlock *Entry = Builder.GetInsertBlock(); + Entry->setName(Twine(Entry->getName(), "_entry")); + BasicBlock *End = IBB->splitBasicBlock(Builder.GetInsertPoint(), + "cleanup"); + BasicBlock *IfEnd = BasicBlock::Create(Builder.getContext(), + "if.end", F, End); + BasicBlock *IfThen7 = BasicBlock::Create(Builder.getContext(), + "if.then7", F, End); + BasicBlock *IfElse = BasicBlock::Create(Builder.getContext(), + "if.else", F, End); + BasicBlock *IfEnd22 = BasicBlock::Create(Builder.getContext(), + "if.end22", F, End); + + Entry->getTerminator()->eraseFromParent(); + + //entry: + Builder.SetInsertPoint(Entry); + Value *cmp = Builder.CreateICmpEQ(IntVal, ConstantInt::getSigned(IntTy, 0), "cmp"); + Builder.CreateCondBr(cmp, End, IfEnd); + + //if.end: + Builder.SetInsertPoint(IfEnd); + Value *a0 = Builder.CreateAnd(IntVal, ConstantInt::getSigned(IntTy, 1ull << (FloatWidth -1)), "a0"); + Value *a1 = Builder.CreateCall(ABS, {IntVal, True}, "a1"); + Value *a2 = Builder.CreateCall(CTLZ, {a1, True}, "a2"); + Value *sub4 = Builder.CreateXor(a2, Builder.getIntN(BitWidth, FloatWidth - 1), "sub4"); + Value *cmp5 = Builder.CreateICmpULT(sub4, Builder.getIntN(BitWidth, FPMantissaWidth + 1), "cmp5"); + Builder.CreateCondBr(cmp5, IfThen7, IfElse); + + //if.then7: + Builder.SetInsertPoint(IfThen7); + Value *sub8 = Builder.CreateSub(Builder.getIntN(BitWidth, FPMantissaWidth), sub4, "sub8"); + Value *shl = Builder.CreateShl(a1, sub8, "shl"); + Value *xorf = Builder.CreateXor(shl, Builder.getIntN(BitWidth, 1ull << FPMantissaWidth), "xor"); + Builder.CreateBr(IfEnd22); + + //if.else: + Builder.SetInsertPoint(IfElse); + Value *sub10 = Builder.CreateSub(Builder.getIntN(BitWidth, FloatWidth - FPMantissaWidth - 1), a2, "sub10"); + Value *shr = Builder.CreateLShr(a1, sub10, "shr"); + Value *xor11 = Builder.CreateXor(shr, Builder.getIntN(BitWidth, 1ull << FPMantissaWidth), "xor11"); + Value *sub12 = Builder.CreateAdd(a2, Builder.getIntN(BitWidth, FPMantissaWidth + 1), "sub12"); + Value *shl13 = Builder.CreateShl(a1, sub12, "shl13"); + Value *cmp14 = Builder.CreateICmpUGT(shl13, ConstantInt::getSigned(IntTy, 1ull<< (FloatWidth -1)), "cmp14"); + Value *inc = Builder.CreateZExt(cmp14, IntTy, "inc"); + Value *spec_select43 = Builder.CreateAdd(xor11, inc, "spec.select43"); + Value *cmp18 = Builder.CreateICmpEQ(shl13, ConstantInt::getSigned(IntTy, 1ull << (FloatWidth -1)), "cmp18"); + Value *andf = Builder.CreateAnd(spec_select43, Builder.getIntN(BitWidth, 1), "and"); + Value *add = Builder.CreateSelect(cmp18, andf, Builder.getIntN(BitWidth, 0), "add"); + Value *result_1 = Builder.CreateAdd(add, spec_select43, "result.1"); + Builder.CreateBr(IfEnd22); + + //if.end22: + Builder.SetInsertPoint(IfEnd22); + PHINode *result_2 = Builder.CreatePHI(IntTy, 2, "result.2"); + result_2->addIncoming(xorf, IfThen7); + result_2->addIncoming(result_1, IfElse); + Value *a3 = Builder.CreateShl(a2, Builder.getIntN(BitWidth, FPMantissaWidth), "a3"); + Value *shl24 = Builder.CreateSub(Builder.getIntN(BitWidth, 4890909195324358656), a3, "shl24"); + Value *add25 = Builder.CreateAdd(shl24, result_2, "add25"); + Value *orf = Builder.CreateOr(add25, a0, "or"); + Value *a4 = Builder.CreateBitCast(orf, IToFP->getType(), "a4"); + Builder.CreateBr(End); + + //cleanup: + Builder.SetInsertPoint(End, End->begin()); + PHINode *retval_0 = Builder.CreatePHI(IToFP->getType(), 2, "retval.0"); + retval_0->addIncoming(a4, IfEnd22); + retval_0->addIncoming(ConstantFP::getZero(IToFP->getType(), false), Entry); + + IToFP->replaceAllUsesWith(retval_0); + IToFP->dropAllReferences(); + IToFP->eraseFromParent(); + return true; +} + +/// Generate code to convert a fp number to integer, replacing S(U)IToFP with +/// the generated code. This currently generates code similarly to compiler-rt's +/// implementations, but future work includes generating more specialized code +/// when more information about the operands are known. +/// +/// Replace integer to fp with generated code. +static bool expandIToFPB(Instruction* IToFP) { + IRBuilder<> Builder(IToFP); + auto* IntVal = IToFP->getOperand(0); + IntegerType *IntTy = cast(IntVal->getType()); + unsigned BitWidth = IntVal->getType()->getIntegerBitWidth(); + unsigned FPMantissaWidth = 23; //IToFP->getType()->getFPMantissaWidth() - 1; + unsigned FloatWidth = 32; //pow(2, int(log2(FPMantissaWidth)) + 1); + + BasicBlock *IBB = Builder.GetInsertBlock(); + Function *F = IBB->getParent(); + Function *CTLZ = Intrinsic::getDeclaration(F->getParent(), Intrinsic::ctlz, + IntTy); + ConstantInt *True = Builder.getTrue(); + + BasicBlock *Entry = Builder.GetInsertBlock(); + Entry->setName(Twine(Entry->getName(), "_entry")); + BasicBlock *End = IBB->splitBasicBlock(Builder.GetInsertPoint(), + "return"); + BasicBlock *IfEnd = BasicBlock::Create(Builder.getContext(), + "if.end", F, End); + BasicBlock *IfThen4 = BasicBlock::Create(Builder.getContext(), + "if.then4", F, End); + BasicBlock *SwBB = BasicBlock::Create(Builder.getContext(), + "sw.bb", F, End); + BasicBlock *SwDefault = BasicBlock::Create(Builder.getContext(), + "sw.default", F, End); + BasicBlock *SwEpilog = BasicBlock::Create(Builder.getContext(), + "sw.epilog", F, End); + BasicBlock *IfElse = BasicBlock::Create(Builder.getContext(), + "if.else", F, End); + BasicBlock *IfEnd26 = BasicBlock::Create(Builder.getContext(), + "if.end26", F, End); + + Entry->getTerminator()->eraseFromParent(); + + //entry: + Builder.SetInsertPoint(Entry); + Value *cmp = Builder.CreateICmpEQ(IntVal, ConstantInt::getSigned(IntTy, 0), "cmp"); + Builder.CreateCondBr(cmp, End, IfEnd); + + //if.end: + Builder.SetInsertPoint(IfEnd); + Value *shr = Builder.CreateAShr(IntVal, Builder.getIntN(BitWidth, BitWidth - 1), "shr"); + Value *xorr = Builder.CreateXor(shr, IntVal, "xor"); + Value *sub = Builder.CreateSub(xorr, shr, "sub"); + Value *a0 = Builder.CreateCall(CTLZ, {sub, True}, "a0"); + Value *cast = Builder.CreateTrunc(a0, Builder.getInt32Ty(), "cast"); + Value *sub1 = Builder.CreateSub(Builder.getInt32(BitWidth), cast, "sub1"); + Value *sub2 = Builder.CreateXor(cast, Builder.getInt32(BitWidth - 1), "sub2"); + Value *cmp3 = Builder.CreateICmpULT(cast, Builder.getInt32(BitWidth - FPMantissaWidth - 1), "cmp3"); + Builder.CreateCondBr(cmp3, IfThen4, IfElse); + + //if.then4: + Builder.SetInsertPoint(IfThen4); + llvm::SwitchInst *SI = Builder.CreateSwitch(sub1, SwDefault); + SI->addCase(Builder.getInt32(FPMantissaWidth + 2), SwBB); + SI->addCase(Builder.getInt32(FPMantissaWidth + 3), SwEpilog); + + //sw.bb: + Builder.SetInsertPoint(SwBB); + Value *shl = Builder.CreateShl(sub, Builder.getIntN(BitWidth, 1), "shl"); + Builder.CreateBr(SwEpilog); + + //sw.default: +#if 0 + Builder.SetInsertPoint(SwDefault); + Value *sub5 = Builder.CreateSub(Builder.getIntN(BitWidth, BitWidth - FPMantissaWidth - 3), a0, "sub5"); + Value *sh_prom = Builder.CreateAnd(sub5, Builder.getIntN(BitWidth, (1ull << FloatWidth) - 1), "sh_prom"); + Value *shr6 = Builder.CreateLShr(sub, sh_prom, "shr6"); + // Value *shr9_temp1 = Builder.CreateLShr(ConstantInt::getSigned(IntTy, 1), ConstantInt::getSigned(IntTy, BitWidth - FPMantissaWidth - 3)); + // Value *shr9_temp2 = Builder.CreateSub(shr9_temp1, Builder.getIntN(BitWidth, 1)); + // Value *shr9 = Builder.CreateLShr(shr9_temp2, a0, "shr9"); + Value *shr9 = Builder.CreateLShr(Builder.getIntN(BitWidth, (1ull << (BitWidth - FPMantissaWidth - 3)) - 1), a0, "shr9"); + Value *andd = Builder.CreateAnd(shr9, sub, "andd"); + Value *cmp10 = Builder.CreateICmpNE(andd, Builder.getIntN(BitWidth, 0), "cmp10"); + Value *conv11 = Builder.CreateZExt(cmp10, IntTy, "conv11"); + Value *orr = Builder.CreateOr(shr6, conv11, "orr"); + Builder.CreateBr(SwEpilog); +#endif + Builder.SetInsertPoint(SwDefault); + Value *sub5 = Builder.CreateSub(Builder.getIntN(FloatWidth, BitWidth - FPMantissaWidth - 3), cast, "sub5"); + Value *sh_prom = Builder.CreateZExt(sub5, IntTy, "sh_prom"); + Value *shr6 = Builder.CreateLShr(sub, sh_prom, "shr6"); + Value *sub8 = Builder.CreateAdd(cast, Builder.getIntN(FloatWidth, FPMantissaWidth + 3), "sub8"); + Value *sh_prom9 = Builder.CreateZExt(sub8, IntTy, "sh_prom9"); + Value *shr9 = Builder.CreateLShr(ConstantInt::getSigned(IntTy, -1), sh_prom9, "shr9"); + Value *andd = Builder.CreateAnd(shr9, sub, "andd"); + Value *cmp10 = Builder.CreateICmpNE(andd, Builder.getIntN(BitWidth, 0), "cmp10"); + Value *conv11 = Builder.CreateZExt(cmp10, IntTy, "conv11"); + Value *orr = Builder.CreateOr(shr6, conv11, "orr"); + Builder.CreateBr(SwEpilog); + + //sw.epilog: + Builder.SetInsertPoint(SwEpilog); + PHINode *a_addr_0 = Builder.CreatePHI(IntTy, 3, "a.addr.0"); + a_addr_0->addIncoming(orr, SwDefault); + a_addr_0->addIncoming(sub, IfThen4); + a_addr_0->addIncoming(shl, SwBB); + Value *a1 = Builder.CreateLShr(a_addr_0, Builder.getIntN(BitWidth, 2), "a1"); + Value *a2 = Builder.CreateAnd(a1, Builder.getIntN(BitWidth, 1), "a2"); + Value *or16 = Builder.CreateOr(a2, a_addr_0, "or16"); + Value *inc = Builder.CreateAdd(or16, Builder.getIntN(BitWidth, 1), "inc"); + Value *a3 = Builder.CreateAnd(inc, Builder.getIntN(BitWidth, 1ull << (FPMantissaWidth + 3)), "a3"); + Value *tobool_not = Builder.CreateICmpEQ(a3, Builder.getIntN(BitWidth, 0), "tobool.not"); + Value *spec_select_v = Builder.CreateSelect(tobool_not, Builder.getIntN(BitWidth, 2), Builder.getIntN(BitWidth, 3), "spec.select.v"); + Value *spec_select = Builder.CreateAShr(inc, spec_select_v, "spec.select"); + Value *spec_select56 = Builder.CreateSelect(tobool_not, sub2, sub1, "spec.select56"); + Builder.CreateBr(IfEnd26); + + //if.else: + Builder.SetInsertPoint(IfElse); + Value *sub23 = Builder.CreateAdd(a0, ConstantInt::getSigned(IntTy, -(BitWidth - FPMantissaWidth - 1)), "sub23"); + Value *sh_prom24 = Builder.CreateAnd(sub23, Builder.getIntN(BitWidth, (1ull << FloatWidth) - 1), "sh_prom24"); + Value *shl25 = Builder.CreateShl(sub, sh_prom24, "shl25"); + Builder.CreateBr(IfEnd26); + + //if.end26: + Builder.SetInsertPoint(IfEnd26); + PHINode *a_addr_1 = Builder.CreatePHI(IntTy, 2, "a.addr.1"); + a_addr_1->addIncoming(shl25, IfElse); + a_addr_1->addIncoming(spec_select, SwEpilog); + PHINode *e_0 = Builder.CreatePHI(Builder.getInt32Ty(), 2, "e.0"); + e_0->addIncoming(sub2, IfElse); + e_0->addIncoming(spec_select56, SwEpilog); + Value *conv27 = Builder.CreateTrunc(shr, Builder.getInt32Ty(), "conv27"); + Value *and28 = Builder.CreateAnd(conv27, Builder.getIntN(FloatWidth, 1ull << (FloatWidth - 1)), "and28"); + Value *add = Builder.CreateShl(e_0, Builder.getIntN(FloatWidth, FPMantissaWidth), "add"); + unsigned long long temp = ((1ull << (FloatWidth - FPMantissaWidth - 2)) - 1) << FPMantissaWidth; + Value *shl29 = Builder.CreateAdd(add, Builder.getIntN(FloatWidth, temp), "shl29"); + Value *conv31 = Builder.CreateTrunc(a_addr_1, Builder.getInt32Ty(), "conv31"); + Value *and32 = Builder.CreateAnd(conv31, Builder.getIntN(FloatWidth, (1ull << FPMantissaWidth) - 1), "and32"); + Value *or30 = Builder.CreateOr(and32, and28, "or30"); + Value *or33 = Builder.CreateOr(or30, shl29, "or33"); + Value *a4 = Builder.CreateBitCast(or33, Builder.getFloatTy()/*IToFP->getType()*/, "a4"); + Builder.CreateBr(End); + + //return: + Builder.SetInsertPoint(End, End->begin()); + PHINode *retval_0 = Builder.CreatePHI(Builder.getFloatTy()/*IToFP->getType()*/, 2, "retval.0"); + retval_0->addIncoming(a4, IfEnd26); + retval_0->addIncoming(ConstantFP::getZero(Builder.getFloatTy()/*IToFP->getType()*/, false), Entry); + if (IToFP->getType()->getFPMantissaWidth() > 32) { + Value *retval_0_ext = Builder.CreateFPExt(retval_0, IToFP->getType(), "retval_0_ext"); + IToFP->replaceAllUsesWith(retval_0_ext); + } + else + IToFP->replaceAllUsesWith(retval_0); + IToFP->dropAllReferences(); + IToFP->eraseFromParent(); + return true; +} + +static bool runImpl(Function &F, const TargetLowering &TLI) { + SmallVector Replace; + bool Modified = false; + + unsigned MaxLegalFpConvertBitWidth = TLI.getMaxDivRemBitWidthSupported(); + if (ExpandFpConvertBits != llvm::IntegerType::MAX_INT_BITS) + MaxLegalFpConvertBitWidth = ExpandFpConvertBits; + + if (MaxLegalFpConvertBitWidth >= llvm::IntegerType::MAX_INT_BITS) + return false; + + for (auto &I : instructions(F)) { + switch (I.getOpcode()) { + case Instruction::FPToUI: + case Instruction::FPToSI: { + // TODO: This doesn't handle vectors. + auto *IntTy = dyn_cast(I.getType()); + if (IntTy->getIntegerBitWidth() <= MaxLegalFpConvertBitWidth) + continue; + + Replace.push_back(&I); + Modified = true; + break; + } + case Instruction::UIToFP: + case Instruction::SIToFP: { + auto *IntTy = dyn_cast(I.getOperand(0)->getType()); + if (IntTy->getIntegerBitWidth() <= MaxLegalFpConvertBitWidth) + continue; + + Replace.push_back(&I); + Modified = true; + break; + } + default: + break; + } + } + + if (Replace.empty()) + return false; + + while (!Replace.empty()) { + Instruction *I = Replace.pop_back_val(); + if (I->getOpcode() == Instruction::FPToUI || + I->getOpcode() == Instruction::FPToSI) { + expandFPToI(I); + } else { + auto* IntVal = I->getOperand(0); + unsigned BitWidth = IntVal->getType()->getIntegerBitWidth(); + unsigned FPMantissaWidth = I->getType()->getFPMantissaWidth() - 1; + unsigned FloatWidth = pow(2, int(log2(FPMantissaWidth)) + 1); + if(BitWidth <= FloatWidth) + expandIToFPA(I); + else + expandIToFPB(I); + } + } + + return Modified; +} + +class ExpandLargeFpConvertLegacyPass : public FunctionPass { +public: + static char ID; + + ExpandLargeFpConvertLegacyPass() : FunctionPass(ID) { + initializeExpandLargeFpConvertLegacyPassPass(*PassRegistry::getPassRegistry()); + } + + bool runOnFunction(Function &F) override { + auto *TM = &getAnalysis().getTM(); + auto *TLI = TM->getSubtargetImpl(F)->getTargetLowering(); + return runImpl(F, *TLI); + } + + void getAnalysisUsage(AnalysisUsage &AU) const override { + AU.addRequired(); + AU.addPreserved(); + AU.addPreserved(); + } +}; + +char ExpandLargeFpConvertLegacyPass::ID = 0; +INITIALIZE_PASS_BEGIN(ExpandLargeFpConvertLegacyPass, "expand-large-fp-convert", + "Expand large fp convert", false, false) +INITIALIZE_PASS_END(ExpandLargeFpConvertLegacyPass, "expand-large-fp-convert", + "Expand large fp convert", false, false) + +FunctionPass *llvm::createExpandLargeFpConvertPass() { + return new ExpandLargeFpConvertLegacyPass(); +} diff --git a/llvm/lib/CodeGen/TargetPassConfig.cpp b/llvm/lib/CodeGen/TargetPassConfig.cpp --- a/llvm/lib/CodeGen/TargetPassConfig.cpp +++ b/llvm/lib/CodeGen/TargetPassConfig.cpp @@ -1114,6 +1114,7 @@ addPass(createPreISelIntrinsicLoweringPass()); PM->add(createTargetTransformInfoWrapperPass(TM->getTargetIRAnalysis())); addPass(createExpandLargeDivRemPass()); + addPass(createExpandLargeFpConvertPass()); addIRPasses(); addCodeGenPrepare(); addPassesToHandleExceptions(); diff --git a/llvm/test/Transforms/ExpandLargeFpConvert/fptosi129.ll b/llvm/test/Transforms/ExpandLargeFpConvert/fptosi129.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Transforms/ExpandLargeFpConvert/fptosi129.ll @@ -0,0 +1,6 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt -mtriple=x86_64 -expand-large-fp-convert llvm/test/Transforms/ExpandLargeFpConvert/fptosi128.ll -expand-fp-convert-bits=32 -S -o - +define i128 @foo(float %a) { + %conv = fptosi float %a to i128 + ret i128 %conv +} diff --git a/llvm/test/Transforms/ExpandLargeFpConvert/si129tofp.ll b/llvm/test/Transforms/ExpandLargeFpConvert/si129tofp.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Transforms/ExpandLargeFpConvert/si129tofp.ll @@ -0,0 +1,6 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt -mtriple=x86_64 -expand-large-fp-convert llvm/test/Transforms/ExpandLargeFpConvert/si129tofp.ll -expand-fp-convert-bits=32 -S -o - +define double @foo(i128 %a) { + %conv = sitofp i128 %a to double + ret double %conv +} diff --git a/llvm/tools/opt/opt.cpp b/llvm/tools/opt/opt.cpp --- a/llvm/tools/opt/opt.cpp +++ b/llvm/tools/opt/opt.cpp @@ -456,7 +456,8 @@ "dot-regions", "dot-regions-only", "view-regions", "view-regions-only", "select-optimize", "expand-large-div-rem", - "structurizecfg", "fix-irreducible"}; + "structurizecfg", "fix-irreducible", + "expand-large-fp-convert"}; for (const auto &P : PassNamePrefix) if (Pass.startswith(P)) return true; @@ -504,6 +505,7 @@ // For codegen passes, only passes that do IR to IR transformation are // supported. initializeExpandLargeDivRemLegacyPassPass(Registry); + initializeExpandLargeFpConvertLegacyPassPass(Registry); initializeExpandMemCmpPassPass(Registry); initializeScalarizeMaskedMemIntrinLegacyPassPass(Registry); initializeSelectOptimizePass(Registry);