mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-27 02:16:06 +00:00

In certain cases (i.e. long double on x86), the bit with we get from the floating point semantics is different than the type size we compute for the BitCast instruction. Pass this along to DoBitCast, so in there we can check only the relevant bits for being initialized. This also fixes a weirdness we still had in DoBitCast.
104 lines
3.3 KiB
C++
104 lines
3.3 KiB
C++
// RUN: %clang_cc1 -verify=ref,both -std=c++2a -fsyntax-only -triple x86_64-apple-macosx10.14.0 %s
|
|
// RUN: %clang_cc1 -verify=ref,both -std=c++2a -fsyntax-only -triple x86_64-apple-macosx10.14.0 %s -fno-signed-char
|
|
// RUN: %clang_cc1 -verify=ref,both -std=c++2a -fsyntax-only -triple aarch64_be-linux-gnu %s
|
|
|
|
// RUN: %clang_cc1 -verify=expected,both -std=c++2a -fsyntax-only -triple x86_64-apple-macosx10.14.0 %s -fexperimental-new-constant-interpreter
|
|
// RUN: %clang_cc1 -verify=expected,both -std=c++2a -fsyntax-only -triple x86_64-apple-macosx10.14.0 %s -fno-signed-char -fexperimental-new-constant-interpreter
|
|
// RUN: %clang_cc1 -verify=expected,both -std=c++2a -fsyntax-only -triple aarch64_be-linux-gnu %s -fexperimental-new-constant-interpreter
|
|
|
|
#if !__x86_64
|
|
// both-no-diagnostics
|
|
#endif
|
|
|
|
|
|
typedef decltype(nullptr) nullptr_t;
|
|
typedef __INTPTR_TYPE__ intptr_t;
|
|
|
|
static_assert(sizeof(int) == 4);
|
|
static_assert(sizeof(long long) == 8);
|
|
|
|
template <class To, class From>
|
|
constexpr To bit_cast(const From &from) {
|
|
static_assert(sizeof(To) == sizeof(From));
|
|
return __builtin_bit_cast(To, from);
|
|
}
|
|
|
|
template <class Intermediate, class Init>
|
|
constexpr bool check_round_trip(const Init &init) {
|
|
return bit_cast<Init>(bit_cast<Intermediate>(init)) == init;
|
|
}
|
|
|
|
template <class Intermediate, class Init>
|
|
constexpr Init round_trip(const Init &init) {
|
|
return bit_cast<Init>(bit_cast<Intermediate>(init));
|
|
}
|
|
|
|
|
|
|
|
|
|
namespace test_long_double {
|
|
#if __x86_64
|
|
/// FIXME: We could enable this, but since it aborts, it causes the usual mempory leak.
|
|
#if 0
|
|
constexpr __int128_t test_cast_to_int128 = bit_cast<__int128_t>((long double)0); // expected-error{{must be initialized by a constant expression}}\
|
|
// expected-note{{in call}}
|
|
#endif
|
|
constexpr long double ld = 3.1425926539;
|
|
|
|
struct bytes {
|
|
unsigned char d[16];
|
|
};
|
|
|
|
static_assert(round_trip<bytes>(ld), "");
|
|
|
|
static_assert(round_trip<long double>(10.0L));
|
|
|
|
constexpr long double foo() {
|
|
bytes A = __builtin_bit_cast(bytes, ld);
|
|
long double ld = __builtin_bit_cast(long double, A);
|
|
return ld;
|
|
}
|
|
static_assert(foo() == ld);
|
|
|
|
constexpr bool f(bool read_uninit) {
|
|
bytes b = bit_cast<bytes>(ld);
|
|
unsigned char ld_bytes[10] = {
|
|
0x0, 0x48, 0x9f, 0x49, 0xf0,
|
|
0x3c, 0x20, 0xc9, 0x0, 0x40,
|
|
};
|
|
|
|
for (int i = 0; i != 10; ++i)
|
|
if (ld_bytes[i] != b.d[i])
|
|
return false;
|
|
|
|
if (read_uninit && b.d[10]) // both-note{{read of uninitialized object is not allowed in a constant expression}}
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
static_assert(f(/*read_uninit=*/false), "");
|
|
static_assert(f(/*read_uninit=*/true), ""); // both-error{{static assertion expression is not an integral constant expression}} \
|
|
// both-note{{in call to 'f(true)'}}
|
|
constexpr bytes ld539 = {
|
|
0x0, 0x0, 0x0, 0x0,
|
|
0x0, 0x0, 0xc0, 0x86,
|
|
0x8, 0x40, 0x0, 0x0,
|
|
0x0, 0x0, 0x0, 0x0,
|
|
};
|
|
constexpr long double fivehundredandthirtynine = 539.0;
|
|
static_assert(bit_cast<long double>(ld539) == fivehundredandthirtynine, "");
|
|
|
|
struct LD {
|
|
long double v;
|
|
};
|
|
|
|
constexpr LD ld2 = __builtin_bit_cast(LD, ld539.d);
|
|
constexpr long double five39 = __builtin_bit_cast(long double, ld539.d);
|
|
static_assert(ld2.v == five39);
|
|
|
|
#else
|
|
static_assert(round_trip<__int128_t>(34.0L));
|
|
#endif
|
|
}
|