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

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

Konstrukce překladačů

Podobné prezentace


Prezentace na téma: "Konstrukce překladačů"— Transkript prezentace:

1 Konstrukce překladačů
David Bednárek

2 Pravidla studia NSWI109 2/1 Z,Zk

3 Alternativa: Implementace části překladače Přednáška Zkouška - písemná
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 Literatura A.V. Aho, R. Sethi, J.D. Ullman Compiler: Principles, Techniques and Tools (1986, 2007) 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 Historie překladačů

7 Vývoj hardware a programovacích jazyků
1957: FORTRAN (IBM) První překladače 1960: IBM general-purpose registers Alokace registrů 1970: Cray - Pipeline Scheduling 1993: PowerPC (IBM) - Out-of-order execution Scheduling v HW 2008: Intel Atom, ARMv7, GPGPU - In-order execution Scheduling překladačem opět důležitý

8 Source: James Laurus @ HiPEAC 2015

9 Source: William J. Dally @ HiPEAC 2015

10 Source: William J. Dally @ HiPEAC 2015

11 Source: William J. Dally @ HiPEAC 2015

12 Architektura překladače

13 Architektura překladače
Amatérský pohled Lexikální analyzátor Posloupnost tokenů Parser Derivační strom Sémantický analyzátor Derivační strom Derivační strom Generátor kódu Cílový kód

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

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

16 Architektura překladače
Detailní pohled akademika (pouze optimalizace) Muchnick: Advanced Compiler Design and Implementation Scalar replacement of array references Data-cache optimizations Constant folding Algebraic simplification and reassociation Procedure integration Tail-call optimization Scalar replacement of aggregates Sparse conditional constant propagation Interprocedural constant propagation Procedure specialization and cloning 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 Intraprocedural I-cache optimization Instruction prefetching Data prefetching Branch prediction 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 Code hoisting Induction-variable strength reduction Linear-function test replacement Induction-variable removal Unnecessary bounds-checking elimination Control-flow optimizations Interprocedural register allocation Aggregation of global references Interprocedural I-cache optimization

17 Architektura překladače
Realita GNU Compiler Collection Internals 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 Control dependence dead code elimination Tail call elimination Warn for function return without value Mudflap statement annotation Leave static single assignment form 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 Remove useless statements Mudflap declaration registration Lower control flow Lower exception handling control flow Build the control flow graph Find all referenced variables

18 Názvosloví

19 Základní blok (BB – basic block)
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

20 Závislost (dependence)
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í

21 Skalární/jednoduchý/atomický typ (scalar)
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ší

22 Statická/globální proměnná (Lokální) 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

23 Alias Alias Proměnná bez aliasu
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

24 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

25 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ů

26 Volací konvence Volací konvence Umístění parametrů
Ú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

27 Č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

28 Typy Logický typ Fyzický 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í

29 Mezikódy Vysokoúrovňový mezikód Mezikód střední úrovně
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)

30 Mezikódy

31 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

32 Informace uložené v mezikódu střední úrovně
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ů

33 Seznam lokálních proměnných
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 Proměnné ve vnořených blocích se obvykle povyšují na úroveň procedury Kód procedury Další informace (popisy výjimek apod.)

34 Částečně sekvenční forma
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 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ů

35 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; 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 JMP L1 L2: RET_I32 Py

36 Čá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; 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 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 GT_I32 T2,Px,C1 JC T2 RET_I32 Py

37 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; return y; Control-Flow vždy if true if false ENTER LD_I32(Px) LD_I32(Py) LD_I32(Py) GT_I32 ST_I32(Vz) JC Dag Data-flow Závislosti LD_I32(Px) ST_I32(Py) LD_I32(Vz) ST_I32(Px) LD_I32(Py) LD_I32(Px) MOD_I32 LD_I32(Px) ST_I32(Vz) GTC_I32(C1) LD_I32(Px) JC CONST:(C1,I32,0) PROC ”gcd” PARAM:(Px,I32,”x”),(Py,I32,”y”) VAR:(Vz,I32,”z”) ST_I32(Py) LD_I32(Vz) ST_I32(Px) LD_I32(Py) RET_I32

38 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

39 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

40 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 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

