Prezentare generală a conductei extinse de compilare a GCC, inclusiv programe specializate precum preprocesorul, asamblorul și linker-ul.
GCC urmează arhitectura în 3 etape tipică compilatoarelor cu mai multe limbi și multi-CPU. Toți arborii de programe sunt convertiți într-o reprezentare abstractă comună la „capătul de mijloc”, permițând optimizarea codului și facilitățile de generare a codului binar să fie partajate de toate limbile.,
interfața externă a GCC urmează convențiile Unix. Utilizatorii invoca un limbaj specific driver program (gcc
pentru C, g++
pentru C++, etc.), care interpretează argumentele de comandă, apelează compilatorul propriu-zis, rulează asamblorul pe ieșire și apoi rulează opțional linker-ul pentru a produce un binar executabil complet.fiecare dintre compilatoare de limbă este un program separat care citește codul sursă și codul mașinii ieșiri. Toate au o structură internă comună., Un front-end per limbă analizează codul sursă în acea limbă și produce un arbore de sintaxă abstractă („copac” pentru scurt).
acestea sunt, dacă este necesar, convertite în reprezentarea de intrare a capătului de mijloc, numită formă generică; capătul de mijloc transformă apoi treptat programul spre forma sa finală. Optimizările compilatorului și tehnicile de analiză statică a codului (cum ar fi FORTIFY_SOURCE, o directivă a compilatorului care încearcă să descopere unele depășiri tampon) sunt aplicate codului., Acestea funcționează pe mai multe reprezentări, mai ales reprezentarea GIMPLE independentă de arhitectură și reprezentarea RTL dependentă de arhitectură. În cele din urmă, codul mașinii este produs folosind potrivirea modelului specific arhitecturii bazată inițial pe un algoritm al lui Jack Davidson și Chris Fraser.
GCC a fost scris în principal în C, cu excepția unor părți ale front-end Ada. Distribuția include bibliotecile standard pentru Ada, C++ și Java al căror cod este scris în mare parte în acele limbi., Pe unele platforme, distribuția include, de asemenea, un nivel scăzut runtime library, libgcc, scrise într-o combinație de mașină-independent C și procesor specifice cod mașină, destinate în primul rând să se ocupe de operații aritmetice că ținta procesor nu poate efectua în mod direct.GCC folosește multe instrumente standard în construcția sa, inclusiv Perl, Flex, Bison și alte instrumente comune. În plus, în prezent este nevoie de trei biblioteci suplimentare pentru a fi prezente pentru a construi: GMP, MPC și MPFR.în mai 2010, Comitetul director al CCG a decis să permită utilizarea unui compilator C++ pentru a compila CCG., Compilatorul a fost destinat să fie scris mai ales în C plus un subset de caracteristici din c++. În special, acest lucru a fost decis astfel încât dezvoltatorii GCC să poată folosi caracteristicile distructive și generice ale c++.în August 2012, Comitetul director al CCG a anunțat că CCG utilizează acum C++ ca limbaj de implementare. Aceasta înseamnă că pentru a construi GCC din surse, este necesar un compilator C++ care înțelege standardul ISO / IEC C++03.,
Fata endsEdit
Fata se termină consta de preprocesare, analiza lexicală, analiza sintactică (parsarea) și analiza semantică. Obiectivele de compilator capetele frontale sunt pentru a accepta sau respinge candidatul programe în funcție de limba gramatica și semantica, pentru a identifica erorile și mâner valabil program de reprezentări pentru mai târziu compiler etape. Acest exemplu arată pașii lexer și parser efectuate pentru un program simplu scris în C.,fiecare front-end folosește un parser pentru a produce arborele de sintaxă abstract al unui fișier sursă dat. Datorită abstractizării arborelui de sintaxă, fișierele sursă ale oricăreia dintre diferitele limbi acceptate pot fi procesate de același capăt din spate. GCC a început să folosească PARSERE LALR generate cu Bison, dar a trecut treptat la parsere recursive-coborâre scrise manual pentru C++ în 2004 și pentru C și Objective-C în 2006. Începând cu 2021, toate capetele frontale folosesc parsere recursive de coborâre scrise manual.
până la CCG 4.,0 reprezentarea arborescentă a programului nu a fost complet independentă de procesorul vizat. Semnificația unui copac a fost oarecum diferită pentru capetele frontale ale diferitelor limbi, iar capetele frontale ar putea oferi propriile coduri de copac. Acest lucru a fost simplificat odată cu introducerea GENERIC și GIMPLE, două noi forme de copaci independenți de limbă care au fost introduse odată cu apariția GCC 4.0. GENERIC este mai complex, bazat pe GCC 3.reprezentarea intermediară X Java front end. GIMPLE este un GENERIC simplificat, în care diferite construcții sunt reduse la mai multe instrucțiuni GIMPLE., Capetele frontale C, C++ și Java produc GENERIC direct în partea frontală. Alte capete frontale au în schimb reprezentări intermediare diferite după parsare și le transformă în generice.
în ambele cazuri, așa-numitul „gimplifier” convertește apoi această formă mai complexă în forma simplă GIMPLE bazată pe SSA, care este limbajul comun pentru un număr mare de optimizări globale (function scope) independente de limbă și arhitectură.,
GENERIC și GIMPLEEdit
GENERIC este un limbaj de reprezentare intermediar folosit ca un” capăt de mijloc ” în timp ce compilarea codului sursă în binare executabile. Un subset, numit GIMPLE, este vizat de toate capetele frontale ale GCC.
etapa de mijloc a GCC face toate analiza de cod și de optimizare, de lucru independent de ambele limbaj compilat și arhitectura țintă, pornind de la reprezentarea generică și extinderea acesteia pentru a înregistra transfer language (RTL)., Reprezentarea generică conține doar subsetul construcțiilor de programare imperative optimizate până la capătul Mijlociu.
în transformarea codului sursă în GIMPLE, expresiile complexe sunt împărțite într-un cod cu trei adrese folosind variabile temporare. Această reprezentare a fost inspirată de reprezentarea simplă propusă în compilatorul McCAT de Laurie J. Hendren pentru simplificarea analizei și optimizarea programelor imperative.,
OptimizationEdit
Optimizarea poate apărea în orice fază a compilării; cu toate acestea, cea mai mare parte de optimizări sunt efectuate după sintaxă și semantică, analiza de front-end și înainte de generarea de cod de back-end; astfel, o comună, chiar dacă oarecum contradictorii, nume pentru această parte a compiler este „middle end.”
setul exact de GCC optimizări variază de la ediție la ediție se dezvoltă, dar include algoritmi standard, cum ar fi bucla de optimizare, sari filetare, comune-ului subexpresie eliminare, instrucțiuni de programare, și așa mai departe., Optimizările RTL au o importanță mai mică prin adăugarea optimizărilor globale bazate pe SSA pe arbori GIMPLE, deoarece optimizările RTL au un domeniu de aplicare mult mai limitat și au mai puține informații la nivel înalt.unele dintre aceste optimizări efectuate la acest nivel includ eliminarea codului mort, eliminarea redundanței parțiale, numerotarea valorii globale, propagarea constantă condiționată redusă și înlocuirea scalară a agregatelor. De asemenea, sunt efectuate optimizări bazate pe dependența de matrice, cum ar fi vectorizarea automată și paralelizarea automată. Optimizarea ghidată de profil este, de asemenea, posibilă.,
Back endEdit
back end-ul GCC este specificat parțial de macro-urile și funcțiile preprocesorului specifice unei arhitecturi țintă, de exemplu pentru a defini endianitatea, dimensiunea cuvântului și convențiile de apelare., Partea frontală a capătului din spate le folosește pentru a decide generarea RTL, astfel încât, deși RTL-ul GCC este nominal independent de procesor, secvența inițială a instrucțiunilor abstracte este deja adaptată la țintă. În orice moment, instrucțiunile RTL reale care formează reprezentarea programului trebuie să respecte Descrierea mașinii a arhitecturii țintă.
fișierul Descriere mașină conține modele RTL, împreună cu constrângeri operand, și fragmente de cod pentru a scoate ansamblul final., Constrângerile indică faptul că un anumit model RTL s-ar putea aplica numai (de exemplu) anumitor registre hardware sau (de exemplu) să permită compensări imediate ale operandului de o dimensiune limitată (de exemplu, 12, 16, 24, … compensări de biți etc.). În timpul generării RTL, sunt verificate constrângerile pentru arhitectura țintă dată. Pentru a emite un fragment dat de RTL, acesta trebuie să se potrivească cu unul (sau mai multe) dintre modelele RTL din fișierul Descriere mașină și să satisfacă constrângerile pentru acel model; în caz contrar, ar fi imposibil să convertiți RTL-ul final în cod mașină.,spre sfârșitul compilării, RTL valid este redus la o formă strictă în care fiecare instrucțiune se referă la registrele reale ale mașinilor și la un model din fișierul de descriere a mașinii țintă. Formarea RTL strictă este o sarcină complicată; un pas important este alocarea registrului, unde registrele hardware reale sunt alese pentru a înlocui pseudo-registrele atribuite inițial. Aceasta este urmată de o „reîncărcare” faza; orice pseudo-registre care nu au fost atribuite un hardware real registru sunt ‘varsat’ în stivă, și RTL pentru a efectua această deversând este generat., De asemenea, compensările care sunt prea mari pentru a se încadra într-o instrucțiune reală trebuie să fie rupte și înlocuite cu secvențe RTL care vor respecta constrângerile compensate.
în faza finală, codul mașinii este construit apelând un mic fragment de cod, asociat cu fiecare model, pentru a genera instrucțiunile reale din setul de instrucțiuni al țintei, folosind registrele finale, compensările și adresele alese în faza de reîncărcare. Fragmentul de generare a ansamblului poate fi doar un șir, caz în care se efectuează o simplă înlocuire a șirurilor de registre, compensări și/sau adrese în șir., Fragmentul de generare de asamblare poate fi, de asemenea, un bloc scurt de cod C, efectuând unele lucrări suplimentare, dar în cele din urmă returnând un șir care conține codul de asamblare valid.
alte featuresEdit
unele caracteristici ale GCC includ:
- optimizare Link-time optimizează peste limitele fișier obiect pentru a îmbunătăți direct binar legat. Optimizarea Link-time se bazează pe un fișier intermediar care conține serializarea unor reprezentări Gimple incluse în fișierul obiect. Fișierul este generat alături de fișierul obiect în timpul compilării sursei., Fiecare compilație sursă generează un fișier obiect separat și link-time fișier helper. Când fișierele obiect sunt legate, compilatorul este executat din nou și utilizează fișierele helper pentru a optimiza codul în fișierele obiect compilate separat.
- pluginurile pot extinde direct compilatorul GCC. Plugin-uri permit un compilator stoc pentru a fi adaptate la nevoile specifice de cod extern încărcat ca plugin-uri. De exemplu, pluginurile pot adăuga, înlocui sau chiar elimina treceri de mijloc care funcționează pe reprezentări Gimple., Mai multe plugin-uri GCC au fost deja publicate, în special plugin-ul GCC Python, care leagă împotriva libpython, și permite să invoce script-uri Python arbitrare din interiorul compilatorului. Scopul este de a permite ca pluginurile GCC să fie scrise în Python. Pluginul MELT oferă un limbaj Lisp la nivel înalt pentru a extinde GCC.
- c++ memorie tranzacțională la compilarea cu-fgnu-tm.
- începând cu GCC 10, identificatorii permit codarea UTF-8 (Unicode), adică codul sursă C utilizează codarea UTF-8 în mod implicit.