Programování

Co je LLVM? Síla za Swiftem, Rustem, Clangem a dalšími

Nové jazyky a vylepšení stávajících se rozmnožují v celé rozvojové krajině. Mozilla’s Rust, Apple's Swift, Jetbrains's Kotlin a mnoho dalších jazyků poskytuje vývojářům novou řadu možností pro rychlost, bezpečnost, pohodlí, přenositelnost a výkon.

Proč teď? Jedním z velkých důvodů jsou nové nástroje pro vytváření jazyků - konkrétně překladače. A hlavním z nich je LLVM, open source projekt původně vyvinutý tvůrcem jazyka Swift Chrisem Lattnerem jako výzkumný projekt na University of Illinois.

LLVM usnadňuje nejen vytváření nových jazyků, ale také rozvoj stávajících jazyků. Poskytuje nástroje pro automatizaci mnoha z nejvíce nevděčných částí úkolu vytváření jazyků: vytvoření kompilátoru, portování výstupního kódu na více platforem a architektur, generování optimalizací specifických pro architekturu, jako je vektorizace, a psaní kódu pro zpracování metafor běžných jazyků, jako je výjimky. Jeho liberální licencování znamená, že jej lze volně znovu použít jako softwarovou součást nebo nasadit jako službu.

Seznam jazyků využívajících LLVM má mnoho známých jmen. Jazyk Swift společnosti Apple používá LLVM jako rámec kompilátoru a Rust používá LLVM jako základní součást svého řetězce nástrojů. Mnoho překladačů má také vydání LLVM, jako je Clang, překladač C / C ++ (tento název, „C-lang“), což je projekt úzce spjatý s LLVM. Mono, implementace .NET, má možnost kompilace do nativního kódu pomocí back-endu LLVM. A Kotlin, nominálně jazyk JVM, vyvíjí verzi jazyka zvaného Kotlin Native, který používá LLVM ke kompilaci do strojově nativního kódu.

LLVM definováno

LLVM je jádrem knihovny pro programové vytváření strojově nativního kódu. Vývojář používá API ke generování pokynů ve formátu nazvaném mezilehlé zastoupenínebo IR. LLVM pak může zkompilovat IR do samostatného binárního souboru nebo provést kompilaci JIT (just-in-time) v kódu, aby se spustil v kontextu jiného programu, například tlumočníka nebo modulu runtime pro jazyk.

Rozhraní API LLVM poskytují primitiva pro vývoj mnoha běžných struktur a vzorů nalezených v programovacích jazycích. Například téměř každý jazyk má koncept funkce a globální proměnné a mnoho z nich má coroutiny a rozhraní C s cizí funkcí. LLVM má funkce a globální proměnné jako standardní prvky ve svém IR a má metafory pro vytváření korutin a propojení s knihovnami C.

Místo toho, abyste trávili čas a energii objevováním těchto konkrétních kol, stačí použít implementace LLVM a zaměřit se na části vašeho jazyka, které vyžadují pozornost.

Přečtěte si více o Go, Kotlin, Python a Rust

Jít:

  • Klepněte na sílu jazyka Google Go
  • Nejlepší IDE a editory jazyka Go

Kotlin:

  • Co je Kotlin? Vysvětlení alternativy Java
  • Rámečky Kotlin: Průzkum vývojových nástrojů JVM

Krajta:

  • Co je Python? Vše, co potřebujete vědět
  • Výukový program: Jak začít s Pythonem
  • 6 základních knihoven pro každého vývojáře Pythonu

Rez:

  • Co je Rust? Způsob bezpečného, ​​rychlého a snadného vývoje softwaru
  • Naučte se, jak začít s Rustem

LLVM: Navrženo pro přenositelnost

Abychom porozuměli LLVM, mohlo by nám pomoci zvážit analogii s programovacím jazykem C: C je někdy popisován jako přenosný montážní jazyk na vysoké úrovni, protože má konstrukce, které lze úzce mapovat na systémový hardware, a bylo přeneseno téměř na každá architektura systému. Ale C je užitečný jako přenosný montážní jazyk pouze do bodu; nebyl navržen pro tento konkrétní účel.

Naproti tomu IR LLVM byl od začátku navržen jako přenosná sestava. Jedním ze způsobů dosažení této přenositelnosti je nabídka primitiv nezávisle na konkrétní architektuře stroje. Například celočíselné typy nejsou omezeny na maximální bitovou šířku podkladového hardwaru (například 32 nebo 64 bitů). Můžete vytvořit primitivní celočíselné typy pomocí tolika bitů, kolik je potřeba, například 128bitové celé číslo. Také si nemusíte dělat starosti s tvorbou výstupu tak, aby odpovídal instrukční sadě konkrétního procesoru; LLVM se o to postará i pro vás.

