I... po miesiącu pracy następna wersja już jest! ;)
Najważniejsza zmiana: control flow graph!
Znaczy to ni mniej ni więcej, że kompilator dla każdej funkcji generuje graf przepływu sterowania (en.control flow graph
), wykonuje na nim parę magicznych sztuczek optymalizacyjnych (jeżeli jakieś są włączone ofc.), po czym dopiero pod koniec generuje bajtkod - czyli identycznie jak "zwykłe" kompilatory; (dla przypomnienia dodam, że wcześniej dane trzymane były po prostu w tablicy występujących po sobie wyrażeń (patrz pierwszy post w tym temacie), więc widać postęp ;]):
W związku z zaimplementowaniem CFG, doszło też parę nowych optymalizacji:
-propagacja stałych (włączane wraz z optymalizacjami -O2
)
-usuwanie (już) nieużywanych zmiennych oraz szeroko pojętego 'martwego kodu' (-O2
)
-optymalizacja rozgałęzień (if-ów) (-O3
)
Dla przykładu wszystkich trzech optymalizacji przedstawionych powyżej weźmy np.taki kod:
@("stdlib/stdio.ss")
use std;
function<int> main()
{
var<int> x = 6;
if (x%2 == 0)
{
if (x%3 == 0)
{
if (x%5 == 0)
println("2, 3, 5"); else
println("2, 3");
} else
println("2");
} else
{
if (x%3 == 0)
println("3"); else
println("neither");
}
return 0;
}
Sprawdza on, czy liczba x
jest podzielna przez 2
, 3
oraz 5
.
Graf przed optymalizacjami:
Graf po optymalizacjach:
Straciłem 3 dni na napisanie samego algorytmu optymalizacji branchy (ponieważ zawsze jak zaczął działać w jednym wypadku, crashował kompilator w innym), ale ostatecznie działa, co widać i można sprawdzić ;)
Inny przykład prosto z Wikipedii:
function<int> main()
{
var<int> a = 30,
b = 9 - a / 5,
c;
c = b * 4;
if (c > 10) {
c = c - 10;
}
return c * (60 / a);
}
Przed:
mniejsza o zbyt dużą ilość nawiasów, procedurka zamieniająca drzewko na string została napisana "na kolanie" w ciągu pięciu minut :P
Po:
Napisane przeze mnie algorytmy nie są idealne i nie wychwytują wszystkiego, co można zoptymalizować, np.:
var<int> i=5;
i++;
return i;
Pozostanie w takiej formie, a nie zostanie zoptymalizowane do return 6;
(jeszcze ;> Bo ofc.potem planuję to zaimplementować).
Podobnie, jak nie działają żadne optymalizacje w przypadku tablic, ale to i tak mały pikuś - w wolnym czasie wszystko się napisze ;)
Ulepszyłem ponadto nieco register-allocator; od teraz najczęściej używane wewnątrz funkcji zmienne lądują w rejestrach, a cała reszta na stosie. To jest wciąż lamerskie rozwiązanie, ponieważ np.w takim wypadku:
var<int> a=10;
foo(a);
var<int> b=0;
foo(b);
Zmienne a
oraz b
wylądują w dwóch osobnych rejestrach, chociaż właściwie mogłyby (ba! powinny) znajdować się w jednym; by to osiągnąć czeka mnie zabawa z kolorowaniem grafów ;P
Zmieniła się też maszyna wirtualna; od teraz - jak obiecałem miesiąc temu - jest to DLL-ka i posiada sensowny (imo) interfejs pomiędzy sobą, programem, który z niej korzysta oraz uruchamianym skryptem; więcej do poczytania (wraz z przykładem) tutaj: http://sscript.4programmers.net/wiki/SSVM/Używanie_biblioteki
Również i parę zmian tknęło samą Wiki - pobawiłem się z GeSHi i dodałem kolorowanie składni SScriptu (np.http://sscript.4programmers.net/wiki/String/strexplode) ;>
Zapraszam do pobierania, testowania, narzekania, dawania sugestii i jakie jeszcze tylko rzeczowniki można by tutaj wstawić ;>
https://raw.github.com/Piterolex/SScript-Editor/0.3.2-stable/build/Win32.zip