Prezentace se nahrává, počkejte prosím

Prezentace se nahrává, počkejte prosím

Konstrukce překladačů David Bednárek www.ksi.mff.cuni.cz.

Podobné prezentace


Prezentace na téma: "Konstrukce překladačů David Bednárek www.ksi.mff.cuni.cz."— Transkript prezentace:

1 Konstrukce překladačů David Bednárek

2 Pravidla studia SWI109 2/1 Z,Zk

3 3 Pravidla studia  Cvičení  Každých 14 dní  Zápis v SIS  Zápočtové testy  Hromadný termín na cvičení koncem semestru  Opravné termíny individuálně ve zkušebních termínech  Alternativa: Implementace části překladače  Podle zadání ze šk.r. 2010/11  Přednáška  Zkouška - písemná

4 Literatura

5 5  A.V. Aho, R. Sethi, J.D. Ullman Compiler: Principles, Techniques and Tools (1986)  Grune, Bal, Jacobs, Langendoen Modern Compiler Design (2000) Přehled včetně front-endů a překladu neprocedurálních jazyků  Steven S. Muchnick Advanced Compiler Design and Implementation (1997) Přehled optimalizací v back-endech  Randy Allen, Ken Kennedy Optimizing Compilers for Modern Architectures (2001) Hardwarově závislé optimalizace  R. Morgan Building an Optimized Compiler (1998)  Srikant, Shankar (eds.) The Compiler Design Handbook (2003) – Optimizations and Machine Code Generation Sbírka 22 článků  J. R. Levine Linkers and Loaders (1999)

6 Architektura překladače

7 7  Amatérský pohled Lexikální analyzátor Parser Sémantický analyzátor Generátor kódu Posloupnost tokenů Derivační strom Cílový kód

8 8 Architektura překladače  Z velké dálky Generátor mezikódu Lexikální analyzátor Parser Sémantický analyzátor Generátor kódu Posloupnost tokenů Derivační strom Mezikód Derivační strom Cílový kód front-end závislý na vstupním jazyku back-end závislý na cílovém stroji

9 9 Architektura překladače  S optimalizacemi Optimalizace Generátor mezikódu Strojově závislé optimalizace Lexikální analyzátor Parser Sémantický analyzátor Optimalizace Generátor kódu Strojově závislé optimalizace Posloupnost tokenů Derivační strom Mezikód (střední úrovně) Derivační strom Mezikód (střední úrovně) Mezikód nízké úrovně Cílový kód front-end závislý na vstupním jazyku back-end závislý na cílovém stroji

10 10 Architektura překladače  Detailní pohled akademika (pouze optimalizace) Muchnick: Advanced Compiler Design and Implementation Scalar replacement of array references Data-cache optimizations Procedure integration Tail-call optimization Scalar replacement of aggregates Sparse conditional constant propagation Interprocedural constant propagation Procedure specialization and cloning Sparse conditional constant propagation Global value numbering Local and global copy propagation Sparse conditional constant propagation Dead-code elimination Local and global common-subexpression elimination Loop-invariant code motion Dead-code elimination Code hoisting Induction-variable strength reduction Linear-function test replacement Induction-variable removal Unnecessary bounds-checking elimination Control-flow optimizations In-line expansion Leaf-routine optimization Shrink wrapping Machine idioms Tail merging Branch optimizations and conditional moves Dead-code elimination Software pipelining, loop unrolling Basic-block and branch scheduling Register allocation Basic-block and branch scheduling Intraprocedural I-cache optimization Instruction prefetching Data prefetching Branch prediction Interprocedural register allocation Aggregation of global references Interprocedural I-cache optimization Constant folding Algebraic simplification and reassociation

11 11 Architektura překladače  Realita  GNU Compiler Collection Internals Remove useless statements Mudflap declaration registration Lower control flow Lower exception handling control flow Build the control flow graph Find all referenced variables RTL generation Generate exception handling landing pads Cleanup control flow graph Common subexpression elimination Global common subexpression elimination. Loop optimization Jump bypassing If conversion Web construction Life analysis Instruction combination Register movement Optimize mode switching Modulo scheduling Instruction scheduling Register class preferencing Local register allocation Global register allocation Reloading Basic block reordering Variable tracking Delayed branch scheduling Branch shortening Register-to-stack conversion Final Debugging information output Enter static single assignment form Warn for uninitialized variables Dead code elimination Dominator optimizations Redundant phi elimination Forward propagation of single-use variables Copy renaming PHI node optimizations May-alias optimization Profiling Lower complex arithmetic Scalar replacement of aggregates Dead store elimination Tail recursion elimination Forward store motion Partial redundancy elimination Loop invariant motion Canonical induction variable creation Induction variable optimizations Loop unswitching Vectorization Tree level if-conversion for vectorizer Conditional constant propagation Folding builtin functions Split critical edges Partial redundancy elimination Control dependence dead code elimination Tail call elimination Warn for function return without value Mudflap statement annotation Leave static single assignment form

12 Názvosloví

13 13 Základní bloky  Procedura  Procedura nebo funkce  Call graph  Graf (možného) volání mezi procedurami  Základní blok (BB – basic block)  Část procedury bez větvení a smyček, se vstupem pouze na začátku a výstupem pouze na konci  Volání procedury může a nemusí být považováno za předěl BB  Tok řízení - control-flow (graph)  Možnosti předávání řízení mezi základními bloky v proceduře  Reprezentováno orientovaným (cyklickým) grafem  Tok dat - data-flow  Předávání dat, obvykle uvnitř jednoho základního bloku  Pro jeden BB může být reprezentováno dagem

14 14 Dag  Závislost (dependence)  Povinnost provést jednu operaci/instrukci po jiné  Částečné uspořádání operací/instrukcí v jednom BB  Datová závislost (dependence)  Závislost producent-konzument v toku dat  Antidependence  Read-Write: Čtení se musí stihnout před zápisem  Write-Write: Pořadí zápisů se nesmí změnit  Jiné důvody, obvykle nízkoúrovňového původu  Dag (directed acyclic graph)  Orientovaný acyklický graf použitý pro zaznamenání data-flow závislostí

15 15 Typy  Skalární/jednoduchý/atomický typ (scalar)  Typ, s nímž dokáže přímo pracovat cílový stroj  Složený typ (aggregate)  Pole, struktura, třída, řetězec apod.  Zarovnání (alignment)  Požadavek na umístění proměnné/paměťového místa na adrese dělitelné 2, 4, 8, nebo 16  Striktní: Při nedodržení procesor vyvolá výjimku  Optimalizační: Při nedodržení bude kód pomalejší

16 16 Proměnné  Proměnná (variable)  Proměnná deklarovaná ve vstupním jazyce, včetně parametrů  Pomocná proměnná (temporary) vytvořená překladačem  Statická/globální proměnná  Proměnná s jedinou instancí přístupná všem procedurám  (Lokální) proměnná  Parametr, deklarovaná či pomocná proměnná přístupná pouze jedné proceduře  Jazyky s vnořenými procedurami vyžadují další kategorii proměnných přístupných z vnořených procedur  Paměťové místo  Část proměnné nebo dynamicky alokované paměti

17 17 Alias  Alias  Situace (nebo možnost výskytu situace), kdy k jedné proměnné, její části, či paměťovému místu, vedou dvě různé přistupové cesty int x;int a[ 20]; int * p = & x;a[ i] =...; a[ j] =...;  Rozhodnutí, zda může jít o alias, je obecně algoritmicky neřešitelná úloha  Pokud si překladač není jist, že o alias nejde, musí se chovat, jako by to alias byl Nejistý alias je ještě horší, než jistý  Proměnná bez aliasu  Lokální proměnná, která prokazatelně nemá alias Všechny přístupy k ní lze jednoznačně určit

18 18 Live range  Doba života/rozsah platnosti proměnné (live range)  Množina míst v proceduře, kdy je proměnná zapotřebí Tedy existuje možnost, že by ještě byla čtena (před zápisem)  Zkoumá se obvykle pouze pro skalární lokální proměnné bez aliasu  Variable splitting/renaming  Proměnnou s nesouvislým rozsahem platnosti lze nahradit několika jinými Odpadne omezení na shodnou alokaci v jednotlivých souvislých oblastích rozsahu platnosti

19 19 Alokace – přidělování místa  Statická alokace (static allocation)  Pro statické proměnné  Vyhrazení místa na „pevné“ adrese Podléhá relokaci při spojování linkerem a zavádění loaderem  Registrová alokace (register allocation)  Pro skalární lokální proměnné bez aliasu  Umístění do fyzického registru cílového stroje Pouze po dobu života proměnné Omezeno počtem fyzických registrů  Zásobníková alokace (stack allocation)  Umístění na zásobníku Zásobník může být definován procesorem nebo emulován  Složené nebo aliasované lokální proměnné  Proměnné, které se nevešly do registrů  Spill-code  Kód „navíc“, který musel být přidán pro manipulaci s proměnnými, které se nevešly do registrů

20 20 Volací konvence  Volací konvence Úmluva o způsobu spolupráce volající a volané procedury Definována cílovým prostředím nebo autorem překladače  Umístění parametrů Zásobník nebo registry Pořadí Přesné umístění je komplikováno zarovnáním  Umístění návratové hodnoty Obvykle registr Složené typy se obvykle řeší jako parametry předávané odkazem  Odpovědnost za úklid zásobníku Volající/volaný  Povinnost zachovat obsah registrů Všechny, některé, nebo žádné  Další technické definice Úprava jména procedury jako symbolu pro linker Pokročilá interprocedurální optimalizace: Automatická úprava volací konvence podle místních podmínek volaného a všech volajících

21 21 Činnost překladače, optimalizace  Intraprocedurální  Uvnitř jedné procedury  Lokální  Uvnitř jednoho základního bloku Příklad: Jednodušší verze schedulingu nebo CSE  Globální  Pro celou proceduru najednou Příklad: Přidělování registrů, složitější CSE  Interprocedurální  Pro celý program najednou  Při separátním překladu modulů je součástí linkeru  Obvykle exponenciální nebo algoritmicky neřešitelné úlohy Příklad: Interprocedurální analýza aliasů Srovnání: In-line expanze procedury patří formálně mezi intraprocedurální optimalizace

22 22 Typy  Logický typ  Datový typ definovaný vstupním jazykem  Základní typy + typové konstrukce  Neomezená množina typů  Fyzický typ  Typ rozeznávaný cílovým strojem  Konečná množina vestavěných typů Celá čísla několika velikostí (znaménková a bezznaménková) Ukazatel (pokud nesplývá s celým číslem) Reálná čísla několika velikostí/přesností  Na ostatní typy se pohlíží jako na posloupnost bajtů Rozhoduje délka, případně požadavek na zarovnání

