如何通过内联函数强制const传播?

时间:2015-07-19 05:54:38

标签: c++ c-preprocessor constexpr

我正在尝试强制预处理器为我执行一些数学操作,以便将常量传播到内联汇编中。这是减少的案例:

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;
}

上面的代码依赖于CPU特定的功能,我很喜欢它(当GCC可用时,它实际上是x86 / x64 Linux上的模板专用)。 "I" 约束表示整数值必须介于[0,31]之间。

代码的调用者看起来像:

byte b1 = RotateRight(1, 1);
byte b2 = RotateRight(1, 31);

RotateRight(1, 31)来自密码学家(其在C / C ++中的未定义行为,因为一个字节只能在[0,7]范围内旋转)。我可以使用ASM摆脱C / C ++约束。由于移位量在编译时是已知的,我希望它在编译时减少;我希望使用immediate-8生成的rorb版本。

没有COMPILE_ASSERT,代码会编译,但我不确定是否正在传播常量。也就是说,它可能会因意外减少而生成(% 32)。使用COMPILE_ASSERT,代码无法编译。

$ 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)>

我知道我不应该使用#define,而C ++内联函数就是答案。但我觉得我正在遭受脱节。

如何强制编译器传播涉及const值的值?

或者,如果COMPILE_ASSERT是错误的工具(const正在传播),我该如何设置测试以便我可以验证{{1}的immediate-8版本使用了吗?

相关,这是一个C ++ 03项目。它不使用Boost,不使用Cmake,不使用Autotools等。

1 个答案:

答案 0 :(得分:4)

如果将 amount 指定为函数参数,则会丢失其编译时常量。

为什么不声明金额是模板参数?在这种情况下,函数用户也被迫传递编译时常量,这也很好。

要确保将shift用作编译时常量,可以创建一个静态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;
}
相关问题