Вот простой C-файл с определением перечисления и main
функцией:
enum days {MON, TUE, WED, THU};
int main() {
enum days d;
d = WED;
return 0;
}
Он переносится в следующий LLVM IR:
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
это, очевидно, d
переменная, которой присвоено 2. Что %1
соответствует, если ноль возвращается напрямую?
c
llvm
llvm-codegen
macleginn
источник
источник
clang-9 -S -emit-llvm simple.c
main
( godbolt.org/z/kEtS-s ). Ссылка показывает, как сборка отображается на источникmain
, таинственная дополнительная переменная исчезнет. Интересно, что он также исчезает, если вы полностью опускаетеreturn
утверждение (что допустимо дляmain
C и эквивалентноreturn 0;
).main
какint main(int argc, char **argv)
видите,argc
иargv
копируете в стек, но загадочная нулевая переменная все еще существует в дополнение к ним.Ответы:
Этот
%1
регистр был создан clang для обработки нескольких операторов return в функции . Представьте, что у вас есть функция для вычисления факториала целого числа. Вместо того, чтобы писать это такВы, вероятно, сделаете это
Почему? Потому что Clang вставит ту
result
переменную, которая содержит возвращаемое значение для вас. Ура. Это точная цель этого%1
. Посмотрите на ИК для немного измененной версии вашего кода.Модифицированный код,
ИК,
Теперь вы видите, что
%1
делает себя полезным, а? Как уже отмечали другие, для функций только с одним оператором return эта переменная, вероятно, будет удалена одним из оптимистических проходов llvm.источник
Почему это важно - какова реальная проблема?
Я думаю, что более глубокий ответ, который вы ищете, может быть таким: архитектура LLVM основана на довольно простых интерфейсах и множестве проходов. Интерфейсы должны генерировать правильный код, но это не обязательно должен быть хороший код. Они могут сделать самое простое, что работает.
В этом случае Clang генерирует пару инструкций, которые, как оказалось, ни для чего не используются. Как правило, это не проблема, потому что некоторая часть LLVM избавится от лишних инструкций. Clang верит, что это произойдет. Clang не нужно избегать испускания мертвого кода; его реализация может быть направлена на корректность, простоту, тестируемость и т. д.
источник
Потому что Clang сделан с синтаксическим анализом, но LLVM даже не начал с оптимизации.
Внешний интерфейс Clang сгенерировал IR (промежуточное представление), а не машинный код. Эти переменные - SSA (одиночные статические назначения); они еще не были связаны с регистрами и фактически после оптимизации никогда не будут, потому что они избыточны.
Этот код является несколько буквальным представлением источника. Это то, что раздается LLVM для оптимизации. По сути, LLVM начинается с этого и оптимизируется оттуда. Действительно, для версии 10 и x86_64 llc -O2 в итоге сгенерирует:
источник