Forum: Compiler & IDEs Nach entfernen von Redundanz größer?


von Manuel K. (draradech)


Lesenswert?

Hallo,

ich habe versucht, folgenden Codeschnipsel zu vereinfachen.

Obwohl in Variante 2 die zweite while-minDigits Schleife eingespart 
wurde, ist der erzeugte Code 12 Byte größer.

OK, ist nicht viel, aber ich möchte gerne wissen, was hier geschieht.

Ich bin kein Assembler-Experte, aber die zweite Variante sieht beim 
auswerten der Ziffernanzahl (digits = ...) deutlich suboptimal aus.
Und was sollen die beiden pop r0 gegen Ende? Ich sehe kein dazugehöriges 
push...

edit: Compilerversion ist "avr-gcc (AVR_Toolchain_3.0_149) 4.4.3"

Vorher:
1
void lcdNumberPad(uint16_t num, uint8_t minDigits, char pad)
2
{
3
   uint8_t digits;
4
   
5
   if(num)
6
   {
7
      digits = ((num >= 10000) ? 5 : ((num >= 1000) ? 4 : ((num >= 100) ? 3 : ((num >= 10) ? 2 : 1))));
8
      while(minDigits-- > digits)
9
      {
10
         lcdData(pad);
11
      }
12
      lcdDigits(num);
13
   }
14
   else
15
   {
16
      while(minDigits-- > 1)
17
      {
18
         lcdData(pad);
19
      }
20
      lcdData('0');
21
   }  
22
}

Nachher:
1
void lcdNumberPad(uint16_t num, uint8_t minDigits, char pad)
2
{
3
   uint8_t digits;
4
   
5
   digits = ((num >= 10000) ? 5 : ((num >= 1000) ? 4 : ((num >= 100) ? 3 : ((num >= 10) ? 2 : 1))));
6
   while(minDigits-- > digits)
7
   {
8
      lcdData(pad);
9
   }
10
11
   if(num)
12
   {
13
      lcdDigits(num);
14
   }
15
   else
16
   {
17
      lcdData('0');
18
   }  
19
}

Vorher:
1
0000009c <lcdNumberPad>:
2
  9c:  ff 92         push  r15
3
  9e:  0f 93         push  r16
4
  a0:  1f 93         push  r17
5
  a2:  cf 93         push  r28
6
  a4:  df 93         push  r29
7
  a6:  ec 01         movw  r28, r24
8
  a8:  16 2f         mov  r17, r22
9
  aa:  f4 2e         mov  r15, r20
10
  ac:  00 97         sbiw  r24, 0x00  ; 0
11
  ae:  31 f1         breq  .+76       ; 0xfc <lcdNumberPad+0x60>
12
  b0:  87 e2         ldi  r24, 0x27  ; 39
13
  b2:  c0 31         cpi  r28, 0x10  ; 16
14
  b4:  d8 07         cpc  r29, r24
15
  b6:  10 f0         brcs  .+4        ; 0xbc <lcdNumberPad+0x20>
16
  b8:  05 e0         ldi  r16, 0x05  ; 5
17
  ba:  16 c0         rjmp  .+44       ; 0xe8 <lcdNumberPad+0x4c>
18
  bc:  83 e0         ldi  r24, 0x03  ; 3
19
  be:  c8 3e         cpi  r28, 0xE8  ; 232
20
  c0:  d8 07         cpc  r29, r24
21
  c2:  10 f0         brcs  .+4        ; 0xc8 <lcdNumberPad+0x2c>
22
  c4:  04 e0         ldi  r16, 0x04  ; 4
23
  c6:  10 c0         rjmp  .+32       ; 0xe8 <lcdNumberPad+0x4c>
24
  c8:  c4 36         cpi  r28, 0x64  ; 100
25
  ca:  d1 05         cpc  r29, r1
26
  cc:  10 f0         brcs  .+4        ; 0xd2 <lcdNumberPad+0x36>
27
  ce:  03 e0         ldi  r16, 0x03  ; 3
28
  d0:  0b c0         rjmp  .+22       ; 0xe8 <lcdNumberPad+0x4c>
29
  d2:  ca 30         cpi  r28, 0x0A  ; 10
30
  d4:  d1 05         cpc  r29, r1
31
  d6:  10 f4         brcc  .+4        ; 0xdc <lcdNumberPad+0x40>
32
  d8:  01 e0         ldi  r16, 0x01  ; 1
33
  da:  06 c0         rjmp  .+12       ; 0xe8 <lcdNumberPad+0x4c>
34
  dc:  02 e0         ldi  r16, 0x02  ; 2
35
  de:  04 c0         rjmp  .+8        ; 0xe8 <lcdNumberPad+0x4c>
36
  e0:  8f 2d         mov  r24, r15
37
  e2:  0e 94 48 00   call  0x90  ; 0x90 <lcdData>
38
  e6:  11 50         subi  r17, 0x01  ; 1
39
  e8:  01 17         cp  r16, r17
40
  ea:  d0 f3         brcs  .-12       ; 0xe0 <lcdNumberPad+0x44>
41
  ec:  ce 01         movw  r24, r28
42
  ee:  0e 94 4b 00   call  0x96  ; 0x96 <lcdDigits>
43
  f2:  09 c0         rjmp  .+18       ; 0x106 <lcdNumberPad+0x6a>
44
  f4:  8f 2d         mov  r24, r15
45
  f6:  0e 94 48 00   call  0x90  ; 0x90 <lcdData>
46
  fa:  11 50         subi  r17, 0x01  ; 1
47
  fc:  12 30         cpi  r17, 0x02  ; 2
48
  fe:  d0 f7         brcc  .-12       ; 0xf4 <lcdNumberPad+0x58>
49
 100:  80 e3         ldi  r24, 0x30  ; 48
50
 102:  0e 94 48 00   call  0x90  ; 0x90 <lcdData>
51
 106:  df 91         pop  r29
52
 108:  cf 91         pop  r28
53
 10a:  1f 91         pop  r17
54
 10c:  0f 91         pop  r16
55
 10e:  ff 90         pop  r15
56
 110:  08 95         ret

Nachher:
1
0000009c <lcdNumberPad>:
2
  9c:  ef 92         push  r14
3
  9e:  ff 92         push  r15
4
  a0:  1f 93         push  r17
5
  a2:  df 93         push  r29
6
  a4:  cf 93         push  r28
7
  a6:  00 d0         rcall  .+0        ; 0xa8 <lcdNumberPad+0xc>
8
  a8:  cd b7         in  r28, 0x3d  ; 61
9
  aa:  de b7         in  r29, 0x3e  ; 62
10
  ac:  7c 01         movw  r14, r24
11
  ae:  80 e1         ldi  r24, 0x10  ; 16
12
  b0:  e8 16         cp  r14, r24
13
  b2:  87 e2         ldi  r24, 0x27  ; 39
14
  b4:  f8 06         cpc  r15, r24
15
  b6:  10 f0         brcs  .+4        ; 0xbc <lcdNumberPad+0x20>
16
  b8:  15 e0         ldi  r17, 0x05  ; 5
17
  ba:  1d c0         rjmp  .+58       ; 0xf6 <lcdNumberPad+0x5a>
18
  bc:  e8 ee         ldi  r30, 0xE8  ; 232
19
  be:  ee 16         cp  r14, r30
20
  c0:  e3 e0         ldi  r30, 0x03  ; 3
21
  c2:  fe 06         cpc  r15, r30
22
  c4:  10 f0         brcs  .+4        ; 0xca <lcdNumberPad+0x2e>
23
  c6:  14 e0         ldi  r17, 0x04  ; 4
24
  c8:  16 c0         rjmp  .+44       ; 0xf6 <lcdNumberPad+0x5a>
25
  ca:  f4 e6         ldi  r31, 0x64  ; 100
26
  cc:  ef 16         cp  r14, r31
27
  ce:  f1 04         cpc  r15, r1
28
  d0:  10 f0         brcs  .+4        ; 0xd6 <lcdNumberPad+0x3a>
29
  d2:  13 e0         ldi  r17, 0x03  ; 3
30
  d4:  10 c0         rjmp  .+32       ; 0xf6 <lcdNumberPad+0x5a>
31
  d6:  8a e0         ldi  r24, 0x0A  ; 10
32
  d8:  e8 16         cp  r14, r24
33
  da:  f1 04         cpc  r15, r1
34
  dc:  10 f4         brcc  .+4        ; 0xe2 <lcdNumberPad+0x46>
35
  de:  11 e0         ldi  r17, 0x01  ; 1
36
  e0:  0a c0         rjmp  .+20       ; 0xf6 <lcdNumberPad+0x5a>
37
  e2:  12 e0         ldi  r17, 0x02  ; 2
38
  e4:  08 c0         rjmp  .+16       ; 0xf6 <lcdNumberPad+0x5a>
39
  e6:  84 2f         mov  r24, r20
40
  e8:  4a 83         std  Y+2, r20  ; 0x02
41
  ea:  69 83         std  Y+1, r22  ; 0x01
42
  ec:  0e 94 48 00   call  0x90  ; 0x90 <lcdData>
