Article View: pl.comp.lang.asm
Article #2035Re: nie widzi stanu flag po “sub”?
From: gupi manʼaʼgo
Date: Fri, 25 Sep 2009 04:41
Date: Fri, 25 Sep 2009 04:41
148 lines
7834 bytes
7834 bytes
odpowiem tutaj niepojedynczo do odpisujących.
‟gupi manʼaʼgo” zaprogramował/a:
> mamy strukturę, której istotny fragment jak niżej:
> ❝
> struct s_t
> { // …
> unsigned n;
> // …
> };
> ❞
> mamy dwie równoważne w efekcie procedury jak niżej:
> ❝
> void
> proc_1( struct s_t *s,
> unsigned count
> )
> { if( s->n >= count )
> s->n -= count;
> else
> s->n = 0;
> }
> void
> proc_2( struct s_t *s,
> unsigned count
> )
> { if(( s->n -= count ) > count )
> s->n = 0;
> }
faktycznie druga procedura nie jest równoważna, czego nie zauważyłem po-
bieżnie patrząc w program z deasemblera, gdzie porównuje rejestr wyniko-
wy.
a historia powstania błędu jest bardzo prosta… :-)
oczywiście procedura druga powstała z kopii pierwszej, w której następ-
nie starałem się ·wyraziściej zapisać fakt· sprawdzania po przejściu wa-
rtości liczby przez zero i wkroczeniu od maksymalnej wartości liczby ca-
łkowitej bez znaku. niestety po zmienieniu znaku nierówności, podczas
modyfikowania wyrażenia po lewej stronie znaku nierówności wcisnąłem
przez pomyłkę klawisz “=”, który jest tuż przy klawiszu “-” na klawiatu-
rze. z tego powodu ;-) nie przeszedłem do poprawiania wyrażenia
po prawej stronie znaku nierówności ;-). widząc, że “s->n -= count”
jest właśnie wykonywane w pozytywnym bloku warunkowym, skasowałem
ten blok jako niepotrzebny, nie analizując już w tym momencie sensownoś-
ci całej instrukcji, lecz jedynie wartości wyrażeń cząstkowych. stąd
powstała procedura druga, która była częściowo prawdziwa dla mnie, po-
nieważ znałem proces jej powstawania, w którym wystarczyło usunąć znak
“=” i odtworzyć wszystkie pozostałe kroki od momentu jego pomyłkowego
wpisania.
czyli właściwie powinna ona wyglądać tak:
❝
void
proc_2( struct s_t *s,
unsigned count
)
{ if(( s->n - count ) > s->n )
s->n -= count;
else
s->n = 0;
}
❞
z takiej postaci powstaje oczekiwany przeze mnie program dla maszyny:
❝
<proc_2>:
8b 47 08 mov 0x8(%rdi),%eax
31 d2 xor %edx,%edx
29 f0 sub %esi,%eax
0f 42 d0 cmovb %eax,%edx
89 57 08 mov %edx,0x8(%rdi)
c3 retq
66 90 xchg %ax,%ax
❞
jakkolwiek —jak widać poniżej— kompilator wybrał optymalizację skoków
kończących procedurę jako lepszą niż korzystanie z instrukcji warunkowo
przenoszącej wartość do rejestru, kiedy —jak widać powyżej— wartość ode-
jmowania może być łatwo zgubiona z tego względu, że i tak wynik musi być
przeniesiony do pamięci, więc mamy z konieczności jedną wartość pośred-
nią, czyli rejestr kopiowany do pamięci.
kompilator wybrał tę optymalizację przypuszczalnie z powodu jego kroków
przetwarzania programu. innymi słowy— ‟gcc” nie mógł widzieć flag in-
strukcji “sub”, gdyż dla niego najpierw jest zamiana na wirtualny kod
maszyny, a później jest optymalizacja, stąd ‟gcc” ma takie flagi optyma-
lizacji dla wiersza poleceń jak te wyłączające podetapy przeszukiwania
wyrażeń pośrednich, a rejestr flag wydaje się być takim wyrażeniem poś-
rednim w sensie już posiadania oczekiwanego wyniku stanu flag.
> ❞
> ⁂
> co zrobić, by kompilator ‟gcc 4.3.2” zauważył, że po odejmowaniu instru-
> kcją “sub” ma flagi, które może wykorzystać zamiast umieszczać instruk-
> cje “cmp”?
> a może ja się mylę?
> ❝
> <proc_1>:
> 8b 47 10 mov 0x10(%rdi),%eax
> 39 f0 cmp %esi,%eax
> 73 08 jae 0f
> c7 47 10 00 00 00 00 movl $0x0,0x10(%rdi)
> c3 retq
> 29 f0 0: sub %esi,%eax
> 89 47 10 mov %eax,0x10(%rdi)
> c3 retq
> <proc_2>:
> 8b 57 10 mov 0x10(%rdi),%edx
> 29 f2 sub %esi,%edx
> 39 d6 cmp %edx,%esi # nadmiarowa?
> b8 00 00 00 00 mov $0x0,%eax
> 0f 43 c2 cmovae %edx,%eax
> 89 47 10 mov %eax,0x10(%rdi)
> c3 retq
> ❞
> ⁂
> może w takiej kolejności, jeśli można :-) :
> 1. czy się mylę?
> 2. czy kompilator robi to specjalnie ze względu na wewnętrzne działa-
> nie ‘cpu’, któremu pomaga w czymś ta instrukcja “cmp”.
> 3. co zrobić, by zapis w ‟C” był ładny, a mimo to nie było nadmiarowej
> “cmp”?
> 4. a jeśli nic nie da się zrobić łatwo :-) , to jak składniowo pytać
> w ‟C” o odpowiednią flagę bez użycia wstawek “asm”?
1. czyli czy się myliłem? wcisnąłem nadmiarowy klawisz podczas wpi-
sywania drugiej procedury, z której to pomyłki w kolejnych krokach pow-
stała błędna “proc_2”.
2. czy kompilator specjalnie wstawia “cmp”. jak widać po sekwencjach
instrukcji maszyny z deasemblera, na ujętych przypadkach— nie wygląda
na to. ale nie radzi sobie dobrze z zamianą kolejności “cmp” i “sub”
w przypadku ogólnym (“proc_1”). i nie można w zgodzie z prawdą w takim
wypadku powiedzieć, że „kompilator robi to co jest napisane”. ‟gcc”
nie ma możliwości wyłączenia optymalizacji nie naruszających granic in-
strukcji określonych w standardzie ‟C” bez wyłączenia optymalizacji in-
strukcji maszynowych. zresztą komu by to było potrzebne oprócz chcą-
cych mieć postać programu zgodną ze standardem ‟C” zamiast oczekiwaną
wykonawczo i efektywną. jednak w takim stanie rzeczy optymalizacja mó-
wi tylko o programie jako takim, a nie programie zgodnym ze standardem
‟C”.
3. ‚ładny’ zapis? nowa postać “proc_2”.
4. o flagę przepełnienia dla całkowitych bez znaku oczywiście można
pytać przy pomocy odejmowania nie zachowującego wartości
“a - b > a”, z czego można by zrobić nawet gotowe makropolecenia umożli-
wiające wykorzystanie cechy dopełniania do 2 na różnych typach liczb ca-
łkowitych i odejście od —wg mnie bezzasadnego— funkcyjnego (od języków
funkcyjnych) podejścia do programowania w ‟C”. :-)
⁂
mimo gburowatości niektórych odpowiedzi, udało się wykorzystać grupy dy-
skusyjne do rozmowy…? ;-] i to jeszcze na dwóch grupach. temat chyba
dobrze pasuje do obu? :-)
--
qo |) CPL<=dataDPL CPL==/>=codeDPL:conform'/nc';max=CPL! AV0ID bHp
_x/ , CPL<=TSS,gateDPL CPL>=/==dest_DPL:/(jmp&nc') ,RPL!- #GP -o0o
| ng __ -- __ -- __ -- __ -- __ -- __ -- __ -- __ -x86-, EV3RY o0o
,__ -- __ -- Current/Requested/DescriptorPrivilegeLevel C/R/DPL , d4y m:#=
Technical Details
Message-ID:
<h9hhlu$17vj$1@adenine.netfront.net>Path:
mbox-mo1.pugleaf.net!news-archive.icm.edu.pl!newsfeed.gazeta.pl!feed.news.interia.pl!news.nask.pl!news.nask.org.pl!newsfeed00.sul.t-online.de!t-online.de!news.glorb.com!news.netfront.net!not-for-mailReferences:
<h9c3fs$bi4$1@adenine.netfront.net>Show Full Headers
Complete Article Headers
Path: mbox-mo1.pugleaf.net!news-archive.icm.edu.pl!newsfeed.gazeta.pl!feed.news.interia.pl!news.nask.pl!news.nask.org.pl!newsfeed00.sul.t-online.de!t-online.de!news.glorb.com!news.netfront.net!not-for-mail From: gupi manʼaʼgo <2009czerwiec@inmail.sk> Newsgroups: pl.comp.lang.c,pl.comp.lang.asm Subject: Re: nie widzi stanu flag po “sub”? Date: Fri, 25 Sep 2009 04:41:36 +0000 (UTC) Organization: opRWTng Lines: 148 Message-ID: <h9hhlu$17vj$1@adenine.netfront.net> References: <h9c3fs$bi4$1@adenine.netfront.net> NNTP-Posting-Host: 66.230.230.230 Mime-Version: 1.0 X-Trace: adenine.netfront.net 1253853696 40947 66.230.230.230 (25 Sep 2009 04:41:36 GMT) X-Complaints-To: news@netfront.net NNTP-Posting-Date: Fri, 25 Sep 2009 04:41:36 +0000 (UTC) Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit