KoporShow Creative Commons License 2005.02.05 0 0 214
C-ben bool helyett altalaban int-et hasznalnak. Minden nemnulla ertek igazat jelent es csak a nulla hamis.

Elönyösebb a maszkot eltolni, igy a fordito optimalis kodot tud generalni, amelyben egyaltalan nem lesz eltolas:

if ( input & (1<<5)) { ... }

A blokkot akkor hajtja vegre, ha az input valtozo 5-ik bitje 1.

Szerintem abbol lehet kiindulni, hogy optimalizalt modban a fordito a assembler hasonlo minösegü kodot fog generalni. Szerintem assemblert gyakorlatilag csak extrem kiveteles körülmenyek között erdemes hasznalni. Ha leakarod ellenörizni a generalt kodot, akkor a "-S" kapcsoloval kell forditani. Az assembler file neve ".s"-re fog vegzödni.

Peldaul a kovetkezo fuggveny 1-et ad vissza, ha az input parameter 5-ik bitje 1, egyebkent 0-at.

unsigned f(unsigned input) { return input & (1<<5) ? 1 : 0; }

A gcc a kovetketo kodot generalja:

pushl %ebp
movl %esp, %ebp
movl 8(%ebp), %eax
shrl $5, %eax
andl $1, %eax
popl %ebp
ret

Ami egy meglepöen intelligens valasz, hiszen a felteteles ugrast önmagatol atalakitotta egy eltolasse es egy es-operaciova. Ez altalaban gyorsabb, mert a modern architekturakban minden feltetes ugras jelentösen lassithatja a programfutast, mert a processzor a pipeline miatt jump-prediction-t hasznal, ami ha nem jön be alapvetöen lassabb mint jopar müvelet vegrehajtasa.

A fenti megoldas persze csak ebben a specialis esetben lehetseges, amennyiben pl. lebegöpontos szamot adnank vissza, itt a fenti trükk nem müködik:

double f(unsigned input) { return input & (1<<5) ? 1.0 : 0.0; }

( -O3 agressziv optimalizalassal forditva a következö kodot adja:)

pushl %ebp
movl %esp, %ebp
testb $32, 8(%ebp)
je .L2
fld1
.L3:
popl %ebp
ret
.p2align 4,,7
.L2:
fldz
jmp .L3

Itt lathatjuk, hogy most megörizte a 32-vel törtenö maszkolast (tehat az 1<<5 müveletet forditasi idöben elvegezte), valamint kihasznalta a tehat megint eleg jo kodot generalt.

Utoljara nezzük meg, hogy mi törtenik, ha az a következö evvel ekvivalens, de kisse szuboptimalisabb kodot forditjuk (elöször az inputot balra toljuk aztan maszkolunk):

double f(unsigned input) { return ((input >> 5) & 1)? 1.0 : 0.0; }

Eredmeny:

pushl %ebp
movl %esp, %ebp
testb $32, 8(%ebp)
je .L2
fld1
.L3:
popl %ebp
ret
.p2align 4,,7
.L2:
fldz
jmp .L3

Azaz ugyanaz mint az elöbb, megint nem törtenik eltolas futasidöben!

A tanulsag: nem erdemes tul sokat agyalni alacsony szintü trükkökön, a fordito jo esellyel megtalalja az optimalis megoldast, talan jobbat meg jobbat is, mint ami a programozonak eszebe jutna. Erdemes inkabb a magasabb szintü algoritmikus kerdesekre koncentralni assembler tuningolas helyett.
Előzmény: thuram (213)