23 23 Mezikódy  Vysokoúrovňový mezikód  Reprezentace vstupního programu Během fází, řešících konstrukce a pravidla vstupního jazyka Užívá logické typy a operace vstupního jazyka  Nejčastěji ve formě anotovaného AST (abstract syntax tree) Derivační strom podle abstraktní gramatiky  Mezikód střední úrovně  Nejčastější hranice mezi front- a back-endem  Na vstupním jazyce nezávislá reprezentace Užívá fyzické typy a operace na nich  Nejčastěji ve formě čtveřic Tříadresové pseudoinstrukce, pomocné proměnné Někdy ve speciálních formách (SSA – static single assignment) Control-flow může být ve formě grafu BB (základních bloků)  Nízkoúrovňový mezikód  Ekvivalent strojových instrukcí Nekompaktní forma, symbolické a relokované operandy Před alokací registrů forma s neomezeným počtem virtuálních registrů  Někdy v univerzální strojově nezávislé formě (GCC RTL)

24 Mezikódy

25 25 Mezikódy  Informace uložené v mezikódu střední úrovně  Seznam globálních proměnných  Další globální informace pro generovaný kód  Seznam procedur  Další informace pro debugger

26 26 Mezikódy  Informace uložené v mezikódu střední úrovně  Seznam globálních proměnných Velikost Inicializace Příznak konstantnosti Jméno (pro linker) Logický typ (pro debugger)  Další globální informace pro generovaný kód  Konstanty (reálné, řetězcové, strukturované)  Tabulky virtuálních funkcí, RTTI  Často splývají s globálními proměnnými  Seznam procedur  Další informace pro debugger  Jména a konstrukce typů

27 27 Mezikódy  Popis procedury  Jméno (pro linker a chybová hlášení)  Seznam parametrů  Fyzický typ (+ velikost)  Umístění podle volací konvence  Jméno (pro debugger a chybová hlášení)  Logický typ (pro debugger a určení aliasů)  Seznam lokálních proměnných  Fyzický typ (+ velikost)  Jméno (pro debugger a chybová hlášení)  Logický typ (pro debugger a určení aliasů)  Proměnné ve vnořených blocích se obvykle povyšují na úroveň procedury  Kód procedury  Další informace (popisy výjimek apod.)

28 28 Mezikódy  Kód procedury  Plně sekvenční forma  Posloupnost (pseudo-)instrukcí virtuálního stroje  Tok řízení popsán skokovými instrukcemi  Částečně sekvenční forma  Tok řízení popsán grafem, jehož uzly jsou základní bloky  Každý základní blok obsahuje posloupnost (pseudo-)instrukcí Skokové instrukce pouze na konci BB nebo zaznamenány jinak  Nesekvenční forma  Tok řízení popsán grafem, jehož uzly jsou základní bloky  Tok dat uvnitř základního bloku popsán dagem Různé formy podle stupně analýzy aliasů a rozsahů platnosti Pokročilejší formy nahrazují lokální proměnné rozhraními bloků

29 29 Plně sekvenční čtveřicový mezikód int gcd( int x, int y) { int z; if ( x > y ) { z = y; y = x; x = z; } while ( x > 0 ) { z = y % x; y = x; x = z; } return y; } CONST:(C1,I32,0) PROC ”gcd” PARAM:(Px,I32,”x”),(Py,I32,”y”) VAR:(Vz,I32,”z”) TMP:(T1,B),(T2,B),(T3,I32) ENTER GT_I32 T1,Px,Py JF T1,L1 MOV_I32 Vz,Py MOV_I32 Py,Px MOV_I32 Px,Vz L1: GT_I32 T2,Px,C1 JF T2,L2 MOD_I32 T3,Py,Px MOV_I32 Vz,T3 MOV_I32 Py,Px MOV_I32 Px,Vz JMP L1 L2: RET_I32 Py

30 30 Částečně sekvenční čtveřicový mezikód int gcd( int x, int y) { int z; if ( x > y ) { z = y; y = x; x = z; } while ( x > 0 ) { z = y % x; y = x; x = z; } return y; } CONST:(C1,I32,0) PROC ”gcd” PARAM:(Px,I32,”x”),(Py,I32,”y”) VAR:(Vz,I32,”z”) TMP:(T1,B),(T2,B),(T3,I32) ENTER GT_I32 T1,Px,Py JC T1 GT_I32 T2,Px,C1 JC T2 RET_I32 Py MOV_I32 Vz,Py MOV_I32 Py,Px MOV_I32 Px,Vz MOD_I32 T3,Py,Px MOV_I32 Vz,T3 MOV_I32 Py,Px MOV_I32 Px,Vz

31 31 Nesekvenční mezikód (před analýzou aliasů) int gcd( int x, int y) { int z; if ( x > y ) { z = y; y = x; x = z; } while ( x > 0 ) { z = y % x; y = x; x = z; } return y; } CONST:(C1,I32,0) PROC ”gcd” PARAM:(Px,I32,”x”),(Py,I32,”y”) VAR:(Vz,I32,”z”) GT_I32 LD_I32(Px)LD_I32(Py) JC ENTER LD_I32(Py) ST_I32(Vz) LD_I32(Px) ST_I32(Py) LD_I32(Vz) ST_I32(Px) GTC_I32(C1) JC LD_I32(Px) LD_I32(Py) ST_I32(Vz) LD_I32(Px) ST_I32(Py) LD_I32(Vz) ST_I32(Px) LD_I32(Px) MOD_I32 LD_I32(Py) RET_I32 Control-Flow vždy if true if false Dag Data-flow Závislosti

32 32 Mezikódy střední úrovně  Plně sekvenční forma  Částečně sekvenční forma  Nesekvenční forma  Všechny tyto formy lze generovat přímo z abstraktního syntaktického stromu  Jedním průchodem zdola nahoru goto je nutné ošetřit dodatečnými zásahy (backpatching)  Strom nemusí fyzicky existovat, postačí průchod myšleným stromem LR analýza: pravá derivace pozpátku LL analýza rekurzivním sestupem  Většina front-endů přesto strom konstruuje Složité konstrukce jazyka (šablony, předkompilované části) Rozhraní mezi syntaktickým a sémantickým analyzátorem Optimalizace

33 33 Mezikódy střední úrovně  Plně sekvenční forma  Částečně sekvenční forma  Nesekvenční forma  Táž forma se obvykle v průběhu překladu upravuje  Připojují se odvozené informace a optimalizační rozhodnutí  Provádějí se ekvivalentní úpravy (optimalizace)  Jedna forma může mít různé variace  A to i uvnitř jednoho překladače  Odráží různé způsoby a/nebo různé stupně analýzy  Řada překladačů užívá dvě z těchto forem  Z historických důvodů (stabilita rozhraní front-end/back-end)  Pro vytvoření druhé formy je nutná analýza první formy

34 34 Detekce základních bloků CONST:(C1,I32,0) PROC ”gcd” PARAM:(Px,I32,”x”),(Py,I32,”y”) VAR:(Vz,I32,”z”) TMP:(T1,B),(T2,B),(T3,I32) ENTER GT_I32 T1,Px,Py JF T1,L1 MOV_I32 Vz,Py MOV_I32 Py,Px MOV_I32 Px,Vz L1: GT_I32 T2,Px,C1 JF T2,L2 MOD_I32 T3,Py,Px MOV_I32 Vz,T3 MOV_I32 Py,Px MOV_I32 Px,Vz JMP L1 L2: RET_I32 Py  V sekvenčním mezikódu  Základní blok  Začíná Na začátku procedury V cíli skoku Za podmíněným skokem  Končí Podmíněným skokem Nepodmíněným skokem Návratem z procedury Před cílem skoku

35 35 Detekce základních bloků CONST:(C1,I32,0) PROC ”gcd” PARAM:(Px,I32,”x”),(Py,I32,”y”) VAR:(Vz,I32,”z”) TMP:(T1,B),(T2,B),(T3,I32) ENTER GT_I32 T1,Px,Py JF T1,L1 MOV_I32 Vz,Py MOV_I32 Py,Px MOV_I32 Px,Vz L1: GT_I32 T2,Px,C1 JF T2,L2 MOD_I32 T3,Py,Px MOV_I32 Vz,T3 MOV_I32 Py,Px MOV_I32 Px,Vz JMP L1 L2: RET_I32 Py CONST:(C1,I32,0) PROC ”gcd” PARAM:(Px,I32,”x”),(Py,I32,”y”) VAR:(Vz,I32,”z”) TMP:(T1,B),(T2,B),(T3,I32) ENTER GT_I32 T1,Px,Py JC T1 GT_I32 T2,Px,C1 JC T2 RET_I32 Py MOV_I32 Vz,Py MOV_I32 Py,Px MOV_I32 Px,Vz MOD_I32 T3,Py,Px MOV_I32 Vz,T3 MOV_I32 Py,Px MOV_I32 Px,Vz

36 36 Detekce základních bloků int gcd( int x, int y) { int z; if ( x > y ) { z = y; y = x; x = z; } while ( x > 0 ) { z = y % x; y = x; x = z; } return y; }  Ve zdrojovém kódu  Základní blok  Začíná Na začátku procedury Na začátku then a else bloku Na začátku těla cyklu Za if příkazem Za while cyklem  Končí Na konci procedury Na konci then a else bloku Na konci těla cyklu Na konci podmínky v if Na konci podmínky ve while Příkazem return/break apod.  Komplikace  Zkrácené vyhodnocování booleovských výrazů  Podmíněný výraz  Příkaz goto

37 37 Detekce základních bloků int gcd( int x, int y) { int z; if ( x > y ) { z = y; y = x; x = z; } while ( x > 0 ) { z = y % x; y = x; x = z; } return y; } CONST:(C1,I32,0) PROC ”gcd” PARAM:(Px,I32,”x”),(Py,I32,”y”) VAR:(Vz,I32,”z”) TMP:(T1,B),(T2,B),(T3,I32) ENTER GT_I32 T1,Px,Py JC T1 GT_I32 T2,Px,C1 JC T2 RET_I32 Py MOV_I32 Vz,Py MOV_I32 Py,Px MOV_I32 Px,Vz MOD_I32 T3,Py,Px MOV_I32 Vz,T3 MOV_I32 Py,Px MOV_I32 Px,Vz

