2017-02-20 3 views
4

Ich habe eine brandneue Kiste mit cargo new a und tippte diese in src/lib.rs:Warum sind Pub-Funktionen, die mit `# [inline]` markiert sind, nicht in der kompilierten Objektdatei vorhanden?

pub fn xor(a: i32, b: i32) -> i32 { 
    a^b 
} 

#[inline] 
pub fn xor_inline(a: i32, b: i32) -> i32 { 
    a^b 
} 

Wenn ich mit cargo build --release kompilieren, nur die erzeugte .rlib enthält xor und nicht xor_inline:

$ gnm -D -C target/release/deps/liba-6a3c2798185fafee.rlib 
gnm: __.SYMDEF: File format not recognized 

a-6a3c2798185fafee.0.o: 
0000000000000000 T a::xor::hf0d97103d53d3286 
gnm: rust.metadata.bin: File format not recognized 
gnm: a-6a3c2798185fafee.0.bytecode.deflate: File format not recognized 

(gnm ist GNU nm installiert auf MacOS über Homebrew.)

Ich habe zwei Fragen:

  1. Warum ist xor_inline innerhalb der Objektdatei nicht? Ich glaube, dass seine Quelle in rust.metadata.bin vorhanden sein muss, damit Cross-Crate-Inlining funktioniert, aber warum wird die Plain-Funktion nicht aus der Objektdatei exportiert?

  2. Gibt es in rustc ein Flag, das ich mit cargo rustc --release -- ... verwenden kann, um sicherzustellen, dass alle #[inline] Funktionen in der Objektdatei vorhanden sind? (Vielleicht eine andere --crate-type oder eine der Fahnen unter -C?)

(Ich brauche das, weil ich die generierte Assembly für die Funktionen in meine Kiste inspizieren wollen, ohne alle inline entfernen Attribute oder jedes Inline-Verpackung Funktion in einer öffentlichen non-inline Funktion.)

+0

In Verbindung stehend: entsprechend [dieser Antwort] (http://stackoverflow.com/a/30726157/1233251), behält das rlib eine Liste der Funktionen bei, die als inline gekennzeichnet werden. –

+1

* Warum wird die Plain-Funktion nicht aus der Objektdatei exportiert * - Ich nehme an, dass dieser Code einfach genug ist, dass er ** immer ** inline ist, daher kann er nie aufgerufen werden, also gibt es keinen Grund, Objektcode zu haben. * Ich möchte die generierte Baugruppe auf die Funktionen in meiner Kiste untersuchen * - einmal inline, sieht diese Baugruppe vielleicht genauso aus wie die inline und optimierte Baugruppe, daher ist es möglicherweise nicht einmal hilfreich, sie vor dem Inlining zu prüfen. – Shepmaster

Antwort

5

Vor Rust 1.13.0 wurde nativer Code tatsächlich immer für #[inline] Funktionen erzeugt. Diese changed in Rust 1.13.0: #[inline] Funktionen, die nicht in der Kiste verwendet werden, sind nicht in nativen Code kompiliert. Die primary motivation für diese Änderung ist, dass Bibliotheken, die eine Menge von Inline-Funktionen enthalten, die sie nicht selbst verwenden, sind viel schneller zu kompilieren, wenn sie überhaupt nicht in systemeigenen Code übersetzt werden.

Der Compiler gibt die Funktion weiterhin in einer Zwischendarstellung aus, damit der Compiler in andere Kisten inline und optimieren kann.

(Ich brauche das, weil ich die generierte Assembly für die Funktionen in meiner Kiste inspizieren will, ohne alle Inline-Attribute zu entfernen oder jede Inline-Funktion in einer öffentlichen Nicht-Inline-Funktion Verpackung.)

Der ganze Sinn von Inline-Funktionen besteht darin, dass der Compiler basierend auf der Verwendung der Funktion einen eindeutigen Assembler-Code ausgibt. Zum Beispiel kann eine Inline-Funktion, die Argumente empfängt, ihre Argumente an constant folding teilnehmen lassen, wenn einige Argumente Konstanten sind. Manchmal kann ein Inlined-Funktionsaufruf Anweisungen auf Null kompilieren (wenn Rust Null-Kosten-Abstraktionen fordert, meinen sie das wirklich!), Aber das konnte man vom nicht-inlinierten Funktionsaufruf nicht erkennen! Daher vermute ich, dass das, was Sie tun möchten, Sie nur irreführen würde; Sie würden nicht auf den Code schauen, den der Compiler tatsächlich ausgibt, wenn Ihre Inline-Funktion verwendet wird.

+0

Macht Sinn, danke! Der Grund, warum ich den Assembly-Code der Funktion sehen möchte, besteht darin, sicherzustellen, dass einige spezifische Grenzen-Checks beseitigt worden sind. Ich schätze, wenn sie ohne Inline eliminiert werden, werden sie auch mit Inline eliminiert (aber das Umgekehrte ist nicht unbedingt wahr, da der umgebende Code dem Compiler helfen könnte, mehr Überprüfungen zu eliminieren). Gibt es eine bessere Möglichkeit, die eigenständige Assembly der Funktion zu sehen, als einen öffentlichen nichtlinearen Wrapper für jede Funktion zu erstellen? – Dogbert

+0

@Dogbert: * Ich schätze, wenn sie ohne Inline eliminiert werden, werden sie auch mit Inline eliminiert (aber das Umgekehrte ist nicht unbedingt wahr, da der umgebende Code dem Compiler helfen könnte, mehr Checks zu eliminieren) * => was scheint vernünftig kann nicht immer halten; Ich wundere mich, wenn die Reihenfolge, in der Optimierungen angewendet werden, die Elision von Grenzen nicht verhindern kann, indem vorherige Optimierungen die Gewässer trüben, wenn die Funktion inline ist: –

Verwandte Themen