| Author |
Message
|
trol.six Poziom 20

Joined: 29 Oct 2005 Posts: 1086 Location: Krakow
|
#1
06 Apr 2007 19:56 call-clobbered register |
|
|
|
mam pytanie, moze ktos mi rozjaśni w głowie, bo co nie co sie znam, ale skąd moze brac sie taki niuans:
deklaracja zmiennej z przypisaniem do rejestru w avr:
| Code: |
| register unsigned char data asm("r3"); |
niektóre funkcje są OK np:
| Code: |
data |= 0x02;
140: 22 60 ori r3, 0x02 ; 2 |
a w innej funkcji do niczego i używa r18:
| Code: |
4e8: 41 fd sbrc r18, 1
4ea: 17 c0 rjmp .+46 ; 0x51a <__stack+0xbb> |
Oczywiście kompilator uprzedza:
| Quote: |
| warning: call-clobbered register used for global register variable |
Przy optymalizacji -Os kod jest generowany poprawnie przy -O2 jest jak powyżej. Czytam o opcjach optymalizcyjnych gcc. Domyslam sie że jakas optymalizacja tutaj ma coś do powiedzenia, ktoś wie która? I czemu to tak.
|
|
| Back to top |
|
 |
eP Poziom 19

Joined: 02 Oct 2006 Posts: 798 Location: Tak
|
#2
11 Apr 2007 09:45 Re: call-clobbered register |
|
|
|
| trol.six wrote: |
| Przy optymalizacji -Os kod jest generowany poprawnie przy -O2 jest jak powyżej. Czytam o opcjach optymalizcyjnych gcc. Domyslam sie że jakas optymalizacja tutaj ma coś do powiedzenia, ktoś wie która? I czemu to tak. |
Jezeli rejestr przechowuje zmienna globalna to kompilator stara sie zamiast tegoz rejestru uzyc chwilowo innego bedacego do dyspozycji - wolnego.
Oczywiscie jezeli zazadasz od kompilatora przy pomocy wyboru odpowiednich opcji do kompilacji aby stosowal sie scisle do Twoich zyczen to on sie zastosuje tyle ze kod programu moze sie przez to wydluzyc i stac sie mniej efektywnym, bo w danej chwili trzeba bedzie dolozyc instrukcje zwolnienia zajetego rejestru by moc go uzywac w innym celu, a na koniec instrukcje przywrocenia mu wartosci poczatkowej.
Pozdrawiam
|
|
| Back to top |
|
 |
Google

|
#
11 Apr 2007 09:45 |
|
|
|
|
|
| Back to top |
|
 |
trol.six Poziom 20

Joined: 29 Oct 2005 Posts: 1086 Location: Krakow
|
#3
11 Apr 2007 12:19 Re: call-clobbered register |
|
|
|
Oki, tyle ze to troche bez sensu, po co uzywa r18 jak ma używać r2. Wtedy zamist jednego zadeklarowanego r2, używa dwóch r2 i r18 w zależnosci od miejsca w programie. Co skutkuje niewłaściwym działeniem programu. I koniecznoscią pisania w inny sposób.
Ja sie domyślam że w jakis przypadkach może to przynieść korzyść, tylko wydaje mi sie to dość drastyczne.
W zasadzie to przy bardzo dużym programie, gdzie duża ilosć danych przewala sie przez przerwania (bo to one są tutaj głownym czynnikiem sprawczym), to musiałbym chyba wszystkie dane zapisać jako volatile, to raz, co i tak pogarsza kod w relacji do -Os,
Po to sobie stosuje zmienna globalną na stałe przypisaną do rejestru r2, żeby mieć do niej dostęp z każdego punktu programu, i to bardzo szybko.
Bo deklaracja zmiennej np:
| Code: |
| volatile unsigned char data |
skutkuje dośc rozdmuchanym kodem, gdyż za każdym razem procesor pobiera zmienna z pamieci do rejestru, a tak mam ją w r2, dzieki czemu szybkość kodu jest znacznie wyższa.
To i tak nie jest to co w asemblerze, ale przy opcjach gdzie zależy nam na czasie poprawia troche całość. A wydawało mi sie że deklaracja na stałe przypisania danej do rejestru jest stała, ale widze ze jednak czasem kompilator ma humor i olewa to przypisanie.
To po kiego grzyba ja to przypisanie na stałe zmiennej do rejestru robie, skoro kompilator ma to gdzieś?
Nie doszukałem sie która opcja gcc powoduje taką optymalizacje, bo moze by mnie troche bardziej oświeciło
|
|
| Back to top |
|
 |