41 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 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 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 GT_I32 T2,Px,C1 JC T2 RET_I32 Py

42 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; 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

43 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; 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 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 GT_I32 T2,Px,C1 JC T2 RET_I32 Py

44 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; return y; Control-Flow vždy if true if false ENTER LD_I32(Px) LD_I32(Py) LD_I32(Py) GT_I32 ST_I32(Vz) JC Dag operand LD_I32(Px) ST_I32(Py) LD_I32(Vz) ST_I32(Px) LD_I32(Py) LD_I32(Px) MOD_I32 LD_I32(Px) ST_I32(Vz) GTC_I32(C1) LD_I32(Px) JC CONST:(C1,I32,0) PROC ”gcd” PARAM:(Px,I32,”x”),(Py,I32,”y”) VAR:(Vz,I32,”z”) ST_I32(Py) LD_I32(Vz) ST_I32(Px) LD_I32(Py) RET_I32

45 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; return y; Control-Flow vždy if true if false GT_I32 LD_I32(Px) LD_I32(Py) JC ENTER ST_I32(Vz) ST_I32(Py) LD_I32(Vz) ST_I32(Px) GTC_I32(C1) MOD_I32 RET_I32 Dag operand pořadí CONST:(C1,I32,0) PROC ”gcd” PARAM:(Px,I32,”x”),(Py,I32,”y”) VAR:(Vz,I32,”z”)

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

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

48 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; return y; Control-Flow vždy if true if false GT_I32 LD_I32(Px) LD_I32(Py) JC ENTER GTC_I32(C1) RET_I32 ST_I32(Vz) ST_I32(Py) LD_I32(Vz) ST_I32(Px) MOD_I32 Dag dependence: operand w-r w-? antidependence: r-w ?-w CONST:(C1,I32,0) PROC ”gcd” PARAM:(Px,I32,”x”),(Py,I32,”y”) VAR:(Vz,I32,”z”)

49 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; return y; Dag operand antidependence: r-w GT_I32 LD_I32(Px) LD_I32(Py) JC ENTER GTC_I32(C1) RET_I32 ST_I32(Vz) ST_I32(Py) LD_I32(Vz) ST_I32(Px) MOD_I32 Oblasti platnosti Px Py Vz/1 Vz/2 CONST:(C1,I32,0) PROC ”gcd” PARAM:(Px,I32,”x”),(Py,I32,”y”) VAR:(Vz,I32,”z”)

50 Určení rozsahů platnosti (live-range analysis)
Rozsah platnosti (životnost) jednoduché lokální proměnné bez aliasu Proměnná je v bodě a živá, jestliže existuje cesta control-flow grafem do bodu b taková, že: Na cestě a-b není žádný zápis do této proměnné V bodě b je tato proměnná čtena Jiné druhy proměnných se obvykle nezkoumají Pro složené proměnné (pole/struktury) neplatí předpoklad, že zápisem do proměnné se předchozí obsah stává irelevantní Složená proměnná je tedy živá všude, kde existuje cesta ke čtení U proměnných s aliasem nelze obvykle jednoznačně určit čtení a zápisy Definici lze upravit i pro nejistá čtení a zápisy Účelem zkoumání životnosti je především alokace registrů Složené a aliasované proměnné do registrů umístit nelze

51 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 Vylepšení Určení komponent souvislosti a přeznačení proměnných

52 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 <b1,b2> 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|)

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

54 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; return y; Dag operand antidependence: r-w GT_I32 LD_I32(Px) LD_I32(Py) JC ENTER ST_I32(Vz) ST_I32(Py) LD_I32(Vz) ST_I32(Px) MOD_I32 GTC_I32(C1) RET_I32 Rozhraní 1 Px Py Rozhraní 2 CONST:(C1,I32,0) PROC ”gcd” PARAM:(Px,I32,”x”),(Py,I32,”y”) VAR:(Vz,I32,”z”)

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

56 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; return y; Dag data GT_I32 JC ENTER GTC_I32(C1) RET_I32 MOD_I32 Rozhraní 1 Px Py Rozhraní 2 CONST:(C1,I32,0) PROC ”gcd” PARAM:(Px,I32,”x”),(Py,I32,”y”)

