Konstrukce překladačů

Slides:



Advertisements
Podobné prezentace
A1PRG - Programování – Seminář Ing. Michal Typová konverze, oblast platnosti, paměťové třídy 9 Verze
Advertisements

J. Pokorný 1 DOTAZOVACÍ JAZYKY slajdy přednášce DBI006 J. Pokorný MFF UK
TEORIE ROZHODOVÁNÍ A TEORIE HER
Orbis pictus 21. století Tato prezentace byla vytvořena v rámci projektu.
Přednáška č. 3 Normalizace dat, Datová a funkční analýza
HYPERTEXT PREPROCESSOR. PROGRAMOVÁNÍ. DEFINICE POJMŮ Problém Problém nevyřešený, nežádoucí stav obvykle vyžaduje nějaké řešení Neřešitelný problém Neřešitelný.
Aplikace teorie grafů Základní pojmy teorie grafů
Sylabus V rámci PNV budeme řešit konkrétní úlohy a to z následujících oblastí: Nelineární úlohy –Řešení nelineárních rovnic –Numerická integrace Lineární.
ALGO – Algoritmizace 1. cvičení
Téma 3 Metody řešení stěn, metoda sítí.
C# pro začátečníky Mgr. Jaromír Osčádal
Téma 3 ODM, analýza prutové soustavy, řešení nosníků
Otázky k absolutoriu HW 1 - 5
Sčítání a odčítání úhlů
Programování v C++ Cvičení.
Principy překladačů Běhová podpora Jakub Yaghob. Běhová podpora Statická podpora jazyka Překladač Interface na knihovny Hlavičkové soubory Dynamická podpora.
Principy překladačů Mezikód Jakub Yaghob.
Úvod. Základní úrovně: hardwarová (procesory, jádra) programová (procesy, vlákna) algoritmická (uf... ) Motivace: zvýšení výkonu redundance jiné cíle,
Dynamické rozvozní úlohy
Programování v Pascalu Přednáška 7
Programování PA - 2.
Materiály k přednášce Úvod do programování Ondřej Čepek.
Principy překladačů Překladač Jakub Yaghob. Literatura a slajdy Aho, Sethi, Ullman: Compilers - Principles, Techniques and Tools, Addison-Wesley 1986.
Generování mezikódu Jakub Yaghob
Principy překladačů Vysokoúrovňové optimalizace Jakub Yaghob.
Principy překladačů Architektury procesorů Jakub Yaghob.
Výzkumy volebních preferencí za ČR a kraje od
NÁSOBENÍ ČÍSLEM 10 ZÁVĚREČNÉ SHRNUTÍ
Téma: SČÍTÁNÍ A ODČÍTÁNÍ CELÝCH ČÍSEL 2
Dělitelnost přirozených čísel
VY_32_INOVACE_INF_RO_12 Digitální učební materiál
VY_32_INOVACE_ 14_ sčítání a odčítání do 100 (SADA ČÍSLO 5)
1 Vyhledávání Principy vyhledávání Klasifikace klíče:  Interní klíč – je součástí prohlížených záznamů  Externí klíč – není jeho součástí, je jím např.
Získávání informací Získání informací o reálném systému
Zábavná matematika.
Dělení se zbytkem 5 MODERNÍ A KONKURENCESCHOPNÁ ŠKOLA
Letokruhy Projekt žáků Střední lesnické školy a střední odborné školy sociální ve Šluknově.
Informatika I 3. přednáška
Jazyk vývojových diagramů
Čtení myšlenek Je to až neuvěřitelné, ale skutečně je to tak. Dokážu číst myšlenky.Pokud mne chceš vyzkoušet – prosím.
Únorové počítání.
Vyučovací hodina 1 vyučovací hodina: Opakování z minulé hodiny 5 min Nová látka 20 min Procvičení nové látky 15 min Shrnutí 5 min 2 vyučovací hodiny: Opakování.
Dělení se zbytkem 8 MODERNÍ A KONKURENCESCHOPNÁ ŠKOLA
Náhoda, generátory náhodných čísel
Deklarace Radim Štefan. 2 Použité zkratky BP – Borland Pascal De – Delphi.
Informatika I 2. přednáška
TI 7.1 NEJKRATŠÍ CESTY Nejkratší cesty - kap. 6. TI 7.2 Nejkratší cesty z jednoho uzlu Seznámíme se s následujícími pojmy: w-vzdálenost (vzdálenost na.
Seminář C cvičení STL, Trolltech Ing. Jan Mikulka.
Obchodní akademie, Ostrava-Poruba, příspěvková organizace Vzdělávací materiál/DUM VY_32_INOVACE_02A13 Autor Ing. Jiří Kalousek Období vytvoření duben 2014.
Sémantická analýza Jakub Yaghob
Gramatiky a jazyky Přednáška z předmětu Řízení v komplexních systémech
1 Celostátní konference ředitelů gymnázií ČR AŘG ČR P ř e r o v Mezikrajová komparace ekonomiky gymnázií.
Jazyk vývojových diagramů
Úvod do Pascalu. Co je Pascal? vyšší programovací jazyk poskytuje prostředky pro popis algoritmů, které odrážejí povahu řešených problémů, a nikoliv technickou.
Počítače a programování 1
3. Příkazy  Příkazy dělíme na jednoduché a strukturované.  Jednoduché příkazy - žádnou jejich dílčí částí neni příkaz - přiřazovací, vstupu a výstupu,
Predikce chemických posunů
KONTROLNÍ PRÁCE.
Dokumentace informačního systému
7. Typ soubor Souborem dat běžně rozumíme uspořádanou množinu dat, uloženou mimo operační paměť počítače (na disku). Pascalský soubor je abstrakcí skutečného.
Metodika objektového přístupu při tvorbě překladačů. Marek Běhálek Informatika a aplikovaná matematika FEI VŠB-TU Ostrava.
Počítače a programování 1 7.přednáška. Základy Pole ve třídách a metodách Pole Arrays.
Výrok „Vypadá to, že jsme narazili na hranici toho, čeho je možné dosáhnout s počítačovými technologiemi. Člověk by si ale měl dávat pozor na takováto.
Základy operačních systémů Meziprocesová komunikace a synchronizace Jakub Yaghob.
Optimalizace versus simulace 8.přednáška. Obecně o optimalizaci  Maximalizovat nebo minimalizovat omezujících podmínkách.  Maximalizovat nebo minimalizovat.
XSLT překladač Marek Běhálek Informatika a aplikovaná matematika FEI VŠB-TU Ostrava.
Pokročilé architektury počítačů (PAP_03.ppt) Karel Vlček, katedra Informatiky, FEI VŠB Technická Univerzita Ostrava.
Konstrukce překladačů David Bednárek
Překladače Optimalizace © Milan Keršláger
Překladače 6. Sémantická analýza
Transkript prezentace:

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

Pravidla studia SWI109 2/1 Z,Zk

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á

Literatura

Literatura 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)

Architektura překladače

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

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

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

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

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

Názvosloví

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

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í

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

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

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

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

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ů

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

Č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

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í

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)

Mezikódy

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

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ů

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.)

Čá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ů

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

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

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

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

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

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

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

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

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

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

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”)

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)

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

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”)

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”)

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

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

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

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”)

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

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”)

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”)

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”)

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

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

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

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

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

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

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

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

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 30-150% Register allocation Přidělování fyzických registrů Standardní řešení: Barvení grafu

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

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

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

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

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

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

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ů

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

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

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

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í

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

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í

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í

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

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

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

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

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

Příklad – scheduling Krok 1 Připravené instrukce Kritická cesta inc rp 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

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

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

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

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

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

Příklad – scheduling Čas 6 Připravené instrukce jgt čas R MEM ALU W mov 1 dec 2 3 cmp 4 inc 5 xor inc, jgt 6 7 mov r1,[rp] 4 inc rp 1 5 1 dec ri xor rs,r1 3 cmp ri,0 1 1 1 jgt

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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 ); /* ... */

Cray 1

Cray 1

Cray 1

Cray 1

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

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

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é

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

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á

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

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

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

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

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ů

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é

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

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í

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

Blocking Vytvoření bloků K J

Blocking Strip mining nad bloky K J

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

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

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

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

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ě

Další optimalizace

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

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í

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

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;

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

Čá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;

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 * 15 + 35 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;

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

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;

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;

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;

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

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

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

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

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