From 3b80ead6959990d17bfa16bc631ea1402e11e282 Mon Sep 17 00:00:00 2001 From: Jeffrey Walton Date: Fri, 24 Nov 2017 17:37:55 -0500 Subject: [PATCH] Add rotlConstant and rotrConstant The template functions take the rotate amount as a template parameter, which will allow the constexpr to propagate into the rotate expression. It should avoid some of the compile problems we were seeing under Clang and C++11 --- misc.h | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/misc.h b/misc.h index 8d834899..fc47403f 100644 --- a/misc.h +++ b/misc.h @@ -1338,6 +1338,58 @@ CRYPTOPP_DLL void CRYPTOPP_API UnalignedDeallocate(void *ptr); // ************** rotate functions *************** +//! \brief Performs a left rotate +//! \tparam R the number of bit positions to rotate the value +//! \tparam T the word type +//! \param x the value to rotate +//! \details This is a portable C/C++ implementation. The value x to be rotated can be 8 to 64-bits wide. +//! \details y must be in the range [0, sizeof(T)*8 - 1] to avoid undefined behavior. +//! Use rotlMod if the rotate amount y is outside the range. +//! \details Use rotlConstant when the rotate amount is constant. The template function was added +//! because Clang did not propagate the constant when passed as a function parameter. Clang's +//! need for a constexpr meant rotlFixed failed to compile on occassion. +//! \note rotlConstant attempts to enlist a rotate IMM instruction because its often faster +//! than a rotate REG. Immediate rotates can be up to three times faster than their register +//! counterparts. +//! \sa rotlConstant, rotrConstant, rotlFixed, rotrFixed, rotlVariable, rotrVariable +template inline T rotlConstant(T x) +{ + // Portable rotate that reduces to single instruction... + // http://gcc.gnu.org/bugzilla/show_bug.cgi?id=57157, + // http://software.intel.com/en-us/forums/topic/580884 + // and http://llvm.org/bugs/show_bug.cgi?id=24226 + static const unsigned int THIS_SIZE = sizeof(T)*8; + static const unsigned int MASK = THIS_SIZE-1; + CRYPTOPP_ASSERT(R < THIS_SIZE); + return T((x<>(-R&MASK))); +} + +//! \brief Performs a right rotate +//! \tparam R the number of bit positions to rotate the value +//! \tparam T the word type +//! \param x the value to rotate +//! \details This is a portable C/C++ implementation. The value x to be rotated can be 8 to 64-bits wide. +//! \details y must be in the range [0, sizeof(T)*8 - 1] to avoid undefined behavior. +//! Use rotrMod if the rotate amount y is outside the range. +//! \details Use rotrConstant when the rotate amount is constant. The template function was added +//! because Clang did not propagate the constant when passed as a function parameter. Clang's +//! need for a constexpr meant rotrFixed failed to compile on occassion. +//! \note rotrConstant attempts to enlist a rotate IMM instruction because its often faster +//! than a rotate REG. Immediate rotates can be up to three times faster than their register +//! counterparts. +//! \sa rotlConstant, rotrConstant, rotlFixed, rotrFixed, rotlVariable, rotrVariable +template inline T rotrConstant(T x) +{ + // Portable rotate that reduces to single instruction... + // http://gcc.gnu.org/bugzilla/show_bug.cgi?id=57157, + // http://software.intel.com/en-us/forums/topic/580884 + // and http://llvm.org/bugs/show_bug.cgi?id=24226 + static const unsigned int THIS_SIZE = sizeof(T)*8; + static const unsigned int MASK = THIS_SIZE-1; + CRYPTOPP_ASSERT(R < THIS_SIZE); + return T((x >> R)|(x<<(-R&MASK))); +} + //! \brief Performs a left rotate //! \tparam T the word type //! \param x the value to rotate @@ -1348,6 +1400,7 @@ CRYPTOPP_DLL void CRYPTOPP_API UnalignedDeallocate(void *ptr); //! \note rotlFixed attempts to enlist a rotate IMM instruction because its often faster //! than a rotate REG. Immediate rotates can be up to three times faster than their register //! counterparts. +//! \sa rotlConstant, rotrConstant, rotlFixed, rotrFixed, rotlVariable, rotrVariable template inline T rotlFixed(T x, unsigned int y) { // Portable rotate that reduces to single instruction... @@ -1370,6 +1423,7 @@ template inline T rotlFixed(T x, unsigned int y) //! \note rotrFixed attempts to enlist a rotate IMM instruction because its often faster //! than a rotate REG. Immediate rotates can be up to three times faster than their register //! counterparts. +//! \sa rotlConstant, rotrConstant, rotlFixed, rotrFixed, rotlVariable, rotrVariable template inline T rotrFixed(T x, unsigned int y) { // Portable rotate that reduces to single instruction... @@ -1392,6 +1446,7 @@ template inline T rotrFixed(T x, unsigned int y) //! \note rotlVariable attempts to enlist a rotate IMM instruction because its often faster //! than a rotate REG. Immediate rotates can be up to three times faster than their register //! counterparts. +//! \sa rotlConstant, rotrConstant, rotlFixed, rotrFixed, rotlVariable, rotrVariable template inline T rotlVariable(T x, unsigned int y) { static const unsigned int THIS_SIZE = sizeof(T)*8; @@ -1410,6 +1465,7 @@ template inline T rotlVariable(T x, unsigned int y) //! \note rotrVariable attempts to enlist a rotate IMM instruction because its often faster //! than a rotate REG. Immediate rotates can be up to three times faster than their register //! counterparts. +//! \sa rotlConstant, rotrConstant, rotlFixed, rotrFixed, rotlVariable, rotrVariable template inline T rotrVariable(T x, unsigned int y) { static const unsigned int THIS_SIZE = sizeof(T)*8; @@ -1425,6 +1481,7 @@ template inline T rotrVariable(T x, unsigned int y) //! \details This is a portable C/C++ implementation. The value x to be rotated can be 8 to 64-bits wide. //! \details y is reduced to the range [0, sizeof(T)*8 - 1] to avoid undefined behavior. //! \note rotrVariable will use either rotate IMM or rotate REG. +//! \sa rotlConstant, rotrConstant, rotlFixed, rotrFixed, rotlVariable, rotrVariable template inline T rotlMod(T x, unsigned int y) { static const unsigned int THIS_SIZE = sizeof(T)*8; @@ -1439,6 +1496,7 @@ template inline T rotlMod(T x, unsigned int y) //! \details This is a portable C/C++ implementation. The value x to be rotated can be 8 to 64-bits wide. //! \details y is reduced to the range [0, sizeof(T)*8 - 1] to avoid undefined behavior. //! \note rotrVariable will use either rotate IMM or rotate REG. +//! \sa rotlConstant, rotrConstant, rotlFixed, rotrFixed, rotlVariable, rotrVariable template inline T rotrMod(T x, unsigned int y) { static const unsigned int THIS_SIZE = sizeof(T)*8;