This is an old revision of the document!


10. Optimisations with LLVM

Introducere

În LLVM optimizătirile sunt implementate sub formă de Pass-uri care traversează programul pentru a-l analiza și a-l transforma. Pentru a aplica o anumită selecție de optimizări se poate folosi tool-ul opt prezentat și 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:

opt -hello -debug-only=hello hello.bc

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 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
V = 4;
  = V + 5;
V = 6;
  = V + 7;
V0 = 4;
   = V0 + 5;
V1 = 6;
   = V1 + 7;
if (...)
    X = 5;
else
    X = 3;
 
Y = X;
if (...)
    X0 = 5;
else
    X1 = 3;
X2 = O(X0, X1);
Y0 = X2;
j = 1;
while (j < X)
    ++j;
N = j;

care se mai poate scrie şi

    j = 1;
    if (j >= X)
        goto E;
S:
    j = j + 1;
    if (j < X)
        goto S;
E:
    N = j;
    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;
 
 
 
 
 

Într-un basic block B având N predecesori P1, P2, …, PN, prin X = O(V1, V2, …, Vn) se înțelege că variabila X va avea valoarea Vj dacă fluxul de control intră în blocul B din blocul Pj, 1⇐j⇐N.

Ierarhia de clase în LLVM

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.

%c = add i32 %a, %b

Aici este un exemplu de cum pot fi parcurşi toţi utilizatorii unei variabile.

Aici este un exemplu de cum pot fi parcurse toate basic block-urile dintr-o funcţie.

Aici este un exemplu de cum pot fi parcurse toate instrucţiunile dintr-un basic block.

Aici este un exemplu de cum pot fi parcurse toate instrucţiunile dintr-o funcţie.

Aici este un exemplu de cum pot fi parcurşi toţi predecesorii şi succesorii unui basic block.

Aici este un exemplu de cast folosit la exerciţiul 4.

Aici este o scurtă descriere a structurii de date ValueMap folosită la exerciţiul 4.

Aici este o scurtă descriere a structurii de date BitVector folosită la exerciţiul 4.

Exerciții de laborator (10p)

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

Exercițiul 1

Generaţi reprezentarea intermediară în forma SSA pentru sursa C de mai jos.

  • obţineţi reprezentarea intermediară neoptimizată şi observaţi structura codului generat:
clang -S -emit-llvm t.c
  • transformaţi programul în format bytecode utilizând ghidul de comenzi LLVM
  • aplicaţi optimizarea mem2reg pentru a obţine o reprezentare în forma SSA cu noduri phi
  • transformaţi înapoi programul optimizarea din forma bytecode în format lizibil şi observaţi structura codului intermediar
  • test.c
    #include <stdlib.h>
     
    int test(int X, int Y) {
      int Z = 1;
      if (X == Y) Z = Z + 1;
      else Z = Z + 2;
      Z = Z + 3;
      return Z;
    }
     
    int main(int argc, char **argv) {
      test(atoi(argv[1]), atoi(argv[2]));
    }

Exercițiul 2

Folosind codul din fişierul Hello2.cpp din archiva laboratorului, urmăriţi modul în care pot fi implementată simple constant propagation în LLVM.

  • cum se obţine numele unui basic block?
  • 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?
  • realizaţi un fişier de test (urmând paşii de la exerciţiul 1) pentru a ilustra beneficiile acestui pas. Rulaţi acest pas pe exemplul ales.

Exercițiul 3

Implementaţi analiza live variables. Algoritmul este explicat clar şi concis în Dragon book dar şi în slide-urile de aici. Puteţi pleca de la fişierul Hello3.cpp din arhiva laboratorului. Pentru implementare, urmăriţi şi instrucţiunile din cod.

  • ce reprezintă gen(B)/def(B)? Dar kill/use?
  • explicaţi ecuaţia de flux pentru in(B)
  • cum arată laticea? Indexaţi instrucţiunile pentru a putea reprezenta un element din latice ca vector de biţi (1)
  • implementaţi calculul def (2) şi use (3)
  • rulaţi pe fişierul de intrare generat la exerciţiul 1
  • implementaţi algoritmul Killdal (4)
cpl/labs/10.1449524769.txt.gz · Last modified: 2015/12/07 23:46 by irina.presa
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