38 38 Nesekvenční mezikód s hranicemi příkazů int gcd( int x, int y) { int z; if ( x > y ) { z = y; y = x; x = z; } while ( x > 0 ) { z = y % x; y = x; x = z; } return y; } CONST:(C1,I32,0) PROC ”gcd” PARAM:(Px,I32,”x”),(Py,I32,”y”) VAR:(Vz,I32,”z”) GT_I32 LD_I32(Px)LD_I32(Py) JC ENTER LD_I32(Py) ST_I32(Vz) LD_I32(Px) ST_I32(Py) LD_I32(Vz) ST_I32(Px) GTC_I32(C1) JC LD_I32(Px) LD_I32(Py) ST_I32(Vz) LD_I32(Px) ST_I32(Py) LD_I32(Vz) ST_I32(Px) LD_I32(Px) MOD_I32 LD_I32(Py) RET_I32 Control-Flow vždy if true if false Dag operand

39 39 Nesekvenční mezikód před analýzou aliasů int gcd( int x, int y) { int z; if ( x > y ) { z = y; y = x; x = z; } while ( x > 0 ) { z = y % x; y = x; x = z; } return y; } CONST:(C1,I32,0) PROC ”gcd” PARAM:(Px,I32,”x”),(Py,I32,”y”) VAR:(Vz,I32,”z”) GT_I32 LD_I32(Px)LD_I32(Py) JC ENTER LD_I32(Py) ST_I32(Vz) LD_I32(Px) ST_I32(Py) LD_I32(Vz) ST_I32(Px) GTC_I32(C1) JC LD_I32(Px) LD_I32(Py) ST_I32(Vz) LD_I32(Px) ST_I32(Py) LD_I32(Vz) ST_I32(Px) LD_I32(Px) MOD_I32 LD_I32(Py) RET_I32 Control-Flow vždy if true if false Dag operand pořadí

40 40 Odstranění závislostí po analýze aliasů LD_I32(Py) ST_I32(Vz) ST_I32(Py) LD_I32(Vz) ST_I32(Px) MOD_I32 LD_I32(Py) ST_I32(Vz) LD_I32(Px) ST_I32(Py) LD_I32(Vz) ST_I32(Px) LD_I32(Px) MOD_I32 LD_I32(Px)

41 41 Odstranění závislostí po analýze aliasů GT_I32 LD_I32(Px)LD_I32(Py) JC ENTER GTC_I32(C1) JC LD_I32(Px) LD_I32(Py) RET_I32 LD_I32(Py) ST_I32(Vz) ST_I32(Py) LD_I32(Vz) ST_I32(Px) LD_I32(Px) MOD_I32 LD_I32(Py) ST_I32(Vz) LD_I32(Px) ST_I32(Py) LD_I32(Vz) ST_I32(Px) GT_I32 LD_I32(Px)LD_I32(Py) JC ENTER LD_I32(Py) ST_I32(Vz) LD_I32(Px) ST_I32(Py) LD_I32(Vz) ST_I32(Px) GTC_I32(C1) JC LD_I32(Px) LD_I32(Py) ST_I32(Vz) LD_I32(Px) ST_I32(Py) LD_I32(Vz) ST_I32(Px) LD_I32(Px) MOD_I32 LD_I32(Py) RET_I32

42 42 Nesekvenční mezikód po analýze aliasů int gcd( int x, int y) { int z; if ( x > y ) { z = y; y = x; x = z; } while ( x > 0 ) { z = y % x; y = x; x = z; } return y; } CONST:(C1,I32,0) PROC ”gcd” PARAM:(Px,I32,”x”),(Py,I32,”y”) VAR:(Vz,I32,”z”) GT_I32 LD_I32(Px)LD_I32(Py) JC ENTER GTC_I32(C1) JC LD_I32(Px) LD_I32(Py) RET_I32 LD_I32(Py) ST_I32(Vz) ST_I32(Py) LD_I32(Vz) ST_I32(Px) LD_I32(Px) MOD_I32 LD_I32(Py) ST_I32(Vz) LD_I32(Px) ST_I32(Py) LD_I32(Vz) ST_I32(Px) Control-Flow vždy if true if false Dag dependence: operand w-r w-? antidependence: r-w ?-w

43 43 Nesekvenční mezikód s rozsahy platnosti int gcd( int x, int y) { int z; if ( x > y ) { z = y; y = x; x = z; } while ( x > 0 ) { z = y % x; y = x; x = z; } return y; } CONST:(C1,I32,0) PROC ”gcd” PARAM:(Px,I32,”x”),(Py,I32,”y”) VAR:(Vz,I32,”z”) Dag operand antidependence: r-w GT_I32 LD_I32(Px)LD_I32(Py) JC ENTER GTC_I32(C1) JC LD_I32(Px) LD_I32(Py) RET_I32 LD_I32(Py) ST_I32(Vz) ST_I32(Py) LD_I32(Vz) ST_I32(Px) LD_I32(Px) MOD_I32 LD_I32(Py) ST_I32(Vz) LD_I32(Px) ST_I32(Py) LD_I32(Vz) ST_I32(Px) Oblasti platnosti Px Py Vz/1 Vz/2

44 44 Algoritmus: Určení rozsahů platnosti  VAR – množina proměnných  Orientovaný graf control-flow v proceduře: (BB,CF)  BB – množina základních bloků  CF  BB  BB – přechody mezi základními bloky  Lokální analýza  Vnitřní chování každého základního bloku  W : BB  VAR → Bool – blok zapisuje do proměnné  R : BB  VAR → Bool – blok čte proměnnou před prvním zápisem  Triviální algoritmus  Globální analýza  Platnost proměnných na začátku každého základního bloku  L : BB  VAR → Bool – proměnná je živá na začátku bloku  Polynomiální algoritmus  Dopočet  Platnost proměnných na koncích bloků a uvnitř bloků  Detekce čtení nezapsaných proměnných  Triviální algoritmus  Vylepšení  Určení komponent souvislosti a přeznačení proměnných

45 45 Algoritmus: Určení rozsahů platnosti  Vstup  (BB,CF) – graf control flow  W(b,v) – blok b zapisuje do proměnné v  R(b,v) – blok b čte proměnnou v před prvním zápisem do ní  Výstup  L(b,v) – proměnná v je živá na začátku bloku b for each b in BB L(b,v) = R(b,v); do { for each in CF L(b1,v) |= ~ W(b1,v) & L(b2,v); } while changed;  Algoritmus se provádí vektorově  Pro všechny proměnné (v) najednou Překladač využije SIMD instrukce  O(|BB|*|CF|*|VAR|)

46 46 Určení rozhraní BB GT_I32 LD_I32(Px)LD_I32(Py) JC ENTER GTC_I32(C1) JC LD_I32(Px) LD_I32(Py) RET_I32 LD_I32(Py) ST_I32(Vz) ST_I32(Py) LD_I32(Vz) ST_I32(Px) LD_I32(Px) MOD_I32 LD_I32(Py) ST_I32(Vz) LD_I32(Px) ST_I32(Py) LD_I32(Vz) ST_I32(Px) GT_I32 LD_I32(Px)LD_I32(Py) JC ENTER LD_I32(Py) ST_I32(Vz) LD_I32(Px) ST_I32(Py) LD_I32(Vz) ST_I32(Px) LD_I32(Py) ST_I32(Vz) ST_I32(Py) LD_I32(Vz) ST_I32(Px) LD_I32(Px) MOD_I32 GTC_I32(C1) JC LD_I32(Px) LD_I32(Py) RET_I32

47 47 Nesekvenční mezikód s rozhraními BB int gcd( int x, int y) { int z; if ( x > y ) { z = y; y = x; x = z; } while ( x > 0 ) { z = y % x; y = x; x = z; } return y; } CONST:(C1,I32,0) PROC ”gcd” PARAM:(Px,I32,”x”),(Py,I32,”y”) VAR:(Vz,I32,”z”) Rozhraní 1 Px Py Rozhraní 2 Px Py GT_I32 LD_I32(Px)LD_I32(Py) JC ENTER LD_I32(Py) ST_I32(Vz) LD_I32(Px) ST_I32(Py) LD_I32(Vz) ST_I32(Px) LD_I32(Py) ST_I32(Vz) ST_I32(Py) LD_I32(Vz) ST_I32(Px) LD_I32(Px) MOD_I32 GTC_I32(C1) JC LD_I32(Px) LD_I32(Py) RET_I32 Dag operand antidependence: r-w

48 48 Náhrada proměnných rozhraním BB GT_I32 JC ENTER GTC_I32(C1) JC RET_I32 MOD_I32 GT_I32 LD_I32(Px)LD_I32(Py) JC ENTER LD_I32(Py) ST_I32(Vz) LD_I32(Px) ST_I32(Py) LD_I32(Vz) ST_I32(Px) LD_I32(Py) ST_I32(Vz) ST_I32(Py) LD_I32(Vz) ST_I32(Px) LD_I32(Px) MOD_I32 GTC_I32(C1) JC LD_I32(Px) LD_I32(Py) RET_I32

49 49 Nesekvenční mezikód bez proměnných int gcd( int x, int y) { int z; if ( x > y ) { z = y; y = x; x = z; } while ( x > 0 ) { z = y % x; y = x; x = z; } return y; } CONST:(C1,I32,0) PROC ”gcd” PARAM:(Px,I32,”x”),(Py,I32,”y”) Dag data Rozhraní 1 Px Py Rozhraní 2 Px Py GT_I32 JC ENTER GTC_I32(C1) JC RET_I32 MOD_I32

50 50 Nesekvenční mezikód po duplikaci BB int gcd( int x, int y) { int z; if ( x > y ) { z = y; y = x; x = z; } while ( x > 0 ) { z = y % x; y = x; x = z; } return y; } CONST:(C1,I32,0) PROC ”gcd” PARAM:(Px,I32,”x”),(Py,I32,”y”) Dag data Rozhraní 1 Px Py Rozhraní 2 Px Py RET_I32 GTC_I32(C1) JC GT_I32 JC ENTER MOD_I32 GTC_I32(C1) JC RET_I32

51 51 Nesekvenční mezikód po přeznačení int gcd( int x, int y) { int z; if ( x > y ) { z = y; y = x; x = z; } while ( x > 0 ) { z = y % x; y = x; x = z; } return y; } CONST:(C1,I32,0) PROC ”gcd” PARAM:(Px,I32,”x”),(Py,I32,”y”) RET_I32 GTC_I32(C1) JC GT_I32 JC ENTER MOD_I32 GTC_I32(C1) JC RET_I32

