LLVM — это набор технологий компилятора и инструментальной цепочки [5] , которые можно использовать для разработки интерфейса для любого языка программирования и бэкэнда для любой архитектуры набора инструкций . LLVM разработан на основе независимого от языка промежуточного представления (IR), которое служит переносимым высокоуровневым языком ассемблера , который можно оптимизировать с помощью различных преобразований за несколько проходов. [6] Название LLVM изначально расшифровывалось как Low Level Virtual Machine (виртуальная машина низкого уровня), хотя проект расширился, и официально это название больше не является аббревиатурой .
LLVM написан на C++ и предназначен для оптимизации во время компиляции , компоновки , выполнения и «времени простоя». Первоначально реализованный для C и C++, независимый от языка дизайн LLVM с тех пор породил широкий спектр интерфейсов: языки с компиляторами, которые используют LLVM (или которые напрямую не используют LLVM, но могут генерировать скомпилированные программы как LLVM IR), включают ActionScript , Ada , C# для .NET , [7] [8] [9] Common Lisp , PicoLisp , Crystal , CUDA , D , Delphi , Dylan , Forth , [10] Fortran , FreeBASIC , Free Pascal , Halide , Haskell , Java bytecode , Julia , Kotlin , язык G LabVIEW , [11] [12] Lua , Objective-C , OpenCL , [13] SQL и PLpgSQL PostgreSQL , [14] Ruby , [15] Rust , [16] Scala , [17] [18] Свифт , Ксоджо и Зиг .
Проект LLVM стартовал в 2000 году в Университете Иллинойса в Урбане-Шампейне под руководством Викрама Адве и Криса Латтнера . Первоначально LLVM был разработан как исследовательская инфраструктура для изучения методов динамической компиляции для статических и динамических языков программирования. LLVM был выпущен под лицензией University of Illinois/NCSA Open Source License [3] , разрешающей лицензией свободного программного обеспечения . В 2005 году Apple Inc. наняла Латтнера и сформировала команду для работы над системой LLVM для различных целей в системах разработки Apple. [19] LLVM является неотъемлемой частью инструментов разработки Xcode от Apple для macOS и iOS с Xcode 4 в 2011 году. [20]
В 2006 году Латтнер начал работать над новым проектом под названием Clang . Сочетание фронтенда Clang и бэкенда LLVM называется Clang/LLVM или просто Clang.
Название LLVM изначально было аббревиатурой от Low Level Virtual Machine (виртуальная машина низкого уровня) . Однако проект LLVM превратился в зонтичный проект, имеющий мало отношения к тому, что большинство современных разработчиков считают виртуальной машиной . Это сделало аббревиатуру «запутанной» и «неуместной», и с 2011 года LLVM «официально больше не является аббревиатурой» [21] , а брендом, который применяется к зонтичному проекту LLVM. [22] Проект охватывает промежуточное представление LLVM (IR), отладчик LLVM , реализацию LLVM стандартной библиотеки C++ (с полной поддержкой C++11 и C++14 [23] ) и т. д. LLVM администрируется LLVM Foundation. Инженер-компилятор Таня Латтнер стала его президентом в 2014 году [24] и занимала эту должность по состоянию на март 2024 года [обновлять][ 25]
«За разработку и внедрение LLVM» Ассоциация вычислительной техники вручила Викраму Адве, Крису Латтнеру и Эвану Ченгу премию ACM Software System Award 2012. [26]
Первоначально проект был доступен под лицензией UIUC . После выпуска v9.0.0 в 2019 году [27] LLVM перелицензировался на Apache License 2.0 с исключениями LLVM. [3] По состоянию на ноябрь 2022 года [обновлять]около 400 вкладов не были перелицензированы. [28] [29]
LLVM может предоставить средние слои полной системы компилятора, беря код промежуточного представления (IR) из компилятора и выдавая оптимизированный IR. Этот новый IR затем может быть преобразован и связан с машинно-зависимым кодом языка ассемблера для целевой платформы. LLVM может принимать IR из набора инструментов GNU Compiler Collection (GCC) , что позволяет использовать его с широким спектром существующих фронтендов компиляторов, написанных для этого проекта. LLVM также может быть собран с помощью gcc после версии 7.5. [30]
LLVM также может генерировать перемещаемый машинный код во время компиляции или компоновки или даже двоичный машинный код во время выполнения.
LLVM поддерживает набор инструкций и систему типов, не зависящих от языка . [6] Каждая инструкция находится в статической форме одиночного присваивания (SSA), что означает, что каждая переменная (называемая типизированным регистром) назначается один раз, а затем замораживается. Это помогает упростить анализ зависимостей между переменными. LLVM позволяет статически компилировать код, как это делается в традиционной системе GCC, или оставлять для поздней компиляции из IR в машинный код с помощью компиляции «на лету» (JIT), аналогично Java . Система типов состоит из основных типов, таких как целые числа или числа с плавающей точкой , и пяти производных типов : указатели , массивы , векторы , структуры и функции . Конструкция типа в конкретном языке может быть представлена путем объединения этих основных типов в LLVM. Например, класс в C++ может быть представлен смесью структур, функций и массивов указателей на функции .
Компилятор LLVM JIT может оптимизировать ненужные статические ветви из программы во время выполнения, и, таким образом, полезен для частичной оценки в случаях, когда программа имеет много опций, большинство из которых можно легко определить как ненужные в определенной среде. Эта функция используется в конвейере OpenGL Mac OS X Leopard (v10.5) для обеспечения поддержки отсутствующих аппаратных функций. [31]
Графический код в стеке OpenGL можно оставить в промежуточном представлении, а затем скомпилировать при запуске на целевой машине. В системах с высокопроизводительными графическими процессорами (GPU) результирующий код остается довольно тонким, передавая инструкции на GPU с минимальными изменениями. В системах с низкопроизводительными GPU LLVM будет компилировать дополнительные процедуры, которые выполняются на локальном центральном процессоре (CPU), эмулируя инструкции, которые GPU не может выполнить внутренне. LLVM улучшил производительность на низкопроизводительных машинах с использованием чипсетов Intel GMA . Похожая система была разработана в рамках Gallium3D LLVMpipe и включена в оболочку GNOME , чтобы позволить ей работать без загрузки надлежащего драйвера 3D-оборудования. [32]
В 2011 году программы, скомпилированные с помощью GCC, в среднем на 10% превосходили программы, скомпилированные с помощью LLVM. [33] [34] В 2013 году phoronix сообщил, что LLVM догнал GCC, компилируя двоичные файлы примерно с одинаковой производительностью. [35]
LLVM стал зонтичным проектом, содержащим несколько компонентов.
LLVM изначально был написан как замена существующему генератору кода в стеке GCC, [36] и многие из фронтендов GCC были изменены для работы с ним, что привело к ныне несуществующему набору LLVM-GCC. Изменения обычно включают шаг GIMPLE -to-LLVM IR, так что оптимизаторы и кодеген LLVM можно использовать вместо системы GIMPLE GCC. Apple была значительным пользователем LLVM-GCC через Xcode 4.x (2013). [37] [38] Такое использование фронтенда GCC считалось в основном временной мерой, но с появлением Clang и преимуществ LLVM и современной и модульной кодовой базы Clang (а также скорости компиляции) оно в основном устарело.
В настоящее время [ на? ] LLVM поддерживает компиляцию Ada , C , C++ , D , Delphi , Fortran , Haskell , Julia , Objective-C , Rust и Swift с использованием различных интерфейсов .
Широкий интерес к LLVM привел к нескольким попыткам разработать новые интерфейсы для многих языков. Наибольшее внимание привлек Clang, новый компилятор, поддерживающий C, C++ и Objective-C. Clang, в первую очередь поддерживаемый Apple, нацелен на замену компилятора C/Objective-C в системе GCC на систему, которая легче интегрируется с интегрированными средами разработки (IDE) и имеет более широкую поддержку многопоточности . Поддержка директив OpenMP была включена в Clang с версии 3.8. [39]
Компилятор Utrecht Haskell может генерировать код для LLVM. Хотя генератор находился на ранних стадиях разработки, во многих случаях он был более эффективен, чем генератор кода C. [40] Бэкэнд Glasgow Haskell Compiler (GHC) использует LLVM и достигает 30% ускорения скомпилированного кода по сравнению с компиляцией собственного кода через GHC или генерацию кода C с последующей компиляцией, пропуская только один из многих методов оптимизации, реализованных GHC. [41]
Многие другие компоненты находятся на разных стадиях разработки, включая, помимо прочего, компилятор Rust , интерфейс байт-кода Java , интерфейс Common Intermediate Language (CIL), реализацию Ruby 1.9 для MacRuby , различные интерфейсы для Standard ML и новый распределитель регистров раскраски графов . [ необходима ссылка ]
Ядром LLVM является промежуточное представление (IR), низкоуровневый язык программирования, похожий на ассемблер. IR — это строго типизированный набор инструкций компьютера с сокращенным набором команд (RISC), который абстрагируется от большинства деталей цели. Например, соглашение о вызовах абстрагируется с помощью call
и ret
инструкций с явными аргументами. Кроме того, вместо фиксированного набора регистров IR использует бесконечный набор временных переменных вида %0, %1 и т. д. LLVM поддерживает три эквивалентные формы IR: человекочитаемый формат ассемблера, [42] формат в памяти, подходящий для фронтендов, и плотный формат биткода для сериализации. Простая программа «Hello, world!» в формате IR:
@.str = внутренняя константа [ 14 x i8 ] c "Привет, мир\0A\00" объявить i32 @printf ( ptr , ...) определить i32 @main ( i32 %argc , ptr %argv ) nounwind { запись: %tmp1 = getelementptr [ 14 x i8 ], ptr @.str , i32 0 , i32 0 %tmp2 = вызвать i32 ( ptr , ...) @printf ( ptr %tmp1 ) nounwind ret i32 0 }
Множество различных соглашений, используемых и функций, предоставляемых различными целями, означают, что LLVM не может по-настоящему создать целенезависимый IR и перенацелить его, не нарушая некоторые установленные правила. Примеры зависимости от цели, выходящие за рамки того, что явно указано в документации, можно найти в предложении 2011 года для "wordcode", полностью независимого от цели варианта LLVM IR, предназначенного для распространения в Интернете. [43] Более практичным примером является PNaCl . [44]
Проект LLVM также вводит другой тип промежуточного представления, называемый MLIR [45] , который помогает строить многократно используемую и расширяемую инфраструктуру компилятора, используя архитектуру плагинов, называемую Dialect. [46] Он позволяет использовать более высокоуровневую информацию о структуре программы в процессе оптимизации, включая полиэдральную компиляцию .
В версии 16 LLVM поддерживает множество наборов инструкций , включая IA-32 , x86-64 , ARM , Qualcomm Hexagon , LoongArch , M68K , MIPS , NVIDIA Parallel Thread Execution (PTX, также называемый NVPTX в документации LLVM), PowerPC , AMD TeraScale , [47] самые последние графические процессоры AMD (также называемые AMDGPU в документации LLVM), [48] SPARC , z/Architecture (также называемый SystemZ в документации LLVM) и XCore .
Некоторые функции недоступны на некоторых платформах. Большинство функций присутствуют для IA-32, x86-64, z/Architecture, ARM и PowerPC. [49] RISC-V поддерживается с версии 7.
В прошлом LLVM также поддерживал другие бэкэнды, полностью или частично, включая бэкэнд C, Cell SPU , mblaze (MicroBlaze) [50] , AMD R600, DEC/Compaq Alpha ( Alpha AXP ) [51] и Nios2 [52] , но это оборудование в основном устарело, и разработчики LLVM решили, что расходы на поддержку и обслуживание больше не оправданы. [ необходима цитата ]
LLVM также поддерживает WebAssembly в качестве цели, позволяя скомпилированным программам выполняться в средах с поддержкой WebAssembly, таких как Google Chrome / Chromium , Firefox , Microsoft Edge , Apple Safari или WAVM. Компиляторы WebAssembly, совместимые с LLVM, обычно поддерживают в основном немодифицированный исходный код, написанный на C, C++, D, Rust, Nim, Kotlin и нескольких других языках.
Подпроект LLVM machine code (MC) — это фреймворк LLVM для перевода машинных инструкций между текстовыми формами и машинным кодом. Раньше LLVM полагался на системный ассемблер или тот, который предоставлялся набором инструментов, для перевода сборки в машинный код. Интегрированный ассемблер LLVM MC поддерживает большинство целевых платформ LLVM, включая IA-32, x86-64, ARM и ARM64. Для некоторых целевых платформ, включая различные наборы инструкций MIPS, встроенная поддержка сборки доступна, но все еще находится на стадии бета-тестирования. [ необходима цитата ]
Подпроект lld представляет собой попытку разработать встроенный, независимый от платформы компоновщик для LLVM. [53] lld нацелен на устранение зависимости от стороннего компоновщика. По состоянию на май 2017 года [обновлять]lld поддерживает ELF , PE/COFF , Mach-O и WebAssembly [54] в порядке убывания полноты. lld быстрее, чем обе разновидности GNU ld . [ требуется ссылка ]
В отличие от компоновщиков GNU, lld имеет встроенную поддержку оптимизации времени компоновки (LTO). Это позволяет быстрее генерировать код, поскольку обходит использование плагина компоновщика, но с другой стороны запрещает взаимодействие с другими разновидностями LTO. [55]
Проект LLVM включает реализацию стандартной библиотеки C++ под названием libc++, имеющую двойную лицензию: MIT License и UIUC License . [56]
Начиная с версии 9.0.0, лицензия была переоформлена на Apache License 2.0 с исключениями LLVM. [3]
Это реализует набор оптимизаций локальности кэша, а также автопараллелизм и векторизацию с использованием многогранной модели . [57]
llvm-libc — это неполная, готовящаяся к выпуску, независимая от ABI стандартная библиотека C , разработанная проектом LLVM и для него. [58]
Из-за разрешительной лицензии многие поставщики выпускают собственные настроенные форки LLVM. Это официально признано документацией LLVM, которая предлагает не использовать номера версий в проверках функций по этой причине. [59] Некоторые поставщики включают:
преобразует
исходный код Ruby вашего проекта в ... машинный код с помощью компилятора с опережением по времени (AOT), основанного на LLVM.
'LLVM' официально больше не является аббревиатурой. Аббревиатура, которую он когда-то расширял, тоже была запутанной и неуместной почти с первого дня. :) По мере того, как LLVM разрастался, охватывая другие подпроекты, он становился еще менее полезным и бессмысленным.
Название «LLVM» когда-то было аббревиатурой, но теперь это просто бренд для зонтичного проекта.
Обратите внимание, что маркетинговые номера версий не следует использовать для проверки языковых функций, поскольку разные поставщики используют разные схемы нумерации. Вместо этого используйте макросы проверки функций.
Текущая спецификация NVVM IR основана на LLVM 5.0