jww*_*jww 6 c++ llvm clang constexpr
这与如何通过内联函数强制const传播有关?Clang有一个集成的汇编程序; 它不使用系统的汇编程序(通常是GNU AS(GAS)).Non-Clang提前完成了数学运算,一切都"正常".
我说"早",因为@nm反对将其描述为"由预处理器执行的数学".但是这个想法是在编译时知道值,并且应该提前评估它,就像预处理器评估a时一样#if (X % 32 == 0).
下面,Clang 3.6抱怨违反约束.看起来这个常数并没有在整个过程中传播:
$ export CXX=/usr/local/bin/clang++
$ $CXX --version
clang version 3.6.0 (tags/RELEASE_360/final)
Target: x86_64-apple-darwin12.6.0
...
$ make
/usr/local/bin/clang++ -DNDEBUG -g2 -O3 -Wall -fPIC -arch i386 -arch x86_64 -pipe -Wno-tautological-compare -c integer.cpp
In file included from integer.cpp:8:
In file included from ./integer.h:7:
In file included from ./secblock.h:7:
./misc.h:941:44: error: constraint 'I' expects an integer constant expression
__asm__ ("rolb %1, %0" : "+mq" (x) : "I" ((unsigned char)(y%8)));
^~~~~~~~~~~~~~~~~~~~
./misc.h:951:44: error: constraint 'I' expects an integer constant expression
...
Run Code Online (Sandbox Code Playgroud)
上述函数是内联模板特化:
template<> inline byte rotrFixed<byte>(byte x, unsigned int y)
{
// The I constraint ensures we use the immediate-8 variant of the
// shift amount y. However, y must be in [0, 31] inclusive. We
// rely on the preprocessor to propoagte the constant and perform
// the modular reduction so the assembler generates the instruction.
__asm__ ("rorb %1, %0" : "+mq" (x) : "I" ((unsigned char)(y%8)));
return x;
}
Run Code Online (Sandbox Code Playgroud)
它们是用const值调用的,因此旋转量在编译时是已知的.典型的调用者可能看起来像:
unsigned int x1 = rotrFixed<byte>(1, 4);
unsigned int x2 = rotrFixed<byte>(1, 32);
Run Code Online (Sandbox Code Playgroud)
如果GCC或Clang提供了在近恒定时间内执行旋转的内在函数,则不需要这些[可疑]技巧.我甚至满足于"执行旋转",因为他们甚至没有.
让Clang继续执行const值的预处理需要什么技巧?
rotrFixed<byte>(1, 32)如果使用传统的C/C++旋转,精明的读者会认识到可能是未定义的行为.因此,我们进入汇编以避免C/C++限制并享受1指令加速.
好奇的读者可能想知道为什么我们会这样做.密码学家提出了规范,有时那些规范并不同情底层硬件或标准组织.我们不是改变密码学家的规范,而是试图逐字提供,以使审核更容易.
针对此问题打开了一个错误:LLVM错误24226 - 常量未传播到内联汇编中,导致"约束"我需要一个整数常量表达式".
我不知道Clang有什么保证,但我知道编译器和集成汇编程序声称与GCC和GNU的汇编程序兼容.并且GCC和GAS提供恒定值的传播.
由于由于设计决策而尝试强制进行持续评估似乎不太走运,因此该ror r/m8, cl形式可能是一个很好的折衷方案:
__asm__ ("rorb %b1, %b0" : "+q,m" (x) : "c,c" (y) : "cc");
Run Code Online (Sandbox Code Playgroud)
由于 clang 的问题,多种替代约束语法是为了“促进”寄存器使用而不是内存使用,此处介绍。不知道这个问题在以后的版本中是否得到了解决。gcc 往往更擅长约束匹配和避免溢出。
这确实需要加载(y)到rcx/ecx/cl寄存器中,但编译器可能会将其隐藏在另一个延迟后面。此外,不存在范围问题(y)。rorb有效地利用(%cl % 8). "cc"不需要破坏者。
如果表达式是常量,gcc 和 clang 都可以使用__builtin_constant_p:
if (__builtin_constant_p(y))
__asm__("rorb %1, %b0" : "+q,m" (x) : "N,N" ((unsigned char) y) : "cc");
else
... non-constant (y) ...
Run Code Online (Sandbox Code Playgroud)
或如邮件列表中提到的:
if (__builtin_constant_p(y))
{
if ((y &= 0x7) != 0)
x = (x >> y) | (x << (8 - y)); /* gcc generates rotate. */
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
534 次 |
| 最近记录: |