eP Poziom 19

Joined: 02 Oct 2006 Posts: 798 Location: Tak
|
#4
11 Apr 2007 16:02 Re: call-clobbered register |
|
|
|
| trol.six wrote: |
Oki, tyle ze to troche bez sensu, po co uzywa r18 jak ma używać r2. Wtedy zamist jednego zadeklarowanego r2, używa dwóch r2 i r18 w zależnosci od miejsca w programie. Co skutkuje niewłaściwym działeniem programu. I koniecznoscią pisania w inny sposób.
|
Sorry Kolego ale za sens to odpowiadasz Ty a nie kompilator - po to masz wlasnie miedzy innymi opcje kompilacji.
Zakladam ze rozrozniasz przypadki przekazywania argumentow do funkcji przez wartosc i przez referencje.
Oraz nie sa Ci obce zakresy waznosci zmiennych w programie.
| trol.six wrote: |
Ja sie domyślam że w jakis przypadkach może to przynieść korzyść, tylko wydaje mi sie to dość drastyczne.
W zasadzie to przy bardzo dużym programie, gdzie duża ilosć danych przewala sie przez przerwania (bo to one są tutaj głownym czynnikiem sprawczym), to musiałbym chyba wszystkie dane zapisać jako volatile, to raz, co i tak pogarsza kod w relacji do -Os,
Po to sobie stosuje zmienna globalną na stałe przypisaną do rejestru r2, żeby mieć do niej dostęp z każdego punktu programu, i to bardzo szybko.
Bo deklaracja zmiennej np:
| Code: |
| volatile unsigned char data |
skutkuje dośc rozdmuchanym kodem, gdyż za każdym razem procesor pobiera zmienna z pamieci do rejestru, a tak mam ją w r2, dzieki czemu szybkość kodu jest znacznie wyższa.
To i tak nie jest to co w asemblerze, ale przy opcjach gdzie zależy nam na czasie poprawia troche całość. A wydawało mi sie że deklaracja na stałe przypisania danej do rejestru jest stała, ale widze ze jednak czasem kompilator ma humor i olewa to przypisanie.
|
Nie, kompilator niczego nie olewa tylko kompiluje kod wedle Twoich osobistych zyczen i zazalen ktore mu zglaszasz ustawiajac lub nie odpowiednie opcje kompilacji.
| trol.six wrote: |
To po kiego grzyba ja to przypisanie na stałe zmiennej do rejestru robie, skoro kompilator ma to gdzieś?
|
A to po kiego grzyba uruchamiasz go z takim a nie innym zestawem opcji ? :D
| trol.six wrote: |
Nie doszukałem sie która opcja gcc powoduje taką optymalizacje, bo moze by mnie troche bardziej oświeciło |
Ja tez sie nie doszukalem, ale najwyrazniej widac ze kompilator stara sie myslec za Ciebie i wysyla ci odpowiednie Warningi aby cie zmotywowac do dokladniejszego przestudiowania sensu opcji z ktorymi go uruchamiasz.
Przypuszczam ze bylbys duzo bardziej zaskoczony gdyby sie okazalo ze jakas funkcja zmienia sobie wartosc Twojej zmiennej globalnej tylko dlatego ze ma zdefiniowane w swoim ciele by korzystac z tego samego rejestru do jakichs swoich celow, ktory sluzy do przechowywania Twojej zmiennej globalnej.
|
|
| Back to top |
|
 |
trol.six Poziom 20

