• No results found

Registerallokering med PBQP f¨or en DSP

N/A
N/A
Protected

Academic year: 2021

Share "Registerallokering med PBQP f¨or en DSP"

Copied!
35
0
0

Loading.... (view fulltext now)

Full text

(1)

Registerallokering med PBQP f¨ or en DSP

Register allocation with PBQP for a DSP

Jakob Steng˚ard

Examensarbete inom information- och programvarusystem, grundniv˚a, 15 hp

Degree Project in Information and Software Systems, First Level

2 september 2011

KTH ICT, Ericsson AB Kurs: II121X, 15hp

(2)

Sammanfattning

Irregulj¨ara arkitekturer, s˚a som Digitala Signal Processorer, utg¨or nya ut- maningar vid konstruktionen av kompilatorer. I det h¨ar projektet unders¨oks PBQP, en alternativ algoritm till den traditionella grafallokeringen som ger st¨orre m¨ojligheter att modellera komplexa begr¨ansningar. Projektet har fokuserat p˚a hur man modellerar alias och parrelationer i teorin, samt vad som finns implementerat i dagsl¨aget i kompilatorramverket LLVM. Det som framkommit ¨ar att st¨od f¨or par relationer saknas i LLVM i dagsl¨aget och d¨arf¨or ges n˚agra f¨orslag p˚a hur man skulle kunna g˚a till v¨aga f¨ora att im- plementera dessa.

Abstract

Irregular architectures, such as Digital Signal Processors, constitute new challenges in the construction of compilers. This project has focused on studies of PBQP, which is an alternative algorithm to the traditional graph coloring approach to register allocation. PBQP enables more sophisticated control over the choices of registers, by means of more fine grained mod- elling of constraints. This report describes how to model alias and pairing constraints and some of the features currently available in the LLVM compil- er framework. It’s concluded that support for pairing constraints is not yet implemented in LLVM, and therefore a few suggestions on how one would go about to implement this is also given.

(3)

Inneh˚ all

1 Introduktion 3

1.1 Syfte . . . 4

1.2 Metod . . . 4

1.3 Uppl¨agg . . . 4

1.4 F¨orkortnings f¨orteckning . . . 5

1.5 Introduktion till DSPer . . . 6

1.6 N˚agra facktermer inom kompilatorteknik . . . 7

1.7 Kompilatorstruktur . . . 8

1.8 Registeralias och registerpar . . . 9

2 PBQP i teorin 11 2.1 Matematisk beskrivning . . . 11

2.2 Exempel vid registerallokering . . . 12

2.2.1 Ett mer avancerat exempel . . . 14

2.2.2 Hur man modellerar alias och par . . . 14

2.3 En l¨osningsalgoritm . . . 17

2.3.1 F¨argbarhet . . . 18

2.3.2 Branch-and-Bound . . . 18

3 Praktisk till¨ampning i LLVM 20 3.1 Om LLVM . . . 20

3.2 Upps¨attningen . . . 20

3.3 Kodbasen . . . 21

3.4 Skillnaden mellan PBQP och klassisk grafallokering . . . 21

3.5 Den nuvarande implementationen . . . 23

3.6 M¨ojligheter att implementera st¨od f¨or registerpar . . . 23

3.7 Utveckling och underh˚all . . . 25

3.A Pseudokod . . . 25

4 Resultat 30 4.1 Slutsatser . . . 30

4.2 Diskussion . . . 31

4.3 Framtida arbete . . . 31

(4)

F¨ orord

Detta ¨ar resultatet av ett 9,5 veckor l˚angt examensarbete jag genomf¨ort f¨or min kandidatexamen vid ICT-skolan p˚a KTH. Denna kandidatexamen g¨ors som en tre˚arig delexamen p˚a Civilingenj¨orsutbildningen i informations- teknik, vilket ¨ar det utbildningsprogram jag l¨aser. Jag har tidigare studerat

¨amnet kompilatorteknik, och n¨ar det blev dags att g¨ora examensarbete s˚a kontaktade jag min tidigare l¨arare inom kompilatorteknik som ocks˚a jobbar som examinator. Tillsammans med honom, hans kontakter, samt n˚agra gam- la kolleger som jag tr¨affat vid mina sommarjobb p˚a Ericsson lyckades vi till- slut styra upp detta projekt. Projektet g˚ar ut p˚a att unders¨oka m¨ojligheterna till att anv¨anda registerallokeringsalgoritmen PBQP vid kompilering av kod f¨or DSPer. Jag valde att arbeta i kompilatorramverket LLVM d˚a det ¨ar ett modernt ramverk, med st¨od f¨or bland annat PBQP algoritmen.

Registerallokering f¨or DSPer var ett ¨amne som min examinator g¨arna kunde t¨anka sig vilja se en v¨alskriven rapport i. Min chef vid Ericsson kunde ocks˚a godta detta som ett examensarbete d˚a den avdelning jag tidigare jobbat p˚a sysslar med att utveckla kompilatorer f¨or DSPer.

Jag vill h¨ar passa p˚a att tacka de personer som har hj¨alpt mig genom projektets g˚ang, n¨amligen mina handledare; Jonas Paulsson och Roberto Casta˜neda Lozano, samt min examinator Christian Schulte.

Jag vill ocks˚a tacka Per Gibson som hj¨alp till med allt det administrativa kring ans¨okningen och projektet.

Jakob Steng˚ard, 6:e juni 2011.

(5)

1. Introduktion

Notera: En referenslista f¨or f¨orkortningar kan hittas l¨angre ned i detta kapi- tel.

Registerallokering ¨ar den process i en kompilator d¨ar lokala variabler i det blivande programmet tilldelas fysiska register i processorn. Instruktionerna i en processor arbetar vanligen med data fr˚an register, ¨aven om det finns un- dantag. Eftersom antalet register oftast ¨ar litet i f¨orh˚allande till de data som skall behandlas r¨acker dessa register s¨allan till. Man blir d˚a tvungen att spara data i minnet f¨or att frig¨ora register och sedan ladda tillbaka dem n¨ar de ˚ater skall anv¨andas. Eftersom laddande och sparande till minnet ¨ar l˚angsamma operationer vill man naturligtvis minimera detta. Men det ¨ar inte alltid helt l¨att att v¨alja r¨att register som vi senare skall se. Registerallokering ¨ar ett v¨al studerat problem inom kompilatortekniken som vanligen l¨oses med sk.

grafallokering. Vid grafallokering abstraherar man problemet och g¨or om det till ett problem med att f¨argl¨agga noder i en sk.interferensgraf.

I det h¨ar projektet har jag tittat p˚a en alternativ algoritm till grafallokering baserad p˚a PBQP. PBQP har m˚anga likheter med grafallokering, men ger m¨ojligheter till en mer nyanserad kontroll ¨over vilka register som v¨aljs i oli- ka situationer. P˚a vanliga processorer spelar valet av register inte alltid s˚a stor roll. Dock finns det andra typer av processorarkitekturer sk. irregulj¨ara arkitekturer d¨ar det finns begr¨ansningar p˚a vilka register som kan anv¨andas till vad. P˚a dessa arkitekturer vill man kunna blockera t.ex. f¨orbjudna reg- isterkombinationer.

Det g˚ar att komma runt dessa problem ¨aven f¨or grafallokering, men detta involverar ofta speciall¨osningar f¨or varje enskilt fall. Grafallokering bygger i grunden p˚a antagandet att alla noder i grafen kan f¨argl¨aggas (tilldelas ett register), med vilken f¨arg som helst. Detta antagande ¨ar felaktigt f¨or irregulj¨ara arkitekturer. De l¨osningar som hitintills presenterats f¨or den h¨ar typen av problem har endast behandlat en liten delm¨angd av problemen. [1, s.147].

F¨or processorer d¨ar majoriteten av registren ¨ar generella spelar det ovanst˚aende liten roll och man kan bevisligen anv¨anda grafallokering med gott resultat.

(6)

Jag har h¨ar dock valt att fokusera p˚a en typ av processorer som vanligtvis bygger p˚a irregulj¨ara arkitekturer, n¨amligen DSPer. DSPer ¨ar en typ av processorer som anv¨ands f¨or signalbehandling.

