2015-07-23 10 views
6

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.

+1

Ciągle mówimy o arytmetyce preprocesora, ale nie istnieją żadne stałe # define'd nigdzie w kodzie. –

+0

Możesz użyć asemblera systemowego przez '-no-integrated-as'. – Thomas

+2

Jeśli 'y' jest znany w czasie comoile, dlaczego nie uczynić go parametrem szablonu? –

Odpowiedz

2

Ponieważ wydaje się być pecha próbuje wymusić stałą ocenę należytej zaprojektować decyzje, forma ror r/m8, cl może być dobrym kompromisem:

__asm__ ("rorb %b1, %b0" : "+q,m" (x) : "c,c" (y) : "cc"); 

Wielokrotna alternatywa składnia ograniczeniem jest „promowanie” rejestr używaj nad pamięcią ze względu na problem z clang, objęte here. Nie wiem, czy problem został rozwiązany w późniejszych wersjach. gcc ma tendencję do lepszego dopasowania do ograniczeń i uniknięcia wycieków.

To wymaga załadowania (y) do rejestru rcx/ecx/cl, ale prawdopodobnie kompilator może ukryć to za innym opóźnieniem. Ponadto nie ma problemów z zasięgiem dla (y). rorb skutecznie używa (%cl % 8).Przeciągnięcie "cc" nie jest wymagane.


Jeśli wyrażenie jest stała, zarówno gcc i brzęk mogą korzystać __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) ... 

lub jak wspomniał w liście do korespondencji:

if (__builtin_constant_p(y)) 
{ 
    if ((y &= 0x7) != 0) 
     x = (x >> y) | (x << (8 - y)); /* gcc generates rotate. */ 
} 
+0

* „' RORB skutecznie wykorzystuje (% CI% 8) '” * - Wiedziałem, że to może być wykorzystane, ale nie wiem, jak to wyrazić ... Dzięki. – jww

+1

@jww - BTW, dla 8-bit unsigned natychmiastowe, można użyć '' "N" ograniczenie, a nie ' "I"' i niech 'ror' obsłużyć modulo 8 Zakres. –

0

If 'N' contraint dla 8 bitów, a co z 16/32/64?

Powiązane problemy