+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

Reply via email to