diff --git a/CMakeLists.txt b/CMakeLists.txt index 2f48dc57e..4bbdfe3fb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -198,7 +198,9 @@ ELSE () MY_CHECK_AND_SET_COMPILER_FLAG("-D_DEBUG -O0" DEBUG) ENDIF() - +IF (MASK_LONGDOUBLE) + MY_CHECK_AND_SET_COMPILER_FLAG("-DMASK_LONGDOUBLE") +ENDIF() SET (ENGINE_LDFLAGS "-Wl,--no-as-needed -Wl,--add-needed") SET (ENGINE_DT_LIB datatypes) diff --git a/cmake/configureEngine.cmake b/cmake/configureEngine.cmake index 07c5326d6..305f9f9a8 100644 --- a/cmake/configureEngine.cmake +++ b/cmake/configureEngine.cmake @@ -6,6 +6,7 @@ INCLUDE (CheckIncludeFiles) INCLUDE (CheckIncludeFileCXX) INCLUDE (CheckCSourceCompiles) +INCLUDE (CheckCXXSourceRuns) INCLUDE (CheckCXXSourceCompiles) INCLUDE (CheckStructHasMember) INCLUDE (CheckLibraryExists) @@ -719,3 +720,20 @@ EXECUTE_PROCESS( COMMAND rm -f conftest.data conftest.file conftest.sym WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} ) + +CHECK_CXX_SOURCE_RUNS(" +#include +int main() +{ + // If long double is 16 bytes and digits and exponent are 64 and 16384 respectively, then we need to mask out the + // unused bits, as they contain garbage. There are times we test for equality by memcmp of a buffer containing, + // in part, the long double set here. Garbage bytes will adversly affect that compare. + // Note: There may be compilers that store 80 bit floats in 12 bytes. We do not account for that here. I don't believe + // there are any modern Linux compilers that do that as a default. Windows uses 64 bits, so no masking is needed. + if (std::numeric_limits::digits == 64 + && std::numeric_limits::max_exponent == 16384 + && sizeof(long double) == 16) + return 0; + return 1; +}" +MASK_LONGDOUBLE) diff --git a/utils/rowgroup/rowgroup.h b/utils/rowgroup/rowgroup.h index 79a0f4b29..7ea19979e 100644 --- a/utils/rowgroup/rowgroup.h +++ b/utils/rowgroup/rowgroup.h @@ -1369,12 +1369,10 @@ inline void Row::setFloatField(float val, uint32_t colIndex) inline void Row::setLongDoubleField(const long double& val, uint32_t colIndex) { uint8_t* p = &data[offsets[colIndex]]; - *((long double*)p) = val; - if (sizeof(long double) == 16) - { - // zero out the unused portion as there may be garbage there. - *((uint64_t*)p+1) &= 0x000000000000FFFFULL; - } + *reinterpret_cast(p) = val; +#ifdef MASK_LONGDOUBLE + *(reinterpret_cast(p)+1) &= 0x000000000000FFFFULL; +#endif } inline void Row::setInt128Field(const int128_t& val, uint32_t colIndex)