diff --git a/clang/lib/CodeGen/Targets/X86.cpp b/clang/lib/CodeGen/Targets/X86.cpp index b7a1374d5b399..b36a6e1396653 100644 --- a/clang/lib/CodeGen/Targets/X86.cpp +++ b/clang/lib/CodeGen/Targets/X86.cpp @@ -3390,6 +3390,9 @@ ABIArgInfo WinX86_64ABIInfo::classify(QualType Ty, unsigned &FreeSSERegs, case BuiltinType::Int128: case BuiltinType::UInt128: + case BuiltinType::Float128: + // 128-bit float and integer types share the same ABI. + // 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. @@ -3400,6 +3403,8 @@ ABIArgInfo WinX86_64ABIInfo::classify(QualType Ty, unsigned &FreeSSERegs, // Mingw64 GCC returns i128 in XMM0. Coerce to v2i64 to handle that. // Clang matches them for compatibility. + // NOTE: GCC actually returns f128 indirectly but will hopefully change. + // See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=115054#c8. return ABIArgInfo::getDirect(llvm::FixedVectorType::get( llvm::Type::getInt64Ty(getVMContext()), 2)); diff --git a/clang/test/CodeGen/win-fp128.c b/clang/test/CodeGen/win-fp128.c new file mode 100644 index 0000000000000..328a7aaa7df57 --- /dev/null +++ b/clang/test/CodeGen/win-fp128.c @@ -0,0 +1,19 @@ +// RUN: %clang_cc1 -triple x86_64-windows-gnu -emit-llvm -o - %s \ +// RUN: | FileCheck %s --check-prefix=CHECK-GNU64 +// __float128 is unsupported on MSVC + +__float128 fp128_ret(void) { return 0; } +// CHECK-GNU64: define dso_local <2 x i64> @fp128_ret() + +__float128 fp128_args(__float128 a, __float128 b) { return a * b; } +// CHECK-GNU64: define dso_local <2 x i64> @fp128_args(ptr noundef %0, ptr noundef %1) + +void fp128_vararg(int a, ...) { + // CHECK-GNU64-LABEL: define dso_local void @fp128_vararg + __builtin_va_list ap; + __builtin_va_start(ap, a); + __float128 i = __builtin_va_arg(ap, __float128); + // CHECK-GNU64: load ptr, ptr + // CHECK-GNU64: load fp128, ptr + __builtin_va_end(ap); +}