aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthew Sloyan <matthew.sloyan@arm.com>2020-09-23 09:51:04 +0100
committerTeresaARM <teresa.charlinreyes@arm.com>2020-10-02 11:48:41 +0000
commit01e8b07452eb691469c0a302fff64ecd5dadd3e3 (patch)
treec2e9c38bec4511600983dee5cc8f4d86299104bc
parent47fce874eae7b2d419373c9ee5826ea4f4fcb2e8 (diff)
downloadarmnn-01e8b07452eb691469c0a302fff64ecd5dadd3e3.tar.gz
IVGCVSW-5306 Add floating point type checks to NumericCast.hpp
* Added Unit Tests to capture all combinations. Signed-off-by: Matthew Sloyan <matthew.sloyan@arm.com> Change-Id: I04db920a5f5f485dc00b2f16582cf7e0bbef3ef2
-rw-r--r--include/armnn/utility/NumericCast.hpp166
-rw-r--r--src/armnn/test/UtilityTests.cpp80
2 files changed, 225 insertions, 21 deletions
diff --git a/include/armnn/utility/NumericCast.hpp b/include/armnn/utility/NumericCast.hpp
index af34013c30..cdbfd89638 100644
--- a/include/armnn/utility/NumericCast.hpp
+++ b/include/armnn/utility/NumericCast.hpp
@@ -22,14 +22,16 @@ namespace armnn
#if defined(ARMNN_NUMERIC_CAST_TESTABLE)
# define ARMNN_NUMERIC_CAST_CHECK(cond, msg) ConditionalThrow<std::bad_cast>(cond)
#else
-# define ARMNN_NUMERIC_CAST_CHECK(cond, msg) ARMNN_ASSERT_MSG(cond, msg)
+#define ARMNN_NUMERIC_CAST_CHECK(cond, msg) ARMNN_ASSERT_MSG(cond, msg)
#endif
+// Unsigned to Unsigned
+
template<typename Dest, typename Source>
typename std::enable_if_t<
std::is_unsigned<Source>::value &&
- std::is_unsigned<Dest>::value
- , Dest>
+ std::is_unsigned<Dest>::value,
+ Dest>
numeric_cast(Source source)
{
#if ENABLE_NUMERIC_CAST_CHECKS
@@ -43,26 +45,53 @@ numeric_cast(Source source)
return static_cast<Dest>(source);
}
+// Signed to Signed
+
+// numeric cast from signed integral to signed integral types, checked for narrowing overflows
template<typename Dest, typename Source>
typename std::enable_if_t<
std::is_signed<Source>::value &&
- std::is_signed<Dest>::value
- , Dest>
+ std::is_integral<Source>::value &&
+ std::is_signed<Dest>::value &&
+ std::is_integral<Dest>::value,
+ Dest>
numeric_cast(Source source)
{
- static_assert(!std::is_floating_point<Source>::value && !std::is_floating_point<Dest>::value,
- "numeric_cast doesn't cast float.");
+#if ENABLE_NUMERIC_CAST_CHECKS
+ if (source > std::numeric_limits<Dest>::max())
+ {
+ ARMNN_NUMERIC_CAST_CHECK(false, "numeric_cast failed casting signed integral type to narrower signed type. "
+ "Overflow detected.");
+ }
+
+ if (source < std::numeric_limits<Dest>::lowest())
+ {
+ ARMNN_NUMERIC_CAST_CHECK(false, "numeric_cast failed casting signed integral type to narrower signed type. "
+ "Underflow detected.");
+ }
+#endif // ENABLE_NUMERIC_CAST_CHECKS
+
+ return static_cast<Dest>(source);
+}
+// numeric cast from floating point to floating point types, checked for narrowing overflows
+template<typename Dest, typename Source>
+typename std::enable_if_t<
+ std::is_floating_point<Source>::value &&
+ std::is_floating_point<Dest>::value,
+ Dest>
+numeric_cast(Source source)
+{
#if ENABLE_NUMERIC_CAST_CHECKS
if (source > std::numeric_limits<Dest>::max())
{
- ARMNN_NUMERIC_CAST_CHECK(false, "numeric_cast failed casting signed type to narrower signed type. "
+ ARMNN_NUMERIC_CAST_CHECK(false, "numeric_cast failed casting floating point type to narrower signed type. "
"Overflow detected.");
}
if (source < std::numeric_limits<Dest>::lowest())
{
- ARMNN_NUMERIC_CAST_CHECK(false, "numeric_cast failed casting signed type to narrower signed type. "
+ ARMNN_NUMERIC_CAST_CHECK(false, "numeric_cast failed casting floating point type to narrower signed type. "
"Underflow detected.");
}
#endif // ENABLE_NUMERIC_CAST_CHECKS
@@ -70,16 +99,71 @@ numeric_cast(Source source)
return static_cast<Dest>(source);
}
-// numeric cast from unsigned to signed checked for narrowing overflows
+// numeric cast from floating point types (signed) to signed integral types, checked for narrowing overflows
template<typename Dest, typename Source>
typename std::enable_if_t<
+ std::is_floating_point<Source>::value &&
std::is_signed<Dest>::value &&
- std::is_unsigned<Source>::value
- , Dest>
-numeric_cast(Source sValue)
+ std::is_integral<Dest>::value,
+ Dest>
+numeric_cast(Source source)
{
- static_assert(!std::is_floating_point<Dest>::value, "numeric_cast doesn't cast to float.");
+#if ENABLE_NUMERIC_CAST_CHECKS
+ if (source > static_cast<Source>(std::numeric_limits<Dest>::max()))
+ {
+ ARMNN_NUMERIC_CAST_CHECK(false, "numeric_cast failed casting floating point type to narrower signed type. "
+ "Overflow detected.");
+ }
+
+ if (source < static_cast<Source>(std::numeric_limits<Dest>::lowest()))
+ {
+ ARMNN_NUMERIC_CAST_CHECK(false, "numeric_cast failed casting floating point type to narrower signed type. "
+ "Underflow detected.");
+ }
+#endif // ENABLE_NUMERIC_CAST_CHECKS
+
+ return static_cast<Dest>(source);
+}
+
+// numeric cast from signed integral types to floating point types (signed), checked for narrowing overflows
+template<typename Dest, typename Source>
+typename std::enable_if_t<
+ std::is_signed<Source>::value &&
+ std::is_integral<Source>::value &&
+ std::is_floating_point<Dest>::value,
+ Dest>
+numeric_cast(Source source)
+{
+#if ENABLE_NUMERIC_CAST_CHECKS
+ Dest sourceConverted = static_cast<Dest>(source);
+
+ if (sourceConverted > std::numeric_limits<Dest>::max())
+ {
+ ARMNN_NUMERIC_CAST_CHECK(false, "numeric_cast failed casting signed type to narrower floating point type. "
+ "Overflow detected.");
+ }
+
+ if (sourceConverted < std::numeric_limits<Dest>::lowest())
+ {
+ ARMNN_NUMERIC_CAST_CHECK(false, "numeric_cast failed casting signed type to narrower floating point type. "
+ "Underflow detected.");
+ }
+#endif // ENABLE_NUMERIC_CAST_CHECKS
+
+ return static_cast<Dest>(source);
+}
+
+// Unsigned to Signed
+// numeric cast from unsigned integral type to signed integral type, checked for narrowing overflows
+template<typename Dest, typename Source>
+typename std::enable_if_t<
+ std::is_signed<Dest>::value &&
+ std::is_integral<Dest>::value &&
+ std::is_unsigned<Source>::value,
+ Dest>
+numeric_cast(Source sValue)
+{
#if ENABLE_NUMERIC_CAST_CHECKS
if (sValue > static_cast< typename std::make_unsigned<Dest>::type >(std::numeric_limits<Dest>::max()))
{
@@ -91,17 +175,36 @@ numeric_cast(Source sValue)
return static_cast<Dest>(sValue);
}
-// numeric cast from signed to unsigned checked for underflows and narrowing overflows
+// numeric cast from unsigned integral type to floating point (signed), checked for narrowing overflows
template<typename Dest, typename Source>
typename std::enable_if_t<
- std::is_unsigned<Dest>::value &&
- std::is_signed<Source>::value
- , Dest>
+ std::is_floating_point<Dest>::value &&
+ std::is_unsigned<Source>::value,
+ Dest>
numeric_cast(Source sValue)
{
- static_assert(!std::is_floating_point<Source>::value && !std::is_floating_point<Dest>::value,
- "numeric_cast doesn't cast floats.");
+#if ENABLE_NUMERIC_CAST_CHECKS
+ if (static_cast<Dest>(sValue) > std::numeric_limits<Dest>::max())
+ {
+ ARMNN_NUMERIC_CAST_CHECK(false, "numeric_cast failed casting unsigned type to floating point type. "
+ "Overflow detected.");
+ }
+#endif // ENABLE_NUMERIC_CAST_CHECKS
+
+ return static_cast<Dest>(sValue);
+}
+
+// Signed to Unsigned
+// numeric cast from signed integral types to unsigned integral type, checked for underflows and narrowing overflows
+template<typename Dest, typename Source>
+typename std::enable_if_t<
+ std::is_unsigned<Dest>::value &&
+ std::is_signed<Source>::value &&
+ std::is_integral<Source>::value,
+ Dest>
+numeric_cast(Source sValue)
+{
#if ENABLE_NUMERIC_CAST_CHECKS
if (sValue < 0)
{
@@ -114,7 +217,30 @@ numeric_cast(Source sValue)
ARMNN_NUMERIC_CAST_CHECK(false, "numeric_cast failed casting signed type to unsigned type. "
"Overflow detected.");
}
+#endif // ENABLE_NUMERIC_CAST_CHECKS
+ return static_cast<Dest>(sValue);
+}
+// numeric cast from floating point (signed) to unsigned integral type, checked for underflows and narrowing overflows
+template<typename Dest, typename Source>
+typename std::enable_if_t<
+ std::is_unsigned<Dest>::value &&
+ std::is_floating_point<Source>::value,
+ Dest>
+numeric_cast(Source sValue)
+{
+#if ENABLE_NUMERIC_CAST_CHECKS
+ if (sValue < 0)
+ {
+ ARMNN_NUMERIC_CAST_CHECK(false, "numeric_cast failed casting negative value to unsigned type. "
+ "Underflow detected.");
+ }
+
+ if (sValue > static_cast<Source>(std::numeric_limits<Dest>::max()))
+ {
+ ARMNN_NUMERIC_CAST_CHECK(false, "numeric_cast failed casting floating point type to unsigned type. "
+ "Overflow detected.");
+ }
#endif // ENABLE_NUMERIC_CAST_CHECKS
return static_cast<Dest>(sValue);
}
diff --git a/src/armnn/test/UtilityTests.cpp b/src/armnn/test/UtilityTests.cpp
index 8d933eb435..bad6c2250b 100644
--- a/src/armnn/test/UtilityTests.cpp
+++ b/src/armnn/test/UtilityTests.cpp
@@ -14,6 +14,8 @@
#include <armnn/Exceptions.hpp>
+#include <limits>
+
// Tests of include/Utility files
BOOST_AUTO_TEST_SUITE(UtilityTests)
@@ -160,6 +162,9 @@ BOOST_AUTO_TEST_CASE(NumericCast)
BOOST_CHECK_NO_THROW(numeric_cast<int16_t>(1L << 7));
BOOST_CHECK_NO_THROW(numeric_cast<int16_t>((1L << 15)*-1));
+ BOOST_CHECK_NO_THROW(numeric_cast<int16_t>(1U << 8));
+ BOOST_CHECK_NO_THROW(numeric_cast<int16_t>(1U << 14));
+
// To 32 bit
BOOST_CHECK_NO_THROW(numeric_cast<uint32_t>(1));
BOOST_CHECK_NO_THROW(numeric_cast<uint32_t>(1 << 8));
@@ -170,6 +175,79 @@ BOOST_AUTO_TEST_CASE(NumericCast)
BOOST_CHECK_NO_THROW(numeric_cast<int32_t>((1L << 8)*-1));
BOOST_CHECK_NO_THROW(numeric_cast<int32_t>((1L << 16)*-1));
BOOST_CHECK_NO_THROW(numeric_cast<int32_t>((1LL << 31)*-1));
-}
+
+ BOOST_CHECK_NO_THROW(numeric_cast<int32_t>(1U));
+ BOOST_CHECK_NO_THROW(numeric_cast<int32_t>(1U << 8));
+ BOOST_CHECK_NO_THROW(numeric_cast<int32_t>(1U << 16));
+ BOOST_CHECK_NO_THROW(numeric_cast<int32_t>(1U << 30));
+
+ float float_max = std::numeric_limits<float>::max();
+ float float_min = std::numeric_limits<float>::lowest();
+ auto int8_max = std::numeric_limits<int8_t>::max();
+ auto int16_max = std::numeric_limits<int16_t>::max();
+ auto int32_max = std::numeric_limits<int32_t>::max();
+ auto int8_min = std::numeric_limits<int8_t>::lowest();
+ auto int16_min = std::numeric_limits<int16_t>::lowest();
+ auto int32_min = std::numeric_limits<int32_t>::lowest();
+ auto uint8_max = std::numeric_limits<uint8_t>::max();
+ auto uint16_max = std::numeric_limits<uint16_t>::max();
+ auto uint32_max = std::numeric_limits<uint32_t>::max();
+ auto double_max = std::numeric_limits<double>::max();
+
+ // Float to signed integer
+ BOOST_CHECK_NO_THROW(numeric_cast<int32_t>(1.324f));
+ BOOST_CHECK(1 == numeric_cast<int32_t>(1.324f));
+ BOOST_CHECK_NO_THROW(numeric_cast<int32_t>(-1.0f));
+ BOOST_CHECK(-1 == numeric_cast<int32_t>(-1.0f));
+
+ BOOST_CHECK_NO_THROW(numeric_cast<int8_t>(static_cast<float>(int8_max)));
+ BOOST_CHECK_NO_THROW(numeric_cast<int16_t>(static_cast<float>(int16_max)));
+ BOOST_CHECK_NO_THROW(numeric_cast<int32_t>(static_cast<float>(int32_max)));
+
+ BOOST_CHECK_THROW(numeric_cast<int8_t>(float_max), std::bad_cast);
+ BOOST_CHECK_THROW(numeric_cast<int16_t>(float_max), std::bad_cast);
+ BOOST_CHECK_THROW(numeric_cast<int32_t>(float_max), std::bad_cast);
+
+ BOOST_CHECK_THROW(numeric_cast<int8_t>(float_min), std::bad_cast);
+ BOOST_CHECK_THROW(numeric_cast<int16_t>(float_min), std::bad_cast);
+ BOOST_CHECK_THROW(numeric_cast<int32_t>(float_min), std::bad_cast);
+
+ // Signed integer to float
+ BOOST_CHECK_NO_THROW(numeric_cast<float>(1));
+ BOOST_CHECK(1.0 == numeric_cast<float>(1));
+ BOOST_CHECK_NO_THROW(numeric_cast<float>(-1));
+ BOOST_CHECK(-1.0 == numeric_cast<float>(-1));
+
+ BOOST_CHECK_NO_THROW(numeric_cast<float>(int8_max));
+ BOOST_CHECK_NO_THROW(numeric_cast<float>(int16_max));
+ BOOST_CHECK_NO_THROW(numeric_cast<float>(int32_max));
+
+ BOOST_CHECK_NO_THROW(numeric_cast<float>(int8_min));
+ BOOST_CHECK_NO_THROW(numeric_cast<float>(int16_min));
+ BOOST_CHECK_NO_THROW(numeric_cast<float>(int32_min));
+
+ // Unsigned integer to float
+ BOOST_CHECK_NO_THROW(numeric_cast<float>(1U));
+ BOOST_CHECK(1.0 == numeric_cast<float>(1U));
+
+ BOOST_CHECK_NO_THROW(numeric_cast<float>(uint8_max));
+ BOOST_CHECK_NO_THROW(numeric_cast<float>(uint16_max));
+ BOOST_CHECK_NO_THROW(numeric_cast<float>(uint32_max));
+
+ // Float to unsigned integer
+ BOOST_CHECK_NO_THROW(numeric_cast<uint32_t>(1.43243f));
+ BOOST_CHECK(1 == numeric_cast<uint32_t>(1.43243f));
+
+ BOOST_CHECK_THROW(numeric_cast<uint32_t>(-1.1f), std::bad_cast);
+ BOOST_CHECK_THROW(numeric_cast<uint32_t>(float_max), std::bad_cast);
+
+ // Double checks
+ BOOST_CHECK_THROW(numeric_cast<int32_t>(double_max), std::bad_cast);
+ BOOST_CHECK_THROW(numeric_cast<int32_t>(double_max), std::bad_cast);
+ BOOST_CHECK_THROW(numeric_cast<float>(double_max), std::bad_cast);
+ BOOST_CHECK_NO_THROW(numeric_cast<double>(int32_max));
+ BOOST_CHECK_NO_THROW(numeric_cast<long double>(int32_max));
+
+ }
BOOST_AUTO_TEST_SUITE_END()