Neden bazı kodları atlayan GCC derleyicisi?


9

Neden mahallede kesinlikle aynı korurken kodumun bir kısmını kesip GCC derleyici anlayamıyorum?

C kodu:

#define setb_SYNCO do{(PORTA|= (1<<0));} while(0);

ISR(INT0_vect){
    unsigned char i;

    i = 10;
    while(i>0)i--;   // first pause - omitted

    setb_SYNCO;
    setb_GATE;
    i=30;
    clrb_SYNCO;
    while(i>0)i--;  // second pause - preserved
    clrb_GATE;
}

LSS'nin karşılık gelen kısmı (derleyici tarafından oluşturulan montajcı dosyası):

ISR(INT0_vect){
  a4:   1f 92           push    r1
  a6:   0f 92           push    r0
  a8:   0f b6           in  r0, 0x3f    ; 63
  aa:   0f 92           push    r0
  ac:   11 24           eor r1, r1
  ae:   8f 93           push    r24
    unsigned char i;

    i = 10;
    while(i>0)i--;

    setb_SYNCO;
  b0:   d8 9a           sbi 0x1b, 0 ; 27
    setb_GATE;
  b2:   d9 9a           sbi 0x1b, 1 ; 27
    i=30;
    clrb_SYNCO;
  b4:   d8 98           cbi 0x1b, 0 ; 27
  b6:   8e e1           ldi r24, 0x1E   ; 30
  b8:   81 50           subi    r24, 0x01   ; 1
    while(i>0)i--;
  ba:   f1 f7           brne    .-4         ; 0xb8 <__vector_1+0x14>
    clrb_GATE;
  bc:   d9 98           cbi 0x1b, 1 ; 27
}
  be:   8f 91           pop r24
  c0:   0f 90           pop r0
  c2:   0f be           out 0x3f, r0    ; 63
  c4:   0f 90           pop r0
  c6:   1f 90           pop r1
  c8:   18 95           reti

Derleyici böyle bir kod kukla ve keser anlamaya varsayabiliriz ama neden aynı kod sonunda korumak mı?

Bu optimizasyondan kaçınmak için derleyici talimatları var mı?


1
Derleyiciye tek bir işlevi optimize etmemesini de söyleyebilirsiniz, belki bu yöntemi ISR'nizle denemeye değer. Stackoverflow ile ilgili bu soruya bakın .
Vladimir Cravero

2
Hey Roman, atmega kaldırma sorunuza "c" etiketini ekledim. Bir sınır (beş) olduğu için bir etiketi kaldırmak zorunda kaldım ve bir kod olarak dil adını ekleyerek kodla ilgili bir soru sorduğumda, tüm kod (Q & As) vurgulanır.
Vladimir Cravero

5
Genel olarak konuşursak, daha yüksek seviyeli diller (C gibi) açıkça ortaya çıkan montajlarıyla 1: 1 bir ilişkiye bağlı olmayacak şekilde tasarlanmıştır . Zamanlamayı doğru yapmak için talimatları saymanız gerekiyorsa, her zaman toplamaya güvenmeniz gerekir (bazı cevapların yaptığı gibi). Üst düzey dillerin asıl amacı, derleyicinin kodunuzu eskisinden daha hızlı-daha güçlü-daha iyi hale getirme özgürlüğüne sahip olmasıdır. Kayıt tahsisleri ve şube tahminleri gibi detaylar derleyiciye çok daha iyi bırakılmıştır ... programcı, tam olarak istediğiniz talimatları tam olarak bildiğiniz zamanlar hariç.
Cort Ammon

5
Daha iyi soru şu ki, GCC neden bu döngülerin ikisini birden optimize etmiyor ?
Ilmari Karonen

5
Gcc önce döngüyü açar ve ancak karşılık gelen kodun işe yaramadığını fark eder. Döngü boyutu 30 olduğunda, açma aptalca olur ve gcc bunu yapmaz. Daha yüksek bir optimizasyon düzeyinde her ikisi de optimize edilir.
Marc Glisse

Yanıtlar:


9

Bir yorumda "her CPU işaretinin değerli olduğunu" belirttiğiniz için, gecikmeler döngünüzü istediğiniz gibi yapmak için bazı satır içi montaj kullanmanızı öneririz. Bu çözüm, çeşitli üstündür volatileya -O0da yapar çünkü net amacınız ne.

unsigned char i = 10;
__asm__ volatile ( "loop: subi    %0, 0x01\n\t"
                   "      brne    loop"
                   : "+rm" (i)
                   : /* no inputs */
                   : /* no dirty registers to decleare*/);

Hile yapmalı. Uçucu olan şey derleyiciye "Bunun hiçbir şey yapmadığını biliyorum, sadece sakla ve bana güven" olduğunu söylemek için var. Üç asm "ifadeleri" oldukça açıklayıcı, r24 yerine herhangi bir kayıt kullanabilirsiniz, derleyici düşük kayıtları seviyor inanıyorum böylece yüksek bir kullanmak isteyebilirsiniz. İlkinden sonra :çıkış (okuma ve yazma) c değişkenlerini listelemelisiniz ve hiçbiri yok, ikincisinden sonra :giriş (ronly) c değişkenlerini listelemelisiniz, yine yok ve üçüncü parametre değiştirilmiş kayıtların virgülle ayrılmış bir listesidir , bu durumda r24. ZEROTabii ki bayrak değiştiğinden durum kaydını da eklemeniz gerekip gerekmediğinden emin değilim, dahil etmedim.

