Перейти до вмісту

Low Level Virtual Machine

Матеріал з Вікіпедії — вільної енциклопедії.
Версія від 09:21, 13 лютого 2014, створена 195.160.235.247 (обговорення) (граматичні виправлення)
LLVM
Low Level Virtual Machine Logo
ТипКомпілятори, оптимізатори і генератори коду
РозробникиLLVM Developer Group
Перший випуск2000
Стабільний випуск3.4 (6 січня 2014; 11 років тому (2014-01-06))
Операційна системакрос-платформовий
Мова програмуванняC++
ЛіцензіяUniversity of Illinois Open Source License[2]
Репозиторійgithub.com/llvm/llvm-project
Вебсайтllvm.org

Low Level Virtual Machine (LLVM) - універсальна система аналізу, трансформації і оптимізації програм, що реалізує віртуальну машину з RISC-подібними інструкціями. Може використовуватися як оптимізуючий компілятор цього байт-коду в машинний код для різних архітектур або для його інтерпретації та JIT-компіляції (для деяких платформ).

LLVM дозволяє компілювати програми, написані на мовах С, C++, ObjC, Fortran, Ada, Haskell, Java, Python, Ruby, JavaScript, GLSL або будь-якій іншій, для якої реалізований front-end. В рамках проекту розроблено фронтенд Clang для мов C і C++ і версія GCC, що використовують LLVM як бекенд. У Glasgow Haskell Compiler також реалізована компіляція за допомогою LLVM, існує ще безліч програм, що використовують цю інфраструктуру.

Історія

LLVM — не просто черговий академічний проект. Його історія почалась у 2000 році в Університеті Іллінойса, а тепер LLVM використовують такі гіганти індустрії як Apple, Adobe та Google. Зокрема, на LLVM заснована підсистема OpenGL у MacOS X 10.5, a iPhone SDK використовує GCC з бекендом на LLVM. Apple та Google є одними із основних спонсорів проекту, а натхненник LLVM — Кріс Латтнер — тепер працює в Apple.

Особливості

У основі LLVM лежить проміжне представлення коду (intermediate representation, IR), над яким можна виконувати трансформації у всі компіляції, компоновки і виконання. Із цього представлення генерується оптимізованний машинний код для цілого ряду платформ, як статично, так і динамічно (JIT-компіляція). LLVM підтримує генерацію кода для x86, x86-64, ARM, PowerPC, SPARC, MIPS, IA-64, Alpha.

LLVM написана на C++ і портована на більшість *nix-систем і Windows. Система має модульну структуру і може розширюватись додатковими алгоритмами трансформації (compiler passes) і кодогенераторами для нових апаратних платформ. Фронтенд користувача, як правило, лінкується із LLVM і використовує C++ API для генерації коду і його перетворень. Однак LLVM включає в себе і standalone утіліти.

У LLVM включена обгортка API для OCaml.

Платформи

LLVM подтримує роботу на наступних платформах:

Операційна система Архітектура Компілятор
FreeBSD x86 GCC, Clang
FreeBSD AMD64 GCC, Clang
Linux AMD64 GCC, Clang
Linux x86 GCC, Clang
Mac OS X PowerPC GCC
Mac OS X x86 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 має часткову підтримку наступних платформ:

Операційна система Архітектура Компілятор
Windows x86 Visual Studio .NET
AIX PowerPC GCC
Linux PowerPC GCC
Linux Alpha GCC
Linux Itanium (IA-64) GCC
HP-UX Itanium (IA-64) HP aCC

Типи даних

Прості типи

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

Похідні типи

Вказівники тип* i32* — вказівник на 32-бітне ціле
Масиви [число елементів x тип]
  • [10 x i32]
  • [8 x double]
Структури { i32, i32, double }
Вектор — спеціальний тип для спрощення SIMD-операцій. Вектор складається із 2^n значень примітивного типу — цілого або з плаваючою крапкою.
< число елементів 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.

Супутні проекти

З проектів, заснованих на LLVM, що розвиваються паралельно, можна відзначити:

  • KLEE - символьний аналізатор і генератор тестових наборів;
  • Runtime-бібліотека compiler-rt;
  • llvm-mc - автогенератор асемблера, дизассемблера та інших, пов'язаних з машинним кодом компонентів, на основі описів параметрів LLVM-сумісних платформ.
  • VMKit - віртуальна машина для Java і .NET;
  • Реалізація функційної мови програмування Pure;
  • LDC - компілятор для мови D;
  • Roadsend PHP - оптимізатор, статичний і JIT компілятор для мови PHP;
  • Віртуальні машини для Ruby: Rubinius і MacRuby;
  • Unladen Swallow - реалізація мови Python;
  • LLVM-Lua
  • FlashCCompiler - засіб для компіляції коду на мові Сі в вид придатний для виконання у віртуальній машині Adobe Flash;
  • LLDB - модульна інфраструктура зневадження, використовує такі підсистеми LLVM як API для дизасембювання, Clang AST (Abstract Syntax Tree), парсер виразів, генератор коду і JIT-компілятор. LLDB підтримує зневадження багатонитевих програм на мовах C, Objective-C і C++; відрізняється можливістю підключення плагінів і скриптів на мові Python; демонструє екстремально високу швидкодія при зневадженні програм великого розміру;
  • emscripten - компілятор біткоду LLVM в JavaScript, що дозволяє перетворити для запуску в браузері застосунки, спочатку написані на мові Сі. Наприклад, вдалося запустити Python, Lua, Quake, Freetype;
  • sparse-llvm - бекенд, націлений на створення Сі-компілятора, здатного збирати ядро Linux.
  • Portable OpenCL - відкрита і незалежна реалізація стандарту OpenCL;
  • CUDA Compiler - дозволяє згенерувати GPU-інструкції з коду, написаного на мовах Сі, Сі++ та Fortran;
  • Julia - відкрита динамічна мова програмування, що використовує напрацювання проекту LLVM.

Посилання

  1. https://github.com/llvm/llvm-project/graphs/contributors?type=a
  2. LLVM: Frequently Asked Questions. Архів оригіналу за 13 липня 2013. Процитовано 23 грудня 2010.