Sawik
Guest
Wed May 23, 2007 11:42 am
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ł?
--
pozdrawiam
Sawi
Mister
Guest
Wed May 23, 2007 12:40 pm
Quote:
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)
Dobry kompilator powinien to tak zoptymalizować.
Mister
Artur M. Piwko
Guest
Wed May 23, 2007 12:41 pm
In the darkest hour on Wed, 23 May 2007 09:57:16 +0000 (UTC),
Sawik <sawik@cos.gdzies.com> screamed:
Quote:
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);
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)
Quote:
t1=(t1*16)||(t1/16);
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.
Quote:
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ł?
Masz tu wędkę:
http://www.ibiblio.org/gferg/ldp/GCC-Inline-Assembly-HOWTO.html
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;
}
--
[ Artur M. Piwko : Pipen : AMP29-RIPE : RLU:100918 : From == Trap! : SIG:217B ]
[ 12:52:20 user up 11350 days, 0:47, 1 user, load average: 0.06, 0.06, 0.06 ]
PLEASE ignore the previous rumor.
Artur M. Piwko
Guest
Wed May 23, 2007 1:41 pm
In the darkest hour on Wed, 23 May 2007 09:57:16 +0000 (UTC),
Sawik <sawik@cos.gdzies.com> screamed:
Quote:
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);
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)
Quote:
t1=(t1*16)||(t1/16);
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.
Quote:
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ł?
Masz tu wędkę:
http://www.ibiblio.org/gferg/ldp/GCC-Inline-Assembly-HOWTO.html
I specjalnie dla AVR:
http://www.nongnu.org/avr-libc/user-manual/inline_asm.html
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;
}
--
[ Artur M. Piwko : Pipen : AMP29-RIPE : RLU:100918 : From == Trap! : SIG:217B ]
[ 12:52:20 user up 11350 days, 0:47, 1 user, load average: 0.06, 0.06, 0.06 ]
PLEASE ignore the previous rumor.
Sawik
Guest
Thu May 24, 2007 12:43 pm
Dnia 23.05.2007 Artur M. Piwko <pipene-news@pu.kielce.pl> napisał/a:
Quote:
In the darkest hour on Wed, 23 May 2007 09:57:16 +0000 (UTC),
Sawik <sawik@cos.gdzies.com> screamed:
t1=(t1*16)||(t1/16);
Tutaj masz dodatkowo błąd związany z użyciem sumy logicznej '||'
zamiast sumy bitowej '|'. To nie są operacje tożsame.
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ę :)
--
pozdrawiam
Sawi
Sawik
Guest
Thu May 24, 2007 12:43 pm
Dnia 23.05.2007 Mister <noweprojekty@wp.pl> napisał/a:
Quote:
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)
Dobry kompilator powinien to tak zoptymalizować.
I też gcc (właściwie g++, bo jego używam) tak robi - sprawdziłem.
--
pozdrawiam
Sawi