Skip to content

Commit

Permalink
Re-land r345676 "[Win64] Handle passing i128 by value"
Browse files Browse the repository at this point in the history
Fix the unintended switch/case fallthrough to avoid changing long double
behavior.
  • Loading branch information
rnk committed Oct 31, 2018
1 parent 4f039e6 commit 4341e8b
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 11 deletions.
44 changes: 33 additions & 11 deletions clang/lib/CodeGen/TargetInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
16 changes: 16 additions & 0 deletions clang/test/CodeGen/win64-i128.c
Original file line number Diff line number Diff line change
@@ -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*)

0 comments on commit 4341e8b

Please sign in to comment.