avr-gcc i strasznie długie pętle :/

Witam!

Niby prosta rzecz:

void test1(void) { while( bit_is_clear (PIND, 4 ) ); }

void test2(void) { while( true ) { if(bit_is_set (PIND, 4 )) break; } }

void test3(void) { for(;;) { if(bit_is_set (PIND, 4 )) break; } }

A efekty co najmniej tragiczne:

00000084 <_Z5test1v>: 84: 21 e0 ldi r18, 0x01 ; 1 86: 30 e0 ldi r19, 0x00 ; 0 88: 80 b3 in r24, 0x10 ; 16 8a: 99 27 eor r25, r25 8c: 92 95 swap r25 8e: 82 95 swap r24 90: 8f 70 andi r24, 0x0F ; 15 92: 89 27 eor r24, r25 94: 9f 70 andi r25, 0x0F ; 15 96: 89 27 eor r24, r25 98: 82 27 eor r24, r18 9a: 93 27 eor r25, r19 9c: 80 fd sbrc r24, 0 9e: f4 cf rjmp .-24 ; 0x88 a0: 08 95 ret

000000a2 <_Z5test2v>: a2: 80 b3 in r24, 0x10 ; 16 a4: 99 27 eor r25, r25 a6: 92 95 swap r25 a8: 82 95 swap r24 aa: 8f 70 andi r24, 0x0F ; 15 ac: 89 27 eor r24, r25 ae: 9f 70 andi r25, 0x0F ; 15 b0: 89 27 eor r24, r25 b2: 81 70 andi r24, 0x01 ; 1 b4: 90 70 andi r25, 0x00 ; 0 b6: 88 23 and r24, r24 b8: a1 f3 breq .-24 ; 0xa2 ba: 08 95 ret

000000bc <_Z5test3v>: bc: 80 b3 in r24, 0x10 ; 16 be: 99 27 eor r25, r25 c0: 92 95 swap r25 c2: 82 95 swap r24 c4: 8f 70 andi r24, 0x0F ; 15 c6: 89 27 eor r24, r25 c8: 9f 70 andi r25, 0x0F ; 15 ca: 89 27 eor r24, r25 cc: 81 70 andi r24, 0x01 ; 1 ce: 90 70 andi r25, 0x00 ; 0 d0: 88 23 and r24, r24 d2: a1 f3 breq .-24 ; 0xbc d4: 08 95 ret

Po co te wszystkie swapy/etc ?

Spodziewałbym się prymitywnej pętli z testowaniem bitu. A dostaje stertę kodu, który nic sensownego nie wnosi ...

gcc 3.4.3, kompilacja z -O2 i -O3 daje takie same efekty.

Zaznaczam, że samo testowanie bitów kompiluje się do pojedynczej instrukcji. Sama pętla while(true); kompiluje sie do prostackiego rjmp .-2. Dopiero zbitek z warunkiem opuszczenia produkuje takie nieoptymale fukcje.

Czy to wina GCC czy może moja ?

Reply to
Sebastian Bialy
Loading thread data ...

A co to sa owe bit_is_set/clear?

Reply to
Krzysztof Rudnik

Sebastian Bialy przemówił ludzkim głosem:

[...]
[...]

U mnie przy kompilacji z optymalizacją rozmiaru (-Os) wychodzi:

while( 1 ) { if(bit_is_set (PIND, 4 )) break; 96: 84 9b sbis 0x10, 4 ; 16 98: fe cf rjmp .-4 ; 0x96 }

Reply to
Zbych

avr-libc-user-manual

IO register bit manipulation #define bit_is_set(sfr, bit) (_SFR_BYTE(sfr) & _BV(bit)) #define bit_is_clear(sfr, bit) (!(_SFR_BYTE(sfr) & _BV(bit))) #define loop_until_bit_is_set(sfr, bit) do { } while (bit_is_clear(sfr, bit)) #define loop_until_bit_is_clear(sfr, bit) do { } while (bit_is_set(sfr, bit))

