Quuxplusone / LLVMBugzillaTest

0 stars 0 forks source link

[LTO] convert math LLVM intrinsics into finite version of libcalls #35853

Open Quuxplusone opened 6 years ago

Quuxplusone commented 6 years ago
Bugzilla Link PR36879
Status NEW
Importance P normal
Reported by Denis Bakhvalov (denis.bakhvalov@intel.com)
Reported on 2018-03-23 09:04:45 -0700
Last modified on 2018-08-13 13:05:18 -0700
Version trunk
Hardware PC Linux
CC andrei.elovikov@intel.com, llvm-bugs@lists.llvm.org, llvm-dev@redking.me.uk, spatel+llvm@rotateright.com
Fixed by commit(s)
Attachments
Blocks
Blocked by
See also PR35672, PR38547
Spawned form https://bugs.llvm.org/show_bug.cgi?id=35672

The problem mentioned above was fixed but only for non-LTO builds. For LTO
build issue still exist.

$ cat a.c
#include <math.h>
int main()
{
  return exp(1.0);
}

1) Non-LTO build (notice call to '__exp_finite'):
$ clang -O0 -ffast-math a.c –lm
$ objdump -d a.out | grep "call.*exp"
  400567:   e8 c4 fe ff ff             callq  400430 <__exp_finite@plt>

2) LTO build (notice call to 'exp'):
$ clang -O0 -flto -ffast-math a.c -lm
$ objdump -d a.out | grep "call.*exp"
  400547:   e8 b4 fe ff ff          callq  400400 <exp@plt>

We can see that if we add ‘-flto’ we stop generating the call to finite version
of ‘exp’ function, although we could, because ‘-ffast-math’ is provided.

I debugged this issue and found the root cause. I can share the details if
someone is interested, however I don’t know how it can be fixed immediately.
Quuxplusone commented 6 years ago
Some additional analysis on the problem:

When we making the decision to which version to lower our intrinsic (see
./lib/CodeGen/SelectionDAG/LegalizeDAG.cpp):
if (CanUseFiniteLibCall && DAG.getLibInfo().has(LibFunc_exp_finite))
the second condition returns false in LTO mode.

SelectionDAGISel object takes LibInfo from TargetLibraryInfoWrapperPass (see
SelectionDAGISel::runOnMachineFunction() in
./lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp).

And LibInfo object inside TargetLibraryInfoWrapperPass was default-constructed,
because TargetLibraryInfoWrapperPass was itself default-constructed (as a
dependency from BasicAAWrapperPass, see TargetPassConfig::addIRPasses()).

Because TargetLibraryInfoImpl object was default-constructed it caused
LibFunc_exp_finite to be unavailable (see implementation of static initialize()
function in ./lib/Analysis/TargetLibraryInfo.cpp)

I just tried dirty hack like shown below and it started working (not a solution
of course):

diff --git a/lib/Analysis/TargetLibraryInfo.cpp
b/lib/Analysis/TargetLibraryInfo.cpp
index 8b9f2a2..1b2c1f2 100644
--- a/lib/Analysis/TargetLibraryInfo.cpp
+++ b/lib/Analysis/TargetLibraryInfo.cpp
@@ -62,6 +62,13 @@ static void initialize(TargetLibraryInfoImpl &TLI, const
Triple &T,
                         }) &&
          "TargetLibraryInfoImpl function names must be sorted");

+  if (T.str().empty())
+  {
+    const_cast<Triple&>(T).setArchName("x86_64");
+    const_cast<Triple&>(T).setVendorName("unknown");
+    const_cast<Triple&>(T).setOSAndEnvironmentName("linux-gnu");
+  }
+
   bool ShouldExtI32Param = false, ShouldExtI32Return = false,
        ShouldSignExtI32Param = false;
   // PowerPC64, Sparc64, SystemZ need signext/zeroext on i32 parameters and