Soweit ich weiß, kann Referenz- / Zeiger-Aliasing die Fähigkeit des Compilers beeinträchtigen, optimierten Code zu generieren, da sie sicherstellen müssen, dass sich die generierte Binärdatei korrekt verhält, wenn die beiden Referenzen / Zeiger tatsächlich Alias sind. Zum Beispiel im folgenden C-Code:
void adds(int *a, int *b) {
*a += *b;
*a += *b;
}
Wenn es clang version 6.0.0-1ubuntu2 (tags/RELEASE_600/final)
mit dem -O3
Flag kompiliert wird , wird es ausgegeben
0000000000000000 <adds>:
0: 8b 07 mov (%rdi),%eax
2: 03 06 add (%rsi),%eax
4: 89 07 mov %eax,(%rdi) # The first time
6: 03 06 add (%rsi),%eax
8: 89 07 mov %eax,(%rdi) # The second time
a: c3 retq
Hier speichert der Code (%rdi)
zweimal in case int *a
und int *b
alias.
Wenn wir dem Compiler ausdrücklich mitteilen, dass diese beiden Zeiger keinen Alias mit dem restrict
Schlüsselwort haben können:
void adds(int * restrict a, int * restrict b) {
*a += *b;
*a += *b;
}
Dann wird Clang eine optimierte Version des Binärcodes ausgeben:
0000000000000000 <adds>:
0: 8b 06 mov (%rsi),%eax
2: 01 c0 add %eax,%eax
4: 01 07 add %eax,(%rdi)
6: c3 retq
Da Rust (außer in unsicherem Code) sicherstellt, dass zwei veränderbare Referenzen keinen Alias haben können, würde ich denken, dass der Compiler in der Lage sein sollte, die optimierte Version des Codes auszugeben.
Als ich mit dem Code testen unten und kompilieren Sie es mit rustc 1.35.0
mit -C opt-level=3 --emit obj
,
#![crate_type = "staticlib"]
#[no_mangle]
fn adds(a: &mut i32, b: &mut i32) {
*a += *b;
*a += *b;
}
es erzeugt:
0000000000000000 <adds>:
0: 8b 07 mov (%rdi),%eax
2: 03 06 add (%rsi),%eax
4: 89 07 mov %eax,(%rdi)
6: 03 06 add (%rsi),%eax
8: 89 07 mov %eax,(%rdi)
a: c3 retq
Dies nutzt die Garantie nicht aus a
und b
kann nicht alias.
Liegt das daran, dass sich der aktuelle Rust-Compiler noch in der Entwicklung befindet und noch keine Alias-Analyse für die Optimierung integriert hat?
Liegt das daran, dass es immer noch eine Chance gibt a
und b
Alias auch in sicherem Rust sein könnte?
unsafe
Aliasing veränderlicher Verweise auch im Code nicht zulässig ist und zu undefiniertem Verhalten führt. Sie können Aliasing-Rohzeiger verwenden, aber mitunsafe
Code können Sie die Rust-Standardregeln nicht ignorieren. Es ist nur ein weit verbreitetes Missverständnis und daher erwähnenswert.+=
Operationen im Körper vonadds
als neu interpretiert werden können*a = *a + *b + *b
. Wenn die Zeiger keinen Alias haben, können Sie sogarb* + *b
in der zweiten ASM-Liste sehen, was sie bedeuten :2: 01 c0 add %eax,%eax
. Wenn sie jedoch einen Alias verwenden, können sie dies nicht, da er*b
zum zweiten Mal einen anderen Wert enthält als beim ersten Mal (den Wert, den Sie online4:
in der ersten ASM-Liste speichern ).Antworten:
Rust ursprünglich tat das LLVM ermöglichen
noalias
Attribut, aber dieses verursacht miscompiled Code . Wenn alle unterstützten LLVM-Versionen den Code nicht mehr falsch kompilieren, wird er wieder aktiviert .Wenn Sie
-Zmutable-noalias=yes
den Compileroptionen hinzufügen , erhalten Sie die erwartete Assembly:Einfach ausgedrückt, Rust hat das Äquivalent des
restrict
Schlüsselworts von C überall platziert , weitaus häufiger als jedes übliche C-Programm. Dies übte Eckfälle von LLVM mehr aus, als es richtig handhaben konnte. Es stellt sich heraus, dass C- und C ++ - Programmierer einfach nichtrestrict
so häufig verwenden wie&mut
in Rust.Dies ist mehrfach passiert .
noalias
aktiviertnoalias
deaktiviertnoalias
aktiviertnoalias
deaktiviertVerwandte Rostprobleme
Aktueller Fall
Vorheriger Fall
Andere
quelle
restrict
sowohl Clang als auch GCC verwenden und falsch kompilieren. Es ist nicht auf Sprachen beschränkt, die nicht „C ++ genug“ sind, es sei denn, Sie zählen C ++ selbst in dieser Gruppe .noalias
Zeiger bei der Ausführung nicht vollständig berücksichtigt. Es wurden neue Zeiger basierend auf Eingabezeigern erstellt, wobei dasnoalias
Attribut nicht ordnungsgemäß kopiert wurde , obwohl die neuen Zeiger einen Alias hatten.