From 5eb3d750c68ec9b2bef977d9bfa9e895d1d869c8 Mon Sep 17 00:00:00 2001 From: Reid Kleckner Date: Wed, 31 Oct 2018 17:43:55 +0000 Subject: [PATCH] Re-land r345676 "[Win64] Handle passing i128 by value" 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 | 44 ++++++++++++++++++++++++++++---------- test/CodeGen/win64-i128.c | 16 ++++++++++++++ 2 files changed, 49 insertions(+), 11 deletions(-) create mode 100644 test/CodeGen/win64-i128.c diff --git a/lib/CodeGen/TargetInfo.cpp b/lib/CodeGen/TargetInfo.cpp index 11551a3619..fe87f544ed 100644 --- a/lib/CodeGen/TargetInfo.cpp +++ b/lib/CodeGen/TargetInfo.cpp @@ -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(); - 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()) { + 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 index 0000000000..0514c4846c --- /dev/null +++ b/test/CodeGen/win64-i128.c @@ -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*) -- 2.40.0