PBQP ¨ar som tidigare antytts inte en algoritm i sig. PBQP st˚ar f¨or Parti- tioned Boolean Quadratic Problem och ¨ar en typ av NP-kompletta problem som kan l¨osas olika typer av reduktionsalgoritmer baserade p˚a heuristik.

Den algoritm som fr¨amst kommer att diskuteras i den h¨ar rapporten ¨ar den som beskrivs av Schoolz och Eckstein i artikeln Registerallocation for Ireg- ular Achitectures [1] samt de f¨orb¨attringar som beskrivs i Nearly Optimal Register Allocation with PBQP av Hames och Scholz [4].

LLVM ¨ar ett open-source kompilatorramverk d¨ar man kan v¨alja att anv¨anda bland annat PQBP f¨or register allokering.

1.1 Syfte

Syftet med projektet ¨ar att skapa bakgrundsmaterial f¨or en bed¨omning av PBQPs l¨amplighet som registerallokerare f¨or DSPer. Fokus i projektet har fr¨amst legat p˚a att ta reda p˚a PBQPs l¨amplighet f¨or anv¨andning f¨or DSPer, unders¨oka LLVMs nuvarande implementation och hur mycket jobb som skulle kr¨avas f¨or att anpassa den till att anv¨andas med en typisk DSP.

1.2 Metod

F¨or att genomf¨ora min unders¨okning inledde jag med en litteraturstudie d¨ar jag gick igenom den bakomliggande teorin. D¨ar efter har jag jobbat aktivt genom att l¨asa LLVM dokumentationen, st¨allt fr˚agor till LLVMs maillista och g˚att igenom k¨allkoden. Jag f¨ors¨okte sj¨alv g¨ora en egen implementation av registerpar i LLVM, men detta ins˚ag jag snart att jag inte skulle hinna med, s˚a det str¨oks.

1.3 Uppl¨ agg

Jag har i min redog¨orelse valt att ta upp f¨oljande aspekter:

• Principerna bakom PBQP.

• Anv¨andning av PBQP f¨or att l¨osa problem med registeralias.

• Anv¨andning av PBQP f¨or att l¨osa problem med registerpar.

• Kort genomg˚ang av en l¨osningsalgoritm f¨or PBQP.

(7)

• Utv¨ardering av en praktisk till¨ampning i en kompilator baserad p˚a LLVM.

Vi har nu g˚att igenom en kort introduktion till ¨amnet. Nedan f¨oljer lite bakgrundsinformation som l¨asaren b¨or k¨anna till. I kapitel 2 g˚ar vi igenom PBQP i teorin medan kapitel 3 fokuserar p˚a den praktiska till¨ampningen i LLVM. I kapitel 4 g¨ors en summering och resultaten presenteras.

1.4 F¨ orkortnings f¨ orteckning

• ALU

Arithmetic Logic Unit.

En enhet som utf¨or logiska aritmetiska operationer. T.ex. AND, OR eller addition och subtraktion.

• DSP

Digital Signal Processor.

En typ av processorer speciellt designade f¨or signalbehandlingsapp- likationer.

• FIR

Finite Impulse Response.

En typ av filter teknik som ¨ar ett vanligt anv¨andningsomr˚ade f¨or DSPer.

• GCC

GNU Compiler Collection.

En samling av kompilatorer och bibliotek f¨or olika programmeringsspr˚ak.

• LLVM

Low Level Virtual Machine.

Ett open-source kompilatorramverk, men st¨od f¨or m˚anga moderna funktioner, t.ex. JIT-kompilering. [12]

• MAC

Multiply-Accumulate.

En teknik f¨or att r¨akna ut ut summan av produkter.

• PBQP

Partitioned Boolean Quadratic Problem (Programming). En register- allokeringsalgoritm.

• SVN Subversion.

Ett versionshanteringssystem f¨or k¨allkod.

(8)

• HRA

Heterogeneous Register Architecture.

Heterogena registerarkitekturer ¨ar arkitekturer med m˚anga sm˚a snab- ba register med specifika anv¨andningsomr˚aden.

• VLIW

Very Long Instruction Word.

En typ av arkitekturer d¨ar man anv¨ander extra l˚anga instruktioner vilket g¨or att man kan utf¨ora flera operationer p˚a samma klockslag.

[3, s. 710] VLIW anv¨ands ist¨allet f¨or schemal¨aggning av parallella in- struktioner i h˚ardvaran, vilket g¨ors p˚a de flesta generella processorer.

P˚a VLIW arkitekturer g¨ors ist¨allet schemal¨aggning i mjukvaran, d˚a vanligen i kompilatorn.

1.5 Introduktion till DSPer

DSPer anv¨ands i huvudsak till att applicera matematiska algoritmer p˚a digi- tal signaler, bla. i sk. realtidssystem d¨ar det finns strikta tidskrav. [10][s.393- 394]

Moderna DPSer g¨ors i dag med allt fler funktioner h¨amtade fr˚an vanliga generella processorer. DSPer brukade f¨orr i tiden programmeras manuellt med assembler, men idag st¨ods g¨ors detta allt mer med hj¨alp av h¨ogniv˚aspr˚ak.

[10][s.393]

Detta st¨allet f¨orst˚as nya krav p˚a kompilatorer f¨or dessa h¨ogniv˚aspr˚ak att generera bra maskinkod f¨or DSPer.

N˚agra exempel p˚a egenskaper hos DSPer som f¨orsv˚arar kompileringen ¨ar:

• Ej ortogonal instruktionsupps¨attning.

• Heterogen registerarkitektur (HRA).

• Mjukvarubaserad parallellisering (VLIW).

• Specialiserade instruktioner.

• Specialiserade adresserings moder och dedikerade adressgenereringsen- heter.

Att en instruktionsupps¨attning inte ¨ar ortogonal betyder att man inte kan adressera alla typer av data fr˚an alla instruktioner. Detta ¨ar vanligt p˚a DSPer, men existerar ¨aven p˚a andra processorer. Icke ortogonalitet skapar begr¨ansningar vid registerallokering [5, s.203].

Heterogena registerarkitekturer g¨or kompileringen mer komplex d˚a HRA skapar ett starkt beroende mellan valet av instruktioner och vilka register

(9)

som kan anv¨andas. [2, s. 149]

P˚a VLIW arkitekturer g¨ors schemal¨aggning av instruktioner oftast p˚a f¨orhand i kompilatorn. Detta g¨or h˚ardvaran enklare och mindre men kompilatorns jobb mer betungande.

Specialiserade instruktioner kan vara instruktioner f¨or specifika ¨andam˚al. P˚a m˚anga DSPer har man t.ex. en upps¨attning snabba multiplikationsinstruk- tioner, sk. multiply-accumulate (MAC) instruktioner. Dessa kan snabba upp till¨ampningar som t.ex. FIR filtrering [10][s. 394].

Man har ¨aven specifika instruktioner f¨or att snabba upp loopar.[10][s. 394].

P˚a vanliga processorer g¨ors ofta loopar med vanliga branch instruktioner som m˚aste utv¨arderas en g˚ang per iteration. Man anv¨ander tekniker som branch prediction f¨or att snabba upp dessa loopar. P˚a m˚anga DSPer har man i st¨allet special instruktioner som repeterar ett kod block ett givet antal g˚anger.

Specialiserade adresserings moder och dedikerade adress genererings enheter

¨

ar ocks˚a vanligt. T.ex. g¨ors adress aritmetik f¨or vissa data paths i separata ALUer.[10][s. 394-395]. En s˚adan ALU syns ofta som ett vanligt register sett ur programmeringssynpunkt. Man kan ¨aven t¨ankas ha instruktioner f¨or specifika till¨ampningar som involverar dessa ALUer. Vi kommer senare i rapporten att ta ett exempel p˚a ett problem som involverar adressregister och modifikationsregister.

Sammanlagt ¨ar detta n˚agra exempel p˚a saker som g¨or DSPer till komplicer- ade arkitekturer att kompilera effektiv kod f¨or. F¨or registerallokeringens del resulterar detta b.la. i att man f˚ar alias och par relationer i en st¨orre ut- str¨ackning ¨an vad som ¨ar vanligt p˚a generella processorer.

Alias och par beskrivs n¨armare senare i detta kapitel.

1.6 N˚ agra facktermer inom kompilatorteknik

• Virtuellt register

