MMX avec Delphi 6 / Kylix

Les instructions MMX (MultiMedia eXtended) sont des instructions sensées faciliter les traitements multimédia. Ces instructions sont apparues pour la première fois sur les Pentium MMX et sont présentes depuis sur toutes la gamme des microprocesseurs Intel à l'exception du Pentium Pro. Ces instructions sont aussi disponibles sur les produits concurrents.

Article lu   fois.

L'auteur

Site personnel

Liens sociaux

Viadeo Twitter Facebook Share on Google+   

En quoi consistent ces instructions ?

Elles permettent de traiter plusieurs calculs sur les nombres entiers simultanément au lieu de un à la fois avec les instructions classiques. Ceci peut être particulièrement intéressant lorsque vous faites du traitement d'image et que vous devez effectuer les mêmes opérations sur l'ensemble des points de l'image.

Comment les exploiter ?

C'est là que commencent les difficultés. Lorsque vous compilez un programme, Delphi prend votre code Pascal et le transforme en instructions pour le microprocesseur (vous pouvez voir le résultat dans la fenêtre CPU). Mais il n'utilise jamais les instructions MMX, d'une part pour des raisons de compatibilité avec la plate-forme i386, d'autre part parce qu'en Pascal, nous ne codons des opérations que de façons séquentielle alors que les instructions MMX effectuent un traitement parallèle. La seule solution pour exploiter les possibilités MMX est de "court-circuiter" le compilateur et d'indiquer directement les instructions que nous voulons utiliser. En d'autres termes, travailler en ASSEMBLEUR. En assembleur, nous écrivons les instructions microprocesseurs à l'aide de séquences mnémotechniques qui sont directement traduites en binaire. Le Pascal Objet dispose de BASM (Built-in ASseMbler) qui permet d'inclure de l'assembleur dans le code pascal. Sauf que jusqu'à Delphi 5 inclus, BASM ne connaissait pas les mnémotechniques correspondants aux instructions MMX. Il fallait réaliser soi même le codage en binaire. Maintenant Delphi 6 et Kylix prennent en charge les instructions MMX. Il n'y a donc plus qu'à les saisir en assembleur et tout va bien.

Il reste à connaître les instructions utilisables. La première étape obligatoire est de récupérer la liste des instructions chez Intel sous le nom de Instruction Set Refernce Manual. Vous récupérez une petite documentation au format pdf de 6,7 Mo et d'un millier de pages. Pour reconnaître les instructions MMX, prenez plutôt celles qui commencent par un P comme Packed, qui travaillent sur des paquets de données.

Allons du côté de Packed Add:
Vous avez trois instructions différentes PADDB/PADDW/PADDD. Elles permettent d'additionner deux séries, dans l'ordre, soit de 8 bytes (PADDByte), soit de 4 words (PADDWord), soit de 2 doubleword (PADDDoubleword). Nous remarquons au passage que ces instructions utilisent des registres spéciaux, les registres MMX. Ces registres, qui sont au nombre de 8 (de mm0 à mm7) ont une dimension de 64 bits. En fait, ce sont les registres ST pour les opérations sur les nombres à virgule flottante et on ne peut pas utiliser simultanément les opérations MMX et celles sur les nombres à virgule flottante.

Passons à la pratique. J'ai voulu essayer l'addition simultanée de 4 entiers 16 bits. Voici le code :

 
Sélectionnez

type 
  T16bit = array[0..3] of word; // tableau de 4 entiers 16 bits 
procedure AdditionMMX(A,B : T16bit; var resultat : T16bit); register; 
// adresse de A dans EAX 
// adresse de B dans EDX 
// adresse de resultat dans ECX 
asm 
  movq mm0,[EAX] // on met le tableau A dans le registre mm0 
  paddw mm0,[EDX] // on lui additionne le contenu du tableau B word par word 
  movq [ECX],mm0 // on renvoie le résultat dans resultat 
end;