W zasadzie kompiluje się do tego samego co PORT&(1<<BIT) etc.

Reply to
Sebastian Bialy

Damn!

Jaką masz wersję gcc ? Jakie bym -Ox nie podawał, zawsze jest źle (choć nie zawsze tak samo). -Os też nic nie daje, dlaej kod jest strasznie rozwlekły.

Reply to
Sebastian Bialy

Sebastian Bialy przemówił ludzkim głosem:

Configured with: ../gcc-3.4.3/configure --prefix=m:/WinAVR

--build=mingw32 --host=mingw32 --target=avr --enable-languages=c,c++

--with-dwarf2 Thread model: single gcc version 3.4.3

Reply to
Zbych

Dziwne ....

Czy możesz zrobić dla mnie test: ?

compile.bat:

@avr-gcc -Os -Wall -mmcu=atmega8 -Wall -o test.elf main.c @avr-objdump -h -S test.elf >test.lst

main.c:

#include <avr/interrupt.h>

#include <avr/io.h>

int main(void) { while ( bit_is_set(PORTD, 6) ); return 0; }

Reply to
Sebastian Bialy

Sebastian Bialy przemówił ludzkim głosem:

Wyszło to samo co u ciebie. Dziś mi się już nie chce dochodzić jakie opcje decydują o takim efekcie, proponuję żebyś skorzystał ze standardowego makefile'a (/winavr/sample). Wystarczy jak zmodyfikujesz w nim dwie linie: TARGET i SRC.

Reply to
Zbych

Ok, ale to dało mi wiele do myślenia. Poszukam wobec tego co to za brakujące opcje i dziękuje za pomoc !

Reply to
Sebastian Bialy

Coś kręcisz. U mnie wyszło z tego chyba to co powinno (wlepiłem tą funkcję do większego programu dla testu):

0001013e <test1>: 1013e: 84 9b sbis 0x10, 4 ; 16 10140: fe cf rjmp .-4 ; 0x1013e 10142: 08 95 ret

Super optymalnie i tak trzymać. Użyłem avr-gcc 3.4.3 z pakietu WinAVR. Opcje kompilacji (takich standardowo używam):

-Os -std=gnu99 -funsigned-char -funsigned-bitfields -fpack-struct \

-finline -fomit-frame-pointer -fshort-enums -Wall -Werror \

-Wstrict-prototypes -Wformat=2

Podobnie dobre wyniki dały kolejne testy:

0001013e <test2>: 1013e: 84 9b sbis 0x10, 4 ; 16 10140: fe cf rjmp .-4 ; 0x1013e 10142: 08 95 ret
0001013e <test3>: 1013e: 84 9b sbis 0x10, 4 ; 16 10140: fe cf rjmp .-4 ; 0x1013e 10142: 08 95 ret

Czyli wszystkie trzy przykłady robią to samo i to samo dają po kompilacji.

Reply to
Adam Dybkowski

Zerknij na odpowiedź Zbycha, a ja zobacze które parametry kompilacji mogą powodować ten głupi efekt.

Reply to
Sebastian Bialy

Głupia sprawa ....

Okazuje się, że pliki xxx.cpp kompiluja się bez optymalizacji, a pliki xxx.c z optymalizacją.

Poz mianie mojego z .cpp na .c wszystko zaczęło działać jak powinno.

Niestety ja chce mieć cpp bo ja _chce_ c++ (ze względu na szablony). Może avr-g++ ignoruje -Ox ?

Reply to
Sebastian Bialy

Heh, jak miło pisać w 100% pure C, bez żadnych ++. :-) Trzeba spróbować powalczyć z optymalizerem lub explicite kazać kompilatorowi tylko wykonać fazę pośrednią, a po nim zapuścić optymalizer. Jeżeli avr-gcc przewiduje takie sztuczki (podobne do rozdzielenia preprocesora od właściwego kompilatora a potem asemblera).

Reply to
Adam Dybkowski

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.