Forum: Compiler & IDEs Wie Umwandlung von Integer -> 2xByte beschleunigen?


von Oli (Gast)


Lesenswert?

Hallo,
ich wäre über eine kleine Hilfe froh (Atmel Studio / GCC).

Ich habe eine unsigned Integer Variable und möchte auf die beiden 
enthaltenen Bytes (MSB / LSB) separat zugreifen.

Das geht natürlich so:

Byte1 = (Integervariable >> 8) & 0xff;
Byte2 = Integervariable & 0xff;

Aber das dauert doch relativ lange, vor allem, da ich das in einer 
Schleife häufig machen muss.

Gibt es keine Möglichkeit das vorher irgendwie zu definieren, so dass 
ich keinen Zeitverlust beim Zugriff habe?

Also z.B. dass "Integervariable" und "Byte1" und "Byte2" den gleichen 
Adressraum belegen und ohne Rotation und Und-Verknüpfung abgegriffen 
werden können?

Soll heißen, wenn ich 1111000000111 in "Integervariable" schreibe, 
stehen in
Byte1: 11110000 und in
Byte2: 00001111.

Wenn nein, hat jemand noch eine Idee zur Beschleunigung?

Danke !!!

Oli

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Oli schrieb:
> Aber das dauert doch relativ lange

Vermutet oder tatsächlich (also im Assemblercode geprüft)?

Neuesten Compiler benutzt (naja, wenigstens 4.7.2)?

von Uwe (Gast)


Lesenswert?

Mach ne Union. Dabei wird nicht gerechnet bzw. geschoben, sondern die
Variablen in den gleichen Speicherbereich gelegt.

    union conv{
      unsigned char c[2];
      int i;
    } r;

conv a;

a.i=7855;

danach kannst du auf a.c[0] und a.c[1] jeweils auf low und high byte 
zugreifen. Oder andersherum a.c[1] verändern und auf a.i zugreifen.

von Peter II (Gast)


Lesenswert?

Uwe schrieb:
> Mach ne Union. Dabei wird nicht gerechnet bzw. geschoben, sondern die
> Variablen in den gleichen Speicherbereich gelegt.
>
>     union conv{
>       unsigned char c[2];
>       int i;
>     } r;
>
> conv a;
>
> a.i=7855;
>
> danach kannst du auf a.c[0] und a.c[1] jeweils auf low und high byte
> zugreifen. Oder andersherum a.c[1] verändern und auf a.i zugreifen.

und es kommt je architektur der cpu was anders raus und es nicht mal 
definiert was raus kommt.

von Uwe (Gast)


Lesenswert?

> und es kommt je architektur der cpu was anders raus und es nicht mal
> definiert was raus kommt.
Jo aber dafür schnell. Was anderes war ja nicht gefordert bzw. die 
kompatible Lösung stand ja schon da.

von Peter (Gast)


Lesenswert?

>Das geht natürlich so:
>Byte1 = (Integervariable >> 8) & 0xff;
>Byte2 = Integervariable & 0xff;

Mit einem halbwegs vernünftigem Compiler und eingeschalteter Optimierung 
ist die obige Variante eben so schnell aber zudem auch noch portierbar, 
unabhängig von der verwendeten CPU!

von Uwe (Gast)


Lesenswert?

> unabhängig von der verwendeten CPU!
Nö, nicht ohne Barrel-Shifter oder Harware Multipliziereinheit

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Uwe schrieb:
> Mach ne Union. Dabei wird nicht gerechnet bzw. geschoben

Keiner sagt, dass bei >> zwingend was gerechnet oder geschoben werden
muss.  Daher habe ich ja auch als erstes gefragt, ob er's denn auch
tatsächlich probiert hat.

Wenn du bspw. sowas hast:
1
#include <stdint.h>
2
3
extern void dosomething(uint8_t h, uint8_t l);
4
5
void
6
doit(uint16_t i)
7
{
8
        dosomething(i >> 8, i);
9
}

dann wird da auch nichts geschoben oder gerechnet:
1
.global doit
2
        .type   doit, @function
3
doit:
4
/* prologue: function */
5
/* frame size = 0 */
6
/* stack size = 0 */
7
.L__stack_usage = 0
8
        mov r22,r24
9
        mov r24,r25
10
        jmp dosomething

von Peter II (Gast)


Lesenswert?

Uwe schrieb:
>> unabhängig von der verwendeten CPU!
> Nö, nicht ohne Barrel-Shifter oder Harware Multipliziereinheit

wozu sollte man hier einen hardware shifter oder einen Multiplizier 
brauchen?

von Jw (Gast)


Lesenswert?

Ok, shiften statt Bytezugriff.
Aber was macht der HW Multiplizierer?
Dividiert der durch 256, wenn man ihn andersrum an die 
Versorgungspannung anschließt?

von Uwe (Gast)


Lesenswert?

>        mov r22,r24
>        mov r24,r25
>        jmp dosomething
Ich dachte unabhängig von der verwendeten CPU

> Dividiert der durch 256
Je nachdem in welche Richtung gewandelt werden soll (char zu integer 
high byte) bzw. Big- oder Little-endian.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Uwe schrieb:
>>        mov r22,r24
>>        mov r24,r25
>>        jmp dosomething
> Ich dachte unabhängig von der verwendeten CPU

Oli schrieb:
> ich wäre über eine kleine Hilfe froh (Atmel Studio / GCC).

von Der (Gast)


Lesenswert?