I kodgenereringsfasen i en kompilator l˚atsas man ofta att man har o¨andligt m˚anga register att tillg˚a. Man anv¨ander d˚a s˚a kallade virtuella register vilka ¨ar tempor¨ara p˚ahittade namn f¨or att referera till regis- ter. Vid registerallokeringen byts dessa sedan ut mot riktiga fysiska register.

• Live-range

Live-range eller livsl¨angd, ¨ar den period d˚a data i ett virtuellt register

¨

ar aktuellt och anv¨ands. Under denna tid ¨ar det bra om data som det

(10)

inneh˚aller kan placeras i ett riktigt register. Efter att livsl¨angden ¨ar slut ¨ar det fritt att skriva ¨over registrets inneh˚all.

• Live-in och Live-out

Man brukar s¨aga att virtuella register som redan ¨ar definierade vid starten p˚a ett kodblock ¨ar live-in f¨or det blocket. De som m˚aste vara definierade vid slutet av kodblocket ¨ar live-out.

• Interferens

N¨ar det finns en konflikt mellan tv˚a virtuella register brukar man s¨aga att de interfererar med varandra. En s˚adan konflikt beror vanligen p˚a att de ¨ar live samtidigt och inte kan allokeras till samma register.

[8][s. 219] Det finns dock andra typer av interferens, t.ex. beroende p˚a registerpar som n¨amns senare i kapitlet. Man brukar st¨alla upp sk.

interferensgrafer f¨or att kunna visualisera detta. D¨ar representeras de virtuella registren med noder, och b˚agarna indikerar olika typer av interferens.

• Coalescing

Coalescing eller sammanslagning, ¨ar n¨ar man sl˚ar ihop flera livsl¨angder till en. Detta g¨ors vid kopieringsinstruktioner d¨ar de tv˚a livsl¨angderna inte interfererar med varandra. Att sl˚a ihop livsl¨angder kan vara f¨ordelaktigt d˚a det minskar antalet livsl¨angder som allokeraren beh¨over behandla, och det eliminerar kopieringsinstruktionen [7][s. 5].

• Precolored registers

Precolored registers ¨ar speciella register som inte f˚ar ¨andas av regis- terallokeraren, de ¨ar allokerade i f¨orv¨ag.

• Spilling

Om inte alla virtuellregister som interfererar f˚ar plats i riktiga register blir man tvungen att spilla. Kompilatorn l¨agger d˚a till spillkod som sparar ut data till minnet s˚a att fler register blir lediga. Den h¨ar datan m˚aste sedan laddas in igen innan den kan anv¨andas.

• Colorability

Colorability eller f¨argbarhet ¨ar en term fr˚an grafallokeringen. Om en nod ¨ar f¨argbar kan man garantera att det virtuella register som noden representerar kommer att kunna bli allokerad ett fysiskt register. Om den inte ¨ar f¨argbar, betyder det att man blir tvungen att spilla den.

1.7 Kompilatorstruktur

En modern kompilator best˚ar normalt av ett ¨ovre lager, sk. front-end och ett undre lager. sk. back-end. I front-end analyserar man sj¨alva koden och

(11)

IR

Lexikalisk analys

Syntaxanalys

Intermediär kodgenerator

Maksinkodsoberoende kodoptimerare

Frontend

Kodgenerator

Maskinberoende kodoptimerare

Backend

Val av instruktioner Regsiterallokering och tilldelning

Omordning av instruktioner

Figur 1.1: Strukturen p˚a en vanlig kompilator, h¨arledd fr˚an beskrivningarna i booken Compilers: Principles, Techniques, and Tools. [3, s.5, 505-506]

genererar en intermedi¨ar representation (IR) av koden, samt en symbolta- bell. Front-end tar hand om att tolka det spr˚ak som kompilatorn skall kom- pilera. IR skickas sedan till back-end, d¨ar kod genereras f¨or en viss arkitektur eller sk. target baserat p˚a informationen i IR. Vissa kompilatorer g¨or ¨aven maskinberoende optimeringar p˚a IR mellan front-end och back-end.[3, s.5]

Detta ¨ar en modul¨ar struktur som g¨or att det finns m¨ojlighet att anv¨anda olika back-ends med samma front-end och tv¨art om. Med en tillr¨ackligt v¨aldefinerad intermedi¨ar representation, kan en kompilator f¨or spr˚aket i och arkitekturen j byggas genom att kombinera front-end f¨or spr˚aket i med back- end f¨or spr˚aket j. Detta tillv¨agag˚angs¨att f¨or att bygga kompilatorer kan spara mycket tid, m × n kompilatorer kan byggas genom att skriva endast m front-ends och n back-ends. [3, s. 357]

Registerallokering g¨ors som en del av kodgenereringen i back-end. Se figur 1.1

1.8 Registeralias och registerpar

N˚agra av de egenheter som man st¨oter p˚a i regulj¨ara arkitekturer ¨ar s˚a kallade registeralias och registerpar.

Tv˚a register kallas alias om dom har olika namn, men delar hela eller en del av samma fysiska register. [2][s. 152] Ett exempel kan vara ett 64 bitar l˚angt ackumulator register a0, d¨ar tv˚a alias a0h och a0l refererar till de

¨

ovre respektive l¨agre 32 bitarna. Om ett virtuellt register allokeras till a0h, blockeras ocks˚a a0 i det h¨ar fallet. ¨Ar a0 upptaget kan man inte anv¨anda

(12)

a0h eller a0l.

Registerpar ¨ar lite kr˚angligare ¨an alias. Registerpar kommer fr˚an begr¨ansningar i h˚ardvaran som resulterar i att man med vissa instruktioner m˚aste anv¨anda kombinationer av register. Definitionerna av vad registerpar ¨ar g˚ar is¨ar n˚agot, och i m˚anga fall finns det dessv¨arre olika definitioner av begreppen beropende p˚a kontext. I boken Compilers: Principles, Techniques, and Tools beskrivs registerpar som par av j¨amna och udda register.[3][s. 510].

Vi skall dock inte anv¨anda den definitionen h¨ar.

Briggs et al. n¨amner registerpar i artiklen Coloring Register Pairs. Han definerar tv˚a typer, sk. ”adjacent pairs”, n¨arliggande par och ”unconstrained pairs”, obegr¨ansade par. [7][s. 7]

P˚a vissa DSPer anv¨ands i vissa instruktioner sk. modifikationsregister (m- register) f¨or att r¨akna upp adressregister (r-register) i loopar. D˚a kan t.ex de f¨orsta tre adress registren vara mappade mot modifikations register m0, de n¨asta tre mot m1 osv. Vid allokeringen m˚aste man allts˚a t¨anka p˚a att man v¨aljer r¨att m register beroende p˚a val av r register. Detta ¨ar de en enligt Briggs definition, en form av obegr¨ansade par.

Den typ av par som beskrivs i ovanst˚aende exempel ¨ar det som vi kommer att syfta p˚a n¨ar vi talar om registerpar i resten av rapporten.

(13)

2. PBQP i teorin

Vi g˚ar h¨ar igenom den teoretiska beskrivningen av PBQP, samt dess l¨osnings- algoritm. Detta ¨ar en kortfattad beskrivning. En mer utf¨orlig beskrivning kan hittas i Scholz och Ecksteins artikel [1].

2.1 Matematisk beskrivning

PBQP ¨ar egentligen ett en specialiserad typ av Quadratic Assignment Prob- lem vilket ¨ar en typ av optimeringsproblem [1, s. 143].

En av grundprinciperna i PBQP ¨ar att man kan uttrycka valet av register som en boolsk ekvation av n variabler. I v˚ar registerallokerare kan vi l˚ata en av dessa boolska variabler representera att vi spiller ett virtuellt register, en annan att vi l¨agger den i register r1 etc. Vi f˚ar ett problem som liknar det nedanst˚aende:

xsp+ xr1+ xr2+ ... + xrn= 1 (2.1) D¨ar xsp ∈ {0, 1} st˚ar f¨or h¨andelsen att man v¨aljer att spilla det virtuella registret xrn ∈ {0, 1} st˚ar f¨or att vi i st¨allet l¨agger det virtuella registret i register n.

Eftersom vi bara kan v¨alja ett alternativ s˚a m˚aste h¨ogerledet vara 1 i det h¨ar fallet.

