Programavimas

Kas yra LLVM? „Swift“, „Rust“, „Clang“ ir dar daugiau

Naujos kalbos ir esamų kalbų patobulinimai grybauja visame vystomame kraštovaizdyje. „Mozilla Rust“, „Apple Swift“, „Jetbrains“ „Kotlin“ ir daugybė kitų kalbų suteikia kūrėjams naują pasirinkimą dėl greičio, saugumo, patogumo, perkeliamumo ir galios.

Kodėl dabar? Viena svarbiausių priežasčių yra nauji kalbos kūrimo įrankiai, būtent kompiliatoriai. Tarp jų yra LLVM, atviro kodo projektas, kurį iš pradžių sukūrė „Swift“ kalbos kūrėjas Chrisas Lattneris kaip mokslinių tyrimų projektą Ilinojaus universitete.

LLVM palengvina ne tik naujų kalbų kūrimą, bet ir esamų kalbų kūrimą. Jame pateikiami įrankiai, skirti automatizuoti daugelį nedėkingiausių kalbos kūrimo užduočių dalių: sukurti kompiliatorių, perkelti išvestą kodą į kelias platformas ir architektūras, generuoti specifines architektūros optimizacijas, tokias kaip vektorizavimas, ir rašyti kodą, kad būtų galima tvarkyti bendrąsias kalbos metaforas išimtys. Liberalus licencijavimas reiškia, kad jį galima laisvai naudoti kaip programinės įrangos komponentą arba naudoti kaip paslaugą.

Kalbų, naudojančių LLVM, sąrašas turi daug žinomų pavadinimų. „Apple“ „Swift“ kalba naudoja LLVM kaip kompiliatoriaus struktūrą, o „Rust“ naudoja LLVM kaip pagrindinį savo įrankių grandinės komponentą. Be to, daugelis kompiliatorių turi LLVM leidimą, pvz., Clang, C / C ++ kompiliatorius (šis pavadinimas yra „C-lang“), kuris pats yra glaudžiai susijęs su LLVM. „Mono“, .NET diegimas, turi galimybę kaupti į gimtąjį kodą naudojant LLVM galinę dalį. O Kotlinas, paprastai JVM kalba, kuria kalbos, vadinamos „Kotlin Native“, versiją, kuri naudoja LLVM kompiliuodama į mašininį kodą.

Apibrėžta LLVM

Savo esme LLVM yra biblioteka, skirta programiškai kurti mašinoms pritaikytą kodą. Kūrėjas naudoja API kurdamas instrukcijas formatu, vadinamu an tarpinis atstovavimasarba IR. Tada LLVM gali kompiliuoti IR į atskirą dvejetainį failą arba atlikti JIT (tiesiog laiku) kompiliaciją kodui, kuris bus vykdomas kitos programos, pavyzdžiui, kalbos vertėjo ar vykdymo metu, kontekste.

LLVM API suteikia primityvumo kuriant daugybę bendrų struktūrų ir modelių, randamų programavimo kalbose. Pavyzdžiui, beveik kiekviena kalba turi funkcijos ir visuotinio kintamojo sąvoką, be to, daugelis turi koroutines ir C užsienio funkcijų sąsajas. LLVM savo funkcijose ir visuotiniuose kintamuosiuose yra standartiniai IR elementai, taip pat turi metaforų, kaip kurti korutines ir sąsajas su C bibliotekomis.

Užuot leidę laiką ir energiją išradę tuos konkrečius ratus, galite tiesiog naudoti LLVM diegimą ir sutelkti dėmesį į tas kalbos dalis, kurioms reikia dėmesio.

Skaitykite daugiau apie „Go“, „Kotlin“, „Python“ ir „Rust“

Eiti:

  • Palieskite „Google's Go“ kalbos galią
  • Geriausi „Go“ kalbos IDE ir redaktoriai

Kotlinas:

  • Kas yra Kotlinas? Paaiškinta „Java“ alternatyva
  • Kotlino sistemos: JVM kūrimo įrankių apžvalga

„Python“:

  • Kas yra „Python“? Viskas, ką reikia žinoti
  • Pamoka: kaip pradėti naudotis „Python“
  • 6 pagrindinės bibliotekos kiekvienam „Python“ kūrėjui

