]> granicus.if.org Git - clang/commitdiff
Re-land r345676 "[Win64] Handle passing i128 by value"
authorReid Kleckner <rnk@google.com>
Wed, 31 Oct 2018 17:43:55 +0000 (17:43 +0000)
committerReid Kleckner <rnk@google.com>
Wed, 31 Oct 2018 17:43:55 +0000 (17:43 +0000)
Fix the unintended switch/case fallthrough to avoid changing long double
behavior.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@345748 91177308-0d34-0410-b5e6-96231b3b80d8

lib/CodeGen/TargetInfo.cpp
test/CodeGen/win64-i128.c [new file with mode: 0644]

index 11551a361927dc9948ff4ba3977a313749d63b4f..fe87f544ed6b1a1a1916f56e135da1fbf6262e02 100644 (file)
@@ -3943,18 +3943,40 @@ ABIArgInfo WinX86_64ABIInfo::classify(QualType Ty, unsigned &FreeSSERegs,
     // Otherwise, coerce it to a small integer.
     return ABIArgInfo::getDirect(llvm::IntegerType::get(getVMContext(), Width));
   }
-  // Bool type is always extended to the ABI, other builtin types are not
-  // extended.
-  const BuiltinType *BT = Ty->getAs<BuiltinType>();
-  if (BT && BT->getKind() == BuiltinType::Bool)
-    return ABIArgInfo::getExtend(Ty);
 
-  // Mingw64 GCC uses the old 80 bit extended precision floating point unit. It
-  // passes them indirectly through memory.
-  if (IsMingw64 && BT && BT->getKind() == BuiltinType::LongDouble) {
-    const llvm::fltSemantics *LDF = &getTarget().getLongDoubleFormat();
-    if (LDF == &llvm::APFloat::x87DoubleExtended())
-      return ABIArgInfo::getIndirect(Align, /*ByVal=*/false);
+  if (const BuiltinType *BT = Ty->getAs<BuiltinType>()) {
+    switch (BT->getKind()) {
+    case BuiltinType::Bool:
+      // Bool type is always extended to the ABI, other builtin types are not
+      // extended.
+      return ABIArgInfo::getExtend(Ty);
+
+    case BuiltinType::LongDouble:
+      // Mingw64 GCC uses the old 80 bit extended precision floating point
+      // unit. It passes them indirectly through memory.
+      if (IsMingw64) {
+        const llvm::fltSemantics *LDF = &getTarget().getLongDoubleFormat();
+        if (LDF == &llvm::APFloat::x87DoubleExtended())
+          return ABIArgInfo::getIndirect(Align, /*ByVal=*/false);
+      }
+      break;
+
+    case BuiltinType::Int128:
+    case BuiltinType::UInt128:
+      // If it's a parameter type, the normal ABI rule is that arguments larger
+      // than 8 bytes are passed indirectly. GCC follows it. We follow it too,
+      // even though it isn't particularly efficient.
+      if (!IsReturnType)
+        return ABIArgInfo::getIndirect(Align, /*ByVal=*/false);
+
+      // Mingw64 GCC returns i128 in XMM0. Coerce to v2i64 to handle that.
+      // Clang matches them for compatibility.
+      return ABIArgInfo::getDirect(
+          llvm::VectorType::get(llvm::Type::getInt64Ty(getVMContext()), 2));
+
+    default:
+      break;
+    }
   }
 
   return ABIArgInfo::getDirect();
diff --git a/test/CodeGen/win64-i128.c b/test/CodeGen/win64-i128.c
new file mode 100644 (file)
index 0000000..0514c48
--- /dev/null
@@ -0,0 +1,16 @@
+// RUN: %clang_cc1 -triple x86_64-windows-gnu -emit-llvm -o - %s \
+// RUN:    | FileCheck %s --check-prefix=GNU64
+// RUN: %clang_cc1 -triple x86_64-windows-msvc -emit-llvm -o - %s \
+// RUN:    | FileCheck %s --check-prefix=MSC64
+
+typedef int int128_t __attribute__((mode(TI)));
+
+int128_t foo() { return 0; }
+
+// GNU64: define dso_local <2 x i64> @foo()
+// MSC64: define dso_local <2 x i64> @foo()
+
+int128_t bar(int128_t a, int128_t b) { return a * b; }
+
+// GNU64: define dso_local <2 x i64> @bar(i128*, i128*)
+// MSC64: define dso_local <2 x i64> @bar(i128*, i128*)