Differences

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

Link to this comparison view

cpl:labs:08 [2015/11/23 16:38]
laura.vasilescu [Relația de post-dominare]
cpl:labs:08 [2017/11/21 06:52] (current)
bogdan.nitulescu [Exercițiul 3]
Line 1: Line 1:
-====== 08. Control Flow Analysis ======+===== 08. LLVM backend ​=====
  
-Înainte de a putea optimiza un program, unui compilator îi sunt necesare componente care sa îl ajute sa "​înțeleagă"​ cum folosește programul respectiv resursele disponibile.+===== Nice to read =====
  
-Astfel, compilatorul trebuie sa fie capabil sa descrie+  * [[http://​llvm.org/​docs/​CodeGenerator.html|The LLVM Target-Independent Code Generator]] 
-  * caracteristicile fluxului de control al programelor +  * [[https://​www.google.com/​url?​sa=t&​rct=j&​q=&​esrc=s&​source=web&​cd=1&​cad=rja&​uact=8&​ved=0CB0QFjAAahUKEwjzt_fS3tbIAhWn_XIKHbiXBkM&​url=http%3A%2F%2Fllvm.org%2Fdevmtg%2F2014-04%2FPDFs%2FTalks%2FBuilding%2520an%2520LLVM%2520backend.pdf&​usg=AFQjCNFzRa244bFKgvM2bPNFE0SHbubtyA&​sig2=CB3kPXTrEvUbHhJ2-jMaBw|Building an LLVM backend]] 
-  * cum sunt manipulate datele +  * [[http://​llvm.org/​devmtg/​2009-10/​Korobeynikov_BackendTutorial.pdf|Building a  
-Astfel, mecanismele mai generale, dar mai puțin eficiente, pot fi înlocuite cu mecanisme mai specializate și mai eficiente.+backend ​in 24 hours]] 
 +  * [[http://​jonathan2251.github.io/​lbd/​|Creating an LLVM Backend for the Cpu0 Architecture]] 
 +  * [[http://​llvm.org/​docs/​TableGen/​|TableGen]]
  
-===== Abordări ale analizei fluxului de control ===== 
  
-Orice analiza a fluxului ​de control al unei rutine începe cu determinarea **blocurilor de bază(basic blocks)**. Acest pas constituie rutina ​și construcția **Control Flow Graph (CFG)**.+===== Introducere ===== 
 +Backend-ul ​de LLVM primește cod scris în limbajul intermediar ​și generează asamblare. 
 +Binarul este llc.
  
-Abordarea descrisă în continuare folosește **dominatorii** pentru ​descoperi buclele și a le memoraîn vederea optimizării ulterioare. Această abordare ​este suficientă optimizoarelor care analizează fluxul de date în mod iterativ.+Pentru ​face trecerea de la codul IR la asamblare, este nevoie de 4 transformări:
  
-O abordare mai sofisticată este **analiza intervalelor (Interval Analysis)**. Aceasta include o serie de metode de a analiza structura unei rutine și de a o descompune în regiuni imbricate denumite intervale. Această structură de regiuni imbricate este descrisă printr-un arbore (denumit arbore de control) care este foarte util în structurarea și îmbunătățirea analizei fluxului de date. Această abordare este mai complexă și nu va fi discutată aici.+LLVM IR -> SelectionDAG -> MachineDAG -> MachineInstr -> MCInst
  
-==== Exemplu ​====+==== SelectionDAG ​==== 
 +Reprezintă un graf în care operațiile sunt reprezentate ca noduri. 
 +Majoritatea nodurilor sunt independente de arhitectură,​ dar pot exista și noduri custom. 
 +Fiecare nod are un opcode, care este definit (pentru nodurile independente de arhitectură) în enum-ul [[http://​llvm.org/​docs/​doxygen/​html/​namespacellvm_1_1ISD.html|ISD::​NodeType]] 
 +Dacă este nevoie de noduri specifice pentru o arhitectură,​ ele se definesc începând cu ISD::​BUILTIN_OP_END. 
 +Se poate observa ca există mai multe opcode-uri decât instrucțiuni llvm.
  
-Înainte de a descrie tehnici formale folosite în analiza fluxului de control și în analiza fluxului de date, să prezentăm un exemplu simplu+Arcele din graf reprezintă dependințe
-Fie rutina C de mai joscare calculează termenul ''​m''​ din șirul lui Fibonacci (''​m ≥ 0''​). Lângă secvența de cod C, am dat șposibilă descriere într-un limbaj intermediar a acestei funcții.+Ele pot fi: 
 +  - de dateo operație folosește un rezultat produs de altă operație;​ 
 +  ​chain, ordonează operații
 +  - glue, operațiile sunt împreună.
  
-^ Cod sursă ^ Pseudocod generat ^ +Valorile din acest graf au tipuri ​(e.g. i32).
-|<code c> +
-unsigned int fib(unsigned int m+
-    unsigned int f0 = 0; +
-    unsigned int f1 = 1; +
-    unsigned int f2, i;+
  
-    if (m <1) +==== MachineDAG ​==== 
-        return m; +Este un graf foarte asemănător cu SelectionDAG,​ în care nodurile sunt înlocuite cu instrucțiuni. ​
-    else { +
-        for(i 2; i <m; i++) { +
-            f2 f0 + f1; +
-            f0 f1; +
-            f1 f2; +
-        } +
-        return f2; +
-    } +
-}</​code>​ | <code asm> +
-1      receive m +
-2      f0 <- 0 +
-3      f1 <- 1 +
-4      if m <1 goto L3 +
-5      i <- 2 +
-6  L1: if i <m goto L2 +
-7      return f2 +
-8  L2: f2 <- f0+f1 +
-9      f0 <- f1 +
-10     f1 <- f2 +
-11     i <- i+1 +
-12     goto L1 +
-13 L3: return m+
  
 +==== MachineInstr ====
 +MachineDAG-ul este transformat într-o listă de instrucțiuni dependente de arhitectură,​ cu câteva excepții (e.g. instrucțiunea COPY).
  
-  +==== MCInst ==== 
-</​code>​ |+Este o reprezentare simplificată,​ care conține un opcode și niște operanzi. ​
  
-Primul pas este de a descoperi structura de control a programului. Această structură poate fi evidentă în codul sursă (''​if-then-else'',​ cu o buclă pe partea cu ''​else''​),​ însă, aceasta nu mai este la fel de evidentă în limbajul intermediar. Mai mult, chiar și în Cexistă situații mult mai complexe (ex. un ''​for''​ ar fi putut fi format din instrucțiuni ''​if'' ​și ''​goto''​)+===== Structura ​de fișiere ===== 
-Pentru a facilita înțelegerea metodei de analiză a fluxul de control, am reprezentat în figura de mai jos codul intermediar într-o formă "​vizuală",​ un ''​flowchart''​.+Pentru a înregistra un backendtrebuie modificate urmatoarele ​fișiere: 
 +  CMakeLists.txt 
 +  ​autoconf/​config.sub 
 +  autoconf/​configure.ac 
 +  configure 
 +  include/​llvm/​ADT/​Triple.h 
 +  include/​llvm/​Object/​ELFObjectFile.h 
 +  include/​llvm/​Support/​ELF.h 
 +  lib/​Support/​Triple.cpp 
 +  lib/​Target/​LLVMBuild.txt
  
-{{ :cpl:​labs:​laborator-08-fibonacci-flowchart.gif |Flowchart pentru fib()}} +HintCăutați în aceste fișiere apariții corespunzătoare unui target existent ​(ex Hexagon).
-===== Basic blocks =====+
  
-Un ** block de bază (basic block)** reprezintă o secvență de instrucțiuni ​care se execută întotdeauna una după alta+Implementarea se face în directorul lib/​Target/​X,​ care trebuie să conțină, printre altele și următoarele fișiere: 
-Formalun **basic block** (bbeste secvență maximală de instrucțiuni consecutive în care se poate intra doar prin intermediul primei ​instrucțiuni și din care se poate ieși doar prin intermediul ultimei instrucțiuni.+^ Nume           ^ Semnificație ​  ^ 
 +| XTargetMachine | Implementarea unei clase care extinde LLVMTargetMachine. Conține ​**XPassConfig** care adaugă pașii de transformare. Cel mai important pas este **createXISelDag** | 
 +| XSubtarget ​    | Extinde ​clasă generată de tablegen, care definiește un subtarget. | 
 +| XISelLowering ​ | Definește modul in care se face lowering la un SelectionDAG legal| 
 +| XISelDAGToDAG ​ | Este responsabil cu trecerea de la SelectionDAG la MachineDAG | 
 +| XRegisterInfo ​ | Conține informații despre regiștrii (regștrii rezervațispeciali, salvați de calling convention). Metoda care trebuie implementată este **eliminateFrameIndex**, care inlocuiește accese abstracte la stivă ​(e.g. FI -3cu adresă concretă (e.g. -20 (SP)) | 
 +| XInstrInfo ​    | Informații și transformări pe instrucțiuni. Cele mai importante metode care trebuiesc implementate sunt **copyPhysReg**,​ **storeRegToStackSlot**,​ **loadRegFromStackSlot**,​ **expandPostRAPseudo** | 
 +| XFrameLowering | Responsabil cu calcularea stivei folosite ​și modificarea ei la intrarea (**emitPrologue**) și ieșirile (**emitEpilogue**) ​din funcție. | 
 +| XAsmPrinter ​   | Emiterea codului ​și datelor. Deși conține Asm în nume, dumparea se face la un stream abstract care poate fi text (pentru asamblare) sau obiect (dacă se generează direct elf)|
  
-** Determinare basic blocks** +===== TableGen ===== 
-  - Prima instrucțiune a unui basic block (denumită **lider**) poate fi+Informațiile dependente de arhitectură sunt definite în fișiere speciale cu extensia ``.td`` într-o manieră declarativă.
-    * punctul de intrare în rutină +
-    * ținta unei instrucțiuni de salt +
-    * instrucțiunea imediat următoare unei instrucțiuni de salt +
-  ​Pentru a determina bb-urile care formează ​rutina întâi se identifică toți liderii și apoi, pentru fiecare lider, includem în  ''​bb''​ toate instrucțiunile de la lider pana la următorul lider sau până la sfârșitul rutinei.+
  
-Pe flowchart-ul de mai sus se vede că putem identifica cu ușurință blocurile ​de bază: +Aceste fișiere sunt procesate ​de utilitarul ​**table-gen**, care generează cod C++ pe baza acestor fișiere.
-  ​nodurile 1-4 formează un basic block (notat B1) +
-  ​nodurile 8-11 formează alt basic block (notat B6) +
-  ​Toate celelalte noduri formează singure câte un basic block +
-    * nodul 12 -> B2 +
-    * nodul 5 -> B3 +
-    * nodul 6 -> B4 +
-    * nodul 7 -> B5 +
-===== Graful fluxului de control (CFG) =====+
  
-{{:​cpl:​labs:​laboratorul08-fibonacci-domination-1.gif? |Graful fluxului de control pentru fib (CFG)}} +Cele 2 concepte importante din limbaj sunt clasele și definițiile.
-{{:​cpl:​labs:​laborator-08-fibonacci-cfg-llvm.png?​|Graful fluxului de control pentru fib (CFG) generate cu LLVM}}+
  
-În prima figură se pot observa, pe lângă blocurile de bază definite mai sus, au fost adăugate două blocuri speciale: +**Clasele** sunt folosite ​pentru ​a grupa caracteristici comune ale resurselor. O clasă poate să extindă una sau mai multe clase. Cu excepția unor clase de baza (Instruction,​ Register, CallingConv,​ CalleeSavedRegs,​ ș.a.), care definesc semantica unor resurse, clasele nu apar in fișierele C++ generate.
-  ​entry +
-  ​exit +
-Motivele ​pentru ​care se introduc cele două blocuri speciale vor deveni ​mai evidente la analiza fluxului ​de date.+
  
-A doua figură (ce conţine cod intermediar LLVM) fost obţinută executând următoarele comenzi+Pentru ​defini un registru R0, extindem clasa **Register**
-<​code ​bash+<​code>​ 
-sudo apt-get install clang +// Clasa CplReg extinde clasa Register. 
-clang -emit-llvm fibo.--o fibo.bc+// Parametrii sunt transmiși printr-o manieră care seamana cu template-urile din C++. 
 +class CplReg<​bits<​5>​ num, string n, list<​string>​ alt = [], 
 +                   ​list<​Register>​ alias = []> : Register<​n>​ { 
 +  let Namespace = "​Cpl"; ​    // Namespace este un câmp din Register în care 
 +                             // vor fi grupate registrele în codul generat. 
 +  field bits<​5>​ Num;         // Field al clasei curente în care salvăm numărul registrului 
 +  let Aliases = alias; ​      // Listă de alias-uri pentru registru 
 +  let HWEncoding{4-0} = num; // Codificarea registrului 
 +}
  
-sudo apt-get install dot2tex+// Ri 32-bit integer registers. 
 +// Această clasă nu se reflectă în fișierul generat. 
 +class Ri<​bits<​5>​ num, string n, list<​string>​ alt = []> : CplReg<​num,​ n, alt> { 
 +  let Num = num; 
 +}
  
-opt -dot-cfg fibo.bc ​dot -Tpdf cfg.fib.dot ​cfg.fib.pdf ​ +// Definim R0, R1 și R2 prin intermediul claselor Ri și DwarfRegNum 
-SAU +def R0 : Ri<0, "​r0">, ​ DwarfRegNum<​[0]>​; 
-opt-3.0 -f -dot-cfg fibo.bc ; dot -Tpdf cfg.fib.dot > cfg.fib.pdf +def R1 : Ri<1, "​r1"​>,  DwarfRegNum<​[1]>;​ 
 +def R2 : Ri<2, "​r2">, ​ DwarfRegNum<​[2]>;​ 
 +//...
 </​code>​ </​code>​
  
-În grafexistă ​**arc** (muchie orientată) de la un nod la altul dacă există posibilitatea caimediat după execuția ultimei instrucțiuni din ''​bb''​-ul din primul nodsă urmeze spre execuție prima instrucțiune din ''​bb''​-ul din cel de-al doilea nod. +Pentru a defini o instrucțiuneextindem clasa **Instruction**
-Există arce de la nodul //entry// la fiecare nod care reprezintă un **basic block de intrare** (liderul său poate fi prima instrucțiune executată la apelul rutinei). Analog, există arce de la fiecare nod ce reprezinta un **basic block de ieșire** (ultima instrucțiunea a ''​bb''​-ului poate fi ultima instrucțiune executată la ieșirea din funcție) la nodul //exit//.+<​code>​ 
 +class InstCpl<​dag outsdag insstring asmstr> 
 +  : Instruction { 
 +  let Namespace = "​Cpl";​
  
-<​note>​În general, exista un singur basic block de intrare, dar, în unele limbaje ​(ex. FORTRAN), pot exista mai multe puncte de intrare într-o rutina).</​note>​+  dag OutOperandList = outs;  // lista operanzilor destinație 
 +  dag InOperandList = ins;    // lista operanzilor sursă 
 +  let AsmString = asmstr; ​    // string-ul corespunzător sintaxei 
 +  let Size = 4;               // dimensiunea ​în octeți ​(pentru generare obiect)
  
-În continuare, definim: +  bits<​32>​ Inst = 0;          // codificarea binară a instrucțiunii 
-  ​* **Succ(b)** - setul de succesori ai unui basic block +  ​bits<​32>​ SoftFail; 
-  * **Pred(b)** - setul de predecesori ai unui basic block. +}
-Tipuri de basic blocks: +
-  * **Branch** - blocul are mai mult de un succesor +
-  * **Join** - blocul are mai mult de un predecesor+
  
-===== Dominatori și postdominatori =====+// Instrucțiunea va fi identificată prin enum-ul Cpl::ADD în codul generat. 
 +def ADD : InstCpl<​ 
 +     (outs IntRegs:​$rc),​ 
 +     (ins IntRegs:​$ra,​ IntRegs:​$rb),​ 
 +     "​add $rc, $ra, $rb" 
 +>; 
 +</​code>​
  
-==== Relația ​de dominare ==== +Generarea ​de cod se face prin intermediul clasei ​**Pat** care mapează noduri din **SelectionDAG** în **MachineDAG**
-Pentru a determina ​**buclele într-un CFG**, definim întâi o relație binară pe nodurile grafului, numită **dominare**+<​code>​ 
-Nodul d **domină** nodul i (**d dom i**) dacă orice drum posibil de la nodul //entry// la nodul //i// include nodul //d//. +// Nu avem nevoie de nume pentru pattern, așa că îl definim anonim
-Nodul d **domină strict** nodul i (**d sdom i**) dacă ''​d dom i''​ și ''​d != i''​. +
-{{ :​cpl:​labs:​laborator-08-dominare.jpeg?​ |d dom i}}+
  
-Proprietăți ale relației de dominare+// add -> ADD 
-  * **Reflexivitate** ​un nod este propriul său dominator +def Pat<(add IntRegs:​$ra,​ IntRegs:​$rb),​ (ADD IntRegs:​$ra,​ IntRegs:​$rb)>;​ 
-  * **Antisimetrie** - dacă A domină B și B domina A atunci A B +// ineg -> 
-  * **Tranzitivitate** ​dacă A domină B și B domină C atunci A domină C+//   ​t ​EOR ra, ra    @ t is zero 
 +//   res = SUB t, ra   @ res is zero ra 
 +def : Pat<​(inot IntRegs:​$ra),​ (SUB (EOR IntRegs:​$ra,​ IntRegs:​$ra),​ IntRegs:​$ra)>;​ 
 +</​code>​
  
-==== Relația de dominare imediată ==== +Clasa **Pat** extinde clasa **Pattern** și ne permite să definim pattern-uri într-un mod mai simplu. In versiunea de LLVM 3.6, aceasta clasa este definita ca:  
-Nodul a este în relație de **dominare imediată (a idom b)** ''​dacă ​și numai dacă''​+<​code>​ 
-//pentru ''​a != b''​''​a idom b <=a dom b''​ și nu există ''​c''​ astfel încât ''​c != a''​ și ''​c != b''​ și ''​a dom c''​ și ''​c dom b''​//. + class Pat<dag patterndag result> : Pattern<pattern, [result]>
-Există un singur ​**dominator imediat** pentru fiecare nod; îl vom nota cu **idom (nod)**. Relația de //dominare imediată// formează ​un arbore cu nodurile CFG-ului a rui rădăcină este nodul //entry// și ale rui arcuri reprezintă relații de //dominare imediată//. Drumurile în acest arbore arată toate relațiile de dominare din CFG (vezi figura de mai sus).+</code> 
 +**Calling convention**-ul se definește tot prin intermediul fișierelor ​**.td**. Calling convention-ul este un contract prin intermediul ​ruia se specifică modalitatea de transmitere a parametrilor ​tre funcții și întoarcerea rezultatelor ​de către acestea ​(folosind registre, stiva sau ambele). 
  
-==== Relația de post-dominare ==== +Se pot defini mai multe calling convention-uri, folosing clasa **CallingConvention**. Această clasă primește ca parametru o listă de acținui ​(**CCAction**) care este folosită pentru a determina modul de transmitere a parametrilor
-Nodul i **post-domină** nodul p (**p pdom i**) dacă orice drum posibil ​de la nodul //i// la nodul //exit// include nodul //p//. +
-{{ :​cpl:​labs:​laborator-08-post-dominare.jpeg? |p pdom i}}+
  
-==== Arbori de dominare ​și post-dominare ==== +Pentru lista tuturor acțiunilor,​ inspectați fișierul **include/​llvm/​Target/​TargetCallingConv.td**. Mai jos sunt prezentate câteva din cele mai comune acțiuni, din acest fișier. 
-Setul de dominatori pentru funcția fib: +<​code>​ 
-^ Nodul i ^ Domin(i) ^ +/// CCIfType - If the current argument is one of the specified typesapply 
-| entry | {entry} | +/// Action A. 
-| B1 | {entry,B1} | +class CCIfType<​list<​ValueType>​ vtsCCAction A> : CCPredicateAction<​A> ​
-| B2 | {entry,​B1,​B2} | +  ​list<​ValueType>​ VTs = vts; 
-| B3 | {entry,B1,B3} | +}
-| B4 | {entry,​B1,​B3,​B4} | +
-| B5 | {entry,​B1,​B3,​B4,​B5} | +
-| B6 | {entry,​B1,​B3,​B4,​B6} | +
-| exit | {entry,​B1,​exit|+
  
-**Arborii de dominare(graf si LLVM IR)** pentru programul Fibanacci+/// CCPromoteToType - If applied, this promotes the specified current value to 
-{{:​cpl:​labs:​laborator-08-fibonacci-domination-2.gif?​|Arbore de dominare pentru fib()}} +/// the specified type
-{{:​cpl:​labs:​laborator-08-fibodom.png?​|Arbore de dominare pentru fib() LLVM IR}}+class CCPromoteToType<​ValueType destTy> : CCAction ​
 +  ​ValueType DestTy = destTy; 
 +}
  
-**Arborele de postdominare** pentru programul Fibanacci+/// CCAssignToReg - This action matches if there is a register in the specified 
-{{:​cpl:​labs:​laborator-08-fibopostdom.png?|Arbore de postdominare pentru fib()}} +/// list that is still available If so, it assigns the value to the first 
-===== Bucle naturale și componente tare conexe =====+/// available register and succeeds
 +class CCAssignToReg<​list<​Register>​ regList> : CCAction { 
 +  list<​Register>​ RegList ​regList; 
 +}
  
-==== Arc înapoi ==== +/// CCAssignToStack ​This action always matches: it assigns the value to a 
-Un **arc înapoi** în CFG este //un arc a cărui destinatie este întalnită înaintea nodului sursă intr-o parcurgere DFS//. +/// stack slot of the specified size and alignment on the stack If size is 
-{{ :​cpl:​labs:​laborator-08-arc-inapoi.jpeg? |Arc înapoi}}+/// zero then the ABI size is used; if align is zero then the ABI alignment 
 +/// is used these may depend on the target or subtarget. 
 +class CCAssignToStack<​int size, int align> : CCAction { 
 +  int Size = size; 
 +  int Align = align; 
 +} 
 +</​code>​
  
-==== Buclă naturală ==== +Este important de menționat că determinarea modului ​de transmitere a unui parametru se face parcurgând lista până la prima acțiune de assign ​care se execută.
-**Buclă naturală** determinată de **arcul înapoi ''​v->​u''​** este definită ca fiind subgraful definit prin: +
-  * mulțimea de noduri - formată din nodul u și toate nodurile din care poate fi atins nodul v fără a trece prin u +
-  * mulțimea de arce - toate arcele conectând nodurile din mulțime.+
  
-**Atenție!** ​Pentru a avea buclă naturală ''​u dom v''​ și, deci, nu există noduri din care v poate fi atins fără a trece prin u și care să nu fie la rândul lor dominate de u. Astfel, nodul u este **header**-ul buclei. +Pentru a defini un calling convention ​care primește toțparametrii pe stivăputem folosi:
-{{ :cpl:​labs:​laborator-08-bucla-naturala.jpeg?​ |Buclă naturală}}+
  
-<note>O buclă naturală este o [[http://en.wikipedia.org/​wiki/​Strongly_connected_component|componentă tare conexă]] cu o singură intrare.</note>+<code> 
 +def CC_Stack : CallingConv<​[ 
 +  ​// Promote values to i32 
 +  CCIfType<​[i1,​ i8, i16], CCPromoteToType<i32>>,
  
-==== Introducerea nodului PRE-HEADER ==== +  // Use the stack (always works) 
-Multe optimizari constau în mutarea codului din interiorul buclei imediat înaintea header-ului buclei. Pentru a garanta că avem un astfel de loc disponibilintroducem conceptul de **pre-header**,​ care este **un nou basic block, inițal gol, plasat imediat înaintea header-ului buclei**. Astfel, toate arcele care înainte intrau în header, venind din afara buclei, acum vor intra în pre-header. În plus, există un singur arc de la pre-header la header. Figura de mai jos arată rezultatul introducerii unui pre-header pentru o buclă.+  ​CCAsignToStack<​00> 
 +]>; 
 +</​code>​
  
-^ Înainte ​de adăugarea nodului de preheader ^ După adăugarea nodului de preheader ^ +===== Setul de instrucțiuni ===== 
-| {{:​cpl:​labs:​laborator-08-bucla-fara-preheader.gif?​|Înainte de adăugarea nodului ​de preheader}}| {{:​cpl:​labs:​laborator-08-bucla-cu-preheader.gif?|După adăugarea nodului de preheader}} |+În cadrul acestui ​laborator ​se va folosi o arhitectură care definește un subset al instrucțiunilor ​de **ARMv3**.
  
-==== Bucle imbricate ==== +Arhitectura dispune ​de un set de 16 registre de 32 biți (R0-R15) și un registru ​de stare (CPSR). Registrele R13-R15 sunt rezervate pentru stack pointer SP (R13), link register LR (R14) și program counter PC (R15). 
-Nu este greu de observat că dacă două bucle au header-e diferite, ele sunt fie **disjuncte**,​ fie **imbricate**. Pe de altă parte, dacă două bucle au acelașheader ​(ca în cazul din figura ​de mai jos), nu este foarte clar dacă una este imbricată în cealaltă ​(și care este imbricată în caresau dacă ele formeaza împreună o singură buclă. +
-{{ :​cpl:​labs:​laborator-08-bucla-dubla.gif? |Bucle cu header comun}}+
  
-Pornind ​de la faptul ca, fără mai multe detalii despre codul sursa, nu se poate distinge între aceste două situații, astfel ​de cazuri vor fi tratate ca fiind o singură buclă (există o modalitate ​de analiză a fluxului ​de control denumită **analiză structurală** care poate face acestă distincție).+Registrul ​de stare este scris de către instrucțiunile ​de comparație și citit de către instrucțiunile ​de salt condiționat.
  
-==== Regiuni improprii ====+Setul de instrucțiuni cuprinde: ​
  
-O buclă naturală este doar un tip particular de componentă tare conexă. În practică, deși rarpot apărea și alte structuri de tip buclă cu mai multe puncte de intrare (în special în programele nestructurate). Deși asemenea structuri sunt rarefaptul că ele totuși apar, ne obligă să le luăm în considerare. Cea mai generală structură de tip buclă care poate să apară este o componentă tare conexă a CFG-ului.+^ Tip ^ Sintaxă ^ Efect ^ 
 +| ALU | add rdrs1rs2 | rd = rs1 + rs2 | 
 +| ::: | add rdrs1i8 | rd = rs1 + i8 | 
 +| ::: | sub rd, rs1, rs2 | rd = rs1 - rs2 | 
 +| ::: | sub rd, rs1, i8 | rd = rs1 - i8 | 
 +| ::: | mul rd, rs1, rs2 | rd = rs1 * rs2 | 
 +| ::: | 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 | 
 +| ::: | mul rd, rs1, rs2 | rd = rs1 * rs2 | 
 +| Transfer | mov rd, rs | rd = rs | 
 +| ::: | mvn rd, rs | rd = NOT rs | 
 +| 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 | 
 +===== Compilare și rulare ===== 
 +Următoarele pachete sunt necesare: 
 +<​code>​ 
 +gcc-arm-linux-gnueabi # cross compiler ​de arm 
 +libc-dev-armel-cross # embedded GNU C library pentru cross-compiling 
 +qemu-user # pt qemu-arm 
 +android-tools-adb # adb 
 +openjdk-7-jre # sau alta varianta de java 
 +lib32z1 lib32ncurses5 lib32stdc++6 # lib-uri pe 32 de biti (daca e cazul) 
 +</​code>​
  
-CFG-ul este **bine-structurat** dacă acesta conține **doar** bucle naturale. +De asemenea, este necesar [[http://dl.google.com/android/android-sdk_r24.4.1-linux.tgz|SDK-ul ​de Android]]. 
-Formalun CFG ''​G=<​N,​E>'' ​este **bine-structurat** dacă mulțimea arcelor poate fi partitionată în două mulțimi: +Acesta trebuie dezarhivatiar calea către directorul obținut în urma dezarhivării trebuie setată în cadrul variabilei ​de mediu ANDROID_SDK_ROOT
-  * mulțimea arcelor înainte - acele arce care formează un graf aciclic orientat (DAG) în care fiecare nod poate fi atins din nodul //entry// +De asemenea trebuie adăugată în PATH calea către directorul $ANDROID_SDK_ROOT/​tools.
-  * multimea arcelor înapoi ​acele arce care sunt conforme cu definiția ​de mai susadică nodul destinație domină nodul sursă +
-Anumite șabloane de flux de control pot face un CFG prost-structurat. Astfel de sabloane se numesc regiuni improprii și în general sunt componente tare conexe cu mai multe intări. Un exemplu ​de regiune improprie este dat și în figura de mai jos (stanga)+
-^ Regiune improprie ^ După "​node-splitting"​ ^ +
-| {{:​cpl:​labs:​laborator-08-regiune-improrie.gif?​|Regiune improprie}} | {{:​cpl:​labs:​laborator-08-regiune-improrie-reparata.gif?​|După "​node-splitting"​}} |+
  
-Regiunile improprii sunt un impediment în special în analiza fluxului de date. Există mai multe metode de trata problema regiunilor improprii dintr-un CFG dintre care menționăm+==== Device pentru android ==== 
-  * **analiza iterativă** a fluxului de date +Pentru ​instala doar target-ul necesar
-  * **node-splitting** pentru transformarea unui CFG ireductibil într-unul reductibil ​ +<​code>​ 
-(vezi exemplul de mai sus (figura din dreapta) în care tehnica a fost aplicată pentru nodul B3).+# Recomandam instalarea celor cu API 22 
 +android list sdk
  
-===== Opțional ​de citit =====+android update sdk --no-ui --filter 4,​25,​38,​tool,​platform-tool 
 +# Numerele pot diferi in functie ​de output-ul comenzii de mai sus. In cazul nostru: 
 +# 4 - SDK Platform Android 5.1.1, API 22, revision 2 
 +# 25 - Google APIs, Android API 22, revision 1 
 +# 38 - Google APIs ARM EABI v7a System Image, Google Inc. API 22, revision 1
  
-* Basic Blocks and Flow Graphs, p528, [[http://​en.wikipedia.org/​wiki/​Compilers:​_Principles,​_Techniques,​_and_Tools|Dragon book]], 2nd edition +android list targets
-* [[http://​en.wikipedia.org/​wiki/​Control_flow_analysis|Analiza fluxului de control]]+
  
-====== Exerciții de laborator (11p) =======+android create avd -n myandroid22 \ 
 +    -t "​Google Inc.:Google APIs:​22"​ \ 
 +    --abi google_apis/​armeabi-v7a 
 +</​code>​
  
-===== Exercițiul 1 hands-onpe foaie (2p) =====+==== Compilare ​==== 
 +Pentru a compila un fișer ''​C''​ vom folosi cross-compiler-ul de ARM ''​arm-linux-gnueabi-gcc''​. 
 +<note important>​ 
 +Pentru temă vom genera cod pentru ARM v3. 
 +Datorită unui bug în gccvom rula cu opțiunea ''​-march=armv4''​. 
 +</​note>​ 
 +Opțiunile sunt similare cu cele date pentru gcc. 
 +Arhitectura dorită va fi specificată cu ''​-march=armv4''​.
  
-Pentru ​următorul CFG: +Pentru ​a obține asamblarea, folosiți ''​-S''​.
-{{ :​cpl:​labs:​laborator-08-bucle.jpeg?​ |CFG}} +
-  * găsiți arcele inapoi +
-  * găsiți nodurile dominate de basic blockurile 2 și 4. +
-  * desenați arborele de dominare +
-  * determinați nodurile de tip branch și cele de tip join +
-  * găsiți buclele naturale și nenaturale +
-  * găsiți buclele imbricate +
-===== Exercițiul 2 - no loops (1p) ===== +
-Este posibil ca o funcție care conține unul din cuvintele cheie ''​for/​while/​do while'' ​să nu conțină bucle? Dacă da, în ce condiții ?+
  
-Scrieți o funcție în C și desenați CFG-ul corespunzător ​folosind ​toolchain-ul LLVM. +Pentru a putea rula executabilele generate ​folosind ​emulatoarele,​ trebuie ca acestea să fie link-ate static ​(prin transmiterea opțiunii ''​-static'' ​către ''​arm-linux-gnueabi-gcc''​)
-===== Exercițiul 3 - no for/​while/​do while (1p) ===== +
-Dați exemplu de o funcție care nu conține cuvintele cheie ''​for/​while/​do while''​, dar conține bucle în CFG.+
  
-Scrieți o funcție în C și desenați CFG-ul corespunzător folosind toolchain-ul LLVM. +==== Emulare ​===
-===== Exercițiul 4 - goto (1p) ===== +Pentru testare, vom folosi emulatorul de Android și qemu. 
-Dați exemplu ​de o funcție care nu conține ''​for/while/do while''​, conține maxim o instrucțiune ​''​goto''​ și are o buclă nenaturală.+=== Emulatorul de Android ​=== 
 +<​code>​ 
 +emulator -avd myandroid22 & # porniti emulatorul ​de android 
 +adb push binar /data/binar  # copiati binarul pe device 
 +adb shell /​data/​binar ​      # rulati binarul 
 +</​code>​ 
 +Pentru a putea rula aceste comenzi, trebuie adăugată în ''​PATH'' ​calea către directorul ​''​$ANDROID_SDK_ROOT/​tools''​. 
 +În cazul în care se folosește un sistem de operare pe 32 biți, este nevoie de forțarea folosirii binarelor pe 32 de biți prin exportarea variabilei de mediu ANDROID_EMULATOR_FORCE_32BIT=true. 
 +=== Qemu === 
 +<​code>​ 
 +qemu-arm binar              # rulati binarul 
 +</​code>​
  
-Scrieți o funcție în C și desenați CFG-ul corespunzător folosind toolchain-ul LLVM. +===== Exerciții ===== 
-===== Exercițiul 5 - transform (3p) ===== +{{:​cpl:​labs:​lab07.zip|Arhiva}} laboratorului. 
-Transformați următoarea regiune improprie într-o buclă naturală plecând de la următorul cod : +==== Exercițiul ​1 ==== 
-{{ :cpl:labs:laborator-08-exsplit.png? |Exemplu de split]}} +Scrieți un program ''​C''​ care printează ''"​Hello World!"''​. Compilați programul și obțineți fișierul .s. Asamblați și link-ați fișierul pentru a obține un fișier ELF. Rulați ELF-ul folosind cele emulatoare ​(Android și qemu). 
-<code cpp> +==== Exercițiul 2 ==== 
-int f (int x, int y) { +Completați funcția ''​sum''​ din fișierul **ex2.s** pentru a întoarce suma elementelor vectorului dat ca parametru. Adresa vectorului este transmisă prin registrul ''​R0'',​ iar numărul elementelor este transmis prin registrul ''​R1''​. Rezultatul trebuie intors prin registrul ''​R0''​. Link-ați **ex2.s** împreună cu **ex2.c** și rulați executabilul.<note important>​ 
-    x x + 1+Funcția nu trebuie sa suprascrie niciun registru rezervat pentru program counter, ​return ​address și stack pointer. 
-    switch(y) { +</note> 
-    case 2: +==== Exercițiul 3 ==== 
-        do +Copiați directorul cpl din arhiva în directorul lib/Target al dristribuției de LLVM de mașinile din laborator. 
-        { +Înregistrați target-ul Cpl în cadrul framework-ului de LLVM. 
-        L2: +După ce ați modificat toate fișierele, compilați **llc** cu suport pentru noul target:
-            x - 2+
-            if (x > 0goto L4; +
-    case 3: +
-            x x * 3; +
-            if (x <6) { +
-                x -5; +
-            } +
-            else { +
-    default: +
-        L4: +
-                x <<4; +
-                if (x !16) goto L2; +
-                x y + 6; +
-            } +
-            y x + 7; +
-        } while(y ​x); +
-    } +
-    return ​x; +
-}</code+
  
-===== Exercițiul ​LLVM pass (3p) =====+   cd ~/​packages/​llvm-3.8.0/​build 
 +   cmake -DLLVM_TARGETS_TO_BUILD=Cpl path_to_llvm_src 
 +   make -j2 llc 
 +    
 +Codul sursa LLVM poate fi descărcat de pe [[http://​llvm.org/​releases/​3.6.0/​llvm-3.6.0.src.tar.xz|llvm.org]] 
 +    
 +Pentru a testa, compilați fișierul ex3.a.ll folosind opțiunea ''​-filetype=null''​ pentru llc. 
 +<note warning>​ 
 +Compilarea llc va dura în jur de 20 minute. 
 +</​note>​ 
 +==== Exercițiul ​4 ==== 
 +Completați în target-ul de Cpl pentru a genera cod pentru următoarele funcții echivalente în ''​C''​. 
 +Funcțiile se află în fișierele ''​ex4_<​no>​.ll''​. 
 +=== ==
 +Va trebui să implementați funcția ''​CplInstPrinter::​printOperand''​. 
 +<​code>​ 
 +void f() {} 
 +</​code>​
  
-Scrieți un LLVM pass pentru ​a afișa: +=== ident === 
-  ​* toate basic block-urile unui program +Va trebui să completați fisierul ''​CplCallingConv.td''​ 
-  * pentru fiecare basic-block:​ +<​code>​ 
-    * basic block-urile predecesoare +int ident(int a) { 
-    * basic block-urile următoare+  return a; 
 +
 +</​code>​ 
 + 
 +=== or === 
 +Va trebui să adăugați instructiunea ''​or''​ în fișierul ''​CplInstrInfo.td''​ și un pattern ​pentru ​nodul ''​or''​ în fișierul ''​CplPatterns.td''​ 
 +<​code>​ 
 +int or(int ​a, int b) { 
 +  ​return a | b; 
 +} 
 +</​code>​ 
 + 
 +=== second === 
 +Va trebui să implementați funcția ''​CplInstrInfo::​copyPhysReg''​. 
 +<​code>​ 
 +int second(int a, int b) { 
 +  return b; 
 +
 +</​code>​
  
  
-Detalii despre [[http://​ocw.cs.pub.ro/​courses/​cpl/​labs/​llvm-pass|LLVM passes]]. 
cpl/labs/08.1448289515.txt.gz · Last modified: 2015/11/23 16:38 by laura.vasilescu
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