Skip to content

Commit 0897caa

Browse files
committed
[Win64] Handle passing i128 by value
For arguments, pass it indirectly, since the ABI doc says pretty clearly that arguments larger than 8 bytes are passed indirectly. This makes va_list handling easier, anyway. When returning, GCC returns in XMM0, and we match them. Fixes PR39492. llvm-svn: 345676
1 parent 91242b7 commit 0897caa

File tree

2 files changed

+48
-11
lines changed

2 files changed

+48
-11
lines changed

clang/lib/CodeGen/TargetInfo.cpp

+32-11
Original file line numberDiff line numberDiff line change
@@ -3944,18 +3944,39 @@ ABIArgInfo WinX86_64ABIInfo::classify(QualType Ty, unsigned &FreeSSERegs,
39443944
return ABIArgInfo::getDirect(llvm::IntegerType::get(getVMContext(), Width));
39453945
}
39463946

3947-
// Bool type is always extended to the ABI, other builtin types are not
3948-
// extended.
3949-
const BuiltinType *BT = Ty->getAs<BuiltinType>();
3950-
if (BT && BT->getKind() == BuiltinType::Bool)
3951-
return ABIArgInfo::getExtend(Ty);
3947+
if (const BuiltinType *BT = Ty->getAs<BuiltinType>()) {
3948+
switch (BT->getKind()) {
3949+
case BuiltinType::Bool:
3950+
// Bool type is always extended to the ABI, other builtin types are not
3951+
// extended.
3952+
return ABIArgInfo::getExtend(Ty);
39523953

3953-
// Mingw64 GCC uses the old 80 bit extended precision floating point unit. It
3954-
// passes them indirectly through memory.
3955-
if (IsMingw64 && BT && BT->getKind() == BuiltinType::LongDouble) {
3956-
const llvm::fltSemantics *LDF = &getTarget().getLongDoubleFormat();
3957-
if (LDF == &llvm::APFloat::x87DoubleExtended())
3958-
return ABIArgInfo::getIndirect(Align, /*ByVal=*/false);
3954+
case BuiltinType::LongDouble:
3955+
// Mingw64 GCC uses the old 80 bit extended precision floating point
3956+
// unit. It passes them indirectly through memory.
3957+
if (IsMingw64) {
3958+
const llvm::fltSemantics *LDF = &getTarget().getLongDoubleFormat();
3959+
if (LDF == &llvm::APFloat::x87DoubleExtended())
3960+
return ABIArgInfo::getIndirect(Align, /*ByVal=*/false);
3961+
break;
3962+
}
3963+
3964+
case BuiltinType::Int128:
3965+
case BuiltinType::UInt128:
3966+
// If it's a parameter type, the normal ABI rule is that arguments larger
3967+
// than 8 bytes are passed indirectly. GCC follows it. We follow it too,
3968+
// even though it isn't particularly efficient.
3969+
if (!IsReturnType)
3970+
return ABIArgInfo::getIndirect(Align, /*ByVal=*/false);
3971+
3972+
// Mingw64 GCC returns i128 in XMM0. Coerce to v2i64 to handle that.
3973+
// Clang matches them for compatibility.
3974+
return ABIArgInfo::getDirect(
3975+
llvm::VectorType::get(llvm::Type::getInt64Ty(getVMContext()), 2));
3976+
3977+
default:
3978+
break;
3979+
}
39593980
}
39603981

39613982
return ABIArgInfo::getDirect();

clang/test/CodeGen/win64-i128.c

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// RUN: %clang_cc1 -triple x86_64-windows-gnu -emit-llvm -o - %s \
2+
// RUN: | FileCheck %s --check-prefix=GNU64
3+
// RUN: %clang_cc1 -triple x86_64-windows-msvc -emit-llvm -o - %s \
4+
// RUN: | FileCheck %s --check-prefix=MSC64
5+
6+
typedef int int128_t __attribute__((mode(TI)));
7+
8+
int128_t foo() { return 0; }
9+
10+
// GNU64: define dso_local <2 x i64> @foo()
11+
// MSC64: define dso_local <2 x i64> @foo()
12+
13+
int128_t bar(int128_t a, int128_t b) { return a * b; }
14+
15+
// GNU64: define dso_local <2 x i64> @bar(i128*, i128*)
16+
// MSC64: define dso_local <2 x i64> @bar(i128*, i128*)

0 commit comments

Comments
 (0)