Voici un simple fichier C avec une définition d'énumération et une main
fonction:
enum days {MON, TUE, WED, THU};
int main() {
enum days d;
d = WED;
return 0;
}
Il transpile vers le LLVM IR suivant:
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
est évidemment la d
variable, qui se voit attribuer 2. À quoi %1
correspond si zéro est retourné directement?
c
llvm
llvm-codegen
macleginn
la source
la source
clang-9 -S -emit-llvm simple.c
main
( godbolt.org/z/kEtS-s ). Le lien montre comment l'assembly est mappé à la sourcemain
, la mystérieuse variable supplémentaire disparaît. Fait intéressant, il disparaît également si vous omettezreturn
complètement la déclaration (ce qui est légal pourmain
en C et équivalent àreturn 0;
).main
commeint main(int argc, char **argv)
vous le voyezargc
etargv
copié sur la pile, mais la mystérieuse variable zéro est toujours là en plus d'eux.Réponses:
Ce
%1
registre a été généré par clang pour gérer plusieurs instructions de retour dans une fonction . Imaginez que vous disposiez d'une fonction pour calculer la factorielle d'un entier. Au lieu de l'écrire comme çaVous feriez probablement ça
Pourquoi? Parce que Clang insérera cette
result
variable qui contient la valeur de retour pour vous. Yay. C'est le but exact de cela%1
. Regardez l'ir pour une version légèrement modifiée de votre code.Code modifié,
IR,
Maintenant vous voyez que se
%1
rendre utile hein? Comme les autres l'ont souligné, pour les fonctions avec une seule instruction de retour, cette variable sera probablement supprimée par l'une des passes optimales de llvm.la source
Pourquoi est-ce important - quel est le problème réel?
Je pense que la réponse la plus profonde que vous cherchez pourrait être: l'architecture de LLVM est basée sur des interfaces assez simples et de nombreuses passes. Les frontends doivent générer du code correct, mais il ne doit pas nécessairement être un bon code. Ils peuvent faire la chose la plus simple qui fonctionne.
Dans ce cas, Clang génère quelques instructions qui s'avèrent ne pas être utilisées pour quoi que ce soit. Ce n'est généralement pas un problème, car une partie de LLVM supprimera les instructions superflues. Clang espère que cela se produira. Clang n'a pas besoin d'éviter d'émettre du code mort; sa mise en œuvre peut se concentrer sur l'exactitude, la simplicité, la testabilité, etc.
la source
Parce que Clang a terminé l'analyse syntaxique, mais LLVM n'a même pas commencé avec l'optimisation.
Le frontal Clang a généré des IR (représentation intermédiaire) et non du code machine. Ces variables sont les SSA (Single Static Assignments); ils ne sont pas encore liés aux registres et en fait après l'optimisation, ils ne le seront jamais car ils sont redondants.
Ce code est une représentation quelque peu littérale de la source. C'est ce qui frappe LLVM pour l'optimisation. Fondamentalement, LLVM commence par cela et optimise à partir de là. En effet, pour les versions 10 et x86_64, llc -O2 finira par générer:
la source