52 52 Nesekvenční mezikód po přeznačení int gcd( int x, int y) { if ( x > y ) goto L2; L1: if ( x <= 0 ) return y; y = y % x; L2: if ( y <= 0 ) return x; x = x % y; goto L1; } RET_I32 GTC_I32(C1) JC GT_I32 JC ENTER MOD_I32 GTC_I32(C1) JC RET_I32

53 53 Nesekvenční mezikód po optimalizaci skoků int gcd( int x, int y) { if ( x > y ) goto L4; if ( x <= 0 ) goto L3; L1: if ( (y = y % x) <= 0 ) goto L5; L2: if ( (x = x % y) > 0 ) goto L1; L3: return y; L4: if ( y > 0 ) goto L2; L5: return x; } GTC_I32(C1) JC MOD_I32 GTC_I32(C1) JC GTC_I32(C1) JC GTC_I32(C1) JC MOD_I32 RET_I32 GT_I32 JC ENTER RET_I32 L4 L3 L1 L2L5

54 54 Architektura back-endu  Různé vnitřní reprezentace  Mezikód střední úrovně  Nezávislá sada operací ADD_I32 a,b,c  Forma Nesekvenční Částečně sekvenční  Mezikód nízké úrovně  Ekvivalenty strojových instrukcí add r1,r2  Forma Nesekvenční Částečně sekvenční Sekvenční Strojově závislé optimalizace Optimalizace Generátor kódu Strojově závislé optimalizace Mezikód (střední úrovně) Mezikód nízké úrovně Cílový kód Mezikód (střední úrovně)

55 55 Architektura back-endu  Sekvenční mezikód Strojově závislé optimalizace Alokace registrů Sekvenční mezikód nízké úrovně s fyzickými registry Strojově závislé optimalizace Optimalizace Instruction selection = Výběr instrukcí Strojově závislé optimalizace Sekvenční mezikód (střední úrovně) Sekvenční mezikód (střední úrovně) Sekvenční mezikód nízké úrovně s virtuálními registry Sekvenční mezikód nízké úrovně s virtuálními registry Sekvenční mezikód (střední úrovně) Finalizer Sekvenční mezikód Strojový kód

56 56 Architektura back-endu  Sekvenční mezikód Alokace registrů Optimalizace Instruction selection = Výběr instrukcí Finalizer Zjednodušená analýza rozsahů platnosti Sekvenční mezikód (střední úrovně) Sekvenční mezikód nízké úrovně s virtuálními registry Sekvenční mezikód nízké úrovně s fyzickými registry Strojový kód Analýza aliasů Optimalizace

57 57 Architektura back-endu  Částečně sekvenční mezikód bez schedulingu Optimalizace Alokace registrů Optimalizace Instruction selection = Výběr instrukcí Finalizer Detekce základních bloků Live-range analysis = Analýza rozsahů platnosti Basic-block (re)ordering = Serializace control-flow Sekvenční mezikód (střední úrovně) Částečně sekvenční mezikód (střední úrovně) Částečně sekvenční mezikód nízké úrovně s virtuálními registry Částečně sekvenční mezikód nízké úrovně s fyzickými registry Sekvenční mezikód nízké úrovně s fyzickými registry Strojový kód Analýza aliasů Optimalizace

58 58 Architektura back-endu  Částečně sekvenční mezikód se schedulingem Optimalizace Alokace registrů Optimalizace Instruction selection = Výběr instrukcí Finalizer Detekce základních bloků Live-range analysis = Analýza rozsahů platnosti Basic-block (re)ordering = Serializace control-flow Sekvenční mezikód (střední úrovně) Částečně sekvenční mezikód (střední úrovně) Částečně sekvenční mezikód nízké úrovně s virtuálními registry Částečně sekvenční mezikód nízké úrovně s fyzickými registry Sekvenční mezikód nízké úrovně s fyzickými registry Strojový kód Analýza aliasů Optimalizace Instruction scheduling = Řazení instrukcí Instruction scheduling = Řazení instrukcí

59 59 Architektura back-endu  Nesekvenční mezikód Optimalizace Alokace registrů Optimalizace Instruction selection = Výběr instrukcí Finalizer Detekce základních bloků Live-range analysis = Analýza rozsahů platnosti Basic-block (re)ordering = Serializace control-flow Sekvenční mezikód (střední úrovně) Nesekvenční mezikód (střední úrovně) Částečně sekvenční mezikód nízké úrovně s virtuálními registry Částečně sekvenční mezikód nízké úrovně s fyzickými registry Sekvenční mezikód nízké úrovně s fyzickými registry Strojový kód Analýza aliasů Optimalizace Instruction scheduling = Řazení instrukcí Instruction scheduling = Řazení instrukcí Nesekvenční mezikód nízké úrovně s virtuálními registry

60 60 Architektura back-endu  Instruction selection  Výběr strojových instrukcí 1:n – přímočaré řešení m:n – stromové/grafové gramatiky apod.  Vliv na kvalitu kódu poklesl RISC, load-store kód apod.  Instruction scheduling  Řazení instrukcí pro lepší využití ILP (instruction-level parallelism) NP-úplná úloha  Lokální v BB Speciální řešení smyček (software pipelining) Částečně globální varianty (trace scheduling)  Zrychluje kód o %  Register allocation  Přidělování fyzických registrů NP-úplná úloha Standardní řešení: Barvení grafu

61 61 Architektura back-endu  ILP (instruction-level parallelism)  Pipeline  Instrukce se zpracovává v několika fázích (stages) fetch – read – execute – write  V jednom okamžiku se provádějí různé fáze různých instrukcí  Závislosti po sobě jdoucích instrukcí způsobují: Pipeline stall – zdržení (i486) Nekorektní provedení kódu (Sparc)  Superskalární procesory (MIMD)  Několik výkonných jednotek (Pentium: 2)  V jednom okamžiku se provádějí stejné fáze několika instrukcí  Vektorové procesory (SIMD)  Mnoho výkonných jednotek (Cray: 64) Slabší varianty: Pentium MMX/SSE  V jednom okamžiku se provádí tatáž instrukce mnohokrát  Využití nepatří pod pojem scheduling Automatická vektorizace používá podobné algoritmy jako některé metody schedulingu

62 62 Alokace registrů  Vstup  Částečně sekvenční kód  Možnost přesně definovat rozsahy platnosti  Ekvivalenty strojových instrukcí  Speciální zpracování přesunových instrukcí  Instrukce pracují s virtuálními registry  Optimistický kód  Všechny jednoduché proměnné bez aliasu v registrech  Spočtené rozsahy platnosti proměnných  Množina bodů v mezikódu, kde je proměnná živá Hranice základních bloků Hranice mezi instrukcemi Přesnější informace v místech, kde je proměnná čtena/zapisována  Výstup  Přiřazení virtuálních registrů fyzickým

63 63 Alokace registrů  Optimalizace: Minimalizace přesunových instrukcí  Vytvoření matice kolizí  C : VAR  VAR → Bool  Matice je velká, ale potřebujeme rychlý přístup  Kolize = neprázný průnik oblastí platnosti  Zvláštní posouzení okrajových doteků oblastí  Odhad ceny za spill-kód  P : VAR → Integer  Odhad počtu použití proměnné v průměrném provedení procedury  Vlastní algoritmus alokace  Barvení grafu (VAR,C) n barvami  n je počet fyzických registrů  NP-úplná úloha, dobré heuristické řešení  Doplnění spill-kódu

64 64 Alokace registrů  Barvení grafu (VAR,C) n barvami  n je počet fyzických registrů  NP-úplná úloha, dobré heuristické řešení  Princip  Má-li vrchol méně než n sousedů, lze jej vždy obarvit  Dvě fáze  Postupné odebírání vrcholů  Ve vhodném pořadí tak, aby později měly šanci na obarvení  Odebrané vrcholy se ukládají na zásobník  Zpětná rekonstrukce grafu  Vrcholy se odebírají ze zásobníku  Pokud je lze obarvit, obarví se a přidají do grafu  Neobarvitelné nebudou přiděleny do registru

65 65 Alokace registrů  Vstup: graf (VAR,C), ceny P, počet n (VAR2,C2) := (VAR,C) while not empty(VAR2) do if not exists v:VAR2 st deg(v,C2) < n then select v st P(v) is minimal; // or deg(v,C2) is maximal end if; (VAR2,C2) := (VAR2-{v},C2-edges(v)) stack.push(v); end while; while not empty(stack) do stack.pop(v) M = {u  VAR2;  C} if exists i  {1..n} st not i  color(M) then color(v) := i (VAR2,C2) := (VAR2+{v},C2+) else spill(v) := true end if end while  Výstup: přidělení registrů color, nepřidělené registry spill

66 66 Alokace registrů  Optimalizace: Minimalizace přesunových instrukcí  Jednoduché řešení: Ztotožnit virtuální registry spojené přesunovou instrukcí  Nelze vždy – ztotožňované registry mohou spolu kolidovat  Duplikace kódu může pomoci  Složitější řešení: Úprava algoritmu alokace  Určení skupin uzlů svázaných přesunovými instrukcemi  Při obarvování vybírat zároveň všechny obarvitelné uzly skupiny

67 67 Alokace registrů  Doplnění spill-kódu  Alokovat neobarvené uzly na zásobníku  Podobný algoritmus barvení grafu s neomezeným n  Opatřit každou instrukci spill-kódem  Prefix: Přesun neobarvených vstupních operandů do registrů  Suffix: Přesun neobarvených výstupních operandů do paměti  Problém: kde vzít registry pro tyto operandy  Jednoduché řešení: Rezervované nepřidělované registry  Lepší řešení: Alokovat pomocné registry v rámci normální alokace Vstupy a výstupy každé instrukce označeny jako uzly grafu Nekolidují s virtuálními registry, na které se vážou Kolidují mezi sebou a s ostatními živými virtuálními registry Opatřeny nejvyšší cenou  Problém: spill-kód je často zbytečný  Dodatečná optimalizace – eliminace redundantních přesunů

68 68 Alokace registrů  Množiny povolených registrů  Pro každý operand každé instrukce je určena množina registrů, v nichž může být tento operand  Ortogonální sada instrukcí  Každé dvě množiny povolených registrů jsou buď identické nebo disjunktní  Alokace registrů se spouští pro každou množinu zvlášť  Neortogonální sada instrukcí  Množiny povolených registrů se simulují v grafu kolizí  Přidat úplný podgraf uzlů vysoké priority - reprezentují fyzické registry  Spojit hranou všechny virtuální registry s těmi fyzickými, do kterých nesmí být přiděleny  Problém: Nemusí existovat obarvení  Odložení do paměti, přestože stačí přesun mezi registry