Joined: 29 Oct 2005 Posts: 1086 Location: Krakow
|
#5
11 Apr 2007 17:50 Re: call-clobbered register |
|
|
|
OKi, ja to wiem wszystko co napisałeś, przeciez napisałem że opcja -Os generuje poprawny kod, i napisałem że działa tutaj jakaś opcja optymalizacyjna.
Dlatego interesuje mnie co takiego kryje sie za ruszaniem moich zmiennych przypisanych do rejestrów, przez kompilator, bo moim zdaniem deklaracje takich zmiennych są dość poważne. Widać nie na tyle poważne.
opcja -O2 jest opcja dość standartowa, i moim zdaniem nie powinna aż tak bardzo ingerować w kod.
Dlatego zadałem pytanie na forum, bo moze ktoś wie albo naprowadzi mnie skąd sie to bierze. Bo jak to działa w praktyce to ja wiem, bo mam przed oczyma w postaci kodu wynikowego a wyniki umieszczone tutaj.
No chyba że zakres zmiennej globalnej przypisanej do r2, nie obejmuje funkcji main. No to faktycznie mam braki.
|
|
| Back to top |
|
 |
Google

|
#
11 Apr 2007 17:50 |
|
|
|
|
|
| Back to top |
|
 |
szelus Poziom 20

Joined: 12 Jul 2004 Posts: 1016
|
#6
11 Apr 2007 19:25 Re: call-clobbered register |
|
|
|
Ten warning wydaje sie sugerować, że użyty rejestr (r3) nie jest przechowywany przez wywoływane funkcje (tzn. że nie jest to "dobry" rejestr na zmienną globalną, bo funkcje biblioteczne mogą go niszczyć). Czy ten warning pojawia sie niezależnie od poziomu optymalizacji, czy tylko przy -O2?
Co do ignorowania Twojej deklaracji, to trochę mało tu danych. Wybrałeś fragmenty, że tak powiem, tendencyjnie. :wink: Bez obejrzenia większych kawałków programu trudno dywagować.
Masz więcej, niż jeden plik źródłowy?
Jaka wersja gcc?
|
|
| Back to top |
|
 |
trol.six Poziom 20

