SIMD Vector3 Math
Posted: Sat Jun 23, 2007 5:41 pm
For those that wish to see for themselves the performance gains associated with SIMD operations, here's a few functions to benchmark against the other standard ones. I'm still fairly new to SIMD operations in assembly, but if anyone needs help with some of the math optimisation, feel free to ask 
Please note that this requires your vector to be alligned on a 16-byte boundary. Also, this was compiled as a win32 project using Visual Studios 2005. You may need to modify the assembly a bit depending on which compiler you use.
Code: Select all
#pragma once
static const float SZero = 0;
__declspec(align(16)) struct Vector3D
{
#pragma region Constructor
public: Vector3D()
{
X = 0;
Y = 0;
Z = 0;
W = 0;
}
public: Vector3D(float x, float y, float z)
{
X = x;
Y = y;
Z = z;
W = 0;
}
#pragma endregion
#pragma region Destructor
public: ~Vector3D(void)
{
}
#pragma endregion
#pragma region Fields
public: float X;
public: float Y;
public: float Z;
private: float W;
#pragma endregion
#pragma region Properties
#pragma endregion
#pragma region Operator Overloads
#pragma endregion
#pragma region Methods
public: void NormalizePrecise()
{
_asm
{
//get length
mov eax, this
movd xmm0, dword ptr ds:[eax]
movd xmm1, dword ptr ds:[eax + 4]
movd xmm2, dword ptr ds:[eax + 8]
mulss xmm0, xmm0
mulss xmm1, xmm1
mulss xmm2, xmm2
addss xmm0, xmm1
addss xmm0, xmm2
sqrtss xmm0, xmm0
ucomiss xmm0, SZero
je Done
//duplicate length across register
pshufd xmm0, xmm0, 0
//divide by length
movdqa xmm1, xmmword ptr ds:[eax]
divps xmm1, xmm0
//store result
movdqa xmmword ptr ds:[eax], xmm1
Done:
}
}
public: void Normalize()
{
_asm
{
//get recipricol length
mov eax, this
movd xmm0, dword ptr ds:[eax]
movd xmm1, dword ptr ds:[eax + 4]
movd xmm2, dword ptr ds:[eax + 8]
mulss xmm0, xmm0
mulss xmm1, xmm1
mulss xmm2, xmm2
addss xmm0, xmm1
addss xmm0, xmm2
ucomiss xmm0, SZero
je Done
rsqrtss xmm0, xmm0
//duplicate length across register
pshufd xmm0, xmm0, 0
//multiply by recipricol length (divide by length)
movdqa xmm1, xmmword ptr ds:[eax]
mulps xmm1, xmm0
//store result
movdqa xmmword ptr ds:[eax], xmm1
Done:
}
}
public: void Absolute()
{
_asm
{
mov eax, this
and dword ptr ds:[eax], 07FFFFFFFh
and dword ptr ds:[eax + 4], 07FFFFFFFh
and dword ptr ds:[eax + 8], 07FFFFFFFh
}
}
public: void Maximize(const Vector3D &v1)
{
_asm
{
//get parameter information
mov eax, v1
movdqa xmm0, xmmword ptr ds:[eax]
mov eax, this
//compute maximum
maxps xmm0, xmmword ptr ds:[eax]
//store result
movdqa xmmword ptr ds:[eax], xmm0
}
}
public: void Minimize(const Vector3D &v1)
{
_asm
{
//get parameter information
mov eax, v1
movdqa xmm0, xmmword ptr ds:[eax]
mov eax, this
//compute minimum
minps xmm0, xmmword ptr ds:[eax]
//store result
movdqa xmmword ptr ds:[eax], xmm0
}
}
public: void Cross(const Vector3D &v1)
{
_asm
{
//get parameter information
mov eax, v1
movdqa xmm0, xmmword ptr ds:[eax]
mov eax, this
movdqa xmm1, xmmword ptr ds:[eax]
//align vectors to be multiplied
pshufd xmm2, xmm0, 11001001b //(v1.Y, v1.Z, v1.X)
pshufd xmm4, xmm1, 11001001b //(Y, Z, X)
pshufd xmm3, xmm0, 11010010b //(v1.Z, v1.X, v1.Y)
pshufd xmm5, xmm1, 11010010b //(Z, X, Y)
//perform cross-product
mulps xmm4, xmm3
mulps xmm5, xmm2
subps xmm4, xmm5
//store result
movdqa xmmword ptr ds:[eax], xmm4
}
}
public: void Lerp(const Vector3D &v1, float interpolator)
{
_asm
{
//get parameter information
mov eax, v1
movdqa xmm0, xmmword ptr ds:[eax]
mov eax, this
movdqa xmm1, xmmword ptr ds:[eax]
//duplicate interpolator across register
pshufd xmm2, interpolator, 0
//interpolate
subps xmm0, xmm1
mulps xmm0, xmm2
addps xmm0, xmm1
//store result
movdqa xmmword ptr ds:[eax], xmm0
}
}
#pragma endregion
};