logo elektroda
logo elektroda
X
logo elektroda
Adblock/uBlockOrigin/AdGuard mogą powodować znikanie niektórych postów z powodu nowej reguły.

[GCC] -Os - czyli jak zrobic, zeby gcc nie zjadalo funkcji?

Freddie Chopin 12 Lis 2008 12:57 2292 10
  • #1 5729596
    Freddie Chopin
    Specjalista - Mikrokontrolery
    sa sobie moje wlasne funkcje do zapisu do EEPROMu:

    
    uint8_t *_save_src_adr=0;
    uint8_t *_save_dst_adr=0;
    volatile uint8_t _save_length=0;
    
    ...
    
    void _eeprom_save_block(uint8_t *src,uint8_t *dst,uint8_t length)
    {
    	while(_save_length);
    
    	_save_src_adr=src;
    	_save_dst_adr=dst;
    	_save_length=length;
    
    	EECR|=EECR_EERIE;
    }
    
    ...
    
    ISR(EE_RDY_vect)
    {
    	uint8_t val;
    
    	EEAR=(uint16_t)_save_dst_adr++;			// set up address
    	EEDR=*(_save_src_adr++);				// ... and data
    
    	if(--_save_length)
    		val=EECR_EERIE|EECR_EEMWE;			// enable master write and interrupt
    	else
    		val=EECR_EEMWE;						// for last write - no interrupt
    
    	EECR=val;
    	EECR|=EECR_EEWE;						// start the write operation
    }
    


    jest tez sobie funkcja, ktora liczy jakas tam prosta sume kontrolna.

    
    uint8_t _xor_checksum(uint8_t *ptr,uint8_t length)
    {
    	uint8_t checksum=0;
    
    	while(length--)
    		checksum^=*ptr++;
    
    	return checksum;
    }
    


    i teraz jest kod glowny:

    
    	uint8_t checksum;
    
    	// request data store in EEPROM
    	_eeprom_save_block((uint8_t*)step_ctrl.limit.min,(uint8_t*)_backups_eeprom.limit.min,sizeof(step_limit_t));
    
    	// meanwhile generate new checksum
    	checksum=_xor_checksum((uint8_t*)step_ctrl.limit.min,sizeof(step_limit_t));
    
    	// request checksum store in EEPROM
    	_eeprom_save_block(&checksum,(uint8_t*)&_checksums_eeprom.limit,sizeof(uint8_t));
    


    przy kompilacji tego slicznego kawalka kodu z opcja -Os gcc uznaje, ze pierwsze wywolanie funkcji zapisu do EEPROMu jest w zasadzie zbedne, bo zostaje z niego tyle (funkcja zostaje wlaczona do funkcji glownej:

    
    	while(_save_length);
      a0:	80 91 7a 00 	lds	r24, 0x007A
      a4:	88 23       	and	r24, r24
      a6:	e1 f7       	brne	.-8      	; 0xa0 <bkup_store_limits+0xa>
    
    	_save_src_adr=src;
    	_save_dst_adr=dst;
    	_save_length=length;
      a8:	88 e0       	ldi	r24, 0x08	; 8
      aa:	80 93 7a 00 	sts	0x007A, r24
    
    	EECR|=EECR_EERIE;
      ae:	e3 9a       	sbi	0x1c, 3	; 28
    


    do tego kompilator stwierdza rowniez, ze funkcja liczaca sume kontrolna jest bezsensu, gdyz w ogolne nie zostaje ona wywolana.

    efekt tego jest wiadomo jaki - kod 'prawie' dziala - zapis do eepromu jest, ale nie tego co chce i nie tam gdzie chce...

    czy istnieje jakikolwiek inny sposob zmuszenia GCC do nieoptymalizowania funkcji poza nastawianiem wszedzie gdzie sie da volatile? aby funkcja zapisu do eepromu zadzialala jak trzeba musze jej zmienne globalne deklarowac jako:

    
    volatile static uint8_t * volatile _save_src_adr=0;
    volatile static uint8_t * volatile _save_dst_adr=0;
    volatile static uint8_t _save_length=0;
    


    aby zadzialala suma kontrolna, musze zmienna wynikowa deklarowac jako volatile, o co oczywiscie kompilator tez sie czepi, bo cos mu tam znow nie pasuje z typami (discard qualifier...)

    zaraz oszaleje, wiec bede wdzieczny za pomoc...

    czy w ogole tryb -Os sie do czegokolwiek nadaje?

    4\/3!!
  • Pomocny post
    #2 5729652
    szelus
    Poziom 34  
    Freddie, i to Ty zadajesz takie pytanie?
    Przecież to oczywiste, że wszystkie Twoje trzy zmienne _save_cośtam muszą być zadeklarowane jako volatile, bo są współużywane w przerwaniach. Inaczej kompilatorowi "brak kontekstu".
    Jeżeli taka deklaracja nie rozwiązuje problemu nieliczenia sumy kontrolnej (powinna), to trzeba szukać problemu tylko dla tego przypadku.
  • #3 5729666
    Freddie Chopin
    Specjalista - Mikrokontrolery
    no dobra, ale te wszystkie volatile uint8_t * volatile niezbyt dobrze wygladaja /; wygladaja wrecz lewo...

    sorry za lamerstwo [; myslalem ze moze jednak jest jakis madry atrybu typu __attribute__ ((no_optimalizations_you_stupid_compiler))

    po prostu liczylem na to, ze tak jak zmienna moze byc volatile, to moze po prostu wystarczy zrobic 'volatile' funkcje, co dla kompilatora bedzie oznaczalo, ze ma ja wywolac ZAWSZE i zrobic wszystko, nawet jesli uwaza to za glupie...

    moze ((noinline))? czy wlasnie tego slowka szukam? <:

    a co do liczenia sumy kontrolnej, to nastawianie volatile na prawo i lewo rozwiazuje problem, ale ten kod wtedy nie wyglada ladnie [;

    4\/3!!
  • Pomocny post
    #4 5729677
    BoskiDialer
    Poziom 34  
    szelus: nie w tym problem - zmienne w pamięci i tak muszą zostać zaktualizowane, chciaż dodanie volatile powinno zapewnić kolejność aktualizowania zmiennych.

    Bardziej obstawiał bym na błąd z czasem istnienia zmiennych - zmienna checksum jest tworzona na stosie (zmienne lokalne, których adres jest potrzebny nie są umieszczane w rejestrach), więc jej istnienie może zostać ograniczone do przypisania wartości oraz wywołania _eeprom_save_block(&checksum, ...). Niestety zmienna ta będzie odczytana o wiele później (w przerwaniu już po wywołaniu funkcji _eeprom_save_block) i tu pojawia się błąd - przerwanie posiada wskaźnik na nieistniejącą zmienną.

    Dodatkowo niepokoi mnie zapis (uint8_t*)step_ctrl.limit.min - zamiast wskaźnika zostanie podstawiona wartość pola! Pewnie chodziło o (uint8_t*)&step_ctrl.limit.min
  • #5 5729694
    Freddie Chopin
    Specjalista - Mikrokontrolery
    w strukturze pole .min jest tabela, wiec fear not <:

    a tak w ogole to ja nie chce wylaczyc wszystkich inline'ow, tylko niektore <: bo jak mam wylaczyc wszystkie to moge po prostu wlaczyc -O1 i efekt bedzie ten sam

    4\/3!!
  • Pomocny post
    #6 5729693
    Konto nie istnieje
    Konto nie istnieje  
  • #7 5729701
    szelus
    Poziom 34  
    Freddie Chopin napisał:
    no dobra, ale te wszystkie volatile uint8_t * volatile niezbyt dobrze wygladaja /; wygladaja wrecz lewo...

    Zrób strukturę, będzie wyglądało lepiej...

    Cytat:

    moze ((noinline))? czy wlasnie tego slowka szukam? <:

    Można, bo w tym przypadku rozwijanie funkcji _eeprom_save_block() to nadoptymalizacja, ale to raczej z tego właśnie powodu. Jako alternatywa dla volatile to raczej takie "hakierstwo" ;) - może się prędzej, czy później zemścić.

    Cytat:

    a co do liczenia sumy kontrolnej, to nastawianie volatile na prawo i lewo rozwiazuje problem, ale ten kod wtedy nie wyglada ladnie [;

    Na lewo i prawo nie trzeba - powinno wystarczyć dla tych trzech zmiennych. Jeśli nie - to wyglądałoby na bug-a w kompilatorze, ale wiesz, sprawdziłbym najpierw dokładnie pozostałe możliwości. :)
  • #8 5729706
    Konto nie istnieje
    Konto nie istnieje  
  • #9 5729720
    szelus
    Poziom 34  
    BoskiDialer napisał:

    Bardziej obstawiał bym na błąd z czasem istnienia zmiennych - zmienna checksum jest tworzona na stosie (zmienne lokalne, których adres jest potrzebny nie są umieszczane w rejestrach), więc jej istnienie może zostać ograniczone do przypisania wartości oraz wywołania _eeprom_save_block(&checksum, ...). Niestety zmienna ta będzie odczytana o wiele później (w przerwaniu już po wywołaniu funkcji _eeprom_save_block) i tu pojawia się błąd - przerwanie posiada wskaźnik na nieistniejącą zmienną.

    No tak, przyznaje się, nie analizowałem kodu bardzo dokładnie...
    I w tym wypadku rację ma, niestety, jak napisał albertb, kompilator.
    Adresy zmiennych lokalnych w zmiennych globalnych - tak daleko wyobraźnia kompilatora nie sięga ;) (chociaż mogłaby, bo to często spotykany błąd).
  • Pomocny post
    #10 5729724
    slomo
    Poziom 18  
    Jezeli nie chesz wylaczac wszystkich inline-ów to mozesz jak sam napisałes uzyc __attribute__ ((noinline)).

    pz
REKLAMA