57 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; return y; Dag data RET_I32 GTC_I32(C1) JC GT_I32 ENTER MOD_I32 Rozhraní 1 Px Py Rozhraní 2 CONST:(C1,I32,0) PROC ”gcd” PARAM:(Px,I32,”x”),(Py,I32,”y”)

58 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; return y; RET_I32 GTC_I32(C1) JC GT_I32 ENTER MOD_I32 CONST:(C1,I32,0) PROC ”gcd” PARAM:(Px,I32,”x”),(Py,I32,”y”)

59 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 ENTER MOD_I32

60 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 RET_I32 GT_I32 ENTER L4 L3 L1 L2 L5

61 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 Sekvenční Mezikód (střední úrovně) Optimalizace Mezikód (střední úrovně) Strojově závislé optimalizace Mezikód (střední úrovně) Generátor kódu Mezikód nízké úrovně Strojově závislé optimalizace Cílový kód

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

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

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

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

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

67 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ů Standardní řešení: Barvení grafu

68 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

69 Částečně sekvenční kód Ekvivalenty strojových instrukcí
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

70 Optimalizace: Minimalizace přesunových instrukcí
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

71 Barvení grafu (VAR,C) n barvami n je počet fyzických registrů
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

72 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; <v,u>  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

73 Optimalizace: Minimalizace přesunových instrukcí
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

74 Alokovat neobarvené uzly na zásobníku
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ů

75 Množiny povolených registrů
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

76 Registrové volací konvence
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

77 Provádí se na jednom základním bloku
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

78 Instrukce volání procedury
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í

79 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

80 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í

81 Latence – časování závislých dvojic instrukcí
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í

82 Rezervační tabulky – schopnosti paralelního zpracování
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

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

84 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 i,0 mov rs,0 jgt mov r1,[rp] inc rp dec ri xor rs,r1 cmp ri,0 jgt ret

85 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 z instrukce do instrukce čas cmp ri,0 jgt 1 mov r1,[rp] xor rs,r1 4 dec ri cmp ri,c 2 inc rp mov r1,[rp] inc rp 4 1 dec ri xor rs,r1 2 cmp ri,0 1 1 z instrukce čas inc rp 2 jgt 1 dec ri xor rs,r1 1 jgt

86 Příklad – rezervační tabulky
Kapacita procesoru inc r1 dec r1 xor r1,r2 cmp r1,r2 R MEM ALU W 1 2 R MEM ALU W 1 2 mov r1,[r2] R MEM ALU W 1 2 3 4 mov r1,[rp] inc rp 4 1 dec ri xor rs,r1 2 cmp ri,0 1 1 1 jgt jgt R MEM ALU W 1

87 Příklad – scheduling Krok 1 Připravené instrukce Kritická cesta
dec ri mov r1,[rp] Kritická cesta mov r1,[rp] – 5 Vybrána instrukce Umístěna do času 0 čas R MEM ALU W mov 1 2 3 4 mov r1,[rp] inc rp 4 1 dec ri xor rs,r1 2 cmp ri,0 1 1 1 jgt

88 Příklad – scheduling Krok 2 Připravené instrukce Kritická cesta
inc rp dec ri xor rs,r1 Kritická cesta xor rs,r1 – 5 Vybrána instrukce Čas 4 určen latencí čas R MEM ALU W mov 1 2 3 4 xor 5 6 mov r1,[rp] inc rp 4 1 dec ri xor rs,r1 2 cmp ri,0 1 1 1 jgt

89 Příklad – scheduling Krok 3 Připravené instrukce Kritická cesta
inc rp dec ri Kritická cesta dec ri - 4 Vybrána instrukce Čas 0 vyhovuje latenci Rezervační tabulky jsou obsazeny Zvolen čas 1 čas R MEM ALU W mov 1 dec 2 3 4 xor 5 6 mov r1,[rp] inc rp 4 1 dec ri xor rs,r1 2 cmp ri,0 1 1 1 jgt

90 Příklad – scheduling Krok 4 Připravené instrukce Kritická cesta
inc rp cmp ri,0 Kritická cesta cmp ri,0 – 4 Vybrána instrukce Čas 3 určen latencí čas R MEM ALU W mov 1 dec 2 3 cmp 4 xor 5 6 mov r1,[rp] inc rp 4 1 1 dec ri xor rs,r1 2 cmp ri,0 1 1 1 jgt

91 Rezervační tabulky pro časy 0-4 obsazeny Umístěno v čase 5
Příklad – scheduling Krok 5 Připravené instrukce inc rp (jgt) – musí být poslední Vybrána instrukce Čas 0 vyhovuje latenci Rezervační tabulky pro časy 0-4 obsazeny Umístěno v čase 5 čas R MEM ALU W mov 1 dec 2 3 cmp 4 xor 5 inc 6 7 mov r1,[rp] inc rp 4 1 1 dec ri xor rs,r1 3 cmp ri,0 1 1 1 jgt

92 Příklad – scheduling Krok 6 Připravené instrukce
jgt Latenci vyhovuje čas 4 Instrukce však musí být poslední Vybrán čas 5 čas R MEM ALU W mov 1 dec 2 3 cmp 4 xor 5 inc xor, jgt 6 7 mov r1,[rp] 5 inc rp 4 1 1 dec ri xor rs,r1 3 cmp ri,0 1 1 1 jgt

93 Příklad – scheduling Výsledný kód 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 čas R MEM ALU W mov 1 dec 2 3 cmp 4 xor 5 inc xor, jgt 6 7 mov r1,[rp] 5 inc rp 1 4 1 dec ri xor rs,r1 3 cmp ri,0 1 1 5 jgt

94 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(n2) 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

95 Příklad – scheduling Výsledný kód Chování ve smyčce
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 čas R MEM ALU W mov 1 dec 2 3 cmp 4 inc 5 xor inc, jgt 6 7 8 9 10 11 12 13 14 15

96 Efekt kapacity procesoru
Příklad – scheduling 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 čas R MEM ALU W mov, dec 1 inc mov dec 2 cmp 3 4 xor jgt mov, cmp 5 6 7 8 9 10 11 12 13 14 R MEM ALU W 2 1

97 Příklad – software pipelining
Závislosti uvnitř BB Závislosti přes hranice BB (loop-carried dependences) z instrukce do instrukce čas cmp ri,0 jgt 1 mov r1,[rp] xor rs,r1 4 dec ri cmp ri,c 2 inc rp 1 2 z instrukce do instrukce čas inc rp 2 mov r1,[rp] dec ri cmp ri,0 xor rs,r1 jgt 1 mov r1,[rp] 2 inc rp 4 2 1 dec ri xor rs,r1 2 cmp ri,0 1 2 jgt

98 Příklad – 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 čas R MEM ALU W mov1, dec1 1 inc1 mov1 dec1 2 cmp1 3 dec2 cmp1, jgt1 4 xor1, mov2 mov1, cmp1 5 inc2, cmp2 mov2 xor1 6 dec3 7 dec3, jgt2 8 xor2, mov3 mov2, dec3 9 inc3, cmp3 mov3 xor2 10 dec4 11 dec4, jgt3 12 xor3, mov4 mov3, dec4 13 inc4, cmp4 mov4 xor3 14 dec5 15 dec5, jgt4 16 xor4, mov5 mov4, dec5 17 inc5, cmp5 mov5 xor4 18 dec6 19 dec6, jgt5 20 xor5 mov5, dec6 21 22

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

100 Příklad – software pipelining
čas R MEM ALU W mov1, dec1 1 inc1 mov1 dec1 2 cmp1 3 dec2 cmp1, jgt1 4 xor1, mov2 mov1, cmp1 5 inc2, cmp2 mov2 xor1 6 dec3 7 dec3, jgt2 8 xor2, mov3 mov2, dec3 9 inc3, cmp3 mov3 xor2 10 dec4 11 dec4, jgt3 12 xor3, mov4 mov3, dec4 13 inc4, cmp4 mov4 xor3 14 dec5 15 dec5, jgt4 16 xor4, mov5 mov4, dec5 17 inc5, cmp5 mov5 xor4 18 dec6 19 dec6, jgt5 20 xor5 mov5, dec6 21 22 2/1 dec ri 0/1 2/0 2/1 cmp ri,0 inc rp 1/1 1/0 jgt 0/0 2/1 1/1 mov r1,[rp] 0/1 2/1 4/0 xor rs,r1

101 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 2/1 dec ri 0/1 2/0 2/1 cmp ri,0 inc rp 1/1 1/0 jgt 0/0 2/1 1/1 mov r1,[rp] 0/1 2/1 4/0 xor rs,r1

102 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 (TB-TA)-M*(IB-IA) ≥ L-M*D čas R MEM ALU W T+0 xor[N], mov[N+1] mov[N], dec[N+1] T+1 inc[N+1], cmp[N+1] mov[N+1] xor[N] T+2 dec[N+2] T+3 dec[N+2], jgt[N+1] 2/1 2/2 dec ri 0/1 2/0 2/1 1/1 cmp ri,0 1/1 inc rp 1/1 1/0 3/1 jgt 0/0 2/1 1/1 0/1 mov r1,[rp] 0/1 2/1 4/0 0/0 B A L/D TB/IB TA/IA xor rs,r1

103 Modulo scheduling 2/2 dec ri 1/1 cmp ri,0 1/1 inc rp 3/1 jgt 0/1
čas R MEM ALU W xor2, mov3 mov2, dec3 1 inc3, cmp3 mov3 xor2 2 dec4 3 dec4, jgt3 4 xor3, mov4 mov3, dec4 5 inc4, cmp4 mov4 xor3 6 dec5 7 dec5, jgt4 2/1 2/2 dec ri 0/1 2/0 2/1 1/1 cmp ri,0 1/1 inc rp 1/1 1/0 3/1 jgt 0/0 2/1 1/1 0/1 mov r1,[rp] 0/1 2/1 4/0 0/0 xor rs,r1

104 Příklad – software pipelining
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 čas R MEM ALU W mov1, dec1 1 inc1 mov1 dec1 2 cmp1 3 dec2 cmp1, jgt1 4 xor1, mov2 mov1, cmp1 5 inc2, cmp2 mov2 xor1 6 dec3 7 dec3, jgt2 8 xor2, mov3 mov2, dec3 9 inc3, cmp3 mov3 xor2 10 dec4 11 dec4, jgt3 12 xor3, mov4 mov3, dec4 13 inc4, cmp4 mov4 xor3 14 dec5 15 dec5, jgt4 16 xor4, mov5 mov4, dec5 17 inc5, cmp5 mov5 xor4 18 dec6 19 dec6, jgt5 20 xor5 mov5, dec6 21 22

105 Příklad – software pipelining
mov r1,[rp] dec ri inc rp cmp ri,0 jle l2 l1: xor rs,r1 jgt l1 l2: čas R MEM ALU W mov1, dec1 1 inc1 mov1 dec1 2 cmp1 3 dec2 cmp1, jgt1 4 xor1, mov2 mov1, cmp1 5 inc2, cmp2 mov2 xor1 6 dec3 7 dec3, jgt2 8 xor2, mov3 mov2, dec3 9 inc3, cmp3 mov3 xor2 10 dec4 11 dec4, jgt3 12 xor3, mov4 mov3, dec4 13 inc4, cmp4 mov4 xor3 14 dec5 15 dec5, jgt4 16 xor4, mov5 mov4, dec5 17 inc5, cmp5 mov5 xor4 18 dec6 19 dec6, jgt5 20 xor5 mov5, dec6 21 22

106 Duplikace proměnných (Variable expansion)
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 2/1 dec ri 0/1 2/0 2/1 cmp ri,0 inc rp 1/1 1/0 jgt 0/0 2/1 1/1 mov r1,[rp] 0/1 2/1 4/0 xor rs,r1

107 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 2/1 dec ri dec ri 2/1 0/1 0/1 2/0 2/0 cmp ri,0 cmp ri,0 1/1 1/1 1/0 1/0 jgt jgt 2/1 inc rp inc rp 2/1 0/0 0/0 1/1 2/1 1/1 2/1 mov r1,[rp] mov r2,[rp] 0/2 0/2 4/0 4/0 2/1 xor rs,r1 xor rs,r2 2/1

108 Duplikace proměnných (Variable expansion)
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í 2/1 dec ri 2/0 2/1 cmp ri,0 inc rp 1/1 1/0 jgt 2/1 1/1 mov r1,[rp] 2/1 4/0 xor rs,r1

109 Příklad – modulo scheduling s duplikací
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: 2/1 2/3 dec ri 0/1 2/0 2/1 1/2 cmp ri,0 0/1 inc rp 1/1 1/0 0/1 jgt 0/0 2/1 1/1 2/2 mov r1,[rp] 0/2 2/1 4/0 0/0 xor rs,r1 čas R MEM ALU W xor2, inc3 mov3 dec4, jgt3 mov2, cmp3 1 cmp4 dec4 2 mov4, dec5

110 Příklad – Intel compiler – x64
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 /*...*/ k = i >> 1; j = 0; do { r8 = *p; r9 = *(p+1); s ^= r8; s ^= r9; p += 2; j += 1; } while ( j < k ); /* ... */

111 Cray 1

112 Cray 1

113 Cray 1

114 Cray 1

115 Paralelizace Hardware Proč paralelizace? Jak paralelizovat?
Zrychlení stojí příliš mnoho energie P = k f2 Místa je dost (108 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

116 Jemnozrnný paralelismus
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

117 Jemnozrnný paralelismus
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é

118 Paralelizace Vektorizace Nízký stupeň (2-8) Vysoký stupeň (64)
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

119 Výměna vzájemného zanoření cyklů
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 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á

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

121 Loop reversal Upravený průchod Většina sousedů v průchodu je nezávislá
K J

122 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] K J

123 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] K J

124 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ů

125 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é

126 Hledání zcela nezávislých bloků
Strip mining Hledání zcela nezávislých bloků K J

127 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í

128 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

129 Blocking Vytvoření bloků K J

130 Blocking Strip mining nad bloky K J

131 Loop skewing uvnitř bloků
Blocking Loop skewing uvnitř bloků K J

132 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 K J

133 Blocking Blocking Implementace vlákny J 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 J := J1 * SJ + J2; K := K1 * SK + K2; C[I,J] := C[I,J]+A[I,K]*B[K,J] end K J

134 Blocking Blocking Task parallelism J 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) for K2 := 1 to SK do parallel for J2 := 1 to SJ do J := J1 * SJ + J2; K := K1 * SK + K2; C[I,J] := C[I,J]+A[I,K]*B[K,J] end K J

135 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ě Blocking většinou vyhovuje i z pohledu cache Obvykle řeší časovou lokalitu Prostorová lokalita závisí na datových strukturách Překladače procedurálních jazyků datové struktury neupravují Mohou však upravit časový průběh přístupů

136 Points-to analysis Alias analysis

137 Paměťová místa se rozdělí do skupin
Points-to analysis Points-to analysis Paměťová místa se rozdělí do skupin Zahrnuje proměnné i dynamicky alokovanou paměť U každého přístupu se určí, které skupiny může zasáhnout Přístupem je výraz (lvalue) v překládaném kódu Cíl: Přesnější analýza závislostí Mají-li dva přístupy disjunktní množiny points-to skupin, nemůže mezi nimi být alias, a tudíž jsou nezávislé Problém: Paměťových míst je neomezeně mnoho Překladač má k dispozici omezené prostředky Překladač řeší všechny možnosti control-flow najednou

138 Kontextová analýza (flow-sensitive)
Points-to analysis Varianty Kontextová analýza (flow-sensitive) Points-to informace je relativní vůči pozici v programu Semantika: Na pozici P v programu výraz E může označovat paměťové místo ze skupiny M Pozice může a nemusí zahrnovat kontext, odkud byla procedura volána (call stack) Bezkontextová analýza (flow-insensitive) Points-to informace je společná pro celý program Semantika: Existuje pozice v programu, kde výraz E může označovat paměťové místo ze skupiny M Překladač počítá horní odhad Sémantika: "může" = "překladač nebyl schopen vyloučit"

139 Překladač počítá horní odhad
Points-to analysis Překladač počítá horní odhad Sémantika: "může" = "překladač nebyl schopen vyloučit" Všechny metody analýzy jsou iterativní (rekurzivní) Zvolená přesnost reprezentace dramaticky ovlivňuje výsledek Analýza s kontextem: p = & x; // p -> x * p = & y; // x -> y p = & u; // p -> u * p = & v; // u -> v Bez kontextu: p -> {x, u} x -> {y, v} u -> {y, v}

140 Na základě kódu se sestaví soustava množinových nerovnic:
Points-to analysis Andersenova metoda Bez kontextu 𝝈(𝒑) = množina (skupin) paměťových míst, na která může odkazovat proměnná (paměťové místo/skupina) 𝒑 Na základě kódu se sestaví soustava množinových nerovnic: p = & x; {𝒙}⊆𝝈(𝒑) p = q; 𝝈(𝒒)⊆ 𝝈(𝒑) p = * q; ∀𝒓 ∈ 𝝈 𝒒 𝝈 𝒓 ⊆𝝈 𝒑 * p = q; ∀𝒓 ∈ 𝝈 𝒑 𝝈 𝒒 ⊆𝝈 𝒓 Soustava se vyřeší metodou nejmenšího pevného bodu

141 Steensgaardova metoda
Points-to analysis Steensgaardova metoda Bez kontextu Méně přesná, ale rychlejší než Andersenova metoda 𝝉(𝒑) = "typ" proměnné (paměťového místa/skupiny) 𝒑 definován rekurzivně, na základě typu, na který může odkazovat 𝝉(𝝉(𝒑)) - "typ" výrazu *p, atd. Začínáme s předpokladem, že 𝝉(𝒑) jsou navzájem různé Přiřazení nalezená v kódu způsobují ztotožnění typů Ztotožnění typů se propagují směrem k odkazovaným typům

142 Další optimalizace

143 Architektura překladače
Detailní pohled akademika (pouze optimalizace) Muchnick: Advanced Compiler Design and Implementation Scalar replacement of array references Data-cache optimizations Constant folding Algebraic simplification and reassociation Procedure integration Tail-call optimization Scalar replacement of aggregates Sparse conditional constant propagation Interprocedural constant propagation Procedure specialization and cloning 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 Intraprocedural I-cache optimization Instruction prefetching Data prefetching Branch prediction 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 Code hoisting Induction-variable strength reduction Linear-function test replacement Induction-variable removal Unnecessary bounds-checking elimination Control-flow optimizations Interprocedural register allocation Aggregation of global references Interprocedural I-cache optimization

144 Výpočet konstantních výrazů Výpočet podmíněně konstantních výrazů
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í

145 Další optimalizace Odstranění redundance Copy propagation
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

146 Výpočet (pod)výrazů obsahujících pouze konstanty
Čá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;

147 Výpočet (pod)výrazů obsahujících pouze konstanty
Čá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);

148 Částečné vyhodnocení a = b + 40; a = b + (4 * 10); c = 40; c = 4 * 10;
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;

149 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;

150 Převedení control-flow na algebraické operace Conditional move
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

151 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;

152 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;

153 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;

154 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

155 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

156 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

157 Architektura překladače
Detailní pohled akademika (pouze optimalizace) Muchnick: Advanced Compiler Design and Implementation Scalar replacement of array references Data-cache optimizations Constant folding Algebraic simplification and reassociation Procedure integration Tail-call optimization Scalar replacement of aggregates Sparse conditional constant propagation Interprocedural constant propagation Procedure specialization and cloning 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 Intraprocedural I-cache optimization Instruction prefetching Data prefetching Branch prediction 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 Code hoisting Induction-variable strength reduction Linear-function test replacement Induction-variable removal Unnecessary bounds-checking elimination Control-flow optimizations Interprocedural register allocation Aggregation of global references Interprocedural I-cache optimization

158 Architektura překladače
Realita GNU Compiler Collection Internals 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 Control dependence dead code elimination Tail call elimination Warn for function return without value Mudflap statement annotation Leave static single assignment form 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 Remove useless statements Mudflap declaration registration Lower control flow Lower exception handling control flow Build the control flow graph Find all referenced variables


Stáhnout ppt "Konstrukce překladačů"

Podobné prezentace


Reklamy Google