Browse Source

Fixed findMSB generic path

Christophe Riccio 13 years ago
parent
commit
8a7d6080d1
2 changed files with 119 additions and 16 deletions
  1. 36 16
      glm/core/func_integer.inl
  2. 83 0
      test/core/core_func_integer.cpp

+ 36 - 16
glm/core/func_integer.inl

@@ -522,6 +522,7 @@ namespace glm
 	}
 
 	// findMSB
+/*
 #if((GLM_ARCH != GLM_ARCH_PURE) && (GLM_COMPILER & GLM_COMPILER_VC))
 
 	template <typename genIUType>
@@ -530,11 +531,16 @@ namespace glm
 		genIUType const & Value
 	)
 	{
+		GLM_STATIC_ASSERT(std::numeric_limits<genIUType>::is_integer, "'findMSB' only accept integer values");
+		if(Value == 0)
+			return -1;
+
 		unsigned long Result(0);
 		_BitScanReverse(&Result, Value); 
 		return int(Result);
 	}
 
+// __builtin_clz seems to be buggy as it crasks for some values, from 0x00200000 to 80000000
 #elif((GLM_ARCH != GLM_ARCH_PURE) && (GLM_COMPILER & GLM_COMPILER_GCC) && (GLM_COMPILER >= GLM_COMPILER_GCC40))
 
 	template <typename genIUType>
@@ -543,18 +549,20 @@ namespace glm
 		genIUType const & Value
 	)
 	{
-		/**
-		 * clz returns the number or trailing 0-bits; see
-		 * http://gcc.gnu.org/onlinedocs/gcc-4.7.1/gcc/Other-Builtins.html
-		 *
-		 * NoteBecause __builtin_clz only works for unsigned ints, this
-		 * implementation will not work for 64-bit integers.
-		 */
-		return 31 - __builtin_clz(Value);
-	}
+		GLM_STATIC_ASSERT(std::numeric_limits<genIUType>::is_integer, "'findMSB' only accept integer values");
+		if(Value == 0)
+			return -1;
 
+		// clz returns the number or trailing 0-bits; see
+		// http://gcc.gnu.org/onlinedocs/gcc-4.7.1/gcc/Other-Builtins.html
+		//
+		// NoteBecause __builtin_clz only works for unsigned ints, this
+		// implementation will not work for 64-bit integers.
+		//
+		return 31 - __builtin_clzl(Value);
+	}
 #else
-
+*/
 	template <typename genIUType>
 	GLM_FUNC_QUALIFIER int findMSB
 	(
@@ -562,14 +570,26 @@ namespace glm
 	)
 	{
 		GLM_STATIC_ASSERT(std::numeric_limits<genIUType>::is_integer, "'findMSB' only accept integer values");
-		if(Value == 0)
+		
+		if(Value == 0 || Value == -1)
 			return -1;
-
-		genIUType bit = genIUType(-1);
-		for(genIUType tmp = Value; tmp; tmp >>= 1, ++bit){}
-		return bit;
+		else if(Value > 0)
+		{
+			genIUType Bit = genIUType(-1);
+			for(genIUType tmp = Value; tmp > 0; tmp >>= 1, ++Bit){}
+			return Bit;
+		}
+		else //if(Value < 0)
+		{
+			int const BitCount(sizeof(genIUType) * 8);
+			int MostSignificantBit(-1);
+			for(int BitIndex(0); BitIndex < BitCount; ++BitIndex)
+				MostSignificantBit = (Value & (1 << BitIndex)) ? MostSignificantBit : BitIndex;
+			assert(MostSignificantBit >= 0);
+			return MostSignificantBit;
+		}
 	}
-#endif//(GLM_COMPILER)
+//#endif//(GLM_COMPILER)
 
 	template <typename T>
 	GLM_FUNC_QUALIFIER detail::tvec2<int> findMSB

+ 83 - 0
test/core/core_func_integer.cpp

@@ -125,6 +125,87 @@ namespace bitfieldReverse
 	}
 }//bitRevert
 
+namespace findMSB
+{
+	template <typename genType>
+	struct type
+	{
+		genType		Value;
+		genType		Return;
+	};
+
+	type<int> const DataI32[] =
+	{
+		{0x00000000, -1},
+		{0x00000001,  0},
+		{0x00000002,  1},
+		{0x00000003,  1},
+		{0x00000004,  2},
+		{0x00000005,  2},
+		{0x00000007,  2},
+		{0x00000008,  3},
+		{0x00000010,  4},
+		{0x00000020,  5},
+		{0x00000040,  6},
+		{0x00000080,  7},
+		{0x00000100,  8},
+		{0x00000200,  9},
+		{0x00000400, 10},
+		{0x00000800, 11},
+		{0x00001000, 12},
+		{0x00002000, 13},
+		{0x00004000, 14},
+		{0x00008000, 15},
+		{0x00010000, 16},
+		{0x00020000, 17},
+		{0x00040000, 18},
+		{0x00080000, 19},
+		{0x00100000, 20},
+		{0x00200000, 21},
+		{0x00400000, 22},
+		{0x00800000, 23},
+		{0x01000000, 24},
+		{0x02000000, 25},
+		{0x04000000, 26},
+		{0x08000000, 27},
+		{0x10000000, 28},
+		{0x20000000, 29},
+		{0x40000000, 30},
+		{0x80000000, 30},
+		{0xffffffff, -1},
+		{0xfffffffe,  0},
+		{0xfffffffd,  1},
+		{0xfffffffc,  1},
+		{0xfffffffb,  2},
+		{0xfffffffa,  2},
+		{0xfffffff0,  3}
+	};
+
+	int test()
+	{
+		int Error(0);
+
+		for(std::size_t i = 0; i < sizeof(DataI32) / sizeof(type<int>); ++i)
+		{
+			int Result = glm::findMSB(DataI32[i].Value);
+			Error += DataI32[i].Return == Result ? 0 : 1;
+			assert(!Error);
+		}
+
+		return Error;
+	}
+}//findMSB
+
+namespace findLSB
+{
+	int test()
+	{
+		int Error(0);
+
+		return Error;
+	}
+}//findLSB
+
 int main()
 {
 	int Error = 0;
@@ -133,6 +214,8 @@ int main()
 
 	Error += ::bitfieldExtract::test();
 	Error += ::bitfieldReverse::test();
+	Error += ::findMSB::test();
+	Error += ::findLSB::test();
 
 	return Error;
 }