Reputation: 102245
I'm trying to coerce the pre-processor to perform some math for me so a constant gets propagated into inline assembly. Here's the reduced 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 code above relies upon CPU specific functionality, and I'm OK with it (its actually a template specialization on x86/x64 Linux when GCC is available). The "I"
constraint says the integral value must be between [0,31]
inclusive.
Callers of the code would look like:
byte b1 = RotateRight(1, 1);
byte b2 = RotateRight(1, 31);
A RotateRight(1, 31)
comes from the cryptographers (its undefined behavior in C/C++ because a byte can only be rotated in the range [0,7]
). I can break free from C/C++ constraints using ASM. And since the shift amount is known at compile time, I'd like it to be reduced at compile time; and I'd like the rorb
version using the immediate-8 generated.
Without the COMPILE_ASSERT
, the code compiles but I'm not sure if the constant is being propagated. That is, it might be generated with an unexpected reduction (% 32
). With the COMPILE_ASSERT
, the code fails to compile.
$ 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'm not supposed to use a #define
, and C++ inline functions are the answer. But I feel like I'm suffering a disconnect.
How do I force the compiler to propagate the value that involves const
values?
Or, if the COMPILE_ASSERT
is the wrong tool (const
is being propagated), how do I set up a test so that I can verify the immediate-8 version of the rorb
is used?
Related, this is a C++03 project. It does not use Boost, does not use Cmake, does not use Autotools, etc.
Upvotes: 3
Views: 706
Reputation: 5533
When you specify amount as function argument, you lose its compile-time constness.
Why don't you declare amount is template argument? In such case the function user is also forced to pass a compile-time constant, which is good too.
To ensure that shift is used as compile-time constant, you can create a static const local variable.
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;
}
Upvotes: 4