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