descargar - c++ programming pdf
¿Cómo controlar si C math usa SSE2? (3)
Entré en el ensamblaje de las funciones matemáticas trascendentales de la biblioteca C con MSVC en fp: modo estricto. Todos parecen seguir el mismo patrón, esto es lo que sucede con el sin
.
Primero hay una rutina de despacho desde un archivo llamado "disp_pentium4.inc". Comprueba si la variable ___use_sse2_mathfcns
se ha establecido; si es así, llama a __sin_pentium4
, de lo contrario llama a __sin_default
.
__sin_pentium4
(en "sin_pentium4.asm") comienza transfiriendo el argumento del x87 fpu al registro xmm0, realiza el cálculo utilizando las instrucciones del SSE2 y vuelve a cargar el resultado en el fpu.
__sin_default
(en "sin.asm") mantiene la variable en la pila x87 y simplemente llama a fsin
.
Entonces, en ambos casos, el operando se empuja en la pila x87 y también se devuelve en ella, haciéndolo transparente para la persona que llama, pero si se define ___use_sse2_mathfcns
, la operación realmente se realiza en SSE2 en lugar de x87.
Este comportamiento es muy interesante para mí porque las funciones trascendentales x87 son notorias por tener comportamientos ligeramente diferentes dependiendo de la implementación, mientras que una determinada pieza de código SSE2 siempre debe dar resultados reproducibles.
¿Hay alguna manera de determinar con certeza, ya sea en tiempo de compilación o en tiempo de ejecución, que se utilizará la ruta del código SSE2? No soy experto en el ensamblaje de escritura, por lo que si esto implica escribir cualquier ensamblaje, se agradecerá un ejemplo de código.
¿Por qué no usar su propia biblioteca en lugar del tiempo de ejecución de C? Esto brindaría una garantía de consistencia aún mayor en todas las computadoras (presumiblemente, el tiempo de ejecución de C se proporciona como una DLL y podría cambiar ligeramente en el tiempo).
Yo recomendaría CRlibm . Si ya está apuntando al SSE2, y mientras no tuviera la intención de cambiar el modo de redondeo de la FPU, está en las condiciones ideales para usarlo y no encontrará una implementación más precisa.
Encontré la respuesta a través de una cuidadosa investigación de math.h. Esto se controla mediante un método llamado _set_SSE2_enable
. Este es un símbolo público documentado here :
Habilita o deshabilita el uso de las instrucciones Streaming SIMD Extensions 2 (SSE2) en las rutinas matemáticas de CRT. (Esta función no está disponible en arquitecturas x64 porque SSE2 está habilitado de forma predeterminada).
Esto hace que el indicador ___use_sse2_mathfcns mencionado anteriormente se establezca en el valor proporcionado, habilitando o deshabilitando efectivamente el uso de las rutinas SSE2 _pentium4.
La documentación menciona que esto afecta solo a ciertas funciones trascendentales, pero al observar el desensamblaje, esto parece afectar a todos ellos.
Edición: entrar en cada función revela que están disponibles en SSE2, excepto por lo siguiente:
- fmod
- sinh
- aporrear
- Tanh
- sqrt
Sqrt es el mayor infractor, pero es trivial de implementar en SSE2 utilizando intrínsecos. Para los demás, no hay una solución simple, excepto quizás el uso de una biblioteca de terceros, pero probablemente no pueda hacerlo.
La respuesta corta es que no puede indicar EN SU CÓDIGO lo que hará la biblioteca, a menos que también incluya detalles específicos de la implementación de la biblioteca. Esto haría que el código sea completamente no portátil, incluso dos compilaciones diferentes del mismo compilador pueden cambiar los elementos internos de la biblioteca.
Por supuesto, si la portabilidad no es un problema, entonces use extern <type> ___use_sse2_mathfcns;
y comprobando si es la verdad funcionaría claramente.
Espero que si el procesador tiene SSE2 y usted está usando una biblioteca suficientemente moderna, usaría SSE2 siempre que sea posible. Pero decir que para cierto es un asunto diferente.
Si esto es crítico para su código, entonces implemente sus propias funciones trascendentales y úselas, esa es la única manera de garantizar el mismo resultado. O use algún código ensamblador en línea (o trascendental) adecuado para calcular los valores seleccionados de sin
, cos
, etc., y compare aquellos con las funciones sin()
y cos()
proporcionadas por la biblioteca.