Jest to związane z How to force const propagation through an inline function? Clang ma zintegrowany asembler; i nie używa on asemblera systemu (który często jest GNU AS (GAS)). Non-Clang wykonywał wcześnie matematykę, a wszystko "po prostu działało".Wymuś Clang, aby "wcześnie wykonać matematykę" na stałych wartościach
Mówię "wcześnie", ponieważ @ n.m. sprzeciwił się opisywaniu go jako "matematyce wykonywanej przez preprocesora". Ale ideą jest, że wartość jest znana w czasie kompilacji i powinna być oceniona wcześnie, tak jak wtedy, gdy preprocesor ocenia #if (X % 32 == 0)
.
Poniżej, Clang 3.6 narzeka na naruszenie ograniczenia. Wydaje się, że stała nie jest propagowane w całym:
$ 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
...
funkcji powyżej włączonych specjalizacji szablonu:
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;
}
Są one wywoływane o wartości const, więc obracanie kwota jest znany w czasie kompilacji . Typowym rozmówca może wyglądać następująco:
unsigned int x1 = rotrFixed<byte>(1, 4);
unsigned int x2 = rotrFixed<byte>(1, 32);
Żaden z tych wątpliwych] [sztuczek byłyby wymagane, jeżeli GCC lub Clang warunkiem nieodłącznym wykonać rotate in near constant time. Osobiście nawet zadowalam się "wykonaniem rotacji", ponieważ oni nawet tego nie mają.
Jaka jest sztuczka, aby Clang wznowił wykonywanie wstępnego przetwarzania wartości stałej?
Uważni czytelnicy rozpoznają rotrFixed<byte>(1, 32)
może być niezdefiniowana zachowanie w przypadku zastosowania tradycyjnych C/C++ obracać. Więc wkraczamy do montażu, aby uniknąć ograniczeń C/C++ i cieszyć się przyspieszeniem 1 instrukcji.
Ciekawy czytelnik może zastanawiać się, dlaczego byśmy to zrobili. Kryptografowie nazywają specyfikacje, a czasami te specyfikacje nie są sympatią dla podstawowego sprzętu lub standardowych ciał. Zamiast zmieniać specyfikację kryptografu, staramy się przekazać go w dosłownym brzmieniu, aby ułatwić przeprowadzanie audytów.
Błąd jest otwarty dla tego problemu: LLVM Bug 24226 - Constant not propagated into inline assembly, results in "constraint 'I' expects an integer constant expression".
Nie wiem, jakie gwarancje robi Clang, ale wiem, że kompilator i zintegrowany asembler twierdzi, że jest zgodny z asemblerem GCC i GNU. A GCC i GAS zapewniają propagację stałej wartości.
Ciągle mówimy o arytmetyce preprocesora, ale nie istnieją żadne stałe # define'd nigdzie w kodzie. –
Możesz użyć asemblera systemowego przez '-no-integrated-as'. – Thomas
Jeśli 'y' jest znany w czasie comoile, dlaczego nie uczynić go parametrem szablonu? –