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

GCC - asm, składnia nop, wstawki asemblerowe: Jak zatrzymać usuwanie NOP-ów przez kompilator?

robiw 25 Kwi 2023 17:23 792 26
  • #1 20555036
    robiw
    Poziom 26  
    Witajcie,
    Nie wiem, jaką składnią w GCC "ogarnąć" wstawki asemblerowe NOP by nie były "wyrzucane" przez kompilator. Mam takie proste funkcje:

    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    Kompilator usuwa mi niepotrzebne, "według niego", NOP-y. Robiw
  • #2 20555189
    hindoos
    Poziom 34  
    Spróbuj wyłączyć optymalizację kompilatora przez flagę -O0
  • #3 20555234
    robiw
    Poziom 26  
    Wiadomo...ale to żadne rozwiązanie, jeśli cały projekt chcę kompilować z OS. Można, z tego co czytałem, kompilować poszczególne funkcje z różnymi poziomami optymalizacji, ale to też nie jest rozwiązanie. Chyba te kilka NOP-ów trzeba zadeklarować, jako blok...właśnie...nie wiem, jak to zrobić... R
  • #4 20555250
    hindoos
    Poziom 34  
    A może po prostu implementacja delaya przy pomocy NOPów nie jest właściwym podejściem? ;)
  • #5 20555294
    khoam
    Poziom 42  
    @robiw Nie możesz użyć _delay_us()?
  • #6 20555370
    robiw
    Poziom 26  
    Jak widzisz, trzeba opóźnić wyłącznie o 2 lub 5 taktów i to jest dość krytyczne. Funkcje opóźniające dodadzą za duży overhead. Robert

    Dodano po 1 [minuty]:

    hindoos napisał:
    A może po prostu implementacja delaya przy pomocy NOPów nie jest właściwym podejściem? ;)


    W tym przypadku jest. Z resztą funkcje opozniajace też używają NOP-ow. Robert
  • Pomocny post
    #7 20555410
    khoam
    Poziom 42  
    A próbowałeś użyć __builtin_avr_delay_cycles()?

    Dodano po 1 [godziny] 9 [minuty]:

    Alternatywnym sposobem może być wyłączenie optymalizacji dla fragmentu kodu:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    Dodano po 5 [minuty]:

    Albo zadeklarować całą funkcję z atrybutem optimize("O0"):
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod
  • #8 20555649
    robiw
    Poziom 26  
    Gdzieś w głowie mi "świtało" to "always inline" ale właśnie składni tego atrybutu nie znałem. Dzięki! A czy nie usuwa - bez tego właśnie usuwa... R
  • #9 20556489
    robiw
    Poziom 26  
    khoam napisał:
    A próbowałeś użyć __builtin_avr_delay_cycles()?

    Dodano po 1 [godziny] 9 [minuty]:

    Alternatywnym sposobem może być wyłączenie optymalizacji dla fragmentu kodu:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    Dodano po 5 [minuty]:


    Albo zadeklarować całą funkcję z atrybutem optimize("O0"):
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    Żadne z rozwiązań nie działa. Kompilator generuje bardzo długi kod z wieloma "ldi" i "rcall" bez NOP-ów. To nie ma prawa działać... R
  • #10 20556668
    excray
    Poziom 41  
    Spróbuj tak:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod
  • #11 20556771
    khoam
    Poziom 42  
    Z _NOP() też nie "działa".
    Sprawdziłem, że nie usuwa NOP tylko wtedy, kiedy obie funkcje ledSendBit() oraz ledSendByte() mają w deklaracji __attribute__((always_inline)):
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    Sprawdzałem dla optymalizacji -Os.
  • #12 20556777
    excray
    Poziom 41  
    Chyba powyżej 3 usuwa. Można ewentualnie zrobić na EOR:
    Kod: AVR assembler
    Zaloguj się, aby zobaczyć kod

    Tego już nie usuwa. A R1 i tak zawsze ma 0.
  • #13 20557006
    robiw
    Poziom 26  
    Obie funkcje są u mnie __attribute__((always_inline)) i niestety, ale usuwa. Nic na kompilator nie działa. W sumie to nie wiem, dlaczego on usuwa coś, co ma atrybut volatile. Wiadomo, że NOP nic nie robi i z punktu widzenia kompilatora można to usunąć, ale nie sądzę by nie można wymusić nieusuwania. Można to oczywiście rozwiązać poprzez odpowiednie zdublowanie makr SET_LED i RESET_LED, bo tego nie usunie, ale nie o to chodzi. Chciałbym wiedzieć, jak to zapisać by nie usuwał.... R

    Dodano po 57 [minuty]:

    Z ciekawym spostrzeżeniem w tym temacie spotkałem się na innym forum, a że jestem w tej chwili w pracy nie jestem w stanie tego zweryfikować. Otóż, ponoć, kompilator kompiluje to dobrze, co można zobaczyć w pliku HEX i w pliku disasemblacji patrząc na adresy rozkazów, tylko disasebmler pokazuje to w mało czytelny sposób. Poniżej zrzuty:

    GCC - asm, składnia nop, wstawki asemblerowe: Jak zatrzymać usuwanie NOP-ów przez kompilator? GCC - asm, składnia nop, wstawki asemblerowe: Jak zatrzymać usuwanie NOP-ów przez kompilator?

    Ciekawe - tak daleko nie zaglądałem. Pozdrowienia. R
  • #14 20557102
    JacekCz
    Poziom 42  
    hindoos napisał:
    A może po prostu implementacja delaya przy pomocy NOPów nie jest właściwym podejściem? ;)


    +1

    Pracowicie rozwiązujemy XY problem.
  • #15 20557107
    robiw
    Poziom 26  
    JacekCz napisał:
    Pracowicie rozwiązujemy XY problem.


    Ni i co? Nawet delaye z GCC to NOP-y a przy takich timingach (0.2us) jaki timer czy też układ peryferyjny transmisji szeregowej chcesz zaprzęgnąć do tego ? Bez podwyższania częstotliwości mikrokontrolera? To prosta transmisja, więc po co tu wymyślać "wodotryski". Bez przesady... Robert
  • #16 20557152
    JacekCz
    Poziom 42  
    robiw napisał:
    JacekCz napisał:
    Pracowicie rozwiązujemy XY problem.


    Ni i co? Nawet delaye z GCC to NOP-y a przy takich timingach (0.2us) jaki timer czy też układ peryferyjny transmisji szeregowej chcesz zaprzęgnąć do tego ? Bez podwyższania częstotliwości mikrokontrolera? To prosta transmisja, więc po co tu wymyślać "wodotryski". Bez przesady... Robert


    tak trudno inny rozkaz spróbować (jak @excray proponuje) ?
    Efektywnie bezskuteczny / nieszkodliwy, a nie kuszący optymalizatora ?

    Dodano po 15 [minuty]:

    ps. "dzięki" za zgłoszenie do moderacji.

    Pięknie to pasuje do postawy "XY problem"
  • #17 20557179
    khoam
    Poziom 42  
    excray napisał:
    Tego już nie usuwa. A R1 i tak zawsze ma 0.

    Sprawdzałeś? W symulacji na godbolt "cudownie" znikają te ""EOR R1,R1" przy optymalizacji -Os. Przy -O3 jest OK.
  • #18 20557185
    robiw
    Poziom 26  
    JacekCz napisał:
    tak trudno inny rozkaz spróbować (jak @excray proponuje) ?
    Efektywnie bezskuteczny / nieszkodliwy, a nie kuszący optymalizatora ?


    Oczywiście, że można. A nawet lepiej, i napisałem o tym, wystarczy zamiast tych NOP-ów powielić LED_SET i LED_RESET i już będziemy mieli odpowiednie timingi bez wpływu na port IO. Ale to jest "ominięcie" problemu a nie jego bezpośrednie rozwiązanie. Chciałbym wiedzieć, na przyszłość i dla innych, jak uniknąć usuwania NOP-ów.

    JacekCz napisał:
    ps. "dzięki" za zgłoszenie do moderacji.


    Nie moja sprawka... R

    Dodano po 2 [minuty]:

    khoam napisał:
    excray napisał:
    Tego już nie usuwa. A R1 i tak zawsze ma 0.

    Sprawdzałeś? W symulacji na godbolt "cudownie" znikają te ""EOR R1,R1" przy optymalizacji -Os. Przy -O3 jest OK.


    Czyż nie to rozwiązanie przed chwilą proponowałeś? ;-). R
  • #19 20557195
    excray
    Poziom 41  
    @khoam Sprawdzałem z Os ale tylko na GCC dołączone do Microchip Studio.
    Szczerze mówiąc jak już wspomniano najlepiej zrobić to na __builtin_avr_delay_cycles() i od razu widzimy ile cykli trwa opóźnienie, nie trzeba liczyć NOPów. A jeżeli o czas to już wspomniane _delay_us():
    SET;
    _delay_us(0.5);
    CLR;
    _delay_us(0.5);
    Przynajmniej jak zmienimy zegar to nie będziemy musieli przeliczać.
  • #20 20557197
    khoam
    Poziom 42  
    robiw napisał:
    Czyż nie to rozwiązanie przed chwilą proponowałeś?

    Kolega @excray zaproponował użycie EOR R1,R1 zamiast NOP.
  • #21 20557203
    robiw
    Poziom 26  
    JacekCz napisał:
    tak trudno inny rozkaz spróbować (jak @excray proponuje) ?


    excray napisał:
    Można ewentualnie zrobić na EOR:
    Kod: avrasm [rozwiń][zwiń] [zaznacz wszystko][Kopiuj do schowka] asm volatile(
    "EOR R1,R1 \n\t"
    "EOR R1,R1 \n\t"
    "EOR R1,R1 \n\t"
    "EOR R1,R1 \n\t"
    "EOR R1,R1 \n\t"
    "EOR R1,R1 \n\t"
    "EOR R1,R1 \n\t"
    "EOR R1,R1 \n\t"
    ::);
    Tego już nie usuwa. A R1 i tak zawsze ma 0.


    khoam napisał:
    Sprawdzałeś? W symulacji na godbolt "cudownie" znikają te ""EOR R1,R1" przy optymalizacji -Os.


    excray napisał:
    Szczerze mówiąc jak już wspomniano najlepiej zrobić to na __builtin_avr_delay_cycles() i od razu widzimy ile cykli trwa opóźnienie


    Wywołuje wtedy funkcję wbudowaną dodając overhead.

    excray napisał:
    SET;
    _delay_us(0.5);
    CLR;
    _delay_us(0.5);


    Overhead, jak wyżej... R
  • #22 20557215
    excray
    Poziom 41  
    robiw napisał:
    Overhead, jak wyżej... R

    U mnie (Os) wrzuca tylko NOPy i skoki +1, jako, że są 2-taktowe więc robią za 2 NOPy:
    GCC - asm, składnia nop, wstawki asemblerowe: Jak zatrzymać usuwanie NOP-ów przez kompilator?
    EDIT> Zegar mam 10MHz
  • #23 20557216
    robiw
    Poziom 26  
    POZA TYM...z zamieszczony screenów z pliku HEX wynika, że liczba NOP-ów jest ODPOWIEDNIA a zwyczajnie disassembler pokazuje je w taki a nie inny sposób. Sprawdzę to. R

    GCC - asm, składnia nop, wstawki asemblerowe: Jak zatrzymać usuwanie NOP-ów przez kompilator?
  • #24 20557218
    Wirnick
    Poziom 30  
    Ciekawe co Wy chcecie osiągnąć - bezczynność procesora, ale to jest niemożliwe. Dajcie mu możliwość policzenia baranów we stadzie i straci na to czas. Ecsklusiwe OR czy bezczynność NOP.
  • #25 20557224
    robiw
    Poziom 26  
    Panowie...
    Dzięki za odpowiedzi. Niestety ani ja ani Wy nie mieliśmy racji. Wszystko od początku było OK i nie trzeba było doszukiwać się "magii" kompilatora, ani sugerować, a tym bardziej ośmieszać, zamieszczone rozwiązania. Wystarczyło znać specyfikę narzędzi toolchain'a i zwrócić uwagę na drobiazgi (adresy rozkazów). O czym ja nie miałem pojęcia. I domyślam się, że Wy również (tyle, że mi to łatwiej przyznać ;-)). Poniżej dowód i rozwiązanie:

    Funkcje z atrybutem always_inline:

    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    Disasembler (tu tkwi "błąd" myślowy) i plik HEX:

    GCC - asm, składnia nop, wstawki asemblerowe: Jak zatrzymać usuwanie NOP-ów przez kompilator?

    Bardzo ciekawe i pouczające. Pozdrawiam. Robert
  • #26 20557674
    khoam
    Poziom 42  
    robiw napisał:
    Funkcje z atrybutem always_inline:

    W tym wypadku, to akurat sam się upierałeś, że są usuwane NOPy, a teraz wiemy dlaczego:
    robiw napisał:
    Disasembler (tu tkwi "błąd" myślowy) i plik HEX
  • #27 20557683
    robiw
    Poziom 26  
    khoam napisał:
    W tym wypadku, to akurat sam się upierałeś, że są usuwane NOPy, a teraz wiemy dlaczego:


    Toć mówiłem, że mi łatwiej przyznać się do niewiedzy ;-P. Sam proponowałeś inne rozwiązania i opinie na temat kodu i jego wyników kompilacji (mając dostęp do kodu) - nawet nie chce mi się cytować ;-P. R

Podsumowanie tematu

W dyskusji poruszono problem usuwania instrukcji NOP przez kompilator GCC w kontekście wstawek asemblerowych. Użytkownik próbował zrealizować opóźnienia w funkcjach ledSendBit i ledSendByte, jednak kompilator optymalizował kod, eliminując NOP-y. Proponowane rozwiązania obejmowały wyłączenie optymalizacji za pomocą flagi -O0, użycie atrybutu __attribute__((always_inline)), oraz alternatywne podejścia, takie jak wykorzystanie instrukcji EOR R1,R1. Ostatecznie, po analizie, okazało się, że NOP-y nie były usuwane, a ich obecność można było potwierdzić w plikach HEX i disasemblacji. Użytkownik podkreślił znaczenie zrozumienia specyfiki narzędzi toolchain oraz dokładności w analizie wyników kompilacji.
Podsumowanie wygenerowane przez model językowy.
REKLAMA