Hier ist eine einfache C-Datei mit einer Aufzählungsdefinition und einer main
Funktion:
enum days {MON, TUE, WED, THU};
int main() {
enum days d;
d = WED;
return 0;
}
Es wird auf das folgende LLVM-IR übertragen:
define dso_local i32 @main() #0 {
%1 = alloca i32, align 4
%2 = alloca i32, align 4
store i32 0, i32* %1, align 4
store i32 2, i32* %2, align 4
ret i32 0
}
%2
ist offensichtlich die d
Variable, der 2 zugewiesen werden. Was %1
entspricht, wenn Null direkt zurückgegeben wird?
c
llvm
llvm-codegen
Macleginn
quelle
quelle
clang-9 -S -emit-llvm simple.c
main
( godbolt.org/z/kEtS-s ). Der Link zeigt, wie die Assembly der Quelle zugeordnet wirdmain
, verschwindet die mysteriöse zusätzliche Variable. Interessanterweise verschwindet es auch, wenn Sie diereturn
Aussage vollständig weglassen (wasmain
in C legal ist und gleichbedeutend mitreturn 0;
).main
wieint main(int argc, char **argv)
Sie sehen,argc
undargv
auf den Stapel kopieren, aber die mysteriöse Nullvariable zusätzlich zu ihnen noch vorhanden ist.Antworten:
Dieses
%1
Register wurde von clang generiert, um mehrere return-Anweisungen in einer Funktion zu verarbeiten . Stellen Sie sich vor, Sie hätten eine Funktion zum Berechnen der Fakultät einer ganzen Zahl. Anstatt es so zu schreibenSie würden das wahrscheinlich tun
Warum? Weil Clang die
result
Variable einfügt , die den Rückgabewert für Sie enthält. Yay. Das ist genau der Zweck davon%1
. Suchen Sie im ir nach einer leicht modifizierten Version Ihres Codes.Geänderter Code,
IR,
Jetzt siehst du, dass
%1
er sich nützlich macht, oder? Wie die anderen bereits betont haben, wird diese Variable für Funktionen mit nur einer return-Anweisung wahrscheinlich durch einen der optimalen Durchgänge von llvm entfernt.quelle
Warum ist das wichtig - was ist das eigentliche Problem?
Ich denke, die tiefere Antwort, die Sie suchen, könnte sein: Die Architektur von LLVM basiert auf ziemlich einfachen Frontends und vielen Durchgängen. Die Frontends müssen korrekten Code generieren, aber es muss kein guter Code sein. Sie können das Einfachste tun, was funktioniert.
In diesem Fall generiert Clang einige Anweisungen, die sich als für nichts verwendbar herausstellen. Dies ist im Allgemeinen kein Problem, da ein Teil von LLVM überflüssige Anweisungen entfernt. Clang vertraut darauf, dass dies geschieht. Clang muss nicht vermeiden, toten Code auszugeben. Die Implementierung kann sich auf Korrektheit, Einfachheit, Testbarkeit usw. konzentrieren.
quelle
Da Clang mit der Syntaxanalyse fertig ist, hat LLVM noch nicht einmal mit der Optimierung begonnen.
Das Clang-Frontend hat IR (Intermediate Representation) und keinen Maschinencode generiert. Diese Variablen sind SSAs (Single Static Assignments). Sie waren noch nicht an Register gebunden und werden es nach der Optimierung niemals sein, weil sie redundant sind.
Dieser Code ist eine etwas wörtliche Darstellung der Quelle. Es ist das, was LLVM zur Optimierung zur Verfügung stellt. Grundsätzlich beginnt LLVM damit und optimiert von dort aus. In der Tat wird llc -O2 für Version 10 und x86_64 schließlich Folgendes generieren:
quelle