LLVM | |
---|---|
![]() | |
Тип | компилятор |
Разработчик | LLVM Developer Group |
Написана на | C++[1], Си[2] и ассемблер[2] |
Операционная система | кроссплатформенность |
Первый выпуск | 15 ноября 2003[3] |
Последняя версия |
|
Лицензия | University of Illinois/NCSA Open Source License |
Сайт | llvm.org |
![]() |
LLVM (ранее Low Level Virtual Machine[5]) — универсальная система анализа, трансформации и оптимизации программ, реализующая виртуальную машину с RISC-подобными инструкциями. Может использоваться как оптимизирующий компилятор байткода в машинный код для различных архитектур либо для его интерпретации и JIT-компиляции (для некоторых платформ).
В рамках проекта LLVM был разработан фронтенд под названием Clang для языков C, C++ и Objective-C, транслирующий исходные коды в байткод LLVM и позволяющий использовать LLVM в качестве полноценного компилятора.
Для LLVM создано несколько фронтендов, в том числе сторонними разработчиками, которые позволяют компилировать программы, написанные на языках С, C++, C#[6], D, Objective-C, Fortran, Ада, Haskell, Java, Kotlin, Python, Ruby, JavaScript, GLSL и Rust. Ранее также была подготовлена версия GCC, транслирующая программы в байт-код LLVM. Существует несколько сторонних программ и проектов, использующих инфраструктуру LLVM для генерации машинного кода[7], в частности, в Glasgow Haskell Compiler реализована компиляция посредством LLVM.
История LLVM началась в 2000 году в Университете Иллинойса. В настоящее время LLVM используется, в том числе, в компаниях Adobe, Apple и Google. В частности, на LLVM основана подсистема OpenGL в Mac OS X 10.5, а iPhone SDK использует препроцессор (фронтенд) GCC с бэкэндом на LLVM. Apple и Google являются одними из основных спонсоров проекта, а вдохновитель LLVM — Крис Латтнер — 11 лет работал в Apple. C января 2017 работает в компании Tesla Motors[8].
В основе LLVM лежит промежуточное представление кода (Intermediate Representation, IR), над которым можно производить трансформации во время компиляции, компоновки и выполнения. Из этого представления генерируется оптимизированный машинный код для целого ряда платформ, как статически, так и динамически (JIT-компиляция). LLVM 3.6 поддерживает статическую генерацию кода для x86, x86-64, ARM, PowerPC, SPARC, MIPS, Qualcomm Hexagon, NVPTX, SystemZ, Xcore. JIT-компиляция (генерация машинного кода во время исполнения) поддержана для архитектур x86, x86_64, PowerPC, MIPS, SystemZ, и частично ARM[9].
LLVM написана на C++ и портирована на большинство Unix-подобных систем и Windows. Система имеет модульную структуру, отдельные её модули могут быть встроены в различные программные комплексы, она может расширяться дополнительными алгоритмами трансформации и кодогенераторами для новых аппаратных платформ.
LLVM поддерживает работу на следующих платформах:
LLVM имеет частичную поддержку следующих платформ:
Операционная система | Архитектура | Компилятор |
---|---|---|
AIX | PowerPC | GCC |
Linux | PowerPC | GCC |
AmigaOS | m68k, PowerPC | GCC |
Windows | x86 | MSVC |
Целые числа произвольной разрядности | iразрядность |
|
| ||
Числа с плавающей точкой | float, double, типы, специфичные для конкретной платформы (например, x86_fp80) | |
Пустое значение | void |
Указатели | тип* | i32* — указатель на 32-разрядное целое |
Массивы | [число элементов x тип] |
|
Структуры | { i32, i32, double } | |
Вектор — специальный тип для упрощения SIMD-операций.
Вектор состоит из 2n значений примитивного типа — целого или с плавающей точкой. |
< число элементов x тип > | < 4 x float > — вектор XMM |
Функции |
|
Система типов рекурсивна, то есть можно использовать многомерные массивы, массивы структур, указатели на структуры и функции и т. д.
Большинство инструкций в LLVM принимают два аргумента (операнда) и возвращают одно значение (трёхадресный код). Значения определяются текстовым идентификатором. Локальные значения обозначаются префиксом %
, а глобальные — @
. Локальные значения также называют регистрами, а LLVM — виртуальной машиной с бесконечным числом регистров.
Пример:
%sum = add i32 %n, 5 %diff = sub double %a, %b %z = add <4 x float> %v1, %v2 ; поэлементное сложение %cond = icmp eq %x, %y ; Сравнение целых чисел. Результат имеет тип i1. %success = call i32 @puts(i8* %str)
Тип операндов всегда указывается явно, и однозначно определяет тип результата. Операнды арифметических инструкций должны иметь одинаковый тип, но сами инструкции «перегружены» для любых числовых типов и векторов.
LLVM поддерживает полный набор арифметических операций, побитовых логических операций и операций сдвига, а также специальные инструкции для работы с векторами.
LLVM IR строго типизирован, поэтому существуют операции приведения типов, которые явно кодируются специальными инструкциями. Набор из 9 инструкций покрывает все возможные приведения между различными числовыми типами: целыми и с плавающей точкой, со знаком и без, различной разрядности и пр. Кроме этого есть инструкции преобразования между целыми и указателями, а также универсальная инструкция для приведения типов bitcast
(ответственность за корректность таких преобразований возлагается на программиста).
Помимо значений-регистров, в LLVM есть и работа с памятью. Значения в памяти адресуются типизированными указателями. Обратиться к памяти можно с помощью двух инструкций: load
и store
.
Например:
%x = load i32* %x.ptr ; загрузить значение типа i32 по указателю %x.ptr %tmp = add i32 %x, 5 ; прибавить 5 store i32 %tmp, i32* %x.ptr ; и положить обратно
Инструкция malloc
транслируется в вызов одноимённой системной функции и выделяет память на куче, возвращая значение — указатель определённого типа. В паре с ней идёт инструкция free
.
%struct.ptr = malloc { double, double } %string = malloc i8, i32 %length %array = malloc [16 x i32] free i8* %string
Инструкция alloca
выделяет память на стеке.
%x.ptr = alloca double ; %x.ptr имеет тип double* %array = alloca float, i32 8 ; %array имеет тип float*, а не [8 x float]!
Память, выделенная alloca
, автоматически освобождается при выходе из функции при помощи инструкций ret
или unwind
.
Для вычисления адресов элементов массивов, структур и т. д. с правильной типизацией используется инструкция getelementptr
.
%array = alloca i32, i32 %size %ptr = getelementptr i32* %array, i32 %index ; значение типа i32*
getelementptr
только вычисляет адрес, но не обращается к памяти. Инструкция принимает произвольное количество индексов и может разыменовывать структуры любой вложенности.
Также существует инструкции extractvalue
и insertvalue
. Они отличаются от getelementptr
тем, что принимают не указатель на агрегатный тип данных (массив или структуру), а само значение такого типа. extractvalue
возвращает соответственное значение подэлемента, а insertvalue
порождает новое значение агрегатного типа.
%n = extractvalue { i32, [4 x i8*] } %s, 0 %tmp = add i32 %n, 1 %s.1 = insertvalue { i32, [4 x i8*] } %s, i32 %tmp, 0
Данная страница на сайте WikiSort.ru содержит текст со страницы сайта "Википедия".
Если Вы хотите её отредактировать, то можете сделать это на странице редактирования в Википедии.
Если сделанные Вами правки не будут кем-нибудь удалены, то через несколько дней они появятся на сайте WikiSort.ru .