Rūdys:

  • Kas yra rūdys? Saugaus, greito ir lengvo programinės įrangos kūrimo būdas
  • Sužinokite, kaip pradėti naudotis „Rust“

LLVM: sukurtas perkeliamumui

Norint suprasti LLVM, tai gali padėti apsvarstyti analogiją su C programavimo kalba: C kartais apibūdinama kaip nešiojama, aukšto lygio surinkimo kalba, nes ji turi konstrukcijas, kurios gali glaudžiai susieti su sistemos aparatine įranga, ir ji buvo perkelta beveik kiekvienos sistemos architektūra. Tačiau C yra naudinga kaip nešiojama surinkimo kalba tik iki taško; jis nebuvo sukurtas tam tikslui.

Priešingai, LLVM IR nuo pat pradžių buvo suprojektuotas kaip nešiojamas mazgas. Vienas iš būdų, kaip pasiekti šį perkeliamumą, yra siūlyti primityvius dalykus, nepriklausančius nuo konkrečios mašinos architektūros. Pavyzdžiui, sveikųjų skaičių tipai neapsiriboja didžiausiu pagrindinės aparatinės įrangos bitų pločiu (pvz., 32 arba 64 bitai). Galite sukurti primityvius sveikųjų skaičių tipus naudodami tiek bitų, kiek reikia, pavyzdžiui, 128 bitų sveikasis skaičius. Jūs taip pat neturite jaudintis dėl to, kaip sukurti išvestį, kad ji atitiktų konkretaus procesoriaus instrukcijų rinkinį; LLVM tuo rūpinasi ir jums.

Dėl LLVM neutralaus architektūros dizaino lengviau palaikyti visų rūšių aparatūrą, esamą ir būsimą. Pvz., IBM neseniai padėjo kodą palaikyti savo z / OS, „Linux on Power“ (įskaitant IBM MASS vektorizavimo bibliotekos palaikymą) ir AIX architektūras LLVM C, C ++ ir Fortran projektams.

Jei norite pamatyti tiesioginius LLVM IR pavyzdžius, eikite į ELLCC projekto svetainę ir išbandykite tiesioginę demonstraciją, kuri konvertuoja C kodą į LLVM IR tiesiai naršyklėje.

Kaip programavimo kalbos naudoja LLVM

Dažniausias LLVM naudojimo atvejis yra kalbos, sudarytos anksčiau laiko (AOT), kompiliatorius. Pavyzdžiui, „Clang“ projektas anksčiau laiko kaupia C ir C ++ į vietinius dvejetainius failus. Bet LLVM leidžia ir kitus dalykus.

Tiesioginis laiko kompiliavimas su LLVM

Kai kuriose situacijose reikalaujama, kad kodas būtų generuojamas skriejant vykdymo metu, o ne būtų sudarytas iš anksto. Pvz., „Julia“ kalba JIT sudaro savo kodą, nes ji turi veikti greitai ir sąveikauti su vartotoju per REPL (read-eval-print loop) arba interaktyvią eilutę.

„Numba“, „Python“ matematikos pagreičio paketas, JIT kompiliuoja pasirinktas „Python“ funkcijas į mašininį kodą. Jis taip pat gali sukompiliuoti „Numba“ dekoruotą kodą anksčiau laiko, tačiau (kaip ir Julija) „Python“ siūlo greitą tobulėjimą būdamas interpretuojama kalba. Naudojant JIT kompiliaciją tokiam kodui sukurti, „Python“ interaktyvi darbo eiga papildoma geriau nei kompiliacija prieš laiką.

Kiti eksperimentuoja su naujais būdais, kaip naudoti LLVM kaip JIT, pavyzdžiui, sudarant „PostgreSQL“ užklausas, našumas padidėja net penkis kartus.

Automatinis kodo optimizavimas naudojant LLVM

LLVM ne tik kompiliuoja IR į vietinį kompiuterio kodą. Taip pat galite jį programiškai nukreipti optimizuodami kodą labai detaliai, visą susiejimo procesą. Optimizavimas gali būti gana agresyvus, įskaitant tokius dalykus kaip funkcijų įterpimas, negyvo kodo pašalinimas (įskaitant nenaudojamas tipo deklaracijas ir funkcijų argumentus) ir kilpų išvyniojimas.

