We are trying to speedup some code under Clang and Visual C++ (GCC and ICC is OK). We thought we could use constexpr
to tell Clang a value is a compile time constant but its causing a compile error:
$ clang++ -g2 -O3 -std=c++11 test.cxx -o test.exe
test.cxx:11:46: error: function parameter cannot be constexpr
unsigned int RightRotate(unsigned int value, constexpr unsigned int rotate)
^
1 error generated.
Here is the reduced case:
$ cat test.cxx
#include <iostream>
unsigned int RightRotate(unsigned int value, constexpr unsigned int rotate);
int main(int argc, char* argv[])
{
std::cout << "Rotated: " << RightRotate(argc, 2) << std::endl;
return 0;
}
unsigned int RightRotate(unsigned int value, constexpr unsigned int rotate)
{
// x = value; y = rotate
__asm__ ("rorl %1, %0" : "+mq" (value) : "I" ((unsigned char)rotate));
return value;
}
GCC and ICC will do the right thing. They recognize a value like 2
in the expression RightRotate(argc, 2)
cannot change under the laws of the physical universe as we know them, and it will treat 2
as a compile time constant and propagate it into the assembly code.
If we remove the constexpr
, then Clang and VC++ aseembles the function into a rotate REGISTER
, which is up to 3x slower than a rotate IMMEDIATE
.
How do we tell Clang the function parameter rotate
is a compile time constant, and it should be assembled into a rotate IMMEDIATE
rather than a rotate REGISTER
?