Architektonicky neutrální design LLVM usnadňuje podporu hardwaru všeho druhu, současného i budoucího. Například IBM nedávno přispěla kódem na podporu svých systémů z / OS, Linux on Power (včetně podpory vektorové knihovny IBM MASS) a architektury AIX pro projekty LLVM C, C ++ a Fortran.

Chcete-li vidět živé příklady LLVM IR, přejděte na web projektu ELLCC a vyzkoušejte živé demo, které převádí C kód na LLVM IR přímo v prohlížeči.

Jak programovací jazyky používají LLVM

Nejběžnějším případem použití pro LLVM je kompilátor předstihu (AOT) pro jazyk. Například projekt Clang předem kompiluje C a C ++ do nativních binárních souborů. Ale LLVM umožňuje i jiné věci.

Just-in-time kompilace s LLVM

Některé situace vyžadují, aby byl kód generován za běhu za běhu, než aby byl kompilován předem. Například jazyk Julia JIT kompiluje svůj kód, protože musí běžet rychle a komunikovat s uživatelem prostřednictvím REPL (smyčka čtení-eval-tisk) nebo interaktivního řádku.

Numba, balíček matematické akcelerace pro Python, JIT kompiluje vybrané funkce Pythonu do strojového kódu. Může také předem sestavit Numba zdobený kód, ale (jako Julia) Python nabízí rychlý vývoj tím, že je interpretovaným jazykem. Použití kompilace JIT k vytvoření takového kódu doplňuje interaktivní pracovní tok Pythonu lépe než kompilace předem.

Jiní experimentují s novými způsoby, jak používat LLVM jako JIT, jako je kompilace dotazů PostgreSQL, což přináší až pětinásobné zvýšení výkonu.

Automatická optimalizace kódu pomocí LLVM

LLVM nejen kompiluje IR do nativního strojového kódu. Můžete jej také programově nasměrovat tak, aby optimalizoval kód s vysokou mírou granularity, a to celou cestou procesu propojení. Optimalizace mohou být docela agresivní, včetně věcí, jako je vložení funkcí, odstranění mrtvého kódu (včetně nepoužitých deklarací typu a argumentů funkcí) a odvíjení smyček.

Opět je síla v tom, že to všechno nemusíte provádět sami. LLVM je může zpracovat za vás, nebo jej můžete podle potřeby přepnout. Například pokud chcete menší binární soubory za cenu nějakého výkonu, můžete svému front-endu kompilátoru říct, aby LLVM zakázal odvíjení smyčky.

Jazyky specifické pro doménu s LLVM

LLVM se používá k výrobě překladačů pro mnoho univerzálních jazyků, ale je také užitečné pro produkci jazyků, které jsou vysoce vertikální nebo výlučné pro problémovou doménu. V některých ohledech je to místo, kde LLVM září nejjasněji, protože při vytváření takového jazyka odstraňuje hodně driny a vytváří dobrý výkon.

Projekt Emscripten například bere IR kód LLVM a převádí jej do JavaScriptu, teoreticky umožňuje exportovat kód, který lze spustit v prohlížeči, libovolnému jazyku s back-endem LLVM. Dlouhodobým plánem je mít back-endy založené na LLVM, které mohou vytvářet WebAssembly, ale Emscripten je dobrým příkladem toho, jak flexibilní LLVM může být.

Dalším způsobem, jak lze LLVM použít, je přidání rozšíření specifických pro doménu do existujícího jazyka. Nvidia použila LLVM k vytvoření kompilátoru Nvidia CUDA, který umožňuje jazykům přidat nativní podporu pro CUDA, která se kompiluje jako součást nativního kódu, který generujete (rychlejší), místo aby byla vyvolána prostřednictvím knihovny dodávané s ním (pomaleji).

Úspěch LLVM v jazycích specifických pro doménu podnítil nové projekty v rámci LLVM zaměřené na řešení problémů, které vytvářejí. Největší otázkou je, jak se některé DSL těžko překládají do LLVM IR, aniž by na front endu bylo hodně práce. Jedním z řešení v pracích je projekt Multi-Level Intermediate Representation neboli MLIR.

MLIR poskytuje pohodlné způsoby, jak reprezentovat složité datové struktury a operace, které lze poté automaticky přeložit do LLVM IR. Například rámec strojového učení TensorFlow může mít mnoho svých komplexních operací grafu toku dat efektivně kompilovaných do nativního kódu pomocí MLIR.

Práce s LLVM v různých jazycích

Typický způsob práce s LLVM je prostřednictvím kódu v jazyce, který vám vyhovuje (a který samozřejmě podporuje knihovny LLVM).