69 69 Alokace registrů  Další problémy  Subregistry  Intel IA-32: al-ax-eax-edx:eax  Řešení: Povýšení na větší registr - neoptimální Různé triky při vytváření grafů kolizí  Registrové volací konvence  Volání procedury se chová jako instrukce používající několik registrů  Neortogonální – volací konvence předepisuje, ve kterém registru má být který operand Často vede k neřešitelným kolizím – zbytečný spill-kód  Řešení: Rozsah platnosti proměnné se rozdělí na oblasti Kolem každé instrukce, používající proměnnou, jedna oblast Oblasti se dotýkají v místě, kde by byla přesunová instrukce, pokud by byla zapotřebí Uzly reprezentující oblasti téže proměnné se přednostně obarvují toutéž barvou

70 70 Scheduling  Provádí se na jednom základním bloku  Trace scheduling: Vybraná posloupnost BB slita do jednoho  Software pipelining: Speciální řešení pro BB jako cyklus  Vstup  Dag  Uzly = instrukce  Hrany = závislosti  Model procesoru  Latence – časování závislých dvojic instrukcí  Rezervační tabulky – schopnosti paralelního zpracování  Výstup  Přiřazení času každému uzlu dagu  Čas měřen cykly procesoru  Instrukce trvá několik cyklů – zvolen referenční bod Obvykle začátek zpracování po načtení a dekódování instrukce

71 71 Scheduling  Dag  Uzly = instrukce  Hrany = závislosti  Dependence vzniklé z předávání dat v registrech  Dependence a antidependence z přístupů do paměti Opatrný přístup: Možná závislost => závislost  Antidependence vzniklé ze soupeření o registry Při schedulingu po alokaci registrů  Další závislosti z technických příčin Manipulace se zásobníkem, skoky apod.  Instrukce volání procedury  „Nekonečně“ dlouhé časování  Často považována za hranici mezi BB Omezená optimalizace přesunem přes volání

72 72 Scheduling  Výstup  Přiřazení času každému uzlu dagu  Aplikace výstupu schedulingu  Běžné procesory (Intel IA-32, včetně x86_64)  Seřazení instrukcí podle schedulovaného času  Procesor nemusí dodržet předpokládaný čas  Procesory se sekvenčními body (Intel IA-64)  V kódu jsou mezi instrukcemi označeny sekvenční body (stops)  Procesor má právo přeházet pořadí instrukcí mezi sekvenčními body Ignorují se antidependence i některé dependence  Výstupem scheduleru jsou i sekvenční body  VLIW procesory  Very Large Instruction Word Instrukce řídí paralelní činnost jednotek procesoru  Jeden schedulovaný čas = jedna instrukce

73 73 Scheduling  Scheduling pouze odhaduje skutečné časování  Skutečné časování je ovlivněno nepředvídatelnými jevy  Zbytky rozpracovaných instrukcí z předchozího BB Řešení: Trace-scheduling, řízení profilem  Paměťová hierarchie Doba přístupu k paměti závisí na přítomnosti v cache Obvykle se předpokládá nejlepší možný průběh Speciální problém: Multithreaded aplikace na multiprocesorech  Fetch bandwidth Instrukce nemusí být načteny a dekódovány včas Zdržují skoky a soupeření o přístup do paměti Přesné simulování fetch jednotky by neúměrně komplikovalo scheduler  Scheduler nezná skutečné závislosti přístupů do paměti  Musí postupovat opatrně a zohledňuje i nejisté závislosti  Procesor zná skutečné adresy přístupů a detekuje pouze skutečné závislosti Agresivně optimalizující procesor může zvolit zcela jiné pořadí instrukcí

74 74 Scheduling  Model procesoru  Latence – časování závislých dvojic instrukcí  Počet cyklů procesoru, který musí proběhnout mezi referenčními body závislých instrukcí  U antidependencí a ve speciálních případech může být nulová  U procesorů se sekvenčními body může být záporná  Latence se obvykle zapisuje ke hranám dagu Přiřazena na základě klasifikace závislosti podle tabulek latencí

75 75 Scheduling  Model procesoru  Rezervační tabulky – schopnosti paralelního zpracování  Procesor je rozdělen na funkční jednotky různých druhů  Je určen počet jednotek každého druhu Limit: Kind -> N  Pro každou instrukci definována rezervační tabulka Res(instr): Time × Kind → N Počet jednotek daného druhu, který instrukce potřebuje v daném čase (měřeno od referenčního bodu)  Rezervační tabulky jsou nutné i pro procesory, které nejsou super- skalární Mají Limit(k)=1, ale různé a tudíž konfliktní rezervační tabulky

76 76 Příklad – mezikód střední úrovně char chksum( char * p, int i) { char s = 0; while ( i > 0 ) { s ^= *p++; --i; } return s; } GTC_I32(C1) JC XLD_I8 RET_I32 GTC_I32(C1) JC ENTER C_I8(C2) ADDC_P(C3) SUBC_I32(C4) XOR_I8

77 77 Příklad – mezikód nízké úrovně char chksum( char * p, int i) { char s = 0; while ( i > 0 ) { s ^= *p++; --i; } return s; } cmp ri,0 jgt mov r1,[rp] ret cmp i,0 jgt mov rs,0 inc rp dec rixor rs,r1

78 78 Příklad – latence  Tabulka latencí  Instrukce-instrukce  Instrukce-konec BB Pesimistická varianta (instrukce musí být dokončena v tomto BB) Pesimistický přístup na konci BB umožňuje optimistiký přístup na začátku: Latence začátek BB-instrukce jsou považovány za nulové Instrukce jgt musí být poslední Latence vůči konci BB se normalizují odečtením latence jgt cmp ri,0 jgt mov r1,[rp] inc rp dec rixor rs,r z instrukcedo instrukcečas cmp ri,0jgt1 mov r1,[rp]xor rs,r14 dec ricmp ri,c2 mov r1,[rp]inc rp0 z instrukcečas inc rp2 jgt1 dec ri2 xor rs,r

79 79  Rezervační tabulky Příklad – rezervační tabulky  Kapacita procesoru inc r1 dec r1 xor r1,r2 cmp r1,r2 RMEMALUW mov r1,[r2]RMEMALUW jgtRMEMALUW 01 RMEMALUW 1121 cmp ri,0 jgt mov r1,[rp] inc rp dec rixor rs,r

80 80  Krok 1  Připravené instrukce  inc rp  dec ri  mov r1,[rp]  Kritická cesta  mov r1,[rp] – 5  Vybrána instrukce  mov r1,[rp]  Umístěna do času 0 Příklad – scheduling časRMEMALUW 0mov cmp ri,0 jgt mov r1,[rp] inc rp dec rixor rs,r

81 81  Krok 2  Připravené instrukce  inc rp  dec ri  xor rs,r1  Kritická cesta  xor rs,r1 – 5  Vybrána instrukce  xor rs,r1  Čas 4 určen latencí Příklad – scheduling časRMEMALUW 0mov xormov 5xor 6 cmp ri,0 jgt mov r1,[rp] inc rp dec rixor rs,r

82 82  Krok 3  Připravené instrukce  inc rp  dec ri  Kritická cesta  dec ri - 4  Vybrána instrukce  dec ri  Čas 0 vyhovuje latenci  Rezervační tabulky jsou obsazeny  Zvolen čas 1 Příklad – scheduling časRMEMALUW 0mov 1decmov 2 dec 3movdec 4xormov 5xor 6 cmp ri,0 jgt mov r1,[rp] inc rp dec rixor rs,r

83 83  Krok 4  Připravené instrukce  inc rp  cmp ri,0  Kritická cesta  cmp ri,0 – 4  Vybrána instrukce  cmp ri,0 – 4  Čas 3 určen latencí Příklad – scheduling časRMEMALUW 0mov 1decmov 2 dec 3cmpmovdec 4xorcmpmov 5xorcmp 6xor cmp ri,0 jgt mov r1,[rp] inc rp dec rixor rs,r

84 84  Krok 5  Připravené instrukce  inc rp  (jgt) – musí být poslední  Vybrána instrukce  inc rp  Čas 0 vyhovuje latenci  Rezervační tabulky pro časy 0-4 obsazeny  Umístěno v čase 5 Příklad – scheduling časRMEMALUW 0mov 1decmov 2 dec 3cmpmovdec 4xorcmpmov 5incxorcmp 6incxor 7inc cmp ri,0 jgt mov r1,[rp] inc rp dec rixor rs,r

85 85  Krok 6  Připravené instrukce  jgt  Latenci vyhovuje čas 4  Instrukce však musí být poslední  Vybrán čas 5 Příklad – scheduling časRMEMALUW 0mov 1decmov 2 dec 3cmpmovdec 4xorcmpmov 5incxor, jgtcmp 6incxor 7inc cmp ri,0 jgt mov r1,[rp] inc rp dec rixor rs,r

86 86  Čas 6  Připravené instrukce  jgt Příklad – scheduling časRMEMALUW 0mov 1decmov 2 dec 3cmpmovdec 4inccmpmov 5xorinc, jgtcmp 6xorinc 7xor cmp ri,0 jgt mov r1,[rp] inc rp dec rixor rs,r

87 87 char chksum( char * p, int i) { char s = 0; while ( i > 0 ) { s ^= *p++; --i; } return s; }  Výsledný kód mov r1,[rp] dec ri cmp ri,0 xor rs,r1 inc rp jgt Příklad – scheduling časRMEMALUW 0mov 1decmov 2 dec 3cmpmovdec 4xorcmpmov 5incxor, jgtcmp 6incxor 7inc cmp ri,0 jgt mov r1,[rp] inc rp dec rixor rs,r

88 88 Scheduling  Základní algoritmus: „List scheduling“  V grafu závislostí s latencemi se pro každý uzel spočte délka kritické, tj. nejdelší cesty ke konci  V každém kroku se určí připravené instrukce a z nich se vybere nejvhodnější  Přednost mají instrukce s nejdelší kritickou cestou  Mezi nimi se vybírá podle dalších heuristik  Při správné implementaci má tento postup složitost O(n 2 )  Vylepšené algoritmy  Posun směrem k exhaustivnímu prohledávání všech možností  Branch-and-bound přístup:  Zkouší se všechny možnosti v pořadí od nejnadějnější, nalezené list schedulingem  Beznadějné pokusy se včas zastaví porovnáváním odhadů úspěšnosti výsledku pomocí kritických cest s doposud známým nejlepším řešením

89 89  Výsledný kód mov r1,[rp] dec ri cmp ri,0 inc rp xor rs,r1 jgt  Chování ve smyčce  Za předpokladu správné predikce skoku procesorem  Výkon: 1/6 iterace/cyklus  Využití jednotek: R: 5/6 MEM: 3/6 ALU: 5/12 W: 5/6 Příklad – scheduling časRMEMALUW 0mov 1decmov 2 dec 3cmpmovdec 4inccmpmov 5xorinc, jgtcmp 6movxorinc 7decmovxor 8movdec 9cmpmovdec 10inccmpmov 11xorinc, jgtcmp 12movxorinc 13decmovxor 14movdec 15cmpmovdec

90 90  Efekt kapacity procesoru  Stejné latence i res. tabulky mov r1,[rp] dec ri inc rp cmp ri,0 xor rs,r1 jgt  Výkon: 1/5 iterace/cyklus  Využití jednotek: R: 5/10 MEM: 3/5 ALU: 5/10 W: 5/10 Příklad – scheduling časRMEMALUW 0mov, dec 1incmovdec 2cmpmovincdec 3movcmpinc 4xorjgtmov, cmp 5mov, decxor 6incmovdecxor 7cmpmovincdec 8movcmpinc 9xorjgtmov, cmp 10mov, decxor 11incmovdecxor 1212cmpmovincdec 1313movcmpinc 1414xorjgtmov, cmp RMEMALUW 2122

91 91  Závislosti uvnitř BB  Závislosti přes hranice BB (loop-carried dependences) Příklad – software pipelining z instrukcedo instrukcečas cmp ri,0jgt1 mov r1,[rp]xor rs,r14 dec ricmp ri,c2 mov r1,[rp]inc rp0 cmp ri,0 jgt mov r1,[rp] inc rp dec rixor rs,r z instrukcedo instrukcečas inc rp 2 mov r1,[rp]2 dec ri 2 cmp ri,0dec ri0 xor rs,r1 2 mov r1,[rp]0 jgtcmp ri,01 jgtmov r1,[rp]

92 92 Příklad – software pipelining  Jiná abstrakce  latence/iterace cmp ri,0 jgt mov r1,[rp] inc rp dec ri xor rs,r1 2/1 1/1 1/0 2/0 4/0 0/1 1/1 cmp ri,0 jgt mov r1,[rp] inc rp dec rixor rs,r /0 0/1

93 93 Příklad – software pipelining časRMEMALUW 0mov1, dec1 1inc1mov1dec1 2cmp1mov1inc1dec1 3dec2mov1cmp1, jgt1inc1 4xor1, mov2dec2mov1, cmp1 5inc2, cmp2mov2xor1dec2 6dec3mov2inc2, cmp2xor1 7mov2dec3, jgt2inc2, cmp2 8xor2, mov3mov2, dec3 9inc3, cmp3mov3xor2 10dec4mov3inc3, cmp3xor2 11mov3dec4, jgt3inc3, cmp3 1212xor3, mov4mov3, dec4 1313inc4, cmp4mov4xor3 14dec5mov4inc4, cmp4xor3 15mov4dec5, jgt4inc4, cmp4 16xor4, mov5mov4, dec5 17inc5, cmp5mov5xor4 18dec6mov5inc5, cmp5xor4 19mov5dec6, jgt5inc5, cmp5 20xor5mov5, dec6 21xor5 22xor5 cmp ri,0 jgt mov r1,[rp] inc rp dec ri xor rs,r1 2/1 1/1 1/0 2/0 4/0 0/1 1/1 0/0 0/1

94 94 Příklad – software pipelining časRMEMALUW 0mov1, dec1 1inc1mov1dec1 2cmp1mov1inc1dec1 3dec2mov1cmp1, jgt1inc1 4xor1, mov2dec2mov1, cmp1 5inc2, cmp2mov2xor1dec2 6dec3mov2inc2, cmp2xor1 7mov2dec3, jgt2inc2, cmp2 8xor2, mov3mov2, dec3 9inc3, cmp3mov3xor2 10dec4mov3inc3, cmp3xor2 11mov3dec4, jgt3inc3, cmp3 1212xor3, mov4mov3, dec4 1313inc4, cmp4mov4xor3 14dec5mov4inc4, cmp4xor3 15mov4dec5, jgt4inc4, cmp4 16xor4, mov5mov4, dec5 17inc5, cmp5mov5xor4 18dec6mov5inc5, cmp5xor4 19mov5dec6, jgt5inc5, cmp5 20xor5mov5, dec6 21xor5 22xor5  Software pipelining  “Unroll-and-compact”  Rozvrhuje se rozvinutý cyklus tak dlouho, dokud nevznikne opakující se vzorek Perioda opakování může odpovídat více iteracím  Problém: Není jasné, co je to kritická cesta Hledá se kritická smyčka

95 95 Software pipelining  „Modulo scheduling“  Analýzou grafu závislostí se odhadne počet cyklů na iteraci Sčítají se ohodnocení hran ve smyčkách dvojicemi latence/iterace Rozhoduje nejvyšší podíl součtů na smyčce, např. 4/1  Hledá se rozvrh s daným počtem cyklů na iteraci Nemusí existovat – opakuje se pro větší počet  Složitější verze zvládají necelé počty cyklů na iteraci Pokud je v grafu závislostí kritická smyčka se součtem ohodnocení např. 5/2 cmp ri,0 jgt mov r1,[rp] inc rp dec ri xor rs,r1 2/1 1/1 1/0 2/0 4/0 0/1 1/1 0/0 0/1

96 96 Modulo scheduling  Zvolená perioda M  Rezervační tabulky jsou používány modulo M: časy 0..(M-1)  Instrukce jsou rozmisťovány do dvojrozměrného prostoru čas/iterace  Rozvrh vyhovuje závislosti pokud (T B -T A )-M*(I B -I A ) ≥ L-M*D cmp ri,0 jgt mov r1,[rp] inc rp dec ri xor rs,r1 2/1 1/1 1/0 2/0 4/0 0/1 1/1 0/0 0/1 časRMEMALUW T+0xor[N], mov[N+1] mov[N], dec[N+1] T+1inc[N+1], cmp[N+1] mov[N+1]xor[N] T+2dec[N+2]mov[N+1]inc[N+1], cmp[N+1] xor[N] T+3mov[N+1]dec[N+2], jgt[N+1] inc[N+1], cmp[N+1] 1/1 2/2 3/1 0/1 0/0 B A L/DL/D TB/IBTB/IB TA/IATA/IA

97 97 Modulo scheduling cmp ri,0 jgt mov r1,[rp] inc rp dec ri xor rs,r1 2/1 1/1 1/0 2/0 4/0 0/1 1/1 0/0 0/1 časRMEMALUW 0xor2, mov3mov2, dec3 1inc3, cmp3mov3xor2 2dec4mov3inc3, cmp3xor2 3mov3dec4, jgt3inc3, cmp3 4xor3, mov4mov3, dec4 5inc4, cmp4mov4xor3 6dec5mov4inc4, cmp4xor3 7mov4dec5, jgt4inc4, cmp4 1/1 2/2 3/1 0/1 0/0

98 98 Příklad – software pipelining časRMEMALUW 0mov1, dec1 1inc1mov1dec1 2cmp1mov1inc1dec1 3dec2mov1cmp1, jgt1inc1 4xor1, mov2dec2mov1, cmp1 5inc2, cmp2mov2xor1dec2 6dec3mov2inc2, cmp2xor1 7mov2dec3, jgt2inc2, cmp2 8xor2, mov3mov2, dec3 9inc3, cmp3mov3xor2 10dec4mov3inc3, cmp3xor2 11mov3dec4, jgt3inc3, cmp3 1212xor3, mov4mov3, dec4 1313inc4, cmp4mov4xor3 14dec5mov4inc4, cmp4xor3 15mov4dec5, jgt4inc4, cmp4 16xor4, mov5mov4, dec5 17inc5, cmp5mov5xor4 18dec6mov5inc5, cmp5xor4 19mov5dec6, jgt5inc5, cmp5 20xor5mov5, dec6 21xor5 22xor5  Výsledek pro příklad  Výkon: 1/4 iterace/cyklus Zlepšení o 25%  Využití jednotek: R: 5/8 MEM: 3/4 ALU: 5/8 W: 5/8  Poslední opakování vzorku provede zbytečně instrukci dec To není chyba  Vytvoření kódu z rozvrhu  Prolog-smyčka-epilog  Dokončení pro odbočky

99 99 Příklad – software pipelining časRMEMALUW 0mov1, dec1 1inc1mov1dec1 2cmp1mov1inc1dec1 3dec2mov1cmp1, jgt1inc1 4xor1, mov2dec2mov1, cmp1 5inc2, cmp2mov2xor1dec2 6dec3mov2inc2, cmp2xor1 7mov2dec3, jgt2inc2, cmp2 8xor2, mov3mov2, dec3 9inc3, cmp3mov3xor2 10dec4mov3inc3, cmp3xor2 11mov3dec4, jgt3inc3, cmp3 1212xor3, mov4mov3, dec4 1313inc4, cmp4mov4xor3 14dec5mov4inc4, cmp4xor3 15mov4dec5, jgt4inc4, cmp4 16xor4, mov5mov4, dec5 17inc5, cmp5mov5xor4 18dec6mov5inc5, cmp5xor4 19mov5dec6, jgt5inc5, cmp5 20xor5mov5, dec6 21xor5 22xor5 mov r1,[rp] dec ri inc rp cmp ri,0 jle l2 dec ri l1: xor rs,r1 mov r1,[rp] inc rp cmp ri,0 dec ri jgt l1 l2: xor rs,r1

100 100 Software pipelining  Duplikace proměnných (Variable expansion)  Duplikací proměnných lze odstranit některé antidependence Teoreticky všechny registrové, roste však počet použitých registrů i velikost kódu  Duplikace proměnných se provede duplikací kódu a vhodným přeznačením cmp ri,0 jgt mov r1,[rp] inc rp dec ri xor rs,r1 2/1 1/1 1/0 2/0 4/0 0/1 1/1 0/0 0/1

101 101 Variable expansion  Duplikace proměnných (Variable expansion)  Duplikací proměnných lze odstranit některé antidependence Teoreticky všechny registrové, roste však počet použitých registrů i velikost kódu  Duplikace proměnných se provede duplikací kódu a vhodným přeznačením  Příklad: Zdvojením proměnné r1 se kritický cyklus zkrátí z poměru 4/1 na 4/2 cmp ri,0 jgt mov r1,[rp] inc rp dec ri xor rs,r1 2/1 1/1 1/0 2/0 4/0 0/2 1/1 0/0 0/1 cmp ri,0 jgt mov r2,[rp] inc rp dec ri xor rs,r2 2/1 1/1 1/0 2/0 4/0 0/2 1/1 0/0 0/1

