Ucebnicovym zpusobem referenci k instrukcim pekne podava http://www.arl.wustl.edu/~lockwood/class/cs306/books/artofasm/toc.html jako rychla prirucka pri cteni assembleru vznikleho prekladem C kodu se pak muze osvedcit napr. http://www.acsu.buffalo.edu/~charngda/x86assembly.html http://en.wikibooks.org/wiki/X86_Assembly/X86_Architecture atd. (pozor na Intel vs. AT&T synaxi) Dulezite je pochopit, ze pro testy pouzivame instrukce test a cmp, ale priznaky procesoru nastavuji i instrukce jine, a na zaklade nastavenych priznaku pak muzeme provadet skoky, nastavovat registry nebo provadet "conditional moves". Suffixy popisujici kombinace priznaku pak maji dva alternativni zapisy, napr. "je" odpovida "jz"; v pripade instrukce cmp (odcitajici operandy) je totiz "equal" ekvivalentni "zero". Vyhoda druhe formy je, ze dava smysl i v jinych kontextech nez pri pouziti instrukce "cmp". Bohuzel ale GNU nastroje generuji suffixy vzdy v prvni forme, tedy nezbyva nez zvyknout si. Podivejte se na http://pasky.or.cz//vyuka/2012-DMI074/reseni/eras/tauferp.c Nejdriv se s kodem alespon zbezne seznamte. Jedna se o implementaci Erastothenova sita, ktera pro kazde potencialni prvocislo vyhrazuje jeden bit a vyuziva toho, ze kazde prvocislo muzeme zapsat jako 2k+1 pro nejake prirozene k. Pak posudte, ktera ze tri zakladnich fazi programu (inicializace, vyskrtavani nasobku, pocitani prvocisel) zabere kolik (radove) procent jeho doby behu. Mohla by se Vam hodit funkce get_timer() z aimkitu. A ted se zkusme podivat na program v assemblerove podobe (nejdrive bez optimalizaci, to je nejmene matouci forma). Mame tri zakladni moznosti: (a) gcc -Wall -O0 -fverbose-asm -S tauferp.c Problem je, ze v assemblerovem zdrojaku se obtizne orientuje. Diky takticky rozmistenym volanim get_timer() muzeme alespon ramcove navigovat, ale stejne tezko posoudime, ktera cast programu odpovida kterym instrukcim. (b) gcc -Wall -O0 -g -Wa,-a=tauferp.s -c tauferp.c Pomoci -Wa,... predame parametry GNU assembleru a nechame si vygenerovat tzv. "listing", ktery obsahuje krome assembleroveho zdrojaku i high-level language, neboli nase puvodni C. Aby tuto kombiaci mohl assembler vyrobit, musi mit k disposici debugovaci informace (parametr -g). (c) gcc -Wall -O0 -g -c tauferp.c objdump -d tauferp.o objdump --source -d tauferp.o Pomoci nastroje objdump se muzeme divat do jiz zkompilovaneho programu. Obsahuje-li binarni soubor i debugovaci informace a zdrojovy soubor je stale na stejnem miste disku jako pri kompilaci, umi objdump pomoci --source take prolnout (interleavovat) do disassemblove formy i puvodni C. Chceme-li porovnavat ruzne varianty assembleroveho zdrojaku jako vystupu z objdumpu, muze se nam hodit zaradit do pipeline neco, co odstrani vecne se menici offsety na zacatku radku, napr.: ... | sed 's/ [0-9a-f]*:/ xxx:/' | ... Zkuste se podivat (a pochopit), jak se prelozi: (i) limit = atoi(argv[1]); (ii) Test a vetev pro priad, ze limit<2. (iii) Zapisovani jednicky do sita. (iv) Cyklus pocitajici prvocisla. Zejmena (iii) bude velmi neefektivni, diky vypnutemu CSE se napr. index cteni ze sieve a zpetneho zapisu bude pocitat zvlast. Tedy (v) Srovnejte (iii) a (iv) s prekladem pouzivajicim -O3 -march=native. Mohou se Vam hodit treba nastroje vimdiff ci meld. Cyklus pocitajici prvocisla by sel jiste dale zoptimalizovat. Nyni pomoci instrukce lea spekulativne pocita novou hodnotu n a zaktualizuje ji (pomoci conditional move), pokud narazil na nulovy bit. Nebylo by efektivnejsi do n pricitat 1 ci 0 spoctene na zaklade extrahovaneho bitu? Nebo dokonce vzdy zpracovavat celou polozku pole sieve najednou? (vi) Zkuste cyklus zoptimalizovat (treba postupne podle dvou napadu uvedenych vyse) a zmerit dosazene zrychleni.