Con GCC 5.3 el siguiente código se compila con -O3 -fma
float mul_add(float a, float b, float c) {
return a*b + c;
}
produce el siguiente ensamblaje
vfmadd132ss %xmm1, %xmm2, %xmm0
ret
Noté que GCC hacía esto con -O3
ya en GCC 4.8.
Sonido 3.7 con -O3 -mfma
produce
vmulss %xmm1, %xmm0, %xmm0
vaddss %xmm2, %xmm0, %xmm0
retq
pero Clang 3.7 con -Ofast -mfma
produce el mismo código que GCC con -O3 fast
.
Me sorprende que GCC haga con -O3
porque de esta respuesta dice
El compilador no puede fusionar sumas y multiplicaciones separadas a menos que permita un modelo relajado de punto flotante.
Esto se debe a que un FMA solo tiene un redondeo, mientras que un ADD + MUL tiene dos. Por lo tanto, el compilador violará el estricto comportamiento de punto flotante IEEE al fusionarse.
Sin embargo, desde este enlace dice
Independientemente del valor de FLT_EVAL_METHOD, se puede contraer cualquier expresión de coma flotante, es decir, se puede calcular como si todos los resultados intermedios tuvieran un rango y una precisión infinitos.
Así que ahora estoy confundido y preocupado.
- ¿Se justifica que GCC use FMA con
-O3
? - ¿La fusión viola el estricto comportamiento de punto flotante IEEE?
- Si la fusión viola el comportamiento de coma flotante de IEEE y dado que GCC regresa
__STDC_IEC_559__
¿No es esto una contradicción?
Dado que FMA se puede emular en el software, parece que debería haber dos conmutadores de compilador para FMA: uno para decirle al compilador que use FMA en los cálculos y otro para decirle al compilador que el hardware tiene FMA.
Apprently esto se puede controlar con la opción -ffp-contract
. Con GCC el valor predeterminado es -ffp-contract=fast
y con Clang no lo es. Otras opciones como -ffp-contract=on
y -ffp-contract=off
no produzca la instrucción FMA.
Por ejemplo Clang 3.7 con -O3 -mfma -ffp-contract=fast
produce vfmadd132ss
.
Revisé algunas permutaciones de #pragma STDC FP_CONTRACT
ajustado a ON
y OFF
con -ffp-contract
ajustado a on
, off
y fast
. EN todos los casos también usé -O3 -mfma
.
Con GCC la respuesta es simple. #pragma STDC FP_CONTRACT
ENCENDIDO o APAGADO no hace ninguna diferencia. Solamente -ffp-contract
asuntos.
CCG que utiliza fma
con
-ffp-contract=fast
(por defecto).
Con Clang usa fma
- con
-ffp-contract=fast
. - con
-ffp-contract=on
(predeterminado) y#pragma STDC FP_CONTRACT ON
(el valor predeterminado esOFF
).
En otras palabras, con Clang puedes obtener fma
con #pragma STDC FP_CONTRACT ON
(ya que -ffp-contract=on
es el predeterminado) o con -ffp-contract=fast
. -ffast-math
(y por lo tanto -Ofast
) colocar -ffp-contract=fast
.
Busqué en MSVC e ICC.
Con MSVC usa la instrucción fma con /O2 /arch:AVX2 /fp:fast
. Con MSVC /fp:precise
es el predeterminado.
Con ICC usa fma con -O3 -march=core-avx2
(en realidad -O1
es suficiente). Esto se debe a que, por defecto, ICC usa -fp-model fast
. Pero ICC usa fma incluso con -fp-model precise
. Para deshabilitar fma con el uso de ICC -fp-model strict
o -no-fma
.
Entonces, por defecto, GCC e ICC usan fma cuando fma está habilitado (con -mfma
para GCC/Clang o -march=core-avx2
con ICC), pero Clang y MSVC no.
Podría ser un error del compilador. Considere denunciarlo.
– fuz
23 de diciembre de 2015 a las 13:01
Estoy bastante seguro de que lo que está haciendo gcc está bien. Después de leer el documento FLT_EVAL_METHOD sobre la contratación de expresiones FP, estoy sorprendido
clang
no hacer esto. No estoy publicando esto como una respuesta, ya que no se basa en ninguna documentación de estándares reales, solo en mi comprensión de cómo I creo que las cosas deberían funcionar/deberían haber sido diseñadas, dado el material de la pregunta.– Peter Cordes
23 de diciembre de 2015 a las 13:04
@FUZxxl, ¿cree que la etiqueta de punto flotante sería más apropiada que ieee-754? (si es así, siéntete libre de cambiarlo). Siento que también debería usar la etiqueta de punto flotante.
– bosón Z
23 de diciembre de 2015 a las 13:06
“¿La fusión viola el estricto comportamiento de punto flotante IEEE?” –> OMI, sí. Utilizar
double fma(double x, double y, double z);
en cambio, ya que es una llamada de función que en un compilador optimizado llamará al código ensamblador esperado. Esto no viola el “comportamiento de punto flotante IEEE”.– chux – Reincorporar a Monica
23 de diciembre de 2015 a las 13:23
gcc.gnu.org/bugzilla/show_bug.cgi?id=37845
– bosón Z
23 de diciembre de 2015 a las 14:21