Dvě možnosti společného jazyka jsou C a C ++. Mnoho vývojářů LLVM má výchozí nastavení jednoho z těchto dvou z několika dobrých důvodů:

  • Samotný LLVM je napsán v C ++.
  • API LLVM jsou k dispozici v inkarnacích C a C ++.
  • K vývoji jazyka obvykle dochází u C / C ++ jako základny

Přesto tyto dva jazyky nejsou jedinou volbou. Mnoho jazyků může nativně volat do knihoven C, takže je teoreticky možné provádět vývoj LLVM s jakýmkoli takovým jazykem. Ale pomůže to mít skutečnou knihovnu v jazyce, který elegantně zabalí API LLVM. Naštěstí má mnoho knihoven a jazykových modulů runtime takové knihovny, včetně C # /. NET / Mono, Rust, Haskell, OCAML, Node.js, Go a Python.

Jednou výhradou je, že některé jazykové vazby na LLVM mohou být méně úplné než jiné. Například v Pythonu existuje mnoho možností, ale každá se liší svou úplností a užitečností:

  • llvmlite, vyvinutý týmem, který vytváří Numbu, se ukázal jako současný uchazeč o práci s LLVM v Pythonu. Implementuje pouze podmnožinu funkcí LLVM, jak to diktují potřeby projektu Numba. Ale tato podmnožina poskytuje drtivou většinu toho, co uživatelé LLVM potřebují. (llvmlite je obecně nejlepší volbou pro práci s LLVM v Pythonu.)
  • Projekt LLVM udržuje vlastní sadu vazeb na C API LLVM, ale v současné době nejsou udržovány.
  • llvmpy, první populární vazba Pythonu pro LLVM, vypadla z údržby v roce 2015. Špatné pro jakýkoli softwarový projekt, ale horší při práci s LLVM, vzhledem k počtu změn, které přicházejí v každém vydání LLVM.
  • llvmcpy si klade za cíl aktualizovat vazby Pythonu pro knihovnu C, aktualizovat je automatizovaným způsobem a zpřístupnit je pomocí nativních idiomů Pythonu. llvmcpy je stále v raných fázích, ale již může provádět základní práci s API LLVM.

Pokud vás zajímá, jak používat knihovny LLVM k vytváření jazyka, vlastní tvůrci LLVM mají výukový program, který používá buď C ++ nebo OCAML a který vás provede vytvořením jednoduchého jazyka s názvem Kaleidoscope. Od té doby byl přenesen do jiných jazyků:

  • Haskell:Přímý port původního tutoriálu.
  • Krajta: Jeden takový port pečlivě sleduje tutoriál, zatímco druhý je ambicióznější přepis s interaktivním příkazovým řádkem. Oba používají llvmlite jako vazby na LLVM.
  • RezaRychlý: Zdálo se nevyhnutelné, že dostaneme porty tutoriálu do dvou jazyků, které LLVM pomohlo uskutečnit.

Nakonec je tutoriál k dispozici také včlověk jazyky. Byl přeložen do čínštiny pomocí původního C ++ a Pythonu.

Co LLVM nedělá

Se vším, co LLVM poskytuje, je užitečné vědět také, co nedělá.

Například LLVM neanalyzuje gramatiku jazyka. Mnoho nástrojů tuto práci již provádí, například lex / yacc, flex / bison, Lark a ANTLR. Analýza má být i tak oddělena od kompilace, takže není divu, že se LLVM o nic z toho nepokouší.

LLVM také přímo neřeší širší kulturu softwaru v daném jazyce. Instalace binárních souborů kompilátoru, správa balíků v instalaci a upgrade řetězce nástrojů - to musíte udělat sami.

A konečně, a co je nejdůležitější, stále existují běžné části jazyků, pro které LLVM neposkytuje primitiva. Mnoho jazyků má nějaký způsob správy paměti shromážděné v paměti, buď jako hlavní způsob správy paměti, nebo jako doplněk ke strategiím jako RAII (které C ++ a Rust používají). LLVM vám neposkytuje mechanismus sběru odpadu, ale poskytuje nástroje k implementaci sběru odpadu tím, že umožňuje označit kód metadaty, což usnadňuje psaní sběračů odpadu.

Nic z toho však nevylučuje možnost, že LLVM může nakonec přidat nativní mechanismy pro implementaci uvolňování paměti. LLVM se vyvíjí rychle, s velkým vydáním přibližně každých šest měsíců. Tempo vývoje se pravděpodobně zrychlí pouze díky tomu, jak mnoho současných jazyků postavilo LLVM do jádra jejich vývojového procesu.

$config[zx-auto] not found$config[zx-overlay] not found