winavr - co się skompiluje do instrukcji swap?

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ł?

Reply to
Sawik
Loading thread data ...

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

Reply to
Artur M. Piwko

Dobry kompilator powinien to tak zoptymalizować.

Mister

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

Reply to
Artur M. Piwko

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.

Reply to
Sawik

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ę :)

Reply to
Sawik

ElectronDepot website is not affiliated with any of the manufacturers or service providers discussed here. All logos and trade names are the property of their respective owners.