F¨or att kunna g¨ora bra val och modellera begr¨ansningar i detta problem inf¨orde Scholz och Eckstein ¨aven kostnader f¨or alla register och en kostnads- matris f¨or registerkombinationer. Med denna modell kan man bla. f¨orhindra att samma register allokeras till tv˚a virtuella register som interfererar. Detta problem kom att kallas f¨or Partitioned Boolean Quadratic Problem.

(14)

Det kan beskrivas som f¨oljande:

min f =

X

1≤i≤j≤n

~

xi· Cij · ~xTj

+

X

1≤i≤n

~ci· ~xTi

(2.2)

F ¨or vilket det g¨aller att : ∀i ∈ 1...n : ~xi· ~1T = 1, d¨ar n ¨ar antalet virtuella register.

I ovanst˚aende uttryck beskriver den f¨orsta summan av alla kostnader f¨or registerpar, medan den andra beskriver summan av alla kostnader f¨or de enskilda registena. Vi skriver min f eftersom m˚alet ¨ar att minimera total- kostnadsfunktionen f.

~

xn ¨ar en vektor av boolska variabler d¨ar varje rad representerar ett val.

Ex:

xsp

xr0

xr1

H¨ar l˚ater vi xsp ∈ {0, 1} representera valet att spilla det virtuella registret och xrn∈ {0, 1} att i st¨allet stoppa det i register n.

~cn¨ar en kostnadsvektor. Kostnaden f¨or ett vanligt register ¨ar ofta 0, medan spillning kan kosta 10 till exempel. Vilka faktiska kostnader man skall anv¨anda

¨

ar upp till den enskilda implementationen.

C ¨ar en en kostnadsmatris som beskriver kostnaden f¨or en viss kombination av val.

Den kan t.ex. se ut p˚a f¨oljande s¨att:

0 0 0

0 ∞ 0

0 0 ∞

H¨ar anv¨ands ∞ i diagonalen f¨or att blockera om¨ojliga kombinationer d¨ar samma register skulle anv¨andas till tv˚a register. Man kan ¨aven l¨agga in andra kostnader, t.ex. kostnaden -b f¨or valet att sl˚a ihop tv˚a virtuella register som

¨ar relaterade med en move instruktion. Notera nollan uppe i v¨anstra h¨ornet;

naturligtvis g˚ar det alltid att v¨alja att spillning f¨or b˚ada virtuella registren.

Detta g¨or att det alltid finns en l¨osning, om ¨an d˚alig s˚adan, p˚a problem av den h¨ar typen.

2.2 Exempel vid registerallokering

F¨oljande exempel ¨ar inspirerade av Lang Hames f¨oredrag om framtida arbete kring registerallokering i LLVM ramverket [6].

(15)

Figur 2.1: Ett enkelt exempel

De tv˚a staplarna i figur 2.1 representerar kostnadsvektorer f¨or tv˚a virtuella register som interfererar med varandra. Dessa kan placeras antingen i register r0, r1 eller spillas p˚a stacken (sp). Rad och kolumn i kostnads matrisen v¨aljs efter index i kostnadsvektorerna (se ekv. 2.2). Vi l˚ater spilling kosta 10, men allokering till register vara gratis.

Ett m¨ojligt val ¨ar att v¨alja att spilla den ena. Detta val f˚ar i s˚a fall kostnaden 10 som i figur 2.2.

Figur 2.2: En d˚alig l¨osning d˚a kostnaden blir on¨odigt h¨og.

Om vi f¨ors¨oker placera de b˚ada virtuella registren i samma reella register som visas i figur 2.3 f˚ar vi en o¨andlig kostnad. Detta alternativ ¨ar allts˚a f¨orbjudet.

Figur 2.3: En f¨orbjuden l¨osning.

Ett b¨attre alternativ som visas i figur 2.4 ¨ar att l¨agga dem i varsitt register;

vi f˚ar d˚a kostnaden 0. Det h¨ar tycks allts˚a vara det b¨asta valet i det h¨ar enkla fallet.

M˚alet f¨or registerallokeringsalgoritmer baserade p˚a PBQP ¨ar att finna dessa bra kombinationer. Detta ¨ar trivialt i det enkla fallet, men i en interferensgraf med m˚anga noder blir antalet val snabbt stort d˚a valet f¨or en nod p˚averkar m¨ojligheterna f¨or de andra.

(16)

0 0 0

0 10

0 0

0 10

0 + + =

0

0 0

0

0 0 0

Figur 2.4: En bra l¨osning.

2.2.1 Ett mer avancerat exempel

I figur 2.5 visas ett exempel p˚a hur man st¨aller upp ett PBQP problem i en graf. I det h¨ar fallet ¨ar problemet att allokera de viruella registren v1, v2 och v3 till de fysiska registren r0, r1. Att spillkostanden varierar ¨ar realistiskt d˚a det kan vara olika d˚aligt att spilla olika register. Vi vill t.ex. inte g¨arna spilla ett register som anv¨ands f¨or indexering i en loop. Detta ¨ar enkelt fixat i teorin genom att bara ge den en h¨og kostnad.

Figur 2.5: Ett exempel p˚a hur det hela st¨alls upp i en graf.

En m¨ojlig l¨osning visas i figur 2.6. H¨ar v¨aljs register r1 till v1, r0 till v3 och splling f¨or v2 d˚a v2 har den l¨agsta spillkostanden.

2.2.2 Hur man modellerar alias och par

Under f¨oljer n˚agra exempel p˚a hur man kan modellera registerpar och alias begr¨ansningar i PBQP.

(17)

v2

0 0

0 0 0

0 0 0 0 0

0 0

0

0 0 0 0 0

En lösning [3, 1 ,2]:

6

0

0 0

v1 v3

7 10 0 0 0

Nod kostnader: 0+6+0 = 6 Båg kostnader: 0+0+0 = 0 Totalkostnad: 6

0

0

0

Figur 2.6: En m¨ojlig l¨osning. Problemet ¨ar att hitta den mest optimala l¨osningen. I det h¨ar fallet var det enkelt, men s˚a l¨att ¨ar inte alltid.

L˚at s¨aga att vi har tv˚a virtuella register. Den ena kan l¨aggas i ackumulator registret a0, och den andra i de kortare a0h eller a0l vilka ¨ar den h¨oga respektive l˚aga delen av a0. Vi skulle d˚a f˚a en kostnadsmatris enligt figur 2.7. Sp st˚ar f¨or alternativet att spilla ett virtuellt register.

Figur 2.7: Ett exemepel p˚a en kostnadsmatris f¨or alias i ett ackumulator register. Det g˚ar inte att v¨alja a0 i kombination med a0l eller a0h eftersom dom tar upp samma fysiska plats.

I figur 2.8 visas ett exempel av kostnadsmatris f¨or x86 arkitekturen d¨ar ett virtuellt register kan placeras antingen i AX eller BX och det andra i AH, AL, BL eller CL. Exemplet ¨ar taget fr˚an rapporten Nearly Optimal Register Allocation with PBQP [4, s. 5].

Par g˚ar ocks˚a ganska enkelt att modellera med kostnadsmatriser. Exem- plet fr˚an kapitel 1 r¨or adressregister (r) och modifikationsregister (m). I det h¨ar fallet kunde man f¨or vissa instruktioner endast v¨alja n˚agot m-register beroende p˚a val av r-register. De ¨ovriga registren som inte valts ¨ar lediga.

L˚at s¨aga att vi har f¨oljande mappning f¨or detta beroende:

(18)

Figur 2.8: Ett exemepel p˚a en kostnadsmatris f¨or alias p˚a x86 arkitekturen.

m1 -> {r0,r1,r2,r3}

m2 -> {r4,r5,r6,r7}

m3 -> {r8,r9,r10,r11}

m4 -> {r12,r13,r14,r15}

Detta betyder att adressregistren r0,r1,r2 och r3 endast kan endast anv¨andas tillsammans med modifikationsregister m1, i den h¨ar typen av instruktion.

Samma sak g¨aller f¨or de ¨ovriga paren.

Vi f˚ar d˚a en matris enligt figur 2.9.

Figur 2.9: Ett exemepel p˚a en kostnadsmatris f¨or par av adress och modi- fikations register

Som vi ser s˚a kan b˚ade alias och par problem beskrivas med l¨atthet. Nu

