Forum: Compiler & IDEs Shift mit Carry


von Gustav (Gast)


Lesenswert?

Geht das "schöner" (kürzer/schneller)? Plattform avr-gcc ATmega.
1
static void shift_left(uint8_t data[]) {
2
  uint8_t i;
3
  for (i = 31; i > 0; i--) data[i] = (data[i] << 1) | (data[i-1] >> 7);
4
  data[0] <<= 1;
5
}

von (prx) A. K. (prx)


Lesenswert?

Nicht schöner, nicht kürzer, nicht optimal, nicht portabel, aber 
schneller:
1
static uint8_t rol32(uint8_t *p, uint8_t c) //inlined
2
{
3
    uint8_t r = p[3] & 0x80;
4
    *(uint32_t *)p <<= 1;
5
    if (c) p[0] |= 1;
6
    return r;
7
}
8
9
void g(uint8_t *data)
10
{
11
    uint8_t c = 0;
12
    for (uint8_t i = 0; i < 32; i += 4)
13
        c = rol32(data+i, c);
14
}

Deutlich länger, aber nochmal etwas schneller:
1
void g(uint8_t *data)
2
{
3
    uint8_t c;
4
    c = rol32(data+0, 0);
5
    c = rol32(data+4, c);
6
    c = rol32(data+8, c);
7
    c = rol32(data+12, c);
8
    c = rol32(data+16, c);
9
    c = rol32(data+20, c);
10
    c = rol32(data+24, c);
11
    c = rol32(data+28, c);
12
}

: Bearbeitet durch User
von Eric B. (beric)


Lesenswert?

Gustav schrieb:
> Geht das "schöner" (kürzer/schneller)? Plattform avr-gcc ATmega.
>
>
1
static void shift_left(uint8_t data[]) {
2
>   uint8_t i;
3
>   for (i = 31; i > 0; i--) data[i] = (data[i] << 1) | (data[i-1] >> 7);
4
>   data[0] <<= 1;
5
> }

