From c11ab6dc37d33b29e8e53bc1ee89e0b3df7cd942 Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Fri, 9 Oct 2026 18:16:56 +0200 Subject: [PATCH] MDEV-39150 Some data conversion macros fail to use memcpy() MDEV-37788 converted the uintNkorr() and intNstore() macros to use memcpy() and byte swap intrinsics, but the floating point and short/long conversion macros in big_endian.h and myisampack.h still accessed data one byte at a time, and those in little_endian.h were a mix of both. Compilers may emit slow byte-at-a-time loads and stores for such code. Reimplement the macros with memcpy(), and with MY_BSWAP32/MY_BSWAP64 where the byte order differs from the host. big_endian.h and little_endian.h no longer differ, so move the macros to my_byteorder.h and remove the two headers, which are no longer installed. Implement mi_float4store() etc. in myisampack.h with the same helper macros. Remove the unused ulongget() macro, and the code for the mixed-endian floating point layout (a little-endian CPU with big-endian floating point word order) from the macros, change_double_for_sort() and dtoa.c. It only applied to the obsolete ARM FPA format. Reimplement mach_double_read(), mach_double_write(), mach_float_read() and mach_float_write() in InnoDB with float8get(), float8store(), float4get() and float4store(), instead of copying bytes in a loop. The stored formats do not change. The unit test byte_order-t now checks the byte layout of the floating point macros and the sign extension of the native byte order macros, so no MTR test is added. --- include/CMakeLists.txt | 2 - include/big_endian.h | 82 ------------------- include/little_endian.h | 75 ----------------- include/my_byteorder.h | 92 ++++++++++++++++++++- include/myisampack.h | 106 ++++--------------------- sql/filesort.cc | 15 +--- storage/innobase/include/mach0data.inl | 54 +------------ strings/dtoa.c | 3 +- unittest/mysys/byte_order-t.c | 77 +++++++++++++++++- 9 files changed, 186 insertions(+), 320 deletions(-) delete mode 100644 include/big_endian.h delete mode 100644 include/little_endian.h diff --git a/include/CMakeLists.txt b/include/CMakeLists.txt index 6593819c4dce5..e53b11c0bb3b0 100644 --- a/include/CMakeLists.txt +++ b/include/CMakeLists.txt @@ -28,8 +28,6 @@ SET(HEADERS mariadb_capi_rename.h pack.h my_byteorder.h - little_endian.h - big_endian.h mysql_time.h ma_dyncol.h my_list.h diff --git a/include/big_endian.h b/include/big_endian.h deleted file mode 100644 index 6487f82924e65..0000000000000 --- a/include/big_endian.h +++ /dev/null @@ -1,82 +0,0 @@ -/* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; version 2 of the License. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ - -/* - Data in big-endian format. -*/ -#define float4store(T,A) do { *(T)= ((uchar *) &A)[3];\ - *((T)+1)=(char) ((uchar *) &A)[2];\ - *((T)+2)=(char) ((uchar *) &A)[1];\ - *((T)+3)=(char) ((uchar *) &A)[0]; } while(0) - -#define float4get(V,M) do { float def_temp;\ - ((uchar*) &def_temp)[0]=(M)[3];\ - ((uchar*) &def_temp)[1]=(M)[2];\ - ((uchar*) &def_temp)[2]=(M)[1];\ - ((uchar*) &def_temp)[3]=(M)[0];\ - (V)=def_temp; } while(0) - -#define float8store(T,V) do { *(T)= ((uchar *) &V)[7];\ - *((T)+1)=(char) ((uchar *) &V)[6];\ - *((T)+2)=(char) ((uchar *) &V)[5];\ - *((T)+3)=(char) ((uchar *) &V)[4];\ - *((T)+4)=(char) ((uchar *) &V)[3];\ - *((T)+5)=(char) ((uchar *) &V)[2];\ - *((T)+6)=(char) ((uchar *) &V)[1];\ - *((T)+7)=(char) ((uchar *) &V)[0]; } while(0) - -#define float8get(V,M) do { double def_temp;\ - ((uchar*) &def_temp)[0]=(M)[7];\ - ((uchar*) &def_temp)[1]=(M)[6];\ - ((uchar*) &def_temp)[2]=(M)[5];\ - ((uchar*) &def_temp)[3]=(M)[4];\ - ((uchar*) &def_temp)[4]=(M)[3];\ - ((uchar*) &def_temp)[5]=(M)[2];\ - ((uchar*) &def_temp)[6]=(M)[1];\ - ((uchar*) &def_temp)[7]=(M)[0];\ - (V) = def_temp; } while(0) - -#define ushortget(V,M) do { V = (uint16) (((uint16) ((uchar) (M)[1]))+\ - ((uint16) ((uint16) (M)[0]) << 8)); } while(0) -#define shortget(V,M) do { V = (short) (((short) ((uchar) (M)[1]))+\ - ((short) ((short) (M)[0]) << 8)); } while(0) -#define longget(V,M) do { int32 def_temp;\ - ((uchar*) &def_temp)[0]=(M)[0];\ - ((uchar*) &def_temp)[1]=(M)[1];\ - ((uchar*) &def_temp)[2]=(M)[2];\ - ((uchar*) &def_temp)[3]=(M)[3];\ - (V)=def_temp; } while(0) -#define ulongget(V,M) do { uint32 def_temp;\ - ((uchar*) &def_temp)[0]=(M)[0];\ - ((uchar*) &def_temp)[1]=(M)[1];\ - ((uchar*) &def_temp)[2]=(M)[2];\ - ((uchar*) &def_temp)[3]=(M)[3];\ - (V)=def_temp; } while(0) -#define shortstore(T,A) do { uint def_temp=(uint) (A) ;\ - *(((char*)T)+1)=(char)(def_temp); \ - *(((char*)T)+0)=(char)(def_temp >> 8); } while(0) -#define longstore(T,A) do { *(((char*)T)+3)=((A));\ - *(((char*)T)+2)=(((A) >> 8));\ - *(((char*)T)+1)=(((A) >> 16));\ - *(((char*)T)+0)=(((A) >> 24)); } while(0) - -#define floatget(V,M) memcpy(&V, (M), sizeof(float)) -/* Cast away type qualifiers (necessary as macro takes argument by value). */ -#define floatstore(T,V) memcpy((T), (void*) (&V), sizeof(float)) -#define doubleget(V,M) memcpy(&V, (M), sizeof(double)) -/* Cast away type qualifiers (necessary as macro takes argument by value). */ -#define doublestore(T,V) memcpy((T), (void*) &V, sizeof(double)) -#define longlongget(V,M) memcpy(&V, (M), sizeof(ulonglong)) -#define longlongstore(T,V) memcpy((T), &V, sizeof(ulonglong)) diff --git a/include/little_endian.h b/include/little_endian.h deleted file mode 100644 index dcddbdd9e27d2..0000000000000 --- a/include/little_endian.h +++ /dev/null @@ -1,75 +0,0 @@ -/* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; version 2 of the License. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ - -/* - Data in little-endian format. -*/ - -#ifndef MY_BYTE_ORDER_ARCH_OPTIMIZED -#define float4get(V,M) memcpy(&V, (M), sizeof(float)) -#define float4store(V,M) memcpy(V, (&M), sizeof(float)) -#define float8get(V,M) doubleget((V),(M)) -#define float8store(V,M) doublestore((V),(M)) - -/* Bi-endian hardware.... */ -#if defined(__FLOAT_WORD_ORDER) && (__FLOAT_WORD_ORDER == __BIG_ENDIAN) -#define doublestore(T,V) do { *(((char*)T)+0)=(char) ((uchar *) &V)[4];\ - *(((char*)T)+1)=(char) ((uchar *) &V)[5];\ - *(((char*)T)+2)=(char) ((uchar *) &V)[6];\ - *(((char*)T)+3)=(char) ((uchar *) &V)[7];\ - *(((char*)T)+4)=(char) ((uchar *) &V)[0];\ - *(((char*)T)+5)=(char) ((uchar *) &V)[1];\ - *(((char*)T)+6)=(char) ((uchar *) &V)[2];\ - *(((char*)T)+7)=(char) ((uchar *) &V)[3]; }\ - while(0) -#define doubleget(V,M) do { double def_temp;\ - ((uchar*) &def_temp)[0]=(M)[4];\ - ((uchar*) &def_temp)[1]=(M)[5];\ - ((uchar*) &def_temp)[2]=(M)[6];\ - ((uchar*) &def_temp)[3]=(M)[7];\ - ((uchar*) &def_temp)[4]=(M)[0];\ - ((uchar*) &def_temp)[5]=(M)[1];\ - ((uchar*) &def_temp)[6]=(M)[2];\ - ((uchar*) &def_temp)[7]=(M)[3];\ - (V) = def_temp; } while(0) -#else /* Bi-endian hardware.... */ - -/* Cast away type qualifiers (necessary as macro takes argument by value). */ -#define doublestore(T,V) memcpy((T), (void*) &V, sizeof(double)) -#define doubleget(V,M) memcpy(&V, (M), sizeof(double)) - -#endif /* Bi-endian hardware.... */ - -#endif /* !MY_BYTE_ORDER_ARCH_OPTIMIZED */ - -#define ushortget(V,M) do { uchar *pM= (uchar*)(M);V = uint2korr(pM);} while(0) -#define shortget(V,M) do { uchar *pM= (uchar*)(M);V = sint2korr(pM);} while(0) -#define longget(V,M) do { uchar *pM= (uchar*)(M);V = sint4korr(pM);} while(0) -#define ulongget(V,M) do { uchar *pM= (uchar*)(M);V = uint4korr(pM);} while(0) -#define shortstore(T,V) int2store(T,V) -#define longstore(T,V) int4store(T,V) - -#ifndef floatstore -/* Cast away type qualifiers (necessary as macro takes argument by value). */ -#define floatstore(T,V) memcpy((T), (void*) (&V), sizeof(float)) -#define floatget(V,M) memcpy(&V, (M), sizeof(float)) -#endif -#ifndef doubleget -#define doubleget(V,M) memcpy(&V, (M), sizeof(double)) -#define doublestore(T,V) memcpy((T), (void *) &V, sizeof(double)) -#endif /* doubleget */ - -#define longlongget(V,M) memcpy(&V, (M), sizeof(ulonglong)) -#define longlongstore(T,V) memcpy((T), &V, sizeof(ulonglong)) diff --git a/include/my_byteorder.h b/include/my_byteorder.h index a68af9520293f..4f456d4ab1e10 100644 --- a/include/my_byteorder.h +++ b/include/my_byteorder.h @@ -280,14 +280,98 @@ static inline int32 int4net(const void *p) } /* - Some macros for reading doubles and floats (clean, do not assume alignment) - These are defined in big_endian.h and little_endian.h + Macros for reading and storing floating point numbers, and 16-bit and 32-bit + integers in the native byte order. They have no alignment requirement. + + The float4*() and float8*() macros use the little-endian byte order on any + host. The mi_float*() macros in myisampack.h use the big-endian byte order. */ + +/* Copy 4 or 8 bytes in the reverse order */ +#define MY_SWAPCPY4(DST,SRC) \ + do { \ + uint32 tmp_; \ + memcpy(&tmp_, (SRC), sizeof(tmp_)); \ + tmp_= MY_BSWAP32(tmp_); \ + memcpy((DST), &tmp_, sizeof(tmp_)); \ + } while(0) + +#define MY_SWAPCPY8(DST,SRC) \ + do { \ + uint64 tmp_; \ + memcpy(&tmp_, (SRC), sizeof(tmp_)); \ + tmp_= MY_BSWAP64(tmp_); \ + memcpy((DST), &tmp_, sizeof(tmp_)); \ + } while(0) + +/* Copy 4 or 8 bytes between the host order and the little/big-endian order */ #ifdef WORDS_BIGENDIAN -#include "big_endian.h" +#define MY_COPY_LE4(DST,SRC) MY_SWAPCPY4(DST, SRC) +#define MY_COPY_LE8(DST,SRC) MY_SWAPCPY8(DST, SRC) +#define MY_COPY_BE4(DST,SRC) memcpy((DST), (SRC), 4) +#define MY_COPY_BE8(DST,SRC) memcpy((DST), (SRC), 8) #else -#include "little_endian.h" +#define MY_COPY_LE4(DST,SRC) memcpy((DST), (SRC), 4) +#define MY_COPY_LE8(DST,SRC) memcpy((DST), (SRC), 8) +#define MY_COPY_BE4(DST,SRC) MY_SWAPCPY4(DST, SRC) +#define MY_COPY_BE8(DST,SRC) MY_SWAPCPY8(DST, SRC) #endif +/* The "const void*" casts allow storing from volatile objects */ +#define float4store(T,A) MY_COPY_LE4((T), (const void*) &(A)) +#define float8store(T,V) MY_COPY_LE8((T), (const void*) &(V)) + +#define float4get(V,M) \ + do { \ + compile_time_assert(sizeof(V) == sizeof(float)); \ + MY_COPY_LE4(&(V), (M)); \ + } while(0) + +#define float8get(V,M) \ + do { \ + compile_time_assert(sizeof(V) == sizeof(double)); \ + MY_COPY_LE8(&(V), (M)); \ + } while(0) + +/* The following use the native byte order. */ +#define ushortget(V,M) \ + do { \ + uint16 tmp_; \ + memcpy(&tmp_, (M), sizeof(tmp_)); \ + (V)= tmp_; \ + } while(0) + +#define shortget(V,M) \ + do { \ + int16 tmp_; \ + memcpy(&tmp_, (M), sizeof(tmp_)); \ + (V)= tmp_; \ + } while(0) + +#define longget(V,M) \ + do { \ + int32 tmp_; \ + memcpy(&tmp_, (M), sizeof(tmp_)); \ + (V)= tmp_; \ + } while(0) + +#define shortstore(T,A) \ + do { \ + uint16 tmp_= (uint16) (A); \ + memcpy((T), &tmp_, sizeof(tmp_)); \ + } while(0) + +#define longstore(T,A) \ + do { \ + uint32 tmp_= (uint32) (A); \ + memcpy((T), &tmp_, sizeof(tmp_)); \ + } while(0) + +#define floatget(V,M) memcpy(&(V), (M), sizeof(float)) +#define doubleget(V,M) memcpy(&(V), (M), sizeof(double)) +#define longlongget(V,M) memcpy(&(V), (M), sizeof(ulonglong)) +#define longlongstore(T,V) memcpy((T), (const void*) &(V), sizeof(ulonglong)) +#define floatstore(T,V) memcpy((T), (const void*) &(V), sizeof(float)) +#define doublestore(T,V) memcpy((T), (const void*) &(V), sizeof(double)) #endif /* MY_BYTEORDER_INCLUDED */ diff --git a/include/myisampack.h b/include/myisampack.h index f3c5fe7114ad9..3f93c0c7b9470 100644 --- a/include/myisampack.h +++ b/include/myisampack.h @@ -141,96 +141,22 @@ mi_int4store((uchar*) (T) + 0, def_temp4);\ mi_int4store((uchar*) (T) + 4, def_temp3); } -#ifdef WORDS_BIGENDIAN - -#define mi_float4store(T,A) { ((uchar*) (T))[0]= ((uchar*) &A)[0];\ - ((uchar*) (T))[1]= ((uchar*) &A)[1];\ - ((uchar*) (T))[2]= ((uchar*) &A)[2];\ - ((uchar*) (T))[3]= ((uchar*) &A)[3]; } - -#define mi_float4get(V,M) { float def_temp;\ - ((uchar*) &def_temp)[0]= ((const uchar*) (M))[0];\ - ((uchar*) &def_temp)[1]= ((const uchar*) (M))[1]; \ - ((uchar*) &def_temp)[2]= ((const uchar*) (M))[2];\ - ((uchar*) &def_temp)[3]= ((const uchar*) (M))[3];\ - (V)= def_temp; } - -#define mi_float8store(T,V) { ((uchar*) (T))[0]= ((const uchar*) &V)[0];\ - ((uchar*) (T))[1]= ((const uchar*) &V)[1];\ - ((uchar*) (T))[2]= ((const uchar*) &V)[2];\ - ((uchar*) (T))[3]= ((const uchar*) &V)[3];\ - ((uchar*) (T))[4]= ((const uchar*) &V)[4];\ - ((uchar*) (T))[5]= ((const uchar*) &V)[5];\ - ((uchar*) (T))[6]= ((const uchar*) &V)[6];\ - ((uchar*) (T))[7]= ((const uchar*) &V)[7]; } - -#define mi_float8get(V,M) { double def_temp;\ - ((uchar*) &def_temp)[0]= ((const uchar*) (M))[0];\ - ((uchar*) &def_temp)[1]= ((const uchar*) (M))[1];\ - ((uchar*) &def_temp)[2]= ((const uchar*) (M))[2];\ - ((uchar*) &def_temp)[3]= ((const uchar*) (M))[3];\ - ((uchar*) &def_temp)[4]= ((const uchar*) (M))[4];\ - ((uchar*) &def_temp)[5]= ((const uchar*) (M))[5];\ - ((uchar*) &def_temp)[6]= ((const uchar*) (M))[6];\ - ((uchar*) &def_temp)[7]= ((const uchar*) (M))[7]; \ - (V)= def_temp; } -#else - -#define mi_float4store(T,A) { ((uchar*) (T))[0]= ((const uchar*) &A)[3];\ - ((uchar*) (T))[1]= ((const uchar*) &A)[2];\ - ((uchar*) (T))[2]= ((const uchar*) &A)[1];\ - ((uchar*) (T))[3]= ((const uchar*) &A)[0]; } - -#define mi_float4get(V,M) { float def_temp;\ - ((uchar*) &def_temp)[0]= ((const uchar*) (M))[3];\ - ((uchar*) &def_temp)[1]= ((const uchar*) (M))[2];\ - ((uchar*) &def_temp)[2]= ((const uchar*) (M))[1];\ - ((uchar*) &def_temp)[3]= ((const uchar*) (M))[0];\ - (V)= def_temp; } - -#if defined(__FLOAT_WORD_ORDER) && (__FLOAT_WORD_ORDER == __BIG_ENDIAN) -#define mi_float8store(T,V) { ((uchar*) (T))[0]= ((const uchar*) &V)[3];\ - ((uchar*) (T))[1]= ((const uchar*) &V)[2];\ - ((uchar*) (T))[2]= ((const uchar*) &V)[1];\ - ((uchar*) (T))[3]= ((const uchar*) &V)[0];\ - ((uchar*) (T))[4]= ((const uchar*) &V)[7];\ - ((uchar*) (T))[5]= ((const uchar*) &V)[6];\ - ((uchar*) (T))[6]= ((const uchar*) &V)[5];\ - ((uchar*) (T))[7]= ((const uchar*) &V)[4];} - -#define mi_float8get(V,M) { double def_temp;\ - ((uchar*) &def_temp)[0]= ((const uchar*) (M))[3];\ - ((uchar*) &def_temp)[1]= ((const uchar*) (M))[2];\ - ((uchar*) &def_temp)[2]= ((const uchar*) (M))[1];\ - ((uchar*) &def_temp)[3]= ((const uchar*) (M))[0];\ - ((uchar*) &def_temp)[4]= ((const uchar*) (M))[7];\ - ((uchar*) &def_temp)[5]= ((const uchar*) (M))[6];\ - ((uchar*) &def_temp)[6]= ((const uchar*) (M))[5];\ - ((uchar*) &def_temp)[7]= ((const uchar*) (M))[4];\ - (V)= def_temp; } - -#else -#define mi_float8store(T,V) { ((uchar*) (T))[0]= ((const uchar*) &V)[7];\ - ((uchar*) (T))[1]= ((const uchar*) &V)[6];\ - ((uchar*) (T))[2]= ((const uchar*) &V)[5];\ - ((uchar*) (T))[3]= ((const uchar*) &V)[4];\ - ((uchar*) (T))[4]= ((const uchar*) &V)[3];\ - ((uchar*) (T))[5]= ((const uchar*) &V)[2];\ - ((uchar*) (T))[6]= ((const uchar*) &V)[1];\ - ((uchar*) (T))[7]= ((const uchar*) &V)[0];} - -#define mi_float8get(V,M) { double def_temp;\ - ((uchar*) &def_temp)[0]= ((const uchar*) (M))[7];\ - ((uchar*) &def_temp)[1]= ((const uchar*) (M))[6];\ - ((uchar*) &def_temp)[2]= ((const uchar*) (M))[5];\ - ((uchar*) &def_temp)[3]= ((const uchar*) (M))[4];\ - ((uchar*) &def_temp)[4]= ((const uchar*) (M))[3];\ - ((uchar*) &def_temp)[5]= ((const uchar*) (M))[2];\ - ((uchar*) &def_temp)[6]= ((const uchar*) (M))[1];\ - ((uchar*) &def_temp)[7]= ((const uchar*) (M))[0];\ - (V)= def_temp; } -#endif /* __FLOAT_WORD_ORDER */ -#endif /* WORDS_BIGENDIAN */ +/* Floating point numbers in MyISAM/Aria keys and in filesort keys are stored + in big-endian byte order. */ +#define mi_float4store(T,A) MY_COPY_BE4((T), (const void*) &(A)) +#define mi_float8store(T,V) MY_COPY_BE8((T), (const void*) &(V)) + +#define mi_float4get(V,M) \ + do { \ + compile_time_assert(sizeof(V) == sizeof(float)); \ + MY_COPY_BE4(&(V), (M)); \ + } while(0) + +#define mi_float8get(V,M) \ + do { \ + compile_time_assert(sizeof(V) == sizeof(double)); \ + MY_COPY_BE8(&(V), (M)); \ + } while(0) /* Fix to avoid warnings when sizeof(ha_rows) == sizeof(long) */ diff --git a/sql/filesort.cc b/sql/filesort.cc index e2f85e58fbbb3..6fadc447491f1 100644 --- a/sql/filesort.cc +++ b/sql/filesort.cc @@ -2413,20 +2413,7 @@ void change_double_for_sort(double nr,uchar *to) } else { -#ifdef WORDS_BIGENDIAN - memcpy(tmp, &nr, sizeof(nr)); -#else - { - uchar *ptr= (uchar*) &nr; -#if defined(__FLOAT_WORD_ORDER) && (__FLOAT_WORD_ORDER == __BIG_ENDIAN) - tmp[0]= ptr[3]; tmp[1]=ptr[2]; tmp[2]= ptr[1]; tmp[3]=ptr[0]; - tmp[4]= ptr[7]; tmp[5]=ptr[6]; tmp[6]= ptr[5]; tmp[7]=ptr[4]; -#else - tmp[0]= ptr[7]; tmp[1]=ptr[6]; tmp[2]= ptr[5]; tmp[3]=ptr[4]; - tmp[4]= ptr[3]; tmp[5]=ptr[2]; tmp[6]= ptr[1]; tmp[7]=ptr[0]; -#endif - } -#endif + mi_float8store(tmp, nr); if (tmp[0] & 128) /* Negative */ { /* make complement */ uint i; diff --git a/storage/innobase/include/mach0data.inl b/storage/innobase/include/mach0data.inl index 8ebfb4543559f..21320d481aa21 100644 --- a/storage/innobase/include/mach0data.inl +++ b/storage/innobase/include/mach0data.inl @@ -554,19 +554,7 @@ mach_double_read( const byte* b) /*!< in: pointer to memory from where to read */ { double d; - ulint i; - byte* ptr; - - ptr = (byte*) &d; - - for (i = 0; i < sizeof(double); i++) { -#ifdef WORDS_BIGENDIAN - ptr[sizeof(double) - i - 1] = b[i]; -#else - ptr[i] = b[i]; -#endif - } - + float8get(d, b); return(d); } @@ -579,18 +567,7 @@ mach_double_write( byte* b, /*!< in: pointer to memory where to write */ double d) /*!< in: double */ { - ulint i; - byte* ptr; - - ptr = (byte*) &d; - - for (i = 0; i < sizeof(double); i++) { -#ifdef WORDS_BIGENDIAN - b[i] = ptr[sizeof(double) - i - 1]; -#else - b[i] = ptr[i]; -#endif - } + float8store(b, d); } /*********************************************************//** @@ -603,19 +580,7 @@ mach_float_read( const byte* b) /*!< in: pointer to memory from where to read */ { float d; - ulint i; - byte* ptr; - - ptr = (byte*) &d; - - for (i = 0; i < sizeof(float); i++) { -#ifdef WORDS_BIGENDIAN - ptr[sizeof(float) - i - 1] = b[i]; -#else - ptr[i] = b[i]; -#endif - } - + float4get(d, b); return(d); } @@ -628,18 +593,7 @@ mach_float_write( byte* b, /*!< in: pointer to memory where to write */ float d) /*!< in: float */ { - ulint i; - byte* ptr; - - ptr = (byte*) &d; - - for (i = 0; i < sizeof(float); i++) { -#ifdef WORDS_BIGENDIAN - b[i] = ptr[sizeof(float) - i - 1]; -#else - b[i] = ptr[i]; -#endif - } + float4store(b, d); } /*********************************************************//** diff --git a/strings/dtoa.c b/strings/dtoa.c index f8cdbd1cccad2..d87f7163b1d4c 100644 --- a/strings/dtoa.c +++ b/strings/dtoa.c @@ -549,8 +549,7 @@ typedef uint64 ULLong; typedef union { double d; ULong L[2]; } U; -#if defined(WORDS_BIGENDIAN) || (defined(__FLOAT_WORD_ORDER) && \ - (__FLOAT_WORD_ORDER == __BIG_ENDIAN)) +#ifdef WORDS_BIGENDIAN #define word0(x) (x)->L[0] #define word1(x) (x)->L[1] #else diff --git a/unittest/mysys/byte_order-t.c b/unittest/mysys/byte_order-t.c index d4481a4135b60..58a18b7037f59 100644 --- a/unittest/mysys/byte_order-t.c +++ b/unittest/mysys/byte_order-t.c @@ -83,6 +83,81 @@ void test_byte_order() TEST(mi_int8store, mi_uint8korr, ulonglong, 0x0807060504030201, ARRAY_8(8, 7, 6, 5, 4, 3, 2, 1)); + /* + Floating point macros. The stored bytes are IEEE 754, little-endian + (float4store etc.) or big-endian (the mi_ variants), on any host. + */ +#define TEST_FLOAT(STORE_NAME, LOAD_NAME, TYPE, VALUE, BYTES) \ + { \ + TYPE value= VALUE, loaded; \ + uchar bytes[]= BYTES; \ + STORE_NAME(aligned, value); \ + ok(!memcmp(aligned, bytes, sizeof(bytes)), "aligned\t\t" #STORE_NAME); \ + LOAD_NAME(loaded, aligned); \ + ok(!memcmp(&loaded, &value, sizeof(value)), "aligned\t\t" #LOAD_NAME); \ + STORE_NAME(not_aligned, value); \ + ok(!memcmp(not_aligned, bytes, sizeof(bytes)), \ + "not aligned\t" #STORE_NAME); \ + LOAD_NAME(loaded, not_aligned); \ + ok(!memcmp(&loaded, &value, sizeof(value)), "not aligned\t" #LOAD_NAME); \ + } + + TEST_FLOAT(float4store, float4get, float, 1.0f, ARRAY_4(0, 0, 0x80, 0x3f)); + TEST_FLOAT(float8store, float8get, double, 1.0, + ARRAY_8(0, 0, 0, 0, 0, 0, 0xf0, 0x3f)); + TEST_FLOAT(float8store, float8get, double, -0.0, + ARRAY_8(0, 0, 0, 0, 0, 0, 0, 0x80)); + TEST_FLOAT(mi_float4store, mi_float4get, float, 1.0f, + ARRAY_4(0x3f, 0x80, 0, 0)); + TEST_FLOAT(mi_float4store, mi_float4get, float, -2.0f, + ARRAY_4(0xc0, 0, 0, 0)); + TEST_FLOAT(mi_float8store, mi_float8get, double, 1.0, + ARRAY_8(0x3f, 0xf0, 0, 0, 0, 0, 0, 0)); + TEST_FLOAT(mi_float8store, mi_float8get, double, -2.0, + ARRAY_8(0xc0, 0, 0, 0, 0, 0, 0, 0)); + + { + /* The bits of a NaN must be preserved, too */ + ulonglong bits= 0x7ff8000000000001ULL; + uchar bytes[]= ARRAY_8(1, 0, 0, 0, 0, 0, 0xf8, 0x7f); + double nan, loaded; + memcpy(&nan, &bits, sizeof(nan)); + float8store(aligned, nan); + ok(!memcmp(aligned, bytes, sizeof(bytes)), "NaN\t\tfloat8store"); + float8get(loaded, aligned); + ok(!memcmp(&loaded, &nan, sizeof(nan)), "NaN\t\tfloat8get"); + } + + /* Native byte order integers, including sign and zero extension on read */ +#define TEST_NATIVE(P, NAME) \ + { \ + int16 s= -2; \ + uint16 us= 0xfffe; \ + int32 l= -70000; \ + int16 s_loaded; \ + int i_loaded; \ + int32 l_loaded; \ + longlong ll_loaded; \ + shortstore(P, s); \ + shortget(s_loaded, P); \ + ok(s_loaded == s, NAME "\tshortstore/shortget"); \ + shortget(i_loaded, P); \ + ok(i_loaded == -2, NAME "\tshortget sign extension"); \ + shortstore(P, us); \ + ushortget(i_loaded, P); \ + ok(i_loaded == 0xfffe, NAME "\tushortget zero extension"); \ + longstore(P, l); \ + longget(l_loaded, P); \ + ok(l_loaded == l, NAME "\tlongstore/longget"); \ + longget(ll_loaded, P); \ + ok(ll_loaded == -70000, NAME "\tlongget sign extension"); \ + } + + TEST_NATIVE(aligned, "aligned"); + TEST_NATIVE(not_aligned, "not aligned"); + +#undef TEST_NATIVE +#undef TEST_FLOAT #undef ARRAY_8 #undef ARRAY_7 #undef ARRAY_6 @@ -96,7 +171,7 @@ void test_byte_order() int main(int argc __attribute__((unused)), char **argv __attribute__((unused))) { - plan(68); + plan(108); test_byte_order(); return exit_status(); }