102 102 Software pipelining  Duplikace proměnných (Variable expansion)  Duplikací proměnných lze odstranit některé antidependence Teoreticky všechny registrové, roste však počet použitých registrů i velikost kódu  Duplikace proměnných se provede duplikací kódu a vhodným přeznačením Duplikaci je možné provést až po schedulingu, který odhalí, která duplikace je užitečná Před schedulingem se odstraní antidependence odstranitelné duplikací cmp ri,0 jgt mov r1,[rp] inc rp dec ri xor rs,r1 2/1 1/1 1/0 2/0 4/0 1/1

103 103 Příklad – modulo scheduling s duplikací časRMEMALUW 0xor2, inc3mov3dec4, jgt3mov2, cmp3 1cmp4mov3xor2, inc3dec4 2mov4, dec5mov3cmp4xor2, inc3 l1: xor rs,r1; čas 0, iterace 2 inc rp; čas 0, iterace 3 cmp ri,0; čas 1, iterace 4 mov r1,[rp]; čas 2, iterace 4 dec ri; čas 2, iterace 5 jle l2; čas 3, iterace 4 xor rs,r2; čas 3, iterace 3 inc rp; čas 3, iterace 4 cmp ri,0; čas 4, iterace 5 mov r2,[rp] ; čas 5, iterace 5 dec ri; čas 5, iterace 6 jgt l1; čas 6, iterace 5 l2: cmp ri,0 jgt mov r1,[rp] inc rp dec ri xor rs,r1 2/1 1/1 1/0 2/0 4/0 1/1 0/0 0/1 1/2 2/3 0/1 2/2 0/0 0/2

104 104 Příklad – Intel compiler – x64 /*...*/ k = i >> 1; j = 0; do { r8 = *p; r9 = *(p+1); s ^= r8; s ^= r9; p += 2; j += 1; } while ( j < k ); /*... */ char chksum( char * p, int i) { char s = 0; while ( i > 0 ) { s ^= *p++; --i; } return s; }..B1.4: movsbq (%rdi), %r8 movsbq 1(%rdi), %r9 xorl %r8d, %eax xorl %r9d, %eax addq $2, %rdi addl $1, %ecx cmpl %edx, %ecx jb..B1.4

105 Cray 1 105

106 Cray 1 106

107 Cray 1 107

108 Cray 1 108

109 109 Paralelizace  Hardware  Proč paralelizace?  Zrychlení stojí příliš mnoho energie P = k f 2  Místa je dost (10 8 tranzistorů/chip)  Jak paralelizovat?  ve světě Intel (IA-32) Pipelining (1989: i486) – bez duplikace Superskalarita (1993: Pentium) – duplikace ALU, původní instrukce SIMD (1996: Pentium MMX) – duplikace ALU, nové instrukce Hyperthreading (1998: Xeon) – duplikace registrů Multi-core (2005: Core 2 Duo) – duplikace CPU  jinde Vektorové instrukce (1974: Cray) – částečná duplikace

110 110 Paralelizace  Z pohledu software  Jemnozrnný paralelismus  ILP Pipelining Superskalarita  SIMD Mírně vektorové instrukce (2-8) Vektorové instrukce (64)  Hrubozrnný paralelismus  SMP Hyperthreading Multi-core Multi-socket  NUMA Multi-core a multi-socket (cc-NUMA) NUMA architektury  Cluster

111 111 Paralelizace  Z pohledu překladače  Jemnozrnný paralelismus  ILP Scheduling, software pipelining – změna pořadí instrukcí  Vektorizace - automatické použití SIMD instrukcí Překladač vybírá speciální instrukce Překladač určuje pořadí provádění  Hrubozrnný paralelismus  SMP – Multithreading Strip-Mining - Překladač dělí kód na nezávislé bloky Pořadí provádění je náhodné

112 112 Paralelizace  Vektorizace  Nízký stupeň (2-8)  Náhodné seskupování a = b + c; d = e + f;  Vektorové seskupování a[i] = b[i] + c[i]; a[i+1] = b[i+1] + c[i+1]; Rozvíjení cyklů podle dostupného stupně vektorizace  Vysoký stupeň (64)  Aplikovatelné na cykly s afinním chováním Numerické aplikace (FORTRAN 90) Nepoužitelné při nebezpečí aliasingu (objektové programování)  Řada afinních transformací cyklů Loop Reversal Loop Skewing

113 Loop reversal  Výměna vzájemného zanoření cyklů  Příklad: Učebnicový zápis násobení matic for I := 1 to M do for J := 1 to N do for K := 1 to P do C[I,J] := C[I,J]+A[I,K]*B[K,J]  Nelze paralelizovat - následující iterace závisí na předchozí  Po výměně zanoření cyklů K/J for I := 1 to M do for K := 1 to P do for J := 1 to N do C[I,J] := C[I,J]+A[I,K]*B[K,J]  Překladač si musí být jistý zachováním semantiky Je nutno vyloučit aliasing C=A resp. C=B  Tato úprava může zhoršit chování vzhledem k cache Závisí na rozměrech P, N  V nenumerických aplikacích je užitečnost nejistá 113

114 Loop reversal  Původní průchod Většina sousedů v průchodu je závislá 114

115 Loop reversal  Upravený průchod Většina sousedů v průchodu je nezávislá 115

116 Loop skewing  Obecnější příklad for J:=1 to N do for K:=N-J to P do A[J,K]:=A[J-1,K]+A[J,K-1] 116 K J

117 Loop skewing  Obecnější příklad for J:=1 to N do for K:=N-J to P do A[J,K]:=A[J-1,K]+A[J,K-1] 117 K J

118 Loop skewing  Loop skewing for J:=1 to N do for K:=N-J to P do A[J,K]:=A[J-1,K]+A[J,K-1]  Prostor iterací = prostor k-tic řídících proměnných Hranice dány lineárními nerovnicemi (s konstantními koeficienty)  Detekce závislostí mezi iteracemi Přístupy do paměti (indexy) určeny lineárními výrazy (s k. k.)  Směry (vektory) závislostí popisují zakázané směry iterací Hledá se vektor ležící mimo konvexní obal vektorů závislostí  Výsledná smyčka pro jemnozrnnou paralelizaci Vnější iterace: Vektor (vektory) v konvexním obalu závislostí Vnitřní iterace: Vektor (vektory) mimo konvexní obal závislostí  Složitější případy: Prostor iterací se dělí na části řešené zvlášť Zjednodušení mezí cyklů: dělení na části jednoduchých tvarů 118

119 Hrubozrnná paralelizace  Hrubozrnná paralelizace  Velká běhová režie Vytváření vláken/úloh, plánování  Vyžaduje relativně velké na sobě nezávislé bloky  Předvídatelně velké bloky: Počet bloků odpovídá počtu CPU  Nepředvídatelně velké bloky: Počet bloků větší než počet CPU Bloky se přidělují na CPU dynamicky  Různé schopnosti běhového prostředí  Vlákna bez vzájemné synchronizace Bloky na sobě nesmějí vůbec záviset  Pipeline parallelism, task parallelism Plánovač respektuje vzájemné závislosti bloků Závislosti nesmějí být cyklické 119

120 Strip mining  Hledání zcela nezávislých bloků 120

121 Hrubozrnná paralelizace  Hrubozrnná paralelizace  Bloky k paralelizaci je třeba vybírat v horních patrech iterací  Zajištění dostatečné velikosti bloků  Smyčku je vhodné upravit, aby vnější iterace nebyly závislé  Stejné metody jako u jemnozrnné paralelizace, ale opačný cíl  Loop skewing pro hrubo- i jemnozrnnou paralelizaci  Vnější iterace nezávislé (pro hrubozrnnou paralelizaci)  Střední iterace závislé  Vnitřní iterace nezávislé (pro jemnozrnnou paralelizaci)  Problém: Vrstev iterací je obvykle málo Středních iterací musí být dost na pokrytí konvexního obalu závislostí 121

122 Hrubozrnná paralelizace  Problém: Vrstev iterací je obvykle málo  Řešení: Blocking  Prostor iterací se rozdělí na menší díly (bloky)  Tím vznikají další úrovně iterace  Iterace nad bloky se uspořádají pro hrubozrnný paralelismus  Vnější iterace řeší nezávislé skupiny bloků Strip mining: Vlákna  Vnitřní iterace procházejí závislé bloky uvnitř skupin Task parallelism: Tasky  Iterace uvnitř bloky se upraví pro jemnozrnný paralelismus  Vnější iterace jsou závislé  Vnitřní iterace jsou bez závislostí SIMD, ILP 122

123 Blocking  Vytvoření bloků 123

124 Blocking  Strip mining nad bloky 124

125 Blocking  Loop skewing uvnitř bloků 125

126 Blocking  Blocking  Původní iterace rozděleny na 2 patra Vždy ekvivalentní Problémy se zbytky  Nové iterace promíchány Pouze některé výměny jsou možné Cílem je nezávislost v okrajových patrech parallel for J1 := 0 to N-1 step SJ do for K1 := 0 to P-1 step SK do for K2 := 1 to SK do parallel for J2 := 1 to SJ do begin J := J1 * SJ + J2; K := K1 * SK + K2; C[I,J] := C[I,J]+A[I,K]*B[K,J] end 126 K J

127 Blocking  Blocking  Implementace vlákny for J1 := 0 to N-1 step SJ do create_thread( f, J1); wait(); function f( J1) begin for K1 := 0 to P-1 step SK do for K2 := 1 to SK do parallel for J2 := 1 to SJ do begin J := J1 * SJ + J2; K := K1 * SK + K2; C[I,J] := C[I,J]+A[I,K]*B[K,J] end 127 K J

128 Blocking  Blocking  Task parallelism for J1 := 0 to N-1 step SJ do for K1 := 0 to P-1 step SK do begin TN := new_task( f, J1, K1); add_dep( TP, TN); TP := TN; end; run(); function f( J1, K1) begin for K2 := 1 to SK do parallel for J2 := 1 to SJ do begin J := J1 * SJ + J2; K := K1 * SK + K2; C[I,J] := C[I,J]+A[I,K]*B[K,J] end 128 K J

