Programmēšana

Kas ir LLVM? Spēks, kas slēpjas aiz Swift, Rust, Clang un citiem

Jaunas valodas un esošo valodu uzlabojumi ir aizraujoši visā attīstītajā ainavā. Mozilla's Rust, Apple Swift, Jetbrains Kotlin un daudzas citas valodas nodrošina izstrādātājiem jaunu izvēles iespēju ātrumu, drošību, ērtību, pārnesamību un jaudu.

Kāpēc tagad? Viens no lielākajiem iemesliem ir jauni valodu veidošanas rīki, īpaši kompilatori. Un galvenais no tiem ir LLVM, atvērtā koda projekts, kuru sākotnēji izstrādāja Swift valodas radītājs Kriss Lattners kā pētījumu projektu Ilinoisas universitātē.

LLVM atvieglo ne tikai jaunu valodu izveidi, bet arī esošo izstrādi. Tas nodrošina rīkus daudzu nepateicīgāko valodas izveides uzdevumu daļu automatizēšanai: sastādītāja izveidošana, izvestā koda pārnešana uz vairākām platformām un arhitektūrām, ģenerēta arhitektūrai specifiska optimizācija, piemēram, vektorizācija, un koda rakstīšana, lai apstrādātu kopīgas valodas metaforas, piemēram, izņēmumiem. Tās liberālā licencēšana nozīmē, ka to var brīvi atkārtoti izmantot kā programmatūras komponentu vai izvietot kā pakalpojumu.

Valodu sarakstā, kas izmanto LLVM, ir daudz pazīstamu vārdu. Apple Swift valoda kā kompilatora ietvaru izmanto LLVM, bet Rust kā rīku ķēdes galveno sastāvdaļu izmanto LLVM. Daudziem kompilatoriem ir LLVM izdevums, piemēram, Clang, C / C ++ kompilators (šis nosaukums ir “C-lang”), kas pats ir projekts, kas cieši saistīts ar LLVM. Mono .NET ieviešanai ir iespēja apkopot vietējā kodā, izmantojot LLVM aizmuguri. Un Kotlin, kas sākotnēji ir JVM valoda, izstrādā valodas versiju ar nosaukumu Kotlin Native, kas izmanto LLVM, lai apkopotu mašīndzimto kodu.

LLVM definēts

Savā sirdī LLVM ir bibliotēka, lai programmatiski izveidotu mašīndzimto kodu. Izstrādātājs izmanto API, lai ģenerētu instrukcijas formātā, ko sauc par starpposma pārstāvībavai IR. Pēc tam LLVM var kompilēt IR atsevišķā binārā failā vai veikt JIT (tieši laikā) kompilāciju kodam, lai palaistu citas programmas, piemēram, valodas tulka vai izpildlaika kontekstā.

LLVM API nodrošina primitīvus daudzu kopīgu struktūru un modeļu izstrādei, kas atrodami programmēšanas valodās. Piemēram, gandrīz katrai valodai ir jēdziens funkcija un globālais mainīgais, un daudzām tām ir korutīnas un C ārfunkciju saskarnes. LLVM ir funkcijas un globālie mainīgie kā standarta elementi IR, un tai ir metaforas korutīnu izveidošanai un saskarnei ar C bibliotēkām.

Tā vietā, lai tērētu laiku un enerģiju, lai izgudrotu šos konkrētos riteņus, jūs varat vienkārši izmantot LLVM ieviešanu un koncentrēties uz tām valodas daļām, kurām jāpievērš uzmanība.

Lasiet vairāk par Go, Kotlin, Python un Rust

Iet:

  • Pieskarieties Google’s Go valodas iespējām
  • Labākie Go valodas IDE un redaktori

Kotlins:

  • Kas ir Kotlins? Java alternatīva ir izskaidrota
  • Kotlina ietvarstruktūras: JVM izstrādes rīku apskats

Python:

  • Kas ir Python? Viss, kas jums jāzina
  • Apmācība: kā sākt darbu ar Python
  • 6 būtiskas bibliotēkas katram Python izstrādātājam

