LLVM
LLVM (Low Level Virtual Machine) — это набор компиляторных технологий и инструментов с открытым исходным кодом, предназначенных для оптимизации, компиляции, компоновки и выполнения программ на различных языках программирования. Проект включает в себя модульные компоненты, которые позволяют разработчикам создавать собственные компиляторы, статические анализаторы кода, инструменты для отладки и другие средства разработки. LLVM не является традиционной виртуальной машиной, а представляет собой инфраструктуру для промежуточного представления (IR) кода, которая обеспечивает переносимость и высокую производительность.
История
Проект LLVM был начат в 2000 году исследователем Викрамом Адве (Vikram Adve) и аспирантом Крисом Латтнером (Chris Lattner) в Иллинойсском университете в Урбане-Шампейне. Первоначально он разрабатывался как исследовательская платформа для изучения методов динамической компиляции и оптимизации. В 2003 году была выпущена первая публичная версия. В 2005 году компания Apple Inc. наняла Криса Латтнера и начала активно использовать LLVM в своих продуктах, включая компилятор для языка Objective-C и инструменты разработки Xcode. В 2011 году LLVM стал основой для компилятора Clang, который заменил GCC в экосистеме Apple. В 2012 году проект был передан под управление некоммерческой организации LLVM Foundation, которая координирует его развитие и поддерживает сообщество разработчиков. С тех пор LLVM стал стандартом де-факто для многих индустриальных и академических проектов, включая компиляторы для языков C, C++, Rust, Swift, Julia и других.
Архитектура
LLVM построен по модульному принципу, что позволяет использовать его компоненты независимо друг от друга. Основные элементы архитектуры:
Промежуточное представление (LLVM IR)
LLVM IR — это низкоуровневый, типизированный, трёхадресный код, который служит мостом между исходным кодом и машинным кодом. Он обладает следующими свойствами:
- Переносимость: IR не зависит от архитектуры целевой платформы.
- Оптимизация: IR позволяет применять универсальные оптимизации (например, свёртку констант, удаление мёртвого кода, инлайнинг) до генерации машинного кода.
- Форматы: IR может быть представлен в трёх формах: текстовый (.ll), бинарный (.bc) и встроенный в память.
Фронтенды
Фронтенды (frontends) отвечают за синтаксический анализ исходного кода и преобразование его в LLVM IR. Наиболее известные фронтенды:
- Clang — компилятор для языков C, C++, Objective-C и Objective-C++. Он обеспечивает высокую скорость компиляции, подробные сообщения об ошибках и совместимость с GCC.
- LLVM-GCC — устаревший фронтенд, основанный на GCC, который использовался на ранних этапах проекта.
- Rustc — компилятор языка Rust, который использует LLVM в качестве бэкенда.
- Swiftc — компилятор языка Swift, разработанный Apple.
- Flang — фронтенд для языка Fortran.
- MLIR — мультиуровневое промежуточное представление, используемое для машинного обучения и других специализированных задач.
Оптимизатор (Pass Manager)
Оптимизатор LLVM состоит из набора проходов (passes), которые обрабатывают LLVM IR. Проходы могут быть:
- Анализирующие — собирают информацию о коде (например, граф потока управления, зависимости данных).
- Трансформирующие — изменяют IR для улучшения производительности или уменьшения размера (например, распространение констант, векторизация, удаление неиспользуемого кода).
Оптимизатор поддерживает как стандартные уровни оптимизации (-O0, -O1, -O2, -O3, -Os, -Oz), так и пользовательские конвейеры.
Бэкенды
Бэкенды (backends) генерируют машинный код для конкретных архитектур из LLVM IR. LLVM поддерживает широкий спектр процессоров, включая:
- x86 и x86-64 (Intel, AMD)
- ARM и AArch64 (включая Apple Silicon)
- RISC-V
- MIPS
- PowerPC
- SPARC
- WebAssembly (wasm)
- GPU (NVIDIA PTX, AMD GCN, Intel SPIR-V)
Бэкенды также включают генерацию отладочной информации (DWARF), ассемблерный код и объектные файлы.
Ключевые компоненты
Помимо ядра LLVM, в проект входят несколько важных инструментов и библиотек:
Clang
Clang — это фронтенд для языков семейства C, который также включает в себя:
- Статический анализатор — находит потенциальные ошибки (например, утечки памяти, неопределённое поведение) без выполнения программы.
- Инструменты для рефакторинга — автоматическое изменение кода (например, переименование переменных, изменение сигнатур функций).
- Поддержка санитайзеров — AddressSanitizer (ASan), UndefinedBehaviorSanitizer (UBSan), MemorySanitizer (MSan) и другие для обнаружения ошибок во время выполнения.
LLDB
LLDB — это отладчик, использующий LLVM и Clang для анализа кода. Он поддерживает отладку на уровне исходного кода, машинного кода и ассемблера, а также имеет встроенный скриптовый движок на Python.
LLD
LLD — это быстрый компоновщик (линкер), который заменяет GNU ld. Он поддерживает форматы ELF, COFF, Mach-O и WebAssembly, и отличается высокой скоростью работы и низким потреблением памяти.
libc++ и libc++abi
libc++ — это реализация стандартной библиотеки C++ (включая STL), а libc++abi — поддержка ABI (Application Binary Interface) для C++. Они разрабатываются в рамках проекта LLVM и оптимизированы для работы с Clang.
Polly
Polly — это оптимизатор, основанный на полиэдральной модели, который выполняет высокоуровневые преобразования циклов (например, распараллеливание, векторизацию, развёртывание) для повышения производительности.
Применение
LLVM широко используется в различных областях разработки программного обеспечения:
Компиляция языков программирования
Благодаря модульной архитектуре, LLVM служит основой для компиляторов многих языков:
- C/C++/Objective-C — через Clang.
- Rust — официальный компилятор rustc.
- Swift — компилятор Apple.
- Julia — использует LLVM для JIT-компиляции.
- Kotlin/Native — компилирует Kotlin в нативный код.
- Crystal — язык с синтаксисом, подобным Ruby, компилируется через LLVM.
- Zig — системный язык, использующий LLVM в качестве бэкенда.
Разработка инструментов анализа
LLVM используется для создания статических анализаторов, инструментов проверки типов и рефакторинга. Например, Clang Static Analyzer встроен в Xcode и используется для поиска ошибок в коде на C/C++.
Оптимизация кода
LLVM применяется в высокопроизводительных вычислениях (HPC) для автоматической векторизации, распараллеливания и оптимизации под конкретные архитектуры. Проект Polly позволяет выполнять полиэдральные преобразования, которые улучшают локальность данных и использование кэша.
Встраиваемые системы и мобильные платформы
LLVM используется для компиляции кода под Android (через NDK) и iOS (через Xcode). Благодаря поддержке ARM и RISC-V, он популярен в разработке для встраиваемых устройств.
Веб-технологии
LLVM используется в проектах, связанных с WebAssembly, например, компилятор Emscripten преобразует C/C++ код в WebAssembly, используя LLVM в качестве бэкенда.
Интересные факты
- Название «LLVM» изначально расшифровывалось как «Low Level Virtual Machine», но с развитием проекта это значение устарело, и теперь LLVM — это просто бренд, не имеющий прямой расшифровки.
- LLVM не является виртуальной машиной в классическом смысле (как JVM или .NET CLR), так как не выполняет код напрямую, а генерирует машинный код для целевой платформы.
- Крис Латтнер, создатель LLVM, покинул Apple в 2017 году и работал над проектом Swift, а затем в Google над языком Mojo.
- LLVM поддерживает более 50 различных архитектур процессоров, включая экспериментальные (например, для квантовых вычислений).
- Проект LLVM распространяется под лицензией Apache 2.0 с исключением LLVM, что позволяет использовать его в коммерческих продуктах без обязательного открытия исходного кода.
Критика
Несмотря на широкое распространение, LLVM имеет некоторые недостатки:
- Сложность архитектуры: из-за модульности и большого количества проходов, настройка оптимизаций может быть нетривиальной.
- Производительность компиляции: для некоторых языков (например, C++) компиляция через Clang может быть медленнее, чем через GCC, хотя в других случаях она быстрее.
- Зависимость от сообщества: развитие новых бэкендов и оптимизаций часто зависит от сторонних разработчиков, что может приводить к неравномерной поддержке архитектур.
- Ограничения в поддержке некоторых языков: например, фронтенд для Fortran (Flang) долгое время был экспериментальным и не достиг зрелости GCC.
Источники
- LLVM Foundation. «The LLVM Compiler Infrastructure.» Официальная документация проекта.
- Lattner, C., & Adve, V. (2004). «LLVM: A Compilation Framework for Lifelong Program Analysis & Transformation.» Proceedings of the International Symposium on Code Generation and Optimization.
- Aho, A. V., Lam, M. S., Sethi, R., & Ullman, J. D. (2006). «Compilers: Principles, Techniques, and Tools.» (2nd ed.). Addison-Wesley.
- «Clang: a C language family frontend for LLVM.» Официальная документация Clang.
- «LLDB: The LLVM Debugger.» Официальная документация LLDB.
BFOmetr — база данных и аналитика по компаниям России.
На главную BFOmetr →