¨ar inte saken klar bara f¨or att vi vet vilken matris vi skall anv¨anda. Innan man kan l¨osa ett PBQP problem med en generell l¨osningsalgoritm s˚a m˚aste man f¨orst konstruera grafen. F¨or det hela skall fungera som vi vill s˚a m˚aste vi s¨atta in kostnadsmatrisen p˚a r¨att st¨allen. F¨or ovanst˚aende regler g¨aller n¨amligen inte generellt n¨ar vi har ett r-register och m-register som ¨ar live samtidigt, utan endast n¨ar de skall anv¨andas tillsammans i vissa instruktion- er. Vi kommer till detta i kap. 3 d¨ar vi diskuterar en praktisk implementation av PBQP. Men f¨orst skall vi titta p˚a den teoretiska beskrivningen av l¨osnings algoritmen.

(19)

2.3 En l¨ osningsalgoritm

Scholz och Eckstein f¨oresl˚ar ¨aven en l¨osningsalgoritm f¨or PBQP problemet i artikeln Register Allocation for Irregular Architectures [1]. Denna algoritm bygger p˚a dynamisk programmering. Dynamisk programmering beskrivs i boken Algorithms som ett kraftfullt algoritmiskt verktyg i vilket ett problem l¨oses genom att identifiera en upps¨attning subproblem som tacklas ett i taget. De minsta behandlas f¨orst, och svaren anv¨ands sedan f¨or att klura ut de st¨orre problemen tills dess att alla ¨ar l¨osta [9].

Eftersom problemet ¨ar NP-komplett finns det ingen l¨osning i polynomisk tid, s˚a d¨arf¨or bygger l¨osningen delvis p˚a heuristik. Detta betyder att l¨osningen vi hittar inte ¨ar optimal, men kan anses ”tillr¨ackligt bra”. En del av l¨osningen som presenterades i den ursprungliga beskrivningen av algoritmen [1] p˚avisades i en senare artikel av av Hames och Scholz prestera d˚aligt i en testb¨ank baserad p˚a SPEC2000 [4][s. 6]. I den nya artikeln, Nearly Optimal Register Allocation with PBQP beskrivs en ny heuristik som enligt f¨orfattarna pro- ducerar allokeringar av tidigare orepresenterad kvalitet p˚a rimlig tid [4][s.

3]. Denna teknik kallas Branch-and-Bound, och diskuteras kort nedan.

Notera: F¨or en mer utf¨orliga och korrekta matematiska beskrivningar h¨anvisas l¨asaren till de ursprungliga rapporterna.

Algoritmen har f¨oljande fyra reduktionsregler; en nods ”grad” best¨ams av hur m˚anga grannar den har:

• R0 - K¨ors f¨or noder av grad noll.

Detta ¨ar en trivial regel som endast pushar noderna p˚a reduktion- sstacken. Den utel¨amnades i beskrivningen av den ursprungliga algo- ritmen, men kan ˚aterfinnas i Nearly Optimal Register Allocation with PBQP .

• RI - K¨ors f¨or noder av f¨orsta graden.

Man r¨aknar h¨ar ut en delta-vektor vilken adderas till kostnaden f¨or den intilliggande noden. Denna delta-vektor representerar den minsta kostnaden f¨or noden x beroende p˚a val av y.

• RII - K¨ors f¨or noder av andra graden.

P˚a liknande s¨att som i RI r¨aknas i st¨allet en delta-matris ut. Denna adderas till kostnadsmatrisen f¨or b˚agen mellan de b˚ada grannoderna.

Om det ej finns en b˚age mellan dessa l¨aggs en s˚adan till och delta- matrisen blir d˚a kostnadsmatrisen f¨or denna b˚age. .

• RN - K¨ors f¨or noder av h¨ogre grad ¨an tv˚a.

De noder som behandlas h¨ar riskerar att spillas. I den ursprungli- ga l¨osningen testades h¨ar alla m¨ojliga kombinationer i jakten p˚a en

(20)

f¨argbar nod. Man har i senare framst¨allningar presenterat en b¨attre algoritm f¨or att avg¨ora en nods f¨argbarhet.

Om ingen f¨argbar nod hittas v¨aljs en nod f¨or spilling enligt Briggs spillheuristik. Man v¨aljer d˚a den nod med den l¨agsta spillkostnaden i f¨orh˚allande till grad.

Efter varje regel pushas den valda noden p˚a stacken.

M˚alet med reduktionerna ¨ar att f¨orenkla problemet tills l¨osningen blir trivial, dvs. d˚a alla kvarvarande noder i grafen har grad noll [1][s.144].

Algoritmen best˚ar av f¨oljande grundl¨aggande steg:

1. Konstruera en viktad PBQP graf med kostnadsmatriser enligt kap. 2 2. Reducera grafen enligt reduktions reglerna R0, RI, RII och RN. L¨agg

reducerade noder p˚a en stack.

3. Poppa stacken och propagera l¨osningen genom de eliminerade noderna.

I detta steg v¨aljs en l¨osning f¨or varje nod, och ”sp” (spilling) f¨or de noder som skall spillas.

4. Baserat p˚a l¨oningen, tilldela faktiska register till noderna. Generera spill kod. Om noder spillts m˚aste algoritmen k¨oras igen d˚a detta skapar nya livsl¨anger som m˚aste tas h¨ansyn till.

2.3.1 F¨argbarhet

En nod u anses normalt som f¨argbar om nodens grad ¨ar l¨agre ¨an antalet lediga register k, vilket ofta skrivs som grad(u) < k. Detta kriterium ¨ar dock felaktigt f¨or irregulj¨ara arkitekturer eftersom en granne till u kan blockera mer ¨an ett registerval; detta pga. aliasing. Hames och Scholzs nya f¨argbarhetsalgoritm definerar d¨arf¨or en nod som f¨argbar om f¨oljande g¨aller:

1. Det h¨ogsta antalet f¨arger som kan blockeras av u genom f¨argl¨aggning av u;s grannar ¨ar mindre ¨an det totala antalet f¨arger tillg¨angliga f¨or u.

2. Det finns minst en f¨arg vilken ¨ar ett till˚atet val f¨or u, men inte f¨or n˚agon av u;s grannar.

2.3.2 Branch-and-Bound

Enligt Hames och Scholz producerar algoritmen garanterat en optimal l¨osning om RN regeln inte anv¨ands [4]. Den alternativa tekniken Branch-and-Bound

(21)

¨andrar i praktiken endast p˚a heuristiken f¨or RN regeln, men de ¨ovriga regler- na beh˚alls intakta d˚a de redan ¨ar optimala. I Branch-and-Bound definieras ett s¨oktr¨ad av problem. F¨or R0, RI, RII blir s¨oktr¨aden triviala med endast en rot-nod, men f¨or RN f˚ar man ett antal subproblem som m˚aste l¨osas.

(22)

3. Praktisk till¨ ampning i LLVM

3.1 Om LLVM

LLVM ¨ar ett open source kompilatorramverk som ineh˚aller en samling av modul¨ara ˚ateranv¨andbara verktygsteknologier (sk. toolchain technologies).

Det hela b¨orjade som ett forskningsprojekt vid University of Illinois, men har sedan dess vuxit enormt och anv¨ands i dag av Apple mfl. f¨oretag. [11]

LLVM st¨odjer i nul¨aget C/C++ i frontend och en rad olika arkitekturer i backend, bland annat ARM och MIPS. Man har ¨aven st¨od f¨or just in time kompilering (JIT), Garbage Collection mm. [12]

Sj¨alva ramverket ¨ar ocks˚a i huvudsak skrivet i C++. F¨or targetbeskrivningar anv¨ander dock LLVM sin egen makrokod. Denna makrokod ¨overs¨atts sedan till C++ kod av en makroprocessor vid namn tablegen. Targetbeskrivnin- gen beskriver de register, beroenden och instruktioner som finns p˚a en viss arkitektur.

3.2 Upps¨ attningen

Den f¨orsta utmaningen i den praktiska implementationen var att s¨atta upp och bygga LLVM. I upps¨attningen anv¨andes LLVM med frontend clang. Att bygga LLVM visade sig inte vara helt trivialt d˚a LLVM ¨ar ett stort projekt.

Aldre versioner av GCC verkar f˚¨ ar problem och p˚ast˚ar att det finns fel i koden.

