2017-10-12 15 views
0

Pouvez-vous me dire où je me trompe?calculer -2xy - 3z avec l'assemblage en ligne MSVC

J'ai besoin de calculer ceci dans l'assemblage en ligne -2xy - 3z.

int solution(int x, int y, int z) 
{ 
    x=4; 
    y=5; 
    z=2; 
    int result; 
    __asm 
    { 
     mov eax, -2 
     imul [x] 
     imul [y] 
     mov ebx, eax 
     mov eax, -3 
     imul [z] 
     sub eax, ebx 


     mov [result], eax  ; 
    } 
     assert(result == -2*x*y – 3*z); 
     printf("solution_for_grade_6(%d, %d,**strong text** %d) = %d\n", x, y, z, result); 
return result; 
+0

Pour quel processeur rédigez-vous l'ASM? En outre, quel type d'erreur obtenez-vous lorsque vous exécutez le code? D'autres informations aideront les autres à trouver la réponse plus rapidement. –

+0

Son pour IA-32. Je n'ai pas d'erreur, ça marche mais rien ne se passe sur la fenêtre. – konstantin97

+1

La seule erreur que je vois est que 'sub eax, ebx' devrait être' ajouter eax, ebx' puisque vous avez multiplié par '-3' et avez déjà fait la négation. Vous pouvez multiplier par '3' au lieu de' -3' et garder le 'sous eax, ebx' tel quel. –

Répondre

1

Ceci est ma cinquième solution (renvoie une valeur de 32 bits, j'ai supprimé les quatrième et troisième solutions erronées/UN-optimisées); il utilise seulement un IMUL; noter qu'ils ne pouvaient pas être> (1 < < 14) -1, abs (Z) doit être < (1 < < 29), les deux abs (X) & & abs (Y):

__asm 
{ 
/* INPUT: EAX= X    */ 
/*   EDX= Y    */ 
/*   EBX= Z    */ 
/* TEMP: EDX     */ 
/* OUTPUT: EAX= -2*xy-3*z)  */ 

NEG EAX 

IMUL EDX   /* EDX:EAX=-x*y */ 

ADD EAX,EAX  /* EAX=-2*x*y */ 

LEA EDX,[EBX+EBX] 
ADD EDX,EBX 
SUB EAX,EDX  /* EAX=-2*x*y-z*3 */ 

MOV [RESULT],EAX 
} 

Cette est ma deuxième solution (renvoie une valeur de 64 bits); il utilise seulement un IMUL; maintenant est optimisé. Notez que les deux abs (X) & & abs (Y) ils ne pouvaient pas être> (1 < < 30) -1. Je suis supposé ce résultat, dans ce cas, est un entier de 64 bits:

__asm 
{ 
/* INPUT: EAX= X    */ 
/*   EDX= Y    */ 
/*   EBX= Z    */ 
/* TEMP: ESI, EDI    */ 
/* OUTPUT: EDX:EAX= -(2*xy+3*z) */ 

IMUL EDX 

ADD EAX,EAX 
ADC EDX,EDX /* EDX:EAX=2*xy */ 

MOV ESI,EBX 
ADD ESI,ESI 
SBB EDI,EDI /* EDI:ESI=2*z */ 

ADD ESI,EBX 
ADC EDI,EDI /* EDI:ESI=3*z */ 

ADD EAX,ESI 
ADC EDX,EDI /* EDX:EAX=2*xy+z*3 */ 

NOT EAX 
NOT EDX 

ADD EAX,1 
ADC EDX,0 /* EDX:EAX=-(2*xy+z*3) */ 

LEA ESI,[RESULT] 
MOV [ESI],EAX 
MOV [ESI+4],EDX 
} 

Mais rappelez-vous que chacun des deux produits a un résultat de plus de 64 bits; dans l'assemblage (retourne une valeur de 96 bits):

; -2xy-3z=-(2*xy+3*z) 

; INPUT: EAX= X 
;  EDX= Y 
;  ECX= Z 

; TEMP: EDI, ESI, EBP 

; OUTPUT: EBX:EDX:EAX= -(2*xy+3*z) 

IMUL EDX 

ADD EAX,EAX 
RCL EDX,1 
SBB EBX,EBX ;EBX:EDX:EAX=2*xy 

MOV ESI,ECX 
ADD ESI,ESI 
SBB EDI,EDI 
MOV EBP,EDI ;EBP:EDI:ESI=z*2 

ADD ESI,ECX 
ADC EDI,EDI 
ADC EBP,EBP ;EBP:EDI:ESI=z*3 

ADD EAX,ESI 
ADC EDX,EDI 
ADC EBX,EBP ;EBX:EDX:EAX=2*xy+z*3 

NOT EAX 
NOT EDX 
NOT EBX 

ADD EAX,1 
ADC EDX,0 
ADC EBX,0 ;EBX:EDX:EAX=-(2*xy+z*3) 
+0

Cependant, vous devez sauvegarder/restaurer les registres EBX, ESI, EDI et EBP avant/après ce code si vous l'utilisez dans une fonction autonome ... –

+0

Ne pas utiliser push/pop pour sauvegarder/restaurer dans les instructions inline-asm. Laissez le compilateur faire cela pour vous s'il le faut. (Il peut ne pas après s'être inséré dans une fonction qui enregistre/restaure déjà ces regs, mais n'a rien de précieux dans eux quand ce code s'exécute.) –

+0

'ajouter edi, edi' est légèrement plus efficace que' shl edi, 1' et place CF exactement pareil. –