Kann ich Rust zwingen, eine einzelne Funktion nicht zu optimieren?

9

Ich habe eine Funktion, bei der die Optimierung von Rust / LLVM fehlschlägt und zu einer Panik führt (in der Release-Version), während der nicht optimierte Code (Debug-Version) einfach funktioniert. Wenn ich den generierten Assemblercode vergleiche, kann ich nicht einmal eine Idee erfassen, was der Optimierer zu erreichen versucht. (Ein Grund könnte sein, dass diese Funktion Inline-Assembler verwendet.)

Gibt es irgendeine Möglichkeit, Rust zu sagen, dass er bestimmte Funktionen während der Optimierung alleine lassen soll, oder muss ich alle Optimierungen ausschalten?

Hier ist die spezifische Funktion:

%Vor%     
Matthias 23.05.2017, 14:39
quelle

2 Antworten

4

Soweit ich weiß, hat Rust keine Möglichkeit, Optimierungsstufen für irgendetwas anderes als die gesamte Kiste festzulegen. Die einzige Problemumgehung wäre, diese Funktion in einer einzelnen Kiste zu kompilieren, sie zu kompilieren und dann als eine vorkompilierte Abhängigkeit einzuschließen. (Normale Rostabhängigkeiten werden auf der Optimierungsstufe des Abhängers zusammengestellt)

Allerdings: Die Angabe eines anderen Optimierungslevels für diese einzelne Funktion löst Ihr Problem nicht! Sicher, es kann heute funktionieren, aber kann jedes Mal wieder brechen, wenn sich der Compiler (oder die Optimierungsflags) ändern.

TL; DR : Nackte Funktionen sind zutiefst unsicher (Mein Respekt, du bist eine mutigere Person als ich!). Die einzige zuverlässige Möglichkeit, sie zu verwenden, besteht darin, nur einen einzigen asm!() -Block als den gesamten Funktionskörper zu schreiben, sonst nichts. Mischen asm! , normal Rust und Funktionsaufrufe wie Sie tun, ist effektiv nicht definiertes Verhalten (in der unheimlichen C / Nasal-Dämon Sinne des Wortes) Keine Menge optimierungs Zwicken wird sich das ändern.

Nackte Funktionen sind immer noch instabil, bis die Rust-Autoren "es richtig machen". Wie Sie gesehen haben, gibt es viele subtile Probleme damit. Tracking-Problem für die Stabilisierung hier

In dem nackt-fn RFC , unter " Motivation ", finden wir:

  

Da der Compiler von einem Funktionsprolog und Epilog abhängt, um den Speicher für lokale Variablenbindungen zu erhalten, ist im Allgemeinen nicht sicher, etwas anderes als Inline-Assembly in eine nackte Funktion zu schreiben . Die LLVM-Sprachreferenz beschreibt diese Funktion als "sehr systemspezifische Konsequenzen", die der Programmierer beachten muss.

(Betonung meiner)

Ein wenig weiter unten in der RFC, unter ungelöste Fragen , erfahren wir, dass dies nicht nur ein Problem für Rust ist. Andere Sprachen haben auch Probleme mit dieser Funktion:

  

.. Die meisten Compiler, die ähnliche Funktionen unterstützen, benötigen oder empfehlen dringend, dass Autoren nur Inline-Assembly in nackte Funktionen schreiben , um sicherzustellen, dass kein Code generiert wird, der ein bestimmtes Stack-Layout voraussetzt.

Der Grund dafür ist, dass alle Compiler eine Menge von Annahmen darüber, wie Funktionen aufgerufen werden (Stichworte: „Anrufer-Saved Register“, „Callee-Register gespeichert“, „Aufrufkonvention“, „Red Zone“). Nackte Funktionen gehorchen diesen Annahmen nicht, und daher ist jeder Code, den ein Compiler erzeugt, wahrscheinlich hoch wahrscheinlich falsch. Die "Lösung" besteht darin, den Compiler nichts generieren zu lassen, d. H. Die gesamte Funktion von Hand in Assembly schreiben zu lassen.

Als solche wird die Art und Weise Sie 'normal' Code ( let mut nr: u32 = 0; ), Funktionsaufrufe ( swi_service_routine(nr); ) und roh Assembler in einer nackten Funktion mischen ist nicht spezifiziert Verhalten . (Ja, so etwas gibt es in Rust, aber nur in Unstable).

Naked Funktionen verursachen genug Probleme, die sie verdienen ihr eigenes Label in Rust Bugtracker. In einem der A-Naked-Ausgaben finden wir diesen Kommentar , vom sachkundigen Benutzer Tari (ua Autor von llvm-sys . Er erklärt:

  

Die tatsächliche Korrektheit von Nicht-Asm-Code in nackten Funktionen hängt vom Optimierer und vom Codegenerator ab, von dem wir im Allgemeinen keine Garantie geben können, was er tun wird.

Es wird auch darüber gesprochen, dass unsafe für nackte Funktionen benötigt wird, da sie viele der normalen Annahmen von Rust brechen. Die Tatsache, dass sie dies noch nicht in allen Fällen benötigen ist ein offener Fehler

Die richtige Lösung für Ihr "Optimierungsproblem" ist also, sich überhaupt nicht mehr auf Optimierung zu verlassen. Schreiben Sie stattdessen nur einen einzelnen asm!() -Block.

Für Ihr Cpu::save_context() / Cpu::restore_context_and_return() -Paar: Ich kann den Wunsch nach Wiederverwendung von Code verstehen. Ändern Sie diese in ein Makro, das die relevante asm!(...) einfügt. Eine Verkettung von asm!(...); asm!(...); asm!(...); sollte einer einzelnen asm!() entsprechen.

    
Jules Kerssemakers 24.05.2017 15:16
quelle
-3

Wenn Sie Fracht verwenden, können Sie ihr mitteilen, dass sie gar nichts oder Ebenen optimieren soll

Fracht optimieren

    
jesusbv - user3085938 23.05.2017 15:37
quelle

Tags und Links