Du kannst auch einen einen Byte Pointer verwenden...

Little / Big endian Problematik bleibt erhalten.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Der schrieb:
> Du kannst auch einen einen Byte Pointer verwenden...

Der wäre effektiver als der Schiebeoperator, meinst du?

Hast du dir obigen compilierten Assemblercode mal angesehen?  Ich
frage mich ernsthaft, warum hier noch jemand 1023 andere Varianten
haben möchte, wenn die generische offensichtlich (zumindest mit
einem aktuellen Compiler und natürlich mit eingeschalteter
Optimierung) prima funktioniert.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Uwe schrieb:
>>        mov r22,r24
>>        mov r24,r25
>>        jmp dosomething
> Ich dachte unabhängig von der verwendeten CPU

ARM, -mthumb -mcpu=cortex-m3:
1
        .type   doit, %function
2
doit:
3
        @ args = 0, pretend = 0, frame = 0
4
        @ frame_needed = 0, uses_anonymous_args = 0
5
        @ link register save eliminated.
6
        mov     r1, r0
7
        uxtb    r1, r1
8
        lsrs    r0, r0, #8
9
        b       dosomething

Dort bleibt ihm natürlich nichts anderes übrig, als auch 8 bits zu
schieben, aber das wäre auch mit einer Union nicht anders.  Dafür
wiederum geht die Schiebeoperation auf dem Cortex-M3 schnell.

von Simon K. (simon) Benutzerseite


Lesenswert?

Und (mal wieder) das gleiche Resultat wie in allen vorherigen, ähnlichen 
Threads: Die (sowohl von der Ausführungszeit als auch Portabilität) 
beste Variante ist die allererste im Ursprungspost gegebene.

Da gibts praktisch keine Diskussion drüber.

von Oli (Gast)


Lesenswert?

Danke für Euer Feedback.
Ich wusste nicht, dass der GCC Compiler das optimiert. Ich probiere das 
mal im Vergleich zu der union-Variante aus.

Führt er diese erwähnte Optimierung in allen Optimierungsstufen durch, 
oder erst in höheren?

Danke
oli

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Oli schrieb:

> Ich wusste nicht, dass der GCC Compiler das optimiert. Ich probiere das
> mal im Vergleich zu der union-Variante aus.

Was sollte sich denn bei der Union noch ändern?

Btw., ich hab's für dem ARM-GCC auch mit einer Union probiert.
Außer, dass man sich dann die besagten Byteorder-Probleme einhandelt
(stehen die höheren 8 Bit nun in b[1] oder in b[0]?), ergab sich kein
Unterschied im generierten Code.

Wichtig: nimm den GCC 4.7.2.  Falls du die Atmel-Toolchain benutzt,
dann musst du die allerletzte Version nehmen, alle davor hatten einen
recht alten (und teilweise buggigen) Compiler dabei.

> Führt er diese erwähnte Optimierung in allen Optimierungsstufen durch,
> oder erst in höheren?

Naja, mit -O0 natürlich nicht. ;-)  Aber ab -O1 schon.  Für den AVR-GCC
ist in der Praxis -Os erfahrungsgemäß die Optimierungsstufe, mit der
man erstmal ins Rennen gehen sollte.

von Oli (Gast)


Lesenswert?

Danke Jörg,

eine Frage noch: Ich arbeite ja mit Studio 6.0, bis jetzt SP1 - da ist 
die GCC 4.6.2 drin.
Auch in SP2 ist noch nicht der GCC 4.7.2 drin, sondern erst in der neuen 
Atmel Studio 6.1 beta.

Eine Beta will ich mir nun aber nicht gerade installieren, kann ich auch 
nur den GCC ohne Klimmzüge updaten? Wenn ja, wie?

Nochmals Danke
Oli

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Oli schrieb:
> Eine Beta will ich mir nun aber nicht gerade installieren, kann ich auch
> nur den GCC ohne Klimmzüge updaten? Wenn ja, wie?

Keine Ahnung, das fragst du ggf. besser im Forum PC-Hard- und
-Software, denn es ist ja ein reines Problem von Atmel Studio.

Sofern du die Toolchain auch separat bekommen kannst, sollte das
schon gehen, dass du sie auch der älteren Version „unterschiebst“.

Ansonsten kannst du dich ja auch mal im entsprechenden Forum auf
avrfreaks.net umsehen, ob denn die 6.1er Beta-Version überhaupt
nennenswert Späne macht, oder ob sie nicht vielleicht ohnehin eine
Verbesserung gegenüber der alten Version ist, trotz Beta.

von Peter II (Gast)


Lesenswert?

Jörg Wunsch schrieb:
> Sofern du die Toolchain auch separat bekommen kannst, sollte das
> schon gehen, dass du sie auch der älteren Version „unterschiebst“.

einfach bei Atmel downloaden.

von Fabian O. (xfr)


Lesenswert?

Jörg Wunsch schrieb:
> Ansonsten kannst du dich ja auch mal im entsprechenden Forum auf
> avrfreaks.net umsehen, ob denn die 6.1er Beta-Version überhaupt
> nennenswert Späne macht, oder ob sie nicht vielleicht ohnehin eine
> Verbesserung gegenüber der alten Version ist, trotz Beta.

Die Beta 6.1 verhaut bei mir regelmäßig die Codeformatierung beim 
Kopieren von Code und klappt manchmal willkürlich sämtliche Dependencies 
auf. Würde ich erstmal nicht installieren, lieber nur die Toolchain.

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.