Differences

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

Link to this comparison view

cpl:teme:tema2 [2016/11/22 19:35]
diana.vasile
cpl:teme:tema2 [2018/01/19 13:23] (current)
bogdan.nitulescu [Informații organizatorice]
Line 1: Line 1:
-====== Tema de casă 2 - Generarea de cod  ​======+====== Tema 2 - Optimizari ​====== 
 +Obiectivul acestei teme este să scrieți unul sau mai mulți pași de optimizare, folosind framework-ul LLVM, astfel încât să reduceți cât mai mult dimensiunea codului rezultat.
  
-În cadrul acestei teme veti implementa generarea ​de cod pentru ​limbajul LCPL.+===== Informații organizatorice ===== 
 +  * **Deadline**:​ Termenul limită până când se poate participa la concurs este **27 ianuarie 2018, ora 23:59**. Deadline-ul este final - după această oră nu se vor mai accepta soluții. 
 +  * **Colaborare**:​ Fiecare soluție este **individuală**. 
 +  * **Condiții** ​de punctare 
 +    * Soluția generează ​cod corect ​pentru ​toate testele din benchmark. (Nu se modifica semantica codului, rezultatul executiei este acelasi) 
 +    * Soluția face cel putin doua transformari non-triviale ale codului. 
 +    * Codul soluției nu este copiat dintr-un [[http://​releases.llvm.org/​3.8.1/​docs/​Passes.html#​transform-passes|pass de transformare existent din LLVM]] 
 +    * Arhiva trebuie sa contina un fisier README in care sa fie descrise optimizarile propuse si modul de implementare.
  
-==== Informații organizatorice ​====+===== Infrastructură ===== 
 +  * Codul va folosi **LLVM 3.8** 
 +  * Soluțiile vor fi trimise prin vmchecker 
 +===== Enunț ===== 
 +Premisa acestei teme este să scrieți un optimizor care va obține un rezultat bun in benchmarkul "​CPLMark"​ . Veți extinde utilitarul **opt** din LLVM, adăugând o bibliotecă ce conține pașii voștri de optimizare.
  
-  * **Deadline**:​ Termenul limită până când se pot trimite temele fără depunctări de întârziere ​este **vineri, 2 decembrie 2016, ora 23:59**. Pentru mai multe detalii, consultaţi [[:​cpl:​teme:​general|regulamentul]] aferent temelor de casă. +Scorul CPLMark ​este dimensiunea totală a secțiunilor ​.text din fișierele din benchmarkdupă ce au trecut prin optimizorul vostru si apoi au fost compilate cu **llc** pentru arhitectura ARM.
-  * **Colaborare**:​ Tema va fi rezolvată **individual**. +
-  * **Punctare**:​ **250p**distribuite astfel: +
-    * **Testele publice (225p)** +
-      * Testele ''​simple''​ (120p) +
-      * Testele ''​advanced''​ (75p) +
-      * Testele ''​complex''​ (30p)  +
-    * **Calitatea implementării (25p)** +
-      ​Organizarea codului sursă +
-      ​Comentariile din cod +
-      * Explicațiile din README - acestea trebuie să conţină o prezentare extinsă a modului de implementare a temei şi a problemelor întâmpinate pe parcurs+
  
-===== Enunţ =====+Fișierele din benchmark sunt în format .ll , dar pentru referință am adăugat și fișierele C originale.
  
-Va trebui să realizaţiîn limbajul C++, porţiunea responsabilă cu generarea ​de cod LLVM IR, preferabil folosind IRBuilderProgramul vostru va trebui să primească la intrare output-ul temei 1 şi să genereze un fișier cu cod corect LLVM IR. Rezultatul programului realizat ​de voi poate folosi tool-urile LLVM pentru a genera cod pentru x86 și pentru a se executa.+<​note>​**opt** nu va rula decât pașii voștri de optimizarenu și cei "​built-in"​. Toate transformările codului vor fi scrise ​de voiO strategie posibilă ar fi să examinați ​fișierele din benchmark, să estimați care sunt optimizările care ar putea aduce reduce dimensiunea codului - de exemplu eliminarea codului mort, optimizarea salturilor, eliminarea subexpresiilor comune ​- și să le implementați pe cele mai promițătoare.</​note>​
  
-Documentaţia principală în cadrul acestei teme va fi [[http://​llvm.org/​releases/​3.8.0/​docs/​LangRef.html|LLVM IR]] și API-ul clasei IRBuilder.+Pentru a calcula scorul unui test se folosește următoarea secvență de comenzi:
  
-===== Generarea de cod =====+<code bash> 
 +# Transform the test .ll file in binary format 
 +llvm-as test.ll -o test.bc 
 +# Run your optimization passes 
 +opt -load=./​libLLVMCpl-Contest.so -cpl-my-1st-pass -cpl-my-2nd-pass test.bc > test-optimized.bc 
 +# Generate an optimized object file for the ARM architecture 
 +llc test-optimized.bc -march=arm -filetype=obj -o test.o 
 +# Compute the size of the text section in the object file 
 +llvm-size -A test.o 
 +</​code>​
  
-Pentru generarea de cod e recomandat să folosiți clasa IRBuilder, similar cu ceea ce ați învățat în cadrul laboratorului. De asemenea, puteți să studiați și tutorialul de generare de cod de [[http://​llvm.org/​releases/​3.8.0/​docs/​tutorial/​LangImpl3.html|aici]].+Scorul final este suma scorului individual pentru fiecare test.
  
-Primul pas ar trebui să fie înțelegerea documentației: ​ 
-  * Semantica și comportamentul programelor LCPL 
-  * LLVM IR / IRBuilder API pentru generarea de LLVM IR 
-  * Suportul pentru runtime 
  
-===== Arhiva de pornire ===== 
  
-Arhiva de pornire conține: 
-  * Directoarele ''​include''​ și ''​src'',​ în care găsiți implementarea analizei semantice și un schelet de cod pentru generarea de IR 
-  * Directorul ''​lcpl-AST'',​ în care se află AST-ul limbajului LCPL 
-  * Directorul ''​runtime'',​ în care găsiți biblioteca de runtime pentru limbajul LCPL, alcătuită din clasele speciale definite în limbaj, precum și câteva funcții ajutătoare 
-  * Fișierul ''​lcpl-driver.sh.in'',​ care este configurat de CMake cu path-urile necesare pentru a servi ca driver pentru un compilator de LCPL ce ia ca input un fișier JSON (output-ul temei 1), îl trece prin generatorul de cod scris de voi, linkează cu biblioteca de runtime și în final rulează interpretorul LLVM (''​lli''​) pe fișierul rezultat 
-  * Fișierul ''​CMakeLists.txt''​ 
  
-Pentru a compila proiectul, va trebui să creați un director de build și să rulați 
  
-  cmake -DPATH_TO_LLVM_CONFIG="/​path/​to/​the/​llvm-config/​tool"​ -DCMAKE_BUILD_TYPE=Debug /​path/​to/​skel/​ 
  
-Opțional puteți adăuga și un generator, ca de exemplu ''​-G Ninja''​. 
  
-în momentul de față, scheletul de cod pus la dispoziție este hardcodat pentru a genera IR-ul pentru testul ''​hello.lcpl.json''​. Va trebui să generalizați pentru a putea procesa AST-uri din ce în ce mai complexe (ordinea recomandată de implementare este cea urmată de teste - încercați să faceți câte un test să treacă și refactorizați pe parcurs). 
  
-Scheletul de cod este descris în detaliu mai jos.+===== Implementare =====
  
-===== Suportul de execuție pentru LCPL =====+Pentru a începe implementarea pașilor LLVM, puteți urmării pașii de mai jos:
  
-== Reprezentarea datelor ==+  - Descărcați {{:​cpl:​concurs-arhiva.zip|arhiva de start}} și dezarhivați-o 
 +  - Creați un director de build și intrați în el (Exemplu: ''​mkdir build; cd build''​) 
 +  - Rulați ''​cmake''​ cu calea directorului unde ați dezarhivat arhiva (Exemplu: ''​cmake ..''​) 
 +  - Compilați pasul (Exemplu: ''​make''​) 
 +  - Dacă totul s-a compilat cu succes, ar trebui să se genereze biblioteca ''​libLLVMCpl-Contest.so''​ în directorul de build.
  
-După apelul către CMake, directorul ​de build va conține ​un fișier ''​lcpl_runtime.ll''​. Acesta este IR-ul corespunzător claselor speciale din limbajul LCPL. Puteți ​folosi acest fișier ca referință pentru reprezentarea datelor în limbajul LCPLAceasta va fi descrisă în cadrul acestei secțiuni.+Arhiva ​de start conține ​trei fișiere sursă, fiecare dintre acestea conținând scheletul de cod pentru un tip de pas de optimizare. Puteți ​să ii modificați,​ să îi ștergeți sau să adăugați alți pașiDacă adăugați sau scoateți ​fișiere din proiect, trebuie să modifcați fișierul **CMakeLists.txt**
  
-<note warning>​Deși scheletul de cod pus la dispoziție generează IR care funcționează, acesta nu respectă întru totul convențiile LCPLCade în sarcina voastră să îl reparați (vedeți TODO-urile din scheletul de cod).</​note>​+Numele fiecărui pas trebuie să inceapă cu **cpl-** ​Linia de comandă cu care va fi apelat **opt** va conține acești pașîn ordine alfabetică.
  
-  * întregii sunt reprezentați pe 4 bytes (''​i32''​) +Din infrastructura existentă LLVM puteți folosi [[http://​releases.llvm.org/​3.8.1/​docs/​Passes.html#​analysis-passes|pașii de analiză]], dar nu și pe cei de transformare;​ nici direct ​(nu aveți voie să îi apelați), nici indirect (nu aveți voie să preluați cod).
-  * Reprezentarea unui obiect în memorie arată astfel:+
  
-^ Offset ^  Descriere ​                                    ^ +Pentru a rula testele, dezarhivați arhiva ce conține {{:​cpl:​concurs-teste.zip|benchmarkul CPLMark}} în directorul de build, si apoi rulați **./​cplmark.sh**
-|   ​+0 ​  | Pointer către RTTI-ul clasei din care face parte obiectul ​          | +
-|   ​+4 ​  | Atributele obiectului - întregi pe 4 bytes sau referinţe către alte obiecte|+
  
-Referinţa la un obiect este adresa din memorie a acelui obiect. 
- 
-  * Reprezentarea RTTI în memorie arată astfel 
- 
-^ Offset ^  Descriere ​                                    ^ 
-|   ​+0 ​  | Pointer către obiectul String care reprezintă numele clasei ​          | 
-|   ​+4 ​  | Dimensiunea în bytes a obiectului, incluzând informația de runtime ​          | 
-|   ​+8 ​  | Pointer către informația de runtime a clasei părinte, NULL pentru Object ​          | 
-|   ​+12 ​  | Tabela de metode | 
- 
-în tabela de metode se găsesc adresele metodelor din clasa părinte, urmate de metodele clasei. Atunci când o metodă a clasei ascunde metoda din clasa părinte, îi va ocupa locul în tabela de metode. 
- 
-== Exemple de reprezentare == 
- 
-Pentru: 
-  class Main inherits IO 
-   main :  
-    [out "Hello world!"​];​ 
-   end; 
-  end; 
- 
-se generează următoarele:​ 
- 
-  * Obiectul de tip ''​String''​ care reprezintă numele clasei 
- 
-  @0 = global [5 x i8] c"​Main\00"​ 
-  @NMain = global %struct.TString { %struct.__lcpl_rtti* @RString, i32 4, i8* getelementptr inbounds ([5 x i8], [5 x i8]* @0, i32 0, i32 0) } 
- 
-  * Informația de runtime pentru clasa ''​Main''​ 
- 
-  @RMain = global { %struct.TString*,​ i32, %struct.__lcpl_rtti*,​ [6 x i8*] } { 
-               ​%struct.TString* @NMain, 
-               i32 8, 
-               ​%struct.__lcpl_rtti* @RIO, 
-               [6 x i8*] [ 
-                   i8* bitcast (void (%struct.TObject*)* @M6_Object_abort to i8*), 
-                   i8* bitcast (%struct.TString* (%struct.TObject*)* @M6_Object_typeName to i8*), 
-                   i8* bitcast (%struct.TObject* (%struct.TObject*)* @M6_Object_copy to i8*), 
-                   i8* bitcast (%struct.TString* (%struct.TIO*)* @M2_IO_in to i8*), 
-                   i8* bitcast (%struct.TIO* (%struct.TIO*,​ %struct.TString*)* @M2_IO_out to i8*), 
-                   i8* bitcast (void (%struct.TMain*)* @M4_Main_main to i8*) 
-               ]} 
- 
-Clasa ''​Main''​ nu are atribute proprii, prin urmare dimensiunea ei este de 8 bytes, dimensiunea pointerului la RTTI. ''​Main''​ este derivată din clasa ''​IO'',​ deci informația de parent va arăta către RTTI-ul clasei ''​IO''​ (@RIO). În tabela de funcții a clasei ''​Main''​ se află metodele clasei părinte ''​IO''​ și metoda ''​main''​ a clasei ''​Main''​. 
- 
-<note tip>​Dimensiunile tipurilor de date depind de platforma pe care rulați (de exemplu pointerii pot avea 8 sau 4 bytes). De aceea, este indicat să folosiți metoda ''​DataLayout::​getTypeAllocSize()''​. Puteți obține DataLayout-ul cu metoda ''​getDataLayout''​ a modulului LLVM pe care îl generați.</​note>​ 
- 
-  * Constructorul clasei 
- 
-  define void @Main_init(%struct.TMain*) { 
-  entry: 
-    %1 = bitcast %struct.TMain* %0 to %struct.TIO* 
-    call void @IO_init(%struct.TIO* %1) 
-    ret void 
-  } 
- 
-Din constructorul clasei ''​Main''​ se apelează constructorul clasei părinte, pentru a se inițializa atributele clasei părinte. Pentru clase care au atribute declarate cu inițializări,​ constructorul trebuie să conțină și codul necesar acestor inițializări. 
- 
-  * Metodele clasei ​ 
- 
-  define void @M4_Main_main(%struct.TMain* %self) { 
-   ; Prologue - save parameters 
-   %1 = alloca %struct.TMain* 
-   store %struct.TMain* %self, %struct.TMain** %1 
-   ... 
-  } 
- 
- 
-== Convenţia de apel == 
- 
-Primul parametru pentru orice funcție generată va conține adresa obiectului de care aceasta aparține (**self**). 
-Variabilele LCPL pot fi pe stivă sau în registre. Structurile precum tabelele virtuale sau informațiile de runtime sunt variabile globale LLVM IR.  
- 
-== Convenţia de nume == 
- 
-  * Obiectele de tip String care reprezintă numele claselor din programul de intrare vor avea forma ''​N<​NumeClasă>''​.  ​ 
-  * Structurile care definesc layoutul obiectelor in memorie vor avea forma ''​T<​NumeClasă>''​ 
-  * Informația de runtime va avea forma ''​R<​NumeClasă>''​ 
-  * Metodele de inițializare vor avea forma ''<​NumeClasă>​_init''​ 
-  * Restul metodelor se vor genera pe principiul ''​M<​N>​_<​NumeClasă>​_<​NumeMetodă>'',​ unde N este numărul de caractere al numelui clasei 
- 
-== Funcţii şi date predefinite pentru LCPL == 
- 
-Biblioteca de runtime LCPL implementează funcţionalitatea claselor de bază aşa cum este descrisă în {{:​cpl:​teme:​lcpl-manual.pdf | manualul limbajului LCPL}}. În codul generat metodele din bibliotecă pot fi folosite respectând convenţia ca obiectul apelant să fie primul parametru al apelului. Este foarte recomandat să folosiţi această convenţie pentru toate clasele şi metodele, nu doar pentru clasele de bază. 
- 
-== Secvenţa de iniţializare == 
- 
-Punctul de intrare în program este funcția ''​main''​ generată de scheletul de cod. Aceasta trebuie să facă următorii pași: 
- 
-  * să creeze un obiect de tip ''​Main''​ (pentru asta trebuie apelată funcția ajutătoare ''​%%__%%lcpl_new'',​ apoi pe obiectul nou obținut trebuie apelat constructorul clasei ''​Main''​) 
-  * să apeleze metoda ''​main''​ a acestui obiect 
- 
-===== Scheletul de cod ===== 
- 
-==== Runtime-ul limbajului LCPL ==== 
- 
-Runtime-ul limbajului LCPL conține definițiile claselor speciale din limbaj, precum și câteva funcții / structuri de date ajutătoare (vedeți fișierul ''​runtime/​lcpl_runtime.h''​ din arhiva de pornire): 
- 
-== Structura __lcpl_rtti == 
- 
-Reprezintă informația de RTTI asociată fiecărei clase: numele clasei, dimensiunea obiectelor din clasa respectivă,​ pointer către RTTI-ul clasei părinte și tabela de metode virtuale. Fiecare obiect din program (în afară de întregi, desigur) va conține ca primul membru un pointer către structura ''​%%__%%lcpl_rtti''​ corespunzătoare clasei din care face parte. 
- 
-== Definițiile claselor speciale == 
- 
-Definiții pentru clasele ''​Object'',​ ''​String''​ și ''​IO'':​ 
-  * Structurile de date corespunzătoare 
-  * Obiectele de tip ''​%%__%%lcpl_rtti''​ corespunzătoare 
-  * Constructorii 
-  * Metodele definite în manual: 
-      * Pentru clasa ''​Object'':​ ''​M6_Object_abort'',​ ''​M6_Object_typeName''​ și ''​M6_Object_copy''​ 
-      * Pentru clasa ''​IO'':​ ''​M2_IO_in''​ și ''​M2_IO_out''​ 
-      * Pentru clasa ''​String'':​ ''​M6_String_length''​ și ''​M6_String_toInt''​ 
-  * Funcții ajutătoare pentru clasa ''​String'':​ 
-      * ''​M6_String_substring'':​ folosită pentru implementarea funcționalității de substring (primește ca parametri un obiect de tip ''​String''​ și 2 indici) 
-      * ''​M6_String_concat'':​ folosită pentru concatenarea stringurilor (primește ca parametri 2 obiecte de tip ''​String''​) 
-      * ''​M6_String_equal'':​ folosită pentru verificarea egalității a 2 obiecte de tip ''​String''​ (primite ca parametri) 
- 
-== Alte funcții ajutătoare == 
- 
-  * ''​%%__%%lcpl_new'':​ alocă memorie pentru un obiect dintr-o clasă al cărei RTTI îl primește ca parametru; după apelarea acestei funcții trebuie invocat constructorul respectiv pe zona de memorie obținută. 
-  * ''​%%__%%lcpl_checkNull'':​ verifică dacă un obiect este ''​null''​ și aruncă o eroare dacă da; această funcție ar trebui apelată înainte de a face dispatch pe un obiect. 
-  * ''​%%__%%lcpl_cast'':​ realizează un cast explicit sau aruncă o eroare dacă nu se poate realiza castul; primește ca parametri obiectul care trebuie castat și RTTI-ul clasei către care se face cast. 
-  * ''​%%__%%lcpl_intToString'':​ realizează conversia implicită de la un întreg la ''​String''​. 
- 
-==== Analiza semantică ==== 
- 
-Analiza semantică se asigură de corectitudinea semantică a programului,​ și în același timp adună informații utile pentru generarea de IR. Este implementată ca un vizitator la nivelul AST-ului (''​ASTVisitor''​). în cadrul temei nu va fi nevoie să modificați partea de analiză semantică, dar vă veți folosi de câteva informații puse la dispoziție de aceasta. 
- 
-== TypeTable == 
- 
-Menține informații legate de tipuri; de exemplu, pentru a afla tipul corespunzător unui nod din AST folosiți metoda ''​getType(TreeNode *)''​. 
- 
-Există câteva tipuri speciale: cele corepunzătoare claselor speciale (''​Object'',​ ''​IO'',​ ''​String''​),​ tipul corespunzător întregilor (''​Int''​),​ tipul corespunzător constantelor ''​null''​ și tipul vid (''​Void''​). Aveți acces la aceste tipuri speciale prin intermediul metodelor ''​getIntType'',​ ''​getStringType''​ etc. 
- 
-Pentru a compara tipuri, puteți compara direct pointerii întorși de ''​TypeTable''​. 
- 
-Alte metode care pot fi utile sunt ''​getParentClass'',​ ''​getAttribute'',​ ''​getMethod''​. 
- 
-== SymbolMap == 
- 
-Reține pentru fiecare nod de tip ''​Symbol''​ nodul din AST corespunzător definiției acestuia (poate fi un ''​LocalDefinition'',​ ''​Attribute'',​ ''​FormalParam''​ sau simbolul special pentru self (vedeți metoda ''​isSelf''​ din nodul ''​Class''​). 
- 
-==== Generatorul de cod ==== 
- 
-Generatorul de cod (''​IRGenerator''​) pus la dispoziție este unul naiv, care știe să genereze cod pentru un singur lucru: "Hello world"​. îl găsiți în fișierele ''​include/​IRGenerator.h''​ și ''​src/​IRGenerator.cpp''​. Va trebui să organizați și să generalizați codul respectiv pentru a putea genera IR valid pentru orice program LCPL. 
- 
-Generatorul de cod este la rândul său un ''​ASTVisitor'',​ cu o metodă ''​visit''​ pentru fiecare tip de nod (în scheletul de cod sunt adăugate doar cele necesare pentru "Hello world",​ va trebui să le adăugați voi pe celelalte). în plus, conține: 
-  * un ''​TypeTable''​(''​ASTTypes''​) și un ''​SymbolMap''​(''​DefinitionsMap''​) în care se găsesc informațiile de la analiza semantică 
-  * un obiect de tip ''​RuntimeInterface''​ care conține informații legate de runtime-ul LCPL (tipuri, declarații de funcții etc - doar declarații,​ întrucât definițiile sunt în biblioteca de runtime) 
-  * un map care asociază fiecărui nod din AST o valoare din IR (''​NodeMap''​) 
-  * un IRBuilder și alte obiecte care pot fi utile (modulul curent etc) 
- 
-Puteți modifica structura generatorului de cod oricum doriți și puteți adăuga oricâte clase ajutătoare. De exemplu, scheletul de cod conține și un ''​ClassVisitor'',​ care vă permite să vizitați clasele din program într-o ordine topologică (clasele părinte sunt vizitate întotdeauna înaintea celor care le moștenesc). Puteți moșteni din aceast vizitator oricând aveți nevoie de prelucrări pentru fiecare clasă (la generarea layout-ului,​ la generarea constructorilor etc). 
- 
-==== Programul principal ==== 
- 
-Toate clasele de mai sus sunt puse cap la cap în ''​main.cpp'':​ AST-ul primit ca input este deserializat,​ apoi este trecut prin analiza semantică și prin generatorul de cod. Modulul obținut este scris în fișierul de output și apoi verificat (astfel, aveți acces la codul generat chiar daca nu este valid). Partea de verificare presupune doar faptul că IR-ul generat respectă constrângerile LLVM IR-ului (ex: fiecare BasicBlock se termină cu o instrucțiune de tip terminator - branch, return etc). 
- 
-în principiu fișierul ''​main.cpp''​ nu ar trebui modificat - conține deja tot ce vă trebuie, inclusiv legătura între analiza semantică și generatorul de cod. 
-===== API LLVM pe scurt ===== 
- 
-Pentru crearea de tipuri puteți folosi metodele statice ale claselor ''​llvm::​StructType'',​ ''​llvm::​FunctionType'',​ ''​llvm::​ArrayType''​ etc. Uneori poate fi util să creați structuri goale și apoi să apelați ''​setBody''​. Pentru tipuri simple puteți folosi metodele din ''​IRBuilder'':​ ''​getInt32Ty'',​ ''​getVoidTy'',​ ''​getInt8PtrTy''​ (acesta din urmă e util pentru a reprezenta ''​void *''​ din C) etc. Tipurile LLVM au o metodă ''​getPointerTo''​ pe care o puteți folosi pentru a crea tipuri pointer. 
- 
-''​IRBuilder''​ conține metode convenabile și pentru adăugarea de constante: ''​getInt32'',​ ''​CreateGlobalStringPtr''​. ​ 
- 
-Cea mai substanțială parte a ''​IRBuilder''​ este crearea de instrucțiuni:​ ''​CreateCall'',​ ''​CreateLoad'',​ ''​CreateRetVoid'',​ ''​CreateGEP'',​ ''​CreateBitCast''​ etc. Va trebui însă să aveți grijă unde sunt create aceste instrucțiuni:​ ''​IRBuilder''​ are un InsertPoint care trebuie setat în locul unde doriți să inserați. Pentru asta puteți folosi ''​GetInsertPoint''​ / ''​SetInsertPoint''​. 
- 
-Nu uitați de forma SSA - o valoare poate fi scrisă o singură dată. De aceea, poate fi util să alocați spațiu pe stivă (''​CreateAlloca''​) pentru valori care pot fi scrise mai mult de o dată (de exemplu, vedeți ce generează ''​clang''​ pentru parametri la -O0). Nu încercați să generați cod optim, important e să fie corect (puteți avea oricâte perechi load/store redundante etc). 
- 
-Este util să folosiți un build de debug al LLVM pentru rezolvarea temei. Buildurile de debug conțin assert-uri care vă pot ajuta să faceți debug atunci când generați IR greșit. De asemenea, clasele derivate din ''​llvm::​Value''​ au o metodă ''​dump''​ care poate fi invocată dintr-un debugger atunci când vreți să vedeți care valori duc la declanșarea assert-urilor. 
- 
-===== Testare automată și punctaj ===== 
- 
-Testarea temei de casă va folosi o serie de teste ce vor fi disponibile pe vmchecker. Aceleași teste sunt disponibile în arhiva de teste. 
- 
-Testele pot fi rulate prin intermediul scriptului ''​eval.sh'',​ care ia ca parametri calea către directorul de teste și calea către ''​lcpl-driver.sh''​ (care se află în directorul de build după ce rulați CMake). Dacă doriți să rulați un singur test, puteți pasa numele acestuia ca al treilea argument pentru ''​eval.sh'':​ 
- 
-  eval.sh /​path/​to/​tests /​path/​to/​lcpl-driver.sh advanced/​stack 
-  ​ 
-Dacă un test pică, ''​eval.sh''​ va păstra următoarele fișiere: 
-  * ''<​test>​.out''​ și ''<​test>​.err''​ - conțin stream-urile de output și error pentru compilarea și rularea testului. 
-  * ''<​test>​.lcpl.json.ll''​ - modulul IR generat de programul vostru. 
-  * ''<​test>​.lcpl.json.bc''​ - bitcode-ul rezultat după linkarea cu runtime-ul LCPL. Pentru a vedea IR-ul corespunzător,​ folosiți ''​llvm-dis''​. 
- 
- 
- 
-===== Instrucţiuni de predare a temei ===== 
- 
-Arhiva trebuie să aibă structura din arhiva de start: 
-  * CMakeLists.txt în rădăcină 
-  * să producă un executabil **lcpl-irgen** 
-  * nu puneți în arhivă fișiere obiect/​executabile 
  
 ===== Resurse ===== ===== Resurse =====
-  * {{:​cpl:​teme:​lcpl-manual.pdf | manualul limbajului LCPL}} 
-  * {{http://​llvm.org/​releases/​3.8.0/​docs/​tutorial/​LangImpl3.html | Tutorial generare de LLVM IR }} 
-  * {{:​cpl:​teme:​tema2-archive.zip | Arhiva de start}} 
-  * {{:​cpl:​teme:​tema2-tests.zip | Arhiva cu teste}} 
-  * {{:​cpl:​teme:​tema2-tests-original.zip | Arhiva cu testele în limbaj LCPL}} 
-===== F A Q ===== 
  
-===== Change Log ===== +  * {{:​cpl:​concurs-arhiva.zip|Arhiva de start}} 
-  +  * {{:​cpl:​concurs-teste.zip|CPLMark}} 
-  * //<​del>​2016.11.13</​del>​2016.11.22//:​ Adăugare punctaj +  * [[http://llvm.org/docs/​WritingAnLLVMPass.html|Writing an LLVM Pass]] ​
-  * //<​del>​2016.11.13</del>2016.11.22//: Adăugare arhivă cu codul original LCPL din care au fost generate testele+
  
cpl/teme/tema2.1479836105.txt.gz · Last modified: 2016/11/22 19:35 by diana.vasile
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