🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Thread View: pl.comp.lang.asm
7 messages
7 total messages Started by gupi manʼaʼgo Wed, 23 Sep 2009 03:08
nie widzi stanu flag po “sub”?
#2029
Author: gupi manʼaʼgo
Date: Wed, 23 Sep 2009 03:08
67 lines
2892 bytes
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;
}
❞
⁂
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”?
⁂
PS   „drogie koleżanki i koledzy”…   aha, miało być na początku. ;->
-- 
/ qo   |)  :@=N%_g=v=a=g_eD_e=c()=d=8! =%!gN@8'Re. w8in/ad
\  _x/ ,  ;h-%-a'hA'H4,X0'Xo~xo~xO,R`-%EXp01ITed: *-7/+eh
/  |   ng `-%__%--'__%--'__%--~__%--^%B`/$qV3r[o; &GooMee
L_._o_O_*_^_"_'_`_ -> http://thereis.notlong.com <- `L"EnOF"
Re: nie widzi stanu flag po “sub”?
#2030
Author: Piotr Wyderski
Date: Wed, 23 Sep 2009 08:07
6 lines
1127 bytes
gupi manʼaʼgo wrote:

Zgłoś do bugzilli na stronie GCC.

    Pozdrawiam
    Piotr Wyderski
Re: nie widzi stanu flag po “sub”?
#2031
Author: Michoo
Date: Wed, 23 Sep 2009 09:37
56 lines
2434 bytes
gupi manʼaʼgo pisze:
> 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:
Nie, nie są równoważne.
> ❝
> void
> proc_1( struct s_t *s,
>     unsigned count
> )
> { if( s->n >= count )
>         s->n -= count;
>     else
>         s->n = 0;
> }
Ta funkcja zmniejsza wartość o maksymalnie count nie przekraczając 0.

> void
> proc_2( struct s_t *s,
>     unsigned count
> )
> { if(( s->n -= count ) > count )
>         s->n = 0;
> }
Ta funkcja zmniejsza wartość o count (dokonując ewentualnych "zawinięć" 
- typy są unsigned) a gdy wynik jest nadal większy od count to go 
zeruje. - w porównaniu z proc_1 nie zawsze ustawia 0 gdy było przejście 
przez 0 za to zawsze zeruje wynik gdy n>=2*count.

> 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”?
Kompilator wygenerował to co napisałeś.

> 1.   czy się mylę?
tak
> 3.   co zrobić, by zapis w ‟C” był ładny, a mimo to nie było nadmiarowej
> “cmp”?
Ale to zapis _pierwszej_ funkcji jest 'ładny'. Spojrzenie na nią od razu 
mówi jaki ma być efekt. Zapis drugiej funkcji imo jest przynajmniej 
nieintuicyjny - coś jak jak pisanie if(!strcmp(a,b)) zamiast 
if(strcmp(a,b)==0).

> PS   „drogie koleżanki i koledzy”…   aha, miało być na początku. ;->
P.S.
Skąd wziąłeś taki sposób formatowania?

-- 
Pozdrawiam
Michoo
Re: nie widzi stanu flag po “sub”?
#2032
Author: Bogdan (bogdro)
Date: Wed, 23 Sep 2009 15:56
86 lines
3634 bytes
gupi manʼaʼgo pisze:
> 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;
> }
> ❞
> ⁂
> 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ę?

 Wygląda na to, że nie.

> 2.   czy  kompilator robi to specjalnie ze względu na wewnętrzne działa-
> nie ‘cpu’, któremu pomaga w czymś ta instrukcja “cmp”.

 Raczej nie. Co prawda wtykanie instrukcji czasem może poprawić
wydajność kodu, ale w tym przypadku CMP faktycznie chyba jest
niepotrzebna.

> 3.   co zrobić, by zapis w ‟C” był ładny, a mimo to nie było nadmiarowej
> “cmp”?

 Po pierwsze, włącz optymalizacje, jeśli jeszcze tego nie zrobiłeś. Po
drugie, wypróbuj może wyrażenia warunkowe, np.

s->n = (s->n >= count)? s->n - count : 0;
s->n -= (s->n >= count)? count : s->n;

> 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”?

 Nie jest mi znany żaden sposób na wykonanie tego. Jak kompilator
miałby przenieść taki operator czy funkcję na architekturę, która nie
ma podobnych flag co x86?

-- 
Pozdrawiam/Regards - Bogdan                     (GNU/Linux & FreeDOS)
Kurs asemblera x86 (DOS, GNU/Linux):http://rudy.mif.pg.gda.pl/~bogdro
Grupy dyskusyjne o asm:  pl.comp.lang.asm alt.pl.asm alt.pl.asm.win32
www.JabberPL.org www.TorProject.org Soft (EN): miniurl.pl/bogdro-soft
Re: nie widzi stanu flag po “sub”?
#2034
Author: Bernard
Date: Thu, 24 Sep 2009 17:25
39 lines
1947 bytes
gupi manʼaʼgo wrote:
> 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;
> }
> ❞
> ⁂
> 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ę?

Mylisz się. SUB ustawia znaczniki stosownie do wyniku odejmowania, a Ty 
po odejmowaniu wykonujesz porównanie ze zmienną count, i korzystasz z 
wyniku tego porównania.

I strasznie paskudnie formatujesz ten kod w C...
Re: nie widzi stanu flag po “sub”?
#2035
Author: 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:#=
Re: nie widzi stanu flag po “sub”?
#2033
Author: gupi manʼaʼgo
Date: Fri, 25 Sep 2009 05:38
25 lines
2103 bytes
‟Bogdan (bogdro)” zaprogramował/a:
>> 3.   co zrobić, by zapis w ‟C” był ładny, a mimo to nie było
>> nadmiarowej “cmp”?
> 
>  Po pierwsze, włącz optymalizacje, jeśli jeszcze tego nie zrobiłeś. Po
> drugie, wypróbuj może wyrażenia warunkowe, np.
>
> s->n = (s->n >= count)? s->n - count : 0; s->n -= (s->n >= count)? count
> : s->n;
w poprawionej  formie —jak  w mojej  odpowiedzi na własny list do wszys-
tkich odpowiadających— dają ten sam wynik— oczekiwany.

>> 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”?
>
>  Nie jest mi znany żaden sposób na wykonanie tego. Jak kompilator
> miałby przenieść taki operator czy funkcję na architekturę, która nie ma
> podobnych flag co x86?
a to pytanie chyba pozostawię otwartym, oczywiście w rozumieniu go jako:
„jak pytać o znaczenie przepełnienia na maszynach, które mają je inne?”.
-- 
/ qo   |)    :@=N%_g=v=a=g_eD_e=c()=d=8! =%!gN@8'Re. w8in/ad
\    _x/ ,   ;h-%-a'hA'H4,X0'Xo~xo~xO,R`-%EXp01ITed: *-7/+eh
/    |    ng `-%__%--'__%--'__%--~__%--^%B`/$qV3r[o; &GooMee
L_._o_O_*_^_"_'_`_ -> http://thereis.notlong.com <- `L"EnOF"
Thread Navigation

This is a paginated view of messages in the thread with full content displayed inline.

Messages are displayed in chronological order, with the original post highlighted in green.

Use pagination controls to navigate through all messages in large threads.

Back to All Threads