Joined: 29 Oct 2005 Posts: 1086 Location: Krakow
|
#7
11 Apr 2007 22:06 Re: call-clobbered register |
|
|
|
wersja gcc avr-3.4.4
warning pojawia sie tylko wtedy kiedy źle jest generowny kod, czyli przy optymalizacji -O2, choć teraz po uproszczeniu nawet sie nie pojawia.
Zdarzyłomi sie że taka zmienna przypisana do rejestru była w innym rejestrze, albo w ogóle w pamieci, tak jak sugerujesz ze jakaś funkcja bibioteczna byłaby używana, to kompilator przesówał ją do innego rejestru.
Natomiast nigdy nie mailem takiego problemu że dwie funkcje korzystają z dwu róznych rejestrów.
Sprawa wygląda tak, że jak uproszcze program to jest OKi, a jak dam troche wiecej linijek to bluzga. Ja wiem dlaczego sie bluzga, i zaraz to wam pokaże:
| Code: |
register unsigned char cz_set asm("r2");
register unsigned char co_st asm("r4");
int main ( void )
{
cz_set = 0;
co_st = 0;
sei();
// --- ja wiem brzydka petla ale while(1){} dziąła tak samo
BIBI:
if ( co_st & 0x02 )
{
co_st &= ~( 0x02 );
liczba_cyfra ( cz_sek/10, 2 );
}
if ( co_st & 0x01 ) {
if ( cz_set == 120 ){
liczba_cyfra ( ' ', 0 );
}
}
sei();
goto BIBI;
return (0);
}
|
| Code: |
00000256 <main>:
256: cf e5 ldi r28, 0x5F ; 95
258: d4 e0 ldi r29, 0x04 ; 4
25a: de bf out 0x3e, r29 ; 62
25c: cd bf out 0x3d, r28 ; 61
25e: 22 24 eor r2, r2 // ---- nasze rejestry
260: 42 2c mov r4, r2
262: 78 94 sei
264: 82 2d mov r24, r2 // ---- kompilator przepisuje do r24 ale o co?
266: 99 27 eor r25, r25
268: 81 fd sbrc r24, 1
26a: 08 c0 rjmp .+16 ; 0x27c <main+0x26>
26c: 80 ff sbrs r24, 0
26e: 03 c0 rjmp .+6 ; 0x276 <main+0x20>
270: 28 e7 ldi r18, 0x78 ; 120
272: 22 16 cp r2, r18
274: 71 f0 breq .+28 ; 0x292 <main+0x3c>
276: 78 94 sei
278: 81 ff sbrs r24, 1 // ---- tutaj mamy skok petli i brak odswieaznia r24 wqartoscia r2
27a: f8 cf rjmp .-16 ; 0x26c <main+0x16>
27c: 2d ef ldi r18, 0xFD ; 253
27e: 42 22 and r4, r18
280: 80 91 72 00 lds r24, 0x0072
284: 6a e0 ldi r22, 0x0A ; 10
286: 9e d2 rcall .+1340 ; 0x7c4 <__udivmodqi4>
288: 62 e0 ldi r22, 0x02 ; 2
28a: 41 df rcall .-382 ; 0x10e <liczba_cyfra>
28c: 84 2d mov r24, r4
28e: 99 27 eor r25, r25
290: ed cf rjmp .-38 ; 0x26c <main+0x16>
292: 60 e0 ldi r22, 0x00 ; 0
294: 80 e2 ldi r24, 0x20 ; 32
296: 3b df rcall .-394 ; 0x10e <liczba_cyfra>
298: 84 2d mov r24, r4
29a: 99 27 eor r25, r25
29c: 78 94 sei
29e: ec cf rjmp .-40 ; 0x278 <main+0x22> |
a jak wyglada skompilowany z opcją -Os
| Code: |
00000212 <main>:
212: cf e5 ldi r28, 0x5F ; 95
214: d4 e0 ldi r29, 0x04 ; 4
216: de bf out 0x3e, r29 ; 62
218: cd bf out 0x3d, r28 ; 61
21a: 22 24 eor r2, r2
21c: 42 2c mov r4, r2
21e: 78 94 sei
220: 41 fe sbrs r4, 1 // ----- poprawne porównanie
222: 08 c0 rjmp .+16 ; 0x234 <main+0x22>
224: 8d ef ldi r24, 0xFD ; 253
226: 48 22 and r4, r24
228: 80 91 72 00 lds r24, 0x0072
22c: 6a e0 ldi r22, 0x0A ; 10
22e: 75 d2 rcall .+1258 ; 0x71a <__udivmodqi4>
230: 62 e0 ldi r22, 0x02 ; 2
232: 20 df rcall .-448 ; 0x74 <liczba_cyfra>
234: 40 fe sbrs r4, 0
236: 06 c0 rjmp .+12 ; 0x244 <main+0x32>
238: 88 e7 ldi r24, 0x78 ; 120
23a: 28 16 cp r2, r24
23c: 19 f4 brne .+6 ; 0x244 <main+0x32>
23e: 60 e0 ldi r22, 0x00 ; 0
240: 80 e2 ldi r24, 0x20 ; 32
242: 18 df rcall .-464 ; 0x74 <liczba_cyfra>
244: 78 94 sei
246: ec cf rjmp .-40 ; 0x220 <main+0xe>
|
W zasadzie jak troche zmienie kod to zawsze cos tam przy -O2 namiesza, tu jest taki przykład.
Wiec sprawa mi sie tak ze sobie chłopina przapisuje do innych rejestrów i z tamtych nie korzysta. Tylko w jakim celu?
Albo liczy adres skoku w petli pomijając przepisanie zmiennych, co czasem może być optymalizacją, ale tutaj wyraźnie ma przypisanie rejetrów do zmiennych i nie podoba mi sie ze se przepisuje do innych.
Poniewaz ja już dosyć mocno namieszałem, możę to nie być to co na początku, ale mniej wiecej coś w tym stylu.
|
|
| Back to top |
|
 |
szelus Poziom 20