düzenlemek edit answer as OP requested. Bazı notlar.

"+rm"Önce (i)sen derleyici izin olduğunu araçlarında i yerleştirmek için karar m Emory veya içinde r egister. Çoğu durumda bu iyi bir şeydir, çünkü derleyici ücretsizse daha iyi optimize edebilir. Sizin durumunuzda, i'yi bir kayıt olmaya zorlamak için yalnızca r kısıtlamasını korumak istediğinize inanıyorum.


Görünüşe göre bu gerçekten ihtiyacım olan bir şey. Ama cevabınızı orijinal cevapta bahsettiğim cdeğişmez değer yerine herhangi bir değişkeni kabul edecek şekilde değiştirebilir misiniz 10? Asm inşaatının doğru kullanımı ile ilgili GCC kılavuzlarını okumaya çalışıyorum, ancak şimdi benim için biraz gizlenmiş. Çok minnettar olurum!
Roman Matveev

1
@RomanMatveev istediğiniz gibi düzenledi
Vladimir Cravero

13

Döngüyü gerçekten bir şey yapmayı deneyebilirsiniz. Derleyici olduğu gibi derleyici haklı olarak "Bu döngü hiçbir şey yapmıyor - ondan kurtulacakım" diyor.

Böylece sık kullandığım bir yapıyı deneyebilirsiniz:

int i;
for (i = 0; i < 10; i++) {
    asm volatile ("nop");
}

Not: gcc derleyicisinin tüm hedefleri aynı satır içi montaj sözdizimini kullanmaz - hedefiniz için ince ayar yapmanız gerekebilir.


Çözümünüz benimkinden çok daha zarif görünüyor ... PRECISE döngü sayısı gerektiğinde benimki daha iyidir? Yani, her şey için belirli bir şekilde derleneceği garanti edilmez, değil mi?
Vladimir Cravero

8
C'yi kullandığı basit gerçek, döngüleri garanti edemeyeceğiniz anlamına gelir. Hassas döngü sayımına ihtiyacınız varsa, ASM tek yoludur. Yani, eğer -funroll-loop'ları yoksa, vb. Etkinleştirilmişse, C döngüsü ile farklı bir zamanlama elde edersiniz
Majenko

Evet ben de öyle düşünmüştüm. Yeterince yüksek i değerleri (100 veya daha fazla) ile HW gecikmeleri yaparken, çözümünüz okunabilirliği arttırırken neredeyse aynı sonuçları verir.
Vladimir Cravero

6

Evet bunu kabul edebilirsiniz. İ değişkenini geçici olarak bildirirseniz derleyiciye i'yi optimize etmemesini söylersiniz.


1
Bence bu tamamen doğru değil.
Vladimir Cravero

1
@VladimirCravero, bunu söyleyerek ne demek istiyorsun? Daha açık söyleyebilir misiniz?
Roman Matveev

2
Demek istediğim, bir derleyicinin ne yaptığından emin olamayacağım. Değişken bir değişkenin bildirilmesi derleyiciye başka bir yerde değişebileceğini söyler, bu yüzden bunu gerçekten yapmalıdır.
Vladimir Cravero

1
@Roman Matveev register unsigned char volatile i __asm__("r1");belki?
a3f

2
iUçucu olarak ilan etmek her şeyi çözer. Bu, C standardı 5.1.2.3 tarafından garanti edilmektedir. Uygun bir derleyici i, uçucu ise bu döngüleri optimize etmemelidir . Neyse ki, GCC uygun bir derleyicidir. Ne yazık ki standarda uymayan birçok C derleyicisi var, ancak bu özel soru için önemsiz. Sıralı montajcıya kesinlikle gerek yoktur.
Lundin

1

İlk döngüden sonra isabit olur. Başlatma ive döngü sabit bir değer üretmekten başka bir şey yapmaz. Standarttaki hiçbir şey bu döngünün olduğu gibi derlenmesi gerektiğini belirtmez. Standart da zamanlama hakkında bir şey söylemiyor. Derlenmiş kod döngü varmış gibi davranmalıdır ve öyle. Bu optimizasyonun standart altında yapıldığını güvenilir bir şekilde söyleyemezsiniz (zamanlama sayılmaz).

İkinci döngü de silinmelidir. Ben bir hata (ya da eksik bir optimizasyon) olmadığını düşünüyorum. Döngü isabit sıfır olduktan sonra . Kod isıfır olarak ayarlanarak değiştirilmelidir .

Bence GCC itamamen (opak) port erişimini etkileyebilmeniz için etrafta duruyor i.

kullanım

asm volatile ("nop");

GCC'yi, döngünün bir şey yaptığını düşünerek kandırmak için.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.