Jesteśmy często mówią , że sprzęt nie obchodzi, co język program jest napisany w jak to widzi tylko skompilowany kod binarny, jednak nie jest to cała prawda. Weźmy na przykład pokornego Z80; jego rozszerzenia do zestawu instrukcji 8080 obejmują instrukcje takie jak CPIR, które są przydatne do skanowania ciągów typu C (zakończonych NULL), np. do wykonania strlen()
. Projektanci musieli zidentyfikować, że uruchamianie programów C (w przeciwieństwie do Pascala, gdzie długość łańcucha znajduje się w nagłówku) było czymś, do czego prawdopodobnie ich projekt mógłby zostać użyty. Innym klasycznym przykładem jest maszyna Lisp .
Jakie są inne przykłady? Np. Instrukcje, liczba i rodzaj rejestrów , tryby adresowania, które sprawiają, że dany procesor sprzyja konwencjom określonego języka? Szczególnie interesują mnie wersje tej samej rodziny.
sizeof(int)
równa się 1, musi wymagaćchar
podpisania tego typu (ponieważint
musi być w stanie pomieścić wszystkie wartości typuchar
). Pisałem kod na komputerze, na którymchar
iint
są zarówno 16-bitowe liczby całkowite podpisane; największe trudności polegają na tym, że nie można używać związków do konwersji typów, a wydajne przechowywanie dużej liczby bajtów wymaga ręcznego pakowania i rozpakowywania. Te problemy są niewielkie w porównaniu z możliwością w C, że sizeof (int) == sizeof (long), ponieważ ...unsigned int
wartościami. C99 poprawił tę sytuację, ale przed C99 nie było gwarantowanego bezpiecznego jednoetapowego sposobu porównania potencjalnie ujemnej wartości z wartością typuunsigned int
(trzeba by sprawdzić, czy liczba była ujemna przed wykonaniem porównania).Odpowiedzi:
Istniejące odpowiedzi koncentrują się na zmianach ISA . Są też inne zmiany sprzętowe. Na przykład C ++ często używa vtables do wywołań wirtualnych. Począwszy od Pentium M , Intel ma komponent „pośredniego predykatora gałęzi”, który przyspiesza wirtualne wywołania funkcji.
źródło
Zestaw instrukcji Intel 8086 zawiera odmianę „ret”, która dodaje wartość do wskaźnika stosu po usunięciu adresu zwrotnego. Jest to przydatne w przypadku wielu implementacji Pascala, w których funkcja wywołująca wypycha argumenty na stos przed wykonaniem wywołania funkcji, a następnie wyrzuca je. Jeśli procedura zaakceptuje np. Parametry o wartości czterech bajtów, może zakończyć się na „RET 0004”, aby wyczyścić stos. W przypadku braku takiej instrukcji, taka konwencja wywoływania prawdopodobnie wymagałaby, aby kod wrzucił adres zwrotny do rejestru, zaktualizował wskaźnik stosu, a następnie przeskoczył do tego rejestru.
Co ciekawe, większość kodu (w tym procedury systemu operacyjnego) na oryginalnym komputerze Macintosh używała konwencji wywoływania Pascala, pomimo braku instrukcji ułatwiającej w 68000. Korzystanie z tej konwencji wywoływania pozwoliło zaoszczędzić 2-4 bajty kodu w typowej witrynie wywoływania, ale wymagało dodatkowych 4-6 bajtów kodu w miejscu zwrotnym każdej funkcji, która pobierała parametry.
źródło
ENTER
odpowiednik tegoRET n
...ENTER
istniał w oryginalnym 8086; przyszedł z późniejszymi procesorami. Przywołuje to jednak interesujący punkt: tryby adresowania oparte na BP są wyraźnie zaprojektowane wokół użycia stosu parametrów i miejsc, do których można uzyskać dostęp za pomocą wskaźnika ramki. Uważam tę konwencję za interesującą na wiele sposobów, zwłaszcza biorąc pod uwagę, że (1) czysty kod języka asemblera jest bardziej skłonny do używania wartości w rejestrach niż na stosie, ale (2) zalety adresowania [BP + nn] nad [SP + nn] adresowanie jest bardziej znaczące dla programów w asemblerze, które uzyskują dostęp do rzeczy na stosie, niż ...Jednym z przykładów jest MIPS, który ma zarówno, jak
add
i odpowiednioaddu
pułapkę i ignorowanie przepełnienia. (Równieżsub
isubu
.) Potrzebował pierwszego rodzaju instrukcji dla języków takich jak Ada (myślę, że tak naprawdę nigdy nie użyłem Ady), które jawnie zajmują się przepełnieniami, a drugiego typu dla języków takich jak C, które ignorują przepełnienia.Jeśli dobrze pamiętam, rzeczywisty procesor ma dodatkowe jednostki obwodów w jednostce ALU do śledzenia przelewów. Gdyby jedynym językiem, na którym zależało ludziom, było C, nie potrzebowałoby tego.
źródło
nmemb*size+offset
bajty i musisz upewnić się, że nie zostanie przepełniony.addu
isubu
(te, które nie sprawdzają przepełnień) to te, które zostały dodane, aby uszczęśliwić C. Oczywiście tak naprawdę nie wiem - omawialiśmy to tylko niejasno podczas wykładu i na pewno nie jestem ekspertem od architektury: P.Seria Burroughs 5000 została zaprojektowana z myślą o wydajnej obsłudze ALGOL, a iAPX-432 Intela został zaprojektowany z myślą o wydajnym uruchamianiu Ady. Inmos Transputer miał swój własny język, Occam. Myślę, że procesor „śmigła” Parallax został zaprojektowany do programowania przy użyciu własnego wariantu BASIC.
To nie jest język, ale zestaw instrukcji VAX-11 ma jedną instrukcję ładowania kontekstu procesu, która została zaprojektowana na żądanie zespołu projektowego VMS. Nie pamiętam szczegółów, ale ISTR wymagało tak wielu instrukcji, aby wprowadzić poważny górny limit liczby procesów, które mogą zaplanować.
źródło
Jedną rzeczą, o której jak dotąd nikt nie wspominał, jest to, że postępy w optymalizacji kompilatora (gdzie język podstawowy jest w dużej mierze nieistotny) doprowadziły do przejścia z zestawów instrukcji CISC (które zostały w dużej mierze zaprojektowane do kodowania przez ludzi) na zestawy instrukcji RISC (które były w dużej mierze zaprojektowane do kodowania przez kompilatory).
źródło
Rodzina Motorola 68000 wprowadziła tryb automatycznego przyrostu , dzięki któremu kopiowanie danych przez procesor jest bardzo wydajne i kompaktowe.
[Zaktualizowany przykład]
to był jakiś kod c ++, który wpłynął na asembler 68000
zaimplementowane w konwencjonalnym asemblerze (pseudokod, zapomniałem poleceń asemblera 68000)
z nowym trybem adresu stało się coś podobnego
tylko dwie instrukcje na pętlę zamiast 4.
źródło
Komputer mainframe serii Z firmy IBM jest potomkiem IBM 360 z lat 60. XX wieku.
Podano tam kilka instrukcji, aby przyspieszyć programy COBOL i Fortran. Klasycznym przykładem jest
BXLE
- „Branch on Index Low or Equal”, który jest w większościfor
pętlą Fortrana lub COBOL-emPERFORM VARYING x from 1 by 1 until x > n
enkapsulowanym w pojedynczej instrukcji.Istnieje również cała rodzina spakowanych instrukcji dziesiętnych do obsługi arytmetyki stałoprzecinkowej dziesiętnej wspólnej w programach COBOL.
źródło
DO
pętlę FORTRAN .Wczesne procesory Intel miały następujące funkcje, z których wiele jest obecnie przestarzałych w trybie 64-bitowym:
Flaga znaku, znajdująca się w rejestrze stanu wielu procesorów, istnieje w celu łatwego wykonywania arytmetyki podpisanej ORAZ niepodpisanej.
Zestaw instrukcji SSE 4.1 wprowadza instrukcje przetwarzania ciągów, zarówno zliczanych, jak i zakończonych zerami (PCMPESTR itp.)
Mogę sobie również wyobrazić, że wiele funkcji na poziomie systemu zaprojektowano w celu zapewnienia bezpieczeństwa skompilowanego kodu (sprawdzanie limitu segmentów, bramki wywołań z kopiowaniem parametrów itp.)
źródło
Niektóre procesory ARM, głównie te w urządzeniach mobilnych, obejmują (d) rozszerzenie Jazelle, które jest sprzętowym interpretatorem JVM; bezpośrednio interpretuje kod bajtowy Java. JVM obsługujący technologię Jazelle może wykorzystać sprzęt do przyspieszenia wykonywania i wyeliminowania dużej części JIT, ale powrót do oprogramowania VM jest nadal zapewniony, jeśli nie można interpretować kodu bajtowego na chipie.
Procesory z taką jednostką zawierają instrukcję BXJ, która wprowadza procesor w specjalny „tryb Jazelle”, lub jeśli aktywacja jednostki nie powiodła się, jest to po prostu interpretowane jako normalna instrukcja rozgałęzienia. Urządzenie ponownie wykorzystuje rejestry ARM do utrzymania stanu JVM.
Następcą technologii Jazelle jest ThumbEE
źródło
O ile wiem, w przeszłości było to bardziej powszechne.
Istnieje sesja pytań, w której James Gosling powiedział, że są ludzie, którzy próbują stworzyć sprzęt, który mógłby lepiej radzić sobie z kodem bajtowym JVM, ale wtedy ci ludzie mogliby znaleźć sposób, aby to zrobić za pomocą zwykłego „generycznego” intel x86 (może kompilując kod bajtowy w jakiś sprytny sposób).
Wspomniał, że korzystanie z popularnego popularnego mikroukładu (takiego jak dane wywiadowcze) ma przewagę, ponieważ ma dużą korporację, która rzuca ogromne ilości pieniędzy na produkt.
Film warto sprawdzić. Mówi o tym w 19 lub 20 minucie.
źródło
Przeprowadziłem szybkie wyszukiwanie strony i wydaje się, że nikt nie wspomniał o procesorach opracowanych specjalnie do wykonywania Forth . Język programowania Forth jest oparty na stosie, zwarty i stosowany w systemach sterowania.
źródło
Intel iAPX CPU został zaprojektowany specjalnie dla języków oo. Jednak nie całkiem wyszło.
źródło
68000 miał MOVEM, który był najbardziej odpowiedni do wypychania wielu rejestrów na stos w jednej instrukcji, czego oczekiwało wiele języków.
Jeśli widziałeś MOVEM (MOVE Multiple) poprzedzający JSR (Jump SubRoutine) w całym kodzie, to ogólnie wiedziałeś, że masz do czynienia z kodem zgodnym z C.
MOVEM zezwalał na automatyczną inkrementację rejestru docelowego, umożliwiając każdemu użyciu dalsze układanie w stos na miejscu docelowym lub usuwanie ze stosu w przypadku automatycznego dekrementacji.
http://68k.hax.com/MOVEM
źródło
Architektura AVR firmy Atmel została całkowicie zaprojektowana od podstaw, aby nadawała się do programowania w C. Na przykład ta nota aplikacyjna jest bardziej szczegółowa.
IMO jest to ściśle związane z doskonałą odpowiedzią rockets4kids , przy czym wczesne PIC16 zostały opracowane do bezpośredniego programowania asemblera (łącznie 40 instrukcji), a późniejsze rodziny celowały w C.
źródło
Podczas projektowania koprocesora numerycznego 8087 dość często języki przeprowadzały matematykę zmiennoprzecinkową przy użyciu typu o najwyższej precyzji i tylko zaokrąglały wynik w celu uzyskania niższej precyzji, przypisując go do zmiennej o niższej precyzji. Na przykład w oryginalnym standardzie C sekwencja:
będzie promować
a
ib
abydouble
dodać je promowaćc
, abydouble
dodać go, a następnie zapisać wynik zaokrągla sięfloat
. Mimo że w wielu przypadkach kompilator szybciej generowałby kod, który wykonywałby operacje bezpośrednio na typiefloat
, łatwiej było mieć zestaw procedur zmiennoprzecinkowych, które działałyby tylko na typiedouble
, wraz z procedurami do konwersji na / odfloat
, niż mieć osobne zestawy procedur do obsługi operacji nafloat
idouble
. 8087 został zaprojektowany w oparciu o takie podejście do arytmetyki, wykonując wszystkie operacje arytmetyczne przy użyciu 80-bitowego typu zmiennoprzecinkowego [prawdopodobnie wybrano 80 bitów, ponieważ:Na wielu 16- i 32-bitowych procesorach szybsza jest praca z 64-bitową mantysą i osobnym wykładnikiem niż praca z wartością, która dzieli bajt między mantysą i wykładnikiem.
Bardzo trudno jest wykonać obliczenia, które są dokładne z pełną precyzją używanych typów numerycznych; jeśli ktoś próbuje np. obliczyć coś takiego jak log10 (x), łatwiej i szybciej jest obliczyć wynik z dokładnością do 100ulp typu 80-bitowego niż obliczyć wynik z dokładnością do 1ulp 64-bitowego typ, a zaokrąglenie pierwszego wyniku do 64-bitowej precyzji da 64-bitową wartość, która jest dokładniejsza niż druga.
Niestety, przyszłe wersje języka zmieniły semantykę działania typów zmiennoprzecinkowych; podczas gdy semantyka 8087 byłaby bardzo ładna, gdyby języki wspierały je konsekwentnie, jeśli zwracane
float
byłyby funkcje f1 (), f2 () itd. , wielu autorów kompilatora wziąłoby na siebielong double
alias 64-bitowego typu podwójnego zamiast 80-bitowego typu kompilatora (i nie zapewniają żadnych innych sposobów tworzenia 80-bitowych zmiennych) i do arbitralnej oceny czegoś takiego:na dowolny z poniższych sposobów:
Zauważ, że jeśli f3 i f4 zwracają te same wartości, co odpowiednio f1 i f2, oryginalne wyrażenie powinno wyraźnie zwracać zero, ale wiele z ostatnich wyrażeń może nie. Doprowadziło to do tego, że ludzie potępiali „dodatkową precyzję” 8087, mimo że ostatnie sformułowanie byłoby na ogół lepsze od trzeciego i - z kodem, który odpowiednio używał rozszerzonego podwójnego typu - rzadko bywało gorsze.
W międzyczasie Intel zareagował na trend języka (niefortunny IMHO) polegający na wymuszaniu zaokrąglania wyników pośrednich do precyzji operandów, projektując ich późniejsze procesory, tak aby faworyzować to zachowanie, ze szkodą dla kodu, który skorzystałby na zastosowaniu wyższej precyzja obliczeń pośrednich.
źródło
## How the stack changed the processor
i## How floating point changed the processor
), aby ludzie mogli uzyskać właściwe nastawienie podczas czytania i mniej prawdopodobne, że pomyślisz, że jesteś nieobecny w odpowiedziach lub odpowiedziach takie same (r podobne) odpowiedzi.