   SIMD techniques.
  I am using MS intrinsics to perform SIMD operations of sets of floats (4 element vectors ofcourse).All I am doing is adding a fixed vector to my array of vectors. They are stored as an array of structures.The code (from memory, I am not at my PC):void ShiftGrid(Vector shift){    _m128 p, v, res;    _mm_load_ps(v, &shift.x);    float *pdata = m_pGrid;    for(int i=0; i<gridsize; i++, pdata+=4)    {   p = _mm_load_ps(pdata);   res = _mm_add_ps(p, v);   _mm_store_ps(pdata, res);    }}This works fine, just want some tips on speeding it up. The data is generally about 16000 vectors. I know you can stream data from memory without going via the cache, and also force data to stream to the cache, but I don't know which is faster in this case, or quite how to implement either.Thanks!   
void ShiftGrid(Vector shift){    _m128 p0,p1,p2,p3,v;    _mm_load_ps(v, &shift.x);    float *pdata = m_pGrid;    for(int i=0; i<gridsize; i+=4, pdata+=16)    {   p0 = _mm_load_ps(pdata);   p1 = _mm_load_ps(pdata+4);   p2 = _mm_load_ps(pdata+8);   p3 = _mm_load_ps(pdata+12);   p0 = _mm_add_ps(p0,v);   p1 = _mm_add_ps(p1,v);   p2 = _mm_add_ps(p2,v);   p3 = _mm_add_ps(p3,v);   _mm_store_ps(pdata, p0);   _mm_store_ps(pdata+4, p1);   _mm_store_ps(pdata+8, p2);   _mm_store_ps(pdata+12, p3);    }};  Okay guess thats one :). Does this interact especially well with SIMD (and if so why) or is it just a standard inner loop expansion?   ;  You usually don't want to execute two *ps instructions on the same xmm* register in a row.   ;  Okay thanks, thats good to know. How about cache usage and streaming, any advice there? Also I've heard that using SIMD forces the FPU to switch modes (all the rest of my code is standard floating point stuff), which is fairly costly, so do I need to do anything to enforce FPU mode during the function, or will it not matter?I would imagine FPU instructions in other threads would cause an FPU mode switch aswell, how do people get around that?;  Make sure your data is aligned on a 16-byte boundary, and use aligned move instructions.  This should result in a noticable speedup.   ;  Yeah I already got that done, its all aligned up nice!What I really want some one to explain is the cache usage in this situation, and how I can control it to my benefit.   ;  If you are using intrinsics, you don't have to worry about it. The compiler is taking care of cache related stuff on its own, and its usually pretty good.The cache activity is pretty simple. Your only reading from one array. Between the compiler and the chips own automatic cache controls, its done.   ;  Keep in mind that most SSE (or floating point instructions in general) have a latency of at least 3-4 cycles. (addps is 4 cycles on Athlon 64, and a good chunk more on P4) So try to ensure you have enough independent instructions to fill in those gaps. (After your addition, it takes 4+ cycles before the result is available to other instructions.So one of the most important optimizations is to eliminate so many dependencies that this gap can be filled with other instructions (for example by unrolling the loop a few times)   ;  This is my function:__m128 shift128, pt128_1, pt128_2, pt128_3, pt128_4;for(i=0; i<fours; i++, bpbuff+=16){pt128_1 = _mm_load_ps(bpbuff);pt128_2 = _mm_load_ps(bpbuff+4);pt128_3 = _mm_load_ps(bpbuff+8);pt128_4 = _mm_load_ps(bpbuff+12);pt128_1 = _mm_add_ps(pt128_1, shift128);pt128_2 = _mm_add_ps(pt128_2, shift128);pt128_3 = _mm_add_ps(pt128_3, shift128);pt128_4 = _mm_add_ps(pt128_4, shift128);_mm_store_ps(bpbuff, pt128_1);_mm_store_ps(bpbuff+4, pt128_2);_mm_store_ps(bpbuff+8, pt128_3);_mm_store_ps(bpbuff+12, pt128_4);}This is the disassembly of my function:for(i=0; i<fours; i++, bpbuff+=16)0049C310  mov    dword ptr ,0 0049C317  jmp    WW::LOD::PatchGrid::ShiftGrid+10Bh (49C32Bh) 0049C319  mov    eax,dword ptr  0049C31C  add    eax,1 0049C31F  mov    dword ptr ,eax 0049C322  mov    ecx,dword ptr [bpbuff] 0049C325  add    ecx,40h 0049C328  mov    dword ptr [bpbuff],ecx 0049C32B  mov    eax,dword ptr  0049C32E  cmp    eax,dword ptr [fours] 0049C331  jge    WW::LOD::PatchGrid::ShiftGrid+25Ah (49C47Ah) {pt128_1 = _mm_load_ps(bpbuff);0049C337  mov    eax,dword ptr [bpbuff] 0049C33A  movaps xmm0,xmmword ptr [eax] 0049C33D  movaps xmmword ptr [ebp-450h],xmm0 0049C344  movaps xmm0,xmmword ptr [ebp-450h] 0049C34B  movaps xmmword ptr [pt128_1],xmm0 pt128_2 = _mm_load_ps(bpbuff+4);0049C352  mov    eax,dword ptr [bpbuff] 0049C355  add    eax,10h 0049C358  movaps xmm0,xmmword ptr [eax] 0049C35B  movaps xmmword ptr [ebp-430h],xmm0 0049C362  movaps xmm0,xmmword ptr [ebp-430h] 0049C369  movaps xmmword ptr [pt128_2],xmm0 pt128_3 = _mm_load_ps(bpbuff+8);0049C370  mov    eax,dword ptr [bpbuff] 0049C373  add    eax,20h 0049C376  movaps xmm0,xmmword ptr [eax] 0049C379  movaps xmmword ptr [ebp-410h],xmm0 0049C380  movaps xmm0,xmmword ptr [ebp-410h] 0049C387  movaps xmmword ptr [pt128_3],xmm0 pt128_4 = _mm_load_ps(bpbuff+12);0049C38E  mov    eax,dword ptr [bpbuff] 0049C391  add    eax,30h 0049C394  movaps xmm0,xmmword ptr [eax] 0049C397  movaps xmmword ptr [ebp-3F0h],xmm0 0049C39E  movaps xmm0,xmmword ptr [ebp-3F0h] 0049C3A5  movaps xmmword ptr [pt128_4],xmm0 pt128_1 = _mm_add_ps(pt128_1, shift128);0049C3AC  movaps xmm0,xmmword ptr [shift128] 0049C3B0  movaps xmm1,xmmword ptr [pt128_1] 0049C3B7  addps  xmm1,xmm0 0049C3BA  movaps xmmword ptr [ebp-3D0h],xmm1 0049C3C1  movaps xmm0,xmmword ptr [ebp-3D0h] 0049C3C8  movaps xmmword ptr [pt128_1],xmm0 pt128_2 = _mm_add_ps(pt128_2, shift128);0049C3CF  movaps xmm0,xmmword ptr [shift128] 0049C3D3  movaps xmm1,xmmword ptr [pt128_2] 0049C3DA  addps  xmm1,xmm0 0049C3DD  movaps xmmword ptr [ebp-3B0h],xmm1 0049C3E4  movaps xmm0,xmmword ptr [ebp-3B0h] 0049C3EB  movaps xmmword ptr [pt128_2],xmm0 pt128_3 = _mm_add_ps(pt128_3, shift128);0049C3F2  movaps xmm0,xmmword ptr [shift128] 0049C3F6  movaps xmm1,xmmword ptr [pt128_3] 0049C3FD  addps  xmm1,xmm0 0049C400  movaps xmmword ptr [ebp-390h],xmm1 0049C407  movaps xmm0,xmmword ptr [ebp-390h] 0049C40E  movaps xmmword ptr [pt128_3],xmm0 pt128_4 = _mm_add_ps(pt128_4, shift128);0049C415  movaps xmm0,xmmword ptr [shift128] 0049C419  movaps xmm1,xmmword ptr [pt128_4] 0049C420  addps  xmm1,xmm0 0049C423  movaps xmmword ptr [ebp-370h],xmm1 0049C42A  movaps xmm0,xmmword ptr [ebp-370h] 0049C431  movaps xmmword ptr [pt128_4],xmm0 _mm_store_ps(bpbuff, pt128_1);0049C438  movaps xmm0,xmmword ptr [pt128_1] 0049C43F  mov    eax,dword ptr [bpbuff] 0049C442  movaps xmmword ptr [eax],xmm0 _mm_store_ps(bpbuff+4, pt128_2);0049C445  movaps xmm0,xmmword ptr [pt128_2] 0049C44C  mov    eax,dword ptr [bpbuff] 0049C44F  add    eax,10h 0049C452  movaps xmmword ptr [eax],xmm0 _mm_store_ps(bpbuff+8, pt128_3);0049C455  movaps xmm0,xmmword ptr [pt128_3] 0049C45C  mov    eax,dword ptr [bpbuff] 0049C45F  add    eax,20h 0049C462  movaps xmmword ptr [eax],xmm0 _mm_store_ps(bpbuff+12, pt128_4);0049C465  movaps xmm0,xmmword ptr [pt128_4] 0049C46C  mov    eax,dword ptr [bpbuff] 0049C46F  add    eax,30h 0049C472  movaps xmmword ptr [eax],xmm0 }There are 7 xmm registers but my compiler is only making code that uses 2! (I'm using MSVC++ 2003).Any way to make this better, or do I have to do the asm myself?