How do I force const propagation through an inline function?
I'm trying to get the pre-processor to do some math for me, so the constant is propagated to inline assembly. Here's the cited case:
inline
unsigned int RotateRight(unsigned char value, unsigned int amount)
{
COMPILE_ASSERT(((unsigned char)(amount%32)) < 32);
__asm__ ("rorb %1, %0" : "+mq" (value) : "I" ((unsigned char)(amount%32)));
return value;
}
The above code is based on processor specific features and I'm fine with it (its specializing by template on x86 / x64 Linux with GCC). The constraint says that the integral value must be between inclusive. "I"
[0,31]
The callers of the code look like this:
byte b1 = RotateRight(1, 1);
byte b2 = RotateRight(1, 31);
A RotateRight(1, 31)
comes from cryptographers (its undefined behavior in C / C ++ because a byte can only be rotated in a range [0,7]
). I can break free from the limitations of C / C ++ using ASM. And since the amount of the shift is known at compile time, I would like it to be reduced at compile time; and I would like the version to rorb
use the generated immediate code.
Without the COMPILE_ASSERT
code compiles, but I'm not sure if the constant is propagated. That is, it could be caused by an unexpected contraction ( % 32
). The COMPILE_ASSERT
code won't compile with.
$ make validat1.o g++ -DNDEBUG -g2 -O3 -march=native -pipe -c validat1.cpp In file included from simple.h:10:0, from filters.h:6, from files.h:5, from validat1.cpp:6: misc.h: In function ‘T CryptoPP::rotlFixed(T, unsigned int) [with T = unsigned char]’: misc.h:940:43: error: ‘y’ cannot appear in a constant-expression CRYPTOPP_COMPILE_ASSERT(((unsigned char)(y%32)) < 32); ^ misc.h:72:85: note: in definition of macro ‘CRYPTOPP_COMPILE_ASSERT_INSTANCE’ _COMPILE_ASSERT_INSTANCE(assertion, instance) static CompileAssert<(assertion)>
I know I shouldn't be using #define
, and C ++ built-in functions is the answer. But I feel like I am suffering from disconnection.
How do I force the compiler to propagate a value that includes values const
?
Or, if it COMPILE_ASSERT
is the wrong tool ( const
distributed), how do I set up the test so I can check that the rorb
immediate version is in use?
The linked one is a C ++ 03 project. It doesn't use Boost, it doesn't use Cmake, it doesn't use Autotools, etc.
source to share
When you supply a value as an argument to a function, you lose your compile-time constant.
Why don't you declare the sum as a template argument? In this case, the user of the function is also forced to pass a compile-time constant, which is fine too.
To ensure that the shift is used as a compile-time constant, you can create a local variable static const.
template<unsigned int amount> inline
unsigned int RotateRight(unsigned char value)
{
static const unsigned char shift = (unsigned char)(amount%32);
__asm__ ("rorb %1, %0" : "+mq" (value) : "I" (shift));
return value;
}
source to share