¿Cómo puedo obtener un intrínseco para la función exp () en código x64?
Tengo el siguiente código y estoy esperando la versión intrínseca delexp()
Función a utilizar. Desafortunadamente, no está en una compilación x64, por lo que es más lento que un Win32 similar (es decir, una compilación de 32 bits):
<code>#include "stdafx.h" #include <cmath> #include <intrin.h> #include <iostream> int main() { const int NUM_ITERATIONS=10000000; double expNum=0.00001; double result=0.0; for (double i=0;i<NUM_ITERATIONS;++i) { result+=exp(expNum); // <-- The code of interest is here expNum+=0.00001; } // To prevent the above from getting optimized out... std::cout << result << '\n'; } </code>
Estoy usando los siguientes interruptores para mi compilación:
<code>/Zi /nologo /W3 /WX- /Ox /Ob2 /Oi /Ot /Oy /GL /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_UNICODE" /D "UNICODE" /Gm- /EHsc /GS /Gy /arch:SSE2 /fp:fast /Zc:wchar_t /Zc:forScope /Yu"StdAfx.h" /Fp"x64\Release\exp.pch" /FAcs /Fa"x64\Release\" /Fo"x64\Release\" /Fd"x64\Release\vc100.pdb" /Gd /errorReport:queue </code>
Como puedes ver, tengo/Oi
, /O2
y/fp:fast
según lo requerido por elArtículo de MSDN sobre intrínsecos.. Sin embargo, a pesar de mis esfuerzos, se hace un llamado a la biblioteca estándar,exp()
Realiza más lento en las versiones x64.
Aquí está el ensamblado generado:
<code> for (double i=0;i<NUM_ITERATIONS;++i) 000000013F911030 movsd xmm10,mmword ptr [__real@3ff0000000000000 (13F912248h)] 000000013F911039 movapd xmm8,xmm6 000000013F91103E movapd xmm7,xmm9 000000013F911043 movaps xmmword ptr [rsp+20h],xmm11 000000013F911049 movsd xmm11,mmword ptr [__real@416312d000000000 (13F912240h)] { result+=exp(expNum); 000000013F911052 movapd xmm0,xmm7 000000013F911056 call exp (13F911A98h) // ***** exp lib call is here ***** 000000013F91105B addsd xmm8,xmm10 expNum+=0.00001; 000000013F911060 addsd xmm7,xmm9 000000013F911065 comisd xmm8,xmm11 000000013F91106A addsd xmm6,xmm0 000000013F91106E jb main+52h (13F911052h) } </code>
Como puede ver en el conjunto anterior, hay una llamada a laexp()
función. Ahora, veamos el código generado para eso.for
bucle con una construcción de 32 bits:
<code> for (double i=0;i<NUM_ITERATIONS;++i) 00101031 xorps xmm1,xmm1 00101034 rdtsc 00101036 push ebx 00101037 push esi 00101038 movsd mmword ptr [esp+1Ch],xmm0 0010103E movsd xmm0,mmword ptr [__real@3ee4f8b588e368f1 (102188h)] 00101046 push edi 00101047 mov ebx,eax 00101049 mov dword ptr [esp+3Ch],edx 0010104D movsd mmword ptr [esp+28h],xmm0 00101053 movsd mmword ptr [esp+30h],xmm1 00101059 lea esp,[esp] { result+=exp(expNum); 00101060 call __libm_sse2_exp (101EC0h) // <--- Quite different from 64-bit 00101065 addsd xmm0,mmword ptr [esp+20h] 0010106B movsd xmm1,mmword ptr [esp+30h] 00101071 addsd xmm1,mmword ptr [__real@3ff0000000000000 (102180h)] 00101079 movsd xmm2,mmword ptr [__real@416312d000000000 (102178h)] 00101081 comisd xmm2,xmm1 00101085 movsd mmword ptr [esp+20h],xmm0 expNum+=0.00001; 0010108B movsd xmm0,mmword ptr [esp+28h] 00101091 addsd xmm0,mmword ptr [__real@3ee4f8b588e368f1 (102188h)] 00101099 movsd mmword ptr [esp+28h],xmm0 0010109F movsd mmword ptr [esp+30h],xmm1 001010A5 ja wmain+40h (101060h) } </code>
Hay mucho más código allí, pero es más rápido. Una prueba de tiempo que realicé en un host Nehalem-EP de 3,3 GHz produjo los siguientes resultados:
32 bits:
Para el tiempo de ejecución promedio del cuerpo del bucle: 34.849229 ciclos / 10.560373 ns
64 bits:
Para el tiempo de ejecución promedio del cuerpo del bucle: 45.845323 ciclos / 13.892522 ns
Muy extraño comportamiento, por cierto. ¿Por qué está sucediendo?
Actualizar:
He creado unInforme de error de Microsoft Connect. No dude en solicitarlo para obtener una respuesta autorizada del propio Microsoft sobre el uso de intrínsecos de punto flotante, especialmente en el código x64.