Skip to content

Commit b2f8b83

Browse files
committed
Only apply GCC 128-bit integer return behavior on Mingw64
The Windows x64 ABI passes values larger than 8 bytes in registers: > Any argument that doesn't fit in 8 bytes, or isn't 1, 2, 4, or 8 bytes, > must be passed by reference. https://learn.microsoft.com/en-us/cpp/build/x64-calling-convention?view=msvc-170 The Mingw64 ABI chooses to treat 128-bit integers as vectors and thus uses xmm0 but we should not do that for the standard Windows x64 ABI.
1 parent 7346e7c commit b2f8b83

File tree

2 files changed

+12
-9
lines changed

2 files changed

+12
-9
lines changed

clang/lib/CodeGen/Targets/X86.cpp

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3331,13 +3331,16 @@ ABIArgInfo WinX86_64ABIInfo::classify(QualType Ty, unsigned &FreeSSERegs,
33313331
// If it's a parameter type, the normal ABI rule is that arguments larger
33323332
// than 8 bytes are passed indirectly. GCC follows it. We follow it too,
33333333
// even though it isn't particularly efficient.
3334-
if (!IsReturnType)
3335-
return ABIArgInfo::getIndirect(Align, /*ByVal=*/false);
3336-
3337-
// Mingw64 GCC returns i128 in XMM0. Coerce to v2i64 to handle that.
3338-
// Clang matches them for compatibility.
3339-
return ABIArgInfo::getDirect(llvm::FixedVectorType::get(
3340-
llvm::Type::getInt64Ty(getVMContext()), 2));
3334+
if (IsMingw64 && IsReturnType) {
3335+
// Mingw64 GCC returns i128 in XMM0. Coerce to v2i64 to handle that.
3336+
// Clang matches them for compatibility.
3337+
return ABIArgInfo::getDirect(llvm::FixedVectorType::get(
3338+
llvm::Type::getInt64Ty(getVMContext()), 2));
3339+
} else {
3340+
// Otherwise, for arguments in Mingw64 GCC or for MS x64 ABI,
3341+
// pass by reference.
3342+
return ABIArgInfo::getIndirect(Align, /*ByVal=*/false);
3343+
}
33413344

33423345
default:
33433346
break;

clang/test/CodeGen/win64-i128.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,12 @@ typedef int int128_t __attribute__((mode(TI)));
88
int128_t foo(void) { return 0; }
99

1010
// GNU64: define dso_local <2 x i64> @foo()
11-
// MSC64: define dso_local <2 x i64> @foo()
11+
// MSC64: define dso_local void @foo(ptr dead_on_unwind noalias writable sret(i128) align 16 %agg.result)
1212

1313
int128_t bar(int128_t a, int128_t b) { return a * b; }
1414

1515
// GNU64: define dso_local <2 x i64> @bar(ptr noundef %0, ptr noundef %1)
16-
// MSC64: define dso_local <2 x i64> @bar(ptr noundef %0, ptr noundef %1)
16+
// MSC64: define dso_local void @bar(ptr dead_on_unwind noalias writable sret(i128) align 16 %agg.result, ptr noundef %0, ptr noundef %1)
1717

1818
void vararg(int a, ...) {
1919
// GNU64-LABEL: define{{.*}} void @vararg

0 commit comments

Comments
 (0)