; Version en langage Assembleur fortement optimisée de FindIDAverage. ; utilise une boucle déroulée et plus efficacement le pointeur. SearchedForID equ 4 ;offsets des paramètres passés dans la BlockPointer equ 6 ;stack frame (saute BP empilé ;et l'adresse de retour) NextBlock equ 0 ;offsets du champ dans BlockHeader BlockCount equ 2 BLOCK_HEADER_SIZE equ 4 ;nombre d'octets dans BlockHeader ID equ 0 ;offsets du champ dans DataElement Value equ 2 DATA_ELEMENT_SIZE equ 4 ;nombre d'octets dans DataElement .model small .code public _FindIDAverage _FindIDAverage proc near push bp ;sauve la stack frame de l'appelant mov bp,sp ;pointe sur notre stack frame push di ;préserve les variables de registre C push si mov di,ds ;prépare pour SCASW mov es,di cld sub dx,dx ;IDMatchSum = 0 mov bx,dx ;IDMatchCount = 0 mov si,[bp+BlockPointer] ;pointeur sur le premier ;bloc mov ax,[bp+SearchedForID] ;ID recherché ; Recherche tous les blocs jusqu'à que soit trouvé le dernier bloc ; (celui dont le pointeur sur le prochain bloc est NULL). BlockLoop: ; Pointe sur la première entrée DataElement du bloc. lea di,[si+BLOCK_HEADER_SIZE] ; Recherche toutes les entrées DataElement du bloc ; et additionne les données de toutes les correspondances avec l'ID recherché. mov cx,[si+BlockCount] ;nombre d'éléments dans le ;bloc jcxz DoNextBlock ;saute le bloc s'il est vide mov bp,cx ;***la stack frame n'est ;plus disponible*** add cx,7 shr cx,1 ;nombre de répétitions de la boucle shr cx,1 ;déroulée= (BlockCount + 7) / 8 shr cx,1 and bp,7 ;génère le point d'entrée ;de la première shl bp,1 ;passe éventuellement partielle dans jmp cs:[LoopEntryTable+bp] ; la boucle déroulée align 2 LoopEntryTable label word dw LoopEntry8,LoopEntry1,LoopEntry2,LoopEntry3 dw LoopEntry4,LoopEntry5,LoopEntry6,LoopEntry7 M_IBL macro P1 local NoMatch LoopEntry&P1&: scasw ;avons-nous une correspondance avec l'ID? jnz NoMatch ;non ;nous avons une correspondance inc bx ;IDMatchCount++; add dx,[di] ;IDMatchSum += DataPointer->Value; NoMatch: add di,DATA_ELEMENT_SIZE-2 ;pointe sur le prochain ; élément ;(SCASW a déjà avancé de 2 octets) endm align 2 IntraBlockLoop: M_IBL 8 M_IBL 7 M_IBL 6 M_IBL 5 M_IBL 4 M_IBL 3 M_IBL 2 M_IBL 1 loop IntraBlockLoop ; Pointe sur le prochain bloc et continue si le pointeur n'est pas NULL. DoNextBlock: mov si,[si+NextBlock] ;récupère le pointeur sur le ; prochain bloc and si,si ;le pointeur est-il NULL? jnz BlockLoop non, continuons ; Calcule la moyenne de toutes les correspondances. sub ax,ax ;suppose que nous n'avons pas trouvé ; de correspondance and bx,bx jz Done ;nous n'avons pas trouvé ;de correspondance ;retourne 0 xchg ax,dx ;prépare la division div bx ;retourne IDMatchSum / IDMatchCount Done: pop si ;restaure les variables registre C pop di pop bp ;restaure la stack frame de l'appelant ret _FindIDAverage ENDP end