Differences

This shows you the differences between two versions of the page.

Link to this comparison view

cpl:labs:11 [2016/10/04 07:55]
bogdan.nitulescu
cpl:labs:11 [2016/12/20 01:59] (current)
bogdan.nitulescu [Exercițiul 3]
Line 1: Line 1:
-====== 11. LLVM Passes - code optimizations ​======+===== 11. LLVM - transformări de cod ===== 
 + 
 + 
 +===== Introducere ===== 
 + 
 +În LLVM optimizările sunt implementate sub formă de [[http://​llvm.org/​docs/​Passes.html|Pass]]-uri care traversează programul pentru a-l analiza și a-l transforma. Obținerea de informații despre program prin analiza fluxului de [[cpl:​labs:​09#​tipuri_de_probleme|date]] sau de [[cpl:​labs:​08|control]] constituie un pas important în implementarea optimizărilor. 
 + 
 +Pentru a aplica o anumită selecție de optimizări se poate folosi tool-ul [[http://​llvm.org/​docs/​CommandGuide/​opt.html|opt]] prezentat și [[cpl:​labs:​llvm-pass|aici]]. Pentru a integra o optimizare nouă în sursele LLVM (fără să mai fim nevoiți să specificăm biblioteca dinamică la runtime) se va folosi [[http://​llvm.org/​docs/​CommandGuide/​llvm-build.html|sistemul de build]] din llvm și pașii descriși în exemplul de [[cpl:​labs:​llvm-pass#​integrarea_unui_pas_in_llvm|aici]]. 
 +===== Afișarea informațiilor de debug ===== 
 +Informațiile de debug, pot fi afișate rulând utilitarul ''​opt''​ cu parametrul ''​-debug''​. Pentru a filtra informațiile de debug doar pentru un anumit pas, se folosește parametrul ''​-debug-only=//<​nume_pass>//''​. De exemplu, pentru a filtra doar log-urile optimizării hello, se rulează comanda: 
 +<code bash> 
 +opt -hello -debug-only=hello hello.bc 
 +</​code>​ 
 + 
 + 
 +===== SSA ====== 
 + 
 +Un program este reprezentat în forma SSA dacă fiecărei variabile i se atribuie o valoare doar o singură dată şi fiecare folosire a variabilei este dominată de definiţia ei. 
 + 
 +Un program poate fi convertit în forma [[http://​en.wikipedia.org/​wiki/​Static_single_assignment_form|SSA]] prin: 
 +  * asocierea de nume unice variabilelor de fiecare dată când li se atribuie o valoare 
 +  * înlocuirea numelor de variabile cu numele unice atunci când variabilele sunt folosite. 
 + 
 +Exemple 
 +^ Program inițial ^ Program în forma SSA ^ 
 +| <code c> 
 +V = 4; 
 +  = V + 5; 
 +V = 6; 
 +  = V + 7; 
 +</​code>​ | <code c> 
 +V0 = 4; 
 +   = V0 + 5; 
 +V1 = 6; 
 +   = V1 + 7; 
 +</​code>​ | 
 +| <code c> 
 +if (...) 
 +    X = 5; 
 +else 
 +    X = 3; 
 + 
 +Y = X; 
 +</​code>​ | <code c> 
 +if (...) 
 +    X0 = 5; 
 +else 
 +    X1 = 3; 
 +X2 = O(X0, X1); 
 +Y0 = X2; 
 +</​code>​ | 
 +| <code c> 
 +j = 1; 
 +while (j < X) 
 +    ++j; 
 +N = j; 
 +</​code>​ care se mai poate scrie şi <code c> 
 +    j = 1; 
 +    if (j >= X) 
 +        goto E; 
 +S: 
 +    j = j + 1; 
 +    if (j < X) 
 +        goto S; 
 +E: 
 +    N = j; 
 +</​code>​ | <code c> 
 +    j0 = 1; 
 +    if (j0 >= X0) 
 +        goto E; 
 +S: 
 +    j1 = O(j0, j2); 
 +    j2 = j1 + 1; 
 +    if (j2 < X0) 
 +        goto S; 
 +E: 
 +    j3 = O(j0, j2); 
 +    N0 = j3; 
 + 
 +  
 + 
 + 
 +  
 +</​code>​ | 
 + 
 +Într-un basic block B având N predecesori P<​sub>​1</​sub>,​ P<​sub>​2</​sub>,​ ..., P<​sub>​N</​sub>,​ prin X = O(V<​sub>​1</​sub>,​ V<​sub>​2</​sub>,​ ..., V<​sub>​n</​sub>​) se înțelege că variabila ''​X''​ va avea valoarea V<​sub>​j</​sub>​ dacă fluxul de control intră în blocul B din blocul P<​sub>​j</​sub>,​ 1<​=j<​=N. 
 + 
 +===== Ierarhia de clase în LLVM ===== 
 +  * clasa [[http://​llvm.org/​docs/​ProgrammersManual.html#​Instruction|Instruction]] este subclasă a 
 +    * clasei [[http://​llvm.org/​docs/​ProgrammersManual.html#​User|User]] care este subclasă a 
 +    * clasei [[http://​llvm.org/​docs/​ProgrammersManual.html#​Value|Value]] 
 +Mai jos este un exemplu de instrucțiune (Instruction). Ea este şi utilizator (User) ale variabilelor (Value) a şi b. În acelaşi timp reprezintă şi definirea variabilei (Value) c. 
 +<code asm> 
 +%c = add i32 %a, %b 
 +</​code>​ 
 + 
 +[[http://​llvm.org/​docs/​ProgrammersManual.html#​iterate-chains|Aici]] este un exemplu de cum pot fi parcurşi toţi utilizatorii unei variabile. 
 + 
 +[[http://​llvm.org/​docs/​ProgrammersManual.html#​iterate-function|Aici]] este un exemplu de cum pot fi parcurse toate basic block-urile dintr-o funcţie. 
 + 
 +[[http://​llvm.org/​docs/​ProgrammersManual.html#​iterate-basicblock|Aici]] este un exemplu de cum pot fi parcurse toate instrucţiunile dintr-un basic block. 
 + 
 +[[http://​llvm.org/​docs/​ProgrammersManual.html#​iterate-institer|Aici]] este un exemplu de cum pot fi parcurse toate instrucţiunile dintr-o funcţie. 
 + 
 +[[http://​llvm.org/​docs/​ProgrammersManual.html#​iterate-preds|Aici]] este un exemplu de cum pot fi parcurşi toţi predecesorii şi succesorii unui basic block. 
 + 
 +[[http://​llvm.org/​docs/​ProgrammersManual.html#​isa|Aici]] este un exemplu de cast folosit la exerciţiul 3. 
 + 
 +[[http://​llvm.org/​docs/​ProgrammersManual.html#​dss-valuemap|Aici]] este o scurtă descriere a structurii de date ValueMap folosită la exerciţiul 3. 
 + 
 +[[http://​llvm.org/​docs/​ProgrammersManual.html#​dss-bitvector|Aici]] este o scurtă descriere a structurii de date BitVector folosită la exerciţiul 3. 
 + 
 +====== Exerciții de laborator (15p) ====== 
 + 
 +<​note>​ 
 +Laboratorul este compus dintr-o exerciții practice care includ analiza formei SSA și implementarea unor optimizări. 
 +Înainte de începerea exercițiilor downloadați arhiva de {{:​cpl:​labs:​lab11_2016.zip|aici}}. 
 + 
 +Compilati exercitiile cu -O0 pentru a nu lasa compilatorul sa aplice optimizari. 
 +</​note>​ 
 + 
 +===== Exercițiul 1 ===== 
 + 
 +Scrieti un Pass de LLVM care sa elimine basic block-urile trivially dead. Hint: Un basic block este trivially dead daca nu exista niciun jump care sa duca catre acesta; cu alte cuvinte nu are predecesori. 
 + 
 +<file c dead.c>​ 
 +#​include<​stdio.h>​ 
 +#​include<​time.h>​ 
 +#​include<​stdlib.h>​ 
 + 
 +void main(void) { 
 +        int a = 1, b =2, c = 3; 
 + 
 +        if (a + b * (rand() % 3) == 3) { 
 +                goto end1; 
 +        } else { 
 +                goto end2; 
 +        } 
 + 
 +dead: 
 +        printf("​Unreachable\n"​);​ 
 + 
 + 
 +end1: 
 +        printf("​Still reachable\n"​);​ 
 +end2: 
 +        printf("​Reachable\n"​);​ 
 +
 + 
 +</​file>​ 
 + 
 +===== Exercițiul 2 ===== 
 + 
 +Scrieti un pass care optimizeaza cazuri de tipul jump to jump. Un caz de jump to jump avem in momentul in care singura intructiune dintr-un basic block este un salt neconditionat intr-un alt bloc. In acest caz toate instructiunile de salt din blocul initial pot fi optimizate pentru a duce direct la blocul destinatie. 
 +Blocul initial este in acest moment dead code si poate fi eliminat cu pass-ul de la exercitiul anterior. 
 + 
 +<file c jump_to_jump.c>​ 
 +#​include<​stdio.h>​ 
 +#​include<​time.h>​ 
 +#​include<​stdlib.h>​ 
 + 
 +void main(void) { 
 +        int x = rand() % 100 - 10; 
 + 
 +        if ( x < 0 ) { 
 +                return; 
 +        } else { 
 +                printf("​Not negative\n"​);​ 
 +        } 
 + 
 +        printf("​End\n"​);​ 
 +
 + 
 +</​file>​ 
 + 
 +===== Exercițiul 3 ===== 
 + 
 +Folosind codul din fişierul ''​Hello.cpp''​ din arhiva laboratorului,​ urmăriţi modul în care poate fi implementată simple constant propagation în LLVM. 
 +  * cum poate fi identificată o instrucţiune inutilă? 
 +  * identificaţi metoda responsabilă pentru constant folding 
 +  * cum se înlocuiesc apariţiile viitoare ale variabilei în cauză cu o constantă?​ 
 +  * de ce se adaugă din nou în worklist unele instrucţiuni?​ 
 +  * Rulaţi acest pas folosind fisierul ''​test.c''​ din arhiva laboratorului.
  
-**TO BE PUBLISHED SOON** 
  
  
cpl/labs/11.1475556933.txt.gz · Last modified: 2016/10/04 07:55 by bogdan.nitulescu
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0