Vėlgi, galia yra tai, kad nereikia viso to įgyvendinti pačiam. LLVM gali juos tvarkyti už jus arba galite nurodyti, kad prireikus juos išjungtumėte. Pvz., Jei norite mažesnių dvejetainių failų už tam tikrą našumą, galite savo kompiliatoriaus priekinėje dalyje nurodyti LLVM išjungti kilpų išvyniojimą.

Domenui būdingos kalbos su LLVM

LLVM buvo naudojamas kuriant kompiliatorius daugeliui bendrosios paskirties kalbų, tačiau jis taip pat naudingas kuriant kalbas, kurios yra labai vertikalios arba išskirtinės tik probleminei sričiai. Tam tikru požiūriu būtent čia LLVM šviečia ryškiausiai, nes kuriant tokią kalbą ji pašalina daugybę drumstumų ir priverčia ją gerai veikti.

Pavyzdžiui, „Emscripten“ projektas paima LLVM IR kodą ir paverčia jį į „JavaScript“, teoriškai leidžiant bet kuriai kalbai, turinčiai LLVM galinę dalį, eksportuoti kodą, kurį galima paleisti naršyklėje. Ilgalaikis planas yra turėti LLVM pagrįstas galines dalis, galinčias sukurti „WebAssembly“, tačiau „Emscripten“ yra geras pavyzdys, kaip LLVM gali būti lankstus.

Kitas LLVM naudojimo būdas yra domenui pritaikytų plėtinių pridėjimas prie esamos kalbos. „Nvidia“ naudojo LLVM, kad sukurtų „Nvidia CUDA Compiler“, leidžiantį kalboms pridėti savąjį CUDA palaikymą, kuris kompiliuojamas kaip jūsų sukurto gimtojo kodo dalis (greičiau), užuot iškvietus jį kartu su juo (lėčiau).

LLVM sėkmė naudojant domeno kalbas paskatino naujus LLVM projektus spręsti jų sukurtas problemas. Didžiausias klausimas yra tai, kaip kai kuriuos DSL sunku išversti į LLVM IR be sunkaus darbo priekyje. Vienas iš sprendimų darbuose yra daugiapakopė tarpinė atstovybė arba MLIR projektas.

MLIR suteikia patogius būdus vaizduoti sudėtingas duomenų struktūras ir operacijas, kurias vėliau galima automatiškai išversti į LLVM IR. Pavyzdžiui, mašininio mokymosi sistemoje „TensorFlow“ gali būti daugybė sudėtingų duomenų srauto-grafiko operacijų, efektyviai sukompiliuotų į gimtąjį kodą su MLIR.

Darbas su LLVM įvairiomis kalbomis

Tipiškas būdas dirbti su LLVM yra kodas jums patogia kalba (ir tai, be abejo, palaiko LLVM bibliotekas).

Du įprasti kalbos pasirinkimai yra C ir C ++. Daugelis LLVM kūrėjų naudoja vieną iš šių dviejų dėl kelių svarių priežasčių:

  • Pats LLVM parašytas C ++.
  • LLVM API yra C ir C ++ įsikūnijimai.
  • Daug kalbų vystosi paprastai, kai C / C ++ yra pagrindas

Vis dėlto šios dvi kalbos nėra vieninteliai pasirinkimai. Daugelis kalbų gali skambinti į C bibliotekas savaime, todėl teoriškai įmanoma atlikti LLVM kūrimą bet kuria tokia kalba. Bet tai padeda turėti tikrąją biblioteką ta kalba, kuri elegantiškai apgaubtų LLVM API. Laimei, daug kalbų ir kalbos vykdymo laiko turi tokias bibliotekas, įskaitant C # /. NET / Mono, Rust, Haskell, OCAML, Node.js, Go ir Python.

