[PATCH] D43142: Experimental pass to convert all floating point operations to the equivalent constrained intrinsics

Cameron McInally via Phabricator via llvm-commits llvm-commits at lists.llvm.org
Thu Nov 1 20:11:27 PDT 2018


cameron.mcinally added a comment.

In https://reviews.llvm.org/D43142#1284977, @andrew.w.kaylor wrote:

> I thought what we said was that if constrained FP intrinsics were used anywhere in a function then they had to be used everywhere in the function. So if you inline a function with FENV_ACCESS=ON into a function with FENV_ACCESS=OFF then the FP operations in the destination function need to be converted to constrained intrinsics, and if you inline a function with FENV_ACCESS=OFF into a function with FENV_ACCESS=ON then the FP operations in the function being inlined need to be converted. This conversion will have a detrimental effect on optimizations, so it would be nice to factor that into the inling cost, but at this point I'm mostly concerned about generating correct code.


I'm realizing that FENV_ACCESS is poorly designed.

Let's take this small example:

  #include <fenv.h>
  #include <stdio.h>
  
  void bar();
  
  #pragma STDC FENV_ACCESS ON
  int main() {
    feenableexcept(FE_DIVBYZERO);
    bar();
    float x = 1.0/0.0;
    printf("main x=%lf\n", x);
  }
  
  #pragma STDC FENV_ACCESS OFF
  void bar() {
    float x = 1.0/0.0;
    printf("bar x=%lf\n", x);
  }

The FDiv in bar() would access the FP environment since main() enabled exceptions. But, since bar() is preceded with FENV_ACCESS=OFF, the Standard says that accessing the FP environment in bar() is undefined behavior. Since it's undefined behavior, the compiler can optimize as it wishes, including inlining bar() without modifying the FDiv.

It would really be the user's responsibility to make bar() safe. E.g.:

  #pragma STDC FENV_ACCESS OFF
  void bar() {
    fedisableexcept(FE_DIVBYZERO);
    float x = 1.0/0.0;
    printf("bar x=%lf\n", x);
    feenableexcept(FE_DIVBYZERO);
  }

In that case, we would be free to inline bar() assuming that the feenableexcept/fedisableexcept functions act as barriers. However, explicitly making each call safe seems like an unreasonable burden on the user. Imagine the mental gymnastics necessary for a large call tree.

I suppose the compiler could automatically manage this for the user, by saving/restoring the FP environment in the prolog/epilog of FENV_ACCESS=OFF functions. But, there would be a non-trivial cost for that. A priori reasoning tells me that it's not worth the trouble.

Can anyone poke holes in this?


https://reviews.llvm.org/D43142





More information about the llvm-commits mailing list