Warum ist der loop-Anweisung langsam? Konnte nicht auf Intel umgesetzt haben, ist es effizient?
LOOP (Intel ref manuelle Eingabe)
dekrementiert ecx /rcx, und dann springt, falls nicht null. Es ist langsam, aber Sie konnte nicht Intel preiswert schnell? dec/jnz
bereits makro-sicherungen in einem einzigen Upstream-Provider auf Sandybridge-Familie; der einzige Unterschied ist, dass das setzt flags.
loop
auf verschiedenen microarchitectures, von Agner Fog-Anweisung Tabellen:
- K8/K10: 7 m-ops
-
Bulldozer-Familie/Ryzen: 1 m-op (gleiche Kosten wie makro-fused test-und-Zweig, oder
jecxz
) -
P4: 4 uops (gleiche wie
jecxz
) - P6 (PII/PIII): 8 uops
- Pentium M, Core2: 11 uops
- Nehalem: 6 uops. (11 für
loope
/loopne
). Durchsatz = 4c (loop
) oder 7c (loope/ne
). - SnB-Familie: 7 uops. (11 für
loope
/loopne
). Durchsatz = eine pro 5 Zyklen, wie viel von einem Engpass, als wenn Ihr den loop-Zähler im Speicher!jecxz
ist nur 2 uops mit dem gleichen Durchsatz wie die regelmäßigejcc
- Silvermont: 7 uops
- AMD Jaguar (low-power): 8 uops, 5c Durchsatz
- Über Nano3000: 2 uops
Konnte nicht die Decoder nur decodieren das gleiche wie lea rcx, [rcx-1]
/jrcxz
? Das wäre 3 uops. Zumindest wäre das der Fall mit keine Adresse-Präfix Größe, da es sonst zu verwenden hat ecx
und abschneiden RIP
zu EIP
wenn der Sprung genommen wird; vielleicht ist die seltsame Wahl der Adresse-Größe, die Steuerung der Breite der Dekrement erklärt die vielen uops?
Oder besser, nur Sie entschlüsseln, wie eines fusionierten, dec-und-Zweig, der nicht gesetzten flags? dec ecx
/jnz
auf SnB dekodiert, um eine einzelne uop (die nicht gesetzten flags).
Ich weiß, dass real-code nicht verwenden (da es schon langsam seit mindestens P5 oder sowas), aber AMD beschlossen, es war es Wert, um es schnell für Bulldozer. Wahrscheinlich, weil es einfach war.
-
Würde es leicht sein, für SnB-Familie uarch die schnelle
loop
? Wenn dem so ist, warum nicht? Wenn nicht, warum ist es schwer? Viele decoder mit transistoren? Oder extra-bits in eine verschmolzen Dez&branch Upstream-Provider zu erfassen, dass es nicht gesetzten flags? Was könnten diese 7 uops tun? Es ist eine wirklich einfache Anleitung. -
Was ist das Besondere an der Bulldozer, der einen schnellen
loop
einfache /lohnt sich das? Oder hat AMD Müll ein Haufen transistoren auf machenloop
schnell? Wenn dem so ist, vermutlich jemand dachte, es war eine gute Idee.
Wenn loop
war schnell, es wäre perfekt für BigInteger beliebige Präzision adc
- Schleifen, um zu vermeiden, Teil-flag-Stände /slowdowns (siehe meine Kommentare auf meine Antwort), oder jedem anderen Fall, wo Sie wollen, um die Schleife, ohne diese zu berühren Fahnen. Es hat auch eine kleinere code-Größe Vorteil gegenüber dec/jnz
. (Und dec/jnz
nur makro-sicherungen auf SnB-Familie).
Auf modernen CPUs, wo dec/jnz
ok ist, in einen ADC-Schleife loop
wäre noch schön für ADCX /ADOX Schleifen (zu bewahren).
Wenn loop
hatte, wurden schnell, Compiler würde schon werden Sie es als eine peephole-Optimierung für code-Größe + Geschwindigkeit auf CPUs ohne makro-fusion.
Es würde nicht aufhören, mich immer genervt auf all die Fragen, die mit schlechten 16bit-code, der verwendet loop
für jeden loop, auch wenn Sie müssen auch ein weiterer Zähler innerhalb der Schleife. Aber zumindest wäre es nicht als schlecht.
- Es ist schon komisch, dass AMD selbst empfiehlt die Vermeidung der
LOOP
Anweisung, wenn die Optimierung für den Bulldozer. - Vielleicht ist es nicht Zweig-Vorhersagen, die auf dieselbe Weise? IDK. Ich fand einige Spekulationen und plausible Theorien über groups.google.com/d/msg/comp.arch/5RN6EegUxE0/KETMqmKWVN4J. (Link zu einer von Paul Clayton ' s post Mitte Weg, obwohl. Scrollen Sie bis zum Beginn des Threads, das war eine exakte Kopie von meiner Frage). hurr durr google Ihre Fragen >.<
- Einer der anderen Antworten, die sagt: "SCHLEIFE wurde langsam auf einige der frühesten Maschinen (circa 486), wenn erhebliche pipelining begann zu geschehen, und die laufen alle, aber die einfachste Anweisung über die pipeline effizient war technisch nicht praktikabel. So SCHLEIFE war zu langsam für eine Anzahl von Generationen. Also niemand benutzt es. Also, wenn es möglich wurde, um ihn zu beschleunigen, gab es keinen wirklichen Anreiz, dies zu tun, da niemand tatsächlich. "Also, wenn der Compiler aufgehört haben, dem Unterricht, warum die Mühe, es jetzt zu verbessern? Es würde nicht verbessern den Grundstein für eine neue CPU...
- "es lohnt sich nicht beschleunigt, 'Ursache, die niemand nutzt, weil es langsam?" ist das genial 🙂
- Hätte es effizient wieder auf P6, Compiler würde schon werden Sie es verwenden, und speichern Sie ein paar code-bytes. (Und bevor makro-fused dec-und-Zweig, speichern uops, auch wenn es einzelne-uop). Dies gilt nur für die seltenen Fälle, in denen ein compiler transformieren kann den Schleifenzähler in ein count-down, da die meisten Programmierer schreiben Ihre loops zu zählen. Auch ohne
loop
auf asm-Ebene, die einen Countdown auf null ist etwas effizienter, da das Dekrementieren wird das zero-flag, ohne dass ein vergleichen Sie. Ich in der Regel immer noch schreiben, dass meine C-Schleifen von 0..n, zur besseren Lesbarkeit aber. - Schleife über einen Puffer nach vorn in eine Schleife, dann rückwärts in die nächste Schleife, ist wahrscheinlich die Idee, den Fall für die Zwischenspeicherung, wenn. In der Theorie erhalten Sie immer eine komplette cache-Größe, block-cache-Treffer bei der turn-around-Ende des Puffers, anstatt sich zu keinem Treffer, wenn das array ist etwas zu groß (und der Anfang ist vertrieben durch die Zeit, die Sie am Ende bekommen). Hardware Prefetcher erkennen vorwärts-und rückwärts-streams, so dass Sie nicht verpassen diese (habe ich geprüft, und das ist wahr für mindestens SnB-Familie. HW Prefetcher vielleicht weniger nach hinten Ablagefächer auf ältere CPUs habe ich vergessen.)
- Ich arbeitete bei Nexgen, für eine kurze Weile, dann bei AMD auf der K6, K6-2 und Athlon Prozessoren. Ein problem, das ich erinnere mich mit der
LOOP
Anweisung ist, dass schnelle Implementierungen, die Sie verursachen würden bestimmte bestehende software (mehr als ein Programm), um Fehlfunktionen, die verwendet werdenLOOP
für delay-Schleifen zu implementieren Mikro-Verzögerungen, z.B. in der Treiber-software. Soweit ich mich erinnere (aber meine Erinnerung ist verschwommen und ich habe nicht die Zeit zu finden, Verweise), die beide Nexgen und Cyrix fiel in die Falle, ca. 1995. Smart-CPU-Architekten nur machen Sie den gleichen Fehler einmal, so dass spätere CPUs gehaltenLOOP
langsam auf Zweck. - Ah, daran hatte ich nicht gedacht Richtigkeit Probleme mit Treibern. Timing-Probleme sind erwähnt worden, wie einer der Gründe, aber ich hatte darüber nachgedacht, Spiele, oder etwas, das würde zu schnell laufen, und variable CPU Geschwindigkeit macht das obsolet. Aber wenn der Fahrer Verzögerungen kann kürzer sein, auf schnellere CPUs, das macht Sinn. (Oder, wenn Sie Kalibrieren den delay Schleifen beim Start, wenn schnell
loop
die erforderlichen Graf überlauf?) Da AMD hat wieder einmal versucht, das Schicksal mit fastloop
ich denke, es ist sicher anzunehmen, dass die Art des delay-Schleife ist komplett tot, im Alter von DVFS Energiespar-/turbo-CPU-clocks. - Nexgen ist Nx586 hatte patchbare microcode, gespeichert in der SBIOS, also die Befestigung das Problem mit dem schnellen
LOOP
Anweisung erforderlich ist nichts mehr als ein BIOS-update, soweit ich mich erinnere. Ich bin unter dem Eindruck, dass patchbare microcode ist eine standard-Funktion auf x86-Prozessoren in diesen Tagen, so dass es nicht nehmen viel Mut, um zu versuchen eine schnelleLOOP
. Diese delay-loops starb wahrscheinlich mit DOS-und Win16-aber für den Athlon-Prozessor stecken wir mit einem langsamenLOOP
Umsetzung zu vermeiden, unnötige Risiken: software hat die Tendenz, länger zu Leben als die hardware. - IDK, wenn Planierraupe
loop
Anweisung kann geändert werden, mit microcode. Ja, Intel und AMD haben patchbare microcode (und ja, es gibt tatsächliche bugfixes in den updates für Skylake, zum Beispiel!). Aber nicht alles ist nicht microcoded. Ich vermuteloop
sein könnte hard-wired. Im AMD-Terminologie, ist es ein "DirectPath Single" Unterricht, decodeable von jedem der 4-Decoder in einem einzigen makro-op. Nur VectorPath Anweisungen (mehr als 2 m-ops) bekommen uops aus einer ucode ROM. (superuser.com/q/360456/20798). (Intel ist ähnlich, 4 uops und weniger decodiert werden direkt). - Ich vermute, NX586 ist
LOOP
war mehrere uops und kam aus ROM sowieso, so dass Sie könnte leicht machen es langsamer? Microcode-updates können oft nur die Dinge beheben durch ausschalten der ganzen features. z.B. Skylake hat einen bug mit Teil-register umbenennen und Zusammenführen uops, und das update zu Update, das deaktiviert die loop-Puffer komplett (also auch kleine loops zu Holen uops aus der L0 uop cache, anstelle von recycling der Puffer, dass die feeds das Problem stage). Zum Glück Skylake nur aufgepeppt die front-end, so dass es nicht zu einem Engpass prob. nur eine kleine power-Strafe. - Nx586 ist
LOOP
Unterricht wurde microcoded, somit die Leichtigkeit der Verlangsamung. DirectPath ist AMD Terminologie für eine Anweisung implementiert, die direkt in hardware, während VectorPath bezieht sich auf microcoded Anweisungen (ich war ein microcoder für den Athlon-Prozessor, wo das gleiche Terminologie verwendet wurde, die vor zwanzig Jahren). Ob DirectPath Anweisungen auf modernen AMD-Prozessoren werden könnte, re-vektorielle Mikrocode für bug-fixing Zwecke, ich weiß nicht; im Allgemeinen ist es sicherlich technisch möglich, design-in-solch eine Funktion (für eine kleine Anzahl von Anweisungen). - in Bezug auf das update, um dass deaktiviert die loop-buffer-ganz - hast du eine Referenz für diese Behauptung? Es wäre eine große Sache, aber ich sehe keine Bestätigung noch. Update: ich fand dieser.
- perf Counter auf meinem desktop. Ich meinte zu erwähnen, dass in einem update zu meinem SKL teilweise-regs Antwort. Alles, was ich habe profilierten da eigentlich aktivieren von Arch Linux zu aktualisieren, die ucode gezeigt hat, genau
0
zählt fürlsd.uops
. Auch nicht-microbench Dinge (wieocperf.py -p some-PID
) haben niemals eine zählt. Entweder, dass die perf counter ist jetzt gebrochen, oder Sie deaktiviert die LSD. Ich habe gelesen, dass die SKL-X nicht verwenden, LSD, und diese Entdeckung erklärt, warum: es versendet mit neuen genug ucode zum deaktivieren des LSD. (update: finden Sie den gleichen link hast du auf wikichip). - IMO ist das eine große Sache.
- Ja, es ist, aber ich denke, der Effekt ist klein bis nicht existent, die meisten der Zeit. Das LSD nur gearbeitet, uops, die enthalten sind in der uop-cache, und die SKL hat ausgezeichnete uop-cache lese-Bandbreite. Es sei denn, dein code passt sehr schlecht in die uop-cache und sonst sustain-4 uops pro Takt, es ist nicht ein echtes Nadelöhr.
- richtig, ich würde vermuten, dass performance-Weise, ist es eigentlich ein pessimization mehr als oft ein Vorteil, aber es ist da, um Energie zu sparen, richtig? Es scheint wie eine nicht-triviale Menge an Komplexität-und Validierungs-Aufwand, so dass ich davon ausgehen muss es eine angemessene Leistung profitieren. Mit sehr hoher Wahrscheinlichkeit die meisten Menschen werden nie in diesen Fehler (aufgrund der speziellen high-reg nutzen, das es auslöst), so bezahlen jeden Preis ist sowas von bedauerlich.
- Ja, ich denke, dass der Hauptvorteil in der SKL war macht. Auf HSW, es könnte einem manchmal perf Schub, denke ich. Ich habe noch nicht getestet, Wann genau uop-cache gelesen werden können, einen Engpass auf NHM (z.B. mit 5 uops pro Zeile?), also, welche Art von Puffer-es gibt vor, dass "4 uops pro Takt aus dem DSB" die Grenze an der HSW. Sie hielt die LSD von NHM, wo es war definitiv ein großer Schub (kein uop-cache), aber wahrscheinlich eine Menge es musste neu implementiert für die SnB. Noch, IDK, wenn Sie würde haben ihn entworfen von Grund auf für die SnB, wenn Sie nicht bereits haben es aus dem NHM.
- Als der KBY (Kaby Lake) und APL (Apollo See) nichts verändert zu haben scheint: uops.info/html-instr/LOOP-786.html
Du musst angemeldet sein, um einen Kommentar abzugeben.
Nun, dass ich gegoogelt nach schreiben meiner Frage, es stellt sich heraus, um eine exakte Kopie von einem auf comp.arch, die kam sofort. Ich erwartet, dass es hart sein, um von google (viele "warum wird mein loop slow" trifft), aber meine ersten versuche (
why is the x86 loop instruction slow
) bekam Ergebnisse.Dies ist nicht eine gute oder vollständige Antwort.
Ist es möglicherweise das beste, was wir bekommen, und müssen genügen, es sei denn, jemand kann Schuppen etwas mehr Licht auf Sie. Ich habe es nicht darauf an, dies zu schreiben als eine Antwort-meine-eigene-Frage-post.
Gute Beiträge mit unterschiedlichen Theorien in diesem thread:
Robert
Anton Ertl:
(Paul, und alle anderen: Sie sind herzlich eingeladen zu re-posten Sie Ihre eigenen zu schreiben, wie Sie Ihre eigene Antwort. Ich werde es entfernen, aus meiner Antwort und Stimme dir.)
@Paul A. Clayton (gelegentlich ALSO poster und CPU-Architektur Kerl) nahm eine Vermutung, wie Sie könnten, viele uops. (Das sieht aus wie
loope/ne
die Prüfungen sowohl der Zähler und ZF):(Beachten Sie, dass dies 6 uops, nicht SnB 11 für LOOPE/LOOPNE, und insgesamt denke nicht einmal versuchen zu berücksichtigen, alles bekannt von der SnB perf Counter.)
Paulus sagte:
Zusammenfassung: Die Designer wollten
loop
unterstützt werden nur über microcode, ohne Anpassungen überhaupt die richtige hardware.(Meine Meinung: die Intel ist wahrscheinlich trotzdem macht es langsam auf Zweck, und hat sich nicht die Mühe gemacht zu umschreiben, deren microcode für es für eine lange Zeit. Moderne CPUs sind wohl zu schnell für alles, was mit
loop
in eine naive Art und Weise, um korrekt zu arbeiten.)... Paul fährt Fort:
Den thread, dann ging er off-topic in den Bereich der AMD weht unsere einzige chance zu bereinigen, die Reste in der x86-instruction-Codierung. Es ist schwer, Sie zu tadeln, da jede änderung ist ein Fall, wo der Decoder kann nicht gemeinsam transistoren. Und bevor Intel verabschiedet, x86-64, es war nicht einmal klar, dass es fangen würde, auf. AMD wollte Sie nicht belasten Ihre CPUs mit hardware, die niemand benutzt, wenn der AMD64 hat nicht fangen auf.
Aber immer noch, es gibt so viele kleine Dinge:
setcc
geändert haben könnte, um 32-bit. (In der Regel verwenden Sie xor-zero /test /setcc zu vermeiden, falsche Abhängigkeiten, oder braucht man da eine null-extended reg). Shift hätte bedingungslos Fahnen geschrieben, auch mit der Verschiebung von null count (entfernen der input-Daten und die Abhängigkeit eflags für variable count shift für OOO-execution). Letztes mal schrieb ich diese Liste von pet peeves, ich denke, es war ein Dritter... ach ja,bt
/bts
etc. mit memory-Operanden ist die Adresse abhängig von der oberen bits des index (bit-string, nicht nur etwas in einer Maschine, word).bts
Anweisungen sind sehr nützlich für das bit-Feld-Zeug, und sind langsamer als Sie sein müssen, so dass Sie fast immer wollen, laden in ein register und verwenden Sie dann die. (Es ist in der Regel schneller shift/Maske, um eine Adresse, die sich, statt mit 10 uopbts [mem], reg
auf Skylake, aber es braucht zusätzliche Anweisungen. So machte es Sinn, 386, aber nicht auf K8). Atomare bit-manipulation ist die Verwendung des memory-dest form, aber dielock
ed-version braucht viel uops sowieso. Es ist immer noch langsamer, als wenn es vorher keinen Zugang außerhalb derdword
es den Betrieb auf.adc
Schleife. Eine günstige Möglichkeit, Schleife, ohne diese zu berühren flags ist genau das, was Sie wollen, für beliebige Größe BigIntegeradc
Schleifen. Also AMD Bulldozer-Familie hat einen soliden Vorteil, auch im Vergleich zum Intel Broadwell und später, woadc
1-uop insn. Compiler können bereits byte-Anzahl in ecx fürrep stos
und so weiter; ich glaube nicht, dass es sein würde, die schwer zu bedienen.adc
Schleifen (in der Regel nur einen einzigen adc für __int128_t oder int64_t). Ich nehme an, Intel kümmert sich einige etwa willkürlich-precision-Integer-zahlen. gmplib.org gewesen herum für eine lange Zeit, und public-key-Krypto ist eine große Sache. Mathe auf große zahlen ist nicht ungewöhnlich.dec/jcc
ins Rollen gebracht, indem Sie 2 oder 4 zu SnB-Familie microarchitectures funktioniert ziemlich gut. Anscheinend bringt es einen einzelnen zusätzlichen uop Zusammenführen, die Flaggen, wenn die nächsteadc
Sie liest, so ein 1uoploop
würde nur speichern 1uop. Aber nur, wenn Sie bereit sind, verwenden Sie code, der führt sich schlecht auf pre-SnB (Nehalem). Andernfalls, speichern/wiederherstellen Flaggencmp/jcc
(mit lahf/sahf) Kosten 2 zusätzliche uops. Und looping mitadcx
/adox
(neu mit broadwell) zu tun, zwei dep-Ketten parallel erfordert eine Schleife, die nicht auf Flaggen. (lahf nichtOF
.)1988, IBM fellow Glenn Henry musste einfach kommen Sie an Bord bei Dell, die hatte ein paar hundert Mitarbeiter auf die Zeit, und in seinem ersten Monat gab er ein tech-talk rund 386 Interna. Ein paar von uns BIOS-Programmierer hatte mich schon gewundert, warum die SCHLEIFE war langsamer als DEC/JNZ, also während der Frage/Antwort-Abschnitt, jemand stellte die Frage.
Seine Antwort machte Sinn. Es hatte zu tun mit paging.
SCHLEIFE besteht aus zwei teilen: Dekrementieren CX, dann springen, wenn CX nicht null ist. Der erste Teil nicht dazu führen, dass ein Prozessor-exception, in der Erwägung, dass der jump-Teil. Für ein, Sie könnte springen (oder fallen) zu einer Adresse außerhalb der segmentgrenzen, was zu einem segmentation Fault. Für die zwei, Sie konnte springen, um eine Seite, die ausgelagert wurden.
Einem SEGFAULT in der Regel buchstabiert das Ende für einen Prozess, aber Seitenfehler sind unterschiedlich. Wenn ein Seitenfehler Auftritt, wird der Prozessor eine exception wirft, und das OS macht den Haushalt, tauschen Sie die Seite von der Festplatte in den RAM. Nach, dass es neu gestartet die Anweisung, die den Fehler verursacht hat.
Neustart bedeutet, dass der Zustand wiederhergestellt wird, der Prozess zu dem, was es war kurz vor der beanstandeten Belehrung. Im Fall der LOOP-Anweisung in allem bedeutete die Wiederherstellung der Wert des CX-register. Man könnte denken, Sie könnten fügen Sie einfach 1 zu CX, da wir wissen, CX bekam dekrementiert, aber anscheinend ist es nicht so einfach. Zum Beispiel, schauen Sie sich dieses erratum von Intel:
Sicher zu sein, die Sie benötigt, um speichern Sie den Wert von CX bei jeder iteration des LOOP-Anweisung, um zuverlässig wiederherstellen, wenn nötig.
Es ist diese zusätzliche Belastung zu speichern CX, die aus LOOP so langsam.
Intel, wie jeder andere auch zu der Zeit, wurde immer mehr RISC. Die alten CISC-Anweisungen (LOOP, ENTER, LEAVE, GEBUNDEN) wurden ausgemustert. Wir benutzte Sie immer noch in der hand-codiert Montage, aber Compiler ignoriert Sie völlig.
dec ecx / jnz
decodiert als eine einzige uop, verringert und Zweige. Interessant, dass es nicht rein absichtlich langsam, um zu versuchen, um zu vermeiden brechen delay loops.Bitte sehen Sie sich den schönen Artikel von Abrash, Michael, erschienen im Dr. Dobb ' s Journal, März 1991 v16 n3 p16(8): http://archive.gamedev.net/archive/reference/articles/article369.html
In der Zusammenfassung des Artikels ist die folgende:
Durch "ungewöhnliche Anweisungen, unterstützt von der 8088", der Autor heisst auch "loop":
Dies ist ein sehr guter Artikel, und ich kann es nur wärmstens empfehlen. Obwohl es wurde 1991 veröffentlicht, ist es überraschend hoch relevant heute.
Aber dieser Artikel gibt nur Hinweise, es fördert die Geschwindigkeit der Testausführung, und wählen Sie schnellere Varianten. Er erklärt nicht, WARUM einige Befehle nur sehr langsam, so dass es nicht vollständig auf Ihre Frage.
Die Antwort ist, dass früher-Prozessoren wie der 80386 (1985) und zuvor ausgeführten Befehlen one-by-one, nacheinander.
Spätere Prozessoren haben begonnen, zu verwenden, instruction pipelining – zunächst einfache, für 804086, und, schließlich, Pentium Pro (1995) eingeführt radikal verschiedenen internen pipeline, nannte es der Out-Of-Order (OOO) Kern, wo Anweisungen wurden transformiert, um kleine Fragmente von Operationen als micro-ops oder µops, und dann alle micro-ops von verschiedenen Anweisungen, die gestellt wurden, um einen großen pool von Mikro-ops, wo Sie sollen gleichzeitig ausführen, solange Sie nicht voneinander abhängen. Diese OOO-pipeline-Prinzip wird immer noch verwendet, fast unverändert, auf modernen Prozessoren. Sie finden mehr Informationen über instruction pipelining in diesem tollen Artikel: https://www.gamedev.net/resources/_/technical/general-programming/a-journey-through-the-cpu-pipeline-r3115
Zur Vereinfachung der chip-design, das Intel sich entschieden build-Prozessoren in der Weise, dass man Anweisungen, die Tat zu transformieren, um die micro-ops in einer sehr effizienten Weise, während andere nicht sind.
Effiziente Umsetzung von Anweisungen zur micro-ops erfordert mehr transistoren, so dass Intel sich entschieden haben, zu speichern, auf die transistoren Kosten bei einer langsameren Decodierung und Ausführung von einigen "komplexen" oder "selten benutzte" Anweisungen.
Beispielsweise die "Intel® Architecture Optimization Reference Manual" http://download.intel.com/design/PentiumII/manuals/24512701.pdf erwähnt die folgenden: "Vermeiden Sie die Verwendung von komplexen Anweisungen (geben Sie beispielsweise, lassen, oder Schleife), die haben in der Regel mehr als vier µops und erfordern mehrere Zyklen zu entschlüsseln. Verwenden Sie Sequenzen von einfachen Anweisungen, statt."
So, Intel irgendwie haben beschlossen, dass die "loop" - Anweisung ist "Komplex", und seitdem wurde es sehr langsam. Es gibt jedoch keine offizielle Intel-Referenz auf Anweisung Panne: wie viele micro-ops-jede Anweisung erzeugt, und wie viele Zyklen erforderlich sind, zu entschlüsseln.
Lesen Sie auch über Die Out-of-Order Execution Engine
in der "Intel® 64 and IA-32 Architectures Optimization Reference Manual"
http://www.intel.com/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-optimization-manual.pdf Abschnitt der 2.1.2.
dec rcx / jnz looptop
als single uop (makro-fusion). Die Frage ist, warum ist LOOP noch langsam auf Sandybridge, wenn es möglich ist, für eine einzelne uop, alles zu tun, dass die SCHLEIFE nicht (außer für lassen Sie die flags unverändert).