Warum waren bitweise Operationen auf älteren Mikroprozessoren etwas schneller als Additions-/Subtraktionsoperationen?

Lesezeit: 7 Minuten

Benutzer-Avatar
Wilhelm Grau

Ich bin heute auf diesen Auszug gestoßen:

Bei den meisten älteren Mikroprozessoren sind bitweise Operationen etwas schneller als Additions- und Subtraktionsoperationen und normalerweise erheblich schneller als Multiplikations- und Divisionsoperationen. Auf modernen Architekturen ist dies nicht der Fall: Bitweise Operationen sind im Allgemeinen genauso schnell wie Additionen (obwohl immer noch schneller als Multiplikationen).

Ich bin neugierig, warum bitweise Operationen auf älteren Mikroprozessoren etwas schneller waren als Additions-/Subtraktionsoperationen.

Alles, was ich mir vorstellen kann, was die Latenz verursachen würde, ist, dass die Schaltungen zur Implementierung von Addition / Subtraktion von mehreren Ebenen von Logikgattern (parallelen Addierern und so weiter) abhängen, während die bitweisen Operationen weitaus einfachere Schaltungsimplementierungen haben. Ist das der Grund?

Ich weiß, dass arithmetische und bitweise Operationen auf modernen Prozessoren innerhalb eines Taktzyklus ausgeführt werden, aber wenn ich nur über die Laufzeit für die Schaltung spreche, ist die Latenz in modernen Prozessoren theoretisch noch vorhanden?

Abschließend hatte ich eine konzeptionelle C-Frage zur Ausführung der bitweisen Verschiebungsoperation:

unsigned x = 1;
x <<= 5;

unsigned y = 0;
y += 32;

Beide x und y sollte den Wert halten 32aber hat es gedauert 5 getrennte Linksverschiebungen zu bekommen x auf diesen Wert (wie in werden bitweise Verschiebungen über Pipes implementiert)? Zur Verdeutlichung frage ich nur nach dem Schaltungsverhalten, nicht nach der Anzahl der Taktzyklen.

  • Ihr erstes Beispiel gibt Null, aber das war wahrscheinlich ein Tippfehler. Der Rest Ihrer Frage ist hardwarespezifisch und hier möglicherweise nicht zum Thema.

    – 500 – Interner Serverfehler

    27. März 2013 um 20:30 Uhr

  • @ 500 Ich denke, es ist relevant, die Funktionsweise eines Prozessors zu kennen, damit Sie besser verstehen können, wie Code auf hoher Ebene ausgeführt wird.

    – kjpreis

    27. März 2013 um 20:31 Uhr


  • @kjprice: Fair genug – Sie werden feststellen, dass ich nicht für das Schließen gestimmt habe.

    – 500 – Interner Serverfehler

    27. März 2013 um 20:34 Uhr

  • @500-InternalServerError Danke für den Hinweis, ich habe den Code so angepasst, dass er korrekt ist. 🙂

    – Wilhelm Grau

    27. März 2013 um 20:38 Uhr

  • Die bitweisen Operationen, die auf alten CPUs möglicherweise schneller sind, werden AND / OR / XOR sein, nicht Verschiebungen um mehr als 1. Ein Barrel-Shifter, der 1-Zyklus-Verschiebungen für eine beliebige Anzahl von Verschiebungen durchführen kann, ist teurer als ein Carry-Lookahead Addierer. (z. B. bei Pentium4: langsame Verschiebungen, aber add so schnell wie xor. agner.org/optimieren/.) Shift-by-1 wäre jedoch ein vernünftiges Beispiel; Viele einfache CPUs unterstützen nur Verschiebungen um 1 oder benötigen 1 Zyklus pro Zählung.

    – Peter Cordes

    1. Mai 2018 um 11:52 Uhr


Benutzer-Avatar
Eric Postpischil

Bei jeder binären bitweisen Operation hängt jedes Ausgangsbit nur von den beiden entsprechenden Bits in den Eingängen ab. Bei einer Additionsoperation hängt jedes Ausgangsbit von den entsprechenden Bits in den Eingängen und allen Bits rechts davon (in Richtung niedrigerer Werte) ab.

