Tabela liderów - Kompilacja JIT (Im niższa, tym lepiej)
- es1024 - 81,2 punktów (w tym działający kompilator!)
- Kieth Randall - 116 punktów
- Ell - 121 punktów
Tabela liderów - interpretowana (im niższa, tym lepiej)
- Martin Büttner - 706654 punktów (około 2 godzin).
- criptych - 30379 punktów (97 sekund)
Twoim zadaniem, jeśli zdecydujesz się to zaakceptować, jest napisanie możliwie najmniejszego interpretera kodu wirtualnego / VM. VM / interpreter używa małej architektury CISC (operacje mogą różnić się rozmiarem), z językiem określonym poniżej. Po zakończeniu należy wydrukować wartość 3 rejestrów procesora, aby udowodnić, że wydrukowano prawidłowe dane wyjściowe (3 126 900 366).
Kompilator
Jeśli chcesz wykonać własne testy, poniżej znajduje się kompilator. Możesz opublikować swoje testy wraz z odpowiedzią.
Specyfikacje „VM”
Maszyna wirtualna ma 3 32-bitowe rejestry integralne bez znaku: R0, R1, R2. Są one reprezentowane w postaci szesnastkowej jako 0x00, 0x01 i 0x02.
Obsługiwane są następujące operacje:
Format to [nazwa] [... operandy ...], [szesnastkowy kod operacji] [... operandy powtórzone ...]
- LOAD [rejestr] [wartość 4 bajtów], 0x00 [rejestr] [wartość 4 bajtów]
- PUSH [rejestr], 0x02 [rejestr]
- POP [rejestr], 0x03 [rejestr]
- ADD [rejestr, 1 bajt] [rejestr, 1 bajt], 0x04 [rejestr] [rejestr]
- SUB [rejestr, 1 bajt] [rejestr, 1 bajt], 0x05 [rejestr] [rejestr]
- MUL [rejestr, 1 bajt] [rejestr, 1 bajt], 0x06 [rejestr] [rejestr]
- DIV [rejestr, 1 bajt] [rejestr, 1 bajt], 0x07 [rejestr] [rejestr]
- JMP [linia kodu, 4 bajty], 0x08 [4 bajtowy numer linii kodu]
- CMP [rejestr, 1 bajt] [rejestr, 1 bajt], 0x09 [rejestr] [rejestr]
- BRANCHLT [linia kodu, 4 bajty], 0x0a [4 bajtowy numer linii kodu]
Niektóre uwagi:
- Powyższe operacje matematyczne sumują wartości 2 rejestrów, umieszczając dane wyjściowe w pierwszym rejestrze.
- CMP, operator porównania, powinien porównywać wartości 2 rejestrów i przechowywać dane wyjściowe w jakiejś wewnętrznej fladze (może to być specyficzne dla implementacji) do przyszłego wykorzystania w instrukcjach oddziału.
- Jeśli BRANCH zostanie wywołany przed CMP, chyba że BRANCHEQ zostanie wywołany, „VM” nie powinno się rozgałęziać.
- PUSH / POP nie zaskakuje push i pop numery ze stosu.
- Operatory skoku i rozgałęzienia skaczą do określonej operacji (wiersza kodu), a nie do adresu binarnego.
- Oddziały nie wykonują porównania. Zamiast tego wykonują dane wyjściowe z ostatniego porównania.
- Operatorzy rozgałęzień i skoków korzystają z systemu indeksowania numerów linii opartego na zerach. (Np. JMP 0 przeskakuje do pierwszej linii)
- Wszystkie operacje należy wykonywać na liczbach bez znaku, które przepełniają się do zera i nie zgłaszają wyjątku w przypadku przepełnienia liczb całkowitych.
- Dzielenie przez zero jest niedozwolone i jako takie zachowanie programu nie jest zdefiniowane. Możesz (na przykład) ...
- Awaria programu.
- Zakończ wykonywanie maszyny wirtualnej i zwróć jej bieżący stan.
- Pokaż komunikat „ERR: Dzielenie przez 0”.
- Zakończenie programu definiuje się, gdy wskaźnik instrukcji osiąga koniec programu (można założyć, że program nie jest pusty).
Dane wyjściowe Dane wyjściowe muszą być dokładnie takie (łącznie z nowymi wierszami)
R0 3126900366
R1 0
R2 10000
Punkty
Punkty są obliczane na podstawie następującego wzoru:Number Of Characters * (Seconds Needed To Run / 2)
Aby uniknąć różnic sprzętowych powodujących różne czasy, każdy test będzie uruchamiany na moim komputerze (i5-4210u, 8 GB pamięci RAM) na serwerze Ubuntu lub w systemie Windows 8, więc staraj się nie używać szalonego, egzotycznego środowiska wykonawczego, które kompiluje się tylko na Dual G5 Mac Pro z dokładnie 762,66 MB wolnej pamięci RAM.
Jeśli używasz specjalistycznego środowiska wykonawczego / języka, opublikuj link do niego.
- Dla zainteresowanych stron opublikowałem kod testowy (napisany w C #) tutaj: http://pastebin.com/WYCG5Uqu
Program testowy
Pomysł przyszedł stąd , więc użyjemy nieco zmodyfikowanej wersji ich programu.
Prawidłowe wyjście dla programu to: 3 126 900 366
W C:
int s, i, j;
for (s = 0, i = 0; i < 10000; i++) {
for (j = 0; j < 10000; j++)
s += (i * j) / 3;
}
W kodzie: [R0 jest reprezentatywne dla s, R1 dla j, R2 dla i]
LOAD R0 0
LOAD R2 0 <--outer loop value
LOAD R1 0 <--inner loop value
--Begin inner loop--
PUSH R1 <--push inner loop value to the stack
MUL R1 R2 <--(i*j)
PUSH R2
LOAD R2 3
DIV R1 R2 <-- / 3
POP R2
ADD R0 R1 <-- s+=
POP R1
PUSH R2
LOAD R2 1
ADD R1 R2 <--j++
POP R2
PUSH R2
LOAD R2 10000
CMP R1 R2 <-- j < 10000
POP R2
BRANCHLT 3 <--Go back to beginning inner loop
--Drop To outer loop--
LOAD R1 1
ADD R2 R1 <--i++
LOAD R1 10000
CMP R2 R1 <-- i < 10000
LOAD R1 0 <--Reset inner loop
BRANCHLT 2
W systemie binarnym / szesnastkowym:
0x00 0x00 0x00 0x00 0x00 0x00
0x00 0x02 0x00 0x00 0x00 0x00
0x00 0x01 0x00 0x00 0x00 0x00
0x02 0x01
0x06 0x01 0x02
0x02 0x02
0x00 0x02 0x00 0x00 0x00 0x03
0x07 0x01 0x02
0x03 0x02
0x04 0x00 0x01
0x03 0x01
0x02 0x02
0x00 0x02 0x00 0x00 0x00 0x01
0x04 0x01 0x02
0x03 0x02
0x02 0x02
0x00 0x02 0x00 0x00 0x27 0x10
0x09 0x01 0x02
0x03 0x02
0x0a 0x00 0x00 0x00 0x03
0x00 0x01 0x00 0x00 0x00 0x01
0x04 0x02 0x01
0x00 0x01 0x00 0x00 0x27 0x10
0x09 0x02 0x01
0x00 0x01 0x00 0x00 0x00 0x00
0x0a 0x00 0x00 0x00 0x02
Punkty bonusowe (Efekty są stosowane multiplikacyjnie) Np. Jeśli zakwalifikujesz się do wszystkich trzech, będzie to ((znaki * 0,50) * 0,75) * 0,90
- 50% mniej, jeśli interpreter jest w rzeczywistości kompilatorem JIT
- Zmniejszenie o 25%, jeśli zastosuje jakiekolwiek rozwinięcie pętli / znaczącą optymalizację.
- 10% mniej, jeśli rozszerzysz maszynę wirtualną o
- BRANCHEQ [linia kodu, 4 bajty] (rozgałęzienie, jeśli jest równe - kod operacji 0x0b)
- BRANCHGT [linia kodu, 4 bajty] (rozgałęzienie, jeśli jest większe niż - kod operacji 0x0c)
- BRANCHNE [linia kodu, 4 bajty] (Rozgałęzienie, jeśli nie jest równe - kod operacji 0x0d)
- RLOAD [rejestr 1] [rejestr 2] (przenieś wartość rejestru 2 do rejestru 1 - kod operacji 0x01).
Niedozwolone
- Kompilowanie przypadku testowego w programie jest zabronione. Musisz zaakceptować kod bajtowy ze STDIN lub z pliku (nie ważne które).
- Zwracanie wyniku bez uruchamiania programu.
- W inny sposób możesz oszukać wymaganie maszyny wirtualnej.
CMP
sprawdza mniej niż lub równość? A co dzieje się z jego wynikiem?
MUL
i DIV
są również nieokreślone. Czy powinny być podpisane czy niepodpisane? Co dzieje się w przypadku przepełnienia mnożenia?