Haladó Fordítóprogramok
Követelmények Horváth Gábor xazax.hun@gmail.com xazax.web.elte.hu 3-5 oldalas esszé, téma bemutatása, minimális előismeretet feltételezve Témák előadás közben További témák GCC Summit Proceedings LLVM Dev meetings http://c9x.me/compile/bib/ Open Book ZH Egy A4-es lap segédlet használható
+ Cikkek + Konferencia előadások Tananyag + Cikkek + Konferencia előadások
Célkitűzések Gyakorlatias ismeretek Mai vezető fordítókban használt algoritmusok, architektúrák GCC, Clang Rust Swift Intuíció arról, mire képes a fordító, mire nem Segítség hatékony kód írásához Könnyebb bekapcsolódás fordítók fejlesztésébe Hány fordító/interpreter van egy böngészőben? TensorFlow AXL, Apache Flink, Configs
Mit várunk el egy fordítótól?
DEMO #include <iostream> int main() { int i = 1; std::cout << ++i << ++i << std::endl; }
DEMO #include <iostream> int fact(int i) { if (i < 1) return 1; return i*fact(i-1); } int main() { std::cout << fact(5) << std::endl; }
Fordítók Egyik nyelvről a másikra fordítunk Pl.: C++ → Haswell utasításkészlet Minél távolabbi a forrás és a cél nyelv annál komplexebb a fordító A számítástudomány minden területét igénybe veszik Mohó algoritmusok (regiszter allokáció) Heurisztikus keresés (ütemezés) Gráf algoritmusok (dead code elimination) Véges automaták (lexing, szintaktikus elemzés) Fix-pont algoritmusok (data-flow analysis) Kevés szoftverfajtában található egyszerre ennyi komplex feladat
Fordítók Számos elméleti eredmény találta meg a fordítókban a felhasználását Lattice theory (hálók) Számelmélet Mintaillesztés gráfokon, gráfredukció Számos megoldandó probléma NP teljes Hatékony közelítőmegoldásokat alkalmazunk Lehetséges jobb heurisztikákat kitalálni Rengeteg a trade-off Regiszter haszálat vs hatékony ütemezés Kódméret vs sebesség Optimalizálásra vs futásra szánt idő
Fordítók felépítése
Fordítók felépítése
Optimalizáció Valamely szempontból javít a kód minőségén Futási idő, memória használat, kódméret, biztonság, … Megőrzi a kód jelentését Biztonságos egy transzformáció használata? Statikus analízis! Döntsük el futtatás nélkül! Tényleg javít a kódon? Költségmodellek Architektúra függő Profile guided optimization
Fordítók felépítése
Fordítók felépítése
Swift fordító, Swift Intermediate Language
Swift fordító, Swift Intermediate Language
Backend Instruction selection Regiszter allokáció Ugyanazt a hatást több utasítással/utasítás sorozattal is el lehet érni adott architektúrán. Melyiket válasszuk? Regiszter allokáció Mely regiszterekbe mely értékeket tároljuk el? Mikor lehet lecserélni egy regiszter tartalmát? Instruction scheduling Az egyes utasítások végrehajtása eltérő időt vehet igénybe Ugyan az az utasítás végrehajtása eltérő időt vehet igénybe (cache locality) Instruction level parallelism Out of order execution
Modern CPU
Modern CPU Pipeline Stalls Cache hierarchy Prefetch Instruction level parallelism Out of order execution Csak az utasítások bufferén belül Van értelme statikus ütemezésnek GPU, mobil processzoroknál néha nincs Branch prediction SIMD instructions
Pipeline
SIMD Kevesebb utasítás jut egységnyi operandusra Prefetch barát Nem a hagyományos regisztereket terheli Természetes módon előfordul Grafika, fizika, matek
Instruction Scheduling LoadAI, StoreAI 3 órajel Mult 2 órajel Többi 1
Instruction Scheduling LoadAI, StoreAI 3 órajel Mult 2 órajel Többi 1
Engineering Ütemezéskor a load-okat távolabb helyezzük a betöltött érték felhasználásától Tovább maradnak az értékek a regiszterekben, nő a regiszter használat
Lexikális elemzés Reguláris nyelvtan Véges automaták Karakterek számában lineáris futási idő Tokenek, tokenizálás Részletesen: Fordítóprogramok tárgy Néhány esetben parser része
Szintaktikus elemzés Környezet független nyelvek Terminálisok, nem terminálisok, kezdőszimbólum, produkciós szabályok Tokeneken dolgozik Nyelvtan leírása (BNF) Balrekurzív szabály, jobbrekurzív szabály Többértelműség feloldása Asszociativitás, precedenciák Szintaxis fa Elemzés alulról felfelé, felülről lefelé Absztrakt szintaxisfa vs konkrét szintaxisfa
Szintaxis fa
Rekurzív leszállás (Recursive Descent) Minden nem-terminálisnak megfeleltehető egy függvény Kézzel írt elemző Az adott függvény a hozzá tartozó nem-terminálist ismeri fel az input streamen A nyelvtan meghatározza mely függvények hívják egymást LL(k) nyelvtanokra jó, balrekurzív nyelvtanok nem működnek Balrekurzív szabály mindig eliminálható! Vigyázat, stack overflow! Legtöbb ipari fordító elemzője ez! Miért!?
Rekurzív leszállás (Recursive Descent) Akadémiai nyelvek Reguláris nyelvtan: lexelés Környezet független nyelvtan: elemzés A nyelvtan egyértelmű Környezet függő nyelvtan a típusellenőrzés C++ Lexelés se reguláris, se nem környezet független (template >>, C++11) Nyelvtan nem egyértelmű, típusinformációk kellenek a feloldáshoz Nem szétválasztható a szemantikus és szintaktikus elemzés Error recovery
P * t; // Pointer vagy szorzás? Többértelmű nyelvtan P * t; // Pointer vagy szorzás?
Balrekurzió eliminálása Expr → Expr + Expr | Integer | String Expr → Integer Expr’ | String Expr’ Expr’ → + Expr Expr’ | Empty Miért van egyáltalán balrekurzív szabályunk? Asszicativitás!
Error recovery Csak mert a felhasználó lefelejtett egy pontos vesszőt, a többi függvényt még lehet elemezni, hogy egyszerre több hibaüzenettel szolgálhassunk Az elemző vissza kell tudjon állni egy stabil állapotba a hibás bemenet után és folytatni a munkát Minél jobb hibaüzenetekre van szükségünk Makróknál minden tokennek két pozíciója van: spelling location, expansion location
Összefoglalás Könyv első 180 oldala letudva Architektúrális áttekintések, emlékeztető lexikális és szintaktikus elemzésről Modern CPU gyorstalpaló Továbbiakban optimalizáció, statikus analízis jóval részletesebben, lassabban Főleg táblás gyakorlatokra lehet számítani