Converter um número em uma string usando FPU

Cada pessoa que gosta de programação é obrigada a escrever sua própria versão da solução para este problema. Decidi não ser exceção.





De acordo com, x64 software conventions



assumiremos que o número a ser convertido está localizado em XMM0



.





Usaremos x64



código de x32



bits para endereçamento de bits. Essa forma de endereçamento permite que você aproveite os dois dialetos.





Salve o valor da pilha e crie um ponto de dados alinhado ao parágrafo para melhorar o desempenho:





	;  
	mov    r9d, esp
	lea    r8d,[r9d - 70h]
	and    r8d, 0FFFFFFF0h
	mov    esp, r8d
      
      



Nós o preparamos FPU



libertando-o dos dados e definimos a maior precisão e arredondamento para zero:





	fsave [esp]
	finit
	mov  dword ptr[esp - dword], 037F0F7Fh
	fldcw         [esp - dword]
      
      



Sobrecarregamos o número de XMM0



para FPU



:





	movd qword ptr[esp - xmmword], xmm0
	fld  qword ptr[esp - xmmword]
      
      



Encontre a ordem decimal do número:





	fld     st(0)
	fxtract
	fldl2t
	fst     st(1)
	fdivr   st(0),st(2)
	frndint
      
      



Defina o arredondamento para o número mais próximo:





	fldcw	[esp - word]
      
      



Preservamos a ordem do número e encontramos a ordem decimal do multiplicador para converter os dígitos significativos do número para a parte inteira:





	fist      dword ptr[esp - dword]
	movzx edx, word ptr[esp - dword]
	mov       dword ptr[esp - dword], 10h
	fisubr    dword ptr[esp - dword]
      
      



Encontre o multiplicador decimal e multiplique-o pelo número:





	fmulp   st(1),st(0)
	fst     st(1)
	frndint
	fsub    st(1),st(0)
	fld1
	fscale
	fstp    st(1)
	fmulp   st(2),st(0)
	f2xm1
	fld1
	faddp   st(1),st(0)
	fmulp   st(1),st(0)
	frndint
      
      



Recarregamos o número resultante FPU



em registradores AX



e XMM0



no tamanho dos primeiros 2 e 8 bytes subsequentes, respectivamente. Ao carregar 8 bytes em um registrador, XMM0



alteramos simultaneamente a ordem dos bytes, pré-alinhando o ponteiro da pilha pelo parágrafo:





	fbstp           tbyte ptr[esp - xmmword]
	mov       ax,    word ptr[esp -   qword]
	pshuflw xmm0, xmmword ptr[esp - xmmword], 00011011b
      
      



Nós restauramos o estado FPU



:





	frstor [esp]
      
      



0



:





	punpcklbw xmm0, xmm0
	pshuflw   xmm0, xmm0, 10110001b
	pshufhw   xmm0, xmm0, 10110001b
      
      



:





	mov            dword ptr[esp], 0FF00FF0h
	pshufd xmm1, xmmword ptr[esp], 0
	pand   xmm0, xmm1
	psrlw  xmm1, 4
	movdqa xmm2, xmm1
	pand   xmm1, xmm0
	psrlw  xmm1, 4
	pandn  xmm2, xmm0
	paddb  xmm1, xmm2
      
      



:





	pxor    xmm0, xmm0
	pcmpeqb xmm0, xmm1
      
      



:





	mov            dword ptr[esp], 30303030h
	pshufd xmm2, xmmword ptr[esp], 0
	paddb  xmm1, xmm2
      
      



:





	mov  byte ptr[esp],'-'
	btr             ax, 0Fh
	adc            esp, 0
	add             ax,'.0'
	mov  word ptr[esp], ax
      
      



0



:





	movdqu	      xmmword ptr[esp + word], xmm1
	pmovmskb ecx, xmm0
	bsf      ecx, ecx
	add      esp, ecx
      
      



:





	mov    ecx,(word + dword)
	mov    eax, edx
	neg     dx
	jnc     @f
	cmovns eax, edx
	setns   dh
      
      



:





	cmp   ax, 0Ah
	sbb  ecx, ecx
	mov   dl, 0Ah
	div   dl
	cmp   al, 0Ah
	sbb  ecx, 0
	shl  eax, 8
	shr   ax, 8
	div   dl
	add eax, 303030h
	lea edx,[edx * 2 + 2B51h]
	
	mov dword ptr[esp + word + ecx + word], eax
	mov  word ptr[esp + word], dx
      
      



EAX



ECX



:





@@:	lea ecx,[esp + ecx + qword]
	sub ecx, r8d
  mov eax,ecx
      
      



XMM1



XMM2



:





	movdqa xmm1, xmmword ptr[r8d]
	movdqa xmm2, xmmword ptr[r8d + xmmword]
      
      



:





	mov esp, r9d
      
      



.





/ . x64 software conventions



.






- .





- , .





- .





- SIMD



FPU



.





, - .








All Articles