43
  f0:  69 81         ldd  r22, Y+1  ; 0x01
44
  f2:  61 50         subi  r22, 0x01  ; 1
45
  f4:  4a 81         ldd  r20, Y+2  ; 0x02
46
  f6:  16 17         cp  r17, r22
47
  f8:  b0 f3         brcs  .-20       ; 0xe6 <lcdNumberPad+0x4a>
48
  fa:  e1 14         cp  r14, r1
49
  fc:  f1 04         cpc  r15, r1
50
  fe:  21 f0         breq  .+8        ; 0x108 <lcdNumberPad+0x6c>
51
 100:  c7 01         movw  r24, r14
52
 102:  0e 94 4b 00   call  0x96  ; 0x96 <lcdDigits>
53
 106:  03 c0         rjmp  .+6        ; 0x10e <lcdNumberPad+0x72>
54
 108:  80 e3         ldi  r24, 0x30  ; 48
55
 10a:  0e 94 48 00   call  0x90  ; 0x90 <lcdData>
56
 10e:  0f 90         pop  r0
57
 110:  0f 90         pop  r0
58
 112:  cf 91         pop  r28
59
 114:  df 91         pop  r29
60
 116:  1f 91         pop  r17
61
 118:  ff 90         pop  r15
62
 11a:  ef 90         pop  r14
63
 11c:  08 95         ret

von reversengineer (Gast)


Lesenswert?

> Ich bin kein Assembler-Experte, aber die zweite Variante sieht beim
> auswerten der Ziffernanzahl (digits = ...) deutlich suboptimal aus.

Sieht für mich praktisch identisch aus.

> Und was sollen die beiden pop r0 gegen Ende? Ich sehe kein dazugehöriges
> push...

Aber ein rcall bei 0xa6. Der Zweck erschliesst sich mir gerade nicht.

Wozu eigentlich das Post-increment an "minDigits"?

In welchem Fall ist "num" false?

von klaus (Gast)


Lesenswert?

Die "optimierte" Variante ist langsamer, da sie "digits" immer 
berechnet.

Schreib mal was deine Funktion tun soll, dann wird man dir eine 
optimierte Variante sagen können.

von Manuel K. (draradech)


Lesenswert?

reversengineer schrieb:
> Sieht für mich praktisch identisch aus.

Die erste Variante nutzt cpi und spart sich damit pro Vergleich ein ldi. 
Warum die zweite nicht?

> Aber ein rcall bei 0xa6. Der Zweck erschliesst sich mir gerade nicht.

Ahh. Was auch immer das soll...

> Wozu eigentlich das Post-increment an "minDigits"?

post-decrement? Um die Anzahl der padding Zeichen herunterzuzählen, die 
noch ausgegeben werden müssen.

> In welchem Fall ist "num" false?

Wenn der User 0 ausgeben möchte? Ich geb ja zu, wenn ich nicht dazusage, 
was das ganze tun soll, ist das nicht gleich offensichtlich. (Siehe 
nächster Beitrag)

von Manuel K. (draradech)


Lesenswert?

klaus schrieb:
> Die "optimierte" Variante ist langsamer, da sie "digits" immer
> berechnet.
>
> Schreib mal was deine Funktion tun soll, dann wird man dir eine
> optimierte Variante sagen können.

Von Laufzeit hab ich auch nicht geredet, sondern von Codegröße.

Die Funktion soll einfach nur eine Zahl (num) ausgeben, rechtsbündig auf 
(minDigit)s Zeichen, aufgefüllt mit einem padding Zeichen (pad).

lcdDigits gibt mir eine Zahl linksbündig aus (und kann keine 0 
ausgeben).

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Der Unterschied ist, daß die zweite Variante einen Frame-Pointer 
benötige -- warum auch immer. Irgendwie gehen dem Compiler die Register 
aus, und er legt (mindestend) eine Variable im Frame an bzw. speichert 
sie dort zwischen. Das kostet natürlich Platz und Zeit.

Die POP R0 korrespondieren mit dem RCALL .+0, welches 2 Bytes im Frame 
schafft beziehungsweise ein SP -= 2 implementiert. Das ist billiger, als 
SP zu leden, zu vermindern, und wieder zurückschreiben.

Die benötigte FRame-Größe sieht man am besten in der Assembler-Ausgebe 
des Compilers nicht es Assemblers oder von objdump.

avr-gcc verwendet "ungünstige" Register der Registerklasse "l", warum 
auch immer. avr-gcc-4.5.0 und WinAVR-20100110 (4.3.3) brauchen beide 5 
Bytes Stack und keinen Frame, zudem nutzen sie R16, anstatt wie oben 
R14.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.