Vienas įspėjimas yra tai, kad kai kurie kalbos susiejimai su LLVM gali būti ne tokie išsamūs nei kiti. Pavyzdžiui, naudojant „Python“ yra daugybė pasirinkimų, tačiau kiekvienas jų išsamumas ir naudingumas skiriasi:

  • „Numba“ kuriančios komandos sukurtas „llvmlite“ tapo dabartiniu konkurentu dirbti su LLVM „Python“. Jis įgyvendina tik LLVM funkcijų pogrupį, kurį diktuoja projekto „Numba“ poreikiai. Bet tas pogrupis suteikia didžiąją dalį to, ko reikia LLVM vartotojams. („llvmlite“ paprastai yra geriausias pasirinkimas dirbant su LLVM „Python“.)
  • LLVM projektas palaiko savo susiejimų su LLVM C API rinkinį, tačiau šiuo metu jie nėra prižiūrimi.
  • „llvmpy“, pirmasis populiarus „LLVM“ „Python“ susiejimas, 2015 m. nebebuvo prižiūrimas. Blogai tinka bet kokiam programinės įrangos projektui, bet blogiau dirbant su LLVM, atsižvelgiant į kiekviename LLVM leidime įvykstančių pakeitimų skaičių.
  • „llvmcpy“ siekia atnaujinti „C“ bibliotekos „Python“ susiejimus, juos atnaujinti automatizuotai ir padaryti juos prieinamus naudojant „Python“ gimtąsias idėjas. „llvmcpy“ vis dar yra ankstyvoje stadijoje, tačiau jau gali atlikti pradinį darbą naudodamas LLVM API.

Jei norite sužinoti, kaip naudoti LLVM bibliotekas kuriant kalbą, patys LLVM kūrėjai turi mokymo programą, naudodami C ++ arba OCAML, kuri padės jums sukurti paprastą kalbą, vadinamą „Kaleidoscope“. Nuo tada jis buvo perkeltas į kitas kalbas:

  • Haskell:Tiesioginis originalios pamokos uostas.
  • „Python“: Vienas iš tokių prievadų atidžiai seka mokymo programą, o kitas yra ambicingesnis perrašymas interaktyvia komandine eilute. Abu jie naudoja llvmlite kaip jungiamąsias medžiagas prie LLVM.
  • RūdysirGreitas: Atrodė neišvengiama, kad gausime mokymo programos uostus dviem kalbomis, kurias LLVM padėjo įgyvendinti.

Galiausiai pamoka taip pat yražmogus kalbomis. Jis buvo išverstas į kinų kalbą naudojant originalius „C ++“ ir „Python“.

Ko nedaro LLVM

Turint visa tai, ką teikia LLVM, naudinga žinoti ir tai, ko jis nedaro.

Pavyzdžiui, LLVM neanalizuoja kalbos gramatikos. Daugelis įrankių jau atlieka tą darbą, pavyzdžiui, „lex / yacc“, „flex / bison“, „Lark“ ir „ANTLR“. Analizavimas vis tiek turi būti atsietas nuo kompiliavimo, todėl nenuostabu, kad LLVM nesistengia to išspręsti.

LLVM taip pat tiesiogiai nesprendžia didesnės programinės įrangos kultūros tam tikra kalba. Įdiekite kompiliatoriaus dvejetainius failus, tvarkykite paketus diegime ir atnaujinkite įrankių grandinę - tai turite padaryti patys.

Galiausiai ir svarbiausia, kad vis dar yra bendrų kalbų dalių, kurioms LLVM neteikia primityvių. Daugelyje kalbų yra tam tikras šiukšlių surinktos atminties tvarkymo būdas, kuris yra pagrindinis atminties valdymo būdas arba kaip papildoma strategija, pvz., RAII (kurią naudoja C ++ ir Rust). LLVM nesuteikia jums šiukšlių surinkimo mechanizmo, tačiau pateikia įrankius šiukšlių surinkimui įgyvendinti, leidžiant pažymėti kodą metaduomenimis, palengvinančiu šiukšlių surinkėjų rašymą.

Tačiau tai neatmeta galimybės, kad LLVM galų gale gali pridėti vietinius mechanizmus šiukšlių surinkimui įgyvendinti. LLVM vystosi greitai, maždaug kas pusmetį išleidžiama iš esmės. Tikėtina, kad vystymosi tempai įsibėgės tik dėl to, kaip daugelis dabartinių kalbų LLVM įtraukė į savo kūrimo procesą.

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