Beispielsweise ist das Bit ganz links von 01111111 + 00000001 1, aber das Bit ganz links von 01111110 + 00000001 ist 0.

In seiner einfachsten Form addiert ein Addierer die beiden niedrigen Bits und erzeugt ein Ausgangsbit und einen Übertrag. Dann werden die nächsten beiden niedrigsten Bits hinzugefügt, und der Übertrag wird hinzugefügt, wodurch ein weiteres Ausgangsbit und ein weiterer Übertrag erzeugt werden. Dies wiederholt sich. Das höchste Ausgangsbit befindet sich also am Ende einer Additionskette. Wenn Sie die Operation Stück für Stück durchführen, wie es ältere Prozessoren taten, dauert es einige Zeit, bis Sie zum Ende kommen.

Es gibt Möglichkeiten, dies etwas zu beschleunigen, indem mehrere Eingangsbits in kompliziertere Logikanordnungen eingespeist werden. Aber das erfordert natürlich mehr Fläche im Chip und mehr Leistung.

Heutige Prozessoren haben viele verschiedene Einheiten, um verschiedene Arten von Arbeit auszuführen – Laden, Speichern, Addieren, Multiplizieren, Gleitkommaoperationen und mehr. Angesichts der heutigen Möglichkeiten ist die Arbeit zum Ausführen einer Hinzufügung im Vergleich zu anderen Aufgaben gering, sodass sie in einen einzigen Prozessorzyklus passt.

Vielleicht könnten Sie theoretisch einen Prozessor bauen, der eine bitweise Operation schneller durchführt als eine Addition. (Und es gibt, zumindest auf dem Papier, exotische Prozessoren, die asynchron arbeiten, wobei verschiedene Einheiten ihre Arbeit in ihrem eigenen Tempo erledigen.) Bei den verwendeten Designs benötigen Sie jedoch einen regelmäßigen festen Zyklus, um viele Dinge im Prozessor zu koordinieren – das Laden Anweisungen, Senden an Ausführungseinheiten, Senden von Ergebnissen von Ausführungseinheiten an Register und vieles mehr. Einige Ausführungseinheiten benötigen mehrere Zyklen, um ihre Aufgaben abzuschließen (z. B. benötigen einige Gleitkommaeinheiten etwa vier Zyklen, um eine Gleitkommaaddition auszuführen). Sie können also eine Mischung haben. Bei aktuellen Maßstäben ist es jedoch wahrscheinlich nicht wirtschaftlich, die Zykluszeit zu verkleinern, so dass sie zu einer bitweisen Operation, aber nicht zu einer Addition passt.

Das Komplizierte am Addieren (Subtrahieren erhalten Sie normalerweise kostenlos) ist, dass es dieses lästige Carry-Problem gibt.

Am Ende haben Sie also die naive Lösung, die N-mal ist Volladdierer wobei N ist, wie viele Bits breit Ihre ALU ist.

Diese lästigen Überträge bedeuten, dass Sie eine große Ausbreitungsverzögerung haben. Und da ein einziger Carry-off das gesamte Ergebnis ungenau machen kann, müssen Sie am Ende ziemlich lange warten, bis alle Carry-Werte und damit alle anderen Volladdierer in der Kette ausgeglichen sind.

Es gibt viele Möglichkeiten, diesen speziellen Engpass zu umgehen, aber keine ist so einfach oder ressourcenschonend zu implementieren wie eine Kette von Volladdierern. (am schnellsten ist eine in Silizium implementierte Nachschlagetabelle)

