Système : Distribution x86_64-linux-gnu
Procédure réalisant le produit scalaire de 2 matrices 4x4 d'entiers signés sur 16 bits. Le résultat de l'opération est une matrice 4x4 d'entiers signés sur 32 bits. Afin d'obtenir les meilleures performances en temps de calcul, nous utilisons les instructions SIMD (single instructions multiple data ; instruction unique à données multiples).
Source / Exemple :
.data # directive de création d'une zone de donnée
.align 8
m1: .word 0, 1, 2, 3
.word 4, 5, 6, 7
.word 8, 9, 10, 11
.word 12, 13, 14, 15
m2: .word 0, 4, 8, 12
.word 1, 5, 9, 13
.word 2, 6, 10, 14
.word 3, 7, 11, 15
m3: .long 0, 0, 0, 0
.long 0, 0, 0, 0
.long 0, 0, 0, 0
.long 0, 0, 0, 0
FormatString16: # pour les appels à printf
.string " %.3d"
FormatString32: # pour les appels à printf
.string " %.6ld"
RetourChariot:
.string "\n"
Annoncem1:
.string "matrice m1:\n"
Annoncem2:
.string "matrice m2:\n"
Annoncem22:
.string "matrice m2 pivotée:\n"
Annoncem3:
.string "m1 x m2 = \n"
.text # directive de création d'une zone d'instructions
.globl main # directive de création d'une étiquette
main: # main est l'adresse de début du programme
pushq $Annoncem1
call AfficheChaineSimple
pushq $m1
call AfficheMatrice16 # Affiche la première matrice
pushq $Annoncem2
call AfficheChaineSimple
pushq $m2
call AfficheMatrice16 # Affiche la deuxième matrice
pushq $m1
pushq $m2
pushq $m3
call ProduitScalaire
pushq $Annoncem22
call AfficheChaineSimple
pushq $m2
call AfficheMatrice16 # Affiche la deuxième matrice après
# inversion ligne/colonnes
pushq $Annoncem3
call AfficheChaineSimple
pushq $m3
call AfficheMatrice32 # Affiche la matrice résultat
movq $1,%rax # sélection de la fonction exit
# du système
xorq %rbx,%rbx # mise à zéro du 1er paramètre en
# utilisant xor, c'est à dire ou exclusif
int $0x80 # appel de l'interruption
# 128 -> GNU/Linux
fin: ret
ProduitScalaire:
movq 16(%rsp), %rdi # adresse de la deuxième matrice
pushq %rdi # pivote la 2e matrice pour avoir les
# vecteurs colonnes
call Pivote # en lignes
movq 8(%rsp), %rcx # adresse de la matrice produit
movq 16(%rsp), %rdi # adresse de la deuxième matrice
movq 24(%rsp), %rsi # adresse de la première matrice
movq $0, %rax # indice de la ligne de la première
# matrice
TraiteLigne:
movq $0, %rbx # indice de la ligne de la transposée
# de la seconde matrice
TraiteColonne:
movq (%rsi, %rax, 8), %mm0 # charge la ligne de la 1ere
# matrice dans mm0
movq (%rdi, %rbx, 8), %mm1 # charge la colonne de la 2e
# matrice (ou ligne de sa
# transposée) dans mm1
pmullw %mm1, %mm0 # %mm0 : partie basse du produit
# composante par composante
call SommeDesComposantes # rdx contient la somme des
# composantes 8 bits de %mm0
movw %dx, (%rcx) # copie du résultat dans la
# matrice produit
movq (%rsi, %rax, 8), %mm0 # charge la ligne de la 1ere
# matrice dans mm0
pmulhw %mm1, %mm0 # %mm0 : partie haute du produit
# composante par composante
call SommeDesComposantes # rdx contient la somme des
# composantes 8 bits de %mm0
shll $16, %edx # décale le résultat de 16 bits vers la
# gauche pour le mettre en partie haute
addl %edx, (%rcx) # ajoute la partie haute du résultat dans
# la matrice produit
addq $4, %rcx # pointe sur l'élément suivant à calculer
addq $1, %rbx # indice de colonne suivant
cmpq $4, %rbx # fin de colonne ?
jne TraiteColonne
movq $0, %rbx # on recommence à la colonne 0
addq $1, %rax # ligne suivante
cmpq $4, %rax # dernière ligne ?
jne TraiteLigne
ret $24
Pivote: movq 8(%rsp), %rsi # adresse de la matrice à pivoter
movq $0, %rax # indice de ligne (l)
movq $0, %rbx # indice de colonne (c)
TraiteElement:
cmpq %rax, %rbx
jbe ColSuivante # élément suivant si l<=c
movq %rsi, %rdi # on va échanger l'élément (l,c)
# avec l'élément (c,l)
addq %rax, %rdi
addq %rax, %rdi # rdi:base + l * 2
pushw (%rdi, %rbx, 8) # élément (l,c) -> pile
movq %rsi, %rdx
addq %rbx, %rdx
addq %rbx, %rdx # rdx:base + c*2
pushw (%rdx, %rax, 8) # élément (c,l) -> pile
popw %cx
movw %cx, (%rdi, %rbx, 8)# pile -> élément (l, c)
popw %cx
movw %cx, (%rdx, %rax, 8)# pile -> element (c ,l)
ColSuivante:
addq $1, %rbx
cmpq $4, %rbx
jne TraiteElement
movq $0, %rbx # retour à la colonne 0
addq $1, %rax # ligne suivante
cmpq $4, %rax
jne TraiteElement
ret $8
SommeDesComposantes:
pushq %rax # sauvegarde
pushq %rbx # sauvegarde
pushq %rcx # sauvegarde
movq $0, %rdx # la somme
movq %mm0, %rax
movb $4, %cl # boucle de cl=4 jusqu'à 0 exclu
Somme: movq %rax, %rbx
andq $0xFFFF, %rbx # mot 16 bits de poids faible
addq %rbx, %rdx # ajoute à %rdx
shrq $16, %rax # décale %rax de 16 bits vers la droite
subb $1, %cl # compteur
jne Somme
popq %rcx
popq %rbx
popq %rax
ret
AfficheMatrice16:
movb $4, %cl # indice colonne
movq 8(%rsp), %rsi # pointeur vers la matrice
TraiteLigne16:
movb $4, %ch # indice ligne
TraiteElement16:
movq $FormatString16, %rdi # pointeur vers la chaîne de
# formatage
movq $0, %rax # stdout
pushq %rcx # sauve rcx car modifié par la fonction printf
pushq %rsi # sauve rsi car utilisé comme paramètre par la
# fonction printf
movq $0, %rbx# pour ne récuperer qu'un octet dans %rsi
movw (%rsi), %bx # récupère le mot 16 bits à afficher
movq %rbx, %rsi # %rsi est le paramètre de donnée
# pour printf
call printf
popq %rsi
popq %rcx
addq $2, %rsi # element suivant de la matrice
subb $1, %ch # indice suivant
jnz TraiteElement16 # traite l'élément suivant dans la ligne
movq $RetourChariot, %rdi # pointeur vers la chaîne saut
# à la ligne
movq $0, %rax # stdout
pushq %rcx # sauve rcx car modifié par la fonction printf
pushq %rsi # sauve rsi car utilisé comme paramètre par la
# fonction printf
call printf # affiche un saut à la ligne
popq %rsi
popq %rcx
subb $1, %cl # ligne suivante
jnz TraiteLigne16
movq $RetourChariot, %rdi # pointeur vers la chaîne
# saut à la ligne
movq $0, %rax # stdout
call printf # affiche un saut à la ligne
ret $8
AfficheMatrice32:
movb $4, %cl # indice colonne
movq 8(%rsp), %rsi # pointeur vers la matrice
TraiteLigne32:
movb $4, %ch # indice ligne
TraiteElement32:
movq $FormatString32, %rdi # pointeur vers la chaîne
# de formatage
movq $0, %rax # stdout
pushq %rcx # sauve rcx car modifié par la
# fonction printf
pushq %rsi # sauve rsi car utilisé comme
# paramètre par la fonction printf
movq $0, %rbx # pour ne récuperer qu'un octet dans %rsi
movl (%rsi), %ebx # récupère l'octet à afficher
movq %rbx, %rsi # %rsi est le paramètre de donnée pour
# printf
call printf
popq %rsi
popq %rcx
addq $4, %rsi # element suivant de la matrice
subb $1, %ch # indice suivant
jnz TraiteElement32 # traite l'élément suivant dans la ligne
movq $RetourChariot, %rdi # pointeur vers la chaîne saut à
# la ligne
movq $0, %rax # stdout
pushq %rcx # sauve rcx car modifié
# par la fonction printf
pushq %rsi # sauve rsi car utilisé comme
# paramètre par la fonction printf
call printf # affiche un saut à la ligne
popq %rsi
popq %rcx
subb $1, %cl # ligne suivante
jnz TraiteLigne32
movq $RetourChariot, %rdi # pointeur vers la chaîne saut
#à la ligne
movq $0, %rax # stdout
call printf # affiche un saut à la ligne
ret $8
AfficheChaineSimple:
movq 8(%rsp), %rdi
movq $0, %rax
call printf
ret $8
Conclusion :
jourlin@pc-jourlin:~/Test/asm$ gcc produit.s
jourlin@pc-jourlin:~/Test/asm$ ./a.out
matrice m1:
000 001 002 003
004 005 006 007
008 009 010 011
012 013 014 015
matrice m2:
000 004 008 012
001 005 009 013
002 006 010 014
003 007 011 015
matrice m2 pivotée:
000 001 002 003
004 005 006 007
008 009 010 011
012 013 014 015
m1 x m2 =
000014 000038 000062 000086
000038 000126 000214 000302
000062 000214 000366 000518
000086 000302 000518 000734
Vous n'êtes pas encore membre ?
inscrivez-vous, c'est gratuit et ça prend moins d'une minute !
Les membres obtiennent plus de réponses que les utilisateurs anonymes.
Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.
Le fait d'être membre vous permet d'avoir des options supplémentaires.