This shows you the differences between two versions of the page.
cpl:labs:04 [2015/10/25 20:24] laura.vasilescu [Tool-uri pentru lucrul cu IR-ul] |
cpl:labs:04 [2016/10/22 18:24] (current) bogdan.nitulescu [04. Introduction to LLVM] |
||
---|---|---|---|
Line 5: | Line 5: | ||
Printre cele mai importante componente ale LLVM se află engine-ul de optimizări independente de platformă și de limbaj. Acesta lucrează cu o reprezentare intermediară a programelor, pe care o vom prezenta în cadrul acestui laborator. Această reprezentare este de asemenea liantul între front-end-uri (precum Clang pentru C/C++/Objective-C) și back-end-uri (în prezent, LLVM are back-end-uri pentru x86, ARM, PowerPC, MIPS, Sparc etc). | Printre cele mai importante componente ale LLVM se află engine-ul de optimizări independente de platformă și de limbaj. Acesta lucrează cu o reprezentare intermediară a programelor, pe care o vom prezenta în cadrul acestui laborator. Această reprezentare este de asemenea liantul între front-end-uri (precum Clang pentru C/C++/Objective-C) și back-end-uri (în prezent, LLVM are back-end-uri pentru x86, ARM, PowerPC, MIPS, Sparc etc). | ||
+ | Pentru a instala LLVM pe un sistem Linux aveți nevoie de pachetele ''llvm'' pentru a folosi tool-urile, ''llvm-dev'' pentru a putea folosi bibliotecile, ''clang'' pentru front-end-ul C/C++ . | ||
===== Reprezentarea intermediară a LLVM (LLVM IR) ===== | ===== Reprezentarea intermediară a LLVM (LLVM IR) ===== | ||
Reprezentarea intermediară a LLVM-ului are 3 forme: | Reprezentarea intermediară a LLVM-ului are 3 forme: | ||
Line 23: | Line 24: | ||
</code> | </code> | ||
- | Observați utilizarea flag-urilor ''-S'', ca atunci când dorim obținerea unui fișier similar cu cel al unui limbaj de asamblare, și ''-c'', ca atunci când dorim obținerea unui fișier binar, similar cu un fișier obiect. Pentru conversia între cele 2 reprezentări se pot folosi tool-urile ''llvm-as'' și ''llvm-dis''. Coincidența nu este întâmplătoare, întrucât IR-ul este foarte asemănător unui limbaj de asamblare. | + | Observați utilizarea flag-urilor ''-S'', ca atunci când dorim obținerea unui fișier în limbaj de asamblare, și ''-c'', ca atunci când dorim obținerea unui fișier obiect, urmate de ''-emit-llvm'' pentru a obține IR (fie în forma textuală, asemănătoare unui limbaj de asamblare, fie în forma binară, similară unui format obiect). Fără flagul ''-emit-llvm'', clang va general cod asamblare sau cod obiect nativ, la fel ca orice alt compilator, de exemplu gcc. |
+ | |||
+ | Pentru conversia între cele 2 reprezentări se pot folosi tool-urile ''llvm-as'' și ''llvm-dis'': | ||
+ | |||
+ | <code bash> | ||
+ | llvm-as yourfile.ll -o yourfile.bc | ||
+ | llvm-dis yourfile.bc -o yourfile.ll | ||
+ | </code> | ||
Alte utilitare care merită menționate sunt ''opt'', care reprezintă o interfață către engine-ul de optimizări (primește ca input fișiere IR și scoate tot fișiere IR), ''llc'', care poate compila un fișier IR pentru o anumită arhitectură (primește un fișier IR și produce un fișier în limbaj de asamblare sau un fișier obiect), și ''lli'', care poate interpreta un fișier IR (primește un fișier IR și produce rezultatele rulării programului respectiv pe platforma curentă). Mai multe informații despre utilitarele din suita LLVM găsiți [[http://llvm.org/docs/CommandGuide/|aici]]. | Alte utilitare care merită menționate sunt ''opt'', care reprezintă o interfață către engine-ul de optimizări (primește ca input fișiere IR și scoate tot fișiere IR), ''llc'', care poate compila un fișier IR pentru o anumită arhitectură (primește un fișier IR și produce un fișier în limbaj de asamblare sau un fișier obiect), și ''lli'', care poate interpreta un fișier IR (primește un fișier IR și produce rezultatele rulării programului respectiv pe platforma curentă). Mai multe informații despre utilitarele din suita LLVM găsiți [[http://llvm.org/docs/CommandGuide/|aici]]. | ||
+ | |||
+ | <code bash> | ||
+ | lli yourfile.ll # Interpretează IR-ul | ||
+ | llc yourfile.ll -o yourfile.s # Genereaza un fișier în limbajul de asamblare nativ | ||
+ | </code> | ||
+ | |||
===== Organizarea IR-ului ===== | ===== Organizarea IR-ului ===== | ||
În general, fiecare fișier ''.ll'' sau ''.bc'' va conține un **modul** alcătuit din mai multe declarații de funcții, variabile globale, tipuri etc. | În general, fiecare fișier ''.ll'' sau ''.bc'' va conține un **modul** alcătuit din mai multe declarații de funcții, variabile globale, tipuri etc. | ||
Line 31: | Line 46: | ||
IR-ul de LLVM pentru fiecare funcție este organizat sub forma unui **control flow graph**, alcătuit din basic block-uri. Un **basic block** este o secvență de instrucțiuni neîntreruptă de transferuri de control. Transferurile de control se realizează prin intermediul unor instrucțiuni de tip ''branch'', ''return'', ''switch'' etc (cunoscute sub numele de ''terminators''). | IR-ul de LLVM pentru fiecare funcție este organizat sub forma unui **control flow graph**, alcătuit din basic block-uri. Un **basic block** este o secvență de instrucțiuni neîntreruptă de transferuri de control. Transferurile de control se realizează prin intermediul unor instrucțiuni de tip ''branch'', ''return'', ''switch'' etc (cunoscute sub numele de ''terminators''). | ||
- | **Control flow graph**-ul poate fi vizualizat sub forma unui fișier ''DOT''. Pentru obținerea fișierelor, se poate utiliza utilitarul ''opt'': | + | **Atenție!** In LLVM, ultima instrucțiune din fiecare basic block trebuie neapărat să fie un terminator. |
+ | |||
+ | **Control flow graph**-ul poate fi vizualizat grafic sub forma unui fișier ''DOT''. Pentru obținerea fișierelor, se poate utiliza utilitarul ''opt'': | ||
<code bash> | <code bash> | ||
opt -dot-cfg yourfile.ll | opt -dot-cfg yourfile.ll | ||
</code> | </code> | ||
- | Rezultatul rulării va consta în cate un fișier ''DOT'' pentru fiecare funcție din modul (''cfg.f.dot'', ''cfg.g.dot'' etc). Pentru a vizualiza fișierele pe mașina virtuală puteți instala pachetul ''xdot'': | + | Rezultatul rulării va consta în câte un fișier ''DOT'' pentru fiecare funcție din modul (''cfg.f.dot'', ''cfg.g.dot'' etc). Pentru a vizualiza fișierele în mașina virtuală puteți instala pachetul ''xdot'': |
<code bash> | <code bash> | ||
sudo apt-get install xdot | sudo apt-get install xdot | ||
Line 41: | Line 58: | ||
</code> | </code> | ||
- | Fiecare nod din graful plotat de ''xdot'' reprezintă un basic block, în timp ce arcele reprezintă posibile căi de execuție. Fiecare nod va conține secvența de instrucțiuni corepunzătoare basic block-ului pe care îl reprezintă. O descriere completă a tuturor instrucțiunilor din IR-ul de LLVM se găsește [[http://llvm.org/docs/LangRef.html|aici]]. Majoritatea instrucțiunilor sunt destul de intuitive: **add**, **sub**, **mul**, **fadd**, **fsub**, **fmul** etc pentru operații aritmetice, **load** și **store** pentru citiri și scrieri din memorie, **icmp** și **fcmp** pentru realizarea comparațiilor, și așa mai departe. Spre deosebire de limbajele de asamblare tradiționale, IR-ul de LLVM este tipat - fiecare valoare are un anumit tip și tipurile pe care se poate aplica o anumită operație sunt bine definite. | + | Fiecare nod din graful plotat de ''xdot'' reprezintă un basic block, în timp ce arcele reprezintă posibile căi de execuție. Fiecare nod va conține secvența de instrucțiuni corepunzătoare basic block-ului pe care îl reprezintă. O descriere completă a tuturor instrucțiunilor din IR-ul de LLVM se găsește [[http://llvm.org/docs/LangRef.html|aici]]. Majoritatea instrucțiunilor sunt destul de intuitive: **add**, **sub**, **mul**, **fadd**, **fsub**, **fmul** etc pentru operații aritmetice, **load** și **store** pentru citiri și scrieri din memorie, **icmp** și **fcmp** pentru realizarea comparațiilor, și așa mai departe. Spre deosebire de limbajele de asamblare tradiționale, IR-ul de LLVM are noțiunea de tipuri de date - fiecare valoare are un anumit tip și tipurile pe care se poate aplica o anumită operație sunt bine definite. |
==== Sistemul de tipuri ==== | ==== Sistemul de tipuri ==== | ||
Line 112: | Line 129: | ||
<code C> | <code C> | ||
- | a = x + y; | ||
x = m * n; | x = m * n; | ||
+ | a = x + y; | ||
+ | x = m + n; | ||
b = x + y; | b = x + y; | ||
</code> | </code> | ||
- | La transformarea în formă SSA, vor exista două versiuni diferite ale variabilei ''x'' - una reprezentând valoarea de dinainte de atribuire, una reprezentând valoarea de după: | + | La transformarea în formă SSA, vor exista două versiuni diferite ale variabilei ''x'' - una reprezentând valoarea de după prima atribuire, una reprezentând valoarea de după cea de-a doua atribuire: |
<code C> | <code C> | ||
+ | x_1 = m * n; | ||
a = x_1 + y; | a = x_1 + y; | ||
- | x_2 = m * n; | + | x_2 = m + n; |
b = x_2 + y; | b = x_2 + y; | ||
</code> | </code> | ||
Line 158: | Line 177: | ||
if.else: | if.else: | ||
%x.2 = add i32 %m, %n | %x.2 = add i32 %m, %n | ||
- | br label %if.else | + | br label %if.end |
if.end: | if.end: | ||
Line 174: | Line 193: | ||
======= Exerciții de laborator (10p) ======= | ======= Exerciții de laborator (10p) ======= | ||
- | În rezolvarea laboratorului folosiți arhiva de sarcini [[TODO | lab04-tasks.zip]] | + | În rezolvarea laboratorului folosiți arhiva de sarcini {{ :cpl:labs:lab04-tasks.zip }} |
===== Exercițiul 1 - Control flow (1p) ===== | ===== Exercițiul 1 - Control flow (1p) ===== | ||
Line 209: | Line 228: | ||
===== BONUS ===== | ===== BONUS ===== | ||
- | === 1 cpl karma - Clase === | + | === Clase === |
Intrați în directorul ''7-classes'' și inspectați fișierul ''classes.cpp''. Cum credeți că va arăta definiția lui ''A''? Dar a lui ''B''? Cum va diferenția compilatorul între cele 2 metode ''g'' ale lui ''B''? | Intrați în directorul ''7-classes'' și inspectați fișierul ''classes.cpp''. Cum credeți că va arăta definiția lui ''A''? Dar a lui ''B''? Cum va diferenția compilatorul între cele 2 metode ''g'' ale lui ''B''? | ||
Rulați ''make classes.ll'' și inspectați fișierul produs. | Rulați ''make classes.ll'' și inspectați fișierul produs. | ||
- | === 1 cpl karma - Metode virtuale === | + | === Metode virtuale === |
Intrați în directorul ''8-virtual'' și inspectați fișierul ''classes.cpp''. Cum credeți că vor arăta definițiile claselor ''A'' și ''B'' în acest caz? Ce metode se vor apela și cum pe obiectele de tip ''A'' și ''B'' în cadrul funcției ''val''? Dar în cadrul funcției ''ref''? De ce? | Intrați în directorul ''8-virtual'' și inspectați fișierul ''classes.cpp''. Cum credeți că vor arăta definițiile claselor ''A'' și ''B'' în acest caz? Ce metode se vor apela și cum pe obiectele de tip ''A'' și ''B'' în cadrul funcției ''val''? Dar în cadrul funcției ''ref''? De ce? | ||