Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 8 additions & 6 deletions clang/lib/CodeGen/Targets/X86.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3437,8 +3437,6 @@ 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.
Expand All @@ -3449,10 +3447,14 @@ 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));
if (BT->getKind() == BuiltinType::Int128 ||
BT->getKind() == BuiltinType::UInt128)
return ABIArgInfo::getDirect(llvm::FixedVectorType::get(
llvm::Type::getInt64Ty(getVMContext()), 2));

// Mingw64 GCC returns f128 via sret. Clang matches that for
// compatibility.
break;
Comment thread
folkertdev marked this conversation as resolved.
Outdated

default:
break;
Expand Down
4 changes: 2 additions & 2 deletions clang/test/CodeGen/win-fp128.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@
// __float128 is unsupported on MSVC

__float128 fp128_ret(void) { return 0; }
// CHECK-GNU64: define dso_local <2 x i64> @fp128_ret()
// CHECK-GNU64: define dso_local fp128 @fp128_ret()
Comment thread
folkertdev marked this conversation as resolved.
Outdated

__float128 fp128_args(__float128 a, __float128 b) { return a * b; }
// CHECK-GNU64: define dso_local <2 x i64> @fp128_args(ptr noundef dead_on_return %0, ptr noundef dead_on_return %1)
// CHECK-GNU64: define dso_local fp128 @fp128_args(ptr noundef dead_on_return %0, ptr noundef dead_on_return %1)

void fp128_vararg(int a, ...) {
// CHECK-GNU64-LABEL: define dso_local void @fp128_vararg
Expand Down
5 changes: 5 additions & 0 deletions llvm/docs/ReleaseNotes.md
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,11 @@ Makes programs 10x faster by doing Special New Thing.
two-register push in Windows x64 V3 unwind info. The directive takes two
register operands: ``.seh_push2regs %r12, %r13``.

* The `fp128` type is now passed via sret instead of XMM0 for some calling
conventions to match GCC. The C, Win64 and vectorcall calling conventions
now use sret, other calling conventions do not need to be compatible with
GCC and still return via XMM0.
Comment thread
folkertdev marked this conversation as resolved.
Outdated

### Changes to the OCaml bindings

### Changes to the Python bindings
Expand Down
34 changes: 32 additions & 2 deletions llvm/lib/Target/X86/X86CallingConv.td

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just thinking as somebody who has chased ABI code around - might be worth a note in RetCC_X86_Win64_C that there's an exception for f128 in X86TargetLowering::CanLowerReturn, since that's a bit unconventional.

Original file line number Diff line number Diff line change
Expand Up @@ -390,8 +390,8 @@ def RetCC_X86_Win64_C : CallingConv<[

// X86-64 vectorcall return-value convention.
def RetCC_X86_64_Vectorcall : CallingConv<[
// Vectorcall calling convention always returns FP values in XMMs.
CCIfType<[f32, f64, f128],
// See RetCC_X86_64 for details on f128.
CCIfType<[f32, f64],
CCAssignToReg<[XMM0, XMM1, XMM2, XMM3]>>,
Comment thread
folkertdev marked this conversation as resolved.

// Otherwise, everything is the same as Windows X86-64 C CC.
Expand Down Expand Up @@ -469,6 +469,36 @@ def RetCC_X86_32 : CallingConv<[

// This is the root return-value convention for the X86-64 backend.
def RetCC_X86_64 : CallingConv<[
// Mingw64 GCC returns f128 via sret, and LLVM matches it for compatibility.
//
// Using sret is a reasonable implementation of the Windows x64 calling
// convention:
//
// https://learn.microsoft.com/en-us/cpp/build/x64-calling-convention?view=msvc-170#return-values
//
// > Otherwise, the caller must allocate memory for the return value and pass
// > a pointer to it as the first argument.
//
// Although it is not the only reasonable interpretation:
//
// > Nonscalar types including floats, doubles, and vector types such as
// > __m128, __m128i, __m128d are returned in XMM0.
//
// For now, we prefer compatibility with GCC. If official guidelines are ever
// published, this can be revisited.
//
// The alignment of 1 is so the frame's alignment is not bumped.
CCIfType<[f128], CCIfCC<"CallingConv::Win64", CCAssignToStack<16, 1>>>,
CCIfType<[f128], CCIfSubtarget<"isTargetWin64()",
CCIfCC<"CallingConv::C", CCAssignToStack<16, 1>>>>,
CCIfType<[f128], CCIfSubtarget<"isTargetWin64()",
CCIfCC<"CallingConv::X86_VectorCall", CCAssignToStack<16, 1>>>>,
// UEFI also uses the Win64 CC.
CCIfType<[f128], CCIfSubtarget<"isTargetUEFI64()",
CCIfCC<"CallingConv::C", CCAssignToStack<16, 1>>>>,
CCIfType<[f128], CCIfSubtarget<"isTargetUEFI64()",
CCIfCC<"CallingConv::X86_VectorCall", CCAssignToStack<16, 1>>>>,
Comment thread
folkertdev marked this conversation as resolved.
Outdated

// HiPE uses RetCC_X86_64_HiPE
CCIfCC<"CallingConv::HiPE", CCDelegateTo<RetCC_X86_64_HiPE>>,

Expand Down
8 changes: 7 additions & 1 deletion llvm/lib/Target/X86/X86ISelLoweringCall.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -672,7 +672,13 @@ bool X86TargetLowering::CanLowerReturn(
const Type *RetTy) const {
SmallVector<CCValAssign, 16> RVLocs;
CCState CCInfo(CallConv, isVarArg, MF, RVLocs, Context);
return CCInfo.CheckReturn(Outs, RetCC_X86);
if (!CCInfo.CheckReturn(Outs, RetCC_X86))
return false;

// Demotion to sret when the value must be returned via memory. This is the
// case for fp128 on windows.
return llvm::none_of(RVLocs,
[](const CCValAssign &VA) { return VA.isMemLoc(); });
Comment thread
folkertdev marked this conversation as resolved.
Outdated
}

const MCPhysReg *X86TargetLowering::getScratchRegisters(CallingConv::ID) const {
Expand Down
Loading