🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Article View: pl.comp.lang.asm
Article #2035

Re: nie widzi stanu flag po “sub”?

#2035
From: gupi manʼaʼgo
Date: Fri, 25 Sep 2009 04:41
148 lines
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-mail
References: <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