Ich entwickle eine Anwendung, bei der Leistung entscheidend ist. Ich möchte, dass GCC einige bestimmte Aufrufe in memset () als eine Anweisung mit einem Wiederholungs-Präfix wie "rep stos QWORD PTR es: [rdi], rax" übersetzt. GCC tut dies automatisch, wenn die Größe bekannt und klein ist.
GCC ordnet jedoch Aufrufe von memset () mit einer zufälligen Länge durch einen Aufruf von memset () über die PLT zu, was eine Verzweigungsfehlvorhersage verursacht, da der Verzweigungsvorhersager-Cache kalt ist.
Gibt es eine Möglichkeit, GCC zu zwingen, das zu tun, was ich will (außerhalb der Inline-Montage)? Beachten Sie, dass dieses Verhalten nicht für das gesamte Programm gilt, sondern nur für bestimmte memset () -Aufrufe.
Zu einem verwandten Thema bin ich auch an jedem Hack interessiert, der verhindert, dass GCC verzweigt, wenn ein cmovcc-Befehl die Aufgabe erfüllen würde (ich weiß, wie man & amp; amp;, etc. anstelle von & amp; & amp;) / p>
Vielen Dank für jede Hilfe.
@FrankH:
Das ist im Grunde, was ich getan habe. Hier ist mein Code:
%Vor% Beachten Sie, dass Ihr Beispiel in Ihrem Test-Setup funktioniert, aber es wird nicht funktionieren
allgemein. GCC kann das Richtungsflag ändern, also ist ein cld
Befehl
notwendig. Außerdem müssen Sie gcc mitteilen, dass %rdi
und %rcx
sein werden
geändert durch die Anweisung stos
, und da gcc das nicht zulässt
Geben Sie an, dass ein Register sowohl eine Eingabe als auch eine ungültige Eingabe ist. Verwenden Sie die Option
peinliche "+"
Syntax (die auch Ihre Eingabewerte beschädigt).
Dies ist wegen der Anweisung 'cld' nicht optimal, die eine Latenz von 4 Zyklen auf Nehalem. GCC verfolgt den Flag-Register-Status intern (AFAICT), so dass diese Anweisung nicht jedes Mal ausgegeben werden muss.
Ich weiß nicht, über GCC, aber unter neueren Builds von MSVC, kann die Verwendung von Schleifen, um das Setzen / Kopieren gezwungen, die Verwendung von REP STOS
(und es ermöglicht immer noch Optimierung für wissen Größen und Auto-Vektorisierung) Arbeitet ein Versuch unter GCC.
die Alternative, um zu überprüfen, ob GCC ein ähnliches eingebaut hat wie __stosq
, sonst wirst du wahrscheinlich auf Inline Assembly gehen müssen, aber das ist überhaupt nicht schlecht unter GCC (und es ist wahrscheinlich der einfachste und schnellste Weg).
Ihre zweite Frage ist viel zu generisch, um wirklich eine gute Antwort zu bekommen, denn es kommt auf den Fall an, aber GCC sollte gut genug sein um Zweige zu optimieren, mit Ausnahme von bestimmten Fällen (mit SETCC
/% co_de) % / MOVCC
).
Wenn Sie dies erzwingen möchten, warum Inline-Assembly als Option ausschließen?
%Vor%Verwenden Sie dies in einem Demo-Programm wie:
%Vor%erstellt mir diese Assembly:
%Vor%Das ist keine Erklärung dafür, warum GCC sich anders entscheidet, aber wie gesagt, wenn Sie das Verhalten erzwingen wollen, und wenn Sie explizit die Orte, wo Sie das brauchen, wissen, dann ist es nicht falsch, irgendeine Art von zu nennen speziell definierte eigene memsets?
Hinweis: repz stos %rax,(%rdi)
(oder die Intel-Syntax QWORD PTR
equiv) ist nicht gleich wie memset()
, da die Granularität für memset()
eine einzige ist Byte. Das obige ist ziemlich genau das gleiche wie memset(..., c, N * 8)
. Denken Sie daran.
Bearbeiten: Wenn Sie den Code wie folgt schreiben:
%Vor%kompiliert beides für 32bit und 64bit.