Rūsas:

  • Kas ir rūsa? Veids, kā veikt drošu, ātru un ērtu programmatūras izstrādi
  • Uzziniet, kā sākt darbu ar Rust

LLVM: Paredzēts pārnesamībai

Lai saprastu LLVM, tas varētu palīdzēt apsvērt analoģiju C programmēšanas valodai: C dažreiz tiek raksturota kā pārnēsājama, augsta līmeņa montāžas valoda, jo tai ir konstrukcijas, kuras var cieši saistīt ar sistēmas aparatūru, un tā ir pārnesta gandrīz uz katra sistēmas arhitektūra. Bet C kā pārnēsājama montāžas valoda ir noderīga tikai līdz punktam; tas nebija paredzēts šim konkrētajam mērķim.

Turpretī LLVM IR jau no paša sākuma tika projektēts kā pārnēsājams mezgls. Viens no veidiem, kā panākt šo pārnesamību, ir primitīvu piedāvāšana neatkarīgi no konkrētas mašīnas arhitektūras. Piemēram, veselu skaitļu veidi neaprobežojas ar pamata aparatūras maksimālo bitu platumu (piemēram, 32 vai 64 biti). Varat izveidot primitīvus veselu skaitļu veidus, izmantojot pēc iespējas vairāk bitu, piemēram, 128 bitu veselu skaitli. Jums arī nav jāuztraucas par izejas izstrādi, lai tā atbilstu konkrēta procesora instrukciju kopai; LLVM par to rūpējas arī jums.

LLVM arhitektoniski neitrāls dizains atvieglo visa veida aparatūras atbalstu gan tagadnē, gan nākotnē. Piemēram, IBM nesen pievienoja kodu, lai atbalstītu savu z / OS, Linux on Power (ieskaitot atbalstu IBM MASS vektorizācijas bibliotēkai) un AIX arhitektūras LLVM C, C ++ un Fortran projektiem.

Ja vēlaties redzēt tiešraides LLVM IR piemērus, dodieties uz ELLCC projekta vietni un izmēģiniet tiešraides demonstrāciju, kas pārveido C kodu LLVM IR tieši pārlūkprogrammā.

Kā programmēšanas valodas izmanto LLVM

Visizplatītākais LLVM izmantošanas gadījums ir valodas pirms laika (AOT) sastādītājs. Piemēram, Clang projekts pirms laika apkopo C un C ++ vietējos bināros failos. Bet LLVM padara iespējamas arī citas lietas.

Tūlītēja apkopošana ar LLVM

Dažās situācijās ir nepieciešams, lai kods tiktu ģenerēts lidojuma laikā, nevis apkopots pirms laika. Piemēram, Jūlijas valoda JIT apkopo savu kodu, jo tai ir jāpalaiž ātri un jāsadarbojas ar lietotāju, izmantojot REPL (read-eval-print loop) vai interaktīvu uzvedni.

Numba, matemātiskās paātrināšanas pakete Python, JIT apkopo atlasītās Python funkcijas mašīnkodā. Tas var arī pirms laika apkopot Numba rotāto kodu, taču (tāpat kā Jūlijai) Python piedāvā ātru attīstību, būdams interpretēta valoda. Izmantojot JIT kompilāciju šāda koda iegūšanai, Python interaktīvā darbplūsma tiek papildināta labāk nekā kompilācija pirms laika.

Citi eksperimentē ar jauniem veidiem, kā izmantot LLVM kā JIT, piemēram, apkopojot PostgreSQL vaicājumus, līdz pat piecreiz palielinot veiktspēju.

Automātiska koda optimizācija ar LLVM

LLVM ne tikai apkopo IR uz vietējo mašīnkodu. Varat arī to programmatiski novirzīt, lai optimizētu kodu ar lielu detalizācijas pakāpi līdz galam saistīšanas procesā. Optimizācija var būt diezgan agresīva, ieskaitot tādas lietas kā funkciju iekļaušana, mirušā koda (ieskaitot neizmantotās tipa deklarācijas un funkciju argumentus) novēršana un cilpu atritināšana.

