IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

x86 32-bits / 64-bits Assembleur Discussion :

Optimiser une ligne de calcul en Assembleur


Sujet :

x86 32-bits / 64-bits Assembleur

  1. #1
    Membre confirmé Avatar de ALEX77
    Profil pro
    Inscrit en
    Juillet 2002
    Messages
    138
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2002
    Messages : 138
    Par défaut Optimiser une ligne de calcul en Assembleur
    Salut

    Je souhaiterais optimiser une simple ligne de calcul (qui est en fait appelée des milllions de fois dans une boucle) qui est la suivante :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    r:= r + Sqrt( Sqr(r1-r2)+Sqr(g1-g2)+Sqr(b1-b2) );
    Les variables r1,g1,b1,r2,g2,b2 sont des valeurs BYTE et r est une valeur DOUBLE.

    L'idée est de transformer cette ligne en une seule fonction ressemblant à cette-ci (en delphi) :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    function DistanceR(d : double; r1,g1,b1,r2,g2,b2 : byte) : double;
    asm
     FLD r1
     FSUB r2
    .
    .
    .
    end;
    Peut-on effectuer tout le calcul de cette ligne en une seule fonction de manière à ce que j'appelle ma fonction de la manière suivante :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    r:= DistanceR(r,r1,g1,b1,r1,g1,b1);
    Merci pour votre aide

  2. #2
    Rédacteur
    Avatar de Neitsa
    Homme Profil pro
    Chercheur sécurité informatique
    Inscrit en
    Octobre 2003
    Messages
    1 041
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Chercheur sécurité informatique

    Informations forums :
    Inscription : Octobre 2003
    Messages : 1 041
    Par défaut
    Bonjour,

    je ne connais pas trop le delphi donc je ne sais pas quelle taille fait un double dans ce langage (4 octets ou 8 ?)

    J'ai fais une proc MASM qui fais le calcul :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
     
    DistanceR PROC r:DWORD, r1:DWORD, r2:DWORD, g1:DWORD, g2:DWORD, b1:DWORD, b2:DWORD 
     
     
    	fninit
    	fild r2
    	fild r1
    	fsub st(0), st(1); r1 - r2
    	fsqrt; sqrt(r1 - r2)
     
     
    	fild g2
    	fild g1	
    	fsub st(0), st(1); g1 - g2
    	fsqrt; sqrt(g1 - g2)
     
     
    	fild b2
    	fild b1	
    	fsub st(0), st(1); b1 - b2
    	fsqrt; sqrt(b1 - b2)
     
     
    	fadd st(0), st(2)
    	fadd st(0), st(4)
     
    	fsqrt ; Sqrt( Sqr(r1-r2)+Sqr(g1-g2)+Sqr(b1-b2)
     
    	mov eax, [r]
    	fld qword ptr[eax]
    	fadd st(0), st(1) ;r + ...
     
    	ret
     
    DistanceR endp
    Que j'appelle comme cela :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    real REAL8 100.0
     
     
    .code
     
    start:
    invoke DistanceR, addr real, 20, 15, 40, 30, 80, 70
    Ici j'ai pensé que r (param en double) valait 8 octet donc je passe l'adresse de r, plutôt que r lui même.

    Deuxième point : ma proc MASM ne retourne rien : le résultat reste stocké dans st(0), ne sachant pas combien fait un double en delphi...

    Si tu sais combien d'octet fait le type double, je peux toujours retoucher le code.

  3. #3
    Membre chevronné Avatar de dapounet
    Profil pro
    Étudiant
    Inscrit en
    Juillet 2007
    Messages
    469
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Juillet 2007
    Messages : 469
    Par défaut
    Salut,

    Ce topic t'intéressera sûrement : http://board.flatassembler.net/topic.php?t=3978

  4. #4
    Membre confirmé Avatar de ALEX77
    Profil pro
    Inscrit en
    Juillet 2002
    Messages
    138
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2002
    Messages : 138
    Par défaut
    Merci pour ta réponse rapide Neitsa

    Dans Delphi, les DOUBLE sont sur 8 octets (64 bits) et les BYTE 1 octet il me semble.

    En fait je me suis inspiré d'un fonction que j'ai trouvé sur le site en delphi qui fait appel à de l'assembleur :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    Function SommeDouble(A,B:Double):Double;
    // [EBP+$10] contient A ( sur 8 octets )
    // [EBP+$08] contient B ( sur 8 octets )
    // ST0 contiendra le résultat
    Asm
      FLD  A
      FADD B
      WAIT
    End;
    donc si j'ai bien compris, c'est STO qui contient le résultat et qui l'assigne automatiquement au résultat de la fonction.

    Peux-tu me montrer avec le renvoi de résultat ?

    Merci pour ton aide

  5. #5
    Rédacteur
    Avatar de Neitsa
    Homme Profil pro
    Chercheur sécurité informatique
    Inscrit en
    Octobre 2003
    Messages
    1 041
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Chercheur sécurité informatique

    Informations forums :
    Inscription : Octobre 2003
    Messages : 1 041
    Par défaut
    Ne sachant pas comment Delphi se débrouille pour récupérer un résultat sur 8 octets provenant du FPU, j'ai rajouter un paramètre pour sauver le résultat.

    r : est passé par valeur
    Resultat : est un pointeur vers là où est sauvé... le résultat

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
     
    DistanceR PROC r:REAL8, r1:DWORD, r2:DWORD, g1:DWORD, g2:DWORD, b1:DWORD, b2:DWORD, Resultat:DWORD 
     
    	fninit
    	fild r2
    	fild r1
    	fsub st(0), st(1); r1 - r2
    	fsqrt; sqrt(r1 - r2)
     
     
    	fild g2
    	fild g1	
    	fsub st(0), st(1); g1 - g2
    	fsqrt; sqrt(g1 - g2)
     
     
    	fild b2
    	fild b1	
    	fsub st(0), st(1); b1 - b2
    	fsqrt; sqrt(b1 - b2)
     
     
    	fadd st(0), st(2)
    	fadd st(0), st(4)
     
    	fsqrt ; Sqrt( Sqr(r1-r2)+Sqr(g1-g2)+Sqr(b1-b2)
     
    	fld [r]
    	fadd st(0), st(1) ;r + ...
     
    	;sauvegarde 
    	mov eax, [Resultat]
    	fstp qword ptr [eax] ; le calcul est sauvé dans "resultat"
     
    	ret
     
    DistanceR endp
    Appel :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    .data?
    Result REAL8 ?
     
    .data
    real REAL8 100.0
     
    .code
    start:
     
    ;attention c'est l'adresse de "resultat" qui est passé, pas sa valeur !
     
    invoke DistanceR, real, 20, 15, 40, 30, 80, 70, addr Result
    Tu peux suivre le lien donné par Dapounet pour ce qui est de l'optimisation, FSQRT est connue pour être une instruction très lente. Par contre l'optimisation proposée (ceci dit très bien faite, je parle de la dernière sur la page) utilise les SSE, à tester avec CPUID donc.

  6. #6
    Membre confirmé Avatar de ALEX77
    Profil pro
    Inscrit en
    Juillet 2002
    Messages
    138
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2002
    Messages : 138
    Par défaut
    Merci pour ton code.

    En fait est-ton obligé d'avoir des DOUBLE pour les valeurs r,g,b ? Car ces valeurs sont des BYTE donc ils vont de 0 à 255 et sont codés sur 1 octets.

    Pourrais-tu modifier le code de manière à ce que la fonction renvoie toujours un résultat à virgule (DOUBLE) mais en n'utilisant que des BYTE ? R lui serait toujour DOUBLE.

    Je suis en train de modifier le code de ma fonction et d'essayer de comprendre comment l'intégrer dans Delphi. Mais lorsque l'essaye de faire

    Le compilateur me met une erreur car R1 étant BYTE les instructions FLD ne sont pas compatibles avec...

  7. #7
    Rédacteur
    Avatar de Neitsa
    Homme Profil pro
    Chercheur sécurité informatique
    Inscrit en
    Octobre 2003
    Messages
    1 041
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Chercheur sécurité informatique

    Informations forums :
    Inscription : Octobre 2003
    Messages : 1 041
    Par défaut
    Citation Envoyé par ALEX77 Voir le message
    Merci pour ton code.

    En fait est-ton obligé d'avoir des DOUBLE pour les valeurs r,g,b ? Car ces valeurs sont des BYTE donc ils vont de 0 à 255 et sont codés sur 1 octets.

    Pourrais-tu modifier le code de manière à ce que la fonction renvoie toujours un résultat à virgule (DOUBLE) mais en n'utilisant que des BYTE ? R lui serait toujour DOUBLE.

    Je suis en train de modifier le code de ma fonction et d'essayer de comprendre comment l'intégrer dans Delphi. Mais lorsque l'essaye de faire

    Le compilateur me met une erreur car R1 étant BYTE les instructions FLD ne sont pas compatibles avec...
    Dans mon code les valeurs r,g,b sont des entiers non signées (4 octets) mais pas des nombres à virgules flottantes.

    Comme tu le soulignes, j'ai utilisé cette taille car FLD et autres instructions ne prennent au minimum qu'un opérande à 4 octets.

    Il serait théoriquement possible de passer un pointeur sur BYTE (ce qui j'imagine contraindrait le type en Delphi) et comme l'assembleur n'est absolument pas typé (au moins pour les pointeurs), il suffirait de prendre la valeur pointée qui serait "transformée" en une valeur à 4 octets. C'est juste que ça va ajouter des instructions - donc ralentir l'exécution - et rendre le code légèrement plus complexe/verbeux...

    En imaginant que r1 et r2 soit des pointeurs sur byte.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    	fninit
    	mov eax, [r2]
    	fild eax
    	mov eax, [r1]
    	fild eax
    	fsub st(0), st(1); r1 - r2
    	fsqrt; sqrt(r1 - r2)
     
            ...

  8. #8
    Membre confirmé Avatar de ALEX77
    Profil pro
    Inscrit en
    Juillet 2002
    Messages
    138
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2002
    Messages : 138
    Par défaut
    En tout cas merci pour ton code, la première solution avec que des DOUBLE (DWORD) me parait la plus rapide. @ +

Discussions similaires

  1. Total : une ligne, plusieurs calculs
    Par ptikiki dans le forum Cognos
    Réponses: 8
    Dernier message: 26/11/2013, 15h43
  2. [XL-2007] erreur de compilation d'une ligne de calcul
    Par amauri dans le forum Macros et VBA Excel
    Réponses: 2
    Dernier message: 26/06/2012, 12h57
  3. Réponses: 9
    Dernier message: 28/01/2011, 18h04
  4. Paramétrage d'une ligne de calcul
    Par kwatz dans le forum MATLAB
    Réponses: 7
    Dernier message: 13/03/2009, 14h41
  5. Simplifier une ligne de calcul
    Par lilyla dans le forum MATLAB
    Réponses: 7
    Dernier message: 18/01/2008, 10h41

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo