INF-5110 Oppgaver kodegenerering etc. INF-5110, vår 2011 Oppgave 1: Løs oppgavene 8.1 og 8.2 i Louden Oppgave 2: Løs oppgave 8.14.a i Louden. I stedet for oppgave 8.14.b, finn en tredje møte å implemetere switch/case på (ikke en serie tester og ikke en ren hopp-tabell) som kan være et godt kompromiss i mange tilfeller. Oppgave 3: Vi skal se på koden generert av TA-instruksjonene til høyre i figur 9.10 i det utdelte notatet, side 539 (men finnes også på siste side i lysarkene fra 5/5-09, dog med en trykkfeil: "SUB a, R1" skal rettes til "SUB c, R1"). a) Påvis at det finnes en bedre kodesekvens for de samme TA-setningene enn den angitte, som er generert av notatets algoritme. b) Diskuter hvordan vi kunne forandre denne kodegenererings-algoritmen, slik at den gir bedre kode i dette tilfellet. Oppgave 4: Løs Oppgave 4 fra eksamen 2007. Denne ligger på: http://www.uio.no/studier/emner/matnat/ifi/inf5110/v08/undervisningsmateriale/inf5110-eksamen2007.pdf Oppgave 5: a) Oversett (pr hånd) følgende setning til TA-kode: if a<b (c>d && e>=f) then x=8 else y=5 endif Oversett den til kode der alle hopp blir så direkte som over hodet mulig (uten å tenke på algoritmen for å gjøre det). b) Forsøk å tenke ut kodegenererings-algoritmer som kunne generere slik kode, f.eks. for setningen over.
Oppgave 1: Løs oppgavene 8.1 i Louden 2 + 3 + 4 + 5 : ------------------ t1 = 2 + 3 t2 = t1 + 4 t3 = t2 + 5 Burde jo heller vært: a, b c og d 2+(3+(4+5)): + (4 + ------------------------ t1 = 4 + 5 t2 = 3+t1 t3 = 2 + t2 a * b + a * b * c: ----------------------- t1 = a * b t2 = t1 * c t3 = t1 + t2 - Her er altså den siste hårfint optimalisert (felles sub-uttrykk er funnet). - En liten optimalisering av de to første (gjøre konstantbergeninger i kompiloatoren) ville lett optimalisert de to første til t1 = 14
Oppgave 1: Løs oppgavene 8.2 i Louden 2 + 3 + 4 + 5 : ------------------ ldc 2 idc 3 ldc 4 ldc 5 2 + (3 + (4 + 5)) : ------------------------ ldc 2 idc 3 ldc 4 ldc 5 a * b + a * b * c : ----------------------- lod a lod b mpi dup //dupliserer toppen lod c mpi Her er igjen den siste hårfint optimalisert, ved at vi antar at det er en dup-instruksjon (duplisering) i P-kode. De to første kan selvfølgelig også optimaliseres som før til ldc 14
Oppgave 2 Løs oppgave 8.14.a i Louden. I stedet for oppgave 8.14.b, finn en tredje møte å implemetere switch/case på (ikke en serie tester og ikke en ren hopp-tabell) som kan være et godt kompromiss i mange tilfeller. a) Vitsen med en hopptabell er at man skal kunne gå rett inn i tabellen med caseindeksen,ogathopp-adressen adressen står der. Det blir altså meget raskt, men tabellen må da spenne fra laveste til høyeste brukte indeks. Om det ikke er så mange brukte indekser, og avstanden mellom største og minste brukte indeks er stor kan tabellen bruke masse plass, men det meste av den vil være tom. Da kan en if-then-else-implementasjon med test på hvert tilfelle være like grei. Men jeg synes at det var veldig rart, slik boka foreslår, å gå over til if-then-else allerede ved 10??! Ny b) En tredje implementasjon kan være å sortere de brukte indeksverdiene, og så legge disse i en tabell med hopp-adressen ved siden av. Da kan man ved run- time bruke binærsøking til å finne om indeksen er der, og hvor det eventuelt skal hoppes. M k D tt b å t di til h t kj t k il t Ell å Merk: Dette bygger på at verdien til hvert case er kjent av kompilatoren. Ellers må if-then-else brukes. Men de fleste språk tillater bare konstanter.
Oppgave 3 Vi skal se på koden generert av TA-instruksjonene til høyre i figur 9.10 i det utdelte notatet, side 539 Påvis at det finnes en bedre kodesekvens for de samme TA-setningene enn den angitte, som er generert av notatets algoritme. SVAR: Det dumme er at vi henter opp a to ganger fra lageret. Om vi allerede første gang hadde sett at vi trengte den en gang til så kunne vi med en gang kopiert den over i et annet register (for eksempel R1) før vi ødela verdien av a i R0 med instruksjonen SUB b, R0. Da ville de første instruksjonene bli: MOV a, R0 MOV R0, R1 // er altså billigere enn en MOV fra lager til register SUB b, R0 SUB c, R1 b) Diskuter hvordan vi kunne forandre denne kodegenererings-algoritmen, slik at den gir bedre kode i dette tilfellet. SVAR: Vi har jo allerede informasjon nok til å kunne gjøre denne optimaliseringen, i og med next use. Vi kan, hver gang vi henter noe fra lageret og dette vil bli ødelagt straks, teste om dette har en neste bruk. Vi vil da se at dette gjelder den første a -en, og vi kan da forsøke å redde verdien unna i et ledig register, om et slik finnes (med en MOV mellom registere)
Til oppgave 3: Eksempel på kode-generering g Setninger Generert kode Reg. deskriptorer Adr. deskriptorer Alle Reg er ubrukte t = a - b MOV a, R0 R0 inneholder t tir0 SUB b, R0 u = a c MOV a, R1 R0 inneholder t t i R0 SUB c, R1 R1 inneholder u u i R1 v = t + u ADD R1, R0 R0 inneholder v v i R0 R1 inneholder u u i R1 d = v + u ADD R1, R0 R0 inneholder d d i R0 og ikke i hukommelsen Avslutning av basal blokk MOV R0, d Alle Reg er ubrukte (Alle prog.variable i hukommelsen) 6
Oppgave 4a, eksamen 2007 Gitt følgende program, der alle setningene er tre-addresse- instruksjoner, bortsett fra at vi også tillater if- og while-setninger på vanlig måte. Instruksjonene x = input og output x regnes som vanlige tre-addresse-instruksjoner, med den opplagte betydning. Vi antar at ingen variable er i live ved slutten av programmet. 4a 1: a = input 2: b = input 3: d = a + b 4: c = a * d 5: if(b<5){ 6: while ( b < 0 ) { 7: a = b + 2 8: b = b+1 9: 10: d = 2 * b 11: else { 12: d = b * 3 13: a = d - b 14: 15: output a 16: output d Angi for hver av variablene a, b, c og d om de er i live eller ikke umiddelbart etter linje 4. Gi en kort forklaring for hver av variablene. Svar: a. Det kunne se ut som om denne var død, siden den settes ( defineres ) både i den ene og den andre grenen av if-setningen, uten å bli brukt først (linje 7 og linje 13). Men, dersom while-løkke l går null ganger vil den verdien som a hadde etter linje 4 være den som brukes i linje 15. Altså er den i live. b. Denne er i høyeste grad live, siden den brukes allerede i linje 5 c. Denne brukes i det hele tatt ikke etter linje 4, og er derfor ikke i live (altså død). d. Denne er ikke i live, siden den helt sikkert settes i begge if-grener, uten å bli brukt først (linje 10 og 12).
Oppgave 4b, eksamen 2007 4b Forklar hva man i kodegenererings-algoritmen it i kap 9.6 (i den utdelte kopien fra ASU-boka) mener med at en variabel har en neste bruk ( next use ) og hvordan dette skiller seg fra å være i live. Forklar hvorfor denne algoritmen skiller mellom disse to begrepene. Svar: Begrepet neste bruk er, i motsetning til begrepet i live knyttet til basale blokker. En variabel har på et gitt sted i programmet en neste bruk dersom den verdien den der har kan bli brukt senere i den basale blokka vi nå er i. (da kan man også si at verdien til variabelen vil bli brukt senere i blokka, siden alt i en basal blokk utføres pent etter hverandre). Grunnen til at algoritmen i notatet er interessert i neste bruk (i den basale blokka) er at den har som grunnfilosofi at ingen variable som er i live skal ligge i et register (men i hjemmeposisjonen sin) mellom basale blokker. Det gjøres altså ikke noe forsøk på å optimalisere over flere basale blokker. Dermed, om en ikke har noen neste bruk i blokka, så er det ingen fordeler med å la den ligge i et register (men om den er i live må man sørge for at verdien ligger i hjemmeposisjonen). (NB: Ordet hjemmeposisjon er ikke brukt i boka. Der snakker man heller om å ha variabel-verdier i et register, og to store them, når de må kopieres til sin variabel-posisjon.)
Oppgave 5 a) a) Oversett (pr hånd) følgende setning til TA-kode: if a<b (c>d && e>=f) then x=8 else y=5 endif Oversett den til kode der alle hopp blir så direkte som over hodet mulig (uten å tenke på algoritmen for å gjøre det). SVAR: t1 = a < b if_true t1 goto 1 // Vi vet at uttrykket er sant t2=c>d if_false t2 goto 2 // Vi vet at uttrykket er galt t3 = e >= f if_false false t3 goto 2 // Vi vet at uttrykket er galt, ellers er det sant og vi fortsetter label 1 x = 8 goto 3 label 2 y = 5 label 3
Oppgave 5 b) b) Forsøk å tenke ut kodegenererings-algoritmer som kunne generere slik kode, f.eks. for setningen over. SVAR: Hovedsaken med den koden som er angitt i 5 a) er altså at man aldri beregner den logiske verdien på hele det boolske uttrykket, og at så fort man har nok informasjon til å vite om uttrykket blir true eller false, så hopper man direkte til den grenen der dette tilfellet skal behandles. Hvordan slik kode kan genereres vil avhenge veldig om vi bare skal ha symbolske labeler som vi kan velge fritt, eller om hoppene skal gå til faktiske fysiske adresser, f.eks. til der else-grenen starter (som ikke er kjent når det boolske uttrykket behandles). Det første kommer på neste foil, men det siste tilfellet ll er mest fiklete: Da kan man generere hopp med tomme adresser der man vet det skal inn hopp til f.eks. en else-gren, og det kan for samme else-gren bli mange slike hopp etter hvert. Man må da holde lister med adressene til alle de hopp som skal gå for eksempel til then-grenen og til else-grenen, og når vi en gang kommer til disse grenene (og vet deres start-adresse) må man gå tilbake i listen og sette inn adressen i alloe de rette hopp-instruksjonene. Merk at man da også må være nøye med om det er på true eller false man skal hoppe
Mer 5b: Vi skal lage tekstlig P-kode, og la oss inspirere av (den gamle) foilen under Hit skal en break i kildeprogrammet gå Om man kommer til break skal man void gencode(treenode t, String label){ gå ut av nærmete omsluttende while- String lab1, lab2; setning (angitt av label-parameteren) if t!= null{ // Er vi falt ut av treet? switch t.kind { case ExprKind { // I boka (forrige foil) er det veldig forenklet. // Kan behandles slik uttrykk er behandlet tidligere case IfKind { // If-setning gencode(t.child[0], label); // Lag kode for det boolske uttrykket lab1= genlabel(); emit2( fjp, lab1); // Hopp til mulig else-gren, eller til slutten av for-setning gencode(t.child[1], label); // kode for then-del, gå helt ut om break opptrer (inne i uttrykk??) if t.child[2]!= null { // Test på om det er else-gren? lab2 = genlabel(); emit2( ujp, lab2); // Hopp over else-grenen emit2( label, lab1); // Start på else-grenen, eller slutt på if- setningen if t.child[2]!= null { // En gang til: test om det er else-gren? (litt plundrete programmering) gencode(t.child[2], label); // Kode for else-gren, gå helt ut om break opptrer emit2( lab, lab2); // Hopp over else-gren går hit case WhileKind { /* mye som over, men OBS ved indre break. Se boka og forrige foil */ case BreakKind { emit2( ujp, label); // Hopp helt ut av koden dette gencode-kallet lager // (og helt ut av nærmest omsluttende while-setning) 11
Mer 5b: Genere P-kode for boolske uttrykk Men heller ikke denne vil lage helt god kode! Hvorfor?? (se helt nederst) void genboolcode(string labt, labf) { For : case : { String labx = genlabel(); left.genboolcode(labt, labx); emit2( label, l labx); right.genboolcode(labt, labf) case && : { String labx = genlabel(); left.genboolcode(labx, labf); emit2( label, labx); right.genboolcode(labt, labf); case not : { // Har bare left -subtre left.genboolcode(labf, labt); // Ingen kode!!! case < : { left false false right labx labf true true labt labt left.genintcode(); // Antar at det er heltall som sammenliknes, svaret til stakk-toppen right.genintcode(); // Som over emit1( lt ); // P-instr som sammenlikner (og popper) toppene og pusher på svaret emit2( fjmp, labf); emit2( ujp, labt); // Denne er unødvendig dersom det som følger etter er labt // Dette kan vi oppdage med en ekstra parameter som angir labelen bak // den konstrusksjonen man kaller kodegenererings-metoden for. 12
Mer 5b: Kodegenerering for If-setning Vi lager behandlingen av if-setning ved bare å fikse på den fra for to foiler siden Vi trenger da ingen label-parameter l på behandlingen av if-setningen i Men må gi med parametere til metoden som behandler det boolske uttrykket case IfKind { String labt = genlabel(); // Skal hoppes til om, betingelse er True String labf = genlabel(); // Skal hoppes til om, betingelse er False genboolcode(t.child[0], labt, labf); // Lag kode for det boolske uttrykket, med parametere // emit2( fjp, lab1); // Hopp til mulig else-gren, eller til slutten av for-setning NÅ UNØDVENDIG! emit2( lab, labt); // Ny! True-hopp fra uttykket skal gå hit gencode(t.child[1]); // kode for then-gren (nå uten label-parameter) String labx = genlabel(); // Skal angi slutten av if-setningen, etter else-grenen if t.child[2]!= null { // Test på om det er else-gren? emit2( ujp, labx); // Hopp over else-grenen emit2( label, labf); // False-hopp fra uttykket skal gå hit if t.child[2]!= null { // En gang g til: test om det er else-gren? (litt plundrete programmering) g) gencode(t.child[2]); // Kode for else-gren (nå uten label-parameter) emit2( lab, labx); // Hopp over else-gren går hit 13