Wenn Sie weitere Details wünschen, müssen Sie dies wahrscheinlich anfragen http://electronics.stackexchange.com stattdessen

  • Wenn Sie darüber nachdenken, wie eine Lookup-Tabelle implementiert werden würde, bei der ihre Demultiplexer ein Signal auswählen, das mit einem Signal des anderen Operanden kombiniert wird, in einem von 2 ^ N-Gattern, die wieder in einen Multiplexer eingespeist werden, werden Sie das vollständig erkennen kombinatorischer Addierer ist nur eine Nachschlagetabelle, stark optimiert, um die ganze doppelte Logik loszuwerden.

    – Bernd Jendrissek

    14. Mai 2013 um 1:57 Uhr

  • @BerndJendrissek Alles läuft irgendwann auf eine Nachschlagetabelle hinaus. Siehe auch “Die taktische Atombombe des Logikdesigns”

    – Earlz

    14. Mai 2013 um 14:55 Uhr

Um Ihre letzte Frage zu beantworten, es kommt darauf an. Einige Architekturen haben nur Verschiebungen um 1 (z. B. z80), einige Architekturen weisen Verschiebungen um größere Konstanten und/oder Variablen auf, aber implementieren sie intern als eine Reihe von “Verschiebungen um 1” (wie alte Implementierungen von x86), gibt es einige Architekturen, die in einem einzigen Zyklus um mehr als 1 verschieben können, aber nur, wenn der Verschiebungsbetrag eine Konstante ist, gibt es einige Architekturen (wie z. B. moderne Implementierungen von x86), die a verwenden Barrel-Shifter und kann sich in einem einzigen Zyklus um eine Variable verschieben, und es gibt noch mehr Möglichkeiten.

Die Schaltungstiefe eines Barrel-Shifters ist logarithmisch in der maximalen Verschiebung, die er ausführen kann, was nicht unbedingt der Breite eines Registers entspricht – manchmal ist sie um eins kleiner als die Breite und es ist denkbar, dass sie noch kleiner ist.

  • Ja, die bitweisen Operationen, die potenziell schneller sind als add sind Dinge wie and / xor. Barrel Shifter sind teurer (oder weniger wichtig) als Addierer, oder zumindest haben die Pentium4-Designer das entschieden.

    – Peter Cordes

    1. Mai 2018 um 11:55 Uhr

Einige Additionsimplementierungen müssen einen zusätzlichen Zyklus für das Übertragsbit ausführen. Beispiel: Eine 16-Bit-Ganzzahl erfordert mehrere Befehle auf einem 8-Bit-Prozessor. Dies gilt auch für die Verschiebung. Aber die Verschiebung kann immer die Höhenbits zu den niedrigeren Bits des nächsten Bytes verschieben. Die Addition muss das untere Bit in einer zusätzlichen Runde hinzufügen.

Der bitweise Operator wird in kürzerer Zeit ausgeführt, weil

  • Der Prozessor nimmt eine Anweisung, um eine bitweise Operation durchzuführen, und (sagen wir) einen Ausführungszyklus, während andere arithmetische Anweisungen (insbesondere Multiplizieren und Dividieren) mehr Ausführungszyklen benötigen
  • Die meiste Zeit wird eine bitweise Operation in einem Register durchgeführt, und andere arithmetische Anweisungen werden benötigt, um mehr als ein Register zu handhaben

Deshalb ist das Verschieben von Bits schneller als andere arithmetische Operationen

  • Bitweise Operationen wie and / xor / or sind auch immer schnell. Natürlich ist mul/div teuer, aber hier geht es um bitweise vs. add/sub.

    – Peter Cordes

    1. Mai 2018 um 11:59 Uhr

Benutzer-Avatar
kjpreis

Das leuchtete mir bei einer Einführung in den Montageunterricht ein. Aber das Verschieben ist so ziemlich die schnellste Anweisung, die ein Prozessor ausführen kann. Das Addieren und Subtrahieren erfordert einige Befehle zur Ausführung. Ich stelle mir vor, dass moderne Prozessoren besser optimiert sind.

Vermutlich kann das jemand genauer und gründlicher beantworten.

  • Bitweise Operationen wie and / xor / or sind auch immer schnell. Natürlich ist mul/div teuer, aber hier geht es um bitweise vs. add/sub.

    – Peter Cordes

    1. Mai 2018 um 11:59 Uhr

1336270cookie-checkWarum waren bitweise Operationen auf älteren Mikroprozessoren etwas schneller als Additions-/Subtraktionsoperationen?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy