GENEROVÁNÍ KÓDU 9. SHRNUTÍ - PŘÍKLAD POSTUPU PŘEKLADU VSTUPNÍHO PROGRAMU (ZA POUŽITÍ DOSUD ZNÁMÝCH TECHNIK) 2011 Jan Janoušek MI-GEN Evropský sociální fond Praha & EU: Investujeme do vaší budoucnosti
Úvod Tato přednáška si klade za cíl reagovat na diskuzi se studenty po minulé přednášce - některým ze studentů chybí předchozí kurz překladačů, viz. předmět BI-PJP. Proto u těchto studentů nastává zjevně obtížnější celková orientace v problému. Na konkrétním příkladu chci probrat postupně jednotlivé kroky překladu, včetně frontendu, a tyto kroky diskutovat na tabuli. Jako vstupní jazyk bude uvažován jazyk Mila, výstupním jazykem bude jazyk Tiny machine (oba jazyky viz. semestrální práce). Přednáška tak může sloužit také jako pomoc k semestrálce.
const a=20, b=2, c=2; var x,y,z,v; begin read v; x:=v+a*b+5; y:=v+a*b+100; z:=0; If (z=0) then z=1; If (v<x) then x=x+1 else x=x*2; while (x < y) do begin z= y+5; v=v+z; x=c-1+x; end; end.
1. fáze lexikální analýza Vstup: program Výstup: posloupnost lexikálních elementů. Tyto lexikální elementy jsou terminální symboly bezkontextové gramatiky a můžou mít své syntetizované atributy. specifikace lexikálních elementů regulární gramatikou, viz. dokumentace Mily implementace konečným automatem, viz. soubor lexan.cpp Výstupní posloupnost: const ident (.sid= a ) = cislo (.shod=20), atd
2. fáze syntaktická + sémantická analýza Vstup: posloupnost lexikálních elementů + jejich syntetizované atributy. Výstup: Zvolený vnitřní kód (záleží pouze na nás), tj. buď AST, nebo DAG, nebo 3 adresový kód (kódy lze později převádět jeden na druhý). Konstanty už jsou nahrazeny svými skutečnými hodnotami. Překlad je specifikovaný atributovou gramatikou, viz. implementace mila (překlad do AST), nebo předchozí přednášky atributových gramatik a převodů pro DAG a/nebo 3-AC. Dále je v této fázi vytvořena tabulka symbolů, v mile viz. tabsym.cpp. Ta uchovává všechny údaje o konstantách, proměnných, návěštích, atd se kterými bude pracovata budeme je nějak potřebovat.
2. fáze syntaktická + sémantická analýza Implementace: některou z metod syntaxí řízeného překladu. Základem algoritmu je deterministická syntaktická analýza. V našem případě je vstupní gramatika LL(1), takže je zvolena LL(1) analýza a její implementace rekurzivním sestupem, viz. soubor parser.cpp. Tabulka symbolů by měla mít po 2. fázi následující položky: jako konstanty a,b,c jako proměnné x,y,z,v pokud generujeme 3-AC, pak také všechny dočasné proměnné
3. fáze lokální optimalizace Pozn. Lokální optimalizace lze provádět případně i v průběhu druhé fáze. Musíme pak ale tyto optimalizace definovat atributovými pravidly. Constant folding + eliminace mrtvého kódu viz. existující implementace mily, viz. soubor strom.cpp a metoda optimize(). Propagace konstant Detekce společných podvýrazů (konstrukce DAGu) Detekce invariantních výrazů v cyklech Výhodnějsí instrukce - machine-idioms další optimalizace (např. optimalizace skoků), viz. předchozí přednáška
3. fáze další optimalizace Tabulku symbolů stále používáme k uchovávání všech potřebných hodnot. U 3-AC je potřeba si určit základní bloky, graf toku řízení a stavy dočasných proměnných (live, dead, unused). Pipelining a globální optimalizace budou probrány na následujících přednáškách. Alokace registrů u 3AC kódu, např. barvením grafu.
4. fáze generování kódu U AST a DAGu výběr instrukcí pokrýváním stromu, popř. přímým generováním. U 3-AC přímé generování. Následuje případně opět alokace registrů. Případně optimalizace založené na použití konkrétního hw.
A detailed order of optimizations (from the book Muchnick: Advanced Compiler Design and Implementation) Scalar replacement of array references Data-cache optimizations Constant folding Algebraic simplification and reassociation 10 Procedure integration Tail-call optimization Scalar replacement of aggregates Sparse conditional constant propagation Interprocedural constant propagation Procedure specialization and cloning Sparse conditional constant propagation Global value numbering Local and global copy propagation Sparse conditional constant propagation Dead-code elimination Local and global common-subexpression elimination Loop-invariant code motion Dead-code elimination Code hoisting Induction-variable strength reduction Linear-function test replacement Induction-variable removal Unnecessary bounds-checking elimination Control-flow optimizations In-line expansion Leaf-routine optimization Shrink wrapping Machine idioms Tail merging Branch optimizations and conditional moves Dead-code elimination Software pipelining, loop unrolling Basic-block and branch scheduling Register allocation Basic-block and branch scheduling Intraprocedural I-cache optimization Instruction prefetching Data prefetching Branch prediction Interprocedural register allocation Aggregation of global references Interprocedural I-cache optimization