Generacja kodu docelowego Zagadnienia związane z generacją kodu Język wejściowy i wynikowy Zarządzanie pamięcią (adresacja) Wybór rozkazów maszynowych (koszty rozkazów) Przydział i wyznaczanie rejestrów Kolejność obliczeń Bloki bazowe lider pierwsza instrukcja, instrukcja bezpośrednio po skoku, cel skoku przekształcenia bloków bazowych zachowujące strukturę: usuwanie wspólnych podwyrażeń (common subexpression), usuwanie martwego kodu, zamiana nazw zmiennych tymczasowych, wymiana dwu niezależnych instrukcji sąsiednich algebraiczne O.Świda wg A.Aho,R.Sethi,J.Ullman 1
(1) r := 0 (2) i := 1 (3) t 1 := 4 * i (4) t 2 := a [ t 1 ] (5) t 3 := 4 * i (6) t 4 := b [ t 3 ] (7) t 5 := t 2 * t 4 (8) t 6 := r + t 5 (9) r := t 6 (10) t 7 := i + 1 (11) i := t 7 (12) if i <= 5 goto (3) (1) i := 0 (2) j := 0 Bloki bazowe i grafy przepływu (3) t1 := i * j (4) t2 := t1 * j (5) t3 := a [ t2 ] (6) t4 := j * j (7) t5 := t4 + i (8) t6 := b [ t5 ] (9) t7 := i * j (10) t8 := t7 + j (11) t9 := t3 * t6 (12) t10 := c [ t8 ] (13) t11 := t10 + t9 (14) c[t8] := t11 (15) t12 := j + 1 (16) j := t12 (17) if j < 5 goto (3) (18) t13 := i + 1 (19) i := t13 (20) if i < 5 goto (2) O.Świda wg A.Aho,R.Sethi,J.Ullman 2
Określanie ostatniego użycia zmiennej Bloki bazowe c.d każda zmienna opisywana jest przez parę [ status(żywa/martwa), linia ] przeglądamy instrukcje od końca (zmienne nietymczasowe są żywe przy wyjściu z bloku) w każdej linii i postaci x := y op z zapisujemy aktualny status oraz zapisujemy: x[martwa, ], y[żywa,i], z[żywa,i] w tablicy symboli Zmienne tymczasowe a informacja o używaniu zmiennych Directed Acyclic Graph reprezentacja bloku Liście etykietowane nazwami zmiennych lub stałych (z indeksem 0) Wierzchołki wewnętrzne posiadają: etykietę operatora, sekwencję identyfikatorów (aktualne wartości nazw) Przydatne do usuwania wspólnych podwyrażeń O.Świda wg A.Aho,R.Sethi,J.Ullman 3
Przykładowy kod Rejestry (R0,R1), pamięć dla zmiennych, Instrukcje: MOV, ADD,SUB,MULT (źródło, cel) t 1 := a + b t 2 := c + d t 3 := e t 2 t 4 := t 1 t 3 Zmiana kolejności instrukcji może polepszyć kod wynikowy MOV a, R0 ADD b, R0 MOV c, R1 ADD d, R1 MOV R0, t1 MOV e, R0 SUB R1,R0 MOV t1,r1 SUB R0,R1 MOV R1,t4 O.Świda wg A.Aho,R.Sethi,J.Ullman 4
Directed Acyclic Graph W(x) wskaźnik na ostatnio utworzony wierzchołek związany z x Dla każdej instrukcji postaci: (1) x := y op z lub (2) x := op y lub (3) x:=y jeżeli W(y)== undef (podobnie dla z w przypadku (1) ) W(y) = nowy wierzchołek o etykiecie y w sytuacji: (1) sprawdź, czy istnieje wierzchołek o etykiecie op,którego lewym dzieckiem jest W(y), a prawym W(z). W (2) podobnie. Jeżeli istnieje taki wierzchołek to oznacz go n, jeśli nie utwórz nowy. W przypadku (3) n=w(y) Usuń x z listy identyfikatorów wierzchołka W(x) i dodaj x do listy n. W(x) = n O.Świda wg A.Aho,R.Sethi,J.Ullman 5
Heurystyczne porządkowanie DAG oraz etykietowanie WW - zbiór niewypisanych wierzchołków wewnętrznych dopóki WW nie jest pusty: { n - niewypisany wierzchołek z wypisanymi rodzicami wypisz n dopóki skrajne lewe dziecko (m) dla n nie ma niewypisanych rodziców i nie jest liściem: { wypisz m n := m } } Jeżeli n jest liściem: lewostronnym - etykieta = 1 innym - etykieta = 0 w przeciwnym wypadku: n 1,n 2,n 3...n i dzieci uporządkowane wg etykiet etykieta = max i (etykieta(n i )+i-1) O.Świda wg A.Aho,R.Sethi,J.Ullman 6
Przykład generacji kodu gen(n): (0) if: n liść reprezentujący zmienną i lewostronne dziecko "MOV n, top(rejestry)" elseif: n wierzchołek wewnętrzny operatora OP (n 1,n 2 - dzieci) (1) if: et(n 2 ) == 0 ) "OP n 2, top(rejestry)" (2) elseif: 1 <= et(n 1 ) < et(n 2 ) oraz et(n 1 ) < rozmiar(rejestry) swap(rejestry); gen(n 2 ); R = pop(rejestry); ); "OP R,top(rejestry)" ; push(rejestry,r) swap(rejestry) (3) elseif: 1 <= et(n 2 ) <= et(n 1 ) oraz et(n 2 ) < rozmiar(rejestry) ); R = pop(rejestry); gen(n 2 ); "OP top(rejestry), R" push(rejestry,r) (4) else: gen(n 2 ); T = pop(temp); "MOV top(rejestry), T"; ); push(temp,t); "OP T, top(rejestry)" O.Świda wg A.Aho,R.Sethi,J.Ullman 7