En lista p˚a GCC versioner som inte fungerar kan hittas p˚a: http://llvm.

org/docs/GettingStarted.html#brokengcc

Det tar tid att kompilera och l¨anka alla program i LLVM. N¨ar man v¨al har kompilerat en g˚ang kan man anv¨anda verktyget makellvm f¨or att bara

(23)

kompilera ¨andringarna i den nuvarande mappen och bara l¨anka ett program.

makellvm kan hittas under llvm/utils Ex:

llvm/lib/CodeGen$ ../../utils/makellvm llc

En fullst¨andig guide f¨or att s¨atta upp LLVM och clang kan hittas p˚a http:

//clang.llvm.org/get_started.html man kan¨aven vilja fundera p˚a vil- ka flaggor man skickar till configure beroende p˚a om man vill ha t.ex. de- bugsymboler eller ej. Debugsymboler ¨ar p˚aslagna som standard i SVN ver- sionen.

3.3 Kodbasen

LLVM best˚ar av en rad olika delar. De moduler som ¨ar intressanta f¨or reg- isterallokeringen ¨ar framf¨or allt den kod som skapar grafen till PBQP al- goritmen, vilken ligger i modulen lib/CodeGen/RegAllocPBQP.cpp. Sj¨alva l¨osningsalgoritmen ligger i form av headerfiler under s¨okv¨agen

include/llvm/CodeGen/PBQP.

3.4 Skillnaden mellan PBQP och klassisk grafal- lokering

Den huvudsakliga skillnaden mellan PBQP och klassisk grafallokering ¨ar f¨orst˚as den viktade grafen. Klassisk grafallokering har ingen viktad graf utan man tittar endast p˚a spillkostnader. I de den praktiska implementationen i LLVM arbetar PBQP iterativt precis som grafallokering. Man g¨or en al- lokering, och om man blir tvungen att spilla l¨aggs spillkod till. Sedan k¨ors algoritmen igen med den nya koden.

De vanliga stegen i grafallokering beskrivs kortfattat nedan. Beskrivningen

¨ar h¨amtad fr˚an boken Modern Compiler Implementation in Java [8][s. 223- 224].

• Build

Konstruera interferensgrafen, kategorisera noder som antingen move- relaterade eller icke move-relaterade. Att en nod ¨ar move-relaterad betyder att den antingen anv¨ands som k¨alla eller destination i en move instruktion.

• Simplify

Ta bort en nod i taget med grad mindre ¨an k fr˚an grafen och pusha den p˚a stacken. K ¨ar antalet lediga register.

(24)

• Coalesce

Konservativ hopslagning av noder i den nuvarande grafen. Noder som efter detta steg inte l¨angre ¨ar relaterade till en move g¨ors tillg¨angliga f¨or n¨asta k¨orning av Simplify. Simplify och Coalesce upprepas tills endast noder av signifikant grad ˚aterst˚ar (grad ≥ k).

• Freeze

Om varken Simplify eller Coalesce kan appliceras letar vi upp en move- relaterad nod av l˚ag grad. Vi fryser de moves vilken den h¨ar noden

¨ar involverad i. Detta betyder att noden inte l¨angre kan klassas som move-relaterad, och d¨armed kan ytterligare f¨orenkling med Simplify m¨ojligg¨oras.

• Spill

Om det inte finns n˚agra noder med l˚ag grad v¨aljer vi en nod av sig- nifikant grad (grad ≤ k) f¨or potentiell spilling. Detta g¨ors med en spill heuristik, t.ex. Briggs. Noden markeras sedan och pushas sedan p˚a stacken.

• Select

Slutfasen, poppa stacken och dela ut f¨arger.

Om inte Select lyckas hitta f¨arger till alla noder m˚aste vi nu introducera rik- tiga spills. Det g¨ors genom att programmet skrivs om och de spillda noderna l¨aggs ut i minnet, varifr˚an de sedan laddas in n¨ar de beh¨ovs. I det h¨ar steget skapas nya noder med korta livsl¨angder. Hela algoritmen k¨ors d¨arf¨or om fr˚an b¨orjan igen.

PBQP fungerar p˚a ett liknande s¨att. Coalescing mm. g¨ors f¨ore reduktioner- na, allts˚a i den fas d¨ar man konstruerar sj¨alva grafen. Denna funktion kallas build i LLVM. D¨arefter k¨ors l¨osningsalgoritmen en g˚ang, och man reducer- ar enligt reduktionsreglerna R0, RI, RII och RN. H¨ar g¨ors ocks˚a PBQP;s motsvarighet till select, dvs. man poppar stacken och v¨aljer en l¨osning f¨or varje nod. Med l¨osningen klar g˚ar man sedan vidare till att f¨ors¨oka tilldela noderna riktiga register i en funktion som i LLVM kallas mapPBQPToRe- gAlloc. Om man h¨ar inser att man beh¨over spilla l¨aggs spillintervall till. D¨ar efter k¨ors hela algoritmen, inklusive konstruktionen av grafen med build, igen.

Sj¨alva l¨osningsalgoritmen i LLVM ligger ocks˚a separat i en funktion vid namn solve.

Anropet fr˚an build ser ut som f¨oljande:

PBQP::HeuristicSolver<PBQP::Heuristics::Briggs>::solve(

problem->getGraph());

Detta ¨ar t¨ankt att ge l¨asaren en ide om hur det hela ¨ar uppdelat.

(25)

3.5 Den nuvarande implementationen

Notis: Pseudokod f¨or viktigaste metoderna i den nuvarande k¨allkoden kan ses i appendix f¨or detta kapitel.

N¨ar jag b¨orjade projektet tittade jag igenom en del material, bland annat Future Works in LLVM Register Allocation [6]. D¨ar n¨amns en del planerad funktionalitet f¨or PBQP, bland annat registerpairing. Detta kunde jag dock inte hitta n¨ar jag gick genom igenom den senaste versionen av k¨allkoden.

Jag skickade ett mail om detta till LLVMs mail-lista och fick svar fr˚an Lang Hames, en av f¨orfattarna till Nearly Optimal Register Allocation with PBQP [4]. Lang ¨ar ocks˚a utvecklare den PBQP l¨osare som finns i LLVM i dag. I sitt mail bekr¨aftade Lang att LLVM saknar st¨od f¨or att modellera registerpar,

˚atminstone f¨or par av typen r och m register. Det som finns i LLVM imple- mentationen i dagsl¨aget tycks vara st¨od f¨or alias och coalescing, vilket g¨or algoritmen ungef¨ar lika kompetent som n˚agon annan algoritm, om m¨ojligen l˚angsammare.

Dock f¨or¨andras koden st¨andigt. I mitt arbete under tiden slutet av april till b¨orjan av maj jobbade jag p˚a version 2.8, n¨ar jag sedan gick ¨over till 2.9 uppt¨ackte jag att man gjort avsev¨arda omstruktureringar av koden i RegAllocPBQP.cpp. Man hade t.ex. haft den goda smaken att bryta ut ma- triskoden till en egen klass Matrix, samt gjort ett f¨ors¨ok att f¨orb¨attra den objektorienterade strukturen genom att l¨agga coalescing koden i en egen subklass klass vid namn PBQPBuilderWithCoalescing.

Man har st¨orre m¨ojligheter att modellera kostnader i PBQP j¨amf¨ort med vanlig grafallokering. Dock ¨ar ¨ar fr˚agan av hur mycket man f˚ar ut av detta i den nuvarande implementationen. Det finns mycket som fortfarande inte ¨ar klart, t.ex. hittades f¨oljande i PBQPBuilderWithCoalescing:

const float copyFactor = 0.5; // Cost of copy relative to load.

// Current value plucked randomly out of the air.

Det ¨ar egentligen det h¨ar som hela PBQP implementationen lider av. Det finns inget st¨od h¨ogre upp i target specifikationen f¨or att ange v¨arden p˚a alla de parametrar som p˚averkar prestandan av PBQP implementationen.

˚Atminstone inte ¨annu.

3.6 M¨ ojligheter att implementera st¨ od f¨ or regis- terpar

Ur ljuset av det ovanst˚aende ser jag tv˚a m¨ojligheter:

(26)

• Ett mer omfattande arbete