Atkal spēks ir tajā, ka tas viss nav jāīsteno pašiem. LLVM var tos apstrādāt jūsu vietā vai arī jūs varat to novirzīt, lai tos pēc vajadzības izslēgtu. Piemēram, ja vēlaties mazākus bināros failus par kādas veiktspējas izmaksām, jūs varat savam kompilatora priekšējam panelim pateikt LLVM atspējot cilpu atritināšanu.

Domēna valodas ar LLVM

LLVM ir izmantots kompilatoru ražošanai daudzām vispārējas nozīmes valodām, taču tas ir noderīgs arī tādu valodu ražošanai, kuras ir ļoti vertikālas vai ekskluzīvas tikai problēmu domēnam. Dažos veidos tieši šeit LLVM spīd visspilgtāk, jo tas noņem daudz drupu šādas valodas veidošanā un liek tai darboties labi.

Piemēram, Emscripten projekts ņem LLVM IR kodu un pārvērš to JavaScript, teorētiski ļaujot jebkurai valodai ar LLVM aizmuguri eksportēt kodu, kas var darboties pārlūkprogrammā. Ilgtermiņa plānā ir LLVM balstītas aizmugures, kas var radīt WebAssembly, taču Emscripten ir labs piemērs tam, cik elastīgs var būt LLVM.

Vēl viens veids, kā var izmantot LLVM, ir domēnam specifisku paplašinājumu pievienošana esošai valodai. Nvidia izmantoja LLVM, lai izveidotu Nvidia CUDA kompilatoru, kas ļauj valodām pievienot vietējo atbalstu CUDA, kas tiek apkopots kā daļa no jūsu veidotā dzimtā koda (ātrāk), nevis tiek izsaukts caur bibliotēku, kas tiek piegādāta kopā (lēnāk).

LLVM panākumi ar domēna valodām ir rosinājuši jaunus projektus LLVM, lai risinātu viņu radītās problēmas. Lielākais jautājums ir tas, kā dažus DSL ir grūti pārveidot LLVM IR bez priekšgalā daudz smaga darba. Viens no risinājumiem darbos ir daudzlīmeņu starpposma pārstāvniecība jeb MLIR projekts.

MLIR nodrošina ērtus veidus, kā attēlot sarežģītas datu struktūras un darbības, kuras pēc tam var automātiski tulkot LLVM IR. Piemēram, mašīnmācīšanās ietvarstruktūrā TensorFlow daudzas no tās sarežģītajām datu plūsmas-diagrammas operācijām varētu efektīvi apkopot līdz vietējam kodam ar MLIR.

Darbs ar LLVM dažādās valodās

Tipisks veids, kā strādāt ar LLVM, ir kods jums ērtā valodā (un tas, protams, atbalsta LLVM bibliotēkas).

Divas kopīgas valodas izvēles iespējas ir C un C ++. Daudzi LLVM izstrādātāji noklusē vienu no šiem diviem vairāku labu iemeslu dēļ:

  • Pati LLVM ir rakstīta C ++.
  • LLVM API ir pieejamas C un C ++ iemiesojumos.
  • Daudz valodas attīstība mēdz notikt ar C / C ++ kā bāzi

Tomēr šīs divas valodas nav vienīgā izvēle. Daudzas valodas var iezvanīties C bibliotēkās, tāpēc teorētiski ir iespējams veikt LLVM izstrādi ar jebkuru šādu valodu. Bet tas palīdz faktiskai bibliotēkai valodā, kas eleganti iesaiņo LLVM API. Par laimi, daudzās valodās un valodu izpildlaikos ir šādas bibliotēkas, tostarp C # /. NET / Mono, Rust, Haskell, OCAML, Node.js, Go un Python.

