RTV forum PL | NewsGroups PL

Jak skompilować w C/C++ na AVR do instrukcji `swap` dla zmiennej 1-bajtowej?

winavr - co się skompiluje do instrukcji swap?

NOWY TEMAT

elektroda NewsGroups Forum Index - Elektronika Polska - Jak skompilować w C/C++ na AVR do instrukcji `swap` dla zmiennej 1-bajtowej?

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 Smile).

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

elektroda NewsGroups Forum Index - Elektronika Polska - Jak skompilować w C/C++ na AVR do instrukcji `swap` dla zmiennej 1-bajtowej?

NOWY TEMAT

Regulamin - Zasady uzytkowania Polityka prywatnosci Kontakt RTV map News map