From: <man...@us...> - 2014-06-03 07:41:27
|
Revision: 4081 http://sourceforge.net/p/modplug/code/4081 Author: manxorist Date: 2014-06-03 07:41:16 +0000 (Tue, 03 Jun 2014) Log Message: ----------- [Ref] Add MPT_COMPILER_UNION_TYPE_ALIASES macro for MSVC and GCC. [Fix] Only use unions for float<->int type punning if MPT_COMPILER_UNION_TYPE_ALIASES. [Ref] Add MPT_PLATFORM_IEEE_FLOAT which indictaes that the platform uses standard ieee754 floating point (currently always defined). [Ref] Add explicit-endian ieee754 floating point types. When appropriate, only use a tiny wrapper around the native type in order to give compilers better optimization opportunities which hab been lost when introducing uint8_4. [Ref] Avoid endian-ambiguous storing of floating point data in uint8_4. [Ref] Kill uint8_4. [Ref] Kill union FloatInt32. [Imp] Add more float<->int test cases. [Ref] Kill MPT_PLATFORM_FLIPPED_FLOAT_ENDIAN. This is better handled as a special case in EncodeIEE754binary32 and DecodeIEEE754binary32 (when required in the future). [Ref] Tiny cleanups. Modified Paths: -------------- trunk/OpenMPT/common/typedefs.h trunk/OpenMPT/mptrack/VstPresets.cpp trunk/OpenMPT/soundlib/Endianness.h trunk/OpenMPT/soundlib/FileReader.h trunk/OpenMPT/soundlib/SampleFormatConverters.h trunk/OpenMPT/test/test.cpp Modified: trunk/OpenMPT/common/typedefs.h =================================================================== --- trunk/OpenMPT/common/typedefs.h 2014-06-02 17:13:19 UTC (rev 4080) +++ trunk/OpenMPT/common/typedefs.h 2014-06-03 07:41:16 UTC (rev 4081) @@ -34,10 +34,34 @@ +#if MPT_COMPILER_GCC || MPT_COMPILER_MSVC +// Compiler supports type-punning through unions. This is not stricly standard-conforming. +// For GCC, this is documented, for MSVC this is apparently not documented, but we assume it. +#define MPT_COMPILER_UNION_TYPE_ALIASES 1 +#endif + +#ifndef MPT_COMPILER_UNION_TYPE_ALIASES +// Compiler does not support type-punning through unions. std::memcpy is used instead. +// This is the safe fallback and strictly standard-conforming. +// Another standard-compliant alternative would be casting pointers to a character type pointer. +// This results in rather unreadable code and, +// in most cases, compilers generate better code by just inlining the memcpy anyway. +// (see <http://blog.regehr.org/archives/959>). +#define MPT_COMPILER_UNION_TYPE_ALIASES 0 +#endif + + + +// Platform has native IEEE floating point representation. +// (Currently always assumed) +#define MPT_PLATFORM_IEEE_FLOAT 1 + + + #if MPT_COMPILER_MSVC #if MPT_MSVC_BEFORE(2010,0) -#define nullptr 0 +#define nullptr 0 #endif #elif MPT_COMPILER_GCC @@ -369,21 +393,21 @@ explicit int24(int other) { #ifdef MPT_PLATFORM_BIG_ENDIAN - bytes[0] = ((unsigned int)other>>16)&0xff; - bytes[1] = ((unsigned int)other>> 8)&0xff; - bytes[2] = ((unsigned int)other>> 0)&0xff; + bytes[0] = (static_cast<unsigned int>(other)>>16)&0xff; + bytes[1] = (static_cast<unsigned int>(other)>> 8)&0xff; + bytes[2] = (static_cast<unsigned int>(other)>> 0)&0xff; #else - bytes[0] = ((unsigned int)other>> 0)&0xff; - bytes[1] = ((unsigned int)other>> 8)&0xff; - bytes[2] = ((unsigned int)other>>16)&0xff; + bytes[0] = (static_cast<unsigned int>(other)>> 0)&0xff; + bytes[1] = (static_cast<unsigned int>(other)>> 8)&0xff; + bytes[2] = (static_cast<unsigned int>(other)>>16)&0xff; #endif } operator int() const { #ifdef MPT_PLATFORM_BIG_ENDIAN - return ((int8)bytes[0] * 65536) + (bytes[1] * 256) + bytes[2]; + return (static_cast<int8>(bytes[0]) * 65536) + (bytes[1] * 256) + bytes[2]; #else - return ((int8)bytes[2] * 65536) + (bytes[1] * 256) + bytes[0]; + return (static_cast<int8>(bytes[2]) * 65536) + (bytes[1] * 256) + bytes[0]; #endif } }; @@ -392,32 +416,11 @@ #define int24_max (0+0x007fffff) -// 32-bit wrapper for encoding 32-bit floats -struct uint8_4 -{ - uint8 x[4]; - uint8_4() { } - uint8_4(uint8 a, uint8 b, uint8 c, uint8 d) { x[0] = a; x[1] = b; x[2] = c; x[3] = d; } - uint32 GetBE() const { return (x[0] << 24) | (x[1] << 16) | (x[2] << 8) | (x[3] << 0); } - uint32 GetLE() const { return (x[0] << 0) | (x[1] << 8) | (x[2] << 16) | (x[3] << 24); } - uint8_4 & SetBE(uint32 y) { x[0] = (y >> 24)&0xff; x[1] = (y >> 16)&0xff; x[2] = (y >> 8)&0xff; x[3] = (y >> 0)&0xff; return *this; } - uint8_4 & SetLE(uint32 y) { x[0] = (y >> 0)&0xff; x[1] = (y >> 8)&0xff; x[2] = (y >> 16)&0xff; x[3] = (y >> 24)&0xff; return *this; } -}; -STATIC_ASSERT(sizeof(uint8_4) == 4); - - typedef float float32; STATIC_ASSERT(sizeof(float32) == 4); -union FloatInt32 -{ - float32 f; - uint32 i; -}; -STATIC_ASSERT(sizeof(FloatInt32) == 4); - #if !defined(MPT_USE_WINDOWS_H) // openmpt assumes these type have exact WIN32 semantics Modified: trunk/OpenMPT/mptrack/VstPresets.cpp =================================================================== --- trunk/OpenMPT/mptrack/VstPresets.cpp 2014-06-02 17:13:19 UTC (rev 4080) +++ trunk/OpenMPT/mptrack/VstPresets.cpp 2014-06-03 07:41:16 UTC (rev 4081) @@ -265,7 +265,7 @@ void VSTPresets::WriteBE(float v, std::ostream &f) //------------------------------------------------ { - Write(EncodeFloatBE(v), f); + Write(IEEE754binary32BE(v), f); } Modified: trunk/OpenMPT/soundlib/Endianness.h =================================================================== --- trunk/OpenMPT/soundlib/Endianness.h 2014-06-02 17:13:19 UTC (rev 4080) +++ trunk/OpenMPT/soundlib/Endianness.h 2014-06-03 07:41:16 UTC (rev 4081) @@ -105,49 +105,199 @@ #undef bswap16 #undef bswap32 -static forceinline float DecodeFloatNE(uint32 i) + +// 1.0f --> 0x3f800000u +static forceinline uint32 EncodeIEEE754binary32(float32 f) { - FloatInt32 conv; - conv.i = i; - return conv.f; -} -static forceinline uint32 EncodeFloatNE(float f) -{ - FloatInt32 conv; - conv.f = f; - return conv.i; -} -static forceinline float DecodeFloatBE(uint8_4 x) -{ - #if defined(MPT_PLATFORM_FLIPPED_FLOAT_ENDIAN) - return DecodeFloatNE(x.GetLE()); +#if MPT_PLATFORM_IEEE_FLOAT + STATIC_ASSERT(sizeof(uint32) == sizeof(float32)); + #if MPT_COMPILER_UNION_TYPE_ALIASES + union { + float32 f; + uint32 i; + } conv; + conv.f = f; + return conv.i; #else - return DecodeFloatNE(x.GetBE()); + uint32 i = 0; + std::memcpy(&i, &f, sizeof(float32)); + return i; #endif +#else + #error "IEEE754 single precision float support is required (for now)" +#endif } -static forceinline uint8_4 EncodeFloatBE(float f) + +// 0x3f800000u --> 1.0f +static forceinline float32 DecodeIEEE754binary32(uint32 i) { - #if defined(MPT_PLATFORM_FLIPPED_FLOAT_ENDIAN) - return uint8_4().SetLE(EncodeFloatNE(f)); +#if MPT_PLATFORM_IEEE_FLOAT + STATIC_ASSERT(sizeof(uint32) == sizeof(float32)); + #if MPT_COMPILER_UNION_TYPE_ALIASES + union { + uint32 i; + float32 f; + } conv; + conv.i = i; + return conv.f; #else - return uint8_4().SetBE(EncodeFloatNE(f)); + float32 f = 0.0f; + std::memcpy(&f, &i, sizeof(float32)); + return f; #endif +#else + #error "IEEE754 single precision float support is required (for now)" +#endif } -static forceinline float DecodeFloatLE(uint8_4 x) + + +// template parameters are byte indices corresponding to the individual bytes of iee754 in memory +template<std::size_t hihi, std::size_t hilo, std::size_t lohi, std::size_t lolo> +struct IEEE754binary32Emulated { - #if defined(MPT_PLATFORM_FLIPPED_FLOAT_ENDIAN) - return DecodeFloatNE(x.GetBE()); - #else - return DecodeFloatNE(x.GetLE()); - #endif -} -static forceinline uint8_4 EncodeFloatLE(float f) +private: + typedef IEEE754binary32Emulated<hihi,hilo,lohi,lolo> self_t; + uint8 bytes[4]; +public: + forceinline uint8 GetByte(std::size_t i) const + { + return bytes[i]; + } + forceinline IEEE754binary32Emulated() { } + forceinline explicit IEEE754binary32Emulated(float32 f) + { + SetInt32(EncodeIEEE754binary32(f)); + } + // b0...b3 are in memroy order, i.e. depend on the endianness of this type + // little endian: (0x00,0x00,0x80,0x3f) + // big endian: (0x3f,0x80,0x00,0x00) + forceinline explicit IEEE754binary32Emulated(uint8 b0, uint8 b1, uint8 b2, uint8 b3) + { + bytes[0] = b0; + bytes[1] = b1; + bytes[2] = b2; + bytes[3] = b3; + } + forceinline operator float32 () const + { + return DecodeIEEE754binary32(GetInt32()); + } + forceinline self_t & SetInt32(uint32 i) + { + bytes[hihi] = static_cast<uint8>(i >> 24); + bytes[hilo] = static_cast<uint8>(i >> 16); + bytes[lohi] = static_cast<uint8>(i >> 8); + bytes[lolo] = static_cast<uint8>(i >> 0); + return *this; + } + forceinline uint32 GetInt32() const + { + return 0u + | (static_cast<uint32>(bytes[hihi]) << 24) + | (static_cast<uint32>(bytes[hilo]) << 16) + | (static_cast<uint32>(bytes[lohi]) << 8) + | (static_cast<uint32>(bytes[lolo]) << 0) + ; + } + forceinline bool operator == (const self_t &cmp) const + { + return true + && bytes[0] == cmp.bytes[0] + && bytes[1] == cmp.bytes[1] + && bytes[2] == cmp.bytes[2] + && bytes[3] == cmp.bytes[3] + ; + } + forceinline bool operator != (const self_t &cmp) const + { + return !(*this == cmp); + } +}; + +#if MPT_PLATFORM_IEEE_FLOAT + +struct IEEE754binary32Native { - #if defined(MPT_PLATFORM_FLIPPED_FLOAT_ENDIAN) - return uint8_4().SetBE(EncodeFloatNE(f)); - #else - return uint8_4().SetLE(EncodeFloatNE(f)); - #endif -} +private: + float32 value; +public: + forceinline uint8 GetByte(std::size_t i) const + { + #if defined(MPT_PLATFORM_LITTLE_ENDIAN) + return static_cast<uint8>(EncodeIEEE754binary32(value) >> (i*8)); + #elif defined(MPT_PLATFORM_BIG_ENDIAN) + return static_cast<uint8>(EncodeIEEE754binary32(value) >> ((4-1-i)*8)); + #else + STATIC_ASSERT(false); + #endif + } + forceinline IEEE754binary32Native() { } + forceinline explicit IEEE754binary32Native(float32 f) + { + value = f; + } + // b0...b3 are in memroy order, i.e. depend on the endianness of this type + // little endian: (0x00,0x00,0x80,0x3f) + // big endian: (0x3f,0x80,0x00,0x00) + forceinline explicit IEEE754binary32Native(uint8 b0, uint8 b1, uint8 b2, uint8 b3) + { + #if defined(MPT_PLATFORM_LITTLE_ENDIAN) + value = DecodeIEEE754binary32(0u + | (static_cast<uint32>(b0) << 0) + | (static_cast<uint32>(b1) << 8) + | (static_cast<uint32>(b2) << 16) + | (static_cast<uint32>(b3) << 24) + ); + #elif defined(MPT_PLATFORM_BIG_ENDIAN) + value = DecodeIEEE754binary32(0u + | (static_cast<uint32>(b0) << 24) + | (static_cast<uint32>(b1) << 16) + | (static_cast<uint32>(b2) << 8) + | (static_cast<uint32>(b3) << 0) + ); + #else + STATIC_ASSERT(false); + #endif + } + forceinline operator float32 () const + { + return value; + } + forceinline IEEE754binary32Native & SetInt32(uint32 i) + { + value = DecodeIEEE754binary32(i); + return *this; + } + forceinline uint32 GetInt32() const + { + return EncodeIEEE754binary32(value); + } + forceinline bool operator == (const IEEE754binary32Native &cmp) const + { + return value == cmp.value; + } + forceinline bool operator != (const IEEE754binary32Native &cmp) const + { + return value != cmp.value; + } +}; +#if defined(MPT_PLATFORM_LITTLE_ENDIAN) +typedef IEEE754binary32Native IEEE754binary32LE; +typedef IEEE754binary32Emulated<0,1,2,3> IEEE754binary32BE; +#elif defined(MPT_PLATFORM_BIG_ENDIAN) +typedef IEEE754binary32Emulated<3,2,1,0> IEEE754binary32LE; +typedef IEEE754binary32Native IEEE754binary32BE; +#endif + +#else // !MPT_PLATFORM_IEEE_FLOAT + +typedef IEEE754binary32Emulated<3,2,1,0> IEEE754binary32LE; +typedef IEEE754binary32Emulated<0,1,2,3> IEEE754binary32BE; + +#endif // MPT_PLATFORM_IEEE_FLOAT + +STATIC_ASSERT(sizeof(IEEE754binary32LE) == 4); +STATIC_ASSERT(sizeof(IEEE754binary32BE) == 4); + OPENMPT_NAMESPACE_END Modified: trunk/OpenMPT/soundlib/FileReader.h =================================================================== --- trunk/OpenMPT/soundlib/FileReader.h 2014-06-02 17:13:19 UTC (rev 4080) +++ trunk/OpenMPT/soundlib/FileReader.h 2014-06-03 07:41:16 UTC (rev 4081) @@ -767,10 +767,10 @@ // If successful, the file cursor is advanced by the size of the float. float ReadFloatLE() { - uint8_4 target; + IEEE754binary32LE target; if(Read(target)) { - return DecodeFloatLE(target); + return target; } else { return 0.0f; @@ -781,10 +781,10 @@ // If successful, the file cursor is advanced by the size of the float. float ReadFloatBE() { - uint8_4 target; + IEEE754binary32BE target; if(Read(target)) { - return DecodeFloatBE(target); + return target; } else { return 0.0f; Modified: trunk/OpenMPT/soundlib/SampleFormatConverters.h =================================================================== --- trunk/OpenMPT/soundlib/SampleFormatConverters.h 2014-06-02 17:13:19 UTC (rev 4080) +++ trunk/OpenMPT/soundlib/SampleFormatConverters.h 2014-06-03 07:41:16 UTC (rev 4081) @@ -166,7 +166,7 @@ static const int input_inc = 4; forceinline output_t operator() (const input_t *inBuf) { - return DecodeFloatLE(uint8_4(uint8(inBuf[loLoByteIndex]), uint8(inBuf[loHiByteIndex]), uint8(inBuf[hiLoByteIndex]), uint8(inBuf[hiHiByteIndex]))); + return IEEE754binary32LE(uint8(inBuf[loLoByteIndex]), uint8(inBuf[loHiByteIndex]), uint8(inBuf[hiLoByteIndex]), uint8(inBuf[hiHiByteIndex])); } }; @@ -179,7 +179,7 @@ float factor; forceinline output_t operator() (const input_t *inBuf) { - return factor * DecodeFloatLE(uint8_4(uint8(inBuf[loLoByteIndex]), uint8(inBuf[loHiByteIndex]), uint8(inBuf[hiLoByteIndex]), uint8(inBuf[hiHiByteIndex]))); + return factor * IEEE754binary32LE(uint8(inBuf[loLoByteIndex]), uint8(inBuf[loHiByteIndex]), uint8(inBuf[hiLoByteIndex]), uint8(inBuf[hiHiByteIndex])); } forceinline DecodeScaledFloat32(float scaleFactor) : factor(scaleFactor) Modified: trunk/OpenMPT/test/test.cpp =================================================================== --- trunk/OpenMPT/test/test.cpp 2014-06-02 17:13:19 UTC (rev 4080) +++ trunk/OpenMPT/test/test.cpp 2014-06-03 07:41:16 UTC (rev 4081) @@ -196,23 +196,6 @@ } -static float AsFloat(uint32 x) -//---------------------------- -{ - FloatInt32 conv; - conv.i = x; - return conv.f; -} - -static uint32 AsInt(float x) -//-------------------------- -{ - FloatInt32 conv; - conv.f = x; - return conv.i; -} - - static void TestFloatFormat(double x, const char * format, mpt::FormatFlags f, std::size_t width = 0, int precision = -1) { #ifdef MODPLUG_TRACKER @@ -284,18 +267,22 @@ //----------------------------- { - VERIFY_EQUAL(0x3f800000u, AsInt(1.0f)); - VERIFY_EQUAL(AsFloat(0x3f800000u), 1.0f); - VERIFY_EQUAL(AsFloat(0x00000000u), 0.0f); - VERIFY_EQUAL(AsFloat(0xbf800000u), -1.0f); - VERIFY_EQUAL(DecodeFloatNE(0x3f800000u), 1.0f); - VERIFY_EQUAL(DecodeFloatLE(uint8_4(0x00,0x00,0x80,0x3f)), 1.0f); - VERIFY_EQUAL(DecodeFloatBE(uint8_4(0x3f,0x80,0x00,0x00)), 1.0f); - VERIFY_EQUAL(EncodeFloatNE(1.0f), 0x3f800000u); - VERIFY_EQUAL(EncodeFloatBE(1.0f).GetBE(), 0x3f800000u); - VERIFY_EQUAL(EncodeFloatLE(1.0f).GetBE(), 0x0000803fu); - VERIFY_EQUAL(EncodeFloatLE(1.0f).GetLE(), 0x3f800000u); - VERIFY_EQUAL(EncodeFloatBE(1.0f).GetLE(), 0x0000803fu); + VERIFY_EQUAL(EncodeIEEE754binary32(1.0f), 0x3f800000u); + VERIFY_EQUAL(EncodeIEEE754binary32(-1.0f), 0xbf800000u); + VERIFY_EQUAL(DecodeIEEE754binary32(0x00000000u), 0.0f); + VERIFY_EQUAL(DecodeIEEE754binary32(0x41840000u), 16.5f); + VERIFY_EQUAL(DecodeIEEE754binary32(0x3faa0000u), 1.328125f); + VERIFY_EQUAL(DecodeIEEE754binary32(0xbfaa0000u), -1.328125f); + VERIFY_EQUAL(DecodeIEEE754binary32(0x3f800000u), 1.0f); + VERIFY_EQUAL(DecodeIEEE754binary32(0x00000000u), 0.0f); + VERIFY_EQUAL(DecodeIEEE754binary32(0xbf800000u), -1.0f); + VERIFY_EQUAL(DecodeIEEE754binary32(0x3f800000u), 1.0f); + VERIFY_EQUAL(IEEE754binary32LE(1.0f).GetInt32(), 0x3f800000u); + VERIFY_EQUAL(IEEE754binary32BE(1.0f).GetInt32(), 0x3f800000u); + VERIFY_EQUAL(IEEE754binary32LE(0x00,0x00,0x80,0x3f), 1.0f); + VERIFY_EQUAL(IEEE754binary32BE(0x3f,0x80,0x00,0x00), 1.0f); + VERIFY_EQUAL(IEEE754binary32LE(1.0f), IEEE754binary32LE(0x00,0x00,0x80,0x3f)); + VERIFY_EQUAL(IEEE754binary32BE(1.0f), IEEE754binary32BE(0x3f,0x80,0x00,0x00)); VERIFY_EQUAL(Stringify(1.5f), "1.5"); VERIFY_EQUAL(Stringify(true), "1"); @@ -2076,11 +2063,11 @@ uint8 *source32 = sourceBuf; for(size_t i = 0; i < 65536; i++) { - uint8_4 floatbits = EncodeFloatBE((static_cast<float>(i) / 65536.0f) - 0.5f); - source32[i * 4 + 0] = floatbits.x[0]; - source32[i * 4 + 1] = floatbits.x[1]; - source32[i * 4 + 2] = floatbits.x[2]; - source32[i * 4 + 3] = floatbits.x[3]; + IEEE754binary32BE floatbits = IEEE754binary32BE((static_cast<float>(i) / 65536.0f) - 0.5f); + source32[i * 4 + 0] = floatbits.GetByte(0); + source32[i * 4 + 1] = floatbits.GetByte(1); + source32[i * 4 + 2] = floatbits.GetByte(2); + source32[i * 4 + 3] = floatbits.GetByte(3); } int16 *truncated16 = static_cast<int16 *>(targetBuf); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |