Produit scalaire via instructions simd (assembleur 80x86 64 bits)

Soyez le premier à donner votre avis sur cette source.

Vue 5 299 fois - Téléchargée 321 fois

Description

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

Codes Sources

A voir également

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.