mstorsjo created this revision.
mstorsjo added reviewers: rnk, compnerd.

On x86_64 mingw, long doubles are passed as arguments and returned as if they 
were a struct. For normal functions, this calling convention detail is handled 
within clang when generating the IR. When a math function is handled as a 
builtin, it gets emitted as an LLVM intrinsic call, which for x86_64 mingw in 
most (all?) cases gets emitted as a libcall. When the libcall is lowered in 
llvm, the long double specifics of the calling convention aren't taken into 
account (since they're normally taken care of in clang).

Skip emitting intrinsics for the functions that handle long doubles for this 
target.

While use of long double might be quite rare in general, it's used internally 
in the implementation of some mingw math functions for other precisions than 
long double.


Repository:
  rC Clang

https://reviews.llvm.org/D44582

Files:
  lib/CodeGen/CGBuiltin.cpp
  test/CodeGen/mingw-x86_64-long-double-builtins.c


Index: test/CodeGen/mingw-x86_64-long-double-builtins.c
===================================================================
--- /dev/null
+++ test/CodeGen/mingw-x86_64-long-double-builtins.c
@@ -0,0 +1,11 @@
+// RUN: %clang_cc1 -triple x86_64-mingw32 -emit-llvm -o - %s | FileCheck %s
+
+// Check that long double math functions are emitted as direct function
+// calls instead of as intrinsics.
+
+long double floorl(long double);
+
+long double foo(long double a) {
+  return floorl(a);
+// CHECK: call void @floorl(x86_fp80* sret {{.*}}, x86_fp80* {{.*}})
+}
Index: lib/CodeGen/CGBuiltin.cpp
===================================================================
--- lib/CodeGen/CGBuiltin.cpp
+++ lib/CodeGen/CGBuiltin.cpp
@@ -945,12 +945,26 @@
                                                Result.Val.getFloat()));
   }
 
+  bool EmitMathIntrinsic = true;
+  const Triple& Triple = getTarget().getTriple();
+  if (Triple.isWindowsGNUEnvironment() &&
+      Triple.getArch() == llvm::Triple::x86_64) {
+    // On x86_64 mingw, the calling convention handles long doubles as
+    // structs. This detail is normally handled within clang, but
+    // intrinsics lowered into libcalls in LLVM don't handle this.
+    // For these cases, skip emitting an intrinsic and emit a normal
+    // function call with the right calling convention instead.
+    const char *TypeStr = getContext().BuiltinInfo.getTypeString(BuiltinID);
+    if (strstr(TypeStr, "Ld")) // long double
+      EmitMathIntrinsic = false;
+  }
+
   // There are LLVM math intrinsics/instructions corresponding to math library
   // functions except the LLVM op will never set errno while the math library
   // might. Also, math builtins have the same semantics as their math library
   // twins. Thus, we can transform math library and builtin calls to their
   // LLVM counterparts if the call is marked 'const' (known to never set 
errno).
-  if (FD->hasAttr<ConstAttr>()) {
+  if (FD->hasAttr<ConstAttr>() && EmitMathIntrinsic) {
     switch (BuiltinID) {
     case Builtin::BIceil:
     case Builtin::BIceilf:


Index: test/CodeGen/mingw-x86_64-long-double-builtins.c
===================================================================
--- /dev/null
+++ test/CodeGen/mingw-x86_64-long-double-builtins.c
@@ -0,0 +1,11 @@
+// RUN: %clang_cc1 -triple x86_64-mingw32 -emit-llvm -o - %s | FileCheck %s
+
+// Check that long double math functions are emitted as direct function
+// calls instead of as intrinsics.
+
+long double floorl(long double);
+
+long double foo(long double a) {
+  return floorl(a);
+// CHECK: call void @floorl(x86_fp80* sret {{.*}}, x86_fp80* {{.*}})
+}
Index: lib/CodeGen/CGBuiltin.cpp
===================================================================
--- lib/CodeGen/CGBuiltin.cpp
+++ lib/CodeGen/CGBuiltin.cpp
@@ -945,12 +945,26 @@
                                                Result.Val.getFloat()));
   }
 
+  bool EmitMathIntrinsic = true;
+  const Triple& Triple = getTarget().getTriple();
+  if (Triple.isWindowsGNUEnvironment() &&
+      Triple.getArch() == llvm::Triple::x86_64) {
+    // On x86_64 mingw, the calling convention handles long doubles as
+    // structs. This detail is normally handled within clang, but
+    // intrinsics lowered into libcalls in LLVM don't handle this.
+    // For these cases, skip emitting an intrinsic and emit a normal
+    // function call with the right calling convention instead.
+    const char *TypeStr = getContext().BuiltinInfo.getTypeString(BuiltinID);
+    if (strstr(TypeStr, "Ld")) // long double
+      EmitMathIntrinsic = false;
+  }
+
   // There are LLVM math intrinsics/instructions corresponding to math library
   // functions except the LLVM op will never set errno while the math library
   // might. Also, math builtins have the same semantics as their math library
   // twins. Thus, we can transform math library and builtin calls to their
   // LLVM counterparts if the call is marked 'const' (known to never set errno).
-  if (FD->hasAttr<ConstAttr>()) {
+  if (FD->hasAttr<ConstAttr>() && EmitMathIntrinsic) {
     switch (BuiltinID) {
     case Builtin::BIceil:
     case Builtin::BIceilf:
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to