Et voilà, trois instructions pour quatre additions, transfert des données compris. Et ça marche.

Pour compliquer, j'ai voulu programmer la multiplication. Il y a un petit problème avec la dimension des paramètres. Je décide de réaliser la multiplication de bytes pour obtenir des words.

 
Sélectionnez

type 
  T8bit = array[0..3] of byte; 
  T16bit = array[0..3] of word; 
procedure MultiplicationMMX(A,B : T8bit; var resultat : T16bit); register; 
// A dans EAX (et non l'adresse)  
// B dans EDX 
// adresse de resultat dans ECX 
asm 
  pxor mm0,mm0 // mise à 0 
  movd mm1,EAX // déplacement du contenu du tableau A dans la partie basse de mm1 
  PUNPCKLBW mm1,mm0 // on intercale des 0 dans mm1 pour passer de 8 en 16 bits 
  movd mm2,EDX // déplacement du contenu du tableau B dans la partie basse de mm2 
  PUNPCKLBW mm2,mm0 // on intercale des 0 dans mm1 pour passer de 8 en 16 bits 
  PMULLW mm1,mm2 // multiplication de mm1 par mm2, word par word 
  movq [ECX],mm1 // on renvoie mm1 dans resultat 
end;

Nous voyons en particulier l'étape d'extension des données 8 bits en 16 bits.

Le code source de l'ensemble avec les mêmes opérations avec et sans MMX est ici (3 ko). Vous remarquerez un petit détail :

 
Sélectionnez

asm 
  EMMS // désactivation des registres MMX, à faire avant tout calcul sur les réels 
end;

Comme signalé plus haut, il y a incompatibilité en les instructions MMX et celles sur virgule flottante. Il faut donc désactiver l'unité MMX avant d'effectuer une opération FP, en l'occurrence l'affichage du temps écoulé. Dans l'autre sens (FP -> MMX), ce n'est pas nécessaire, le compilateur mettant d'office un FWAIT en sorti des opérations sur virgule flottante.

Point de vue performances, le recours aux instructions MMX permet de multiplier la vitesse d'un facteur compris entre 4 et 5 aussi bien pour les additions que pour les multiplications. Donc, les instructions MMX sont efficaces. Reste à les utiliser en conditions réelles :))) Ce qui est fait dans mon nouvel article.

Sinon, sachez que Delphi 6 et Kylix prennent aussi en charge d'autres jeux d'instructions SIMD (single intruction multiple datas = une seule intructions, plusieurs données). Il en va ainsi des instructions SSE et SSE2 (calcul simultané sur plusieurs réels) apparues avec les Pentium III et 4 chez Intel et reprises pour les premières par l'Athlon 4 chez AMD. On retrouve aussi les instructions 3D Now! (à partir du K6-2) et Extended 3D Now! (Athlon) de chez AMD (même principe que SSE) et quelques autres détails. Un article présente l'utilisation de ces instructions.

Pour terminer, sachez que les instructions MMX ont été étendues aux registres SSE avec le jeu d'instruction SSE2. Comme les regsitres correspondants sont deux fois plus grands, vous pouvez traiter deux fois plus de données avec les mêmes instructions.

Vous avez aimé ce tutoriel ? Alors partagez-le en cliquant sur les boutons suivants : Viadeo Twitter Facebook Share on Google+   

Liste de mes articles :
Types énumérés, intervalle et ensemble
MMX avec Delphi 6 / Kylix
Préchargement de données dans le cache
MMX ( 2 ) avec Delphi 6 / Kylix
Instructions SIMD sur les réels
Internationaliser un projet Delphi
Installer D6 sous Windows 95
Tramage d'une image
Coder le PNG soi-même
Utiliser LibTiff avec Delphi
Ecrire une UDF FireBird avec Kylix

Ce document est issu de http://www.developpez.com et reste la propriété exclusive de son auteur. La copie, modification et/ou distribution par quelque moyen que ce soit est soumise à l'obtention préalable de l'autorisation de l'auteur.