129 Optimalizace pro cache  Podmínky dobrého využití cache  Prostorová lokalita Jednotkou přístupu je cache line (typ. 64 B) Přístupy do sousedních míst mají být blízko, nejlépe najednou Zápisy také způsobují výpadky - antidependence se řeší také  Časová lokalita Čím delší je doba mezi přístupy, tím větší je pravděpodobnost výpadku Přístupy k témuž paměťovému místu je výhodné v čase rozmístit nepravidelně 129

130 Další optimalizace 130

131 131 Architektura překladače  Detailní pohled akademika (pouze optimalizace) Muchnick: Advanced Compiler Design and Implementation Scalar replacement of array references Data-cache optimizations Procedure integration Tail-call optimization Scalar replacement of aggregates Sparse conditional constant propagation Interprocedural constant propagation Procedure specialization and cloning Sparse conditional constant propagation Global value numbering Local and global copy propagation Sparse conditional constant propagation Dead-code elimination Local and global common-subexpression elimination Loop-invariant code motion Dead-code elimination Code hoisting Induction-variable strength reduction Linear-function test replacement Induction-variable removal Unnecessary bounds-checking elimination Control-flow optimizations In-line expansion Leaf-routine optimization Shrink wrapping Machine idioms Tail merging Branch optimizations and conditional moves Dead-code elimination Software pipelining, loop unrolling Basic-block and branch scheduling Register allocation Basic-block and branch scheduling Intraprocedural I-cache optimization Instruction prefetching Data prefetching Branch prediction Interprocedural register allocation Aggregation of global references Interprocedural I-cache optimization Constant folding Algebraic simplification and reassociation

132 132 Další optimalizace  Částečné vyhodnocení  Část požadovaného výpočtu je vyhodnocována již překladačem  Výpočet konstantních výrazů  Constant-expression evaluation (constant folding)  Výpočet podmíněně konstantních výrazů  Sparse conditional constant propagation  Algebraické úpravy  Využití algebraických identit ke zjednodušení kódu  Algebraické úpravy výrazů  Redukce síly v cyklech  Strength reduction  Odstranění zbytečných kontrol mezí

133 133 Další optimalizace  Odstranění redundance  Nahrazení opakovaných výpočtů uložením výsledku  Copy propagation  Lokální/globální eliminace společných podvýrazů  Common-subexpression elimination  Přesun invariantního kódu z cyklu  Loop-invariant code motion  Partial-redundancy elimination  Lazy code motion  Odstranění neužitečného kódu  Odstranění mrtvého kódu  Dead-code elimination  Odstranění nedosažitelného kódu  Unreachable-code elimination  Optimalizace skoků  Jump optimization

134 134 Částečné vyhodnocení  Výpočet (pod)výrazů obsahujících pouze konstanty  Constant-expression evaluation  Obvykle prováděn již front- endem  Určení proměnných s konstantním obsahem  Constant folding  Určení proměnných s podmíněně konstantním obsahem  Sparse conditional constant propagation  Upravuje control-flow! a = b + (4 * 10); c = 4 * 10; d = c + 5; e = f + (d * 2); if ( g > h ) i = 1; else i = 0; j = i + 1; if ( j > 1 ) k = k + 1;

135 135 Částečné vyhodnocení  Výpočet (pod)výrazů obsahujících pouze konstanty  Constant-expression evaluation  Obvykle prováděn již front- endem  Určení proměnných s konstantním obsahem  Constant folding  Určení proměnných s podmíněně konstantním obsahem  Sparse conditional constant propagation  Upravuje control-flow!  Integrace procedur generuje nové příležitosti pro částečné vyhodnocení void f( int i, bool f) { int j = i + 1; if ( f ) g( j); else h( j); } f( k + 1, false);

136 136 Částečné vyhodnocení a = b + 40; c = 40; d = 45; e = f + 90; if ( g > h ) { i = 1; j = 2; k = k + 1; } else { i = 0; j = 1; } a = b + (4 * 10); c = 4 * 10; d = c + 5; e = f + (d * 2); if ( g > h ) i = 1; else i = 0; j = i + 1; if ( j > 1 ) k = k + 1;

137 137 Algebraické úpravy  Algebraické úpravy výrazů  Většinou v souvislosti s přítomností konstant  Důležité pro ukazatelovou aritmetiku (přístup k polím)  Úprava do kanonického tvaru  Redukce síly v cyklech  Důležité pro přístup k polím  Odstranění zbytečných kontrol mezí  Machine idioms  Instrukce provádějící speciální kombinace nebo varianty operací a = ((b * 3) + 7) * 5 a = b * for ( i = 1; i < 10; ++i ) a[ 4 * i] = 0; for ( j = 4; j < 40; j += 40 ) a[ j] = 0; int b[ 10]; for ( i = 0; i < 10; ++i ) b[ i] = 0;

138 138 Algebraické úpravy  Převedení control-flow na algebraické operace  Conditional move  Ušetří podmíněné skoky  Může přidat zbytečné operace  Užitečnost obtížně odhadnutelná  Cena podmíněných skoků závisí na úspěšnosti predikce  Překladač úspěšnost nedokáže odhadnout  Profilem řízené optimalizace if ( a > b ) c = d + e; CMP t,a,b ADD u,d,e CMOV t,c,u

139 139 Odstranění redundance  Copy propagation  Lokální/globální eliminace společných podvýrazů  Přesun invariantního kódu z cyklu  Častý výskyt u přístupu k polím  Partial-redundancy elimination  Lazy code motion  Integrace procedur generuje nové redundance b = a; c = b; // c = a; c = a + b; d = a + b; // d = c; for ( i = 0; i < 10; ++i) a[ i] = k + l; if ( a < b ) c = d + e; f = d + e;

140 140 Odstranění neužitečného kódu  Odstranění mrtvého kódu  Kód, jehož efekt nebude využit Přiřazení do proměnných, které již nebudou čteny  Odstranění nedosažitelného kódu  Kód, ke kterému nevede cesta  Optimalizace skoků  Skoky na skoky apod.  Řeší především chyby vyprodukované předchozími fázemi  Aplikuje se opakovaně a = b + 40; c = 40; d = 45; e = f + 90; if ( g > h ) { i = 1; j = 2; k = k + 1; } else { i = 0; j = 1; }

141 141 Přesouvání kódu  Code hoisting  Provedení operace dříve, než předepisoval původní program  Omezeno závislostmi  „very busy“ expression = operace, která bude provedena v každém pokračování  Algoritmus: Lazy code motion  Užitečnost úpravy je nejistá  Paralelismus  Omezený počet registrů if ( g > h ) { for ( i = 1; i < k; ++ i) { a[ i] = x + y; } u = x + y; } else { z = x + y; }

142 142 Optimalizace režie volání  Integrace procedur  a.k.a inline-expansion  Listové procedury  Nevolají žádné další  Není třeba kompletní prolog a epilog procedury  Užitečné zejména v přítomnosti výjimek  Shrink wrapping  Přesouvání prologu a epilogu  Ve větvích, které nevolají další procedury, se prolog a epilog anihilují Tail merging Ztotožnění identických konců procedur Poslední BB často obsahuje pouze epilog a je tudíž shodný Šetří velikost kódu Zlepšuje využití I-cache

143 143 Interprocedurální úpravy  Specializace procedur  Procedury se naklonují  Jednotlivé klony se přizpůsobují okolnostem, které panují při jejich volání  Speciální tvary argumentů  Konstantní argumenty  Aliasing  Interprocedurální alokace registrů  Volací konvence se upravuje podle místních podmínek  Efekt je obdobný jako u integrace procedur  Specializace vede k menší expanzi kódu  Specializace se obtížněji řídí  Integrace odstraňuje režii volání  Integrace umožňuje další optimalizace

144 144 Nápověda pro procesor  Intraprocedural I-cache optimization  Využití atomicity cache-line  Serializace BB tak, aby chování CPU vedlo k minimálnímu počtu výpadků I-cache  Instruction prefetching  Data prefetching  Využití speciálních instrukcí pro nedestruktivní čtení  Branch prediction  Generování nápovědy pro branch prediction

145 145 Architektura překladače  Detailní pohled akademika (pouze optimalizace) Muchnick: Advanced Compiler Design and Implementation Scalar replacement of array references Data-cache optimizations Procedure integration Tail-call optimization Scalar replacement of aggregates Sparse conditional constant propagation Interprocedural constant propagation Procedure specialization and cloning Sparse conditional constant propagation Global value numbering Local and global copy propagation Sparse conditional constant propagation Dead-code elimination Local and global common-subexpression elimination Loop-invariant code motion Dead-code elimination Code hoisting Induction-variable strength reduction Linear-function test replacement Induction-variable removal Unnecessary bounds-checking elimination Control-flow optimizations In-line expansion Leaf-routine optimization Shrink wrapping Machine idioms Tail merging Branch optimizations and conditional moves Dead-code elimination Software pipelining, loop unrolling Basic-block and branch scheduling Register allocation Basic-block and branch scheduling Intraprocedural I-cache optimization Instruction prefetching Data prefetching Branch prediction Interprocedural register allocation Aggregation of global references Interprocedural I-cache optimization Constant folding Algebraic simplification and reassociation

146 146 Architektura překladače  Realita  GNU Compiler Collection Internals Remove useless statements Mudflap declaration registration Lower control flow Lower exception handling control flow Build the control flow graph Find all referenced variables RTL generation Generate exception handling landing pads Cleanup control flow graph Common subexpression elimination Global common subexpression elimination. Loop optimization Jump bypassing If conversion Web construction Life analysis Instruction combination Register movement Optimize mode switching Modulo scheduling Instruction scheduling Register class preferencing Local register allocation Global register allocation Reloading Basic block reordering Variable tracking Delayed branch scheduling Branch shortening Register-to-stack conversion Final Debugging information output Enter static single assignment form Warn for uninitialized variables Dead code elimination Dominator optimizations Redundant phi elimination Forward propagation of single-use variables Copy renaming PHI node optimizations May-alias optimization Profiling Lower complex arithmetic Scalar replacement of aggregates Dead store elimination Tail recursion elimination Forward store motion Partial redundancy elimination Loop invariant motion Canonical induction variable creation Induction variable optimizations Loop unswitching Vectorization Tree level if-conversion for vectorizer Conditional constant propagation Folding builtin functions Split critical edges Partial redundancy elimination Control dependence dead code elimination Tail call elimination Warn for function return without value Mudflap statement annotation Leave static single assignment form


Stáhnout ppt "Konstrukce překladačů David Bednárek www.ksi.mff.cuni.cz."

Podobné prezentace


Reklamy Google