Man kan v¨alja att g¨ora ett mer omfattande arbete d¨ar man tillsam- mans med LLVM teamet bygger till den funktionalitet som beh¨ovs f¨or att kunna utnyttja PBQPs fulla potential. Detta skulle i s˚a fall involvera b˚ade en del ¨andringar i RegAllocPBQP.cpp, men ¨aven i t.ex.

makroprocessorn tablegen.

• Eget hack

Ta den nuvarande koden i RegAllocPBQP.cpp och g¨ora en egen ver- sion, specifik f¨or en viss target och till¨ampning. Man skulle d˚a fr¨amst kunna fokusera p˚a att skriva en egen PBQPBuilder subklass f¨or att konstruera PBQP grafen.

Problemet med det senare ¨ar f¨orst˚as att f˚a det att fungera med framtida releaser. Som jag tidigare n¨amnt s˚a f¨or¨andrades koden avsev¨art bara under den korta tid jag jobbade med detta. Det som ocks˚a talar f¨or det f¨orsta alternativet ¨ar att LLVM teamet redan planerat f¨or att implementera fullt st¨od f¨or pairing.

N˚agra saker som man b¨or t¨anka p˚a om man v¨aljer att implementera sin egen parl¨osning ¨ar:

• N¨ar man skall s¨atta in kostnadsmatriser

I enighet med det som n¨amndes i exemplet f¨or pairing av m och r register skall man endast stoppa in kostnadsmatriser vid instruktioner d¨ar begr¨ansningarna g¨aller. Att ett t.ex. m register och r register ¨ar live samtidigt ¨ar inte tillr¨ackligt.

D¨armed kanske man skall v¨alja att iterera ¨over instruktioner. I var- je iteration h¨amtar man de virtuella register som anv¨ands. Om en f¨orbjuden kombination hittas letar man upp noderna i grafen och upp- daterar kostnadsmatrisen. Man kan anv¨anda en likande loop som den i PBQPBuilderWithCoalescing vilken itererar ¨over funktioner block och instruktioner.

• Coalescing

Just nu ligger coalescing koden i sin egen klass PBQPBuilderWithCoa- lescing och har en egen funktion PBQPBuilderWithCoalescing::build(...).

Denna funktion kallar sedan p˚a superklassens funktion PBQPBuilder- :build(...). Det kan vara v¨art att dubbelkolla att den nuvarande ko- den kommer att fungera tillsammans med de nya f¨or¨andringarna man g¨or i sin egen build funktion. Man kan eventuellt bli tvungen att g¨ora

¨

andringar ¨aven h¨ar.

(27)

N˚agonting annat som kan vara bra att ha n¨ar man utvecklar det h¨ar ¨ar en m¨ojlighet att skriva ut en grafisk representation av PBQP grafen s˚a att man kan verifiera att det man g¨or ¨ar r¨att. En funktion som g¨or detta heter printDot som ligger i include/llvm/CodeGen/PBQP/Graph.h. Den anv¨ander dock LLVMs egen utmatningsstr¨om, raw ostream.

3.7 Utveckling och underh˚ all

Det kan vara rimligt att uppskatta att storleken p˚a den nya funktionaliteten till storleken av den nuvarande PBQPBuilderWithCoalescing klassen med alla metoder. Om man r¨aknar ihop allt samman blir det totalt ca 130 rader kod. Det ¨ar inte s˚a mycket, men det kan dock bli mer om man vill im- plementera register pairing f¨or flera fall eller om man vill g¨ora en generell l¨osning med st¨od i tablegen. Det ¨ar inte heller helt l¨att att skriva den h¨ar koden om man inte har full koll p˚a de olika objekt och datastrukturer som anv¨ands i kodgenereringslagret. En gissning p˚a hur l˚ang tid det skulle kunna ta att f˚a till en f¨ardig testad l¨osning ligger mellan 2 veckor till 3 m˚anader, beroende p˚a hur bra koll man har p˚a LLVM.

I en egen l¨osning vill man f¨ormodligen ocks˚a f¨ora in nya f¨or¨andringar som g¨ors i RegAllocPBQP.cpp ¨over tiden . Man m˚aste d˚a ¨aven se till att h˚alla sig kompatibel mot de f¨or¨andringar som g¨ors i resten av LLVM. LLVM k¨or SVN f¨or versionshantering, men det hj¨alper inte mycket eftersom att man

¨

and˚a kommer att f˚a konflikter mellan de f¨or¨andringar man sj¨alv gjort och LLVM teamets f¨or¨andringar n¨ar man f¨ors¨oker uppdatera k¨allkoden. Som jag n¨amnt tidigare kan f¨or¨andringarna vara ganska omfattande mellan olika versioner.

3.A Pseudokod

Nedan f¨oljer pseudokod f¨or n˚agra av de viktigaste metoderna i RegAllocPBQP.cpp.

Detta kan vara bra, kanske f¨or att f˚a en hj¨alp att f¨orst˚a koden i LLVM.

Pseudokod f¨or sj¨alva l¨osningsalgoritmen kan hittas i rapporten Register Al- location for Irregular Architectures av Scholz et al. [1].

(28)

/* This function contains the main allocation loop. */

runOnMachineFunction {

find vreg intervals in need of allocation;

if there are non-empty intervalls { while allocation not complete {

if coalescing is enabled {

problem := construct the PBQP problem

using the builder with coalescing;

} else {

problem := construct the PBQP problem

usingh the normal build function;

}

problem := build the PBQP problem with build();

solution := solve it using the PBQP solver;

map the solution back to the problem

using mapPBQPToRegAlloc(problem, solution);

check if the allocation is complete;

} } }

/* Build the pbqp problem. */

PBQPBuilder::build () {

pbqpProblem := new pbqp problem with a supposedly empty or initial PBQP graph;

graph := the graph from pbqpProblem;

for each live intervall {

mark all physical register as used;

}

for each virtual register {

compute an initial allowed set;

remove all physical register which overlap;

remove all aliases;

vector := compute a cost vector from the allowed set;

create a node with this cost vector;

add the node to the graph;

add spill costs for the node;

}

(29)

for each virtual register as v1 { live1 : = get live intervall for v1;

for each virtual register as v2 { live2 : = get live intervall for v2;

if live1 and live2 overlap { node1 := get the node in

the graph representing v1;

node2 := get the node in

the graph representing v2;

matrix := cost matrix for node1 and node2;

add an edge in the graph between

node1 and node2 and assign the interence matrix to the edge;

} } }

return pbqpProblem;

}

/* Build the pbqp problem and do coalescing. */

PBQPBuilderWithCoalescing::build () { /* We first construct the problem using

the normal build function.. */

pbqpProblem := PBQPBuilder::build();

/* ..then we do coalescing. */

for each machine basic block as block { for each machine isntruction as instr {

if the virtual registers in instr are not coalescable {

skipp this instruction and continue;

}

if the source and dest vreg are the same { /* Already coalesced */

skipp this instruction and continue;

}

compute coalesce benefit;

if this coalesce pair is physical { if the live interval of the dest vreg

is not allocatabe {

(30)

skipp and continue;

}

count the number of options availiable

based on the allowed set of the source vreg;

add phycial coalese;

update cost vector;

} else {

node1 := node for dest vreg;

node2 := node for source vreg;

edge := find edge in graph for node1 and node2;

if not found {

matrix := construct cost matrix from the allowed sets of dest vreg and source vreg;

edge := add an edge in the graph between node1 and node2 with the cost matrix;

} else {

if the first node conected by the edge is equal to node2 { swap node1 with node2;

swap the allowed sets of the nodes;

} }

Add a virtual register coalesce, with edge costs from the edge, the allowed sets for node1,

node2 and the coalesce bennefit;

} } } }

/* Map the solution back to the problem. */

RegAllocPBQP::mapPBQPToRegAlloc() { clear the previous allocation;

/* We’re going to do a new one right here. */

for each node in the graph { if a physical register has been

choosen for this node {

assign a physical register to this node;

} else if spilling has been choosen for this node { remove the old interval;

assign new spill intervals for this node;

(31)

add the new intervals to the PBQP graph;

} }

if new spills where added {

returnValue := we need another

round with the solver;

} else {

returnValue := allocation is complete;

}

return returnValue;

}

(32)

4. Resultat

4.1 Slutsatser

