10.45: (intègre): Avoid useless dynamic checks in arithmetic operations.

int_u6 = int_u8 + int_u8 est safe au niveau de l'opération arithmétique, seul l'affectation à besoin d'être checkée. int_u6 = int_u32 + int_u8 n'est pas safe au niveau arithmétique, ie. il ne suffit pas de faire l'opération puis de vérifier l'affectation. (int + int => int en C/C++). Ce patch permet de déterminer avec plus de précision les cas où un check dynamique est requis. Index: integre/ChangeLog from Nicolas Burrus <burrus_n@lrde.epita.fr> * tests/types/tests/int_u8: New test. * tests/types/runtests: Rename KEEP_RUN as KEEP_RUNS. +2003-11-27 Nicolas Burrus <burrus_n@lrde.epita.fr> + + * ntg/real/behavior.hh: Check arithmetic operators, not arithmetic + assignment operators. + (force): New behavior. + (ret_behavior_if): New helper struct. + + * ntg/core/value.hh: Define unsafe_type. + * ntg/core/macros.hh (ntg_unsafe_type): New macro. + * ntg/utils/cast.hh: Use ntg_unsafe_type. + + * ntg/real/typetraits_builtin_int.hh: Define abstract_behavior_type. + * ntg/real/builtin_float.hh: Likewise. + * ntg/real/range.hh: Likewise. + * ntg/real/cycle.hh: Likewise. + + * ntg/real/int_s.hh: Remove useless arithmetic operations + checks. Define need_check for operation traits. + * ntg/real/int_u.hh: Likewise. + + * ntg/real/optraits_real_defs.hh: Derive arithmetic assignment + operators from arithmetic operators. Use the behavior given by the + operator traits instead of the behavior of the return type. + * ntg/real/optraits_real.hh: Adjust consequently. + +2003-11-27 Nicolas Burrus <burrus_n@lrde.epita.fr> + Make typetraits and optraits reproduce more accurately the value hierarchy. Index: integre/ntg/real/behavior.hh --- integre/ntg/real/behavior.hh Wed, 26 Nov 2003 16:45:27 +0100 burrus_n (oln/g/31_behaviour. 1.13.1.16 640) +++ integre/ntg/real/behavior.hh Thu, 27 Nov 2003 11:26:27 +0100 burrus_n (oln/g/31_behaviour. 1.13.1.15.1.1 640) @@ -29,7 +29,7 @@ # define NTG_REAL_BEHAVIOUR_HH /* - Behaviors for data_types int_u, int_s, etc ... + Behaviors for real datatypes int_u, int_s, etc ... <WARNING> Don't forget that behaviors are checked on assignements and contruction of types, and use comparison, so create only vars @@ -53,10 +53,10 @@ # include <string> # include <sstream> - // FIXME: there is maybe simpler a way to write that, but we want it // to be compatible with icc, so the behaviors must stay classes, not // meta classes. +// FIXME: are these considerations still accurate? namespace ntg { @@ -86,28 +86,28 @@ template <class T1, class T2> static T - check_plus_equal (T1 lhs, T2 rhs) + check_plus (T1 lhs, T2 rhs) { return lhs + rhs; } template <class T1, class T2> static T - check_minus_equal (T1 lhs, T2 rhs) + check_minus (T1 lhs, T2 rhs) { return lhs - rhs; } template <class T1, class T2> static T - check_times_equal (T1 lhs, T2 rhs) + check_times (T1 lhs, T2 rhs) { return lhs * rhs; } template <class T1, class T2> static T - check_div_equal (T1 lhs, T2 rhs) + check_div (T1 lhs, T2 rhs) { return lhs / rhs; } template <class P> static storage_type check (const P& p) - { return static_cast<storage_type>(p); } + { return p; } }; static std::string @@ -115,6 +115,63 @@ { return "unsafe"; } }; + /*------. + | force | + `------*/ + //! Force the value to be assigned without checks. + /*! + Quite similar to unsafe, but even if the destination type has a + strict behavior, by using cast::force we ensure that no check will + be performed. + + Example: + + int_u<8, strict> a; + a = force::get<int_u<8, strict> >::check_plus(5, 6); + + => no check + + This construction is useful when we want to use code from a + particular behavior to a type defined with another behavior. + */ + struct force + { + template <class T> + struct get + { + typedef ntgi_storage_type(T) storage_type; + + template <class T1, class T2> + static T + check_plus (T1 lhs, T2 rhs) + { return cast::force<T>(lhs + rhs); } + + template <class T1, class T2> + static T + check_minus (T1 lhs, T2 rhs) + { return cast::force<T>(lhs - rhs); } + + template <class T1, class T2> + static T + check_times (T1 lhs, T2 rhs) + { return cast::force<T>(lhs * rhs); } + + template <class T1, class T2> + static T + check_div (T1 lhs, T2 rhs) + { return cast::force<T>(lhs / rhs); } + + template <class P> + static storage_type + check (const P& p) + { return cast::force<T>(p); } + }; + + static std::string + name() + { return "force"; } + }; + /*-------. | strict | `-------*/ @@ -136,7 +193,7 @@ template <class T1, class T2> static T - check_plus_equal (T1 lhs, T2 rhs) + check_plus (T1 lhs, T2 rhs) { T ret = lhs + rhs; if (rhs > 0) @@ -148,7 +205,7 @@ template <class T1, class T2> static T - check_minus_equal (T1 lhs, T2 rhs) + check_minus (T1 lhs, T2 rhs) { T ret = lhs - rhs; if (rhs > 0) @@ -161,7 +218,7 @@ // FIXME: this check is very slow! Find another solution. template <class T1, class T2> static T - check_times_equal (T1 lhs, T2 rhs) + check_times (T1 lhs, T2 rhs) { T ret = lhs * rhs; if (rhs != 0) @@ -171,7 +228,7 @@ template <class T1, class T2> static T - check_div_equal (T1 lhs, T2 rhs) + check_div (T1 lhs, T2 rhs) { return lhs / rhs; } template <class P> @@ -203,7 +260,7 @@ template <class T1, class T2> static T - check_plus_equal (T1 lhs, T2 rhs) + check_plus (T1 lhs, T2 rhs) { T ret = lhs + rhs; if (rhs > 0) @@ -218,7 +275,7 @@ template <class T1, class T2> static T - check_minus_equal (T1 lhs, T2 rhs) + check_minus (T1 lhs, T2 rhs) { T ret = lhs - rhs; if (rhs > 0) @@ -234,7 +291,7 @@ // FIXME: this check is very slow ! find another solution ... template <class T1, class T2> static T - check_times_equal (T1 lhs, T2 rhs) + check_times (T1 lhs, T2 rhs) { T ret = lhs * rhs; if ((ret / rhs) != lhs) @@ -250,7 +307,7 @@ template <class T1, class T2> static T - check_div_equal (T1 lhs, T2 rhs) + check_div (T1 lhs, T2 rhs) { return lhs / rhs; } template <class P> @@ -292,19 +349,19 @@ // FIXME: calculate real values! template <class T1, class T2> - static T check_plus_equal (T1 lhs, T2 rhs) + static T check_plus (T1 lhs, T2 rhs) { return lhs + rhs; } template <class T1, class T2> - static T check_minus_equal (T1 lhs, T2 rhs) + static T check_minus (T1 lhs, T2 rhs) { return lhs - rhs; } template <class T1, class T2> - static T check_times_equal (T1 lhs, T2 rhs) + static T check_times (T1 lhs, T2 rhs) { return lhs * rhs; } template <class T1, class T2> - static T check_div_equal (T1 lhs, T2 rhs) + static T check_div (T1 lhs, T2 rhs) { return lhs / rhs; } // float modulus @@ -372,6 +429,32 @@ struct deduce_op_behavior<B, B> { typedef B ret; }; + /*----------------. + | ret_behavior_if | + `----------------*/ + + //! Determine the behavior to use depending on check requirements. + /*! + If need_check is true, the returned behavior will be the same as + the previously determined return type (generally safe). + + In some cases, no check is required, thus type used to perform + the calculus does not need to be safe. The force behavior is + returned in such cases. + */ + + template <bool need_check, class Ret> + struct ret_behavior_if + { + typedef typename typetraits<Ret>::abstract_behavior_type ret; + }; + + template <class Ret> + struct ret_behavior_if<false, Ret> + { + typedef ntg::force ret; + }; + } // end of internal. } // end of ntg. Index: integre/ntg/utils/cast.hh --- integre/ntg/utils/cast.hh Fri, 07 Nov 2003 17:26:19 +0100 burrus_n (oln/i/26_cast.hh 1.3.1.10 640) +++ integre/ntg/utils/cast.hh Thu, 27 Nov 2003 11:26:27 +0100 burrus_n (oln/i/26_cast.hh 1.3.1.11 640) @@ -74,7 +74,7 @@ const Tdest force(const Tsrc& val) { - Tdest tmp(static_cast<ntg_storage_type(Tdest)>(val)); + ntg_unsafe_type(Tdest) tmp (val); return tmp; } Index: integre/ntg/real/int_s.hh --- integre/ntg/real/int_s.hh Thu, 27 Nov 2003 11:17:00 +0100 burrus_n (oln/g/24_int_s.hh 1.16.1.18 640) +++ integre/ntg/real/int_s.hh Thu, 27 Nov 2003 11:26:27 +0100 burrus_n (oln/g/24_int_s.hh 1.16.1.16.1.1 640) @@ -46,17 +46,41 @@ // FIXME: add bits number comparison to avoid useless checks. -# define INT_S_CTOR_FROM_BUILTIN(Builtin) \ +# define INT_S_CTOR_FROM_UNSIGNED_BUILTIN(Builtin) \ int_s (const Builtin rhs) \ { \ + if ((unsigned) internal::typetraits<ntg_type(Builtin)>::size < nbits) \ + this->val_ = rhs; \ + else \ this->val_ = optraits_type::check(rhs); \ } \ self& operator=(const Builtin rhs) \ { \ + if ((unsigned) internal::typetraits<ntg_type(Builtin)>::size < nbits) \ + this->val_ = rhs; \ + else \ this->val_ = optraits_type::check(rhs); \ return *this; \ } +# define INT_S_CTOR_FROM_SIGNED_BUILTIN(Builtin) \ +int_s (const Builtin rhs) \ +{ \ + if ((unsigned)internal::typetraits<ntg_type(Builtin)>::size <= nbits) \ + this->val_ = rhs; \ + else \ + this->val_ = optraits_type::check(rhs); \ +} \ +self& operator=(const Builtin rhs) \ +{ \ + if ((unsigned)internal::typetraits<ntg_type(Builtin)>::size <= nbits) \ + this->val_ = rhs; \ + else \ + this->val_ = optraits_type::check(rhs); \ + return *this; \ +} + + namespace ntg { namespace internal { @@ -76,6 +100,7 @@ ntg_build_value_type(sint_value<E>); typedef optraits<self> optraits_type; + typedef behavior abstract_behavior_type; typedef typename behavior::template get<self> behavior_type; typedef self base_type; @@ -90,6 +115,9 @@ typedef int_u<32, behavior> unsigned_largest_type; typedef int_u<32, behavior> unsigned_cumul_type; typedef signed int integer_type; + + // Particular properties + enum { size = nbits }; }; } // end of internal. @@ -112,18 +140,18 @@ // We define ctor for each builtin to avoid implicit builtin // promotion. - INT_S_CTOR_FROM_BUILTIN(unsigned long); - INT_S_CTOR_FROM_BUILTIN(signed long); + INT_S_CTOR_FROM_UNSIGNED_BUILTIN(unsigned long); + INT_S_CTOR_FROM_SIGNED_BUILTIN(signed long); - INT_S_CTOR_FROM_BUILTIN(unsigned int); - INT_S_CTOR_FROM_BUILTIN(signed int); + INT_S_CTOR_FROM_UNSIGNED_BUILTIN(unsigned int); + INT_S_CTOR_FROM_SIGNED_BUILTIN(signed int); - INT_S_CTOR_FROM_BUILTIN(unsigned short); - INT_S_CTOR_FROM_BUILTIN(signed short); + INT_S_CTOR_FROM_UNSIGNED_BUILTIN(unsigned short); + INT_S_CTOR_FROM_SIGNED_BUILTIN(signed short); - INT_S_CTOR_FROM_BUILTIN(unsigned char); - INT_S_CTOR_FROM_BUILTIN(signed char); - INT_S_CTOR_FROM_BUILTIN(char); + INT_S_CTOR_FROM_UNSIGNED_BUILTIN(unsigned char); + INT_S_CTOR_FROM_SIGNED_BUILTIN(signed char); + INT_S_CTOR_FROM_SIGNED_BUILTIN(char); template <unsigned mbits, class B2> int_s (const int_s<mbits, B2>& rhs) @@ -306,7 +334,8 @@ // debug static std::string name() { std::ostringstream out; - out << "int_s<" << int(nbits) << ", " << behavior::name() << ">"<< std::ends; + out << "int_s<" << int(nbits) << ", " << behavior::name() << ">" + << std::ends; return out.str(); } }; @@ -325,10 +354,12 @@ template<unsigned nbits, class B1, unsigned mbits, class B2> struct operator_traits<operator_plus, int_s<nbits, B1>, int_s<mbits, B2> > { - enum { commutative = true }; + enum { commutative = true, + need_check = ((unsigned) mlc::max<nbits, mbits>::ret >= 32) }; typedef int_s<(unsigned)mlc::maxN<nbits + 1,mbits + 1, 32>::ret, typename deduce_op_behavior<B1, B2>::ret> ret; - typedef int_s<nbits, B1> impl; + typedef int_s<nbits, + typename ret_behavior_if<need_check, ret>::ret> impl; }; @@ -337,10 +368,12 @@ template <unsigned nbits, class B1, unsigned mbits, class B2> struct operator_traits<operator_plus, int_s<nbits, B1>, int_u<mbits, B2> > { - enum { commutative = true }; + enum { commutative = true, + need_check = ((mbits >= 31) || (nbits >= 32)) }; typedef int_s<(unsigned)mlc::maxN<nbits + 1,mbits + 2, 32>::ret, typename deduce_op_behavior<B1, B2>::ret> ret; - typedef int_s<nbits, B1> impl; + typedef int_s<nbits, + typename ret_behavior_if<need_check, ret>::ret> impl; }; @@ -353,10 +386,12 @@ template<unsigned nbits, class B1, unsigned mbits, class B2> struct operator_traits<operator_minus, int_s<nbits, B1>, int_s<mbits, B2> > { - enum { commutative = true }; + enum { commutative = true, + need_check = ((mbits >= 31) || (nbits >= 31)) }; typedef int_s<(unsigned)mlc::maxN<nbits + 1, mbits + 1, 32>::ret, typename deduce_op_behavior<B1, B2>::ret> ret; - typedef int_s<nbits, B1> impl; + typedef int_s<nbits, + typename ret_behavior_if<need_check, ret>::ret> impl; }; // int_s - int_u ; int_u - int_s @@ -364,10 +399,12 @@ template <unsigned nbits, class B1, unsigned mbits, class B2> struct operator_traits<operator_minus, int_s<nbits, B1>, int_u<mbits, B2> > { - enum { commutative = true }; + enum { commutative = true, + need_check = ((mbits >= 31) || (nbits >= 32)) }; typedef int_s<(unsigned)mlc::maxN<nbits + 1, mbits + 2, 32>::ret, typename deduce_op_behavior<B1, B2>::ret> ret; - typedef int_s<nbits, B1> impl; + typedef int_s<nbits, + typename ret_behavior_if<need_check, ret>::ret> impl; }; @@ -380,10 +417,12 @@ template<unsigned nbits, class B1, unsigned mbits, class B2> struct operator_traits<operator_times, int_s<nbits, B1>, int_s<mbits, B2> > { - enum { commutative = true }; + enum { commutative = true, + need_check = (mbits + nbits > 32) }; typedef int_s<(unsigned)mlc::saturateN<nbits + mbits, 32>::ret, typename deduce_op_behavior<B1, B2>::ret> ret; - typedef int_s<nbits, B1> impl; + typedef int_s<nbits, + typename ret_behavior_if<need_check, ret>::ret> impl; }; @@ -392,10 +431,12 @@ template <unsigned nbits, class B1, unsigned mbits, class B2> struct operator_traits<operator_times, int_s<nbits, B1>, int_u<mbits, B2> > { - enum { commutative = true }; + enum { commutative = true, + need_check = (nbits + mbits + 1 > 32)}; typedef int_s<(unsigned)mlc::saturateN<nbits + mbits+1, 32>::ret, typename deduce_op_behavior<B1, B2>::ret> ret; - typedef int_s<nbits, B1> impl; + typedef int_s<nbits, + typename ret_behavior_if<need_check, ret>::ret> impl; }; // @@ -409,7 +450,7 @@ { enum { commutative = true }; typedef int_s<nbits, typename deduce_op_behavior<B1, B2>::ret> ret; - typedef int_s<nbits, B1> impl; + typedef int_s<nbits, force> impl; }; // int_s / int_u ; int_u / int_s @@ -417,18 +458,22 @@ template <unsigned nbits, class B1, unsigned mbits, class B2> struct operator_traits<operator_div, int_s<nbits, B1>, int_u<mbits, B2> > { - enum { commutative = false }; + enum { commutative = false, + need_check = (mbits >= 32) }; typedef int_s<nbits, typename deduce_op_behavior<B1, B2>::ret> ret; - typedef int_s<nbits, B1> impl; + typedef int_s<nbits, + typename ret_behavior_if<need_check, ret>::ret> impl; }; template <unsigned nbits, class B1, unsigned mbits, class B2> struct operator_traits<operator_div, int_u<mbits, B2>, int_s<nbits, B1> > { - enum { commutative = false }; + enum { commutative = false, + need_check = (mbits >= 32) }; typedef int_s<mlc::saturateN<mbits + 1, 32>::ret, typename deduce_op_behavior<B1, B2>::ret> ret; - typedef int_s<nbits, B1> impl; + typedef int_s<nbits, + typename ret_behavior_if<need_check, ret>::ret> impl; }; // @@ -442,7 +487,7 @@ { enum { commutative = false }; typedef int_s<mbits, typename deduce_op_behavior<B1, B2>::ret> ret; - typedef int_s<nbits, B1> impl; + typedef int_s<nbits, force> impl; }; // int_s % int_u ; int_u % int_s @@ -450,12 +495,19 @@ template <unsigned nbits, class B1, unsigned mbits, class B2> struct operator_traits<operator_mod, int_s<nbits, B1>, int_u<mbits, B2> > { - enum { commutative = false }; + enum { commutative = false, + need_check = (mbits >= 32) }; typedef int_s<(unsigned)mlc::saturateN<mbits + 1, 32>::ret, typename deduce_op_behavior<B1, B2>::ret> ret; - typedef int_s<nbits, B1> impl; + typedef int_s<nbits, + typename ret_behavior_if<need_check, ret>::ret> impl; }; + // FIXME: don't know what to do with this operator, so the + // implementation is disabled. In classical C++, (a % b) with b < 0 + // returns a whatever b is. + +#if 0 template <unsigned nbits, class B1, unsigned mbits, class B2> struct operator_traits<operator_mod, int_u<nbits, B1>, int_s<mbits, B2> > { @@ -463,7 +515,7 @@ typedef int_u<mbits, typename deduce_op_behavior<B1, B2>::ret> ret; typedef int_s<nbits, B1> impl; }; - +#endif // // Min @@ -477,7 +529,7 @@ enum { commutative = true }; typedef int_s<(unsigned) mlc::min<nbits, mbits>::ret, typename deduce_op_behavior<B1, B2>::ret> ret; - typedef int_s<nbits, B1> impl; + typedef int_s<nbits, force> impl; }; // @@ -492,7 +544,7 @@ enum { commutative = true }; typedef int_s<(unsigned) mlc::max<nbits, mbits>::ret, typename deduce_op_behavior<B1, B2>::ret> ret; - typedef int_s<nbits, B1> impl; + typedef int_s<nbits, force> impl; }; // @@ -506,7 +558,7 @@ { enum { commutative = true }; typedef int_s<(unsigned)mlc::maxN<nbits,mbits,32>::ret, unsafe> ret; - typedef int_s<nbits, B1> impl; + typedef int_s<nbits, force> impl; }; @@ -517,7 +569,7 @@ { enum { commutative = true }; typedef int_s<(unsigned)mlc::maxN<nbits,mbits+1, 32>::ret, unsafe> ret; - typedef int_s<nbits, B1> impl; + typedef int_s<nbits, force> impl; }; } // end of internal. Index: integre/ntg/real/int_u.hh --- integre/ntg/real/int_u.hh Thu, 27 Nov 2003 11:17:00 +0100 burrus_n (oln/g/23_int_u.hh 1.19.1.18 640) +++ integre/ntg/real/int_u.hh Thu, 27 Nov 2003 11:26:27 +0100 burrus_n (oln/g/23_int_u.hh 1.19.1.16.1.1 640) @@ -42,6 +42,23 @@ | macros | `-------*/ +# define INT_U_CTOR_FROM_UNSIGNED_BUILTIN_INT(Builtin) \ +int_u (const Builtin rhs) \ +{ \ + if ((unsigned) internal::typetraits<ntg_type(Builtin)>::size <= nbits) \ + this->val_ = rhs; \ + else \ + this->val_ = optraits_type::check(rhs); \ +} \ +self& operator=(const Builtin rhs) \ +{ \ + if ((unsigned) internal::typetraits<ntg_type(Builtin)>::size <= nbits) \ + this->val_ = rhs; \ + else \ + this->val_ = optraits_type::check(rhs); \ + return *this; \ +} + # define INT_U_CTOR_FROM_BUILTIN_INT(Builtin) \ int_u (const Builtin rhs) \ { \ @@ -53,6 +70,7 @@ return *this; \ } + namespace ntg { namespace internal { @@ -72,9 +90,9 @@ ntg_build_value_type(uint_value<E>); typedef optraits<self> optraits_type; + typedef behavior abstract_behavior_type; typedef typename behavior::template get<self> behavior_type; - typedef self base_type; typedef typename C_for_int_u<nbits>::type storage_type; typedef int_s<mlc::saturateN<nbits+1, 32>::ret, @@ -88,6 +106,10 @@ typedef int_u<32, behavior> unsigned_largest_type; typedef int_u<32, behavior> unsigned_cumul_type; typedef unsigned int integer_type; + typedef int_u<nbits, unsafe> unsafe_type; + + // Particular properties + enum { size = nbits }; }; } // end of internal. @@ -111,16 +133,18 @@ // We define ctor for each builtin to avoid implicit builtin // promotion. - INT_U_CTOR_FROM_BUILTIN_INT(unsigned long); + // FIXME: dynamic checks are not necessary for all builtin types! + + INT_U_CTOR_FROM_UNSIGNED_BUILTIN_INT(unsigned long); INT_U_CTOR_FROM_BUILTIN_INT(signed long); - INT_U_CTOR_FROM_BUILTIN_INT(unsigned int); + INT_U_CTOR_FROM_UNSIGNED_BUILTIN_INT(unsigned int); INT_U_CTOR_FROM_BUILTIN_INT(signed int); - INT_U_CTOR_FROM_BUILTIN_INT(unsigned short); + INT_U_CTOR_FROM_UNSIGNED_BUILTIN_INT(unsigned short); INT_U_CTOR_FROM_BUILTIN_INT(signed short); - INT_U_CTOR_FROM_BUILTIN_INT(unsigned char); + INT_U_CTOR_FROM_UNSIGNED_BUILTIN_INT(unsigned char); INT_U_CTOR_FROM_BUILTIN_INT(signed char); INT_U_CTOR_FROM_BUILTIN_INT(char); @@ -252,10 +276,12 @@ template<unsigned nbits, class B1, unsigned mbits, class B2> struct operator_traits<operator_plus, int_u<nbits, B1>, int_u<mbits, B2> > { - enum { commutative = true }; + enum { commutative = true, + need_check = ((unsigned) mlc::max<nbits, mbits>::ret >= 32) }; typedef int_u<(unsigned) mlc::maxN<nbits + 1, mbits + 1, 32>::ret, typename deduce_op_behavior<B1, B2>::ret> ret; - typedef int_u<nbits, B1> impl; + typedef int_u<nbits, + typename ret_behavior_if<need_check, ret>::ret> impl; }; // @@ -267,10 +293,12 @@ template<unsigned nbits, class B1, unsigned mbits, class B2> struct operator_traits<operator_minus, int_u<nbits, B1>, int_u<mbits, B2> > { - enum { commutative = true }; + enum { commutative = true, + need_check = ((unsigned) mlc::max<nbits, mbits>::ret >= 32) }; typedef int_s<(unsigned) mlc::maxN<nbits+1, mbits+1, 32>::ret, typename deduce_op_behavior<B1, B2>::ret> ret; - typedef int_u<nbits, B1> impl; + typedef int_u<nbits, + typename ret_behavior_if<need_check, ret>::ret> impl; }; // int_u32 - int_u : we do not convert result to int_s because we @@ -281,7 +309,7 @@ { enum { commutative = true }; typedef int_u<32, typename deduce_op_behavior<B1, B2>::ret> ret; - typedef int_u<32, B1> impl; + typedef int_u<32, force> impl; }; // @@ -293,10 +321,11 @@ template<unsigned nbits, class B1, unsigned mbits, class B2> struct operator_traits<operator_times, int_u<nbits, B1>, int_u<mbits, B2> > { - enum { commutative = true }; + enum { commutative = true, need_check = (nbits + mbits > 32) }; typedef int_u<(unsigned) mlc::saturateN<nbits + mbits, 32>::ret, typename deduce_op_behavior<B1, B2>::ret> ret; - typedef int_u<nbits, B1> impl; + typedef int_u<nbits, + typename ret_behavior_if<need_check, ret>::ret> impl; }; // @@ -310,7 +339,7 @@ { enum { commutative = true }; typedef int_u<nbits, typename deduce_op_behavior<B1, B2>::ret> ret; - typedef int_u<nbits, B1> impl; + typedef int_u<nbits, force> impl; }; // @@ -324,7 +353,7 @@ { enum { commutative = false }; typedef int_u<mbits, typename deduce_op_behavior<B1, B2>::ret> ret; - typedef int_u<nbits, B1> impl; + typedef int_u<nbits, force> impl; }; // @@ -339,7 +368,7 @@ enum { commutative = true }; typedef int_u<(unsigned) mlc::min<nbits, mbits>::ret, typename deduce_op_behavior<B1, B2>::ret> ret; - typedef int_u<nbits, B1> impl; + typedef int_u<nbits, force> impl; }; @@ -355,7 +384,7 @@ enum { commutative = true }; typedef int_u<(unsigned) mlc::max<nbits, mbits>::ret, typename deduce_op_behavior<B1, B2>::ret> ret; - typedef int_u<nbits, B1> impl; + typedef int_u<nbits, force> impl; }; @@ -369,8 +398,9 @@ struct operator_traits<operator_cmp, int_u<nbits, B1>, int_u<mbits, B2> > { enum { commutative = true }; + // FIXME: why unsafe? I think there is a reason. typedef int_u<(unsigned) mlc::maxN<nbits, mbits, 32>::ret, unsafe> ret; - typedef int_u<nbits, B1> impl; + typedef int_u<nbits, force> impl; }; } // end of internal. Index: integre/ntg/real/optraits_real_defs.hh --- integre/ntg/real/optraits_real_defs.hh Wed, 26 Nov 2003 16:45:27 +0100 burrus_n (oln/g/11_optraits_s 1.15 640) +++ integre/ntg/real/optraits_real_defs.hh Thu, 27 Nov 2003 11:26:27 +0100 burrus_n (oln/g/11_optraits_s 1.14.1.1 640) @@ -29,23 +29,23 @@ # define NTG_OPTRAITS_REAL_DEFS_HH // -// macros used in optraits_scalar definition +// macros used in optraits_real definition // ///////////////////////////////////////////// -# define ASSIGN_SCALAR_OPERATOR(Name, Op) \ +# define ASSIGN_SCALAR_OPERATOR(Name) \ template <class T1, class T2> inline \ - static T1& Name(T1& lhs, const T2& rhs) \ + static T1& Name##_equal(T1& lhs, const T2& rhs) \ { \ ntg_is_a(T1, ntg::real)::ensure(); \ ntg_is_a(T2, ntg::real)::ensure(); \ \ - return Name##_impl<T1,T2>(lhs, rhs); \ + return Name##_equal_impl<T1,T2>(lhs, rhs); \ } \ \ template <class T1, class T2> inline \ static T1& \ - Name##_impl(ntg::real_value<T1>& lhs, \ + Name##_equal_impl(ntg::real_value<T1>& lhs, \ const ntg::real_value<T2>& rhs) \ { \ typedef typename typetraits<T1>::behavior_type behavior_type; \ @@ -56,7 +56,7 @@ \ template <class T1, class T2> inline \ static T1& \ - Name##_impl(ntg::real_value<T1>& lhs, \ + Name##_equal_impl(ntg::real_value<T1>& lhs, \ const ntg::any_const_class<T2> rhs) \ { \ typedef typename typetraits<T1>::behavior_type behavior_type; \ @@ -67,7 +67,7 @@ \ template <class T1, class T2> inline \ static T1& \ - Name##_impl(ntg::any_class<T1> lhs, \ + Name##_equal_impl(ntg::any_class<T1> lhs, \ const ntg::real_value<T2>& rhs) \ { \ typedef typename typetraits<T1>::behavior_type behavior_type; \ @@ -76,7 +76,7 @@ return lhs.exact(); \ } -# define ARITH_SCALAR_OPERATOR(Name, Op) \ +# define ARITH_SCALAR_OPERATOR(Name) \ template <class T1, class T2> inline \ static ntg_return_type(Name, T1, T2) \ Name(const T1& lhs, const T2& rhs) \ @@ -84,13 +84,54 @@ ntg_is_a(T1, ntg::real)::ensure(); \ ntg_is_a(T2, ntg::real)::ensure(); \ \ + return Name##_impl<T1,T2>(lhs, rhs); \ + } \ + \ + template <class T1, class T2> inline \ + static ntg_return_type(Name, T1, T2) \ + Name##_impl(const ntg::real_value<T1>& lhs, \ + const ntg::real_value<T2>& rhs) \ + { \ typedef ntg_return_type(Name, T1, T2) return_type; \ - return_type result(lhs); \ - result Op rhs; \ - return result; \ + typedef typename \ + typetraits<E>::abstract_behavior_type::get<return_type> \ + behavior_type; \ + return_type tmp; \ + tmp = behavior_type::check_##Name(lhs.exact().val(), \ + rhs.exact().val()); \ + return tmp; \ + } \ + \ + template <class T1, class T2> inline \ + static ntg_return_type(Name, T1, T2) \ + Name##_impl(const ntg::real_value<T1>& lhs, \ + const ntg::any_const_class<T2>& rhs) \ + { \ + typedef ntg_return_type(Name, T1, T2) return_type; \ + typedef typename \ + typetraits<E>::abstract_behavior_type::get<return_type> \ + behavior_type; \ + return_type tmp; \ + tmp = behavior_type::check_##Name(lhs.exact().val(), \ + rhs.exact()); \ + return tmp; \ + } \ + \ + template <class T1, class T2> inline \ + static ntg_return_type(Name, T1, T2) \ + Name##_impl(const ntg::any_const_class<T1>& lhs, \ + const ntg::real_value<T2>& rhs) \ + { \ + typedef ntg_return_type(Name, T1, T2) return_type; \ + typedef typename \ + typetraits<E>::abstract_behavior_type::get<return_type> \ + behavior_type; \ + return_type tmp; \ + tmp = behavior_type::check_##Name(lhs.exact(), \ + rhs.exact().val()); \ + return tmp; \ } - # define CMP_SCALAR_OPERATOR(Name, Op) \ template <class T1, class T2> inline \ static bool Name (const T1& lhs, const T2& rhs) \ @@ -105,7 +146,8 @@ } \ \ template <class T> inline \ - static bool Name##_impl(const ntg::real_value<T>& lhs, \ + static bool \ + Name##_impl(const ntg::real_value<T>& lhs, \ const ntg::real_value<T>& rhs) \ { return lhs.exact().val() Op rhs.exact().val(); } \ \ @@ -121,7 +163,6 @@ // //////////////////////////// - # define ASSIGN_INT_OPERATOR(Name, Op) \ template <class T1, class T2> inline \ static T1& Name(T1& lhs, const T2& rhs) \ Index: integre/ntg/real/optraits_real.hh --- integre/ntg/real/optraits_real.hh Thu, 27 Nov 2003 11:17:00 +0100 burrus_n (oln/g/12_optraits_s 1.11.1.10 640) +++ integre/ntg/real/optraits_real.hh Thu, 27 Nov 2003 11:26:27 +0100 burrus_n (oln/g/12_optraits_s 1.11.1.8.1.1 640) @@ -65,27 +65,26 @@ static storage_type_ default_val() { return zero(); } // - // dev note : the goal in those default operators is to check the kind + // dev note : the aim of these default operators is to check the kind // of operands (value or not), and then call the good function. // // ASSIGN_SCALAR_OPERATOR includes default check_xxx_equal functions // - ASSIGN_SCALAR_OPERATOR(plus_equal, +) - ASSIGN_SCALAR_OPERATOR(minus_equal, -) - ASSIGN_SCALAR_OPERATOR(times_equal, *) - ASSIGN_SCALAR_OPERATOR(div_equal, /) - - ARITH_SCALAR_OPERATOR(plus, +=) - ARITH_SCALAR_OPERATOR(minus, -=) - ARITH_SCALAR_OPERATOR(times, *=) - ARITH_SCALAR_OPERATOR(div, /=) + ASSIGN_SCALAR_OPERATOR(plus) + ASSIGN_SCALAR_OPERATOR(minus) + ASSIGN_SCALAR_OPERATOR(times) + ASSIGN_SCALAR_OPERATOR(div) + + ARITH_SCALAR_OPERATOR(plus) + ARITH_SCALAR_OPERATOR(minus) + ARITH_SCALAR_OPERATOR(times) + ARITH_SCALAR_OPERATOR(div) CMP_SCALAR_OPERATOR(cmp_eq, ==) CMP_SCALAR_OPERATOR(cmp_lt, <) }; - /*----------------------. | optraits<float_value> | `----------------------*/ Index: integre/ntg/core/value.hh --- integre/ntg/core/value.hh Thu, 27 Nov 2003 11:17:00 +0100 burrus_n (oln/g/8_rec_value. 1.8.1.9 640) +++ integre/ntg/core/value.hh Thu, 27 Nov 2003 11:26:27 +0100 burrus_n (oln/g/8_rec_value. 1.8.1.8.1.1 640) @@ -107,7 +107,9 @@ template <class E> struct typetraits<value<E> > - {}; + { + typedef E unsafe_type; + }; template <class E> struct optraits<value<E> > Index: integre/ntg/real/typetraits_builtin_int.hh --- integre/ntg/real/typetraits_builtin_int.hh Thu, 27 Nov 2003 11:17:00 +0100 burrus_n (oln/g/3_typetraits 1.7.1.13 640) +++ integre/ntg/real/typetraits_builtin_int.hh Thu, 27 Nov 2003 11:26:27 +0100 burrus_n (oln/g/3_typetraits 1.7.1.11.1.1 640) @@ -51,6 +51,7 @@ \ typedef optraits<self> optraits; \ typedef unsafe::get<self> behavior_type; \ + typedef unsafe abstract_behavior_type; \ \ typedef self base_type; \ typedef self storage_type; \ Index: integre/tests/types/runtests --- integre/tests/types/runtests Fri, 01 Aug 2003 11:42:33 +0200 burrus_n (oln/h/3_runtests 1.14.1.6 750) +++ integre/tests/types/runtests Thu, 27 Nov 2003 11:26:27 +0100 burrus_n (oln/h/3_runtests 1.14.1.7 750) @@ -93,7 +93,7 @@ msg=""; case $expected:$estatus in ok:0 | compfail:50 | abort:134) - if test ! x"$KEEP_RUN" = x"1"; then + if test ! x"$KEEP_RUNS" = x"1"; then rm -rf "$dir"; fi msg="(ok)" ;; Index: integre/ntg/core/macros.hh --- integre/ntg/core/macros.hh Sun, 27 Jul 2003 19:14:42 +0200 burrus_n (oln/s/19_macros.hh 1.7 640) +++ integre/ntg/core/macros.hh Thu, 27 Nov 2003 11:26:27 +0100 burrus_n (oln/s/19_macros.hh 1.8 640) @@ -92,6 +92,9 @@ # define ntg_comp_type_(T) \ ntg::type_traits<T>::comp_type +# define ntg_unsafe_type(T) typename ntg::type_traits<T>::unsafe_type +# define ntg_unsafe_type_(T) ntg::type_traits<T>::unsafe_type + /*-----------------. | values accessors | `-----------------*/ Index: integre/ntg/real/builtin_float.hh --- integre/ntg/real/builtin_float.hh Thu, 27 Nov 2003 11:17:00 +0100 burrus_n (oln/s/47_builtin_fl 1.4 640) +++ integre/ntg/real/builtin_float.hh Thu, 27 Nov 2003 11:26:27 +0100 burrus_n (oln/s/47_builtin_fl 1.2.1.1 640) @@ -57,6 +57,7 @@ typedef optraits<self> optraits_type; typedef unsafe::get<self> behavior_type; + typedef unsafe abstract_behavior_type; typedef self base_type; typedef self storage_type; @@ -86,6 +87,7 @@ typedef optraits<self> optraits_type; typedef unsafe::get<self> behavior_type; + typedef unsafe abstract_behavior_type; typedef self base_type; typedef self storage_type; Index: integre/ntg/real/range.hh --- integre/ntg/real/range.hh Thu, 27 Nov 2003 11:17:00 +0100 burrus_n (oln/t/16_range.hh 1.5 640) +++ integre/ntg/real/range.hh Thu, 27 Nov 2003 11:26:27 +0100 burrus_n (oln/t/16_range.hh 1.3.1.1 640) @@ -53,6 +53,7 @@ typedef self ntg_type; typedef optraits<self> optraits_type; typedef typename behavior::template get<self> behavior_type; + typedef behavior abstract_behavior_type; typedef ntgi_base_type(T) base_type; typedef T storage_type; Index: integre/ntg/real/cycle.hh --- integre/ntg/real/cycle.hh Thu, 27 Nov 2003 11:17:00 +0100 burrus_n (oln/t/17_cycle.hh 1.3 640) +++ integre/ntg/real/cycle.hh Thu, 27 Nov 2003 11:26:27 +0100 burrus_n (oln/t/17_cycle.hh 1.2.1.1 640) @@ -53,6 +53,7 @@ typedef self ntg_type; typedef optraits<self> optraits_type; typedef cycle_behavior::get<self> behavior_type; + typedef cycle_behavior abstract_behavior_type; typedef typename typetraits<T>::base_type base_type; typedef T storage_type; Index: integre/tests/types/tests/int_u8 --- integre/tests/types/tests/int_u8 Thu, 27 Nov 2003 11:45:11 +0100 burrus_n () +++ integre/tests/types/tests/int_u8 Thu, 27 Nov 2003 11:26:27 +0100 burrus_n (oln/w/6_int_u8 1.1 640) @@ -0,0 +1,9 @@ +int_u8 u1 = (unsigned char) 56; +int_u8 u2 = (unsigned char) 153; +int_u32 u = 0U; + +for (unsigned i = 0; i < 5000000; ++i) + for (unsigned j = 0; j < 10; ++j) + u = u1 * u2 + int_u8u(i % 50); + +return u != 8617;
participants (1)
-
Nicolas Burrus