LLVM

Материал из Википедии — свободной энциклопедии
Перейти к навигации Перейти к поиску
LLVM
LLVM Logo.png
Тип компилятор
Разработчик LLVM Developer Group
Написана на C++[3], Си[4] и ассемблер[4]
Операционная система кроссплатформенность
Первый выпуск 15 ноября 2003[1]
Последняя версия
Лицензия University of Illinois/NCSA Open Source License
Сайт llvm.org
Commons-logo.svg LLVM на Викискладе

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 включена обёртка API для OCaml.

Платформы[править | править код]

LLVM поддерживает работу на следующих платформах:

Операционная система Архитектура Компилятор
Linux x86/AMD64 GCC, Clang
FreeBSD x86/AMD64 GCC, Clang
OpenBSD x86/AMD64 GCC, Clang
Mac OS X PowerPC GCC
Mac OS X x86/AMD64 GCC, Clang
Solaris UltraSPARC GCC
Cygwin/Win32 x86 GCC 3.4.X, Binutils 2.15
MinGW/Win32 x86 GCC 3.4.X, Binutils 2.15

LLVM имеет частичную поддержку следующих платформ:

Операционная система Архитектура Компилятор
AIX PowerPC GCC
Linux PowerPC GCC
AmigaOS m68k, PowerPC GCC
Windows x86 MSVC

Типы данных[править | править код]

Простые типы[править | править код]

Целые числа произвольной разрядности iразрядность
  • i1 — булево значение — 0 или 1
  • i32 — 32-разрядное целое
  • i17
  • i256
  • Генерация машинного кода для типов очень большой разрядности не поддерживается. Но для промежуточного представления никаких ограничений нет.
  • Числа считаются представленными в дополнительном коде. Различий между знаковыми и беззнаковыми целыми на уровне типов не делается: в тех случаях, когда это имеет значение, с ними работают разные инструкции.
Числа с плавающей точкой float, double, типы, специфичные для конкретной платформы (например, x86_fp80)
Пустое значение void

Производные типы[править | править код]

Указатели тип* i32* — указатель на 32-разрядное целое
Массивы [число элементов x тип]
  • [10 x i32]
  • [8 x double]
Структуры { i32, i32, double }
Вектор — специальный тип для упрощения SIMD-операций.

Вектор состоит из 2n значений примитивного типа — целого или с плавающей точкой.

< число элементов x тип > < 4 x float > — вектор XMM
Функции
  • i32 (i32, i32)
  • float ({ float, float }, { float, float })

Система типов рекурсивна, то есть можно использовать многомерные массивы, массивы структур, указатели на структуры и функции и т. д.

Операции[править | править код]

Большинство инструкций в 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

См. также[править | править код]

Примечания[править | править код]

  1. Латтнер К. LLVM Status Update
  2. http://lists.llvm.org/pipermail/llvm-dev/2019-March/131157.html
  3. The llvm Open Source Project on Open Hub: Languages Page — 2006.
  4. 1 2 The llvm Open Source Project on Open Hub: Languages Page
  5. LLVMdev: The name of LLVM, Chris Lattner (Apple), 2011-12-21 ""LLVM" is officially no longer an acronym. The acronym it once expanded too was confusing, and inappropriate almost from day 1."
  6. LLILC.
  7. Projects built with LLVM (англ.). llvm.
  8. Welcome Chris Lattner | Tesla
  9. The LLVM Target-Independent Code Generator раздел Target Feature Matrix  (англ.)

Литература[править | править код]

Ссылки[править | править код]