winavr - co się skompiluje do instrukcji swap?

May 23, 2007 5 Replies

Witam



Ostatnio mam taki problem: potrzebuję zamienić starszą część z młodszą w zmiennej jedno-bajtowej. Możemy nawet założyć, że znajduje się ona już w jednym z rejestrów mikrokontrolera. AVRy mają instrukcję swap - to jest dokładnie to, czego potrzebuję. Ale co napisać w C/C++, aby kompilator skompilował to do jednej instrukcji w kodzie maszynowym (właśnie swap)?



Próbowałem np.



t1=(t1*16)+(t1/16);



albo



t1=(t1*16)||(t1/16);



ale kompilator sobie nie radzi i tworzy z tego ciąg co najmniej kilku instrukcji (mam włączoną opcję optymalizacji wielkości kodu).



Chwilowo problem rozwiązałem wstawką asemblera: asm("swap r26\n"); ale jest to rozwiązanie mało eleganckie, bo jak kompilator ulokuje mi moją zmienną t1 w innym rejestrze, to będę musiał ręcznie zmienić r26 na coś innego.



Macie jakiś pomysł?


In the darkest hour on Wed, 23 May 2007 09:57:16 +0000 (UTC), Sawik snipped-for-privacy@cos.gdzies.com> screamed:

Nie używaj mnożenia, gdy chcesz pomnożyć przez potęgę dwójki. Znacznie szybciej będzie przesunąć w lewo bitowo.

t1 * 16 == t1 << 4 (16 == 2^4)

Tutaj masz dodatkowo błąd związany z użyciem sumy logicznej '||' zamiast sumy bitowej '|'. To nie są operacje tożsame.

t1 = (t1 << 4) | (t1 >> 4);

Ale i tak zostanie to zamienione na przesunięcia bitowe.

Masz tu wędkę:

formatting link
I wyjątkowo dziś, bo w dobrym humorze jestem, rybkę: ;-)

char x = 0xf0; asm( "mov %0, r26\n\t" "swap r26\n\t" "mov r26, %1\n\t" : "=r"(x) : "r"(x) : "r26" );

Jak widzisz całość sprowadziłem do 2x mov, 1x swap. Zamiast '\n\t' możesz użyć ';'.

Jeśli chcesz tego używać częściej, zrób sobie funkcję:

inline char swap( char x ) { asm( ... ); return x; }

Dobry kompilator powinien to tak zoptymalizować.

Mister

In the darkest hour on Wed, 23 May 2007 09:57:16 +0000 (UTC), Sawik snipped-for-privacy@cos.gdzies.com> screamed:

Nie używaj mnożenia, gdy chcesz pomnożyć przez potęgę dwójki. Znacznie szybciej będzie przesunąć w lewo bitowo.

t1 * 16 == t1 << 4 (16 == 2^4)

Tutaj masz dodatkowo błąd związany z użyciem sumy logicznej '||' zamiast sumy bitowej '|'. To nie są operacje tożsame.

t1 = (t1 << 4) | (t1 >> 4);

Ale i tak zostanie to zamienione na przesunięcia bitowe.

Masz tu wędkę:

formatting link
specjalnie dla AVR:
formatting link
I wyjątkowo dziś, bo w dobrym humorze jestem, rybkę: ;-)

char x = 0xf0; asm( "mov %0, r26\n\t" "swap r26\n\t" "mov r26, %1\n\t" : "=r"(x) : "r"(x) : "r26" );

Jak widzisz całość sprowadziłem do 2x mov, 1x swap. Zamiast '\n\t' możesz użyć ';'.

Jeśli chcesz tego używać częściej, zrób sobie funkcję:

inline char swap( char x ) { asm( ... ); return x; }

Dnia 23.05.2007 Mister snipped-for-privacy@wp.pl napisał/a:

I też gcc (właściwie g++, bo jego używam) tak robi - sprawdziłem.

Dnia 23.05.2007 Artur M. Piwko snipped-for-privacy@pu.kielce.pl> napisał/a:

Aa, fakt. Na szczęście, w oryginale mam dobrze, tylko pomyliłem się przy przepisywaniu (mam to chyba w podświadomości, bo nie pierwszy raz robię ten błąd, a potem się dziwię, że zmienna ma dziwne wartości :)).

Dzięki za wędkę i rybkę :)

Join the Discussion

Have something to add? Share your thoughts — no account required.

Didn't find your answer?

Ask the community — no account required