Viens no iebildumiem ir tāds, ka dažas valodas saistīšanas ar LLVM var būt mazāk pilnīgas nekā citas. Piemēram, ar Python ir daudz izvēles iespēju, taču katra no tām atšķiras pēc pilnības un lietderības:

  • llvmlite, ko izstrādājusi komanda, kas izveido Numba, ir kļuvusi par pašreizējo pretendentu darbam ar LLVM Python. Tas īsteno tikai LLVM funkcionalitātes apakškopu, kā to nosaka Numba projekta vajadzības. Bet šī apakškopa nodrošina lielāko daļu LLVM lietotājiem nepieciešamo. (llvmlite parasti ir labākā izvēle darbam ar LLVM Python.)
  • LLVM projekts uztur savu saistījumu kopumu ar LLVM C API, taču pašlaik tie netiek uzturēti.
  • llvmpy, kas ir pirmā populārā LLVM Python saistīšana, 2015. gadā atteicās no apkopes. Slikti jebkuram programmatūras projektam, bet sliktāk, strādājot ar LLVM, ņemot vērā izmaiņu skaitu, kas nāk katrā LLVM izdevumā.
  • llvmcpy mērķis ir atjaunināt C bibliotēkas Python saistījumus, tos automātiski atjaunināt un padarīt tos pieejamus, izmantojot Python vietējās idiomas. llvmcpy joprojām ir agrīnā stadijā, taču jau tagad var veikt dažus elementārus darbus ar LLVM API.

Ja vēlaties uzzināt, kā izmantot LLVM bibliotēkas, lai izveidotu valodu, pašu LLVM veidotājiem ir apmācība, izmantojot C ++ vai OCAML, kas palīdzēs izveidot vienkāršu valodu, ko sauc par Kaleidoscope. Kopš tā laika tas ir pārnests uz citām valodām:

  • Haskels:Sākotnējās apmācības tiešais ports.
  • Python: Viens šāds ports cieši seko apmācībai, bet otrs ir vērienīgāks pārrakstīt ar interaktīvu komandrindu. Abi no tiem izmanto llvmlite kā saistvielu ar LLVM.
  • RūsasunĀtra: Šķita neizbēgami, ka mēs iegūsim apmācības porti divās valodās, kuras LLVM palīdzēja ieviest.

Visbeidzot, apmācība ir pieejama arīcilvēks valodās. Tas ir tulkots ķīniešu valodā, izmantojot oriģinālos C ++ un Python.

Ko nedara LLVM

Ņemot vērā visu, ko LLVM sniedz, ir noderīgi arī zināt, ko tas nedara.

Piemēram, LLVM parsē valodas gramatiku. Daudzi rīki jau veic šo darbu, piemēram, lex / yacc, flex / bison, Lark un ANTLR. Parsēšana tik un tā ir paredzēta atdalīšanai no kompilācijas, tāpēc nav pārsteidzoši, ka LLVM nemēģina to risināt.

LLVM arī tieši neattiecas uz lielāku programmatūras kultūru noteiktā valodā. Instalējot kompilatora bināros failus, pārvaldot paketes instalācijā un jauninot rīku ķēdi - tas jādara pats.

Visbeidzot, vissvarīgākais ir tas, ka joprojām ir kopīgas valodu daļas, kurām LLVM nenodrošina primitīvus. Daudzās valodās ir kaut kāda atkritumu savākšanas veida atmiņas pārvaldība - vai nu kā galvenais veids, kā pārvaldīt atmiņu, vai arī kā papildinājums tādām stratēģijām kā RAII (kuras C ++ un Rust izmanto). LLVM nedod jums atkritumu savācēja mehānismu, taču tas nodrošina rīkus atkritumu savākšanai, ļaujot kodu atzīmēt ar metadatiem, kas atvieglo atkritumu savācēju rakstīšanu.

Neviens no tiem tomēr neizslēdz iespēju, ka LLVM galu galā varētu pievienot vietējos mehānismus atkritumu savākšanas ieviešanai. LLVM attīstās ātri, aptuveni reizi sešos mēnešos tiek izlaists. Attīstības temps, visticamāk, pieaugs tikai pateicoties tam, kā daudzas pašreizējās valodas ir izvirzījušas LLVM to attīstības procesa centrā.

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