Il y a plusieurs raisons pourquoi LLVM roule ses propres RTTI système. Ce système est simple et puissant, et décrits dans une section de la LLVM Manuel du Programmeur. Comme une autre affiche a souligné, les Normes de Codage soulève deux problèmes majeurs avec C++ RTTI: 1) le coût de l'espace et 2) la mauvaise performance de l'utiliser.
Le coût de l'espace de RTTI est assez élevé: chaque classe avec une vtable (au moins une méthode virtuelle) obtient RTTI de l'information, qui comprend le nom de la classe et de l'information au sujet de ses classes de base. Cette information est utilisée pour mettre en œuvre le typeid de l'opérateur ainsi que dynamic_cast. Parce que ce coût est payé pour chaque classe avec une vtable (et non, PGO et lien-temps optimisations ne vous aide pas, parce que la vtable de points pour le RTTI info) LLVM construit avec -fno-rtti. Empiriquement, cela permet d'économiser de l'ordre de 5 à 10% de la taille de l'exécutable, ce qui est assez considérable. LLVM n'a pas besoin d'un équivalent de typeid, donc les garder autour de noms (parmi d'autres choses dans type_info) pour chaque classe est juste un gaspillage d'espace.
La mauvaise performance est assez facile de voir si vous faites un peu de benchmarking ou de regarder le code généré pour les opérations simples. La LLVM isa<> opérateur généralement compile le bas à une seule charge et une comparaison avec une constante (bien que les classes de contrôle basée sur la façon dont ils mettent en œuvre leurs classof méthode). Voici un exemple trivial:
#include "llvm/Constants.h"
using namespace llvm;
bool isConstantInt(Value *V) { return isa<ConstantInt>(V); }
Cette compile:
$ clang t.cc -S -o - -O3-I$HOME/llvm/include -D__STDC_LIMIT_MACROS -D__STDC_CONSTANTS_MACROS -mkernel -fomit-frame-pointer
...
__Z13isConstantIntPN4llvm5ValueE:
cmpb $9, 8(%rdi)
sete %al
movzbl %al, %eax
ret
(si vous n'avez pas lu l'assemblée) est une charge et de la comparer à une constante. En revanche, l'équivalent avec dynamic_cast est:
#include "llvm/Constants.h"
using namespace llvm;
bool isConstantInt(Value *V) { return dynamic_cast<ConstantInt*>(V) != 0; }
qui compile:
clang t.cc -S -o - -O3-I$HOME/llvm/include -D__STDC_LIMIT_MACROS -D__STDC_CONSTANTS_MACROS -mkernel -fomit-frame-pointer
...
__Z13isConstantIntPN4llvm5ValueE:
pushq %rax
xorb %al, %al
testq %de l'aqr, %rdi
je LBB0_2
xorl %esi, %esi
movq $-1, %rcx
xorl %edx, %edx
callq ___dynamiques_cast
testq %rax, %rax
setne %al
LBB0_2:
movzbl %al, %eax
popq %rdx
ret
C'est beaucoup plus de code, mais le tueur est l'appel à __dynamiques_exprimés, ce qui a alors à ramper à travers le RTTI structures de données et de faire une très général, calculée dynamiquement à pied à travers ce genre de choses. C'est de plusieurs ordres de grandeur inférieure à celle d'une charge et de les comparer.
Ok, ok, donc c'est plus lent, pourquoi est-ce important? C'est important parce que LLVM fait BEAUCOUP de type de contrôles. De nombreuses parties de la optimiseurs sont construits autour de la correspondance de motif spécifique des constructions dans le code et d'effectuer des substitutions sur eux. Pour exemple, voici un peu de code pour la mise en correspondance d'un modèle simple (qui sait déjà que Op0/Op1 sont la gauche et la droite d'un entier de soustraire l'opération):
// (X*2) - X -> X
if (match(Op0, m_Mul(m_Specific(Op1), m_ConstantInt<2>())))
return Op1;
L'opérateur de match et m_* sont modèle metaprograms qui se résument à une série de isa/dyn_cast appels, dont chacune doit faire une vérification de type. À l'aide de dynamic_cast pour ce genre de fines pattern matching serait brutalement et showstoppingly lent.
Enfin, il y a un autre point, qui est l'un de l'expressivité. Les différents "rtti" opérateurs que LLVM utilise sont utilisés pour exprimer des choses différentes: vérification de type, dynamic_cast, forcé (affirmant) en fonte, la gestion des valeurs null etc. C++de dynamic_cast n'est pas (natif) offrent cette fonctionnalité.
En fin de compte, il y a deux façons de voir cette situation. Sur le côté négatif, C++ RTTI est à la fois trop étroitement définie pour ce que beaucoup de gens veulent (réflexion totale) et est trop lente pour être utile, même pour des choses simples comme ce que LLVM. Sur le côté positif, le langage C++ est assez puissant pour que nous puissions définir des abstractions comme ceci comme code de bibliothèque, et de refuser de l'aide de la fonctionnalité du langage. Une de mes choses préférées au sujet de C++ est comment puissant et élégant, les bibliothèques peuvent être. RTTI n'est pas encore très élevée chez mes fonctionnalités préférées de C++ :) !
-Chris