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

Reply via email to