Jag har i den h¨ar ¨ar rapporten visat hur man i teorin kan modellera par och alias i en interferensgraf f¨or anv¨andning med PBQP. Jag har ocks˚a g˚att igenom vad som i dagsl¨aget finns implementerat i LLVM och gett f¨orslag p˚a hur man skulle kunna g˚a till v¨aga f¨or att l¨agga till st¨od f¨or registerpar.

Det som slutligen kan konstateras ¨ar:

• PBQP ger m¨ojlighet att modellera m˚anga olika typer av begr¨ansningar, bland annat par och alias.

• Det praktiska problemet ligger i att konstruera PBQP grafen och s¨atta in r¨att kostnadsmatris p˚a r¨att st¨alle. N¨ar problemet v¨al ¨ar beskrivet kan det l¨osas enligt l¨osningsalgoritmen f¨or PBQP, vilken beskrivs i sin helhet i [1].

• St¨od f¨or registerpar saknas i dagsl¨aget i PBQP implementationen i LLVM.

• En ev. implementation kan g¨oras antingen i egen regi eller som ett samarbete med LLVM teamet.

• F¨or att kunna g¨ora en generell l¨oning som st¨odjer alla typer av be- gr¨ansningar b¨or st¨od f¨or PBQP implementeras i LLVMs targetspeci- fikation.

• Storleken p˚a en minimal egen l¨oning kan uppskattas till ca 130 rader, men kan komma att bli mycket st¨orre och avancerad f¨or att t¨acka alla olika typer av parrelationer.

• Vid en eventuell implementation av st¨od f¨or registerpar m˚aste den nuvarande coalescing koden med st¨orsta sannolikhet anpassas.

(33)

4.2 Diskussion

De resultat som har presenterats h¨ar skulle f¨orhoppningsvis vara till nytta vid framtida arbete i LLVM. Med lite mer tid hade man kanske kunnat ge sig p˚a att implementera registerpar i LLVM. Detta kunde ha varit ett m˚al i ett l¨angre examensarbete p˚a sex m˚anader. I ¨ovrigt diskuterade jag med min handledare att g¨ora lite prestandatester p˚a algoritmen, men f¨or att det skall bli meningsfullt s˚a f¨oruts¨atter det att man har en l¨amplig DSP tar- getbeskrivning. Att i st¨allet g¨ora en prestandautv¨ardering f¨or ARM arkitek- turen hade varit en m¨ojlighet, men vi kom fram till att detta f¨ormodligen inte skulle bli speciellt representativt f¨or en DSP. Vidare ¨ar PBQP imple- mentationen i LLVM som sagt inte fullst¨andig heller.

4.3 Framtida arbete

Det vore intressant att ta reda p˚a PBQPs prestanda f¨or en typisk DSP.

Detta f¨oruts¨atter dock att man har en implementation som st¨odjer alla de egenheter som en typisk DSP har. En tidigare utv¨ardering som gjorts kan hittas i Nearly Optimal Register Allocation with PBQP [4]. D¨ar visade man att PBQPs l¨osningar f¨or problemen i testb¨anken SPEC2000 l˚ag i medeltal omkring 2% ifr˚an en optimal l¨osning [4][s. 15-16]. Problemet med det h¨ar testet ¨ar att det ¨ar gjort f¨or en hyfsat regulj¨ar arkitektur, IA-32 (x86). Det s¨ager d¨arf¨or inte s˚a mycket om PBQPs prestanda f¨or irregulj¨ara arkitekturer, s˚a som DSPer. D¨armed s˚a kan det vara intressant att titta n¨armare p˚a detta i framtiden. N˚agot man skulle kunna unders¨oka ¨ar t.ex. hur mycket spilling man f˚ar j¨amf¨ort med en optimal l¨osning, eller j¨amf¨ort med grafallokering.

P˚a detta s¨att skulle man kunna f˚a ett hum om hur mycket PBQP i realiteten kan tillf¨ora i form av ¨okad prestanda.

Naturligtvis s˚a beh¨over ocks˚a implementationen av st¨od f¨or registerpar i LLVM g¨oras.

(34)

Litteraturf¨ orteckning

[1] Scholz B., Eckstein E. (2002). Register allocation for irregular architec- tures. (ACM SIGPLAN Notices. Juli 2002. Vol. 37. Num. 7. s. 139-148).

ACM New York, NY, USA. DOI: 10.1145/566225.513854

[2] Paek Y., Ahn M. (2009). Fast Code Generation for Embedded Proces- sors with Aliased Heterogeneous Registers (Lecture Notes in Computer Science. 2009. Vol. 5470. s. 149-172). Springer-Verlag. DOI 10.1007/978- 3-642-00904-4

[3] Aho A., Lam M., Sethi R., Ullman J. (2006). Compilers: Principles, Techniques, and Tools (2. uppl.). Pearson Education. ISBN 0-321-48681- 1.

[4] Hames L., Scholz B. (2006). Neraly Optimal Register Allocation with PBQP. (Lecture Notes in Computer Science. 2006. Vol. 4228. s. 346-361).

Springer-Verlag. DOI: 10.1007/11860990 21

[5] U. Hirnschrott, A. Krall, B. Scholz. (2003). Graph Coloring vs. Opti- mal Register Allocation for Optimizing Compilers. In Proc. of the Joint Modular Languages Conference (JMLC’03). Lecture Notes in Comput- er Science. Augusti 2003. Vol. 2789. s. 202-213) Springer-Verlag. DOI:

10.1007/978-3-540-45213-3 26

[6] Hames L. (2009). Future Works in LLVM Register Alloca- tion F¨oredrag om LLVMs framtidsplaner f¨or registerallokering.

http://llvm.org/devmtg/2009-10/RegisterAllocationFutureWorks.pdf.

H¨amtad den 4 maj 2011.

[7] Briggs P., Cooper K., Torczon L. (1992) Coloring Register Pairs (ACM Letters on Programming Languages and Systems, Mars 1992. Vol. 1, Num.

1. s. 3-13). ACM New York, NY, USA. DOI: 10.1145/130616.130617 [8] Apple A. Palsberg J. (2002). Modern Compiler Implementation in Java

(2. uppl.). Cambridge university press. ISBN 978-0-521-82060-8.

(35)

[9] S. Dasgupta, C.H. Papadimitriou, U.V. Vazirani (2006) Algoritms Utkast till en bok. http://www.cs.berkeley.edu/ vazirani/algorithms.html.

H¨amtad den 7 maj 2011.

[10] Takala J. General-Purpose DSP Processors (Handbook of Signal Pro- cessing Systems. 2010. Del 2. s. 393-413). Springer Science+Business Me- dia, LLC. DOI: 10.1007/978-1-4419-6345-1 15

[11] LLVM Users LLVM websidan. Anv¨andare av LLVM.

http://llvm.org/Users.html H¨amtad den 11 maj 2011.

[12] LLVM Users LLVM websidan. Funktioner i LLVM http://llvm.org/Features.html H¨amtad den 30 augusti 2011.

References

Related documents

(b) Ber¨ akna den betingade sannolikheten att komponent C inte funkar givet att str¨ om kan passera genom systemet fr˚ an v¨ anster till h¨ oger..

Man kan faktiskt g¨ora ett konfidensintervall f¨or medianen med konfidensgrad minst lika med 1 − α helt utan n˚ agra som helst antaganden om den bakom- liggande f¨ordelningen

Till exempel fick jag inte med n˚ agot Ljus- och Optikland i f¨ orsta f¨ ors¨ oket, och pilen mot Kosmologi, som ligger utanf¨ or den h¨ ar kartan, borde peka mer upp˚ at,

Rutinen som anv¨ands f¨ or att definiera operatorn, kan ha antingen ett eller tv˚ a argument, men eftersom funktionen normalt definieras i samma modul som inneh˚

[r]

Vid bed¨ omningen av l¨ osningarna av uppgifterna i del 2 l¨ aggs stor vikt vid hur l¨ osningarna ¨ ar motiverade och redovisade. T¨ ank p˚ a att noga redovisa inf¨ orda

Vi noterar att denna ekvation redan ¨ ar p˚ a “r¨ att” form (skriver vi ekvationen p˚ a standardform och multiplicerar med den integrerande faktorn f˚ as precis detta uttryck),

Matematiska institutionen Stockholms