Существует несколько причин, по которым LLVM выпускает собственную систему RTTI. Эта система проста и мощна и описана в разделе Руководства программиста LLVM . Как указал другой автор, Стандарты кодирования поднимают две основные проблемы с C ++ RTTI: 1) стоимость места и 2) низкая производительность при его использовании.
Стоимость пространства RTTI довольно высока: каждый класс с vtable (по крайней мере, один виртуальный метод) получает информацию RTTI, которая включает в себя имя класса и информацию о его базовых классах. Эта информация используется для реализации оператора typeid , а также dynamic_cast . Поскольку эта стоимость оплачивается для каждого класса с помощью vtable (и нет, оптимизация PGO и времени соединения не помогает, потому что vtable указывает на информацию RTTI), LLVM собирается с -fno-rtti. Опытным путем это экономит порядка 5-10% от размера исполняемого файла, что довольно существенно. LLVM не нуждается в эквиваленте typeid, поэтому хранение имен (среди прочего в type_info) для каждого класса - просто трата пространства.
Низкую производительность довольно легко увидеть, если вы проведете какой-то тест или посмотрите на код, сгенерированный для простых операций. Оператор LLVM isa <> обычно компилируется до одной загрузки и сравнения с константой (хотя классы управляют этим на основе того, как они реализуют свой метод classof). Вот тривиальный пример:
#include "llvm/Constants.h"
using namespace llvm;
bool isConstantInt(Value *V) { return isa<ConstantInt>(V); }
Это компилируется в:
$ clang t.cc -S -o - -O3 -I$HOME/llvm/include -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -mkernel -fomit-frame-pointer
...
__Z13isConstantIntPN4llvm5ValueE:
cmpb $9, 8(%rdi)
sete %al
movzbl %al, %eax
ret
который (если вы не читаете сборку) является загрузкой и сравнивается с константой. Напротив, эквивалент с dynamic_cast:
#include "llvm/Constants.h"
using namespace llvm;
bool isConstantInt(Value *V) { return dynamic_cast<ConstantInt*>(V) != 0; }
, который сводится к:
clang t.cc -S -o - -O3 -I$HOME/llvm/include -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -mkernel -fomit-frame-pointer
...
__Z13isConstantIntPN4llvm5ValueE:
pushq %rax
xorb %al, %al
testq %rdi, %rdi
je LBB0_2
xorl %esi, %esi
movq $-1, %rcx
xorl %edx, %edx
callq ___dynamic_cast
testq %rax, %rax
setne %al
LBB0_2:
movzbl %al, %eax
popq %rdx
ret
Это гораздо больше кода, но убийцей является вызов __dynamic_cast, который затем должен разбираться со структурами данных RTTI и выполнять очень общий, динамически вычисляемый анализ всего этого. Это на несколько порядков медленнее, чем загрузка и сравнение.
Хорошо, хорошо, так медленнее, почему это имеет значение? Это важно, потому что LLVM выполняет МНОГО проверок типов. Многие части оптимизаторов построены вокруг сопоставления с образцом определенных конструкций в коде и выполнения подстановок на них. Например, вот некоторый код для сопоставления простого шаблона (который уже знает, что Op0 / Op1 являются левой и правой частью операции целочисленного вычитания):
// (X*2) - X -> X
if (match(Op0, m_Mul(m_Specific(Op1), m_ConstantInt<2>())))
return Op1;
Оператор сопоставления и m_ * являются шаблонными метапрограммами, которые сводятся к серии вызовов isa / dyn_cast, каждый из которых должен выполнять проверку типа. Использование dynamic_cast для такого рода детального сопоставления с образцом было бы жестоко и показывало бы невероятно медленный.
Наконец, есть еще один момент, который относится к выразительности. различные операторы 'rtti' , которые использует LLVM, используются для выражения разных вещей: проверка типа, dynamic_cast, принудительное (утверждение) приведение, нулевая обработка и т. Д. C ++ dynamic_cast (изначально) не предлагает ни одной из этих функций .
В конце концов, есть два способа взглянуть на эту ситуацию. С другой стороны, C ++ RTTI слишком узко определен для того, что хотят многие люди (полное отражение), и слишком медленен, чтобы быть полезным даже для простых вещей, таких как LLVM. С положительной стороны, язык C ++ достаточно мощный, чтобы мы могли определять такие абстракции как библиотечный код и отказаться от использования языковой функции. Одна из моих любимых вещей в C ++ - насколько мощными и элегантными могут быть библиотеки. RTTI даже не очень высоко среди моих наименее любимых функций C ++ :)!
-Крис