The conditions when convert from double to float is permitted?
Xionghu Luo
luoxhu@linux.ibm.com
Fri Dec 11 07:54:44 GMT 2020
+cc.
On 2020/12/11 14:25, Xionghu Luo via Gcc wrote:
> 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
>
--
Thanks,
Xionghu
More information about the Gcc
mailing list