Joined: 12 Jul 2004 Posts: 1016
|
#8
12 Apr 2007 10:53 Re: call-clobbered register |
|
|
|
Wersja 3.4.4 nie jest najświeższa (chociaż ja tez korzystam z 3.4.3). Z tego co pamiętam, były zastrzeżenia co do optymalności generowanego kodu.
Co do samego kodu, to błędu nie widzę. Tzn. przy -O2 kod nie jest może najoptymalniejszy (zawsze możesz jeszcze sprawdzić -O3), ale generalnie poprawny.
Jeżeli chodzi o brak odświeżania r24 z r2 to jest to OK. W instrukcji gcc jest wyraźnie napisane, że nie wolno używać zmiennych przypisanych na stałe do rejestrów w przerwaniach. Zresztą, brak tu volatile. Zatem kompilator całkiem poprawnie zakłada, że w tym miejscu wartość r2 nie mogła ulec zmianie.
Nawiasem mówiąc, kod, który pokazałeś nie jest z tej wersji źródeł. W obu wersjach brak w kodzie wynikowym czegoś, co odpowiadałoby "if ( co_st & 0x02 )" w kodzie źródłowym. Z kolei w kodzie źródłowym brak instrukcji out, które są w kodzie wynikowym.
|
|
| Back to top |
|
 |
trol.six Poziom 20

Joined: 29 Oct 2005 Posts: 1086 Location: Krakow
|
#9
12 Apr 2007 11:57 Re: call-clobbered register |
|
|
|
Niestety musze cie zmartwić , ale jest to kod bezpośrednio przekopiowany z kompilacji. Kod if jest tutaj 268: 81 fd sbrc r24, 1 , a ten out, to inicjacja stosu jaka nastepuje w procach avr.
OKi, nie można uzywać zmiennych rejestrowych, i to będzie ta odpowiedź, nie doczytałem sie tego niestety, musze poprzewertować jeszcze mana.
Ten kod jest poprawny ... ale z punktu widzenia kompilatora, a nie z punktu widzenia programu i zawartych w nim danych o przypisaniu zmiennej do rejestru.
Bo po to przypisuje zmienna do rejestru zeby była przypisana, a nie po to żeby kompilator twierdził że on lepiej wie po co tą zmienna przypisuje.
Juz sie wypowiadałem dlaczego nie chce tam volatile.
W takim razie nie ma sensu przypisywania zmiennych do rejestrów. To po co to jest?
|
|
| Back to top |
|
 |
Google

|
#
12 Apr 2007 11:57 |
|
|
|
|
|
| Back to top |
|
 |
szelus Poziom 20

Joined: 12 Jul 2004 Posts: 1016
|
#10
12 Apr 2007 14:49 Re: call-clobbered register |
|
|
|
| trol.six wrote: |
Niestety musze cie zmartwić , ale jest to kod bezpośrednio przekopiowany z kompilacji. Kod if jest tutaj 268: 81 fd sbrc r24, 1 , a ten out, to inicjacja stosu jaka nastepuje w procach avr.
|
Ok, no może nie przyjrzałem sie zbyt dokładnie, a z tym out-em faktyczie AVR-gcc tak ma.
Cóż, przeczytaj sobie ten wątek http://gcc.gnu.org/ml/gcc-patches/2005-11/msg00657.html.
Wygląda, że póki co, jest to ograniczenie gcc.
[/url]
|
|
| Back to top |
|
 |
trol.six Poziom 20

Joined: 29 Oct 2005 Posts: 1086 Location: Krakow
|
#11
12 Apr 2007 16:46 Re: call-clobbered register |
|
|
|
No wiec wszystko jest jasne, kompilator traktuje moja zmienna rejestrowa jak inna zmienna i ją optymalizuje po swojemu, brak volatile przed zmienną jest wynikiem niechęci kompilatora przed traktowaniem zmiennej rejestrowej w ten sposób.
Niby sie ma to zmienić, post o zmianie jest z 2005-11 z obietnicą że wersja gcc 4.2 będzie miała te zmiany i nasza zmienna będzie miała status volatile.
Zobaczymy :)
|
|
| Back to top |
|
 |