Mais uma dica sobre ponto-flutuante…

Em C temos alguns tipos diferentes para “ponto-flutuante”. Os tipos padrão, que segem a especificação IEEE 754, são: floatdoublelong double.

O tipo floatdouble são contemplados nas especificações de SSE e SSE2. Mas o tipo long double não é! Isso pode ser problemático, do ponto de vista tanto de performance quanto do tamanho do código final gerado pelo compilador. Na arquitetura x86-64, quando usamos variáveis dos dois primeiros tipos, o compilador gerará instruções SSE para lidar com eles, mas para o tipo long double, ele não tem escolha: Precisará usar a pilha de registradores do co-processador matemático. O código abaixo:

int test_d(double x)
{
  return (x == 0.0) ? 1 : 0;
}

int test_ld(long double x)
{
  return (x == 0.0) ? 1 : 0;
}

Resultará numa listagem semelhante a esta, em assembly:

bits 64
section .data

; Infelizmente NASM não tem um "define" para 128 bits!
zero:   dq  0
        dq  0

section .text

global test_d
test_d:
  xor eax, eax
  comisd  xmm0,[zero]    ; apenas compara XMM0 com o conteúdo 
                         ; da memória [zero]
  sete  al
  ret

global test_ld
test_ld:
  fldz                ; epilha 0.0.
  xor eax,eax
  fld tword [rsp+8]   ; carrega 'x' da pilha do processador.
  fcomip  st0,st1     ; compara st(0) com st(1).
  fstp  st0           ; desempilha st(0).
  sete  al
  ret

Note que, em test_ld o valor de x precisa ser empilhado! Enquanto que a versão que usa double, e usa SSE, o valor já chega na função usando o registrador XMM0.

Então a dica é não use o tipo long double.

Anúncios

Deixe um comentário

Faça o login usando um destes métodos para comentar:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair / Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair / Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair / Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair / Alterar )

Conectando a %s