[X86][Windows] Return fp128 on the stack#204887
Conversation
This is in line with mingw64 gcc and follows the win64 CC (at least more)
|
@llvm/pr-subscribers-backend-x86 @llvm/pr-subscribers-clang-codegen Author: Folkert de Vries (folkertdev) ChangesSubsumes #194214 For x86-64 Windows targets, LLVM currently returns https://gcc.godbolt.org/z/xnWeGqcbW Microsoft does not specify a Thus, change Relates to the pass ABI change in 5ee1c0b ("[windows] Always pass fp128 arguments indirectly"). Patch is 63.26 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/204887.diff 6 Files Affected:
diff --git a/clang/lib/CodeGen/Targets/X86.cpp b/clang/lib/CodeGen/Targets/X86.cpp
index dbe4d656aabc5..77c912b021604 100644
--- a/clang/lib/CodeGen/Targets/X86.cpp
+++ b/clang/lib/CodeGen/Targets/X86.cpp
@@ -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.
@@ -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;
default:
break;
diff --git a/clang/test/CodeGen/win-fp128.c b/clang/test/CodeGen/win-fp128.c
index 58e203d4fc8ed..dc144f899fa4f 100644
--- a/clang/test/CodeGen/win-fp128.c
+++ b/clang/test/CodeGen/win-fp128.c
@@ -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()
__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
diff --git a/llvm/lib/Target/X86/X86ISelLoweringCall.cpp b/llvm/lib/Target/X86/X86ISelLoweringCall.cpp
index 7c068115df481..bce581ad7a48b 100644
--- a/llvm/lib/Target/X86/X86ISelLoweringCall.cpp
+++ b/llvm/lib/Target/X86/X86ISelLoweringCall.cpp
@@ -670,6 +670,20 @@ bool X86TargetLowering::CanLowerReturn(
CallingConv::ID CallConv, MachineFunction &MF, bool isVarArg,
const SmallVectorImpl<ISD::OutputArg> &Outs, LLVMContext &Context,
const Type *RetTy) const {
+ // Mingw64 GCC returns f128 via sret, which matches the documentation 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.
+ //
+ // Return false, which will perform sret demotion.
+ if (Subtarget.isCallingConvWin64(CallConv) &&
+ llvm::any_of(
+ Outs, [](const ISD::OutputArg &Out) { return Out.VT == MVT::f128; }))
+ return false;
+
SmallVector<CCValAssign, 16> RVLocs;
CCState CCInfo(CallConv, isVarArg, MF, RVLocs, Context);
return CCInfo.CheckReturn(Outs, RetCC_X86);
diff --git a/llvm/test/CodeGen/X86/fp128-libcalls-strict.ll b/llvm/test/CodeGen/X86/fp128-libcalls-strict.ll
index ad2d690fd7ed0..dfff88d30bcd4 100644
--- a/llvm/test/CodeGen/X86/fp128-libcalls-strict.ll
+++ b/llvm/test/CodeGen/X86/fp128-libcalls-strict.ll
@@ -79,15 +79,22 @@ define fp128 @add(fp128 %x, fp128 %y) nounwind strictfp {
;
; WIN-LABEL: add:
; WIN: # %bb.0: # %entry
-; WIN-NEXT: subq $72, %rsp
-; WIN-NEXT: movaps (%rcx), %xmm0
-; WIN-NEXT: movaps (%rdx), %xmm1
+; WIN-NEXT: pushq %rsi
+; WIN-NEXT: subq $80, %rsp
+; WIN-NEXT: movq %rcx, %rsi
+; WIN-NEXT: movaps (%rdx), %xmm0
+; WIN-NEXT: movaps (%r8), %xmm1
; WIN-NEXT: movaps %xmm1, {{[0-9]+}}(%rsp)
; WIN-NEXT: movaps %xmm0, {{[0-9]+}}(%rsp)
; WIN-NEXT: leaq {{[0-9]+}}(%rsp), %rcx
; WIN-NEXT: leaq {{[0-9]+}}(%rsp), %rdx
+; WIN-NEXT: leaq {{[0-9]+}}(%rsp), %r8
; WIN-NEXT: callq __addtf3
-; WIN-NEXT: addq $72, %rsp
+; WIN-NEXT: movaps {{[0-9]+}}(%rsp), %xmm0
+; WIN-NEXT: movaps %xmm0, (%rsi)
+; WIN-NEXT: movq %rsi, %rax
+; WIN-NEXT: addq $80, %rsp
+; WIN-NEXT: popq %rsi
; WIN-NEXT: retq
;
; WIN-X86-LABEL: add:
@@ -201,15 +208,22 @@ define fp128 @sub(fp128 %x, fp128 %y) nounwind strictfp {
;
; WIN-LABEL: sub:
; WIN: # %bb.0: # %entry
-; WIN-NEXT: subq $72, %rsp
-; WIN-NEXT: movaps (%rcx), %xmm0
-; WIN-NEXT: movaps (%rdx), %xmm1
+; WIN-NEXT: pushq %rsi
+; WIN-NEXT: subq $80, %rsp
+; WIN-NEXT: movq %rcx, %rsi
+; WIN-NEXT: movaps (%rdx), %xmm0
+; WIN-NEXT: movaps (%r8), %xmm1
; WIN-NEXT: movaps %xmm1, {{[0-9]+}}(%rsp)
; WIN-NEXT: movaps %xmm0, {{[0-9]+}}(%rsp)
; WIN-NEXT: leaq {{[0-9]+}}(%rsp), %rcx
; WIN-NEXT: leaq {{[0-9]+}}(%rsp), %rdx
+; WIN-NEXT: leaq {{[0-9]+}}(%rsp), %r8
; WIN-NEXT: callq __subtf3
-; WIN-NEXT: addq $72, %rsp
+; WIN-NEXT: movaps {{[0-9]+}}(%rsp), %xmm0
+; WIN-NEXT: movaps %xmm0, (%rsi)
+; WIN-NEXT: movq %rsi, %rax
+; WIN-NEXT: addq $80, %rsp
+; WIN-NEXT: popq %rsi
; WIN-NEXT: retq
;
; WIN-X86-LABEL: sub:
@@ -323,15 +337,22 @@ define fp128 @mul(fp128 %x, fp128 %y) nounwind strictfp {
;
; WIN-LABEL: mul:
; WIN: # %bb.0: # %entry
-; WIN-NEXT: subq $72, %rsp
-; WIN-NEXT: movaps (%rcx), %xmm0
-; WIN-NEXT: movaps (%rdx), %xmm1
+; WIN-NEXT: pushq %rsi
+; WIN-NEXT: subq $80, %rsp
+; WIN-NEXT: movq %rcx, %rsi
+; WIN-NEXT: movaps (%rdx), %xmm0
+; WIN-NEXT: movaps (%r8), %xmm1
; WIN-NEXT: movaps %xmm1, {{[0-9]+}}(%rsp)
; WIN-NEXT: movaps %xmm0, {{[0-9]+}}(%rsp)
; WIN-NEXT: leaq {{[0-9]+}}(%rsp), %rcx
; WIN-NEXT: leaq {{[0-9]+}}(%rsp), %rdx
+; WIN-NEXT: leaq {{[0-9]+}}(%rsp), %r8
; WIN-NEXT: callq __multf3
-; WIN-NEXT: addq $72, %rsp
+; WIN-NEXT: movaps {{[0-9]+}}(%rsp), %xmm0
+; WIN-NEXT: movaps %xmm0, (%rsi)
+; WIN-NEXT: movq %rsi, %rax
+; WIN-NEXT: addq $80, %rsp
+; WIN-NEXT: popq %rsi
; WIN-NEXT: retq
;
; WIN-X86-LABEL: mul:
@@ -445,15 +466,22 @@ define fp128 @div(fp128 %x, fp128 %y) nounwind strictfp {
;
; WIN-LABEL: div:
; WIN: # %bb.0: # %entry
-; WIN-NEXT: subq $72, %rsp
-; WIN-NEXT: movaps (%rcx), %xmm0
-; WIN-NEXT: movaps (%rdx), %xmm1
+; WIN-NEXT: pushq %rsi
+; WIN-NEXT: subq $80, %rsp
+; WIN-NEXT: movq %rcx, %rsi
+; WIN-NEXT: movaps (%rdx), %xmm0
+; WIN-NEXT: movaps (%r8), %xmm1
; WIN-NEXT: movaps %xmm1, {{[0-9]+}}(%rsp)
; WIN-NEXT: movaps %xmm0, {{[0-9]+}}(%rsp)
; WIN-NEXT: leaq {{[0-9]+}}(%rsp), %rcx
; WIN-NEXT: leaq {{[0-9]+}}(%rsp), %rdx
+; WIN-NEXT: leaq {{[0-9]+}}(%rsp), %r8
; WIN-NEXT: callq __divtf3
-; WIN-NEXT: addq $72, %rsp
+; WIN-NEXT: movaps {{[0-9]+}}(%rsp), %xmm0
+; WIN-NEXT: movaps %xmm0, (%rsi)
+; WIN-NEXT: movq %rsi, %rax
+; WIN-NEXT: addq $80, %rsp
+; WIN-NEXT: popq %rsi
; WIN-NEXT: retq
;
; WIN-X86-LABEL: div:
@@ -568,18 +596,25 @@ define fp128 @fma(fp128 %x, fp128 %y, fp128 %z) nounwind strictfp {
;
; WIN-LABEL: fma:
; WIN: # %bb.0: # %entry
-; WIN-NEXT: subq $88, %rsp
-; WIN-NEXT: movaps (%r8), %xmm0
-; WIN-NEXT: movaps (%rcx), %xmm1
-; WIN-NEXT: movaps (%rdx), %xmm2
+; WIN-NEXT: pushq %rsi
+; WIN-NEXT: subq $96, %rsp
+; WIN-NEXT: movq %rcx, %rsi
+; WIN-NEXT: movaps (%r9), %xmm0
+; WIN-NEXT: movaps (%rdx), %xmm1
+; WIN-NEXT: movaps (%r8), %xmm2
; WIN-NEXT: movaps %xmm2, {{[0-9]+}}(%rsp)
; WIN-NEXT: movaps %xmm1, {{[0-9]+}}(%rsp)
; WIN-NEXT: movaps %xmm0, {{[0-9]+}}(%rsp)
; WIN-NEXT: leaq {{[0-9]+}}(%rsp), %rcx
; WIN-NEXT: leaq {{[0-9]+}}(%rsp), %rdx
; WIN-NEXT: leaq {{[0-9]+}}(%rsp), %r8
+; WIN-NEXT: leaq {{[0-9]+}}(%rsp), %r9
; WIN-NEXT: callq fmal
-; WIN-NEXT: addq $88, %rsp
+; WIN-NEXT: movaps {{[0-9]+}}(%rsp), %xmm0
+; WIN-NEXT: movaps %xmm0, (%rsi)
+; WIN-NEXT: movq %rsi, %rax
+; WIN-NEXT: addq $96, %rsp
+; WIN-NEXT: popq %rsi
; WIN-NEXT: retq
;
; WIN-X86-LABEL: fma:
@@ -694,15 +729,22 @@ define fp128 @frem(fp128 %x, fp128 %y) nounwind strictfp {
;
; WIN-LABEL: frem:
; WIN: # %bb.0: # %entry
-; WIN-NEXT: subq $72, %rsp
-; WIN-NEXT: movaps (%rcx), %xmm0
-; WIN-NEXT: movaps (%rdx), %xmm1
+; WIN-NEXT: pushq %rsi
+; WIN-NEXT: subq $80, %rsp
+; WIN-NEXT: movq %rcx, %rsi
+; WIN-NEXT: movaps (%rdx), %xmm0
+; WIN-NEXT: movaps (%r8), %xmm1
; WIN-NEXT: movaps %xmm1, {{[0-9]+}}(%rsp)
; WIN-NEXT: movaps %xmm0, {{[0-9]+}}(%rsp)
; WIN-NEXT: leaq {{[0-9]+}}(%rsp), %rcx
; WIN-NEXT: leaq {{[0-9]+}}(%rsp), %rdx
+; WIN-NEXT: leaq {{[0-9]+}}(%rsp), %r8
; WIN-NEXT: callq fmodl
-; WIN-NEXT: addq $72, %rsp
+; WIN-NEXT: movaps {{[0-9]+}}(%rsp), %xmm0
+; WIN-NEXT: movaps %xmm0, (%rsi)
+; WIN-NEXT: movq %rsi, %rax
+; WIN-NEXT: addq $80, %rsp
+; WIN-NEXT: popq %rsi
; WIN-NEXT: retq
;
; WIN-X86-LABEL: frem:
@@ -797,12 +839,19 @@ define fp128 @ceil(fp128 %x) nounwind strictfp {
;
; WIN-LABEL: ceil:
; WIN: # %bb.0: # %entry
-; WIN-NEXT: subq $56, %rsp
-; WIN-NEXT: movaps (%rcx), %xmm0
+; WIN-NEXT: pushq %rsi
+; WIN-NEXT: subq $64, %rsp
+; WIN-NEXT: movq %rcx, %rsi
+; WIN-NEXT: movaps (%rdx), %xmm0
; WIN-NEXT: movaps %xmm0, {{[0-9]+}}(%rsp)
; WIN-NEXT: leaq {{[0-9]+}}(%rsp), %rcx
+; WIN-NEXT: leaq {{[0-9]+}}(%rsp), %rdx
; WIN-NEXT: callq ceill
-; WIN-NEXT: addq $56, %rsp
+; WIN-NEXT: movaps {{[0-9]+}}(%rsp), %xmm0
+; WIN-NEXT: movaps %xmm0, (%rsi)
+; WIN-NEXT: movq %rsi, %rax
+; WIN-NEXT: addq $64, %rsp
+; WIN-NEXT: popq %rsi
; WIN-NEXT: retq
;
; WIN-X86-LABEL: ceil:
@@ -887,12 +936,19 @@ define fp128 @acos(fp128 %x) nounwind strictfp {
;
; WIN-LABEL: acos:
; WIN: # %bb.0: # %entry
-; WIN-NEXT: subq $56, %rsp
-; WIN-NEXT: movaps (%rcx), %xmm0
+; WIN-NEXT: pushq %rsi
+; WIN-NEXT: subq $64, %rsp
+; WIN-NEXT: movq %rcx, %rsi
+; WIN-NEXT: movaps (%rdx), %xmm0
; WIN-NEXT: movaps %xmm0, {{[0-9]+}}(%rsp)
; WIN-NEXT: leaq {{[0-9]+}}(%rsp), %rcx
+; WIN-NEXT: leaq {{[0-9]+}}(%rsp), %rdx
; WIN-NEXT: callq acosl
-; WIN-NEXT: addq $56, %rsp
+; WIN-NEXT: movaps {{[0-9]+}}(%rsp), %xmm0
+; WIN-NEXT: movaps %xmm0, (%rsi)
+; WIN-NEXT: movq %rsi, %rax
+; WIN-NEXT: addq $64, %rsp
+; WIN-NEXT: popq %rsi
; WIN-NEXT: retq
;
; WIN-X86-LABEL: acos:
@@ -977,12 +1033,19 @@ define fp128 @cos(fp128 %x) nounwind strictfp {
;
; WIN-LABEL: cos:
; WIN: # %bb.0: # %entry
-; WIN-NEXT: subq $56, %rsp
-; WIN-NEXT: movaps (%rcx), %xmm0
+; WIN-NEXT: pushq %rsi
+; WIN-NEXT: subq $64, %rsp
+; WIN-NEXT: movq %rcx, %rsi
+; WIN-NEXT: movaps (%rdx), %xmm0
; WIN-NEXT: movaps %xmm0, {{[0-9]+}}(%rsp)
; WIN-NEXT: leaq {{[0-9]+}}(%rsp), %rcx
+; WIN-NEXT: leaq {{[0-9]+}}(%rsp), %rdx
; WIN-NEXT: callq cosl
-; WIN-NEXT: addq $56, %rsp
+; WIN-NEXT: movaps {{[0-9]+}}(%rsp), %xmm0
+; WIN-NEXT: movaps %xmm0, (%rsi)
+; WIN-NEXT: movq %rsi, %rax
+; WIN-NEXT: addq $64, %rsp
+; WIN-NEXT: popq %rsi
; WIN-NEXT: retq
;
; WIN-X86-LABEL: cos:
@@ -1067,12 +1130,19 @@ define fp128 @cosh(fp128 %x) nounwind strictfp {
;
; WIN-LABEL: cosh:
; WIN: # %bb.0: # %entry
-; WIN-NEXT: subq $56, %rsp
-; WIN-NEXT: movaps (%rcx), %xmm0
+; WIN-NEXT: pushq %rsi
+; WIN-NEXT: subq $64, %rsp
+; WIN-NEXT: movq %rcx, %rsi
+; WIN-NEXT: movaps (%rdx), %xmm0
; WIN-NEXT: movaps %xmm0, {{[0-9]+}}(%rsp)
; WIN-NEXT: leaq {{[0-9]+}}(%rsp), %rcx
+; WIN-NEXT: leaq {{[0-9]+}}(%rsp), %rdx
; WIN-NEXT: callq coshl
-; WIN-NEXT: addq $56, %rsp
+; WIN-NEXT: movaps {{[0-9]+}}(%rsp), %xmm0
+; WIN-NEXT: movaps %xmm0, (%rsi)
+; WIN-NEXT: movq %rsi, %rax
+; WIN-NEXT: addq $64, %rsp
+; WIN-NEXT: popq %rsi
; WIN-NEXT: retq
;
; WIN-X86-LABEL: cosh:
@@ -1157,12 +1227,19 @@ define fp128 @exp(fp128 %x) nounwind strictfp {
;
; WIN-LABEL: exp:
; WIN: # %bb.0: # %entry
-; WIN-NEXT: subq $56, %rsp
-; WIN-NEXT: movaps (%rcx), %xmm0
+; WIN-NEXT: pushq %rsi
+; WIN-NEXT: subq $64, %rsp
+; WIN-NEXT: movq %rcx, %rsi
+; WIN-NEXT: movaps (%rdx), %xmm0
; WIN-NEXT: movaps %xmm0, {{[0-9]+}}(%rsp)
; WIN-NEXT: leaq {{[0-9]+}}(%rsp), %rcx
+; WIN-NEXT: leaq {{[0-9]+}}(%rsp), %rdx
; WIN-NEXT: callq expl
-; WIN-NEXT: addq $56, %rsp
+; WIN-NEXT: movaps {{[0-9]+}}(%rsp), %xmm0
+; WIN-NEXT: movaps %xmm0, (%rsi)
+; WIN-NEXT: movq %rsi, %rax
+; WIN-NEXT: addq $64, %rsp
+; WIN-NEXT: popq %rsi
; WIN-NEXT: retq
;
; WIN-X86-LABEL: exp:
@@ -1247,12 +1324,19 @@ define fp128 @exp2(fp128 %x) nounwind strictfp {
;
; WIN-LABEL: exp2:
; WIN: # %bb.0: # %entry
-; WIN-NEXT: subq $56, %rsp
-; WIN-NEXT: movaps (%rcx), %xmm0
+; WIN-NEXT: pushq %rsi
+; WIN-NEXT: subq $64, %rsp
+; WIN-NEXT: movq %rcx, %rsi
+; WIN-NEXT: movaps (%rdx), %xmm0
; WIN-NEXT: movaps %xmm0, {{[0-9]+}}(%rsp)
; WIN-NEXT: leaq {{[0-9]+}}(%rsp), %rcx
+; WIN-NEXT: leaq {{[0-9]+}}(%rsp), %rdx
; WIN-NEXT: callq exp2l
-; WIN-NEXT: addq $56, %rsp
+; WIN-NEXT: movaps {{[0-9]+}}(%rsp), %xmm0
+; WIN-NEXT: movaps %xmm0, (%rsi)
+; WIN-NEXT: movq %rsi, %rax
+; WIN-NEXT: addq $64, %rsp
+; WIN-NEXT: popq %rsi
; WIN-NEXT: retq
;
; WIN-X86-LABEL: exp2:
@@ -1337,12 +1421,19 @@ define fp128 @floor(fp128 %x) nounwind strictfp {
;
; WIN-LABEL: floor:
; WIN: # %bb.0: # %entry
-; WIN-NEXT: subq $56, %rsp
-; WIN-NEXT: movaps (%rcx), %xmm0
+; WIN-NEXT: pushq %rsi
+; WIN-NEXT: subq $64, %rsp
+; WIN-NEXT: movq %rcx, %rsi
+; WIN-NEXT: movaps (%rdx), %xmm0
; WIN-NEXT: movaps %xmm0, {{[0-9]+}}(%rsp)
; WIN-NEXT: leaq {{[0-9]+}}(%rsp), %rcx
+; WIN-NEXT: leaq {{[0-9]+}}(%rsp), %rdx
; WIN-NEXT: callq floorl
-; WIN-NEXT: addq $56, %rsp
+; WIN-NEXT: movaps {{[0-9]+}}(%rsp), %xmm0
+; WIN-NEXT: movaps %xmm0, (%rsi)
+; WIN-NEXT: movq %rsi, %rax
+; WIN-NEXT: addq $64, %rsp
+; WIN-NEXT: popq %rsi
; WIN-NEXT: retq
;
; WIN-X86-LABEL: floor:
@@ -1427,12 +1518,19 @@ define fp128 @log(fp128 %x) nounwind strictfp {
;
; WIN-LABEL: log:
; WIN: # %bb.0: # %entry
-; WIN-NEXT: subq $56, %rsp
-; WIN-NEXT: movaps (%rcx), %xmm0
+; WIN-NEXT: pushq %rsi
+; WIN-NEXT: subq $64, %rsp
+; WIN-NEXT: movq %rcx, %rsi
+; WIN-NEXT: movaps (%rdx), %xmm0
; WIN-NEXT: movaps %xmm0, {{[0-9]+}}(%rsp)
; WIN-NEXT: leaq {{[0-9]+}}(%rsp), %rcx
+; WIN-NEXT: leaq {{[0-9]+}}(%rsp), %rdx
; WIN-NEXT: callq logl
-; WIN-NEXT: addq $56, %rsp
+; WIN-NEXT: movaps {{[0-9]+}}(%rsp), %xmm0
+; WIN-NEXT: movaps %xmm0, (%rsi)
+; WIN-NEXT: movq %rsi, %rax
+; WIN-NEXT: addq $64, %rsp
+; WIN-NEXT: popq %rsi
; WIN-NEXT: retq
;
; WIN-X86-LABEL: log:
@@ -1517,12 +1615,19 @@ define fp128 @log10(fp128 %x) nounwind strictfp {
;
; WIN-LABEL: log10:
; WIN: # %bb.0: # %entry
-; WIN-NEXT: subq $56, %rsp
-; WIN-NEXT: movaps (%rcx), %xmm0
+; WIN-NEXT: pushq %rsi
+; WIN-NEXT: subq $64, %rsp
+; WIN-NEXT: movq %rcx, %rsi
+; WIN-NEXT: movaps (%rdx), %xmm0
; WIN-NEXT: movaps %xmm0, {{[0-9]+}}(%rsp)
; WIN-NEXT: leaq {{[0-9]+}}(%rsp), %rcx
+; WIN-NEXT: leaq {{[0-9]+}}(%rsp), %rdx
; WIN-NEXT: callq log10l
-; WIN-NEXT: addq $56, %rsp
+; WIN-NEXT: movaps {{[0-9]+}}(%rsp), %xmm0
+; WIN-NEXT: movaps %xmm0, (%rsi)
+; WIN-NEXT: movq %rsi, %rax
+; WIN-NEXT: addq $64, %rsp
+; WIN-NEXT: popq %rsi
; WIN-NEXT: retq
;
; WIN-X86-LABEL: log10:
@@ -1607,12 +1712,19 @@ define fp128 @log2(fp128 %x) nounwind strictfp {
;
; WIN-LABEL: log2:
; WIN: # %bb.0: # %entry
-; WIN-NEXT: subq $56, %rsp
-; WIN-NEXT: movaps (%rcx), %xmm0
+; WIN-NEXT: pushq %rsi
+; WIN-NEXT: subq $64, %rsp
+; WIN-NEXT: movq %rcx, %rsi
+; WIN-NEXT: movaps (%rdx), %xmm0
; WIN-NEXT: movaps %xmm0, {{[0-9]+}}(%rsp)
; WIN-NEXT: leaq {{[0-9]+}}(%rsp), %rcx
+; WIN-NEXT: leaq {{[0-9]+}}(%rsp), %rdx
; WIN-NEXT: callq log2l
-; WIN-NEXT: addq $56, %rsp
+; WIN-NEXT: movaps {{[0-9]+}}(%rsp), %xmm0
+; WIN-NEXT: movaps %xmm0, (%rsi)
+; WIN-NEXT: movq %rsi, %rax
+; WIN-NEXT: addq $64, %rsp
+; WIN-NEXT: popq %rsi
; WIN-NEXT: retq
;
; WIN-X86-LABEL: log2:
@@ -1709,15 +1821,22 @@ define fp128 @maxnum(fp128 %x, fp128 %y) nounwind strictfp {
;
; WIN-LABEL: maxnum:
; WIN: # %bb.0: # %entry
-; WIN-NEXT: subq $72, %rsp
-; WIN-NEXT: movaps (%rcx), %xmm0
-; WIN-NEXT: movaps (%rdx), %xmm1
+; WIN-NEXT: pushq %rsi
+; WIN-NEXT: subq $80, %rsp
+; WIN-NEXT: movq %rcx, %rsi
+; WIN-NEXT: movaps (%rdx), %xmm0
+; WIN-NEXT: movaps (%r8), %xmm1
; WIN-NEXT: movaps %xmm1, {{[0-9]+}}(%rsp)
; WIN-NEXT: movaps %xmm0, {{[0-9]+}}(%rsp)
; WIN-NEXT: leaq {{[0-9]+}}(%rsp), %rcx
; WIN-NEXT: leaq {{[0-9]+}}(%rsp), %rdx
+; WIN-NEXT: leaq {{[0-9]+}}(%rsp), %r8
; WIN-NEXT: callq fmaxl
-; WIN-NEXT: addq $72, %rsp
+; WIN-NEXT: movaps {{[0-9]+}}(%rsp), %xmm0
+; WIN-NEXT: movaps %xmm0, (%rsi)
+; WIN-NEXT: movq %rsi, %rax
+; WIN-NEXT: addq $80, %rsp
+; WIN-NEXT: popq %rsi
; WIN-NEXT: retq
;
; WIN-X86-LABEL: maxnum:
@@ -1824,15 +1943,22 @@ define fp128 @minnum(fp128 %x, fp128 %y) nounwind strictfp {
;
; WIN-LABEL: minnum:
; WIN: # %bb.0: # %entry
-; WIN-NEXT: subq $72, %rsp
-; WIN-NEXT: movaps (%rcx), %xmm0
-; WIN-NEXT: movaps (%rdx), %xmm1
+; WIN-NEXT: pushq %rsi
+; WIN-NEXT: subq $80, %rsp
+; WIN-NEXT: movq %rcx, %rsi
+; WIN-NEXT: movaps (%rdx), %xmm0
+; WIN-NEXT: movaps (%r8), %xmm1
; WIN-NEXT: movaps %xmm1, {{[0-9]+}}(%rsp)
; WIN-NEXT: movaps %xmm0, {{[0-9]+}}(%rsp)
; WIN-NEXT: leaq {{[0-9]+}}(%rsp), %rcx
; WIN-NEXT: leaq {{[0-9]+}}(%rsp), %rdx
+; WIN-NEXT: leaq {{[0-9]+}}(%rsp), %r8
; WIN-NEXT: callq fminl
-; WIN-NEXT: addq $72, %rsp
+; WIN-NEXT: movaps {{[0-9]+}}(%rsp), %xmm0
+; WIN-NEXT: movaps %xmm0, (%rsi)
+; WIN-NEXT: movq %rsi, %rax
+; WIN-NEXT: addq $80, %rsp
+; WIN-NEXT: popq %rsi
; WIN-NEXT: retq
;
; WIN-X86-LABEL: minnum:
@@ -1927,12 +2053,19 @@ define fp128 @nearbyint(fp128 %x) nounwind strictfp {
;
; WIN-LABEL: nearbyint:
; WIN: # %bb.0: # %entry
-; WIN-NEXT: subq $56, %rsp
-; WIN-NEXT: movaps (%rcx), %xmm0
+; WIN-NEXT: pushq %rsi
+; WIN-NEXT: subq $64, %rsp
+; WIN-NEXT: movq %rcx, %rsi
+; WIN-NEXT: movaps (%rdx), %xmm0
; WIN-NEXT: movaps %xmm0, {{[0-9]+}}(%rsp)
; WIN-NEXT: leaq {{[0-9]+}}(%rsp), %rcx
+; WIN-NEXT: leaq {{[0-9]+}}(%rsp), %rdx
; WIN-NEXT: callq nearbyintl
-; WIN-NEXT: addq $56, %rsp
+; WIN-NEXT: movaps {{[0-9]+}}(%rsp), %xmm0
+; WIN-NEXT: movaps %xmm0, (%rsi)
+; WIN-NEXT: movq %rsi, %rax
+; WIN-NEXT: addq $64, %rsp
+; WIN-NEXT: popq %rsi
; WIN-NEXT: retq
;
; WIN-X86-LABEL: nearbyint:
@@ -2029,15 +2162,22 @@ define fp128 @pow(fp128 %x, fp128 %y) nounwind strictfp {
;
; WIN-LABEL: pow:
; WIN: # %bb.0: # %entry
-; WIN-NEXT: subq $72, %rsp
-; WIN-NEXT: movaps (%rcx), %xmm0
-; WIN-NEXT: movaps (%rdx), %xmm1
+; WIN-NEXT: pushq %rsi
+; WIN-NEXT: subq $80, %rsp
+; WIN-NEXT: movq %rcx, %rsi
+; WIN-NEXT: movaps (%rdx), %xmm0
+; WIN-NEXT: movaps (%r8), %xmm1
; WIN-NEXT: movaps %xmm1, {{[0-9]+}}(%rsp)
; WIN-NEXT: movaps %xmm0, {{[0-9]+}}(%rsp)
; WIN-NEXT: leaq {{[0-9]+}}(%rsp), %rcx
; WIN-NEXT: leaq {{[0-9]+}}(%rsp), %rdx
+; WIN-NEXT: leaq {{[0-9]+}}(%rsp), %r8
; WIN-NEXT: callq powl
-; WIN-NEXT: addq $72, %rsp
+; WIN-NEXT: movaps {{[0-9]+}}(%rsp), %xmm0
+; WIN-NEXT: movaps %xmm0, (%rsi)
+; WIN-NEXT: movq %rsi, %rax
+; WIN-NEXT: addq $80, %rsp
+; WIN-NEXT: popq %rsi
; WIN-NEXT: retq
;
; WIN-X86-LABEL: pow:
@@ -2143,12 +2283,19 @@ define fp128 @powi(fp128 %x, i32 %y) nounwind strictfp {
;
; WIN-LABEL: powi:
; WIN: # %bb.0: # %entry
-; WIN-NEXT: subq $56, %rsp
-; WIN-NEXT: ...
[truncated]
|
|
Copying my reply to @Andarwinux on #19214 for some more context on reasoning:
I'll close https://gcc.gnu.org/bugzilla/show_bug.cgi?id=115054 once this merges. |
tgross35
left a comment
There was a problem hiding this comment.
Codegen changes look correct to me
There was a problem hiding this comment.
MSVC and MinGW should be matching for these types, so I believe you could merge CHECK-MSVC64-F128 and CHECK-MINGW-F128 into CHECK-WIN64-F128 (same for i128).
Could also be separate since I think this was true before this PR
There was a problem hiding this comment.
I'll leave it for now, that would make this harder to review
tgross35
left a comment
There was a problem hiding this comment.
Obviously needs review from somebody else but this all LGTM, assuming CanLowerReturn is the way to get around tablegen not working.
rnk
left a comment
There was a problem hiding this comment.
We need to think about how to manage the ABI change. At a minimum, we should announce the change with a release note, but I'll elaborate.
There are two interrelated changes here:
- Clang-side
- LLVM-side
Part of me wants to say: let's make this a clang-only change. Then we can respect the -fclang-abi=N flag, and clients who are affected by the ABI break can pin back to the old version. This requires LLVM to retain the behavior of passing f128 in XMM0.
Then we turn our attention to libclang_rt.builtins and the backend library call emission. Returning false for CanLowerReturn activates the sret demotion path, but I think that codepath is generally understood to be non-loadbearing for ABI compatibility purposes, i.e. once we get on that codepath, the compiler can do anything, so long as it handshakes with LLVM itself.
A different route would be to try to generalize the compiler runtime call so that it directly emits an sret call, rather than relying on the demotion.
To conclude, if you go this way, where you keep the change in the frontend and runtime call emission, you give the IR generator maximum control. They get to pick between implicit sret and XMM0, and they get to manage their ABI transition.
WDYT?
The obvious tradeoff here is that when you give frontends control, ABI compatibility becomes their problem, and people really hate this. Rust developers really love rediscovering all the ugly ABI lowering corner cases we've run into over the years. :p |
I don't think this will work on its own because libcalls use LLVM's ABI. It's also doesn't seem worth any effort to do a gentle migration; because of the ABI mismatch, (+1 to relnotes anyway)
Not sure if you're already aware or not, but Folkert and I are the Rust developers trying to figure out all the f128 ABI problems :) hence this PR, Windows is one of the few remaining popular platforms that's currently unusable. |
Well, we have lots examples of custom lowered library calls, like X86TargetLowering::LowerI128_TO_FP (sp). I think my hesitance was founded on a a really hazy recollection of this 2009 commit: 9f34406a9048 That's where this codepath comes from, and the test case provided suggests that the use case is for returning large structs from However, over the years, research shows that it has become ABI load-bearing. You can read the GPT research report here: https://gist.github.com/rnk/9a63ccc03bd3d0188d653dababbe8889 Long story short, I had a long conversation with a computer and convinced myself we should just use this codepath.
What I'm worried about going wrong is clang-cl calling compiler-rt builtins in libclang_rt.builtins, if there is skew between the compiler and the runtime. Chromium and all its derivatives ship that, but they don't have a stable ABI, so that probably doesn't matter.
Maybe one day 128 FP bits won't be enough, and some poor soul will come along and ask, "why didn't these compiler engineers think about the fp256 ABI!? so short-sighted!" |
9055ee8 to
8e66e5a
Compare
actually vectorcall is clang-specific so we don't need to be compatible there
| switch (CC) { | ||
| case llvm::CallingConv::Win64: | ||
| return true; | ||
| case llvm::CallingConv::C: |
There was a problem hiding this comment.
VectorCall is, from what I can find, clang-specific and so I don't think we need to be compatible with anything for it. Leaving it as before is easier.
There was a problem hiding this comment.
No, it's this: https://learn.microsoft.com/en-us/cpp/cpp/vectorcall?view=msvc-170
GCC might wish to support it one day, I would consider it to be part of the platform C ABI, even if it does have some quirks that require two iterations over the argument list.
There was a problem hiding this comment.
Ah, sorry yeah I meant that clang is the only compiler that needs to decide what f128 does for that calling convention. And given the name, here it kind of would make sense for GCC to pick passing/returning via vector registers?
In any case, anything we do here is arbitrary, and switching it over is kind of ugly code-wise.
There was a problem hiding this comment.
And given the name, here it kind of would make sense for GCC to pick passing/returning via vector registers?
I haven't looked at what this code does but my assumption is yes, for vectorcall f128 should ideally be returned in xmm0 (like what LLVM does for the C convention today) and passed that way too (unlike the C convention)
There was a problem hiding this comment.
We currently pass f128 via XMM registers (below xmm0 contains %a, rdx contains %p):
define x86_vectorcallcc void @"\01pass_vectorcall"(fp128 %a, ptr %p) {
; WIN-LABEL: pass_vectorcall:
; WIN: # %bb.0:
; WIN-NEXT: movaps %xmm0, (%rdx)
; WIN-NEXT: retq
;
; LINUX-LABEL: pass_vectorcall:
; LINUX: # %bb.0:
; LINUX-NEXT: movaps %xmm0, (%rdx)
; LINUX-NEXT: retq
store fp128 %a, ptr %p
ret void
}The current code also returns via xmm0 for vectorcall.
So yeah, we can discuss this but it seems quite reasonable? And it can be changed later if there is something we'd want to be compatible with that makes a different choice.
There was a problem hiding this comment.
I think I agree, if MSVC ever adds f128 support, I strongly suspect they'll choose to return in XMM0, so this is probably the right set of conventions.
| __float128 __attribute__((vectorcall)) fp128_ret_vectorcall(void) { return 0; } | ||
| // CHECK-GNU64: define dso_local x86_vectorcallcc fp128 @"\01fp128_ret_vectorcall@@0"() |
There was a problem hiding this comment.
this returns fp128 and then it's up to the backend to figure out what that means. We could force XMM0 with the <2 x i64> trick, I haven't done that yet because it does seem a bit hacky.
rnk
left a comment
There was a problem hiding this comment.
Minor code golf fix, otherwise, let's ship it.
| case llvm::CallingConv::Win64: | ||
| return true; | ||
| case llvm::CallingConv::C: | ||
| return getTarget().getTriple().isOSWindows() || |
There was a problem hiding this comment.
I added Triple::isOSWindowsOrUEFI for this in a recent revision
There was a problem hiding this comment.
Neat, I'm using that now.
| switch (CC) { | ||
| case llvm::CallingConv::Win64: | ||
| return true; | ||
| case llvm::CallingConv::C: |
There was a problem hiding this comment.
I think I agree, if MSVC ever adds f128 support, I strongly suspect they'll choose to return in XMM0, so this is probably the right set of conventions.
There was a problem hiding this comment.
I added a predicate for this just now
There was a problem hiding this comment.
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.
Subsumes llvm#194214 For x86-64 Windows targets, LLVM currently returns `fp128` in xmm0. This does match `i128` (both Clang and GCC return `__int128` in xmm0) but disagrees with GCC's behavior of returning `__float128` on the stack. https://gcc.godbolt.org/z/xnWeGqcbW Microsoft does not specify a `__float128` ABI so any decision is purely an extension. The Windows x64 calling convention [1] does say that user- defined types that do not fit in a register should be returned indirectly, so the GCC behavior seems like a reasonable interpretation of this rule. Thus, change `fp128` to return on the stack for Windows targets. This is done for both MinGW and MSVC targets; if official guidelines are ever published, this can be revisited. The change is made in LLVM (via sret demotion of f128), but also explicitly in `clang`. Frontends should emit the `sret` explicitly, if only for debug info, return value optimization, etc. Relates to the pass ABI change in 5ee1c0b ("[windows] Always pass fp128 arguments indirectly"). [1]: https://learn.microsoft.com/en-us/cpp/build/x64-calling-convention?view=msvc-170#return-values
…version (#207285) This change fixes an ABI issue where the signed conversion passes a `i128` different from a `u128`, and crucially different from GCC. https://godbolt.org/z/x3daY3rej ```diff --- <unnamed> +++ <unnamed> @@ -1,15 +1,15 @@ -conv_from_i128: +conv_from_u128: push rsi - sub rsp, 64 + sub rsp, 48 mov rsi, rcx - movaps xmm0, xmmword ptr [rdx] - movaps xmmword ptr [rsp + 48], xmm0 + mov rax, qword ptr [rdx] + mov r8, qword ptr [rdx + 8] lea rcx, [rsp + 32] - lea rdx, [rsp + 48] - call __floattitf + mov rdx, rax + call __floatuntitf movaps xmm0, xmmword ptr [rsp + 32] movaps xmmword ptr [rsi], xmm0 mov rax, rsi - add rsp, 64 + add rsp, 48 pop rsi ret ``` The signed case being correct is apparently due to a special windows-specific path being chosen. The unsigned version bailed out too early. So, I've changed `LowerUINT_TO_FP` to be more like `LowerSINT_TO_FP`. In particular this moves the "Bail out when we don't have native conversion instructions." down a bit, so that `LowerWin64_INT128_TO_FP` is actually used. I've then also added some testing for win64 SSE. I'm not sure if the other target features are as relevant but I can add those too if helpful. This was found by running the `rust-lang/compiler-builtins` tests with a build that includes #204887.
… `f128` conversion (#207285) This change fixes an ABI issue where the signed conversion passes a `i128` different from a `u128`, and crucially different from GCC. https://godbolt.org/z/x3daY3rej ```diff --- <unnamed> +++ <unnamed> @@ -1,15 +1,15 @@ -conv_from_i128: +conv_from_u128: push rsi - sub rsp, 64 + sub rsp, 48 mov rsi, rcx - movaps xmm0, xmmword ptr [rdx] - movaps xmmword ptr [rsp + 48], xmm0 + mov rax, qword ptr [rdx] + mov r8, qword ptr [rdx + 8] lea rcx, [rsp + 32] - lea rdx, [rsp + 48] - call __floattitf + mov rdx, rax + call __floatuntitf movaps xmm0, xmmword ptr [rsp + 32] movaps xmmword ptr [rsi], xmm0 mov rax, rsi - add rsp, 64 + add rsp, 48 pop rsi ret ``` The signed case being correct is apparently due to a special windows-specific path being chosen. The unsigned version bailed out too early. So, I've changed `LowerUINT_TO_FP` to be more like `LowerSINT_TO_FP`. In particular this moves the "Bail out when we don't have native conversion instructions." down a bit, so that `LowerWin64_INT128_TO_FP` is actually used. I've then also added some testing for win64 SSE. I'm not sure if the other target features are as relevant but I can add those too if helpful. This was found by running the `rust-lang/compiler-builtins` tests with a build that includes llvm/llvm-project#204887.
… `f128` conversion (#207285) This change fixes an ABI issue where the signed conversion passes a `i128` different from a `u128`, and crucially different from GCC. https://godbolt.org/z/x3daY3rej ```diff --- <unnamed> +++ <unnamed> @@ -1,15 +1,15 @@ -conv_from_i128: +conv_from_u128: push rsi - sub rsp, 64 + sub rsp, 48 mov rsi, rcx - movaps xmm0, xmmword ptr [rdx] - movaps xmmword ptr [rsp + 48], xmm0 + mov rax, qword ptr [rdx] + mov r8, qword ptr [rdx + 8] lea rcx, [rsp + 32] - lea rdx, [rsp + 48] - call __floattitf + mov rdx, rax + call __floatuntitf movaps xmm0, xmmword ptr [rsp + 32] movaps xmmword ptr [rsi], xmm0 mov rax, rsi - add rsp, 64 + add rsp, 48 pop rsi ret ``` The signed case being correct is apparently due to a special windows-specific path being chosen. The unsigned version bailed out too early. So, I've changed `LowerUINT_TO_FP` to be more like `LowerSINT_TO_FP`. In particular this moves the "Bail out when we don't have native conversion instructions." down a bit, so that `LowerWin64_INT128_TO_FP` is actually used. I've then also added some testing for win64 SSE. I'm not sure if the other target features are as relevant but I can add those too if helpful. This was found by running the `rust-lang/compiler-builtins` tests with a build that includes llvm/llvm-project#204887.
… `f128` conversion (#207285) This change fixes an ABI issue where the signed conversion passes a `i128` different from a `u128`, and crucially different from GCC. https://godbolt.org/z/x3daY3rej ```diff --- <unnamed> +++ <unnamed> @@ -1,15 +1,15 @@ -conv_from_i128: +conv_from_u128: push rsi - sub rsp, 64 + sub rsp, 48 mov rsi, rcx - movaps xmm0, xmmword ptr [rdx] - movaps xmmword ptr [rsp + 48], xmm0 + mov rax, qword ptr [rdx] + mov r8, qword ptr [rdx + 8] lea rcx, [rsp + 32] - lea rdx, [rsp + 48] - call __floattitf + mov rdx, rax + call __floatuntitf movaps xmm0, xmmword ptr [rsp + 32] movaps xmmword ptr [rsi], xmm0 mov rax, rsi - add rsp, 64 + add rsp, 48 pop rsi ret ``` The signed case being correct is apparently due to a special windows-specific path being chosen. The unsigned version bailed out too early. So, I've changed `LowerUINT_TO_FP` to be more like `LowerSINT_TO_FP`. In particular this moves the "Bail out when we don't have native conversion instructions." down a bit, so that `LowerWin64_INT128_TO_FP` is actually used. I've then also added some testing for win64 SSE. I'm not sure if the other target features are as relevant but I can add those too if helpful. This was found by running the `rust-lang/compiler-builtins` tests with a build that includes llvm/llvm-project#204887.
…version (llvm#207285) This change fixes an ABI issue where the signed conversion passes a `i128` different from a `u128`, and crucially different from GCC. https://godbolt.org/z/x3daY3rej ```diff --- <unnamed> +++ <unnamed> @@ -1,15 +1,15 @@ -conv_from_i128: +conv_from_u128: push rsi - sub rsp, 64 + sub rsp, 48 mov rsi, rcx - movaps xmm0, xmmword ptr [rdx] - movaps xmmword ptr [rsp + 48], xmm0 + mov rax, qword ptr [rdx] + mov r8, qword ptr [rdx + 8] lea rcx, [rsp + 32] - lea rdx, [rsp + 48] - call __floattitf + mov rdx, rax + call __floatuntitf movaps xmm0, xmmword ptr [rsp + 32] movaps xmmword ptr [rsi], xmm0 mov rax, rsi - add rsp, 64 + add rsp, 48 pop rsi ret ``` The signed case being correct is apparently due to a special windows-specific path being chosen. The unsigned version bailed out too early. So, I've changed `LowerUINT_TO_FP` to be more like `LowerSINT_TO_FP`. In particular this moves the "Bail out when we don't have native conversion instructions." down a bit, so that `LowerWin64_INT128_TO_FP` is actually used. I've then also added some testing for win64 SSE. I'm not sure if the other target features are as relevant but I can add those too if helpful. This was found by running the `rust-lang/compiler-builtins` tests with a build that includes llvm#204887.
…version (#207285) This change fixes an ABI issue where the signed conversion passes a `i128` different from a `u128`, and crucially different from GCC. https://godbolt.org/z/x3daY3rej ```diff --- <unnamed> +++ <unnamed> @@ -1,15 +1,15 @@ -conv_from_i128: +conv_from_u128: push rsi - sub rsp, 64 + sub rsp, 48 mov rsi, rcx - movaps xmm0, xmmword ptr [rdx] - movaps xmmword ptr [rsp + 48], xmm0 + mov rax, qword ptr [rdx] + mov r8, qword ptr [rdx + 8] lea rcx, [rsp + 32] - lea rdx, [rsp + 48] - call __floattitf + mov rdx, rax + call __floatuntitf movaps xmm0, xmmword ptr [rsp + 32] movaps xmmword ptr [rsi], xmm0 mov rax, rsi - add rsp, 64 + add rsp, 48 pop rsi ret ``` The signed case being correct is apparently due to a special windows-specific path being chosen. The unsigned version bailed out too early. So, I've changed `LowerUINT_TO_FP` to be more like `LowerSINT_TO_FP`. In particular this moves the "Bail out when we don't have native conversion instructions." down a bit, so that `LowerWin64_INT128_TO_FP` is actually used. I've then also added some testing for win64 SSE. I'm not sure if the other target features are as relevant but I can add those too if helpful. This was found by running the `rust-lang/compiler-builtins` tests with a build that includes #204887.
Subsumes #194214
For x86-64 Windows targets, LLVM currently returns
fp128in xmm0. This does matchi128(both Clang and GCC return__int128in xmm0) but disagrees with GCC's behavior of returning__float128on the stack.https://gcc.godbolt.org/z/xnWeGqcbW
Microsoft does not specify a
__float128ABI so any decision is purely an extension. The Windows x64 calling convention 1 does say that user- defined types that do not fit in a register should be returned indirectly, so the GCC behavior seems like a reasonable interpretation of this rule.Thus, change
fp128to return on the stack for Windows targets. This is done for both MinGW and MSVC targets; if official guidelines are ever published, this can be revisited.The change is made in LLVM (via sret demotion of f128), but also explicitly in
clang. Frontends should emit thesretexplicitly, if only for debug info, return value optimization, etc.Relates to the pass ABI change in 5ee1c0b ("[windows] Always pass fp128 arguments indirectly").