Differences

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

Link to this comparison view

cpl:teme:tema3 [2016/12/07 08:04]
bogdan.nitulescu
— (current)
Line 1: Line 1:
-====== Tema de casa 3 - Backend ====== 
-În cadrul acestei teme veți implementa un backend în LLVM pentru arhitectura **Cpl**. 
-Deoarece implementarea unui backend necesită un volum mare de muncă, veți porni tema de la o {{:​cpl:​teme:​cpl.tar.gz|arhivă de start}}. 
-===== Informaţii organizatorice ===== 
- 
-  * **Deadline**:​ Termenul limită până când se pot trimite temele fără depunctări de întârziere este ** ,marți, 20 decembrie 2016, ora 23:59**. Pentru mai multe detalii, consultaţi [[:​cpl:​teme:​general|regulamentul]] aferent temelor de casă. 
-  * **Colaborare**:​ Tema va fi rezolvată [[http://​ocw.cs.pub.ro/​courses/​cpl/​meta/​notare#​penalizare_pentru_teme_copiate|individual]]. 
-  * **Punctare**:​ 150p pentru implementarea completă şi corectă 
- 
-===== Enunț ===== 
-Va trebui să implementați în limbajul C++ porțiuni din cod responsabile cu generarea de generare de cod pentru arhitectura **Cpl**. 
-Programul vostru va trebui să primească la intrare output-ul temei 3 și să genereze un fișier cu cod în limbaj de asamblare. 
-Output-ul programului realizat de voi poate fi asamblat și link-at cu **gcc-arm-linux-gnueabi** și rulat cu ajutorul unui emulator ([[cpl:​labs:​08|laboratorul 8]]). 
-===== Arhitectură ===== 
-În cadrul acestei teme se va folosi o arhitectură care definește un subset al instrucțiunilor de **ARMv3**. 
- 
-==== Registre ==== 
-Arhitectura dispune de un set de 16 registre de 32 biți (**R0**-**R15**) și un registru de stare (**CPSR**): 
-  * **R0**-**R12** registre generale folosite de alocator 
-  * **R13** stack pointer (**SP**) 
-  * **R14** link register (**LR**, adresa de return) 
-  * **R15** program counter (**PC**) 
- 
-Registrul **R14** (**LR**) conține adresa de return și este inițializat la intrarea in funcție. 
-El poate fi folosit de alocator, daca adresa de return este salvată pe stivă sau în alt registru. 
-Registrele **R13** (**SP**) si **R15** (**PC**) sunt rezervate și nu vor fi folosite de alocator. 
- 
-Registrul de stare este scris de către instrucțiunile de comparație și citit de către instrucțiunile de salt condiționat. 
- 
-=== Registrul R15 === 
-Registrul **R15** (program counter) poate fi scris pentru a sări la o anumită adresă. 
-Citind acest registru, obținem adresa instrucțiunii curente + 8 octeți (2 instrucțiuni în față relativ la instrucțiunea curentă). 
-Dacă acest registru nu este scris de o instrucțiune,​ el este incrementat automat cu 4, pentru a executa instrucțiunea urmatoare. 
- 
-==== Calling convention ==== 
-Parametrii unei funcții sunt transmiși prin intermediul registrelor **R0**-**R3**. 
-Restul parametrilor sunt transmiși prin intermediul stivei. 
- 
-Rezultatul funcției, dacă este cazul, este întors prin registrul **R0**. 
- 
-Adresa de return este transmisă prin registrul **R14**. 
- 
-Registrele **R4**-**R11** trebuie salvate de funcția apelată. 
- 
-==== Stivă ==== 
-Vârful stivei este ținut în registrul **R13**. 
-Pentru a aloca spațiu pe stivă, acest registru este decrementat. 
-Similar, pentru a elibera stiva vom incrementa acest registru. 
-Valorea din **R13** reprezintă o locație validă pe stivă (i.e. putem să stocăm folosind instrucțiunea ''​str r14, [r13, #​0]''​). 
- 
-Nu există instrucțiuni de tipul **push** sau **pop** pentru lucrul cu stiva. 
- 
-==== Setul de instrucțiuni ==== 
- 
-Setul de instrucțiuni cuprinde: ​ 
- 
-^ Tip ^ Sintaxă ^ Efect ^ Observații ^ 
-| ALU | add rd, rs1, rs2 | rd = rs1 + rs2 | | 
-| ::: | add rd, rs1, i8 | rd = rs1 + i8 | | 
-| ::: | sub rd, rs1, rs2 | rd = rs1 - rs2 | | 
-| ::: | sub rd, rs1, i8 | rd = rs1 - i8 | | 
-| ::: | mul rd, rs1, rs2 | rd = rs1 * rs2 | rd != rs1 | 
-| ::: | and rd, rs1, rs2 | rd = rs1 AND rs2 | | 
-| ::: | and rd, rs1, i8 | rd = rs1 AND i8 | | 
-| ::: | orr rd, rs1, rs2 | rd = rs1 OR rs2 | | 
-| ::: | orr rd, rs1, i8 | rd = rs1 OR i8 | | 
-| ::: | eor rd, rs1, rs2 | rd = rs1 XOR rs2 | | 
-| ::: | eor rd, rs1, i8 | rd = rs1 XOR i8 | | 
-| Transfer | mov rd, rs | rd = rs | | 
-| ::: | mvn rd, rs | rd = NOT rs | | 
-| ::: | mov rd, i8 | rd = zero_extend i8 | | 
-| ::: | mvn rd, i8 | rd = NOT zero_extend i8 | | 
-| Transfer condiționat | moveq rd, i8 | if eq then rd = zero_extend i8 | | 
-| ::: | movne rd, i8 | if ne then rd = zero_extend i8 | | 
-| ::: | movge rd, i8 | if ge then rd = zero_extend i8 | | 
-| ::: | movgt rd, i8 | if gt then rd = zero_extend i8 | | 
-| ::: | movle rd, i8 | if le then rd = zero_extend i8 | | 
-| ::: | movlt rd, i8 | if lt then rd = zero_extend i8 | | 
-| Salt | b i24 | pc = address | | 
-| Salt condiționat | beq i24 | if eq then pc = address | | 
-| ::: | bne i24 | if ne then pc = address | | 
-| ::: | bge i24 | if ge then pc = address | | 
-| ::: | bgt i24 | if gt then pc = address | | 
-| ::: | ble i24 | if le then pc = address | | 
-| ::: | blt i24 | if lt then pc = address | | 
-| Apel funcție | bl i24 | lr = next_address;​ pc = address | | 
-| Memorie | ldr rd, [ra, i12] | rd = [ra + i12] | | 
-| ::: | ldrb rd, [ra, i12] | rd = zero_extend [ra + i12] | | 
-| ::: | str rs, [ra, i12] | [ra + i12] = rs | | 
-| ::: | strb rs, [ra, i12] | [ra + i12] = rs AND 0xFF | | 
- 
-===== Detalii de implementare ===== 
- 
-==== Flux de control ==== 
-Pentru arhitectura **Cpl**, program counter-ul este registrul **R15**. 
-Deoarece nu există o instrucțiune dedicată de return, intoarcere din funcția curentă se face punând în **R15** adresa de return. 
-La intrarea în funcție, adresa de return este disponibilă în registrul **R14**. 
-Valoarea acestui registru este mutată (prin pseudo instrucțiunea COPY) într-un registru virtual. 
-Ieșirea din funcție se face mutând această valoare din registrul virtual în **R15**, folosind o instrucțiune specială. 
-Această instrucțiune trebuie marcată cu ''​isTerminator''​ pentru a nu fi eliminată de pașii de optimizare. 
- 
-==== Imediat pe 32 de biți ==== 
-Pentru o valoare pe 8 biți, aceasta se poate pune într-un registru folosind instrucțiunea ''​MOV''​. 
-Dacă avem o valoare mai mare (sau un simbol), avem nevoie de un alt mecanism de inițializare a registrului. 
- 
-Recomandăm folosirea unei instrucțiunii de load pentru această inițializare. 
- 
-==== Comparații ==== 
-Pentru **if-uri** și bucle putem folosi branch-uri condiționate. 
-Aceste pattern-uri se pot defini direct. 
-Pentru o obține rezultatul unei comparații (e.g. ''​return a < b;''​) avem nevoie de instrucțiuni de transfer condiționate. 
- 
-Recomandăm definirea unor pseudo instrucțiuni de comparație care au ca rezultat **0** sau **0xFFFFFFFF**,​ în funcție de operația relațională. 
-Aceste pseudo instrucțiuni pot fi înlocuite în metoda ''​expandPostRAPseudo''​ cu o instrucțiune de comparație și 2 transferuri,​ unul condiționat (sau ambele). 
- 
-Pentru funcția următoare: 
-<​code>​ 
-int lt(int a, int b) { 
- return a < b; 
-} 
-</​code>​ 
- 
-Codul generat ar putea fi următorul: 
-<​code>​ 
-       cmp r0, r1 
-       mvn r0, #0 
-       movge r0, #0 
-       mov r1, #1 
-       and r0, r0, r1 
-       orr r15, r14, r14               @ Return 
-</​code>​ 
- 
- 
-==== Stiva ==== 
-Adresele de pe stivă sunt reprezentate printr-un operand special, numit **Frame Index**. 
-Acest operand este un întreg (poate avea și valori negative) care caracterizeaza o intrare pe stiva: offset, dimensiune, aliniament. 
- 
-În partea de generare de cod (fișiere td), **Frame Index**-ul este identificat printr-un **ComplexPattern** numit **frame_addr**. 
-Pentru instrucțiunile care accesează memoria, acest **frame_addr** se pune in locul registrului de adresă, iar imediatul este pus pe 0. 
-După pasul de alocare de registre, acești operanzi sunt înlocuiți cu **R13** iar offset-ul se pune în locul imediatului. 
- 
-În prologul și epilogurile funcției se introduc instrucțiuni care modifică stiva cu cantitatea necesară funcției. 
- 
-===== Task-uri ===== 
-Funcționalitatea se va puncta folosind testele din arhivă. 
-Puteți totuși să vă ghidați după următoarele task-uri pentru rezolvarea temei de backend. 
- 
-Fiecare task este marcat în cod prin intermediul comentariilor cu **TODO**. 
- 
-Arhiva de start nu se poate compila. 
- 
-==== Task 1 ==== 
-Definiți instrucțiunile care compun setul de instrucțiuni corespunzător arhitecturii Cpl. 
-Acest lucru se realizează în fișierul **CplInstrInfo.td** prin instanțierea claselor definite în fișierul **CplInstrFormat.td**. 
-Instrucțiunile de comparație,​ salt, apel de funcție și/sau condiționate trebuie marcate corespunzător. Un exemplu în acest sens în constituie instrucțiunea ORR_RET care este marcată ca fiind instrucțiune de întoarcere din funcție prin setarea câmpului //​isReturn//​. ​ 
-De asemenea, trebuie să definiți în **CplPatterns.td** și patternurile care descriu transfomările de la noduri din graful de selecție la instrucțiuni specifice arhitecturii Cpl. 
- 
-==== Task 2 ==== 
-Pentru a putea transmite parametri unor funcții și pentru a primi rezultatul corect este necesar ca toate funcțiile să respecte un **calling convention**. 
-Descrierea acestui **calling convention** pentru target-ul **Cpl** o găsiți în secțiunea de [[cpl:​teme:​tema3##​calling_convention|arhitectură]]. 
- 
-Trebuie să modificați în fișierul **CplCallingConv.td** registrele folosite pentru transmiterea parametrilor,​ rezultatului și registrele salvate de funcția apelată. 
- 
- 
-==== Task 3 ==== 
-Limbajul intermediar LLVM conține o instrucțiune de **select**. 
-Această instrucțiune primește 3 operanzi, primul de tip **i1** și întoarce al 2-lea sau al 3-lea operand în funcție de valoarea primului operand. 
- 
-Această instrucțiune se poate genera foarte ușor din următorul cod **C**: 
-<​code>​ 
-int f(bool c, int a, int b) { 
-    return c ? a : b; 
-} 
-</​code>​ 
- 
-==== Task 4 ==== 
-După terminarea pasului de alocare de registre, trebuie alocat spațiu pe stivă. 
-Acest spațiu poate fi necesar pentru spill-uri, pentru parametrii transmiși unor funcții sau pentru variable a căror adresă este folosită explicit. 
-Funcția **adjustStackPtr** este apelată la intrarea în funcție pentru a aloca spațiu pe stiva și la ieșirile din funcție pentru a elibera acest spațiu. 
-În cadrul acestei metode, trebuie să adăugați cod necesar pentru modificarea stivei (R13). 
- 
-Tot după alocarea de registre, pot să existe unele transferuri. 
-Acestea pot sa provină din alocare, sau din calling convention. 
-În metoda **CplInstrInfo::​copyPhysReg**,​ trebuie să adăugațti cod care să copieze valoarea unui registru în alt registru. 
- 
-==== Task 5 ==== 
-Pentru apeluri de funcție indirecte (cu adresa funcției într-un registru) va trebui să generați o secvență de cod care să salveze **LR**-ul și să modifice **PC**-ul. 
-În cadrul selecției de instrucțiuni,​ se generează o pseudo-instrucțiune **CALLR**, care va trebui înlocuită. 
- 
-Pentru **return**-ul unei funcții, se generează o pseudo-instrucțiune **RET**. 
-Aceasta va trebui înlocuită cu **ORR_RET**,​ pentru a transfera **LR** în **PC**. 
- 
-==== Task 6 ==== 
-În cadrul acestui task, trebuie sa generați cod pentru secvențe de forma: 
-<​code>​ 
-int lt(int a, int b) { 
- return a < b; 
-} 
-</​code>​ 
- 
-Deoarece nu există o instrucțiune care să pună într-un registru valoarea unei comparații,​ este necesară o secvență de instrucțiuni. 
-Pentru a simplifica generarea de cod mașină, recomandăm să se folosească o pseudo-instrucțiune care sa fie înlocuită cu o secvență validă de instrucțiuni în metoda **expandPostRAPseudo**. 
-Căutați **TODO 6** în codul sursă. 
- 
-Consultați secțiunea [[cpl:​teme:​tema3#​comparatii|comparații]] pentru detalii de implementare. 
- 
-===== Testare ===== 
-Testarea se va face folosind următoarea {{:​cpl:​teme:​tema4-teste.tar.gz|arhivă}} 
- 
-Setați în variabila de mediu ''​CPL_LLC''​ calea către executabilul de **llc**, care suportă target-ul **cpl**. 
- 
-Testele se rulează folosind comanda: 
- 
-<​code>​ 
-./​run_all.sh 
-</​code>​ 
- 
-Modul în care este distribuit punctajul pentru această temă este următorul: 
-  * **Testele publice (120p)** 
-    * 20 de teste, fiecare valorând 6 puncte 
-  * **Calitatea implementării (30p)** 
-    * 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. ​ 
-===== Resurse ===== 
-  * {{:​cpl:​teme:​cpl.tar.gz | Arhiva de start}} 
-  * {{:​cpl:​teme:​tema4-teste.tar.gz | Arhiva de testare}} 
  
cpl/teme/tema3.1481090695.txt.gz · Last modified: 2016/12/07 08:04 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