Was sind einige Tipps für die Optimierung des Assembler-code, der vom compiler erzeugt?
Ich bin derzeit in den Prozess des Schreibens ein compiler und ich scheinen zu haben, in einige Probleme laufen, wie es den Ausgabe-code, der ausgeführt wird, in einem anständigen Zeitrahmen.
Einen kurzen überblick über den compiler:
7Basic ist ein compiler, der soll zu kompilieren 7Basic code direkt in Maschinen-code für die Ziel-Architektur /Plattform. Derzeit 7Basic generiert x86 Assembler gegeben, eine source-Datei.
Das problem ist, dass der Assembler-code, der vom compiler generiert wird langsam und ineffizient.
Beispielsweise diese code (die kompiliert unten zu diese Assembler-code) dauert fast 80.47 mal länger auszuführen als der entsprechende C-code.
Teil des Problems ist, dass der compiler erzeugt code wie den folgenden:
push eax
push 5000000
pop ebx
pop eax
Anstelle der logisch:
mov ebx,5000000
..., führt die gleiche Sache.
Meine Frage ist: was sind einige Techniken, um zu vermeiden, diese Art von problem? Der parser grundsätzlich verwendet Rekursion, um eine Analyse der Ausdrücke, so dass der erzeugte code spiegelt dies wider.
- Add-O3 zu Ihrem compiler-Befehlszeile 😉
- +1 @drhirsch LOL
- "...ein cross-Plattform BASIC-compiler erzeugt native Win32 ausführbaren Dateien." Warten Sie, was?
- Gut, es soll auch zu generieren ELF-executables auch.
- Crenshaw tutorial, sagt ein (sehr!) wenig über peephole-Optimierung in einem one-pass-compiler. Kurz-kurz-version: Puffer für die Ausgabe von N Anweisungen und überprüfen Sie mögliche Optimierungen in den Puffer jedes mal, wenn eine neue Anweisung emittiert wird, zu dem Puffer. Drücken die Ergebnisse aus, wie gebraucht. Welche Optimierungen sind zu tun? Ah...das ist der schwierige Teil, nicht wahr?
- Das scheint, wie hilfreiche Ratschläge.
- Ist LLVM eine option für dich?
Du musst angemeldet sein, um einen Kommentar abzugeben.
Einer Technik namens peephole-Optimierung. Dieser nimmt einen iterativen Ansatz, um die Säuberung Assembler-code. Im wesentlichen Scannen Sie über die assembly-code, Blick auf nur zwei oder drei Anweisungen in einer Zeit, und sehen, ob Sie können, reduzieren Sie in etwas einfacher. Zum Beispiel,
Der erste Schritt Aussehen würde, in den Zeilen 2 und 3, und Ersetze Sie mit:
Zweiten, sollten Sie erwägen, 1 und 4, und wenn
eax
ist nicht berührt, in der Mitte Instruktion, entfernen Sie Sie beide, verlassen, was Sie wollen:Möchten Sie vielleicht zu prüfen, generieren von C-code anstatt der Montage und dann lassen Sie einen C-compiler (z.B. gcc) Griff die code-Generierung für Sie. Es gibt keinen Punkt versucht, das Rad neu zu erfinden.
Nehme ich einen compiler-Kurs im moment. Ich habe einige große Fortschritte in der Ausgabe effizienten code, aber Sie sollten in der dragon book. Es ist eine rite de passage. Sie sollten einen Blick auf den code, der von Jeremy Bennett Buch Einführung zu Kompilieren Techniken: Ein Erster Kurs Mit ANSI-C, LEX und YACC. Das Buch selbst ist sehr schwer zu finden, aber Sie können downloaden Sie den Quellcode für die compiler frei von
http://www.jeremybennett.com/publications/download.html
Den code-generator-Datei (cg.c) verfügt über einige Funktionen für die Erzeugung von relativ optimierten code. Die Zielsprache ist nicht i386, aber man sollte betrachten, wie er beschreibt, registriert und verfolgt, wo die symbol-Tabelle der Einträge werden gespeichert. Sein output assembly konnte weiter optimiert werden, aber es bietet eine großartige Basis für die Herstellung von code, konnte der Rivale der Ausgabe von gcc -S in einigen Punkten.
Einer Allgemeinen Optimierung wäre zu subtrahieren Sie den stack-pointer zu reservieren Speicherplatz für alle lokalen und temporären Variablen nach Eingabe einer Funktion. Dann einfach die Referenz-offsets statt ständig drängen/knallen.
Zum Beispiel, wenn Ihr intermediate code ist eine Liste vervierfacht, Sie sollten einfach iterator durch es für jede Funktion und verfolgen das maximale offset. Dann die Ausgabe der Zeile zu subtrahieren Sie die Menge an Speicherplatz auf dem stack. Dies beseitigt die Notwendigkeit zu schieben so viele Variablen ein-und ausschalten. Um die zu entfernen, müssen Sie pop, können Sie einfach mov Ihren Wert aus Ihrer offset auf den stack in ein register. Dies wird deutlich verbessern die Leistung.
Gibt es eine Reihe von Gründen, die einer bestimmten code-generator kann emittieren die Befehlsfolge, die Sie Liste. Die wahrscheinlichste ist, dass der code-generator, die Sie verwenden ist einfach nicht versuchen, sehr schwer zu emittieren optimalen code.
Dieses Muster der ausgegebene code lässt mich vermuten, dass Sie Ihre code-generator, die nicht wissen, dass die x86 - "mov unmittelbaren" Anweisungen, die Sie einbetten der Konstante Wert in der instruction stream direkt. Der x86-Codierung für opcodes mit der sofortigen Werte kann ein wenig kompliziert (variable-Länge-R/M bytes), aber dies ist bereits erforderlich, wenn Sie verwenden möchten, viele der x86-Anweisungen.
Dieser ausgegebene code auch darauf hin, dass der code-generator nicht wissen, dass EAX wird nicht geändert von der EBX-Anweisungen. Das fühlt sich an wie die codegen ist Vorlage getrieben, anstatt diskreter Logik.
Diese Art von codegen passiert, wenn der compiler die interne zwischendarstellung von Operationen ist nicht detailliert genug sind, um alle Facetten der Ziel-Architektur. Dieses ist besonders zutreffend, wenn der code-generator-Architektur wurde ursprünglich für ein RISC-Befehlssatz, wurde aber von einem neuen Zweck zugeführt zu emittieren x86-Anweisungen. RISC-Architektur neigen dazu, sehr wenige und sehr einfach zu laden, zu speichern und zu betreiben reg/reg-Anweisungen, wobei der x86-Befehlssatz hat sich organisch über Jahrzehnte, um eine Vielzahl von opcodes, die arbeiten direkt auf dem Speicher, inline-Konstanten in den Anweisungen, und eine ganze Durcheinander mit anderen Sachen. Wenn der compiler intermediate representation (expression-Kurve) - Kabel RISC, wird es schwierig sein, um es zu verstehen, die Vielfalt und die Feinheiten der x86.
Peephole-Optimierungen helfen, aber ein offensichtliches Problem ist, dass dein compiler nicht tun-register-Allokation!
http://en.wikipedia.org/wiki/Register_allocation
Wenn Sie wollen, ernst zu erhalten, Leistungen, die Sie zu tun haben, zu untersuchen. Es kann getan werden, in einem einzigen Durchgang, wenn Sie es gierig "on the fly".