Ich glaube da ist noch ein Bug drinne:
1
data[i] = (data[i] << 1) | (data[i-1] >> 7);
2
3
4
byte   : |data[i-1]              |data[i]                |
5
vorher : |a7 a6 a5 a4 a3 a2 a1 a0|b7 b6 b5 b4 b3 b2 b1 b0|
6
           `-------------------------/--/--/--/--/--/--/.
7
                                    /  /  /  /  /  /  / v
8
nachher: |a7 a6 a5 a4 a3 a2 a1 a0|b6 b5 b4 b3 b2 b1 b0 a7|
9
10
Und b7 ist weg!

: Bearbeitet durch User
von Gustav (Gast)


Lesenswert?

Dass der Wert, der ganz links steht, verschwindet, hat ein Leftshift so 
an sich. Das ist auch so erwünscht.

@A. K.

Danke, ich werde mal testen!

von Gustav (Gast)


Lesenswert?

Habe mal beides disassembliert. Sicher, dass deine Variante (unten) auch 
schneller ist??
1
    22ca:  dc 01         movw  r26, r24
2
    22cc:  90 96         adiw  r26, 0x20  ; 32
3
    22ce:  fc 01         movw  r30, r24
4
    22d0:  7f 96         adiw  r30, 0x1f  ; 31
5
    22d2:  2e 91         ld  r18, -X
6
    22d4:  22 0f         add  r18, r18
7
    22d6:  32 91         ld  r19, -Z
8
    22d8:  33 1f         adc  r19, r19
9
    22da:  33 27         eor  r19, r19
10
    22dc:  33 1f         adc  r19, r19
11
    22de:  23 2b         or  r18, r19
12
    22e0:  2c 93         st  X, r18
13
    22e2:  e8 17         cp  r30, r24
14
    22e4:  f9 07         cpc  r31, r25
15
    22e6:  a9 f7         brne  .-22       ; 0x22d2 <shift_left+0x8>
16
    22e8:  80 81         ld  r24, Z
17
    22ea:  88 0f         add  r24, r24
18
    22ec:  80 83         st  Z, r24
19
    22ee:  08 95         ret
20
21
    323e:  fc 01         movw  r30, r24
22
    3240:  9c 01         movw  r18, r24
23
    3242:  20 5e         subi  r18, 0xE0  ; 224
24
    3244:  3f 4f         sbci  r19, 0xFF  ; 255
25
    3246:  80 e0         ldi  r24, 0x00  ; 0
26
    3248:  93 81         ldd  r25, Z+3  ; 0x03
27
    324a:  90 78         andi  r25, 0x80  ; 128
28
    324c:  40 81         ld  r20, Z
29
    324e:  51 81         ldd  r21, Z+1  ; 0x01
30
    3250:  62 81         ldd  r22, Z+2  ; 0x02
31
    3252:  73 81         ldd  r23, Z+3  ; 0x03
32
    3254:  44 0f         add  r20, r20
33
    3256:  55 1f         adc  r21, r21
34
    3258:  66 1f         adc  r22, r22
35
    325a:  77 1f         adc  r23, r23
36
    325c:  40 83         st  Z, r20
37
    325e:  51 83         std  Z+1, r21  ; 0x01
38
    3260:  62 83         std  Z+2, r22  ; 0x02
39
    3262:  73 83         std  Z+3, r23  ; 0x03
40
    3264:  88 23         and  r24, r24
41
    3266:  19 f0         breq  .+6        ; 0x326e <shift_left.lto_priv.21+0x30>
42
    3268:  80 81         ld  r24, Z
43
    326a:  81 60         ori  r24, 0x01  ; 1
44
    326c:  80 83         st  Z, r24
45
    326e:  34 96         adiw  r30, 0x04  ; 4
46
    3270:  89 2f         mov  r24, r25
47
    3272:  e2 17         cp  r30, r18
48
    3274:  f3 07         cpc  r31, r19
49
    3276:  41 f7         brne  .-48       ; 0x3248 <shift_left.lto_priv.21+0xa>
50
    3278:  08 95         ret

von (prx) A. K. (prx)


Lesenswert?

Gustav schrieb:
> Sicher, dass deine Variante (unten) auch schneller ist??

Denke schon. Deine schleift 32x, meine 8x.

: Bearbeitet durch User
von Eric B. (beric)


Lesenswert?

Gustav schrieb:
> Dass der Wert, der ganz links steht, verschwindet, hat ein Leftshift so
> an sich. Das ist auch so erwünscht.

Ah, LSB versus MSB. Ich hatte wohl noch zuviel Blut im Kaffee und dachte 
du würdest hier alle b7-s verlieren...

von Gustav (Gast)


Lesenswert?

Stimmt, bei 32 Bit schleift es weniger. ;)

von Michael U. (amiga)


Lesenswert?

Hallo,

mit ähnlichem habe ich vor Jahren mal experimentiert und Jörg Wunsch hat 
mir damals bei der inline-ASM Geschichte geholfen.
War für eine DCF77-Uhr, die alle Impulse in ein 64Bit Register schiebt 
und das neue Bit anhängt.

Schiebt zwar nach rechts und hängt ganz links an, das zum links schieben 
umzubauen und auf 32 statt 64 Bit zu kürzen sollte aber ja kein Problem 
sein.
1
                  dcf77_bit_cnt++;         // Bitcount erhöhen
2
                  asm volatile             // shift long long right und höchstwertiges Bit bleibt 0
3
                    (
4
                      "lds __tmp_reg__, %0 + 7" "\n\t"
5
                      "lsr __tmp_reg__" "\n\t"
6
                      "sts %0 + 7, __tmp_reg__" "\n\t"
7
                      "lds __tmp_reg__, %0 + 6" "\n\t"
8
                      "ror __tmp_reg__" "\n\t"
9
                      "sts %0 + 6, __tmp_reg__" "\n\t"
10
                      "lds __tmp_reg__, %0 + 5" "\n\t"
11
                      "ror __tmp_reg__" "\n\t"
12
                      "sts %0 + 5, __tmp_reg__" "\n\t"
13
                      "lds __tmp_reg__, %0 + 4" "\n\t"
14
                      "ror __tmp_reg__" "\n\t"
15
                      "sts %0 + 4, __tmp_reg__" "\n\t"
16
                      "lds __tmp_reg__, %0 + 3" "\n\t"
17
                      "ror __tmp_reg__" "\n\t"
18
                      "sts %0 + 3, __tmp_reg__" "\n\t"
19
                      "lds __tmp_reg__, %0 + 2" "\n\t"
20
                      "ror __tmp_reg__" "\n\t"
21
                      "sts %0 + 2, __tmp_reg__" "\n\t"
22
                      "lds __tmp_reg__, %0 + 1" "\n\t"
23
                      "ror __tmp_reg__" "\n\t"
24
                      "sts %0 + 1, __tmp_reg__" "\n\t"
25
                      "lds __tmp_reg__, %0" "\n\t"
26
                      "ror __tmp_reg__" "\n\t"
27
                      "sts %0, __tmp_reg__"
28
                    : "+m" (dcf77_daten)
29
                    );
30
                  if (dcf77_time_cnt < 87) // Bit war 1 
31
                    {
32
                      asm volatile        // höchstwertiges Bit des long long auf 1 setzen
33
                        (
34
                          "lds __tmp_reg__, %0 + 7" "\n\t"
35
                          "set" "\n\t"                      // T setzen
36
                          "bld __tmp_reg__, 7" "\n\t"       // und in Bit 7 kopieren
37
                          "sts %0 + 7, __tmp_reg__" "\n\t"
38
                        : "+m" (dcf77_daten)
39
                        );
40
                    }

Ist jetzt nur schnell rauskopiert...

Gruß aus Berlin
Michael

von (prx) A. K. (prx)


Lesenswert?

Michael U. schrieb:
> und auf 32 statt 64 Bit zu kürzen

Da wär eher angesagt, es auf 32 Bytes = 256 Bits zu verlängern.

von Michael U. (amiga)


Lesenswert?

Hallo,

sorry, DAS hatte ich glatt übersehen...

Gruß aus Berlin
Michael

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.