Thanks, On 2020/12/10 17:12, Richard Biener wrote: >> 2) From PR90070: >> >> double temp1 = (double)r->red; >> double temp2 = (double)aggregate.red; >> double temp3 = temp2 + (temp1 * 5.0); > temp1 * 5 could be not representable in float but the > result of the add could so the transform could result > in -+Inf where the original computation was fine (but > still very large result). > > Usually in such cases one could say we should implement some > diagnostic hints to the user that he might consider refactoring > his code to use float computations because we cannot really say > whether it's safe (we do at the moment not implement value-range > propagation for floating point types). >
foo (double x, float y, float z) { return ( fabs (x) * y - z ) ; } int main () { float res = foo (1e38, 5.0, 3e38); printf ("res:%f\n", res); } (1) $ gcc a.c -Ofast -ffp-contract=off: 0000000000000880 <foo>: 880: 10 0a 20 fc fabs f1,f1 884: b2 00 21 fc fmul f1,f1,f2 888: 28 18 21 fc fsub f1,f1,f3 88c: 18 08 20 fc frsp f1,f1 890: 20 00 80 4e blr $ ./a.out res:199999993605713849301312521538346418176.000000 (2) $ gcc_MODIFIED a.c -Ofast -ffp-contract=off: 0000000010000660 <foo>: 10000660: 18 08 00 fc frsp f0,f1 10000664: 10 02 00 fc fabs f0,f0 10000668: b2 00 00 ec fmuls f0,f0,f2 // Inf 1000066c: 28 18 20 ec fsubs f1,f0,f3 10000670: 20 00 80 4e blr $ ./a.out res:inf It's true that if change all double computation to float will result in INF if "fabs (x) * y" is larger than FLT_MAX, though the double result in (1) could get back to a large number smaller than FLT_MAX. But the add/sub could also produces INF similarly, foo (double x, float y, float z) { return ( -fabs (x) + y + z ) ; } int main () { float res = foo (1e38, 1e38, 3e38); printf ("res:%f\n", res); } (3) $ gcc a.c -Ofast: 0000000000000880 <foo>: 880: 10 0a 20 fc fabs f1,f1 884: 28 08 42 fc fsub f2,f2,f1 888: 2a 18 22 fc fadd f1,f2,f3 88c: 18 08 20 fc frsp f1,f1 890: 20 00 80 4e blr $ ./a.out res:300000000549775575777803994281145270272.000000 4) $ gcc_MODIFIED a.c -Ofast: 0000000010000660 <foo>: 10000660: 18 08 20 fc frsp f1,f1 10000664: 2a 18 42 ec fadds f2,f2,f3 10000668: 10 0a 20 fc fabs f1,f1 1000066c: 28 08 22 ec fsubs f1,f2,f1 10000670: 20 00 80 4e blr $ ./a.out res:inf Note that the add/sub sequence is different for (3) and (4) since -funsafe-math-optimizations is implicitly true. "fp-contract=fast" in (1) and (2) could avoid Inf as fmads could handle float overflow (verified it on Power, not sure other targets support this), but without float value-range info, it is unsafe to change computation from double to float even for only add/sub expressions. What's more, It seems also difficult to do computation *partly float and partly double* in backprop pass since all the expressions are chained and strong dependent unlike the sign-changing operations, which could only change expressions partly. Thanks, Xionghu