Mostrar mensagens com a etiqueta SSE. Mostrar todas as mensagens
Mostrar mensagens com a etiqueta SSE. Mostrar todas as mensagens

terça-feira, setembro 22, 2009

Operações com vetor usando SSE Parte II

Parte I

Agora segue as quatro operações com vetores usando SSE foi usando g++ e o inline assembly, mais portar para outros compiladores é uma tarefa simples


**** vec4.hpp ****
#ifndef __vec4hpp__


typedef struct vec4f

{

float x;

float y;

float z;

float w;

}

vec4f __attribute__ ((aligned(16)));

// Soma de Vetores
inline vec4f operator+(vec4f a, vec4f b)

{

vec4f r;

asm("movaps %[ina], %%xmm0 \n\t" \

"movaps %[inb], %%xmm1 \n\t" \

"addps %%xmm0, %%xmm1 \n\r" \

"movaps %%xmm1, %[o] \n\t" \

: [o] "=m"(r)

: [ina] "m"(a), [inb] "m"(b));

return r;

}

// Subtração de Vetores
inline vec4f operator-(vec4f a,vec4f b)

{

vec4f r;

asm("movaps %[ina], %%xmm0 \n\t" \

"movaps %[inb], %%xmm1 \n\t" \

"subps %%xmm1, %%xmm0 \n\r" \

"movaps %%xmm0, %[o] \n\t" \

: [o] "=m"(r)

: [ina] "m"(a), [inb] "m"(b));

return r;

}

// Multiplicação de Vetores
inline vec4f operator*(vec4f a,vec4f b)

{

vec4f r;

asm("movaps %[ina], %%xmm0 \n\t" \

"movaps %[inb], %%xmm1 \n\t" \

"mulps %%xmm0, %%xmm1 \n\r" \

"movaps %%xmm1, %[o] \n\t" \

: [o] "=m"(r)

: [ina] "m"(a), [inb] "m"(b));

return r;

}

// Divisão de Vetores
inline vec4f operator/(vec4f a,vec4f b)
{

vec4f r;

asm("movaps %[ina], %%xmm0 \n\t" \

"movaps %[inb], %%xmm1 \n\t" \

"divps %%xmm1, %%xmm0 \n\r" \

"movaps %%xmm0, %[o] \n\t" \

: [o] "=m"(r)

: [ina] "m"(a), [inb] "m"(b));

return r;

}
#endif

*** EOF ***
 
Segue um teste básico
 
*** teste_cpp.cpp ****
 
#include "vec4.hpp"


#include

void printV(vec4f v)

{

printf("x: %f y: %f z: %f w: %f\n",v.x, v.y, v.z, v.w);

}



int main(int argc,char **argv)

{

vec4f a = {10.f,10.0f,10.0f,10.0f};

vec4f b = {2.0f,2.0f,2.0f,2.0f};

vec4f c;
printf("a ");

printV(a);

printf("b ");

printV(b);

c = a + b;

printf("a + b \n");

printV(c);

c = a - b;

printf("a - b \n");

printV(c);

c = a * b;

printf("a * b \n");

printV(c);

c = a / b;

printf("a / b \n");

printV(c);

vec4f z = a*a / b;


printf("z = a*a /b \n");

printV(z);

return 0;

}
 *** EOF ***


O Resultado:
a x: 10.000000 y: 10.000000 z: 10.000000 w: 10.000000


b x: 2.000000 y: 2.000000 z: 2.000000 w: 2.000000

a + b

x: 12.000000 y: 12.000000 z: 12.000000 w: 12.000000

a - b

x: 8.000000 y: 8.000000 z: 8.000000 w: 8.000000

a * b

x: 20.000000 y: 20.000000 z: 20.000000 w: 20.000000

a / b

x: 5.000000 y: 5.000000 z: 5.000000 w: 5.000000

z = a*a /b

x: 50.000000 y: 50.000000 z: 50.000000 w: 50.000000


por equanto tudo tranquilo, o próximo passo é fazer as multiplicação por matrizes, apesar de não ser ideal fazer por SSE mas é de maneira geral um artigo interessante, então no próximo da série trataremos de multiplicação de vetores por matrizes

quinta-feira, junho 25, 2009

Operações com vetor usando SSE

Olá pessoal depois de fuçar com o vertex_program/fragment program, descobri o SIMD
(Single Instruction, Multiple Data), o que isso siginifica.

imagine que temos o vetor a = [x,y,z,w] e b = [x,y,z,w], quando vamos fazer uma operação do tipo c = a * b o processo seria este.

c.x = a.x * b.x;
c.y = a.y * b.y;
c.z = a.z * b.z;
c.w = a.w * b.w;

o disassembly deste processo no MSVC++ 2005

c.x = a.x * b.x;
0041197E fld dword ptr [a]
00411981 fmul dword ptr [b]
00411984 fstp dword ptr [c]
c.y = a.y * b.y;
00411987 fld dword ptr [ebp+10h]
0041198A fmul dword ptr [ebp+20h]
0041198D fstp dword ptr [ebp-10h]
c.z = a.z * b.z;
00411990 fld dword ptr [ebp+14h]
00411993 fmul dword ptr [ebp+24h]
00411996 fstp dword ptr [ebp-0Ch]
c.w = a.w * b.w;
00411999 fld dword ptr [ebp+18h]
0041199C fmul dword ptr [ebp+28h]
0041199F fstp dword ptr [ebp-8]

o gcc é bem mais inteligente que isso (to no maldito windows agora)

a mesma operação usando SSE, nos dois caso eu não coloquei a parte responsável por pegar os parametros passados p/ a função e o seu retorno.
o abaixo foi escrito p/ o nasm

mov eax, [ebp+0x8] ;parametro 1 a
mov ebx, [ebp+0xc] ;parametro 2 b
mov ecx, [ebp+0x10] ;parametro 3 c

movups xmm0, [eax] ;coloca eax em xmm0
movups xmm1, [ebx] ;coloca ebx em xmm1
mulps xmm0, xmm1 ; xmm0 = xmm0 * xmm1
movups [ecx], xmm0 ;move xmm0 ecx (c)

creio que iriamos economizar alguns ciclos de processamento, então SSE é isto fazer operações com registradores de 128bits (16 bytes).

pra mais informações na comunidade tem bastante informação, os manuais da intel IA-32 2A e IA-32 2B tem o conjunto de instrução completo.

o 3DNow da amd e o altiVec do PowerPC tem o mesmo propósito, até o ARM tem um conjunto de instruções vetorias, você pode ser bem criativo ao usar esse conjunto de instruções, por exemplo o memcpy copia 4 bytes de cada vez (ao menos no header que eu vi), usando registradores de 128bits poderiamos mover 16bytes por vez, interessante não.

coloquei exemplos no link : http://www.mediafire.com/?sharekey=75c36d37bd6d2c0a391d7d881749d3a7e04e75f6e8ebb871

matematica.zip -> VC++ 2005
vectors.zip -> GCC + nasm

uma curiosiade é que este é o segredo do PS3 (CELL/B.E) ele tem um porcessador PowerPC (PPE) e 6 processadores (SPE), atualmente o Top 1 da top500.org o RoadRunner tem alguns milhares deste (CELL/B.E).

se eu falei alguma besteira favor me corrigir.

veja a Parte II.

Obrigado.